Mailto landing.

The mailto library is the mail compose code ripped out of the old
Messenger libmsg library, then cleaned up somewhat
(it could still use more cleaning).
This library should only be built ifdef MOZ_MAIL_COMPOSE.


git-svn-id: svn://10.0.0.236/trunk@9361 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
akkana%netscape.com
1998-09-04 19:04:30 +00:00
parent 498b0dfae9
commit 3e79243700
51 changed files with 27047 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../..
MODULE = mailto
LIBRARY_NAME = mailto
CSRCS = \
ad_strm.c \
ap_decod.c \
ap_encod.c \
appledbl.c \
bh_strm.c \
m_binhex.c \
msgutils.c \
$(NULL)
CPPSRCS = \
addrutil.cpp \
bytearr.cpp \
dwordarr.cpp \
mhtmlstm.cpp \
msgbg.cpp \
msgcflds.cpp \
msgcpane.cpp \
msgglue.cpp \
msgmast.cpp \
msgmdn.cpp \
msgpane.cpp \
msgppane.cpp \
msgprefs.cpp \
msgsend.cpp \
msgsendp.cpp \
msgurlq.cpp \
msgzap.cpp \
ptrarray.cpp \
$(NULL)
# We'd like to include msgdlqml.cpp eventually (deliver queued mail)
EXPORTS = \
ad_codes.h \
appledbl.h \
bytearr.h \
dwordarr.h \
errcode.h \
error.h \
m_binhex.h \
mhtmlstm.h \
msg.h \
msgcflds.h \
msgcpane.h \
msghdr.h \
msgmast.h \
msgmdn.h \
msgpane.h \
msgppane.h \
msgprefs.h \
msgprnot.h \
msgsend.h \
msgsendp.h \
msgutils.h \
msgzap.h \
ptrarray.h \
$(NULL)
REQUIRES = nspr htmldlgs img util layer pref security js java net progress network
include $(DEPTH)/config/rules.mk
# INCLUDES += -I$(DIST)/include -I$(PUBLIC)/security -I../libaddr -I$(PUBLIC)/msg

View File

@@ -0,0 +1,129 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
** AD_Codes.h
**
** ---------------
**
** Head file for Apple Decode/Encode enssential codes.
**
**
*/
#ifndef ad_codes_h
#define ad_codes_h
#include "xp_core.h"
/*
** applefile definitions used
*/
#ifdef XP_MAC
#if PRAGMA_ALIGN_SUPPORTED
#pragma options align=mac68k
#endif
#endif /* XP_MAC */
#define APPLESINGLE_MAGIC 0x00051600L
#define APPLEDOUBLE_MAGIC 0x00051607L
#define VERSION 0x00020000
#define NUM_ENTRIES 6
#define ENT_DFORK 1L
#define ENT_RFORK 2L
#define ENT_NAME 3L
#define ENT_COMMENT 4L
#define ENT_DATES 8L
#define ENT_FINFO 9L
#define CONVERT_TIME 1265437696L
/*
** data type used in the encoder/decoder.
*/
typedef struct ap_header
{
int32 magic;
int32 version;
char fill[16];
int16 entries;
} ap_header;
typedef struct ap_entry
{
uint32 id;
uint32 offset;
uint32 length;
} ap_entry;
typedef struct ap_dates
{
int32 create, modify, backup, access;
} ap_dates;
typedef struct myFInfo /* the mac FInfo structure for the cross platform. */
{
int32 fdType, fdCreator;
int16 fdFlags;
int32 fdLocation; /* it really should be a pointer, but just a place-holder */
int16 fdFldr;
} myFInfo;
XP_BEGIN_PROTOS
/*
** string utils.
*/
int write_stream(appledouble_encode_object *p_ap_encode_obj,char *s,int len);
int fill_apple_mime_header(appledouble_encode_object *p_ap_encode_obj);
int ap_encode_file_infor(appledouble_encode_object *p_ap_encode_obj);
int ap_encode_header(appledouble_encode_object* p_ap_encode_obj, XP_Bool firstTime);
int ap_encode_data( appledouble_encode_object* p_ap_encode_obj, XP_Bool firstTime);
/*
** the prototypes for the ap_decoder.
*/
int fetch_a_line(appledouble_decode_object* p_ap_decode_obj, char *buff);
int ParseFileHeader(appledouble_decode_object* p_ap_decode_obj);
int ap_seek_part_start(appledouble_decode_object* p_ap_decode_obj);
void parse_param(char *p, char **param, char**define, char **np);
int ap_seek_to_boundary(appledouble_decode_object* p_ap_decode_obj, XP_Bool firstime);
int ap_parse_header(appledouble_decode_object* p_ap_decode_obj,XP_Bool firstime);
int ap_decode_file_infor(appledouble_decode_object* p_ap_decode_obj);
int ap_decode_process_header(appledouble_decode_object* p_ap_decode_obj, XP_Bool firstime);
int ap_decode_process_data( appledouble_decode_object* p_ap_decode_obj, XP_Bool firstime);
#ifdef XP_MAC
OSErr my_FSSpecFromPathname(char* src_filename, FSSpec* fspec);
char* my_PathnameFromFSSpec(FSSpec* fspec);
#endif
XP_END_PROTOS
#ifdef XP_MAC
#if PRAGMA_ALIGN_SUPPORTED
#pragma options align=reset
#endif
#endif /* XP_MAC */
#endif /* ad_codes_h */

View File

@@ -0,0 +1,719 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/**
* Apple Double encode/decode stream
* ----------------------------------
*
* 11sep95 mym created.
*/
#include "msg.h"
#include "appledbl.h"
#include "m_binhex.h"
#include "m_cvstrm.h"
#include "ad_codes.h"
/* for XP_GetString() */
#include "xpgetstr.h"
extern int MK_MSG_SAVE_ATTACH_AS;
#ifdef XP_MAC
#pragma warn_unusedarg off
extern int MK_UNABLE_TO_OPEN_TMP_FILE;
extern int MK_MIME_ERROR_WRITING_FILE;
/* ---------------------------------------------------------------------------------
**
** The codes for Apple-double encoding stream. --- it's only useful on Mac OS
**
** ---------------------------------------------------------------------------------
*/
#define WORKING_BUFF_SIZE 8192
typedef struct _AppledoubleEncodeObject
{
appledouble_encode_object ap_encode_obj;
char* buff; /* the working buff. */
int32 s_buff; /* the working buff size. */
XP_File fp; /* file to hold the encoding */
char *fname; /* and the file name. */
} AppleDoubleEncodeObject;
/*
Let's go "l" characters forward of the encoding for this write.
Note:
"s" is just a dummy paramter.
*/
PRIVATE int
net_AppleDouble_Encode_Write (
void *stream, const char* s, int32 l)
{
int status = 0;
AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream;
int32 count, size;
while (l > 0)
{
size = obj->s_buff * 11 / 16;
size = MIN(l, size);
status = ap_encode_next(&(obj->ap_encode_obj),
obj->buff,
size,
&count);
if (status == noErr || status == errDone)
{
/*
* we get the encode data, so call the next stream to write it to the disk.
*/
if (XP_FileWrite(obj->buff, count, obj->fp) != count)
return errFileWrite;
}
if (status != noErr ) /* abort when error / done? */
break;
l -= size;
}
return status;
}
/*
** is the stream ready for writing?
*/
PRIVATE unsigned int net_AppleDouble_Encode_Ready (void *stream)
{
return(MAX_WRITE_READY); /* always ready for writing */
}
PRIVATE void net_AppleDouble_Encode_Complete (void *stream)
{
AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream;
ap_encode_end(&(obj->ap_encode_obj), false); /* this is a normal ending */
if (obj->fp)
{
XP_FileClose(obj->fp); /* done with the target file */
FREEIF(obj->fname); /* and the file name too */
}
FREEIF(obj->buff); /* free the working buff. */
XP_FREE(obj);
}
PRIVATE void net_AppleDouble_Encode_Abort (void *stream, int status)
{
AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream;
ap_encode_end(&(obj->ap_encode_obj), true); /* it is an aborting exist... */
if (obj->fp)
{
XP_FileClose(obj->fp);
XP_FileRemove (obj->fname, xpURL); /* remove the partial file. */
FREEIF(obj->fname);
}
FREEIF(obj->buff); /* free the working buff. */
XP_FREE(obj);
}
/*
** fe_MakeAppleDoubleEncodeStream
** ------------------------------
**
** Will create a apple double encode stream:
**
** -> take the filename as the input source (it needs to be a mac file.)
** -> take a file name for the temp file we are generating.
*/
PUBLIC NET_StreamClass *
fe_MakeAppleDoubleEncodeStream (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id,
char* src_filename,
char* dst_filename,
char* separator)
{
AppleDoubleEncodeObject* obj;
NET_StreamClass* stream;
char* working_buff = NULL;
int bSize = WORKING_BUFF_SIZE;
TRACEMSG(("Setting up apple encode stream. Have URL: %s\n", URL_s->address));
stream = XP_NEW(NET_StreamClass);
if(stream == NULL)
return(NULL);
obj = XP_NEW(AppleDoubleEncodeObject);
if (obj == NULL)
{
XP_FREE (stream);
return(NULL);
}
while (!working_buff && (bSize >= 512))
{
working_buff = (char *)XP_ALLOC(bSize);
if (!working_buff)
bSize /= 2;
}
if (working_buff == NULL)
{
XP_FREE (obj);
XP_FREE (stream);
return (NULL);
}
stream->name = "Apple Double Encode";
stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Encode_Complete;
stream->abort = (MKStreamAbortFunc) net_AppleDouble_Encode_Abort;
stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Encode_Write;
stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Encode_Ready;
stream->data_object = obj;
stream->window_id = window_id;
obj->fp = XP_FileOpen(dst_filename, xpFileToPost, XP_FILE_WRITE_BIN);
if (obj->fp == NULL)
{
XP_FREE (working_buff);
XP_FREE (obj);
XP_FREE (stream);
return (NULL);
}
obj->fname = XP_STRDUP(dst_filename);
obj->buff = working_buff;
obj->s_buff = bSize;
/*
** setup all the need information on the apple double encoder.
*/
ap_encode_init(&(obj->ap_encode_obj),
src_filename, /* pass the file name of the source. */
separator);
TRACEMSG(("Returning stream from NET_AppleDoubleEncoder\n"));
return stream;
}
#endif
/*
** ---------------------------------------------------------------------------------
**
** The codes for the Apple sigle/double decoding.
**
** ---------------------------------------------------------------------------------
*/
typedef struct AppleDoubleDecodeObject
{
appledouble_decode_object ap_decode_obj;
char* in_buff; /* the temporary buff to accumulate */
/* the input, make sure the call to */
/* the dedcoder engine big enough buff */
int32 bytes_in_buff; /* the count for the temporary buff. */
NET_StreamClass* binhex_stream; /* a binhex encode stream to convert */
/* the decoded mac file to binhex. */
} AppleDoubleDecodeObject;
PRIVATE int
net_AppleDouble_Decode_Write (
void *stream, const char* s, int32 l)
{
int status = NOERR;
AppleDoubleDecodeObject * obj = (AppleDoubleDecodeObject*) stream;
int32 size;
/*
** To force an effecient decoding, we should
** make sure that the buff pass to the decode next is great than 1024 bytes.
*/
if (obj->bytes_in_buff + l > 1024)
{
size = 1024 - obj->bytes_in_buff;
XP_MEMCPY(obj->in_buff+obj->bytes_in_buff,
s,
size);
s += size;
l -= size;
status = ap_decode_next(&(obj->ap_decode_obj),
obj->in_buff,
1024);
obj->bytes_in_buff = 0;
}
if (l > 1024)
{
/* we are sure that obj->bytes_in_buff == 0 at this point. */
status = ap_decode_next(&(obj->ap_decode_obj),
(char *)s,
l);
}
else
{
/* and we are sure we will not get overflow with the buff. */
XP_MEMCPY(obj->in_buff+obj->bytes_in_buff,
s,
l);
obj->bytes_in_buff += l;
}
return status;
}
PRIVATE unsigned int
net_AppleDouble_Decode_Ready (NET_StreamClass *stream)
{
return(MAX_WRITE_READY); /* always ready for writing */
}
PRIVATE void
net_AppleDouble_Decode_Complete (void *stream)
{
AppleDoubleDecodeObject *obj = (AppleDoubleDecodeObject *)stream;
if (obj->bytes_in_buff)
{
ap_decode_next(&(obj->ap_decode_obj), /* do the last calls. */
(char *)obj->in_buff,
obj->bytes_in_buff);
obj->bytes_in_buff = 0;
}
ap_decode_end(&(obj->ap_decode_obj), FALSE); /* it is a normal clean up cases.*/
if (obj->binhex_stream)
XP_FREE(obj->binhex_stream);
if (obj->in_buff)
XP_FREE(obj->in_buff);
XP_FREE(obj);
}
PRIVATE void
net_AppleDouble_Decode_Abort (
void *stream, int status)
{
AppleDoubleDecodeObject *obj = (AppleDoubleDecodeObject *)stream;
ap_decode_end(&(obj->ap_decode_obj), TRUE); /* it is an abort. */
if (obj->binhex_stream)
XP_FREE(obj->binhex_stream);
if (obj->in_buff)
XP_FREE(obj->in_buff);
XP_FREE(obj);
}
/*
** fe_MakeAppleDoubleDecodeStream_1
** ---------------------------------
**
** Create the apple double decode stream.
**
** In the Mac OS, it will create a stream to decode to an apple file;
**
** In other OS, the stream will decode apple double object,
** then encode it in binhex format, and save to the file.
*/
#ifndef XP_MAC
static void
simple_copy(MWContext* context, char* saveName, void* closure)
{
/* just copy the filename to the closure, so the caller can get it. */
XP_STRCPY(closure, saveName);
}
#endif
PUBLIC NET_StreamClass *
fe_MakeAppleDoubleDecodeStream_1 (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id)
{
#ifdef XP_MAC
return fe_MakeAppleDoubleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
false,
NULL);
#else
#if 0 /* just a test in the mac OS */
NET_StreamClass *p;
char* url;
StandardFileReply reply;
StandardPutFile("\pSave binhex encoded file as:", "\pUntitled", &reply);
if (!reply.sfGood)
{
return NULL;
}
url = my_PathnameFromFSSpec(&(reply.sfFile));
p = fe_MakeAppleDoubleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
true,
url+7);
XP_FREE(url);
return (p);
#else /* for the none mac-os to get a file name */
NET_StreamClass *p;
char* filename;
filename = XP_ALLOC(1024);
if (filename == NULL)
return NULL;
if (FE_PromptForFileName(window_id,
XP_GetString(MK_MSG_SAVE_ATTACH_AS),
0,
FALSE,
FALSE,
simple_copy,
filename) == -1)
{
return NULL;
}
p = fe_MakeAppleDoubleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
TRUE,
filename);
XP_FREE(filename);
return (p);
#endif
#endif
}
PUBLIC NET_StreamClass *
fe_MakeAppleDoubleDecodeStream (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id,
XP_Bool write_as_binhex,
char *dst_filename)
{
AppleDoubleDecodeObject* obj;
NET_StreamClass* stream;
TRACEMSG(("Setting up apple double decode stream. Have URL: %s\n", URL_s->address));
stream = XP_NEW(NET_StreamClass);
if(stream == NULL)
return(NULL);
obj = XP_NEW(AppleDoubleDecodeObject);
if (obj == NULL)
{
XP_FREE(stream);
return(NULL);
}
stream->name = "AppleDouble Decode";
stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Decode_Complete;
stream->abort = (MKStreamAbortFunc) net_AppleDouble_Decode_Abort;
stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Decode_Write;
stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Decode_Ready;
stream->data_object = obj;
stream->window_id = window_id;
/*
** setup all the need information on the apple double encoder.
*/
obj->in_buff = (char *)XP_ALLOC(1024);
if (obj->in_buff == NULL)
{
XP_FREE(obj);
XP_FREE(stream);
return (NULL);
}
obj->bytes_in_buff = 0;
if (write_as_binhex)
{
obj->binhex_stream =
fe_MakeBinHexEncodeStream(format_out,
data_obj,
URL_s,
window_id,
dst_filename);
if (obj->binhex_stream == NULL)
{
XP_FREE(obj);
XP_FREE(stream);
XP_FREE(obj->in_buff);
return NULL;
}
ap_decode_init(&(obj->ap_decode_obj),
FALSE,
TRUE,
obj->binhex_stream);
}
else
{
obj->binhex_stream = NULL;
ap_decode_init(&(obj->ap_decode_obj),
FALSE,
FALSE,
window_id);
/*
* jt 8/8/97 -- I think this should be set to true. But'
* let's not touch it for now.
*
* obj->ap_decode_obj.is_binary = TRUE;
*/
}
if (dst_filename)
{
XP_STRNCPY_SAFE(obj->ap_decode_obj.fname, dst_filename,
sizeof(obj->ap_decode_obj.fname));
}
#ifdef XP_MAC
obj->ap_decode_obj.mSpec = (FSSpec*)( URL_s->fe_data );
#endif
TRACEMSG(("Returning stream from NET_AppleDoubleDecode\n"));
return stream;
}
/*
** fe_MakeAppleSingleDecodeStream_1
** --------------------------------
**
** Create the apple single decode stream.
**
** In the Mac OS, it will create a stream to decode object to an apple file;
**
** In other OS, the stream will decode apple single object,
** then encode context in binhex format, and save to the file.
*/
PUBLIC NET_StreamClass *
fe_MakeAppleSingleDecodeStream_1 (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id)
{
#ifdef XP_MAC
return fe_MakeAppleSingleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
FALSE,
NULL);
#else
#if 0 /* just a test in the mac OS */
NET_StreamClass *p;
char* url;
StandardFileReply reply;
StandardPutFile("\pSave binhex encoded file as:", "\pUntitled", &reply);
if (!reply.sfGood)
{
return NULL;
}
url = my_PathnameFromFSSpec(&(reply.sfFile));
p = fe_MakeAppleSingleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
true,
url+7);
XP_FREE(url);
return (p);
#else /* for the none mac-os to get a file name */
NET_StreamClass *p;
char* filename;
char* defaultPath = 0;
defaultPath = URL_s->content_name;
#ifdef XP_WIN16
if (XP_FileNameContainsBadChars(defaultPath))
defaultPath = 0;
#endif
filename = XP_ALLOC(1024);
if (filename == NULL)
return NULL;
if (FE_PromptForFileName(window_id,
XP_GetString(MK_MSG_SAVE_ATTACH_AS),
defaultPath,
FALSE,
FALSE,
simple_copy,
filename) == -1)
{
return NULL;
}
p = fe_MakeAppleSingleDecodeStream(format_out,
data_obj,
URL_s,
window_id,
FALSE,
filename);
XP_FREE(filename);
return (p);
#endif
#endif
}
/*
** Create the Apple Doube Decode stream.
**
*/
PUBLIC NET_StreamClass *
fe_MakeAppleSingleDecodeStream (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id,
XP_Bool write_as_binhex,
char *dst_filename)
{
AppleDoubleDecodeObject* obj;
NET_StreamClass* stream;
int encoding = kEncodeNone; /* default is that we don't know the encoding */
TRACEMSG(("Setting up apple single decode stream. Have URL: %s\n", URL_s->address));
stream = XP_NEW(NET_StreamClass);
if(stream == NULL)
return(NULL);
obj = XP_NEW(AppleDoubleDecodeObject);
if (obj == NULL)
{
XP_FREE(stream);
return(NULL);
}
stream->name = "AppleSingle Decode";
stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Decode_Complete;
stream->abort = (MKStreamAbortFunc) net_AppleDouble_Decode_Abort;
stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Decode_Write;
stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Decode_Ready;
stream->data_object = obj;
stream->window_id = window_id;
/*
** setup all the need information on the apple double encoder.
*/
obj->in_buff = (char *)XP_ALLOC(1024);
if (obj->in_buff == NULL)
{
XP_FREE(obj);
XP_FREE(stream);
return (NULL);
}
obj->bytes_in_buff = 0;
if (write_as_binhex)
{
obj->binhex_stream =
fe_MakeBinHexEncodeStream(format_out,
data_obj,
URL_s,
window_id,
dst_filename);
if (obj->binhex_stream == NULL)
{
XP_FREE(obj);
XP_FREE(stream);
XP_FREE(obj->in_buff);
return NULL;
}
ap_decode_init(&(obj->ap_decode_obj),
TRUE,
TRUE,
obj->binhex_stream);
}
else
{
obj->binhex_stream = NULL;
ap_decode_init(&(obj->ap_decode_obj),
TRUE,
FALSE,
window_id);
#ifndef XP_MAC
obj->ap_decode_obj.is_binary = TRUE;
#endif
}
if (dst_filename)
{
XP_STRNCPY_SAFE(obj->ap_decode_obj.fname, dst_filename,
sizeof(obj->ap_decode_obj.fname));
}
/* If we are of a broken content-type, impose its encoding. */
if (URL_s->content_type
&& !XP_STRNCASECMP(URL_s->content_type, "x-uuencode-apple-single", 23))
obj->ap_decode_obj.encoding = kEncodeUU;
else
obj->ap_decode_obj.encoding = kEncodeNone;
TRACEMSG(("Returning stream from NET_AppleSingleDecode\n"));
return stream;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,733 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
*
* apple_double_encode.c
* ---------------------
*
* The routines doing the Apple Double Encoding.
*
* 2aug95 mym Created.
*
*/
#include "msg.h"
#include "appledbl.h"
#include "ad_codes.h"
#ifdef XP_MAC
extern int MK_UNABLE_TO_OPEN_TMP_FILE;
extern int MK_MIME_ERROR_WRITING_FILE;
#include <Errors.h>
/*
** Local Functions prototypes.
*/
PRIVATE int output64chunk( appledouble_encode_object* p_ap_encode_obj,
int c1, int c2, int c3, int pads);
PRIVATE int to64(appledouble_encode_object* p_ap_encode_obj,
char *p,
int in_size);
PRIVATE int finish64(appledouble_encode_object* p_ap_encode_obj);
#define BUFF_LEFT(p) ((p)->s_outbuff - (p)->pos_outbuff)
/*
** write_stream.
*/
int write_stream(
appledouble_encode_object *p_ap_encode_obj,
char *out_string,
int len)
{
if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff)
{
XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
out_string,
len);
p_ap_encode_obj->pos_outbuff += len;
return noErr;
}
else
{
/*
** If the buff doesn't have enough space, use the overflow buffer then.
*/
int s_len = p_ap_encode_obj->s_outbuff - p_ap_encode_obj->pos_outbuff;
XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
out_string,
s_len);
XP_MEMCPY(p_ap_encode_obj->b_overflow + p_ap_encode_obj->s_overflow,
out_string + s_len,
p_ap_encode_obj->s_overflow += (len - s_len));
p_ap_encode_obj->pos_outbuff += s_len;
return errEOB;
}
}
int fill_apple_mime_header(
appledouble_encode_object *p_ap_encode_obj)
{
int status;
char tmpstr[266];
#if 0
// strcpy(tmpstr, "Content-Type: multipart/mixed; boundary=\"-\"\n\n---\n");
// status = write_stream(p_ap_encode_env,
// tmpstr,
// strlen(tmpstr));
// if (status != noErr)
// return status;
sprintf(tmpstr,
"Content-Type: multipart/appledouble; boundary=\"=\"; name=\"");
status = write_stream(p_ap_encode_obj,
tmpstr,
strlen(tmpstr));
if (status != noErr)
return status;
status = write_stream(p_ap_encode_obj,
p_ap_encode_obj->fname,
XP_STRLEN(p_ap_encode_obj->fname));
if (status != noErr)
return status;
XP_SPRINTF(tmpstr,
"\"\nContent-Disposition: inline; filename=\"%s\"\n\n\n--=\n",
p_ap_encode_obj->fname);
#endif
XP_SPRINTF(tmpstr, "--%s"CRLF, p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj,
tmpstr,
XP_STRLEN(tmpstr));
return status;
}
int ap_encode_file_infor(
appledouble_encode_object *p_ap_encode_obj)
{
CInfoPBRec cipbr;
HFileInfo *fpb = (HFileInfo *)&cipbr;
ap_header head;
ap_entry entries[NUM_ENTRIES];
ap_dates dates;
short i;
long comlen, procID;
DateTimeRec cur_time;
unsigned long cur_secs;
IOParam vinfo;
GetVolParmsInfoBuffer vp;
DTPBRec dtp;
char comment[256];
Str63 fname;
int status;
strcpy((char *)fname+1,p_ap_encode_obj->fname);
fname[0] = XP_STRLEN(p_ap_encode_obj->fname);
fpb->ioNamePtr = fname;
fpb->ioDirID = p_ap_encode_obj->dirId;
fpb->ioVRefNum = p_ap_encode_obj->vRefNum;
fpb->ioFDirIndex = 0;
if (PBGetCatInfoSync(&cipbr) != noErr)
{
return errFileOpen;
}
/* get a file comment, if possible */
procID = 0;
GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID);
memset((void *) &vinfo, '\0', sizeof (vinfo));
vinfo.ioCompletion = nil;
vinfo.ioVRefNum = fpb->ioVRefNum;
vinfo.ioBuffer = (Ptr) &vp;
vinfo.ioReqCount = sizeof (vp);
comlen = 0;
if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr &&
((vp.vMAttrib >> bHasDesktopMgr) & 1))
{
memset((void *) &dtp, '\0', sizeof (dtp));
dtp.ioVRefNum = fpb->ioVRefNum;
if (PBDTGetPath(&dtp) == noErr)
{
dtp.ioCompletion = nil;
dtp.ioDTBuffer = (Ptr) comment;
dtp.ioNamePtr = fpb->ioNamePtr;
dtp.ioDirID = fpb->ioFlParID;
if (PBDTGetCommentSync(&dtp) == noErr)
comlen = dtp.ioDTActCount;
}
}
/* write header */
// head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC;
head.magic = APPLEDOUBLE_MAGIC; /* always do apple double */
head.version = VERSION;
memset(head.fill, '\0', sizeof (head.fill));
head.entries = NUM_ENTRIES - 1;
status = to64(p_ap_encode_obj,
(char *) &head,
sizeof (head));
if (status != noErr)
return status;
/* write entry descriptors */
entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries;
entries[0].id = ENT_NAME;
entries[0].length = *fpb->ioNamePtr;
entries[1].id = ENT_FINFO;
entries[1].length = sizeof (FInfo) + sizeof (FXInfo);
entries[2].id = ENT_DATES;
entries[2].length = sizeof (ap_dates);
entries[3].id = ENT_COMMENT;
entries[3].length = comlen;
entries[4].id = ENT_RFORK;
entries[4].length = fpb->ioFlRLgLen;
entries[5].id = ENT_DFORK;
entries[5].length = fpb->ioFlLgLen;
/* correct the link in the entries. */
for (i = 1; i < NUM_ENTRIES; ++i)
{
entries[i].offset = entries[i-1].offset + entries[i-1].length;
}
status = to64(p_ap_encode_obj,
(char *) entries,
sizeof (ap_entry) * head.entries);
if (status != noErr)
return status;
/* write name */
status = to64(p_ap_encode_obj,
(char *) fpb->ioNamePtr + 1,
*fpb->ioNamePtr);
if (status != noErr)
return status;
/* write finder info */
status = to64(p_ap_encode_obj,
(char *) &fpb->ioFlFndrInfo,
sizeof (FInfo));
if (status != noErr)
return status;
status = to64(p_ap_encode_obj,
(char *) &fpb->ioFlXFndrInfo,
sizeof (FXInfo));
if (status != noErr)
return status;
/* write dates */
GetTime(&cur_time);
DateToSeconds(&cur_time, &cur_secs);
dates.create = fpb->ioFlCrDat + CONVERT_TIME;
dates.modify = fpb->ioFlMdDat + CONVERT_TIME;
dates.backup = fpb->ioFlBkDat + CONVERT_TIME;
dates.access = cur_secs + CONVERT_TIME;
status = to64(p_ap_encode_obj,
(char *) &dates,
sizeof (ap_dates));
if (status != noErr)
return status;
/* write comment */
if (comlen)
{
status = to64(p_ap_encode_obj,
comment,
comlen * sizeof(char));
}
/*
** Get some help information on deciding the file type.
*/
if (fpb->ioFlFndrInfo.fdType == 'TEXT' || fpb->ioFlFndrInfo.fdType == 'text')
{
p_ap_encode_obj->text_file_type = true;
}
return status;
}
/*
** ap_encode_header
**
** encode the file header and the resource fork.
**
*/
int ap_encode_header(
appledouble_encode_object* p_ap_encode_obj,
XP_Bool firstime)
{
Str255 name;
char rd_buff[256];
short fileId;
OSErr retval = noErr;
int status;
long inCount;
if (firstime)
{
XP_STRCPY(rd_buff,
"Content-Type: application/applefile\nContent-Transfer-Encoding: base64\n\n");
status = write_stream(p_ap_encode_obj,
rd_buff,
strlen(rd_buff));
if (status != noErr)
return status;
status = ap_encode_file_infor(p_ap_encode_obj);
if (status != noErr)
return status;
/*
** preparing to encode the resource fork.
*/
name[0] = strlen(p_ap_encode_obj->fname);
strcpy((char *)name+1, p_ap_encode_obj->fname);
if (HOpenRF(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId,
name, fsRdPerm,
&p_ap_encode_obj->fileId) != noErr)
{
return errFileOpen;
}
}
fileId = p_ap_encode_obj->fileId;
while (retval == noErr)
{
if (BUFF_LEFT(p_ap_encode_obj) < 400)
break;
inCount = 256;
retval = FSRead(fileId, &inCount, rd_buff);
if (inCount)
{
status = to64(p_ap_encode_obj,
rd_buff,
inCount);
if (status != noErr)
return status;
}
}
if (retval == eofErr)
{
FSClose(fileId);
status = finish64(p_ap_encode_obj);
if (status != noErr)
return status;
/*
** write out the boundary
*/
XP_SPRINTF(rd_buff,
CRLF"--%s"CRLF,
p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj,
rd_buff,
XP_STRLEN(rd_buff));
if (status == noErr)
status = errDone;
}
return status;
}
static void replace(char *p, int len, char frm, char to)
{
for (; len > 0; len--, p++)
if (*p == frm) *p = to;
}
/* Description of the various file formats and their magic numbers */
struct magic
{
char *name; /* Name of the file format */
char *num; /* The magic number */
int len; /* Length (0 means strlen(magicnum)) */
};
/* The magic numbers of the file formats we know about */
static struct magic magic[] =
{
{ "image/gif", "GIF", 0 },
{ "image/jpeg", "\377\330\377", 0 },
{ "video/mpeg", "\0\0\001\263", 4 },
{ "application/postscript", "%!", 0 },
};
static int num_magic = (sizeof(magic)/sizeof(magic[0]));
static char *text_type = TEXT_PLAIN; /* the text file type. */
static char *default_type = APPLICATION_OCTET_STREAM;
/*
* Determins the format of the file "inputf". The name
* of the file format (or NULL on error) is returned.
*/
PRIVATE char *magic_look(char *inbuff, int numread)
{
int i, j;
for (i=0; i<num_magic; i++)
{
if (magic[i].len == 0)
magic[i].len = XP_STRLEN(magic[i].num);
}
for (i=0; i<num_magic; i++)
{
if (numread >= magic[i].len)
{
for (j=0; j<magic[i].len; j++)
{
if (inbuff[j] != magic[i].num[j]) break;
}
if (j == magic[i].len)
return magic[i].name;
}
}
return default_type;
}
/*
** ap_encode_data
**
** ---------------
**
** encode on the data fork.
**
*/
int ap_encode_data(
appledouble_encode_object* p_ap_encode_obj,
XP_Bool firstime)
{
Str255 name;
char rd_buff[256];
short fileId;
OSErr retval = noErr;
long in_count;
int status;
if (firstime)
{
char* magic_type;
/*
** preparing to encode the data fork.
*/
name[0] = XP_STRLEN(p_ap_encode_obj->fname);
XP_STRCPY((char*)name+1, p_ap_encode_obj->fname);
if (HOpen( p_ap_encode_obj->vRefNum,
p_ap_encode_obj->dirId,
name,
fsRdPerm,
&fileId) != noErr)
{
return errFileOpen;
}
p_ap_encode_obj->fileId = fileId;
if (!p_ap_encode_obj->text_file_type)
{
OSErr err;
FSSpec file_spec;
char* path;
Bool do_magic = true;
/* First attempt to get the file's mime type via FE_FileType.
If that fails, we'll do a "magic_look"
*/
err = FSMakeFSSpec(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId, name, &file_spec);
if (err == noErr)
{
path = my_PathnameFromFSSpec(&file_spec);
if (path != NULL)
{
char* ignore;
FE_FileType(path, &do_magic, &magic_type, &ignore);
/*
if we ended up with the default type, dispose of it
so we can do a magic_look
*/
if (do_magic && magic_type)
XP_FREE(magic_type);
}
}
if (do_magic)
{
/*
** do a smart check for the file type.
*/
in_count = 256;
retval = FSRead(fileId, &in_count, rd_buff);
magic_type = magic_look(rd_buff, in_count);
/* don't forget to rewind the index to start point. */
SetFPos(fileId, fsFromStart, 0L);
}
}
else
{
magic_type = text_type; /* we already know it is a text type. */
}
/*
** the data portion header information.
*/
XP_SPRINTF(rd_buff,
"Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\""CRLF CRLF,
magic_type,
p_ap_encode_obj->fname,
p_ap_encode_obj->fname);
status = write_stream(p_ap_encode_obj,
rd_buff,
XP_STRLEN(rd_buff));
if (status != noErr)
return status;
}
while (retval == noErr)
{
if (BUFF_LEFT(p_ap_encode_obj) < 400)
break;
in_count = 256;
retval = FSRead(p_ap_encode_obj->fileId,
&in_count,
rd_buff);
if (in_count)
{
/* replace(rd_buff, in_count, '\r', '\n'); */
/* ** may be need to do character set conversion here for localization. ** */
status = to64(p_ap_encode_obj,
rd_buff,
in_count);
if (status != noErr)
return status;
}
}
if (retval == eofErr)
{
FSClose(p_ap_encode_obj->fileId);
status = finish64(p_ap_encode_obj);
if (status != noErr)
return status;
/* write out the boundary */
XP_SPRINTF(rd_buff,
CRLF"--%s--"CRLF CRLF,
p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj,
rd_buff,
XP_STRLEN(rd_buff));
if (status == noErr)
status = errDone;
}
return status;
}
static char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
** convert the stream in the inbuff to 64 format and put it in the out buff.
** To make the life easier, the caller will responcable of the cheking of the outbuff's bundary.
*/
PRIVATE int
to64(appledouble_encode_object* p_ap_encode_obj,
char *p,
int in_size)
{
int status;
int c1, c2, c3, ct;
unsigned char *inbuff = (unsigned char*)p;
ct = p_ap_encode_obj->ct; /* the char count left last time. */
/*
** resume the left state of the last conversion.
*/
switch (p_ap_encode_obj->state64)
{
case 0:
p_ap_encode_obj->c1 = c1 = *inbuff ++;
if (--in_size <= 0)
{
p_ap_encode_obj->state64 = 1;
return noErr;
}
p_ap_encode_obj->c2 = c2 = *inbuff ++;
if (--in_size <= 0)
{
p_ap_encode_obj->state64 = 2;
return noErr;
}
c3 = *inbuff ++; --in_size;
break;
case 1:
c1 = p_ap_encode_obj->c1;
p_ap_encode_obj->c2 = c2 = *inbuff ++;
if (--in_size <= 0)
{
p_ap_encode_obj->state64 = 2;
return noErr;
}
c3 = *inbuff ++; --in_size;
break;
case 2:
c1 = p_ap_encode_obj->c1;
c2 = p_ap_encode_obj->c2;
c3 = *inbuff ++; --in_size;
break;
}
while (in_size >= 0)
{
status = output64chunk(p_ap_encode_obj,
c1,
c2,
c3,
0);
if (status != noErr)
return status;
ct += 4;
if (ct > 71)
{
status = write_stream(p_ap_encode_obj,
CRLF,
2);
if (status != noErr)
return status;
ct = 0;
}
if (in_size <= 0)
{
p_ap_encode_obj->state64 = 0;
break;
}
c1 = (int)*inbuff++;
if (--in_size <= 0)
{
p_ap_encode_obj->c1 = c1;
p_ap_encode_obj->state64 = 1;
break;
}
c2 = *inbuff++;
if (--in_size <= 0)
{
p_ap_encode_obj->c1 = c1;
p_ap_encode_obj->c2 = c2;
p_ap_encode_obj->state64 = 2;
break;
}
c3 = *inbuff++;
in_size--;
}
p_ap_encode_obj->ct = ct;
return status;
}
/*
** clear the left base64 encodes.
*/
PRIVATE int
finish64(appledouble_encode_object* p_ap_encode_obj)
{
int status;
switch (p_ap_encode_obj->state64)
{
case 0:
break;
case 1:
status = output64chunk(p_ap_encode_obj,
p_ap_encode_obj->c1,
0,
0,
2);
break;
case 2:
status = output64chunk(p_ap_encode_obj,
p_ap_encode_obj->c1,
p_ap_encode_obj->c2,
0,
1);
break;
}
status = write_stream(p_ap_encode_obj, CRLF, 2);
p_ap_encode_obj->state64 = 0;
p_ap_encode_obj->ct = 0;
return status;
}
PRIVATE int output64chunk(
appledouble_encode_object* p_ap_encode_obj,
int c1, int c2, int c3, int pads)
{
char tmpstr[32];
char *p = tmpstr;
*p++ = basis_64[c1>>2];
*p++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
if (pads == 2)
{
*p++ = '=';
*p++ = '=';
}
else if (pads)
{
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
*p++ = '=';
}
else
{
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
*p++ = basis_64[c3 & 0x3F];
}
return write_stream(p_ap_encode_obj,
tmpstr,
p-tmpstr);
}
#endif /* if define XP_MAC */

View File

@@ -0,0 +1,615 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
*
* apple-double.c
* --------------
*
* The codes to do apple double encoding/decoding.
*
* 02aug95 mym created.
* 27sep95 mym Add the XP_Mac to ensure the cross-platform.
*
*/
#include "msg.h"
#include "appledbl.h"
#include "ad_codes.h"
#ifdef XP_MAC
#pragma warn_unusedarg off
#include "m_cvstrm.h"
#pragma cplusplus on
#include "InternetConfig.h"
#include "ufilemgr.h"
#include "BufferStream.h"
#include "Umimemap.h"
#include "uprefd.h"
#include "ulaunch.h"
void DecodingDone( appledouble_decode_object* p_ap_decode_obj );
OSErr my_FSSpecFromPathname(char* src_filename, FSSpec* fspec)
{
/* don't resolve aliases... */
return CFileMgr::FSSpecFromLocalUnixPath(src_filename, fspec, false);
}
char* my_PathnameFromFSSpec(FSSpec* fspec)
{
return CFileMgr::GetURLFromFileSpec(*fspec);
}
/* returns true if the resource fork should be sent */
XP_Bool isMacFile(char* filename)
{
Boolean returnValue = FALSE;
FSSpec fspec;
my_FSSpecFromPathname(filename, &fspec);
returnValue = CFileMgr::FileHasResourceFork(fspec);
/* always use IC even if the pref isn't checked since we have no
other way to determine if the resource is significant */
if ( returnValue )
{
CMimeMapper * mapper = CPrefs::sMimeTypes.FindMimeType(fspec);
if ( mapper )
{
returnValue = mapper->GetFileFlags()& ICmap_resource_fork_mask;
return returnValue;
}
// Get the Internet Config file mapping for this type
// and see if the existing resources are significant.
// First, get the type/creator of the file.
FInfo fileInfo;
OSErr err = ::FSpGetFInfo(&fspec, &fileInfo);
if (err == noErr)
{
if ( fileInfo.fdType == 'APPL' )
return TRUE;
ICMapEntry ent;
err = CInternetConfigInterface::GetInternetConfigFileMapping(fileInfo.fdType,
fileInfo.fdCreator,
fspec.name, &ent);
if (err == noErr)
{
// resource fork is significant if the resource fork mask bit is set
returnValue = (ent.flags & ICmap_resource_fork_mask) != 0;
}
}
}
return (XP_Bool) returnValue;
}
void DecodingDone( appledouble_decode_object* p_ap_decode_obj )
{
FSSpec fspec;
fspec.vRefNum = p_ap_decode_obj->vRefNum;
fspec.parID = p_ap_decode_obj->dirId;
fspec.name[0] = XP_STRLEN(p_ap_decode_obj->fname);
XP_STRCPY((char*)fspec.name+1, p_ap_decode_obj->fname);
CMimeMapper * mapper = CPrefs::sMimeTypes.FindMimeType(fspec);
if( mapper && (mapper->GetLoadAction() == CMimeMapper::Launch ) )
{
LFileBufferStream file( fspec );
LaunchFile( &file );
}
}
#pragma cplusplus reset
/*
* ap_encode_init
* --------------
*
* Setup the encode envirment
*/
int ap_encode_init(
appledouble_encode_object *p_ap_encode_obj,
char* fname,
char* separator)
{
FSSpec fspec;
if (my_FSSpecFromPathname(fname, &fspec) != noErr )
return -1;
XP_MEMSET(p_ap_encode_obj, 0, sizeof(appledouble_encode_object));
/*
** Fill out the source file inforamtion.
*/
XP_MEMCPY(p_ap_encode_obj->fname, fspec.name+1, *fspec.name);
p_ap_encode_obj->fname[*fspec.name] = '\0';
p_ap_encode_obj->vRefNum = fspec.vRefNum;
p_ap_encode_obj->dirId = fspec.parID;
p_ap_encode_obj->boundary = XP_STRDUP(separator);
return noErr;
}
/*
** ap_encode_next
** --------------
**
** return :
** noErr : everything is ok
** errDone : when encoding is done.
** errors : otherwise.
*/
int ap_encode_next(
appledouble_encode_object* p_ap_encode_obj,
char *to_buff,
int32 buff_size,
int32* real_size)
{
int status;
/*
** install the out buff now.
*/
p_ap_encode_obj->outbuff = to_buff;
p_ap_encode_obj->s_outbuff = buff_size;
p_ap_encode_obj->pos_outbuff = 0;
/*
** first copy the outstandind data in the overflow buff to the out buffer.
*/
if (p_ap_encode_obj->s_overflow)
{
status = write_stream(p_ap_encode_obj,
p_ap_encode_obj->b_overflow,
p_ap_encode_obj->s_overflow);
if (status != noErr)
return status;
p_ap_encode_obj->s_overflow = 0;
}
/*
** go the next processing stage based on the current state.
*/
switch (p_ap_encode_obj->state)
{
case kInit:
/*
** We are in the starting position, fill out the header.
*/
status = fill_apple_mime_header(p_ap_encode_obj);
if (status != noErr)
break; /* some error happens */
p_ap_encode_obj->state = kDoingHeaderPortion;
status = ap_encode_header(p_ap_encode_obj, true);
/* it is the first time to calling */
if (status == errDone)
{
p_ap_encode_obj->state = kDoneHeaderPortion;
}
else
{
break; /* we need more work on header portion. */
}
/*
** we are done with the header, so let's go to the data port.
*/
p_ap_encode_obj->state = kDoingDataPortion;
status = ap_encode_data(p_ap_encode_obj, true);
/* it is first time call do data portion */
if (status == errDone)
{
p_ap_encode_obj->state = kDoneDataPortion;
status = noErr;
}
break;
case kDoingHeaderPortion:
status = ap_encode_header(p_ap_encode_obj, false);
/* continue with the header portion. */
if (status == errDone)
{
p_ap_encode_obj->state = kDoneHeaderPortion;
}
else
{
break; /* we need more work on header portion. */
}
/*
** start the data portion.
*/
p_ap_encode_obj->state = kDoingDataPortion;
status = ap_encode_data(p_ap_encode_obj, true);
/* it is the first time calling */
if (status == errDone)
{
p_ap_encode_obj->state = kDoneDataPortion;
status = noErr;
}
break;
case kDoingDataPortion:
status = ap_encode_data(p_ap_encode_obj, false);
/* it is not the first time */
if (status == errDone)
{
p_ap_encode_obj->state = kDoneDataPortion;
status = noErr;
}
break;
case kDoneDataPortion:
#if 0
status = write_stream(p_ap_encode_obj,
"\n-----\n\n",
8);
if (status == noErr)
#endif
status = errDone; /* we are really done. */
break;
}
*real_size = p_ap_encode_obj->pos_outbuff;
return status;
}
/*
** ap_encode_end
** -------------
**
** clear the apple encoding.
*/
int ap_encode_end(
appledouble_encode_object *p_ap_encode_obj,
XP_Bool is_aborting)
{
/*
** clear up the apple doubler.
*/
if (p_ap_encode_obj == NULL)
return noErr;
if (p_ap_encode_obj->fileId) /* close the file if it is open. */
FSClose(p_ap_encode_obj->fileId);
FREEIF(p_ap_encode_obj->boundary); /* the boundary string. */
return noErr;
}
#endif /* the ifdef of XP_MAC */
/*
** The initial of the apple double decoder.
**
** Set up the next output stream based on the input.
*/
int ap_decode_init(
appledouble_decode_object* p_ap_decode_obj,
XP_Bool is_apple_single,
XP_Bool write_as_binhex,
void *closure)
{
XP_MEMSET(p_ap_decode_obj, 0, sizeof(appledouble_decode_object));
/* presume first buff starts a line */
p_ap_decode_obj->uu_starts_line = TRUE;
if (write_as_binhex)
{
p_ap_decode_obj->write_as_binhex = TRUE;
p_ap_decode_obj->binhex_stream = (NET_StreamClass*)closure;
p_ap_decode_obj->data_size = 0;
}
else
{
p_ap_decode_obj->write_as_binhex = FALSE;
p_ap_decode_obj->binhex_stream = NULL;
p_ap_decode_obj->context = (MWContext*)closure;
}
p_ap_decode_obj->is_apple_single = is_apple_single;
if (is_apple_single)
{
p_ap_decode_obj->encoding = kEncodeNone;
}
return NOERR;
}
static int ap_decode_state_machine(appledouble_decode_object* p_ap_decode_obj);
/*
* process the buffer
*/
int ap_decode_next(
appledouble_decode_object* p_ap_decode_obj,
char *in_buff,
int32 buff_size)
{
/*
** install the buff to the decoder.
*/
p_ap_decode_obj->inbuff = in_buff;
p_ap_decode_obj->s_inbuff = buff_size;
p_ap_decode_obj->pos_inbuff = 0;
/*
** run off the decode state machine
*/
return ap_decode_state_machine(p_ap_decode_obj);
}
PRIVATE int ap_decode_state_machine(
appledouble_decode_object* p_ap_decode_obj)
{
int status = NOERR;
int32 size;
switch (p_ap_decode_obj->state)
{
case kInit:
/*
** Make sure that there are stuff in the buff
** before we can parse the file head .
*/
if (p_ap_decode_obj->s_inbuff <=1 )
return NOERR;
if (p_ap_decode_obj->is_apple_single)
{
p_ap_decode_obj->state = kBeginHeaderPortion;
}
else
{
status = ap_seek_part_start(p_ap_decode_obj);
if (status != errDone)
return status;
p_ap_decode_obj->state = kBeginParseHeader;
}
status = ap_decode_state_machine(p_ap_decode_obj);
break;
case kBeginSeekBoundary:
p_ap_decode_obj->state = kSeekingBoundary;
status = ap_seek_to_boundary(p_ap_decode_obj, TRUE);
if (status == errDone)
{
p_ap_decode_obj->state = kBeginParseHeader;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kSeekingBoundary:
status = ap_seek_to_boundary(p_ap_decode_obj, FALSE);
if (status == errDone)
{
p_ap_decode_obj->state = kBeginParseHeader;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kBeginParseHeader:
p_ap_decode_obj->state = kParsingHeader;
status = ap_parse_header(p_ap_decode_obj, TRUE);
if (status == errDone)
{
if (p_ap_decode_obj->which_part == kDataPortion)
p_ap_decode_obj->state = kBeginDataPortion;
else if (p_ap_decode_obj->which_part == kHeaderPortion)
p_ap_decode_obj->state = kBeginHeaderPortion;
else
p_ap_decode_obj->state = kFinishing;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kParsingHeader:
status = ap_parse_header(p_ap_decode_obj, FALSE);
if (status == errDone)
{
if (p_ap_decode_obj->which_part == kDataPortion)
p_ap_decode_obj->state = kBeginDataPortion;
else if (p_ap_decode_obj->which_part == kHeaderPortion)
p_ap_decode_obj->state = kBeginHeaderPortion;
else
p_ap_decode_obj->state = kFinishing;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kBeginHeaderPortion:
p_ap_decode_obj->state = kProcessingHeaderPortion;
status = ap_decode_process_header(p_ap_decode_obj, TRUE);
if (status == errDone)
{
if (p_ap_decode_obj->is_apple_single)
p_ap_decode_obj->state = kBeginDataPortion;
else
p_ap_decode_obj->state = kBeginSeekBoundary;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kProcessingHeaderPortion:
status = ap_decode_process_header(p_ap_decode_obj, FALSE);
if (status == errDone)
{
if (p_ap_decode_obj->is_apple_single)
p_ap_decode_obj->state = kBeginDataPortion;
else
p_ap_decode_obj->state = kBeginSeekBoundary;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kBeginDataPortion:
p_ap_decode_obj->state = kProcessingDataPortion;
status = ap_decode_process_data(p_ap_decode_obj, TRUE);
if (status == errDone)
{
if (p_ap_decode_obj->is_apple_single)
p_ap_decode_obj->state = kFinishing;
else
p_ap_decode_obj->state = kBeginSeekBoundary;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kProcessingDataPortion:
status = ap_decode_process_data(p_ap_decode_obj, FALSE);
if (status == errDone)
{
if (p_ap_decode_obj->is_apple_single)
p_ap_decode_obj->state = kFinishing;
else
p_ap_decode_obj->state = kBeginSeekBoundary;
status = ap_decode_state_machine(p_ap_decode_obj);
}
break;
case kFinishing:
if (p_ap_decode_obj->write_as_binhex)
{
if (p_ap_decode_obj->tmpfd)
{
/*
** It is time to append the data fork to bin hex encoder.
**
** The reason behind this dirt work is resource fork is the last
** piece in the binhex, while it is the first piece in apple double.
*/
XP_FileSeek(p_ap_decode_obj->tmpfd, 0L, SEEK_SET);
while (p_ap_decode_obj->data_size > 0)
{
char buff[1024];
size = MIN(1024, p_ap_decode_obj->data_size);
XP_FileRead(buff, size, p_ap_decode_obj->tmpfd);
status = (*p_ap_decode_obj->binhex_stream->put_block)
(p_ap_decode_obj->binhex_stream->data_object,
buff,
size);
p_ap_decode_obj->data_size -= size;
}
}
if (p_ap_decode_obj->data_size <= 0)
{
/* CALL put_block with size == 0 to close a part. */
status = (*p_ap_decode_obj->binhex_stream->put_block)
(p_ap_decode_obj->binhex_stream->data_object,
NULL,
0);
if (status != NOERR)
break;
/* and now we are really done. */
status = errDone;
}
else
status = NOERR;
}
break;
}
return (status == errEOB) ? NOERR : status;
}
int ap_decode_end(
appledouble_decode_object* p_ap_decode_obj,
XP_Bool is_aborting)
{
/*
** clear up the apple doubler object.
*/
if (p_ap_decode_obj == NULL)
return NOERR;
FREEIF(p_ap_decode_obj->boundary0);
#ifdef XP_MAC
if (p_ap_decode_obj->fileId)
FSClose(p_ap_decode_obj->fileId);
if( p_ap_decode_obj->vRefNum )
FlushVol(nil, p_ap_decode_obj->vRefNum );
#endif
if (p_ap_decode_obj->write_as_binhex)
{
/*
** make sure close the binhex stream too.
*/
if (is_aborting)
{
(*p_ap_decode_obj->binhex_stream->abort)
(p_ap_decode_obj->binhex_stream->data_object, 0);
}
else
{
(*p_ap_decode_obj->binhex_stream->complete)
(p_ap_decode_obj->binhex_stream->data_object);
}
if (p_ap_decode_obj->tmpfd)
XP_FileClose(p_ap_decode_obj->tmpfd);
if (p_ap_decode_obj->tmpfname)
{
XP_FileRemove(p_ap_decode_obj->tmpfname, xpTemporary);
/* remove tmp file if we used it */
XP_FREE(p_ap_decode_obj->tmpfname); /* and release the file name too. */
}
}
else if (p_ap_decode_obj->fd)
{
XP_FileClose(p_ap_decode_obj->fd);
}
#ifdef XP_MAC
if( !is_aborting )
DecodingDone( p_ap_decode_obj);
#endif
return NOERR;
}

View File

@@ -0,0 +1,232 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* AppleDouble.h
* -------------
*
* The header file for a stream based apple single/double encodor/decodor.
*
* 2aug95 mym
*
*/
#ifndef AppleDouble_h
#define AppleDouble_h
#include "xp.h"
#include "xp_file.h"
#include "msg.h"
#define NOERR 0
#define errDone 1
/* Done with current operation. */
#define errEOB 2
/* End of a buffer. */
#define errEOP 3
/* End of a Part. */
#define errMemoryAlloc MK_OUT_OF_MEMORY
#define errDataCrupt -1
#define errDiskFull MK_DISK_FULL
#define errFileOpen MK_UNABLE_TO_OPEN_TMP_FILE
#define errVersion -1
#define errFileWrite MK_MIME_ERROR_WRITING_FILE
#define errDecoding -1
#define errUsrCancel MK_INTERRUPTED
/*
** The envirment block data type.
*/
enum
{
kInit,
kDoingHeaderPortion,
kDoneHeaderPortion,
kDoingDataPortion,
kDoneDataPortion
};
typedef struct _appledouble_encode_object
{
char fname[64];
int32 dirId;
int16 vRefNum;
int16 fileId; /* the id for the open file (data/resource fork) */
int state;
int text_file_type; /* if the file has a text file type with it. */
char *boundary; /* the boundary string. */
int status; /* the error code if anyerror happens. */
char b_overflow[200];
int s_overflow;
int state64; /* the left over state of base64 enocding */
int ct; /* the character count of base64 encoding */
int c1, c2; /* the left of the last base64 encoding */
char *outbuff; /* the outbuff by the caller. */
int s_outbuff; /* the size of the buffer. */
int pos_outbuff; /* the offset in the current buffer. */
} appledouble_encode_object;
/* The possible content transfer encodings */
enum
{
kEncodeNone,
kEncodeQP,
kEncodeBase64,
kEncodeUU
};
enum
{
kGeneralMine,
kAppleDouble,
kAppleSingle
};
enum
{
kInline,
kDontCare
};
enum
{
kHeaderPortion,
kDataPortion
};
/* the decode states. */
enum
{
kBeginParseHeader = 3,
kParsingHeader,
kBeginSeekBoundary,
kSeekingBoundary,
kBeginHeaderPortion,
kProcessingHeaderPortion,
kBeginDataPortion,
kProcessingDataPortion,
kFinishing
};
/* uuencode states */
enum
{
kWaitingForBegin = (int) 0,
kBegin,
kMainBody,
kEnd
};
typedef struct _appledouble_decode_object
{
int is_binary;
int is_apple_single; /* if the object encoded is in apple single */
int write_as_binhex;
int messagetype;
char* boundary0; /* the boundary for the enclosure. */
int deposition; /* the deposition. */
int encoding; /* the encoding method. */
int which_part;
char fname[256];
#ifdef XP_MAC
FSSpec* mSpec; /* the filespec to save the file to*/
int16 vRefNum;
int32 dirId;
int16 fileId; /* the id for the open file (data/resource fork) */
#endif
XP_File fd; /* the fd for data fork work. */
MWContext *context;
NET_StreamClass* binhex_stream; /* the stream to output as binhex output.*/
int state;
int rksize; /* the resource fork size count. */
int dksize; /* the data fork size count. */
int status; /* the error code if anyerror happens. */
char b_leftover[256];
int s_leftover;
int encode; /* the encode type of the message. */
int state64; /* the left over state of base64 enocding */
int left; /* the character count of base64 encoding */
int c[4]; /* the left of the last base64 encoding */
int uu_starts_line; /* is decoder at the start of a line? (uuencode) */
int uu_state; /* state w/r/t the uuencode body */
int uu_bytes_written; /* bytes written from the current tuple (uuencode) */
int uu_line_bytes; /* encoded bytes remaining in the current line (uuencode) */
char *inbuff; /* the outbuff by the caller. */
int s_inbuff; /* the size of the buffer. */
int pos_inbuff; /* the offset in the current buffer. */
char* tmpfname; /* the temp file to hold the decode data fork */
/* when doing the binhex exporting. */
XP_File tmpfd;
int32 data_size; /* the size of the data in the tmp file. */
} appledouble_decode_object;
/*
** The protypes.
*/
XP_BEGIN_PROTOS
int ap_encode_init(appledouble_encode_object *p_ap_encode_obj,
char* fname,
char* separator);
int ap_encode_next(appledouble_encode_object* p_ap_encode_obj,
char *to_buff,
int32 buff_size,
int32* real_size);
int ap_encode_end(appledouble_encode_object* p_ap_encode_obj,
XP_Bool is_aborting);
int ap_decode_init(appledouble_decode_object* p_ap_decode_obj,
XP_Bool is_apple_single,
XP_Bool write_as_bin_hex,
void *closure);
int ap_decode_next(appledouble_decode_object* p_ap_decode_obj,
char *in_buff,
int32 buff_size);
int ap_decode_end(appledouble_decode_object* p_ap_decode_obj,
XP_Bool is_aborting);
XP_END_PROTOS
#endif

View File

@@ -0,0 +1,411 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
**
** Binhex_stream.c
** ---------------
**
** The code for the binhex encode/decode stream.
**
** 20sep95 mym Created.
**
*/
#include "msg.h"
#include "appledbl.h"
#include "m_binhex.h"
#include "m_cvstrm.h"
#include "ad_codes.h"
#ifdef XP_MAC
#pragma warn_unusedarg off
#endif /* XP_MAC */
/*
** -----------------------------------------------------------
**
** The BinHex encode writer stream.
**
** -----------------------------------------------------------
*/
extern int MK_MIME_ERROR_WRITING_FILE;
#define WORKING_BUFF_SIZE 8192
typedef struct
{
binhex_encode_object bh_encode_obj;
char *buff; /* the working buff */
int32 s_buff; /* the size of workiong buff. */
XP_File fp;
char *fname; /* the filename for file holding the encoding */
} BinHexEncodeObject ;
/*
** Let's go "l" characters forward of the encoding for this write.
** Note:
** "s" is just a dummy paramter.
*/
PRIVATE int net_BinHex_Encode_Write (void *dataObject, const char* s, int32 l)
{
int status = 0;
BinHexEncodeObject * obj = (BinHexEncodeObject*)dataObject;
int32 count;
int32 size;
do
{
size = obj->s_buff * 11 / 16;
size = MIN(l, size);
status = binhex_encode_next(&(obj->bh_encode_obj),
(char*)s,
size,
obj->buff,
obj->s_buff,
&count);
if (status == NOERR || status == errDone)
{
/*
* we get the encode data, so call the next stream to write it to the disk.
*/
if ((int) XP_FileWrite(obj->buff, count, obj->fp) != count )
return errFileWrite;
}
if (status < 0) /* abort */
break;
l -= size;
s += size;
} while (l > 0);
return status;
}
PRIVATE unsigned int net_BinHex_Encode_Ready (NET_StreamClass *dataObject)
{
return(MAX_WRITE_READY); /* always ready for writing */
}
PRIVATE void net_BinHex_Encode_Complete (void *dataObject)
{
int32 count, len = 0;
BinHexEncodeObject *obj = (BinHexEncodeObject *)dataObject;
/*
** push the close part.
*/
len = binhex_encode_next(&(obj->bh_encode_obj),
NULL,
0,
obj->buff,
obj->s_buff,
&count); /* this help us generate the finishing */
len = XP_FileWrite(obj->buff, count, obj->fp);
/*
** time to do some dirty work -- fix the real file size.
** (since we can only know by now)
*/
binhex_reencode_head(&(obj->bh_encode_obj),
obj->buff,
obj->s_buff,
&count); /* get the head part encoded again */
XP_FileSeek(obj->fp, 0L, SEEK_SET); /* and override the previous dummy */
XP_FileWrite(obj->buff, count, obj->fp);
binhex_encode_end(&(obj->bh_encode_obj), FALSE); /* now we get a real ending */
if (obj->fp)
{
XP_FileClose(obj->fp); /* we are done with the target file */
FREEIF(obj->fname); /* free the space for the file name */
}
FREEIF(obj->buff); /* and free the working buff. */
XP_FREE(obj);
}
PRIVATE void net_BinHex_Encode_Abort (void *dataObject, int status)
{
BinHexEncodeObject * obj = (BinHexEncodeObject*)dataObject;
binhex_encode_end(&(obj->bh_encode_obj), TRUE); /* it is an aborting exist... */
if (obj->fp)
{
XP_FileClose(obj->fp); /* we are aboring with the decoding */
XP_FileRemove(obj->fname, xpURL);
/* remove the incomplete file. */
FREEIF (obj->fname); /* free the space for the file name */
}
FREEIF(obj->buff); /* free the working buff. */
XP_FREE(obj);
}
/*
** Will create a apple double encode stream:
**
** -> take the filename as the input source (it needs to be a mac file.)
** -> tkae a stream to take care of the writing to a temp file.
*/
PUBLIC NET_StreamClass *
fe_MakeBinHexEncodeStream (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id,
char* dst_filename )
{
BinHexEncodeObject* obj;
NET_StreamClass* stream;
char* working_buff = NULL;
int bSize = WORKING_BUFF_SIZE;
TRACEMSG(("Setting up apple encode stream. Have URL: %s\n", URL_s->address));
stream = XP_NEW(NET_StreamClass);
if(stream == NULL)
return(NULL);
obj = XP_NEW(BinHexEncodeObject);
if (obj == NULL)
{
XP_FREE (stream);
return(NULL);
}
while (!working_buff && (bSize >= 512))
{
working_buff = (char *)XP_ALLOC(bSize);
if (!working_buff)
bSize /= 2;
}
if (working_buff == NULL)
{
XP_FREE (obj);
XP_FREE (stream);
return (NULL);
}
stream->name = "BinHex Encode";
stream->complete = (MKStreamCompleteFunc) net_BinHex_Encode_Complete;
stream->abort = (MKStreamAbortFunc) net_BinHex_Encode_Abort;
stream->put_block = (MKStreamWriteFunc) net_BinHex_Encode_Write;
stream->is_write_ready = (MKStreamWriteReadyFunc) net_BinHex_Encode_Ready;
stream->data_object = obj; /* document info object */
stream->window_id = window_id;
obj->fname = XP_STRDUP(dst_filename);
obj->fp = XP_FileOpen(obj->fname, xpURL, XP_FILE_TRUNCATE);
/* this file will hold all the encoded data */
if (obj->fp == NULL)
{
XP_FREE(working_buff); /* if we can't open the target file, roll back then */
if(obj->fname) XP_FREE(obj->fname);
XP_FREE (obj);
XP_FREE (stream);
return (NULL);
}
obj->buff = working_buff;
obj->s_buff = WORKING_BUFF_SIZE;
/*
** setup all the need information on the apple double encoder.
*/
binhex_encode_init(&(obj->bh_encode_obj)); /* pass the file name of the source.*/
TRACEMSG(("Returning stream from NET_BinHexEncoder\n"));
return stream;
}
/*
** -----------------------------------------------------------
**
** The BinHex decode writer stream.
**
** -----------------------------------------------------------
*/
typedef struct BinHexDecodeObject
{
binhex_decode_object bh_decode_obj;
char* in_buff;
int32 bytes_in_buff;
} BinHexDecodeObject;
PRIVATE int
net_BinHex_Decode_Write (
void *dataObject, const char* s, int32 l)
{
int status = NOERR;
BinHexDecodeObject * obj = (BinHexDecodeObject*)dataObject;
int32 size;
if (obj->bytes_in_buff + l > 1024)
{
size = 1024 - obj->bytes_in_buff;
XP_MEMCPY(obj->in_buff+obj->bytes_in_buff,
s,
size);
s += size;
l -= size;
status = binhex_decode_next(&(obj->bh_decode_obj),
obj->in_buff,
1024);
if (status != NOERR)
return status;
obj->bytes_in_buff = 0;
}
if (l > 1024)
{
/* we are sure that obj->bytes_in_buff == 0 at this point. */
status = binhex_decode_next(&(obj->bh_decode_obj),
s,
l);
}
else
{
XP_MEMCPY(obj->in_buff+obj->bytes_in_buff,
s,
l);
obj->bytes_in_buff += l;
}
return status;
}
/*
* is the stream ready for writeing?
*/
PRIVATE unsigned int net_BinHex_Decode_Ready (void *stream)
{
return(MAX_WRITE_READY); /* always ready for writing */
}
PRIVATE void net_BinHex_Decode_Complete (void *dataObject)
{
BinHexDecodeObject *obj = (BinHexDecodeObject *) dataObject;
if (obj->bytes_in_buff)
{
/* do the last calls. */
binhex_decode_next(&(obj->bh_decode_obj),
(char *)obj->in_buff,
obj->bytes_in_buff);
obj->bytes_in_buff = 0;
}
binhex_decode_end(&(obj->bh_decode_obj), FALSE); /* it is a normal clean up classes. */
if (obj->in_buff)
XP_FREE(obj->in_buff);
XP_FREE(obj);
}
PRIVATE void net_BinHex_Decode_Abort (void *dataObject, int status)
{
BinHexDecodeObject *obj = (BinHexDecodeObject *)dataObject;
binhex_decode_end(&(obj->bh_decode_obj), TRUE); /* it is an abort. */
if (obj->in_buff)
XP_FREE(obj->in_buff);
XP_FREE(obj);
}
/*
** Create the bin hex decode stream.
**
*/
PUBLIC NET_StreamClass *
fe_MakeBinHexDecodeStream (int format_out,
void *data_obj,
URL_Struct *URL_s,
MWContext *window_id )
{
BinHexDecodeObject* obj;
NET_StreamClass* stream;
TRACEMSG(("Setting up bin hex decode stream. Have URL: %s\n", URL_s->address));
stream = XP_NEW(NET_StreamClass);
if(stream == NULL)
return(NULL);
obj = XP_NEW(BinHexDecodeObject);
if (obj == NULL)
{
XP_FREE(stream);
return(NULL);
}
if ((obj->in_buff = (char *)XP_ALLOC(1024)) == NULL)
{
XP_FREE(obj);
XP_FREE(stream);
return (NULL);
}
stream->name = "BinHex Decoder";
stream->complete = (MKStreamCompleteFunc) net_BinHex_Decode_Complete;
stream->abort = (MKStreamAbortFunc) net_BinHex_Decode_Abort;
stream->put_block = (MKStreamWriteFunc) net_BinHex_Decode_Write;
stream->is_write_ready = (MKStreamWriteReadyFunc) net_BinHex_Decode_Ready;
stream->data_object = obj;
stream->window_id = window_id;
/*
** Some initial to the object.
*/
obj->bytes_in_buff = 0;
/*
** setup all the need information on the apple double encoder.
*/
binhex_decode_init(&(obj->bh_decode_obj),window_id);
#ifdef XP_MAC
obj->bh_decode_obj.mSpec = (FSSpec*)( URL_s->fe_data );
#endif
TRACEMSG(("Returning stream from NET_BinHexDecode\n"));
return stream;
}

View File

@@ -0,0 +1,221 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "xp.h"
#include "bytearr.h"
#ifdef XP_WIN16
#define SIZE_T_MAX 0xFF80 // Maximum allocation size
#define MAX_ARR_ELEMS SIZE_T_MAX/sizeof(BYTE)
#endif
XPByteArray::XPByteArray()
{
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
XPByteArray::~XPByteArray()
{
SetSize(0);
}
/////////////////////////////////////////////////////////////////////////////
int XPByteArray::GetSize() const
{
return m_nSize;
}
XP_Bool XPByteArray::SetSize(int nSize)
{
XP_ASSERT(nSize >= 0);
#ifdef MAX_ARR_ELEMS
if (nSize > MAX_ARR_ELEMS);
{
XP_ASSERT(nSize <= MAX_ARR_ELEMS); // Will fail
return FALSE;
}
#endif
if (nSize == 0)
{
// Remove all elements
XP_FREE(m_pData);
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
else if (m_pData == NULL)
{
// Create a new array
m_nMaxSize = MAX(8, nSize);
m_pData = (BYTE *)XP_CALLOC(1, m_nMaxSize * sizeof(BYTE));
if (m_pData)
m_nSize = nSize;
else
m_nSize = m_nMaxSize = 0;
}
else if (nSize <= m_nMaxSize)
{
// The new size is within the current maximum size, make sure new
// elements are to initialized to zero
if (nSize > m_nSize)
XP_MEMSET(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(BYTE));
m_nSize = nSize;
}
else
{
// The array needs to grow, figure out how much
int nGrowBy, nMaxSize;
nGrowBy = MIN(1024, MAX(8, m_nSize / 8));
nMaxSize = MAX(nSize, m_nMaxSize + nGrowBy);
#ifdef MAX_ARR_ELEMS
nMaxSize = MIN(MAX_ARR_ELEMS, nMaxSize);
#endif
BYTE *pNewData = (BYTE *)XP_ALLOC(nMaxSize * sizeof(BYTE));
if (pNewData)
{
// Copy the data from the old array to the new one
XP_MEMCPY(pNewData, m_pData, m_nSize * sizeof(BYTE));
// Zero out the remaining elements
XP_MEMSET(&pNewData[m_nSize], 0, (nSize - m_nSize) * sizeof(BYTE));
m_nSize = nSize;
m_nMaxSize = nMaxSize;
// Free the old array
XP_FREE(m_pData);
m_pData = pNewData;
}
}
return nSize == m_nSize;
}
/////////////////////////////////////////////////////////////////////////////
BYTE &XPByteArray::ElementAt(int nIndex)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
BYTE XPByteArray::GetAt(int nIndex) const
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
void XPByteArray::SetAt(int nIndex, BYTE newElement)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
int XPByteArray::Add(BYTE newElement)
{
int nIndex = m_nSize;
#ifdef MAX_ARR_ELEMS
if (nIndex >= MAX_ARR_ELEMS)
return -1;
#endif
SetAtGrow(nIndex, newElement);
return nIndex;
}
void XPByteArray::InsertAt(int nIndex, BYTE newElement, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nCount > 0);
if (nIndex >= m_nSize)
{
// If the new element is after the end of the array, grow the array
SetSize(nIndex + nCount);
}
else
{
// The element is being insert inside the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount);
// Move the data after the insertion point
XP_MEMMOVE(&m_pData[nIndex + nCount], &m_pData[nIndex],
(nOldSize - nIndex) * sizeof(BYTE));
}
// Insert the new elements
XP_ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
void XPByteArray::InsertAt(int nStartIndex, const XPByteArray *pNewArray)
{
XP_ASSERT(nStartIndex >= 0);
XP_ASSERT(pNewArray != NULL);
if (pNewArray->GetSize() > 0)
{
InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
for (int i = 1; i < pNewArray->GetSize(); i++)
m_pData[nStartIndex + i] = pNewArray->GetAt(i);
}
}
void XPByteArray::RemoveAll()
{
SetSize(0);
}
void XPByteArray::RemoveAt(int nIndex, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nIndex + nCount <= m_nSize);
if (nCount > 0)
{
// Make sure not to overstep the end of the array
int nMoveCount = m_nSize - (nIndex + nCount);
if (nCount && nMoveCount >= 0)
XP_MEMMOVE(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(BYTE));
m_nSize -= nCount;
}
}
void XPByteArray::SetAtGrow(int nIndex, BYTE newElement)
{
XP_ASSERT(nIndex >= 0);
if (nIndex >= m_nSize)
SetSize(nIndex+1);
m_pData[nIndex] = newElement;
}

View File

@@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _ByteArray_H_
#define _ByteArray_H_
#if !defined(_WINDOWS) && !defined(XP_OS2)
typedef uint8 BYTE;
#endif
class XPByteArray
{
public:
// Construction/destruction
XPByteArray();
~XPByteArray();
// State/attribute member functions
int GetSize() const;
XP_Bool SetSize(int nNewSize);
// Accessor member functions
BYTE &ElementAt(int nIndex);
BYTE GetAt(int nIndex) const;
void SetAt(int nIndex, BYTE newElement);
// Insertion/deletion member functions
int Add(BYTE newElement);
void InsertAt(int nIndex, BYTE newElement, int nCount = 1);
void InsertAt(int nStartIndex, const XPByteArray *pNewArray);
void RemoveAll();
void RemoveAt(int nIndex, int nCount = 1);
void SetAtGrow(int nIndex, BYTE newElement);
// Overloaded operators
BYTE operator[](int nIndex) const { return GetAt(nIndex); }
BYTE &operator[](int nIndex) { return ElementAt(nIndex); }
// Use the result carefully, it is only valid until another function called on the array
BYTE *GetArray(void) {return((BYTE *)m_pData);}
protected:
// Member data
int m_nSize;
int m_nMaxSize;
BYTE* m_pData;
};
#endif

View File

@@ -0,0 +1,281 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "xp.h"
#include "dwordarr.h"
#include "xp_qsort.h"
#ifdef XP_WIN16
#define SIZE_T_MAX 0xFF80 // Maximum allocation size
#define MAX_ARR_ELEMS SIZE_T_MAX/sizeof(uint32)
#endif
XPDWordArray::XPDWordArray()
{
m_nSize = 0;
m_nMaxSize = 0;
m_nGrowBy = 0;
m_pData = NULL;
}
XPDWordArray::~XPDWordArray()
{
SetSize(0);
}
/////////////////////////////////////////////////////////////////////////////
int XPDWordArray::GetSize() const
{
return m_nSize;
}
XP_Bool XPDWordArray::SetSize(int nSize, int nGrowBy)
{
XP_ASSERT(nSize >= 0);
if (nGrowBy >= 0)
m_nGrowBy = nGrowBy;
#ifdef MAX_ARR_ELEMS
if (nSize > MAX_ARR_ELEMS);
{
XP_ASSERT(nSize <= MAX_ARR_ELEMS); // Will fail
return FALSE;
}
#endif
if (nSize == 0)
{
// Remove all elements
XP_FREE(m_pData);
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
else if (m_pData == NULL)
{
// Create a new array
m_nMaxSize = MAX(8, nSize);
m_pData = (uint32 *)XP_CALLOC(1, m_nMaxSize * sizeof(uint32));
if (m_pData)
m_nSize = nSize;
else
m_nSize = m_nMaxSize = 0;
}
else if (nSize <= m_nMaxSize)
{
// The new size is within the current maximum size, make sure new
// elements are to initialized to zero
if (nSize > m_nSize)
XP_MEMSET(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(uint32));
m_nSize = nSize;
}
else
{
// The array needs to grow, figure out how much
int nMaxSize;
nGrowBy = MAX(m_nGrowBy, MIN(1024, MAX(8, m_nSize / 8)));
nMaxSize = MAX(nSize, m_nMaxSize + nGrowBy);
#ifdef MAX_ARR_ELEMS
nMaxSize = MIN(MAX_ARR_ELEMS, nMaxSize);
#endif
uint32 *pNewData = (uint32 *)XP_ALLOC(nMaxSize * sizeof(uint32));
if (pNewData)
{
// Copy the data from the old array to the new one
XP_MEMCPY(pNewData, m_pData, m_nSize * sizeof(uint32));
// Zero out the remaining elements
XP_MEMSET(&pNewData[m_nSize], 0, (nSize - m_nSize) * sizeof(uint32));
m_nSize = nSize;
m_nMaxSize = nMaxSize;
// Free the old array
XP_FREE(m_pData);
m_pData = pNewData;
}
}
return nSize == m_nSize;
}
/////////////////////////////////////////////////////////////////////////////
uint32 &XPDWordArray::ElementAt(int nIndex)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
uint32 XPDWordArray::GetAt(int nIndex) const
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
uint32 *XPDWordArray::GetData()
{
return m_pData;
}
void XPDWordArray::SetAt(int nIndex, uint32 newElement)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
int XPDWordArray::Add(uint32 newElement)
{
int nIndex = m_nSize;
#ifdef MAX_ARR_ELEMS
if (nIndex >= MAX_ARR_ELEMS)
return -1;
#endif
SetAtGrow(nIndex, newElement);
return nIndex;
}
uint XPDWordArray::Add(uint32 *elementPtr, uint numElements)
{
if (SetSize(m_nSize + numElements))
XP_MEMCPY(m_pData + m_nSize, elementPtr, numElements * sizeof(uint32));
return m_nSize;
}
uint32 *XPDWordArray::CloneData()
{
uint32 *copyOfData = (uint32 *)XP_ALLOC(m_nSize * sizeof(uint32));
if (copyOfData)
XP_MEMCPY(copyOfData, m_pData, m_nSize * sizeof(uint32));
return copyOfData;
}
void XPDWordArray::InsertAt(int nIndex, uint32 newElement, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nCount > 0);
if (nIndex >= m_nSize)
{
// If the new element is after the end of the array, grow the array
SetSize(nIndex + nCount);
}
else
{
// The element is being insert inside the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount);
// Move the data after the insertion point
XP_MEMMOVE(&m_pData[nIndex + nCount], &m_pData[nIndex],
(nOldSize - nIndex) * sizeof(uint32));
}
// Insert the new elements
XP_ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
void XPDWordArray::InsertAt(int nStartIndex, const XPDWordArray *pNewArray)
{
XP_ASSERT(nStartIndex >= 0);
XP_ASSERT(pNewArray != NULL);
if (pNewArray->GetSize() > 0)
{
InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
for (int i = 1; i < pNewArray->GetSize(); i++)
m_pData[nStartIndex + i] = pNewArray->GetAt(i);
}
}
void XPDWordArray::RemoveAll()
{
SetSize(0);
}
void XPDWordArray::RemoveAt(int nIndex, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nIndex + nCount <= m_nSize);
if (nCount > 0)
{
// Make sure not to overstep the end of the array
int nMoveCount = m_nSize - (nIndex + nCount);
if (nCount && nMoveCount)
XP_MEMMOVE(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(uint32));
m_nSize -= nCount;
}
}
void XPDWordArray::SetAtGrow(int nIndex, uint32 newElement)
{
XP_ASSERT(nIndex >= 0);
if (nIndex >= m_nSize)
SetSize(nIndex+1);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
void XPDWordArray::CopyArray(XPDWordArray *oldA)
{
CopyArray(*oldA);
}
void XPDWordArray::CopyArray(XPDWordArray &oldA)
{
if (m_pData)
XP_FREE(m_pData);
m_nSize = oldA.m_nSize;
m_nMaxSize = oldA.m_nMaxSize;
m_pData = (uint32 *)XP_ALLOC(m_nSize * sizeof(uint32));
if (m_pData)
XP_MEMCPY(m_pData, oldA.m_pData, m_nSize * sizeof(uint32));
}
/////////////////////////////////////////////////////////////////////////////
static int CompareDWord (const void *v1, const void *v2)
{
// QuickSort callback to compare array values
uint32 i1 = *(uint32 *)v1;
uint32 i2 = *(uint32 *)v2;
return i1 - i2;
}
void XPDWordArray::QuickSort (int (*compare) (const void *elem1, const void *elem2))
{
if (m_nSize > 1)
XP_QSORT (m_pData, m_nSize, sizeof(void*), compare ? compare : CompareDWord);
}

View File

@@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _DWordArray_H_
#define _DWordArray_H_
class XPDWordArray
{
public:
// Construction/destruction
XPDWordArray();
~XPDWordArray();
// State/attribute member functions
int GetSize() const;
XP_Bool SetSize(int nNewSize, int nGrowBy = -1);
// Accessor member functions
uint32 &ElementAt(int nIndex);
uint32 GetAt(int nIndex) const;
uint32 *GetData();
void SetAt(int nIndex, uint32 newElement);
// Insertion/deletion member functions
int Add(uint32 newElement);
uint Add(uint32 *elementPtr, uint numElements);
void InsertAt(int nIndex, uint32 newElement, int nCount = 1);
void InsertAt(int nStartIndex, const XPDWordArray *pNewArray);
void RemoveAll();
void RemoveAt(int nIndex, int nCount = 1);
void SetAtGrow(int nIndex, uint32 newElement);
// Sorting member functions
void QuickSort(int (*compare) (const void *elem1, const void *elem2) = NULL);
// Overloaded operators
uint32 operator[](int nIndex) const { return GetAt(nIndex); }
uint32 &operator[](int nIndex) { return ElementAt(nIndex); }
// Miscellaneous member functions
uint32 *CloneData();
void CopyArray(XPDWordArray *oldA);
void CopyArray(XPDWordArray &oldA);
protected:
// Member data
int m_nSize;
int m_nMaxSize;
int m_nGrowBy;
uint32* m_pData;
};
#endif // _DWordArray_H_

View File

@@ -0,0 +1,118 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// errcode.h
#ifndef _ERRCODE_H_
#define _ERRCODE_H_
/*
** Error classifications (Database, RPC, Network, etc)
**
** Each error classification defines a range of up to 0xffff error codes.
**
** The top word of an msgERR is the classification, the low byte is an error
** offset within that classification.
**
** For diagnostic purposes, each classification can register it's strings for GetErrorString
** support. These are NOT nationalizable strings; the string tables are autogenerated from the
** MsgError() macro machinery, not stored in .rc files. They're intended for use in debugging,
** logfiles, etc.
*/
typedef uint32 MsgERR;
typedef MsgERR msgErrorClass;
#define msgErrorDb 0xFF000000 /* DB errors (generic) */
#define msgErrorVw 0xF8000000 /* View layer */
#define msgErrorMisc 0xF0000000 /* Random miscellaneous errors. */
#define msgErrorOk 0x00000000
/*
** GetErrorClass(msgERR)
**
** Returns classification range for an error.
**
** For example,
** if (GetErrorClass(err) == msgErrorRp)
** Alert("Problem chatting with forum service.");
**
*/
#define GetErrorClass(err) ((err) & ((MsgERR) 0xFFFF0000))
/*
** RegisterErrorClass (msgErrorClass, pFn)
**
** Register a function to return error-strings in the given class.
**
** (Note: this could be best done by automatically building a linked list of
** diagnostic routines/classes - by simply using a C++ class for error
** classes, and a static constructor to link each class into the queue.
** However, we've had problems with static constructors within DLL's
** that use MFC and DLL's on NT - so we're avoiding them for now.)
**
** See dberror.cpp (in the database) for an example of an auto-generated diagnostic
** map. The error-code to string mapping function implementation can be generated
** automatically, but the client must register the function manually.
**
** There is no limit on how many ranges a given diagnostic function might handle.
** The function must be registered once for each class, of course.
**
** Normally there will be a function for every specific .h that defines error codes
** (whether that .h defines one or more classes of error codes). For example,
** dberror.h defines 3 error class ranges, so the DB registers one diagnostic function
** that handles those 3 classes accordingly.
**
*/
//typedef const char * (msgCALLBACK *msgErrorDiagnosticCallback) (msgERR);
//extern void RegisterErrorClass (msgErrorClass, msgErrorDiagnosticCallback pFn);
/*
** NOTE: remainder of this file may be multiply-included
** place all one-shot definitions above this point
*/
#endif // __msgERROR_H__
/*
** Within an error-class range, the errors are allocated/declared independently.
** See, for example, dberror.h, rperror.h, ecerror.h, etc.
*/
/* msgError: wrapper-macro for an error code definition */
#ifndef MsgError
#define MsgError(errorclass, name, offset) const MsgERR name = (MsgERR) (errorclass + offset);
#endif
/* msgErrorDiagnostic: causes wrapper-macro to generate a diagnostic string */
#ifndef MsgErrorDiagnostic
#define MsgErrorDiagnostic(errorclass, name, offset) case ((errorclass)+(offset)): return #name;
#endif
/*
** msgSUCCESS - universal no-error indication (zero).
** '! msgERR' is guaranteed to mean success.
*/
#ifndef MsgErrorBasic
#define MsgErrorBasic
MsgError (msgErrorOk, eSUCCESS, 0x0000) /* 0 Success */
MsgError (msgErrorMisc, eUNKNOWN, 0x0001) // 1 Something weird
// happened.
#endif

View File

@@ -0,0 +1,54 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef DBERROR_H
#define DBERROR_H
#include "errcode.h"
/* General errors */
MsgError (msgErrorDb, eFAILURE, 0xFFFF) /* -1 Unqualified DB failure */
MsgError (msgErrorDb, eBAD_PARAMETER, 0xFFFE) /* -2 Null pointer, empty string, etc. */
MsgError (msgErrorDb, eMORE, 0xFFFD) /* -3 More work to do. */
MsgError (msgErrorDb, eNYI, 0xFFFC) /* -4 Not yet implemented */
MsgError (msgErrorDb, eEXCEPTION, 0xFFFB) /* -5 An unexpected exception occurred */
MsgError (msgErrorDb, eBAD_VIEW_INTF, 0xFFFA) /* -6 COM intf to view layer is out of sync */
MsgError (msgErrorDb, eBAD_DB_INTF, 0xFFF9) /* -7 COM intf to db is out of sync */
MsgError (msgErrorDb, eID_NOT_FOUND, 0xFFF8) /* -8 Message id not found */
MsgError (msgErrorDb, eDBEndOfList, 0xFFF7) /* -9 iterator reached end of db */
MsgError (msgErrorDb, eBAD_URL, 0xFFF5) /* -11 Unable to parse URL */
/* NewsRC errors */
MsgError (msgErrorDb, eNewsRCError, 0xFFF4) /* -10 General news rc error */
/* News errors */
MsgError (msgErrorDb, eXOverParseError, 0xFFF3) /* -13 Error parsing XOver data */
/* Internal db errors */
MsgError (msgErrorDb, eDBExistsNot, 0xFFF2) /* -14 db doesn't exist */
MsgError (msgErrorDb, eDBNotOpen, 0xFFF1) /* -15 our db is not open (or ptr NULL) */
MsgError (msgErrorDb, eErrorOpeningDB, 0xFFF0) /* -16 Error opening internal db */
MsgError (msgErrorDb, eOldSummaryFile, 0xFFE0) /* -32 Attempt to oepn old summary file format */
MsgError (msgErrorDb, eNullView, 0xFFE1) /* -31 View Null */
MsgError (msgErrorDb, eNotThread, 0xFFE2) /* -30 operation requires a thread */
MsgError (msgErrorDb, eNoSummaryFile, 0xFFE3) /* -31 summary file was gone */
MsgError (msgErrorDb, eBuildViewInBackground, 0xFFE4) /* -32 db is huge - build view in background */
MsgError (msgErrorDb, eCorruptDB, 0xFFE5) /* -33 db is corrupt - throw it away */
/* Platform System Errors */
MsgError (msgErrorDb, eOUT_OF_MEMORY, 0xFF7F) /* -129 Out of memory for buffer or file-level objects */
/* file errors */
MsgError (msgErrorDb, eWRITE_ERROR, 0xFFC0) /* -64 Error writing to disk */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* The head file for Bin Hex 4.0 encode/decode
* -------------------------------------------
*
* 10sep95 mym created
*/
#ifndef binhex_h
#define binhex_h
#ifdef XP_MAC
#if PRAGMA_ALIGN_SUPPORTED
#pragma options align=mac68k
#endif
#endif /* XP_MAC */
#define BINHEX_STATE_START 0
#define BINHEX_STATE_FNAME 1
#define BINHEX_STATE_HEADER 2
#define BINHEX_STATE_HCRC 3
#define BINHEX_STATE_DFORK 4
#define BINHEX_STATE_DCRC 5
#define BINHEX_STATE_RFORK 6
#define BINHEX_STATE_RCRC 7
#define BINHEX_STATE_FINISH 8
#define BINHEX_STATE_DONE 9
/* #define BINHEX_STATE_ERROR 10 */
/*
** The Definitions for the binhex encoder
*/
typedef struct _binhex_header
{
uint32 type, creator;
uint16 flags;
int32 dlen, rlen ;
} binhex_header;
typedef struct _binhex_encode_object
{
int state; /* progress state. */
int state86; /* binhex encode state. */
unsigned long CRC; /* accumulated CRC */
int line_length; /* the line length count */
char saved_bits;
int s_inbuff; /* the inbuff size */
int pos_inbuff; /* the inbuff position */
char* inbuff; /* the inbuff pool */
int s_outbuff; /* the outbuff size */
int pos_outbuff; /* the outbuff position */
char* outbuff; /* the outbuf pool */
int s_overflow; /* the real size of overflow */
char overflow[32]; /* a small overflow buffer */
char c[2];
char newline[4]; /* the new line char seq. */
/* -- for last fix up. -- */
char name[64];
binhex_header head;
} binhex_encode_object;
/*
** The defination for the binhex decoder.
** NOTE: This define is for Mac only.
*/
typedef union
{
unsigned char c[4];
uint32 val;
} longbuf;
#define MAX_BUFF_SIZE 256
typedef struct _binhex_decode_object
{
int state; /* current state */
uint16 CRC; /* cumulative CRC */
uint16 fileCRC; /* CRC value from file */
longbuf octetbuf; /* buffer for decoded 6-bit values */
int16 octetin; /* current input position in octetbuf */
int16 donepos; /* ending position in octetbuf */
int16 inCRC; /* flag set when reading a CRC */
int32 count; /* generic counter */
int16 marker; /* flag indicating maker */
unsigned char rlebuf; /* buffer for last run length encoding value */
binhex_header head; /* buffer for header */
#ifdef XP_MAC
FSSpec* mSpec;
char name[64]; /* fsspec for the output file */
int16 vRefNum;
int32 parID ;
int16 fileId; /* the refnum of the output file */
#else
char *name; /* file name for the output file in non-mac OS */
XP_File fileId; /* the file if for the outpur file. non-mac OS */
#endif
MWContext* context; /* context for call back function. */
int32 s_inbuff; /* the valid size of the inbuff */
int32 pos_inbuff; /* the index of the inbuff. */
char* inbuff; /* the inbuff pointer. */
int32 pos_outbuff; /* the position of the out buff. */
char outbuff[MAX_BUFF_SIZE];
} binhex_decode_object;
XP_BEGIN_PROTOS
/*
** The binhex file encode prototypes.
*/
int binhex_encode_init(binhex_encode_object *p_bh_encode_obj);
int binhex_encode_next(binhex_encode_object *p_bh_encode_obj,
char *in_buff,
int32 in_size,
char *out_buff,
int32 buff_size,
int32 *real_size);
int binhex_encode_end (binhex_encode_object *p_bh_encode_obj,
XP_Bool is_aborting);
int binhex_reencode_head(
binhex_encode_object *p_bh_encode_obj,
char* outbuff,
int32 buff_size,
int32* real_size);
/*
** The binhex stream decode prototypes.
*/
int binhex_decode_init(binhex_decode_object *p_bh_decode_env,
MWContext *context);
int binhex_decode_next(binhex_decode_object *p_bh_decode_env,
const char *in_buff,
int32 buff_size);
int binhex_decode_end (binhex_decode_object *p_bh_decode_env,
XP_Bool is_aborting);
XP_END_PROTOS
#ifdef XP_MAC
#if PRAGMA_ALIGN_SUPPORTED
#pragma options align=reset
#endif
#endif /* XP_MAC */
#endif /* binhex_h */

View File

@@ -0,0 +1,885 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* mhtmlstm.c --- generation of MIME HTML.
*/
//#ifdef MSG_SEND_MULTIPART_RELATED
#include "msg.h"
#include "net.h"
#include "structs.h"
#include "xp_core.h"
#include "mhtmlstm.h"
#include "xp_mem.h"
#include "xp_str.h"
#include "xp_mcom.h"
#include "xp_file.h"
#include "prprf.h"
#include "xpassert.h"
#include "msgsend.h"
#include "msgsendp.h"
#include "mimeenc.h"
#include "libi18n.h"
extern "C" {
extern int MK_UNABLE_TO_OPEN_FILE;
}
/* Defined in libnet/mkcache.c */
extern "C" int NET_FindURLInCache(URL_Struct * URL_s, MWContext *ctxt);
/* Defined in layout/editor.cpp */
extern "C" XP_Bool EDT_IsSameURL(char *url1,char *url2,char *base1,char *base2);
/*
----------------------------------------------------------------------
MSG_MimeRelatedFileInfo
----------------------------------------------------------------------
*/
/*
----------------------------------------------------------------------
MSG_MimeRelatedStreamOut
----------------------------------------------------------------------
*/
class MSG_MimeRelatedStreamOut : public IStreamOut
{
public:
MSG_MimeRelatedStreamOut(XP_File file);
~MSG_MimeRelatedStreamOut(void);
virtual void Write( char *pBuffer, int32 iCount );
//static int WriteMimeData( const char *pBuffer, int32 iCount, void *closure);
virtual EOutStreamStatus Status();
virtual intn Close(void);
XP_File m_file;
XP_Bool m_hasWritten;
//MimeEncoderData *m_encoder;
EOutStreamStatus m_status;
};
MSG_MimeRelatedStreamOut::MSG_MimeRelatedStreamOut(XP_File file)
: m_file(file), m_hasWritten(FALSE), m_status(EOS_NoError)
{
}
MSG_MimeRelatedStreamOut::~MSG_MimeRelatedStreamOut(void)
{
Close();
}
void
MSG_MimeRelatedStreamOut::Write(char *pBuffer, int32 iCount)
{
// if (!m_encoder)
// (void) WriteMimeData(pBuffer, iCount, this);
// else
// (void) MimeEncoderWrite(m_encoder, pBuffer, iCount);
if (m_status != EOS_NoError)
return;
// For now, pass through the information.
XP_ASSERT(m_file);
int numBytes = 0;
if (m_file)
{
numBytes = XP_FileWrite(pBuffer, iCount, m_file);
if (numBytes != iCount)
{
TRACEMSG(("MSG_MimeRelatedStreamOut::Write(): error: %d written != %ld to write",numBytes, (long)iCount));
if (m_hasWritten)
m_status = EOS_DeviceFull; // wrote in the past, so this means the disk is full
else
m_status = EOS_FileError; // couldn't even write once, so assume it's some other problem
}
}
if (!m_hasWritten) m_hasWritten = TRUE;
}
//int
//MSG_MimeRelatedStreamOut::WriteMimeData(const char *pBuffer, int32 iCount, void *closure)
//{
//}
IStreamOut::EOutStreamStatus
MSG_MimeRelatedStreamOut::Status(void)
{
return m_status;
}
intn
MSG_MimeRelatedStreamOut::Close(void)
{
if (m_file)
{
XP_FileClose(m_file);
m_file = 0;
}
return 0;
}
/*
----------------------------------------------------------------------
MSG_MimeRelatedSubpart
----------------------------------------------------------------------
*/
char *
MSG_MimeRelatedSubpart::GenerateCIDHeader(void)
{
char *header;
// If we have a Content-ID, generate that.
header = (m_pContentID ?
PR_smprintf("Content-ID: <%s>", m_pContentID) : 0);
// If we have no Content-ID but an original URL, send that.
if (!header && m_pOriginalURL)
header = PR_smprintf("Content-Location: %s", m_pOriginalURL);
// If none of the above and we have a local URL, use that instead.
if (!header && m_pLocalURL)
header = PR_smprintf("Content-Location: %s", m_pLocalURL);
if (!header)
header = XP_STRDUP("");
return header;
}
char *
MSG_MimeRelatedSubpart::GenerateEncodingHeader(void)
{
char *header = NULL;
if (m_pEncoding)
header = PR_smprintf("Content-Transfer-Encoding: %s", m_pEncoding);
else
header = XP_STRDUP("");
return header;
}
char *
MSG_MimeRelatedSubpart::GetContentID(XP_Bool bAttachMIMEPrefix)
{
char *result = NULL;
if (m_pContentID)
{
result = PR_smprintf("%s%s", (bAttachMIMEPrefix ? "cid:" : ""),
m_pContentID);
}
return result;
}
int
MSG_MimeRelatedSubpart::GetStreamOut(IStreamOut **pReturn)
{
int result = 0;
if (!m_pStreamOut)
{
if (m_filename)
{
XP_File file = XP_FileOpen(m_filename, xpFileToPost, XP_FILE_WRITE_BIN);
if (file)
{
m_pStreamOut = new MSG_MimeRelatedStreamOut(file);
}
}
}
if (!m_pStreamOut)
result = MK_UNABLE_TO_OPEN_FILE; /* -1; rb */
*pReturn = (IStreamOut *) m_pStreamOut;
return result;
}
int
MSG_MimeRelatedSubpart::CloseStreamOut(void)
{
int result = 0;
if (m_pStreamOut)
{
delete m_pStreamOut; // this will close the stream
m_pStreamOut = NULL;
}
return result;
}
MSG_MimeRelatedSubpart::MSG_MimeRelatedSubpart(MSG_MimeRelatedSaver *parent,
char *pContentID,
char *pOriginal, char *pLocal,
char *pMime, int16 part_csid, char *pFilename)
: MSG_SendPart(NULL, part_csid), m_pOriginalURL(NULL),
m_pLocalURL(NULL), m_pParentFS(parent),
m_pContentID(NULL), m_pContentName(NULL), m_rootPart(FALSE)
{
m_filetype = xpFileToPost;
if (pOriginal)
m_pOriginalURL = XP_STRDUP(pOriginal);
if (pLocal)
m_pLocalURL = XP_STRDUP(pLocal);
if (pMime)
m_type = XP_STRDUP(pMime);
if (pContentID)
m_pContentID = XP_STRDUP(pContentID);
if ((!m_pOriginalURL) && (!m_type))
{
// Assume we're saving an untitled HTML document (the root part) if
// we're given neither the name nor the type.
m_type = XP_STRDUP(TEXT_HTML);
}
if (pFilename)
{
CopyString(&m_filename, pFilename);
m_rootPart = TRUE;
}
else
{
// Generate a temp name for a file to which to write.
char *tmp = WH_TempName(xpFileToPost, "nsmail");
if (tmp)
{
CopyString(&m_filename, tmp);
XP_FREE(tmp);
}
}
// If we have a filename, create the file now so that
// the Mac doesn't generate the same file name twice.
if (m_filename)
{
XP_File fp = XP_FileOpen(m_filename, xpFileToPost, XP_FILE_WRITE_BIN);
if (fp)
XP_FileClose(fp);
}
//XP_ASSERT(m_type != NULL);
XP_ASSERT(m_filename != NULL);
//XP_ASSERT(m_pContentID != NULL);
}
MSG_MimeRelatedSubpart::~MSG_MimeRelatedSubpart(void)
{
// Close any streams we may have had open.
if (m_pStreamOut)
delete m_pStreamOut;
// Delete the file we represent.
if (m_filename)
{
XP_FileRemove(m_filename, xpFileToPost);
}
XP_FREEIF(m_pOriginalURL);
XP_FREEIF(m_pLocalURL);
XP_FREEIF(m_pContentID);
XP_FREEIF(m_pEncoding);
XP_FREEIF(m_pContentName);
m_pOriginalURL = m_pLocalURL = NULL;
}
int
MSG_MimeRelatedSubpart::WriteEncodedMessageBody(const char *buf, int32 size,
void *pPart)
{
MSG_MimeRelatedSubpart *subpart = (MSG_MimeRelatedSubpart *) pPart;
int returnVal = 0;
XP_ASSERT(subpart->m_state != NULL);
if (subpart->m_state)
returnVal = mime_write_message_body(subpart->m_state, (char *) buf, size);
return returnVal;
}
void
MSG_MimeRelatedSubpart::CopyURLInfo(const URL_Struct *pURL)
{
char *suffix = NULL;
if (pURL != NULL)
{
// Get the MIME type if we have it.
if (pURL->content_type && *(pURL->content_type))
SetType(pURL->content_type);
// Look for a content name in this order:
// 1. If we have a content name, use that as is.
// 2. If we have a content type, find an extension
// corresponding to the content type, and attach it to
// the temp filename.
// 3. If we have neither a content name nor a content type,
// duplicate the temp filename as is. (Yuck.)
if (pURL->content_name && *(pURL->content_name))
m_pContentName = XP_STRDUP(pURL->content_name);
else if (pURL->content_type && (suffix = NET_cinfo_find_ext(pURL->content_type)) != NULL)
{
// We found an extension locally, add it to the temp name.
char *end = XP_STRRCHR(m_filename, '.');
if (end)
*end = '\0';
m_pContentName = PR_smprintf("%s.%s", m_filename, suffix);
if (end)
*end = '.';
}
}
if (!m_pContentName)
m_pContentName = XP_STRDUP(m_filename);
}
int
MSG_MimeRelatedSubpart::Write(void)
{
// If we weren't given the mime type by the editor,
// then attempt to deduce it from what information we can get.
if ((m_pOriginalURL) && (!m_type))
{
// We weren't explicitly given the MIME type, so
// we ask the cache if it knows anything about this URL.
URL_Struct testUrl;
XP_MEMSET(&testUrl, 0, sizeof(URL_Struct));
testUrl.address = m_pOriginalURL;
int findResult = NET_FindURLInCache(&testUrl,
m_pParentFS->GetContext());
if ((findResult != 0) && (testUrl.content_type))
{
// Got a MIME type from the cache.
m_type = XP_STRDUP(testUrl.content_type);
}
}
if ((m_pOriginalURL) && (!m_type))
{
// Either we didn't find the URL in the cache, or
// we have it but don't know its MIME type.
// So, we trot out our last resort: attempt to grok
// the MIME type based on the filename. (Mr. Yuk says: "Yuk.")
NET_cinfo *pMimeInfo = NET_cinfo_find_type(m_pOriginalURL);
if ((pMimeInfo) && (pMimeInfo->type))
{
// Got a MIME type based on the filename.
m_type = XP_STRDUP(pMimeInfo->type);
}
}
if (!m_type)
{
// No matter what we've done, we will never figure out the type.
// So, we punt and call it an application/octet-stream.
m_type = XP_STRDUP(APPLICATION_OCTET_STREAM);
}
// Determine what the encoding of this data should be depending
// on the MIME type. This is fairly braindead: base64 encode anything
// that isn't text.
if (m_type && (!m_rootPart))
{
// Uuencode only if we have to, otherwise use base64
if (m_pParentFS->m_pPane->
GetCompBoolHeader(MSG_UUENCODE_BINARY_BOOL_HEADER_MASK))
{
m_pEncoding = XP_STRDUP(ENCODING_UUENCODE);
SetEncoderData(MimeUUEncoderInit(m_pContentName ? m_pContentName : "",
#ifdef XP_OS2
(int (_Optlink*) (const char*,int32,void*))
#endif
WriteEncodedMessageBody,
this));
}
else
{
m_pEncoding = XP_STRDUP(ENCODING_BASE64);
SetEncoderData(MimeB64EncoderInit(
#ifdef XP_OS2
(int (_Optlink*) (const char*,int32,void*))
#endif
WriteEncodedMessageBody,
this));
}
}
// Horrible hack: if we got a local filename then we're the root lump,
// hence we don't generate a content ID header in that case
// (but we do in all other cases where we have a content ID)
char *cidHeader = NULL;
if ((!m_rootPart) && (m_pContentID))
{
cidHeader = GenerateCIDHeader();
if (cidHeader)
{
AppendOtherHeaders(cidHeader);
AppendOtherHeaders(CRLF);
XP_FREE(cidHeader);
}
}
if (m_pEncoding)
{
char *encHeader = GenerateEncodingHeader();
if (encHeader)
{
AppendOtherHeaders(encHeader);
AppendOtherHeaders(CRLF);
XP_FREE(encHeader);
}
}
if ((!m_rootPart) && (m_pOriginalURL))
{
char *fileHeader = PR_smprintf("Content-Disposition: inline; filename=\"%s\"",
m_pContentName ? m_pContentName : "");
if (fileHeader)
{
AppendOtherHeaders(fileHeader);
AppendOtherHeaders(CRLF);
XP_FREE(fileHeader);
}
}
return MSG_SendPart::Write();
}
/*
----------------------------------------------------------------------
MSG_MimeRelatedParentPart
----------------------------------------------------------------------
*/
MSG_MimeRelatedParentPart::MSG_MimeRelatedParentPart(int16 part_csid)
: MSG_SendPart(NULL, part_csid)
{
}
MSG_MimeRelatedParentPart::~MSG_MimeRelatedParentPart(void)
{
}
/*
----------------------------------------------------------------------
MSG_MimeRelatedSaver
----------------------------------------------------------------------
*/
extern char * msg_generate_message_id(void);
// Constructor
MSG_MimeRelatedSaver::MSG_MimeRelatedSaver(MSG_CompositionPane *pane,
MWContext *context,
MSG_CompositionFields *fields,
XP_Bool digest_p,
MSG_Deliver_Mode deliver_mode,
const char *body,
uint32 body_length,
MSG_AttachedFile *attachedFiles,
DeliveryDoneCallback cb,
char **ppOriginalRootURL)
: m_pContext(context), m_pBaseURL(NULL), m_pPane(pane),
m_pFields(fields), m_digest(digest_p), m_deliverMode(deliver_mode),
m_pBody(body), m_bodyLength(body_length),
m_pAttachedFiles(attachedFiles), m_cbDeliveryDone(cb), m_pSourceBaseURL(NULL)
{
// Generate the message ID.
m_pMessageID = msg_generate_message_id();
if (m_pMessageID)
{
// Massage the message ID so that it can be used for generating
// part IDs. For now, just remove the angle brackets.
m_pMessageID[strlen(m_pMessageID)-1] = '\0'; // shorten the end by 1
char *temp = XP_STRDUP(&(m_pMessageID[1])); // and strip off the leading '<'
if (temp)
{
XP_FREE(m_pMessageID);
m_pMessageID = temp;
}
}
XP_ASSERT(m_pMessageID);
// Create the part object that we represent.
m_pPart = new MSG_MimeRelatedParentPart(INTL_DefaultWinCharSetID(context));
XP_ASSERT(m_pPart);
if ((ppOriginalRootURL != NULL) && *(ppOriginalRootURL))
{
// Have a valid string of some sort, wait to be added.
}
else if (ppOriginalRootURL != NULL)
{
// ### mwelch This is a hack, required because EDT_SaveFileTo
// requires a source URL string, even if the document
// is currently untitled. The hack consists of adding
// the return parameter in the constructor, and passing
// back an improvised source URL if we were not given one.
//
// Autogenerate the title and pass it back.
m_rootFilename = WH_TempName(xpFileToPost,"nsmail");
XP_ASSERT(m_rootFilename);
char * temp = WH_FileName(m_rootFilename, xpFileToPost);
*ppOriginalRootURL = XP_PlatformFileToURL(temp);
if (temp)
XP_FREE( temp );
}
// Set our type to be multipart/related.
m_pPart->SetType(MULTIPART_RELATED);
}
// Destructor
MSG_MimeRelatedSaver::~MSG_MimeRelatedSaver(void)
{
XP_FREEIF(m_pSourceBaseURL);
if (m_rootFilename)
{
XP_FileRemove(m_rootFilename, xpFileToPost);
XP_FREEIF(m_rootFilename);
}
XP_FREEIF(m_pMessageID);
}
intn MSG_MimeRelatedSaver::GetType()
{
return ITapeFileSystem::MailSend;
}
MSG_MimeRelatedSubpart *
MSG_MimeRelatedSaver::GetSubpart(intn iFileIndex)
{
XP_ASSERT(m_pPart != NULL);
MSG_MimeRelatedSubpart *part =
(MSG_MimeRelatedSubpart *) m_pPart->GetChild(iFileIndex);
return part;
}
// This function is called before anything else.
// Tell the file system the base URL it is going to see.
void
MSG_MimeRelatedSaver::SetSourceBaseURL(char *pURL)
{
XP_FREEIF(m_pSourceBaseURL);
m_pSourceBaseURL = XP_STRDUP(pURL);
#if 0
MSG_MimeRelatedSubpart *part = NULL;
// Remember the URL for later.
m_pBaseURL = pURL;
// Add this URL as the first in the list.
if (m_pPart->GetNumChildren() == 0)
{
AddFile(pURL);
}
else
{
part = GetSubpart(0);
if (part)
{
XP_FREEIF(part->m_pOriginalURL);
part->m_pOriginalURL = (pURL == NULL) ? NULL : XP_STRDUP(pURL);
}
}
// Fix the local URL/filename reference if we haven't already opened the file.
if (!part)
part = GetSubpart(0);
if (part && (part->m_pStreamOut == NULL))
{
XP_FREEIF(part->m_pLocalURL);
part->m_pLocalURL = PR_smprintf("file:%s",part->GetFilename());
XP_ASSERT(part->m_pLocalURL);
part->SetOtherHeaders(""); // no headers for the lead part
}
#endif
}
char*
MSG_MimeRelatedSaver::GetSourceURL(intn iFileIndex)
{
char *result = NULL;
MSG_MimeRelatedSubpart *part = GetSubpart(iFileIndex);
if (part->m_pOriginalURL) {
// Try to make absolute relative to value set in MSG_MimeRelatedSaver::SetSourceBaseURL().
if (m_pSourceBaseURL) {
result = NET_MakeAbsoluteURL(m_pSourceBaseURL,part->m_pOriginalURL);
}
else {
result = XP_STRDUP(part->m_pOriginalURL);
}
}
return result;
}
// Add a name to the file system.
// Returns the index of the file added (0 based).
intn
MSG_MimeRelatedSaver::AddFile(char * pURL, char * pMimeType, int16 part_csid)
{
intn returnValue = 0;
MSG_MimeRelatedSubpart *newPart = NULL;
int i;
// See if a part with this url already exists.
for(i=0;(i<m_pPart->GetNumChildren()) && (!newPart);i++)
{
newPart = GetSubpart(i);
// Use EDT_IsSameURL to deal with case insensitivity on MAC and Win16
if (!newPart ||
!EDT_IsSameURL(newPart->m_pOriginalURL, pURL,m_pSourceBaseURL,m_pSourceBaseURL)) {
newPart = NULL; // not this one, try the next one
}
else {
// found it.
returnValue = i;
}
}
if (newPart == NULL)
{
// Generate a Content ID. This will look a lot like our message ID,
// except that we will add the part number.
XP_ASSERT(m_pMessageID != NULL);
char *newPartID = PR_smprintf("part%ld.%s", (long) m_pPart->GetNumChildren(),
m_pMessageID);
XP_ASSERT(newPartID != NULL);
char *newLocalURL = PR_smprintf("cid:%s",newPartID);
XP_ASSERT(newLocalURL != NULL);
returnValue = m_pPart->GetNumChildren();
if (m_pPart->GetNumChildren() == 0)
// This is the root file in the file system.
newPart = new MSG_MimeRelatedSubpart(this, newPartID, pURL,
pURL, TEXT_HTML, part_csid,
m_rootFilename);
else
newPart = new MSG_MimeRelatedSubpart(this, newPartID, pURL,
newLocalURL, pMimeType, part_csid );
if (newPart)
m_pPart->AddChild(newPart);
else
returnValue = (intn) ITapeFileSystem::Error; // an error since 0 is the base URL (??)
XP_FREEIF(newPartID);
XP_FREEIF(newLocalURL);
}
return returnValue;
}
intn
MSG_MimeRelatedSaver::GetNumFiles(void)
{
return m_pPart->GetNumChildren();
}
char *
MSG_MimeRelatedSaver::GetDestAbsURL()
{
// No meaningful destination URL for sending mail.
return NULL;
}
// Get the name of the relative url to place in the file.
char *
MSG_MimeRelatedSaver::GetDestURL(intn iFileIndex)
{
char *result = NULL;
MSG_MimeRelatedSubpart *thePart = GetSubpart(iFileIndex);
if (thePart != NULL)
{
result = XP_STRDUP(thePart->m_pLocalURL);
}
return result;
}
char *
MSG_MimeRelatedSaver::GetDestPathURL(void)
{
//return XP_STRDUP(""); // no path prefix for content IDs
return NULL;
}
// Return the name to display when saving the file.
char *
MSG_MimeRelatedSaver::GetHumanName(intn iFileIndex)
{
char *result = NULL;
MSG_MimeRelatedSubpart *thePart = GetSubpart(iFileIndex);
if (thePart != NULL)
{
result = thePart->m_pOriginalURL;
char *end = XP_STRRCHR(result, '/');
if (end)
result = XP_STRDUP(++end);
else
result = XP_STRDUP(result);
}
return result;
}
// Open the output stream.
IStreamOut *
MSG_MimeRelatedSaver::OpenStream(intn iFileIndex)
{
intn theError = 0;
IStreamOut *pStream = NULL; // in case we fail
// Create a stream object that can be written to.
MSG_MimeRelatedSubpart *thePart = GetSubpart(iFileIndex);
if (thePart)
{
theError = (intn) thePart->GetStreamOut(&pStream);
}
return pStream;
}
void
MSG_MimeRelatedSaver::CopyURLInfo(intn iFileIndex, const URL_Struct *pURL)
{
MSG_MimeRelatedSubpart *thePart = GetSubpart(iFileIndex);
if (thePart != NULL)
thePart->CopyURLInfo(pURL);
}
// Close the output stream.
// Called on completion. bSuccess is TRUE if completed successfully,
// FALSE if it failed.
void
MSG_MimeRelatedSaver::Complete(Bool bSuccess,
EDT_ITapeFileSystemComplete *pfComplete, void *pArg )
{
m_pEditorCompletionFunc = pfComplete;
m_pEditorCompletionArg = pArg;
// Call StartMessageDelivery (and should) if we
// were told to at creation time.
if (bSuccess)
{
// If we only generated a single HTML part, treat that as
// the root part.
if (m_pPart->GetNumChildren() == 1)
{
MSG_SendPart *tempPart = m_pPart->DetachChild(0);
delete m_pPart;
m_pPart = tempPart;
}
msg_StartMessageDeliveryWithAttachments(m_pPane, this,
m_pFields,
m_digest, FALSE,
m_deliverMode,
TEXT_HTML,
m_pBody, m_bodyLength,
m_pAttachedFiles,
m_pPart,
#ifdef XP_OS2
(void (_Optlink*) (MWContext*,void*,int,const char*))
#endif
MSG_MimeRelatedSaver::UrlExit);
}
else
{
// delete the contained part since we failed
delete m_pPart;
m_pPart = NULL;
// Call our UrlExit routine to perform cleanup.
UrlExit(m_pPane->GetContext(), this, MK_INTERRUPTED, NULL);
}
}
void
MSG_MimeRelatedSaver::UrlExit(MWContext *context, void *fe_data, int status,
const char *error_message)
{
MSG_MimeRelatedSaver *saver = (MSG_MimeRelatedSaver *) fe_data;
XP_ASSERT(saver != NULL);
if (saver)
{
if (saver->m_pEditorCompletionFunc)
{
(*(saver->m_pEditorCompletionFunc))((status == 0),
saver->m_pEditorCompletionArg);
}
if (saver->m_cbDeliveryDone)
{
(*(saver->m_cbDeliveryDone))(context,saver->m_pPane,
status,error_message);
}
}
delete saver; // the part within stays around, we don't
}
void
MSG_MimeRelatedSaver::CloseStream( intn iFileIndex )
{
// Get the piece whose stream we will close.
MSG_MimeRelatedSubpart *thePart = GetSubpart(iFileIndex);
if (thePart)
{
thePart->CloseStreamOut();
}
}
XP_Bool
MSG_MimeRelatedSaver::FileExists( intn /*iFileIndex*/ )
{
return FALSE;
}
XP_Bool
MSG_MimeRelatedSaver::IsLocalPersistentFile(intn /*iFileIndex*/) {
return FALSE;
}
//#endif

View File

@@ -0,0 +1,225 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
mhtmlstm.h --- generation of MIME HTML from the editor.
*/
#ifndef LIBMSG_MHTMLSTM_H
#define LIBMSG_MHTMLSTM_H
// Comment out the next line if you want to turn off the sending of multipart/related info.
#define MSG_SEND_MULTIPART_RELATED
//#ifdef MSG_SEND_MULTIPART_RELATED
#include "msg.h"
#include "itapefs.h"
#include "ptrarray.h"
#include "xp_file.h"
#include "ntypes.h"
#include "msgcpane.h"
#include "msgsendp.h"
#include "itapefs.h"
class MSG_MimeRelatedStreamIn;
class MSG_MimeRelatedStreamOut;
class MSG_MimeRelatedSubpart;
class MSG_MimeRelatedSaver;
class MSG_SendMimeDeliveryState;
typedef void (*DeliveryDoneCallback) (MWContext *context,
void *fe_data,
int status,
const char *error_message);
// A record which represents a part of this multipart.
// Encapsulates the stuff necessary to convert MIME part data
// into message text.
class MSG_MimeRelatedSubpart : public MSG_SendPart
{
public:
char *m_pOriginalURL; // Original URL for this lump
char *m_pLocalURL; // Local relative URL for this lump
MSG_MimeRelatedSaver *m_pParentFS; // The parent FS that includes us
char *m_pContentID; // Content ID of this lump
char *m_pEncoding; // Content transfer encoding
char *m_pContentName; // Content name (as conveyed by CopyURLInfo)
MSG_MimeRelatedStreamOut *m_pStreamOut; // Current output (to file) stream
XP_Bool m_rootPart; // Are we the first part of the multipart?
MSG_MimeRelatedSubpart(MSG_MimeRelatedSaver *parent,
char *pContentID,
char *pOriginal,
char *pLocal,
char *pMime,
int16 part_csid,
char *pRootFileName = NULL);
~MSG_MimeRelatedSubpart(void);
char *GetContentID(XP_Bool bAddMIMEPrefix);
int GetStreamOut(IStreamOut **pReturn);
int CloseStreamOut(void);
int Write(void);
// Copy information out of the URL used to fetch its data
void CopyURLInfo(const URL_Struct *pURL);
// Function used by the mime encoder when writing to message file
static int WriteEncodedMessageBody(const char *buf, int32 size, void *pPart);
// Generate any additional header strings for this part
// (such as the "Content-ID:" string)
char * GenerateCIDHeader(void);
char * GenerateEncodingHeader(void);
};
class MSG_MimeRelatedSaver;
class MSG_MimeRelatedParentPart : public MSG_SendPart
{
public:
MSG_MimeRelatedParentPart(int16 part_csid);
virtual ~MSG_MimeRelatedParentPart();
//virtual int Write();
//virtual int SetFile(const char* filename, XP_FileType filetype);
//virtual int SetBuffer(const char* buffer);
//virtual int SetOtherHeaders(const char* other);
//virtual int AppendOtherHeaders(const char* moreother);
//virtual int AddChild(MSG_SendPart* child);
};
class MSG_MimeRelatedSaver : public ITapeFileSystem
{
public:
MWContext * m_pContext; // Context
char * m_pBaseURL; // Base URL of this lump
char * m_pMessageID; // Message ID that we will use to generate
// unique names for each content ID
char * m_rootFilename; // Filename for root object (created at const. time)
char * m_pSourceBaseURL; // Only used to return absolute URLs for GetSourceURL()
MSG_SendPart *m_pPart;
// All these are parameters to be passed to StartMessageDelivery
MSG_CompositionPane *m_pPane;
MSG_CompositionFields *m_pFields;
XP_Bool m_digest;
MSG_Deliver_Mode m_deliverMode;
const char *m_pBody;
uint32 m_bodyLength;
MSG_AttachedFile *m_pAttachedFiles;
DeliveryDoneCallback m_cbDeliveryDone;
void (*m_pEditorCompletionFunc)(XP_Bool success, void *data);
void *m_pEditorCompletionArg;
void ClearAllParts(void);
public:
MSG_MimeRelatedSaver(MSG_CompositionPane *pane, MWContext *context,
MSG_CompositionFields *fields,
XP_Bool digest_p, MSG_Deliver_Mode deliver_mode,
const char *body, uint32 body_length,
MSG_AttachedFile *attachedFiles,
DeliveryDoneCallback cb,
char **ppOriginalRootURL);
virtual ~MSG_MimeRelatedSaver();
virtual intn GetType();
// This function is called before anything else. It tells the file
// system the base url it is going to see.
virtual void SetSourceBaseURL( char* pURL );
virtual char* GetSourceURL(intn iFileIndex);
// DESCRIPTION:
//
// Add a name to the file system. It is up to the file system to localize
// the name. For example, I could add 'http://home.netscape.com/'
// and the file system might decide that it should be called 'index.html'
// if the file system were DOS, the url might be converted to INDEX.HTML
//
// RETURNS: index of the file (0 based)
//
virtual intn AddFile( char* pURL, char *pMimeType, int16 iDocCharSetID );
// Count the number of files we know about.
virtual intn GetNumFiles(void);
virtual char* GetDestAbsURL();
// Gets the name of the RELATIVE url to place in the file. String is
// allocated with XP_STRDUP();
//
virtual char* GetDestURL( intn iFileIndex );
// String is allocated with XP_STRDUP().
virtual char* GetDestPathURL();
//
// Returns the name to display when saving the file, can be the same as
// GetURLName. String is allocated with XP_STRDUP();
//
virtual char* GetHumanName( intn iFileIndex );
virtual XP_Bool IsLocalPersistentFile(intn iFileIndex);
// Does the file referenced by iFileIndex already exist?
// For the MHTML version, this will always return FALSE.
virtual XP_Bool FileExists(intn iFileIndex);
//
// Opens the output stream. Returns a stream that can be written to. All
// 'AddFile's occur before the first OpenStream.
//
virtual IStreamOut * OpenStream( intn iFileIndex );
virtual void CloseStream( intn iFileIndex );
// ### mwelch Added so that multipart/related message saver can properly construct
// messages using quoted/forwarded part data.
// Tell the tape file system the mime type of a particular part.
// (Calling this overrides any previously determined mime type for this part.)
virtual void CopyURLInfo(intn iFileIndex, const URL_Struct *pURL);
//
// Called on completion, TRUE if completed successfully, FALSE if it failed.
//
virtual void Complete( Bool bSuccess, EDT_ITapeFileSystemComplete *pfComplete, void *pArg );
// Has this file system received a true multipart or just some HTML?
char *GetMimeType(void);
MWContext *GetContext(void) const { return m_pContext; }
char *GetMessageID(void) const { return m_pMessageID; }
MSG_MimeRelatedSubpart *GetSubpart( intn iFileIndex );
// Used when the mail system is done sending the message.
// Causes the editor to clean up from the save.
static void UrlExit(MWContext *context, void *fe_data, int status,
const char *error_message);
};
//#endif
#endif

318
mozilla/lib/mailto/msg.h Normal file
View File

@@ -0,0 +1,318 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
msg.h --- internal defs for the msg library
*/
#ifndef _MSG_H_
#define _MSG_H_
#include "xp.h"
#include "msgcom.h"
#include "msgnet.h"
#include "msgutils.h"
#include "xpgetstr.h"
#ifdef XP_CPLUSPLUS
class MessageDBView;
class MSG_SendPart;
#endif
#define MANGLE_INTERNAL_ENVELOPE_LINES /* We always need to do this, for now */
#undef FIXED_SEPARATORS /* this doesn't work yet */
#define EMIT_CONTENT_LENGTH /* Experimental; and anyway, we only
emit it, we don't parse it, so this
is only the first step. */
/* This string gets appended to the beginning of an attachment field
during a forward quoted operation */
#define MSG_FORWARD_COOKIE "$forward_quoted$"
/* The PRINTF macro is for debugging messages of unusual events (summary */
/* files out of date or invalid or the like. It's so that as I use the mail */
/* to actually read my e-mail, I can look at the shell output whenever */
/* something unusual happens so I can get some clues as to what's going on. */
/* Please don't remove any PRINTF calls you see, and be sparing of adding */
/* any additional ones. Thanks. - Terry */
#ifdef DEBUG
#define PRINTF(msg) XP_Trace msg
#else
#define PRINTF(msg)
#endif
#ifdef FREEIF
#undef FREEIF
#endif
#define FREEIF(obj) do { if (obj) { XP_FREE (obj); obj = 0; }} while (0)
/* The Netscape-specific header fields that we use for storing our
various bits of state in mail folders.
*/
#define X_MOZILLA_STATUS "X-Mozilla-Status"
#define X_MOZILLA_STATUS_FORMAT X_MOZILLA_STATUS ": %04.4x"
#define X_MOZILLA_STATUS_LEN /*1234567890123456*/ 16
#define X_MOZILLA_STATUS2 "X-Mozilla-Status2"
#define X_MOZILLA_STATUS2_FORMAT X_MOZILLA_STATUS2 ": %08.8x"
#define X_MOZILLA_STATUS2_LEN /*12345678901234567*/ 17
#define X_MOZILLA_DRAFT_INFO "X-Mozilla-Draft-Info"
#define X_MOZILLA_DRAFT_INFO_LEN /*12345678901234567890*/ 20
#define X_MOZILLA_NEWSHOST "X-Mozilla-News-Host"
#define X_MOZILLA_NEWSHOST_LEN /*1234567890123456789*/ 19
#define X_UIDL "X-UIDL"
#define X_UIDL_LEN /*123456*/ 6
#define CONTENT_LENGTH "Content-Length"
#define CONTENT_LENGTH_LEN /*12345678901234*/ 14
/* Provide a common means of detecting empty lines in a message. i.e. to detect the end of headers among other things...*/
#define EMPTY_MESSAGE_LINE(buf) (buf[0] == CR || buf[0] == LF || buf[0] == '\0')
typedef int32 MsgChangeCookie; /* used to unregister change notification */
/* The three ways the list of newsgroups can be pruned.
*/
typedef enum
{
MSG_ShowAll,
MSG_ShowSubscribed,
MSG_ShowSubscribedWithArticles
} MSG_NEWSGROUP_DISPLAY_STYLE;
/* The three ways to deliver a message.
*/
typedef enum
{
MSG_DeliverNow,
MSG_QueueForLater,
MSG_SaveAsDraft,
MSG_SaveAsTemplate
} MSG_Deliver_Mode;
/* A little enum for things we'd like to learn lazily.
* e.g. displaying recipients for this pane? Yes we are,
* no we're not, haven't figured it out yet
*/
typedef enum
{
msg_No,
msg_Yes,
msg_DontKnow
} msg_YesNoDontKnow;
/* The MSG_REPLY_TYPE shares the same space as MSG_CommandType, to avoid
possible weird errors, but is restricted to the `composition' commands
(MSG_ReplyToSender through MSG_ForwardMessage.)
*/
typedef MSG_CommandType MSG_REPLY_TYPE;
/* The list of all message flags to not write to disk. */
#define MSG_FLAG_RUNTIME_ONLY (MSG_FLAG_ELIDED)
/* ===========================================================================
Structures.
===========================================================================
*/
/* Used for the various things that parse RFC822 headers...
*/
typedef struct message_header
{
const char *value; /* The contents of a header (after ": ") */
int32 length; /* The length of the data (it is not NULL-terminated.) */
} message_header;
/* Argument to msg_NewsgroupNameMapper() */
typedef int (*msg_SubscribedGroupNameMapper) (MWContext *context,
const char *name,
void *closure);
XP_BEGIN_PROTOS
/* we'll need this for localized folder names */
extern int MK_MSG_INBOX_L10N_NAME;
extern int MK_MSG_OUTBOX_L10N_NAME; /* win16 variations are in allxpstr.h */
extern int MK_MSG_OUTBOX_L10N_NAME_OLD;
extern int MK_MSG_TRASH_L10N_NAME;
extern int MK_MSG_DRAFTS_L10N_NAME;
extern int MK_MSG_SENT_L10N_NAME;
extern int MK_MSG_TEMPLATES_L10N_NAME;
#define INBOX_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_INBOX_L10N_NAME)
#define QUEUE_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_OUTBOX_L10N_NAME)
#define QUEUE_FOLDER_NAME_OLD MSG_GetSpecialFolderName(MK_MSG_OUTBOX_L10N_NAME_OLD)
#define TRASH_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_TRASH_L10N_NAME)
#define DRAFTS_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_DRAFTS_L10N_NAME)
#define SENT_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_SENT_L10N_NAME)
#define TEMPLATES_FOLDER_NAME MSG_GetSpecialFolderName(MK_MSG_TEMPLATES_L10N_NAME)
#ifdef XP_OS2
#define INBOX_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_INBOX_L10N_NAME)
#define QUEUE_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_OUTBOX_L10N_NAME)
#define QUEUE_FOLDER_PRETTY_NAME_OLD MSG_GetSpecialFolderPrettyName(MK_MSG_OUTBOX_L10N_NAME_OLD)
#define TRASH_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_TRASH_L10N_NAME)
#define DRAFTS_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_DRAFTS_L10N_NAME)
#define SENT_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_SENT_L10N_NAME)
#define TEMPLATES_FOLDER_PRETTY_NAME MSG_GetSpecialFolderPrettyName(MK_MSG_TEMPLATES_L10N_NAME)
#endif
int ConvertMsgErrToMKErr(uint32 err); /* this routine might live - the rest are
probably already dead */
/* ===========================================================================
Redisplay-related stuff
===========================================================================
*/
/* Clear out the message display (make Layout be displaying no document.) */
extern void msg_ClearMessageArea (MWContext *context);
/* Returns a line suitable for using as the envelope line in a BSD
mail folder. The returned string is stored in a static, and so
should be used before msg_GetDummyEnvelope is called again. */
extern char * msg_GetDummyEnvelope(void);
/* Returns TRUE if the buffer looks like a valid envelope.
This test is somewhat more restrictive than XP_STRNCMP(buf, "From ", 5).
*/
extern XP_Bool msg_IsEnvelopeLine(const char *buf, int32 buf_size);
/* ===========================================================================
Utilities specific to mail folders and their Folders and ThreadEntries.
===========================================================================
*/
/* returns the name of a magic folder - returns a new string. */
extern char *msg_MagicFolderName(MSG_Prefs* prefs, uint32 flag, int *pStatus);
/* Get the current fcc folder name, so we can sort them up at the top of the
other folder lists with the other magic folders. */
const char* msg_GetDefaultFcc(XP_Bool news_p);
/* Reads the first few bytes of the file and returns FALSE if it doesn't
seem to be a mail folder. (Empty and nonexistent files return TRUE.)
If it doesn't seem to be one, the user is asked whether it should be
written to anyway, and their answer is returned.
*/
extern XP_Bool msg_ConfirmMailFile (MWContext *context, const char *file_name);
/* ===========================================================================
The content-type converters for the MIME types. These are provided by
compose.c, but are registered by netlib rather than msglib, for some
destined-to-be-mysterious reason.
===========================================================================
*/
extern NET_StreamClass *MIME_MessageConverter (int format_out, void *closure,
URL_Struct *url,
MWContext *context);
extern NET_StreamClass *MIME_RichtextConverter (int format_out, void *data_obj,
URL_Struct *url,
MWContext *context);
extern NET_StreamClass *MIME_EnrichedTextConverter (int format_out,
void *data_obj,
URL_Struct *url,
MWContext *context);
extern NET_StreamClass *MIME_ToDraftConverter (int format_out, void *closure,
URL_Struct *url,
MWContext *context);
extern NET_StreamClass *MIME_VCardConverter (int format_out, void *data_obj,
URL_Struct *url,
MWContext *context);
extern NET_StreamClass *MIME_JulianConverter (int format_out, void *data_obj,
URL_Struct *url,
MWContext *context);
/* This nastiness is how msg_SaveSelectedNewsMessages() works. */
extern NET_StreamClass *msg_MakeAppendToFolderStream (int format_out,
void *closure,
URL_Struct *url,
MWContext *);
/* This probably should be in mime.h, except that mime.h should mostly be
private to libmsg. So it's here. */
extern void
msg_StartMessageDeliveryWithAttachments (MSG_Pane *pane,
void *fe_data,
MSG_CompositionFields *fields,
XP_Bool digest_p,
XP_Bool dont_deliver_p,
MSG_Deliver_Mode deliver_mode,
const char *attachment1_type,
const char *attachment1_body,
uint32 attachment1_body_length,
const struct MSG_AttachedFile *attachments,
void *mimeRelatedPart,
void (*message_delivery_done_callback)
(MWContext *context,
void *fe_data,
int status,
const char *error_message));
extern int
msg_DownloadAttachments (MSG_Pane *pane,
void *fe_data,
const struct MSG_AttachmentData *attachments,
void (*attachments_done_callback)
(MWContext *context,
void *fe_data,
int status, const char *error_message,
struct MSG_AttachedFile *attachments));
extern
int msg_DoFCC (MSG_Pane *pane,
const char *input_file, XP_FileType input_file_type,
const char *output_file, XP_FileType output_file_type,
const char *bcc_header_value,
const char *fcc_header_value);
extern char* msg_generate_message_id (void);
#ifdef XP_UNIX
extern int msg_DeliverMessageExternally(MWContext *, const char *msg_file);
#endif /* XP_UNIX */
XP_END_PROTOS
#endif /* !_MSG_H_ */

View File

@@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "msgbg.h"
#include "msgpane.h"
#include "msgurlq.h"
extern "C" {
extern int MK_OUT_OF_MEMORY;
}
msg_Background::msg_Background()
{
}
msg_Background::~msg_Background()
{
if (m_pane) Interrupt();
}
int
msg_Background::Begin(MSG_Pane* pane)
{
XP_ASSERT(!m_pane);
if (m_pane) return -1;
char* url = XP_STRDUP("mailbox:?background");
if (!url) return MK_OUT_OF_MEMORY;
m_urlstruct = NET_CreateURLStruct(url, NET_NORMAL_RELOAD);
if (!m_urlstruct) {
XP_FREE(url);
return MK_OUT_OF_MEMORY;
}
XP_FREE(url);
m_urlstruct->internal_url = TRUE;
m_pane = pane;
msg_InterruptContext(pane->GetContext(), TRUE);
XP_ASSERT(pane->GetCurrentBackgroundJob() == NULL);
pane->SetCurrentBackgroundJob(this);
MSG_UrlQueue::AddUrlToPane(m_urlstruct, msg_Background::PreExit_s, pane);
return 0;
}
void
msg_Background::Interrupt()
{
XP_ASSERT(m_pane);
if (m_pane) {
msg_InterruptContext(m_pane->GetContext(), FALSE);
XP_ASSERT(m_pane == NULL);
}
}
msg_Background*
msg_Background::FindBGObj(URL_Struct* urlstruct)
{
XP_ASSERT(urlstruct && urlstruct->msg_pane);
if (!urlstruct || !urlstruct->msg_pane) return NULL;
msg_Background* result = urlstruct->msg_pane->GetCurrentBackgroundJob();
// OK, I'm truly evil, but I'm using this as an empty url that goes through
// netlib once. so result will be null...
XP_ASSERT(!result || result->m_pane == urlstruct->msg_pane);
return result;
}
int
msg_Background::ProcessBackground(URL_Struct* urlstruct)
{
msg_Background* obj = FindBGObj(urlstruct);
if (obj) {
return obj->DoSomeWork();
}
return MK_CONNECTED;
}
void
msg_Background::PreExit_s(URL_Struct* urlstruct, int status,
MWContext* context)
{
msg_Background* obj = FindBGObj(urlstruct);
if (obj) {
obj->PreExit(urlstruct, status, context);
}
}
void
msg_Background::PreExit(URL_Struct* /*urlstruct*/, int status,
MWContext*)
{
XP_Bool deleteself = AllDone(status);
XP_ASSERT(m_pane);
if (m_pane) {
m_pane->SetCurrentBackgroundJob(NULL);
m_pane = NULL;
}
if (deleteself) delete this;
}
XP_Bool
msg_Background::AllDone(int /*status*/)
{
return FALSE;
}
XP_Bool
msg_Background::IsRunning()
{
return m_pane != NULL;
}

View File

@@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgBg_H_
#define _MsgBg_H_
#include "msgzap.h"
class MSG_Pane;
class msg_Background : public MSG_ZapIt {
public:
msg_Background();
virtual ~msg_Background();
/* Begin() kicks things off. Sometime after making this call, calls will
be made to DoSomeWork(). This will interrupt any current background
operation or URL running on the given MSG_Pane. */
virtual int Begin(MSG_Pane* pane);
/* Interrupt() interrupts the running background operation. Just does an
InterruptContext on the pane's context. */
virtual void Interrupt();
/* Whether we are currently doing our background operation. */
virtual XP_Bool IsRunning();
// This routine is called from netlib (via msgglue) to cause us to actually
// do something.
static int ProcessBackground(URL_Struct* urlstruct);
protected:
static msg_Background* FindBGObj(URL_Struct* urlstruct);
static void PreExit_s(URL_Struct* urlstruct, int status,
MWContext* context);
virtual void PreExit(URL_Struct* urlstruct, int status,
MWContext* context);
/* The below are the only routines typically redefined by subclasses. */
/* DoSomeWork() keeps getting called. If it returns
MK_WAITING_FOR_CONNECTION, that means it hasn't finished its stuff. If
it returns MK_CONNECTED, that means it has successfully finished. If it
returns a negative value, that means we failed and it's an error
condition. */
virtual int DoSomeWork() = 0;
/* AllDone() gets called when things are finished. If the given status is
negative, then we were interrupted or had an error. This is a good
place to kick off another background operation. If it returns TRUE,
then this background object will be destroyed. */
virtual XP_Bool AllDone(int status);
MSG_Pane* m_pane;
URL_Struct* m_urlstruct;
};
#endif /* _MsgBg_H_ */

View File

@@ -0,0 +1,382 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "rosetta.h"
#include "msg.h"
#include "errcode.h"
#include "msgcflds.h"
#include "prefapi.h"
#include "ptrarray.h"
extern "C" {
extern int MK_OUT_OF_MEMORY;
}
MSG_CompositionFields::MSG_CompositionFields()
{
XP_Bool bReturnReceiptOn = FALSE;
PREF_GetBoolPref("mail.request.return_receipt_on", &bReturnReceiptOn);
PREF_GetIntPref("mail.request.return_receipt", &m_receiptType);
SetReturnReceipt (bReturnReceiptOn);
}
MSG_CompositionFields::MSG_CompositionFields(MSG_CompositionFields* c)
{
int i;
for (i=0 ; i<sizeof(m_headers) / sizeof(char*) ; i++) {
if (c->m_headers[i]) {
m_headers[i] = XP_STRDUP(c->m_headers[i]);
}
}
if (c->m_body) {
m_body = XP_STRDUP(c->m_body);
}
for (i=0 ; i<c->m_numforward ; i++) {
AddForwardURL(c->m_forwardurl[i]);
}
for (i=0; i<sizeof(m_boolHeaders)/sizeof(XP_Bool) ; i++) {
m_boolHeaders[i] = c->m_boolHeaders[i];
}
m_receiptType = c->m_receiptType;
}
MSG_CompositionFields::~MSG_CompositionFields()
{
int i;
for (i=0 ; i<sizeof(m_headers) / sizeof(char*) ; i++) {
FREEIF(m_headers[i]);
}
FREEIF(m_body);
for (i=0 ; i<m_numforward ; i++) {
delete [] m_forwardurl[i];
}
delete [] m_forwardurl;
}
int MSG_CompositionFields::SetNewsUrlHeader (const char *hostPort, XP_Bool xxx, const char *group)
{
// Here's where we allow URLs in the newsgroups: header
int status = -1;
if (hostPort && group) // must have a group
{
char *newsPostUrl = PR_smprintf ("%s://%s/", HG71654 "news", hostPort);
if (newsPostUrl)
{
SetHeader (MSG_NEWSPOSTURL_HEADER_MASK, newsPostUrl);
XP_FREE(newsPostUrl);
status = 0; // we succeeded, no need to keep looking at this header
}
else
status = MK_OUT_OF_MEMORY;
}
return status;
}
int MSG_CompositionFields::ParseNewsgroupsForUrls (const char *value)
{
int status = 0;
#ifdef MOZ_MAIL_NEWS
// Here we pull apart the comma-separated header value and look for news
// URLs. We'll use the URL to set the newspost URL to determine the host
msg_StringArray values (TRUE /*owns memory for strings*/);
values.ImportTokenList (value);
for (int i = 0; i < values.GetSize(); i++)
{
const char *singleValue = values.GetAt(i);
if (NEWS_TYPE_URL == NET_URL_Type (singleValue))
{
char *hostPort, *group, *id, *data;
XP_Bool xxx;
if (0 == NET_parse_news_url (value, &hostPort, &xxx, &group, &id, &data))
{
status = SetNewsUrlHeader (hostPort, xxx, group);
if (status == 0)
{
values.RemoveAt(i); // Remove the URL spec for this group
values.Add (group); // Add in the plain old group name
}
FREEIF (hostPort);
FREEIF (group);
FREEIF (id);
FREEIF (data);
}
}
}
char *newValue = values.ExportTokenList ();
if (newValue)
{
status = SetHeader (MSG_NEWSGROUPS_HEADER_MASK, newValue);
XP_FREE(newValue);
}
#endif /* MOZ_MAIL_NEWS */
return status;
}
int
MSG_CompositionFields::SetHeader(MSG_HEADER_SET header, const char* value)
{
int status = 0;
// Since colon is not a legal character in a newsgroup name under son-of-1036
// we're assuming that such a header contains a URL, and we should parse it out
// to infer the news server.
if (value && MSG_NEWSGROUPS_HEADER_MASK == header && XP_STRCHR(value, ':'))
return ParseNewsgroupsForUrls (value);
int i = DecodeHeader(header);
if (i >= 0)
{
char* old = m_headers[i]; // Done with careful paranoia, in case the
// value given is the old value (or worse,
// a substring of the old value, as does
// happen here and there.)
if (value != old)
{
if (value)
{
m_headers[i] = XP_STRDUP(value);
if (!m_headers[i])
status = MK_OUT_OF_MEMORY;
}
else
m_headers[i] = NULL;
FREEIF(old);
}
}
return status;
}
extern "C"const char* MSG_GetCompFieldsHeader(MSG_CompositionFields *fields,
MSG_HEADER_SET header)
{
return fields->GetHeader(header);
}
const char*
MSG_CompositionFields::GetHeader(MSG_HEADER_SET header)
{
int i = DecodeHeader(header);
if (i >= 0) {
return m_headers[i] ? m_headers[i] : "";
}
return NULL;
}
int
MSG_CompositionFields::SetBoolHeader(MSG_BOOL_HEADER_SET header, XP_Bool bValue)
{
int status = 0;
XP_ASSERT ((int) header >= (int) MSG_RETURN_RECEIPT_BOOL_HEADER_MASK &&
(int) header < (int) MSG_LAST_BOOL_HEADER_MASK);
if ( (int) header < (int) MSG_RETURN_RECEIPT_BOOL_HEADER_MASK ||
(int) header >= (int) MSG_LAST_BOOL_HEADER_MASK )
return -1;
m_boolHeaders[header] = bValue;
return status;
}
XP_Bool
MSG_CompositionFields::GetBoolHeader(MSG_BOOL_HEADER_SET header)
{
XP_ASSERT ((int) header >= (int) MSG_RETURN_RECEIPT_BOOL_HEADER_MASK &&
(int) header < (int) MSG_LAST_BOOL_HEADER_MASK);
if ( (int) header < (int) MSG_RETURN_RECEIPT_BOOL_HEADER_MASK ||
(int) header >= (int) MSG_LAST_BOOL_HEADER_MASK )
return FALSE;
return m_boolHeaders[header];
}
int
MSG_CompositionFields::SetBody(const char* value)
{
FREEIF(m_body);
if (value) {
m_body = XP_STRDUP(value);
if (!m_body) return MK_OUT_OF_MEMORY;
}
return 0;
}
const char*
MSG_CompositionFields::GetBody()
{
return m_body ? m_body : "";
}
int
MSG_CompositionFields::AppendBody(const char* value)
{
if (!value || !*value) return 0;
if (!m_body) {
return SetBody(value);
} else {
char* tmp = (char*) XP_ALLOC(XP_STRLEN(m_body) + XP_STRLEN(value) + 1);
if (tmp) {
XP_STRCPY(tmp, m_body);
XP_STRCAT(tmp, value);
XP_FREE(m_body);
m_body = tmp;
} else {
return MK_OUT_OF_MEMORY;
}
}
return 0;
}
int
MSG_CompositionFields::DecodeHeader(MSG_HEADER_SET header)
{
int result;
switch(header) {
case MSG_FROM_HEADER_MASK:
result = 0;
break;
case MSG_REPLY_TO_HEADER_MASK:
result = 1;
break;
case MSG_TO_HEADER_MASK:
result = 2;
break;
case MSG_CC_HEADER_MASK:
result = 3;
break;
case MSG_BCC_HEADER_MASK:
result = 4;
break;
case MSG_FCC_HEADER_MASK:
result = 5;
break;
case MSG_NEWSGROUPS_HEADER_MASK:
result = 6;
break;
case MSG_FOLLOWUP_TO_HEADER_MASK:
result = 7;
break;
case MSG_SUBJECT_HEADER_MASK:
result = 8;
break;
case MSG_ATTACHMENTS_HEADER_MASK:
result = 9;
break;
case MSG_ORGANIZATION_HEADER_MASK:
result = 10;
break;
case MSG_REFERENCES_HEADER_MASK:
result = 11;
break;
case MSG_OTHERRANDOMHEADERS_HEADER_MASK:
result = 12;
break;
case MSG_NEWSPOSTURL_HEADER_MASK:
result = 13;
break;
case MSG_PRIORITY_HEADER_MASK:
result = 14;
break;
case MSG_NEWS_FCC_HEADER_MASK:
result = 15;
break;
case MSG_MESSAGE_ENCODING_HEADER_MASK:
result = 16;
break;
case MSG_CHARACTER_SET_HEADER_MASK:
result = 17;
break;
case MSG_MESSAGE_ID_HEADER_MASK:
result = 18;
break;
case MSG_NEWS_BCC_HEADER_MASK:
result = 19;
break;
case MSG_HTML_PART_HEADER_MASK:
result = 20;
break;
case MSG_DEFAULTBODY_HEADER_MASK:
result = 21;
break;
case MSG_X_TEMPLATE_HEADER_MASK:
result = 22;
break;
default:
XP_ASSERT(0);
result = -1;
break;
}
XP_ASSERT(result < sizeof(m_headers) / sizeof(char*));
return result;
}
int
MSG_CompositionFields::AddForwardURL(const char* url)
{
XP_ASSERT(url && *url);
if (!url || !*url) return -1;
if (m_numforward >= m_maxforward) {
m_maxforward += 10;
char** tmp = new char* [m_maxforward];
if (!tmp) return MK_OUT_OF_MEMORY;
for (int32 i=0 ; i<m_numforward ; i++) {
tmp[i] = m_forwardurl[i];
}
delete [] m_forwardurl;
m_forwardurl = tmp;
}
m_forwardurl[m_numforward] = new char[XP_STRLEN(url) + 1];
if (!m_forwardurl[m_numforward]) return MK_OUT_OF_MEMORY;
XP_STRCPY(m_forwardurl[m_numforward], url);
m_numforward++;
return 0;
}
int32
MSG_CompositionFields::GetNumForwardURL()
{
return m_numforward;
}
const char*
MSG_CompositionFields::GetForwardURL(int32 which)
{
XP_ASSERT(which >= 0 && which < m_numforward);
if (which >= 0 && which < m_numforward) {
return m_forwardurl[which];
}
return NULL;
}

View File

@@ -0,0 +1,288 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgCFlds_H_
#define _MsgCFlds_H_
#include "rosetta.h"
#include "msgzap.h"
// Note that all the "Get" methods never return NULL (except in case of serious
// error, like an illegal parameter); rather, they return "" if things were set
// to NULL. This makes it real handy for the callers.
class MSG_CompositionFields : public MSG_ZapIt {
public:
MSG_CompositionFields();
MSG_CompositionFields(MSG_CompositionFields*); // Makes a copy.
virtual ~MSG_CompositionFields();
int SetHeader(MSG_HEADER_SET header, const char* value);
const char* GetHeader(MSG_HEADER_SET header);
int SetBoolHeader(MSG_BOOL_HEADER_SET header, XP_Bool bValue);
XP_Bool GetBoolHeader(MSG_BOOL_HEADER_SET header);
int SetBody(const char*);
const char* GetBody();
int AppendBody(const char*);
// When forwarding a bunch of messages, we can have a bunch of
// "forward url's" instead of an attachment.
int AddForwardURL(const char*);
int32 GetNumForwardURL();
const char* GetForwardURL(int32 which);
int32 GetReturnReceiptType() { return m_receiptType; };
void SetReturnReceiptType(int32 type) {m_receiptType = type;};
// Convenience routines...
int SetFrom(const char* value) {
return SetHeader(MSG_FROM_HEADER_MASK, value);
}
const char* GetFrom() {
return GetHeader(MSG_FROM_HEADER_MASK);
}
int SetReplyTo(const char* value) {
return SetHeader(MSG_REPLY_TO_HEADER_MASK, value);
}
const char* GetReplyTo() {
return GetHeader(MSG_REPLY_TO_HEADER_MASK);
}
int SetTo(const char* value) {
return SetHeader(MSG_TO_HEADER_MASK, value);
}
const char* GetTo() {
return GetHeader(MSG_TO_HEADER_MASK);
}
int SetCc(const char* value) {
return SetHeader(MSG_CC_HEADER_MASK, value);
}
const char* GetCc() {
return GetHeader(MSG_CC_HEADER_MASK);
}
int SetBcc(const char* value) {
return SetHeader(MSG_BCC_HEADER_MASK, value);
}
const char* GetBcc() {
return GetHeader(MSG_BCC_HEADER_MASK);
}
int SetFcc(const char* value) {
return SetHeader(MSG_FCC_HEADER_MASK, value);
}
const char* GetFcc() {
return GetHeader(MSG_FCC_HEADER_MASK);
}
int SetNewsFcc(const char* value) {
return SetHeader(MSG_NEWS_FCC_HEADER_MASK, value);
}
const char* GetNewsFcc() {
return GetHeader(MSG_NEWS_FCC_HEADER_MASK);
}
int SetNewsBcc(const char* value) {
return SetHeader(MSG_NEWS_BCC_HEADER_MASK, value);
}
const char* GetNewsBcc() {
return GetHeader(MSG_NEWS_BCC_HEADER_MASK);
}
int SetNewsgroups(const char* value) {
return SetHeader(MSG_NEWSGROUPS_HEADER_MASK, value);
}
const char* GetNewsgroups() {
return GetHeader(MSG_NEWSGROUPS_HEADER_MASK);
}
int SetFollowupTo(const char* value) {
return SetHeader(MSG_FOLLOWUP_TO_HEADER_MASK, value);
}
const char* GetFollowupTo() {
return GetHeader(MSG_FOLLOWUP_TO_HEADER_MASK);
}
int SetSubject(const char* value) {
return SetHeader(MSG_SUBJECT_HEADER_MASK, value);
}
const char* GetSubject() {
return GetHeader(MSG_SUBJECT_HEADER_MASK);
}
int SetAttachments(const char* value) {
return SetHeader(MSG_ATTACHMENTS_HEADER_MASK, value);
}
const char* GetAttachments() {
return GetHeader(MSG_ATTACHMENTS_HEADER_MASK);
}
int SetOrganization(const char* value) {
return SetHeader(MSG_ORGANIZATION_HEADER_MASK, value);
}
const char* GetOrganization() {
return GetHeader(MSG_ORGANIZATION_HEADER_MASK);
}
int SetReferences(const char* value) {
return SetHeader(MSG_REFERENCES_HEADER_MASK, value);
}
const char* GetReferences() {
return GetHeader(MSG_REFERENCES_HEADER_MASK);
}
int SetOtherRandomHeaders(const char* value) {
return SetHeader(MSG_OTHERRANDOMHEADERS_HEADER_MASK, value);
}
const char* GetOtherRandomHeaders() {
return GetHeader(MSG_OTHERRANDOMHEADERS_HEADER_MASK);
}
int SetNewspostUrl(const char* value) {
return SetHeader(MSG_NEWSPOSTURL_HEADER_MASK, value);
}
const char* GetNewspostUrl() {
return GetHeader(MSG_NEWSPOSTURL_HEADER_MASK);
}
int SetDefaultBody(const char* value) {
return SetHeader(MSG_DEFAULTBODY_HEADER_MASK, value);
}
const char* GetDefaultBody() {
return GetHeader(MSG_DEFAULTBODY_HEADER_MASK);
}
int SetPriority(const char* value) {
return SetHeader(MSG_PRIORITY_HEADER_MASK, value);
}
const char* GetPriority() {
return GetHeader(MSG_PRIORITY_HEADER_MASK);
}
int SetMessageEncoding(const char* value) {
return SetHeader(MSG_MESSAGE_ENCODING_HEADER_MASK, value);
}
const char* GetMessageEncoding() {
return GetHeader(MSG_MESSAGE_ENCODING_HEADER_MASK);
}
int SetCharacterSet(const char* value) {
return SetHeader (MSG_CHARACTER_SET_HEADER_MASK, value);
}
const char* GetCharacterSet() {
return GetHeader(MSG_CHARACTER_SET_HEADER_MASK);
}
int SetMessageId(const char* value) {
return SetHeader (MSG_MESSAGE_ID_HEADER_MASK, value);
}
const char* GetMessageId() {
return GetHeader(MSG_MESSAGE_ID_HEADER_MASK);
}
int SetHTMLPart(const char* value) {
return SetHeader(MSG_HTML_PART_HEADER_MASK, value);
}
const char* GetHTMLPart() {
return GetHeader(MSG_HTML_PART_HEADER_MASK);
}
int SetTemplateName(const char* value) {
return SetHeader(MSG_X_TEMPLATE_HEADER_MASK, value);
}
const char* GetTemplateName() {
return GetHeader(MSG_X_TEMPLATE_HEADER_MASK);
}
// Bool headers
int SetReturnReceipt(XP_Bool value) {
return SetBoolHeader(MSG_RETURN_RECEIPT_BOOL_HEADER_MASK, value);
}
XP_Bool GetReturnReceipt() {
return GetBoolHeader(MSG_RETURN_RECEIPT_BOOL_HEADER_MASK);
}
HG87266
int SetSigned(XP_Bool value) {
return SetBoolHeader(MSG_SIGNED_BOOL_HEADER_MASK, value);
}
XP_Bool GetSigned() {
return GetBoolHeader(MSG_SIGNED_BOOL_HEADER_MASK);
}
int SetAttachVCard(XP_Bool value) {
return SetBoolHeader(MSG_ATTACH_VCARD_BOOL_HEADER_MASK, value);
}
XP_Bool GetAttachVCard() {
return GetBoolHeader(MSG_ATTACH_VCARD_BOOL_HEADER_MASK);
}
void SetOwner(MSG_Pane *pane) {
m_owner = pane;
}
MSG_Pane * GetOwner() { return m_owner; }
void SetForcePlainText(XP_Bool value) {m_force_plain_text = value;}
XP_Bool GetForcePlainText() {return m_force_plain_text;}
void SetUseMultipartAlternative(XP_Bool value) {m_multipart_alt = value;}
XP_Bool GetUseMultipartAlternative() {return m_multipart_alt;}
protected:
int DecodeHeader(MSG_HEADER_SET header);
// These methods allow news URLs in the newsgroups header
int SetNewsUrlHeader (const char *hostPort, XP_Bool xxx, const char *group);
int ParseNewsgroupsForUrls (const char *value);
MSG_Pane *m_owner;
char* m_headers[32];
char* m_body;
char** m_forwardurl;
int32 m_numforward;
int32 m_maxforward;
XP_Bool m_boolHeaders[MSG_LAST_BOOL_HEADER_MASK];
XP_Bool m_force_plain_text;
XP_Bool m_multipart_alt;
int32 m_receiptType; /* 0:None 1:DSN 2:MDN 3:BOTH */
};
#endif /* _MsgCFlds_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,274 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgCPane_H_
#define _MsgCPane_H_
#include "rosetta.h"
#include "msg.h"
#include "msgpane.h"
#include "xlate.h"
/* The MSG_REPLY_TYPE shares the same space as MSG_CommandType, to avoid
possible weird errors, but is restricted to the `composition' commands
(MSG_ReplyToSender through MSG_ForwardMessage.)
*/
typedef MSG_CommandType MSG_REPLY_TYPE;
struct MSG_AttachedFile;
typedef struct PrintSetup_ PrintSetup;
typedef struct _XPDialogState XPDialogState;
HG82621
class MSG_NewsHost;
class MSG_HTMLRecipients;
class MSG_CompositionPane : public MSG_Pane {
public:
MSG_CompositionPane(MWContext* context, MWContext* old_context,
MSG_Prefs* prefs, MSG_CompositionFields* initfields,
MSG_Master* master);
// Or, if you prefer, construct using below constructor and be sure to
// soon call the Initialize() method:
MSG_CompositionPane(MWContext* context, MSG_Prefs* prefs,
MSG_Master* master);
int Initialize(MWContext* old_context, MSG_CompositionFields* initfields);
virtual ~MSG_CompositionPane();
virtual MSG_PaneType GetPaneType();
virtual void NotifyPrefsChange(NotifyCode code);
virtual MsgERR GetCommandStatus(MSG_CommandType command,
const MSG_ViewIndex* indices,
int32 numindices,
XP_Bool *selectable_p,
MSG_COMMAND_CHECK_STATE *selected_p,
const char **display_string,
XP_Bool * plural_p);
virtual MsgERR DoCommand(MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices);
const char* GetDefaultURL();
int SetCallbacks(MSG_CompositionPaneCallbacks* callbacks, void* closure);
MSG_CompositionFields* GetInitialFields();
MSG_HEADER_SET GetInterestingHeaders();
int SetAttachmentList(struct MSG_AttachmentData*);
char* GetAttachmentString();
XP_Bool ShouldAutoQuote();
const char* GetCompHeader(MSG_HEADER_SET);
int SetCompHeader(MSG_HEADER_SET, const char*);
XP_Bool GetCompBoolHeader(MSG_BOOL_HEADER_SET);
int SetCompBoolHeader(MSG_BOOL_HEADER_SET, XP_Bool);
const char* GetCompBody();
int SetCompBody(const char*);
void ToggleCompositionHeader(uint32 header);
XP_Bool ShowingAllCompositionHeaders();
XP_Bool ShowingCompositionHeader(uint32 mask);
XP_Bool GetHTMLMarkup(void);
void SetHTMLMarkup(XP_Bool flag);
MsgERR QuoteMessage(int (*func)(void* closure, const char* data),
void* closure);
int PastePlaintextQuotation(const char* str);
const struct MSG_AttachmentData *GetAttachmentList();
int DownloadAttachments();
char* UpdateHeaderContents(MSG_HEADER_SET which_header, const char* value);
const char* GetWindowTitle();
void SetBodyEdited(XP_Bool value);
void MailCompositionAllConnectionsComplete();
XP_Bool DeliveryInProgress();
int SendMessageNow();
int QueueMessageForLater();
int SaveMessageAsDraft();
int SaveMessageAsTemplate();
XP_Bool IsDuplicatePost();
const char* GetCompositionMessageID();
void ClearCompositionMessageID();
HG22960
int SanityCheck(int skippast);
/* draft */
int SetPreloadedAttachments ( MWContext *context,
struct MSG_AttachmentData *attachmentData,
struct MSG_AttachedFile *attachments,
int attachments_count );
#ifdef MOZ_MAIL_NEWS
virtual void SetIMAPMessageUID (MessageKey key);
#endif /* MOZ_MAIL_NEWS */
int RetrieveStandardHeaders(MSG_HeaderEntry ** return_list);
void SetHeaderEntries(MSG_HeaderEntry * in_list,int count);
void ClearComposeHeaders();
int SetHTMLAction(MSG_HTMLComposeAction action) {
m_htmlaction = action;
return 0;
}
MSG_HTMLComposeAction GetHTMLAction() {return m_htmlaction;}
int PutUpRecipientsDialog(void *pWnd = NULL);
int ResultsRecipients(XP_Bool cancelled, int32* nohtml, int32* htmlok);
XP_Bool m_confirmed_uuencode_p; // Have we confirmed sending uuencoded data?
// For qutoing plain text to html then convert back to plain text
void SetLineWidth(int width) { m_lineWidth = width; }
int GetLineWidth() { return m_lineWidth; }
protected:
static void QuoteHTMLDone_S(URL_Struct* url,
int status, MWContext* context);
void InitializeHeaders(MWContext* old_context,
MSG_CompositionFields* fields);
char* FigureBcc(XP_Bool newsBcc);
static void GetUrlDone_S(PrintSetup*);
void GetUrlDone(PrintSetup*);
static void DownloadAttachmentsDone_S(MWContext *context,
void *fe_data,
int status,
const char *error_message,
struct MSG_AttachedFile *attachmnts);
void DownloadAttachmentsDone(MWContext* context, int status,
const char* error_message,
struct MSG_AttachedFile *attachments);
int DoneComposeMessage(MSG_Deliver_Mode deliver_mode);
static void DeliveryDoneCB_s(MWContext *context, void *fe_data, int status,
const char *error_message);
void DeliveryDoneCB(MWContext* context, int status,
const char* error_message);
HG22860
XP_Bool HasNoMarkup();
MSG_HTMLComposeAction DetermineHTMLAction();
int MungeThroughRecipients(XP_Bool* someNonHTML, XP_Bool* groupNonHTML);
static PRBool AskDialogDone_s(XPDialogState *state, char **argv, int argc,
unsigned int button);
PRBool AskDialogDone(XPDialogState *state, char **argv, int argc,
unsigned int button);
static PRBool RecipientDialogDone_s(XPDialogState *state, char **argv,
int argc, unsigned int button);
PRBool RecipientDialogDone(XPDialogState *state, char **argv, int argc,
unsigned int button);
int CreateVcardAttachment ();
MSG_REPLY_TYPE m_replyType; /* The kind of message composition in
progress (reply, forward, etc.) */
XP_Bool m_markup; /* Whether we should generate messages
whose first part is text/html rather
than text/plain. */
MSG_AttachmentData *m_attachData; /* null-terminated list of the URLs and
desired types currently scheduled
for attachment. */
MSG_AttachedFile *m_attachedFiles; /* The attachments which have already
been downloaded, and some info about
them. */
char *m_defaultUrl; /* Default URL for attaching, etc. */
MSG_CompositionFields* m_initfields; // What all the fields were,
// initially.
MSG_CompositionFields* m_fields; // Current value of all the fields.
char* m_messageId; // Message-Id to use for composition.
char* m_attachmentString; // Storage for string to display in UI for
// the list of attachments.
char* m_quotedText; // The results of quoting the original text.
/* Stuff used while quoting a message. */
PrintSetup* m_print;
MWContext *m_textContext;
char* m_quoteUrl;
URL_Struct *m_dummyUrl;
Net_GetUrlExitFunc *m_exitQuoting;
int (*m_quotefunc)(void* closure, const char* data);
void* m_quoteclosure;
XP_Bool m_deliveryInProgress; /* True while mail is being sent. */
XP_Bool m_attachmentInProgress; /* True while attachments being
saved. */
int m_pendingAttachmentsCount;
MSG_Deliver_Mode m_deliver_mode; /* MSG_DelverNow, MSG_QueueForLater,
* MSG_SaveAsDraft, MSG_SaveAsTemplate
*/
XP_Bool m_cited;
XP_Bool m_duplicatePost; /* Whether we seem to be trying for a
second time to post the same message.
(If this is true, then we know to ignore
435 errors from the newsserver.) */
HG92827
MSG_HTMLComposeAction m_htmlaction;
MSG_HTMLRecipients* m_htmlrecip;
int m_status;
// I'm sure this isn't what Terry had in mind... // ### dmb
MSG_HEADER_SET m_visible_headers;
MSG_NewsHost* m_host; // Which newshost we're posting to. This is
// lazily evaluated, so a NULL does necessarily
// mean we have no news host specified.
XP_Bool m_closeAfterSave;
XP_Bool m_haveQuoted;
XP_Bool m_haveAttachedVcard;
MSG_CompositionPaneCallbacks m_callbacks;
void* m_callbackclosure;
int m_lineWidth; // for quoting plain text to html then convert back
// to plain text
};
#endif /* _MsgCPane_H_ */

View File

@@ -0,0 +1,834 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "rosetta.h"
#include "msg.h"
#include "msgcom.h"
#include "error.h"
#include "client.h"
#include "xpgetstr.h"
#include "msgcpane.h"
#include "msgprefs.h"
#include "msgmast.h"
#include "msgcflds.h"
#include "shist.h"
#include "msgppane.h"
#include "mime.h"
#include "msgbg.h"
#include "prefapi.h"
#include "msgurlq.h"
#include "msgsend.h"
#include "pw_public.h"
#include HG99874
extern "C"
{
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_ID_NOT_IN_FOLDER;
extern int MK_MSG_CANT_OPEN;
extern int MK_MSG_INBOX_L10N_NAME;
extern int MK_MSG_OUTBOX_L10N_NAME;
extern int MK_MSG_OUTBOX_L10N_NAME_OLD;
extern int MK_MSG_TRASH_L10N_NAME;
extern int MK_MSG_DRAFTS_L10N_NAME;
extern int MK_MSG_SENT_L10N_NAME;
extern int MK_MSG_TEMPLATES_L10N_NAME;
extern int XP_MSG_IMAP_ACL_FULL_RIGHTS;
extern int XP_MSG_IMAP_PERSONAL_FOLDER_TYPE_NAME;
extern int XP_MSG_IMAP_PERSONAL_FOLDER_TYPE_DESCRIPTION;
}
#ifndef IMAP4_PORT_SSL_DEFAULT
#define IMAP4_PORT_SSL_DEFAULT 993 /* use a separate port for imap4 over ssl */
#endif
#if defined(XP_MAC) && defined (__MWERKS__)
#pragma require_prototypes off
#endif
extern "C"
int ConvertMsgErrToMKErr(uint32 err); // ### Need to get from a header file...
inline MSG_CompositionPane* CastCompositionPane(MSG_Pane* pane) {
XP_ASSERT(pane && pane->GetPaneType() == MSG_COMPOSITIONPANE);
return (MSG_CompositionPane*) pane;
}
extern "C" MSG_Pane* MSG_FindPane(MWContext* context, MSG_PaneType type) {
return MSG_Pane::FindPane(context, type, FALSE);
}
extern "C" XP_Bool
MSG_RequiresMailWindow (const char *) { return FALSE; }
extern "C" XP_Bool
MSG_RequiresNewsWindow (const char *) { return FALSE; }
/* If this URL requires a particular kind of window, and this is not
that kind of window, then we need to find or create one.
*/
XP_Bool msg_NewWindowRequired (MWContext *context, const char *url)
{
if (!context)
return TRUE;
if (context->type == MWContextSearch || context->type == MWContextPrint || context->type == MWContextBiff)
return FALSE;
/* Search URLs always run in the pane they started in */
if (!XP_STRNCASECMP(url, "search-libmsg:", 14))
return FALSE;
// If we can figure out the content type, and there is no converter,
// return FALSE so we'll run the save as url in our window instead
// of creating an empty browser window.
char *contentType = MimeGetURLContentType(context, url);
if (contentType && !NET_HaveConverterForMimeType(contentType))
return FALSE;
/* This is not a browser window, and one is required. */
if (context->type != MWContextBrowser && context->type != MWContextPane && MSG_RequiresBrowserWindow(url))
return TRUE;
return FALSE; /*!msgPane && threadPane; */ // if msgPane is NULL, but we have a thread pane, return FALSE because we have the wrong window.
}
extern "C" XP_Bool MSG_NewWindowRequiredForURL (MWContext *context, URL_Struct *urlStruct)
{
if (urlStruct->open_new_window_specified)
return urlStruct->open_new_window;
if (context->type != MWContextBrowser && !strncasecomp (urlStruct->address, "about:", 6) && !urlStruct->internal_url
&& strncasecomp(urlStruct->address, "about:editfilenew", 17))
return TRUE;
return msg_NewWindowRequired(context, urlStruct->address);
}
extern "C"
{
void MSG_InitMsgLib(void) { } ;
}
extern "C" MSG_Master* MSG_InitializeMail(MSG_Prefs* prefs)
{
MSG_Master *master = prefs->GetMasterForBiff();
if (master)
return (master); // already initialized
MSG_InitMsgLib(); // make sure db code is initialized
master = new MSG_Master(prefs);
prefs->SetMasterForBiff(master);
return master;
}
extern "C" MSG_Pane* MSG_CreateProgressPane (MWContext *context,
MSG_Master *master,
MSG_Pane *parentPane)
{
return new MSG_ProgressPane(context, master, parentPane);
}
extern "C" MSG_Pane* MSG_CreateCompositionPane(MWContext* context,
MWContext* old_context,
MSG_Prefs* prefs,
MSG_CompositionFields* fields,
MSG_Master* master)
{
return new MSG_CompositionPane(context, old_context, prefs, fields, master);
}
extern "C" int
MSG_SetCompositionPaneCallbacks(MSG_Pane* composepane,
MSG_CompositionPaneCallbacks* callbacks,
void* closure)
{
return CastCompositionPane(composepane)->SetCallbacks(callbacks, closure);
}
extern "C" MSG_Pane* MSG_CreateCompositionPaneNoInit(MWContext* context,
MSG_Prefs* prefs,
MSG_Master* master)
{
return new MSG_CompositionPane(context, prefs, master);
}
extern "C" int MSG_InitializeCompositionPane(MSG_Pane* comppane,
MWContext* old_context,
MSG_CompositionFields* fields)
{
return CastCompositionPane(comppane)->Initialize(old_context, fields);
}
extern "C" void MSG_SetFEData(MSG_Pane* pane, void* data) {
pane->SetFEData(data);
}
extern "C" void* MSG_GetFEData(MSG_Pane* pane) {
return pane->GetFEData();
}
extern "C" MSG_PaneType MSG_GetPaneType(MSG_Pane* pane) {
return pane->GetPaneType();
}
extern "C" MWContext* MSG_GetContext(MSG_Pane* pane) {
if (pane)
return pane->GetContext();
else
return NULL;
}
extern "C" MSG_Prefs* MSG_GetPrefs(MSG_Pane* pane) {
return pane->GetPrefs();
}
extern "C" void MSG_WriteNewProfileAge() {
PREF_SetIntPref("mailnews.profile_age", MSG_IMAP_CURRENT_START_FLAGS);
}
extern "C" MSG_Prefs* MSG_GetPrefsForMaster(MSG_Master* master) {
return master->GetPrefs();
}
extern "C" int MSG_GetURL(MSG_Pane *pane, URL_Struct* url)
{
XP_ASSERT(pane && url);
if (pane && url)
{
url->msg_pane = pane;
return msg_GetURL(pane->GetContext(), url, FALSE);
}
else
return 0;
}
extern "C" void MSG_Command(MSG_Pane* pane, MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices) {
int status =
ConvertMsgErrToMKErr(pane->DoCommand(command, indices, numindices));
if (status < 0) {
char* pString = XP_GetString(status);
if (pString && strlen(pString))
FE_Alert(pane->GetContext(), pString);
}
}
extern "C" int MSG_CommandStatus(MSG_Pane* pane,
MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices,
XP_Bool *selectable_p,
MSG_COMMAND_CHECK_STATE *selected_p,
const char **display_string,
XP_Bool *plural_p) {
return ConvertMsgErrToMKErr(pane->GetCommandStatus(command,
indices, numindices,
selectable_p,
selected_p,
display_string,
plural_p));
}
extern "C" int MSG_SetToggleStatus(MSG_Pane* pane, MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices,
MSG_COMMAND_CHECK_STATE value) {
return ConvertMsgErrToMKErr(pane->SetToggleStatus(command,
indices, numindices,
value));
}
extern "C" MSG_COMMAND_CHECK_STATE MSG_GetToggleStatus(MSG_Pane* pane,
MSG_CommandType command,
MSG_ViewIndex* indices,
int32 numindices)
{
return pane->GetToggleStatus(command, indices, numindices);
}
extern "C" void MSG_DestroyMaster (MSG_Master* master) {
delete master;
}
extern "C" void MSG_DestroyPane(MSG_Pane* pane) {
delete pane;
}
extern "C" void MSG_SetLineWidth(MSG_Pane* composepane, int width)
{
CastCompositionPane(composepane)->SetLineWidth(width);
}
extern "C" int MSG_SetHTMLAction(MSG_Pane* composepane,
MSG_HTMLComposeAction action)
{
return CastCompositionPane(composepane)->SetHTMLAction(action);
}
extern "C" MSG_HTMLComposeAction MSG_GetHTMLAction(MSG_Pane* composepane)
{
return CastCompositionPane(composepane)->GetHTMLAction();
}
extern "C" int MSG_PutUpRecipientsDialog(MSG_Pane* composepane, void *pWnd)
{
return CastCompositionPane(composepane)->PutUpRecipientsDialog(pWnd);
}
extern "C" int MSG_ResultsRecipients(MSG_Pane* composepane,
XP_Bool cancelled,
int32* nohtml,
int32* htmlok)
{
return CastCompositionPane(composepane)->ResultsRecipients(cancelled,
nohtml,
htmlok);
}
extern "C" XP_Bool MSG_GetHTMLMarkup(MSG_Pane * composepane) {
return CastCompositionPane(composepane)->GetHTMLMarkup();
}
extern "C" XP_Bool MSG_DeliveryInProgress(MSG_Pane * composepane) {
if (!composepane || MSG_COMPOSITIONPANE != MSG_GetPaneType(composepane))
return FALSE;
return CastCompositionPane(composepane)->DeliveryInProgress();
}
extern "C" void MSG_SetHTMLMarkup(MSG_Pane * composepane, XP_Bool flag) {
CastCompositionPane(composepane)->SetHTMLMarkup(flag);
}
extern "C" const char *MSG_GetMessageIdFromState(void *state)
{
if (state)
{
MSG_SendMimeDeliveryState *deliveryState =
(MSG_SendMimeDeliveryState *) state;
return deliveryState->m_fields->GetMessageId();
}
return NULL;
}
extern "C" XP_Bool MSG_IsSaveDraftDeliveryState(void *state)
{
if (state)
return (((MSG_SendMimeDeliveryState *) state)->m_deliver_mode ==
MSG_SaveAsDraft);
return FALSE;
}
extern "C" int MSG_SetPreloadedAttachments ( MSG_Pane *composepane,
MWContext *context,
void *attachmentData,
void *attachments,
int attachments_count )
{
return ConvertMsgErrToMKErr ( CastCompositionPane(
composepane)->SetPreloadedAttachments (
context,
(MSG_AttachmentData *) attachmentData,
(MSG_AttachedFile *) attachments,
attachments_count) );
}
extern "C" MSG_Prefs* MSG_CreatePrefs() {
return new MSG_Prefs();
}
extern "C" void MSG_DestroyPrefs(MSG_Prefs* prefs) {
delete prefs;
}
extern "C" XP_Bool
MSG_GetNoInlineAttachments(MSG_Prefs* prefs)
{
return prefs->GetNoInlineAttachments();
}
extern "C" XP_Bool MSG_GetAutoQuoteReply(MSG_Prefs* prefs) {
return prefs->GetAutoQuoteReply();
}
extern MSG_Pane*
MSG_GetParentPane(MSG_Pane* progresspane)
{
return progresspane->GetParentPane();
}
extern "C" MSG_Pane*
MSG_MailDocument (MWContext *old_context)
{
// For backwards compatability.
return MSG_MailDocumentURL(old_context,NULL);
}
extern "C" MSG_Pane*
MSG_MailDocumentURL (MWContext *old_context,const char *url)
{
// Don't allow a compose window to be created if the user hasn't
// specified an email address
const char *real_addr = FE_UsersMailAddress();
if (MISC_ValidateReturnAddress(old_context, real_addr) < 0)
return NULL;
MSG_CompositionFields* fields = new MSG_CompositionFields();
if (!fields) return NULL; // Out of memory.
/* It's so cool that there are half a dozen entrypoints to
composition-window-creation. */
HG62239
/* If url is not specified, grab current history entry. */
if (!url) {
History_entry *h =
(old_context ? SHIST_GetCurrent (&old_context->hist) : 0);
if (h && h->address && *h->address) {
url = h->address;
}
}
#if 1 /* Do this if we want to attach the target of Mail Document by default */
if (url) {
fields->SetHeader(MSG_ATTACHMENTS_HEADER_MASK, url);
}
#endif
if (old_context && old_context->title) {
fields->SetHeader(MSG_SUBJECT_HEADER_MASK, old_context->title);
}
if (url) {
fields->SetBody(url);
}
XP_Bool prefBool = FALSE;
PREF_GetBoolPref("mail.attach_vcard",&prefBool);
fields->SetAttachVCard(prefBool);
MSG_CompositionPane* comppane = (MSG_CompositionPane*)
FE_CreateCompositionPane(old_context, fields, NULL, MSG_DEFAULT);
if (!comppane) {
delete fields;
return NULL;
}
HG42420
XP_ASSERT(comppane->GetPaneType() == MSG_COMPOSITIONPANE);
return comppane;
}
extern "C" MSG_Pane*
MSG_Mail (MWContext *old_context)
{
MSG_CompositionFields* fields = new MSG_CompositionFields();
if (!fields) return NULL; // Out of memory.
/* It's so cool that there are half a dozen entrypoints to
composition-window-creation. */
HG42933
XP_Bool prefBool = FALSE;
PREF_GetBoolPref("mail.attach_vcard",&prefBool);
fields->SetAttachVCard(prefBool);
MSG_CompositionPane* comppane = (MSG_CompositionPane*)
FE_CreateCompositionPane(old_context, fields, NULL, MSG_DEFAULT);
if (!comppane) {
delete fields;
return NULL;
}
HG52965
XP_ASSERT(comppane->GetPaneType() == MSG_COMPOSITIONPANE);
return comppane;
}
extern "C" void
MSG_ResetUUEncode(MSG_Pane *pane)
{
CastCompositionPane(pane)->m_confirmed_uuencode_p = FALSE;
}
extern "C" MSG_CompositionFields*
MSG_CreateCompositionFields (
const char *from,
const char *reply_to,
const char *to,
const char *cc,
const char *bcc,
const char *fcc,
const char *newsgroups,
const char *followup_to,
const char *organization,
const char *subject,
const char *references,
const char *other_random_headers,
const char *priority,
const char *attachment,
const char *newspost_url
HG66663
)
{
MSG_CompositionFields* fields = new MSG_CompositionFields();
fields->SetFrom(from);
fields->SetReplyTo(reply_to);
fields->SetTo(to);
fields->SetCc(cc);
fields->SetBcc(bcc);
fields->SetFcc(fcc);
fields->SetNewsgroups(newsgroups);
fields->SetFollowupTo(followup_to);
fields->SetOrganization(organization);
fields->SetSubject(subject);
fields->SetReferences(references);
fields->SetOtherRandomHeaders(other_random_headers);
fields->SetAttachments(attachment);
fields->SetNewspostUrl(newspost_url);
fields->SetPriority(priority);
HG65243
return fields;
}
extern "C" void
MSG_DestroyCompositionFields(MSG_CompositionFields *fields)
{
delete fields;
}
extern "C" void
MSG_SetCompFieldsReceiptType(MSG_CompositionFields *fields,
int32 type)
{
fields->SetReturnReceiptType(type);
}
extern "C" int32
MSG_GetCompFieldsReceiptType(MSG_CompositionFields *fields)
{
return fields->GetReturnReceiptType();
}
extern "C" int
MSG_SetCompFieldsBoolHeader(MSG_CompositionFields *fields,
MSG_BOOL_HEADER_SET header,
XP_Bool bValue)
{
return fields->SetBoolHeader(header, bValue);
}
extern "C" XP_Bool
MSG_GetCompFieldsBoolHeader(MSG_CompositionFields *fields,
MSG_BOOL_HEADER_SET header)
{
return fields->GetBoolHeader(header);
}
extern "C" XP_Bool
MSG_GetForcePlainText(MSG_CompositionFields* fields)
{
return fields->GetForcePlainText();
}
extern "C" MSG_Pane*
MSG_ComposeMessage (MWContext *old_context,
const char *from,
const char *reply_to,
const char *to,
const char *cc,
const char *bcc,
const char *fcc,
const char *newsgroups,
const char *followup_to,
const char *organization,
const char *subject,
const char *references,
const char *other_random_headers,
const char *priority,
const char *attachment,
const char *newspost_url,
const char *body,
HG00282
XP_Bool force_plain_text,
const char* html_part
)
{
// Don't allow a compose window to be created if the user hasn't
// specified an email address
const char *real_addr = FE_UsersMailAddress();
if (MISC_ValidateReturnAddress(old_context, real_addr) < 0)
return NULL;
HG02872
MSG_CompositionFields* fields =
MSG_CreateCompositionFields(from, reply_to, to, cc, bcc,
fcc, newsgroups, followup_to,
organization, subject, references,
other_random_headers, priority, attachment,
newspost_url HG65241);
fields->SetForcePlainText(force_plain_text);
fields->SetHTMLPart(html_part);
fields->SetDefaultBody(body);
XP_Bool prefBool = FALSE;
PREF_GetBoolPref("mail.attach_vcard",&prefBool);
fields->SetAttachVCard(prefBool);
MSG_CompositionPane* comppane = (MSG_CompositionPane*)
FE_CreateCompositionPane(old_context, fields, NULL, MSG_DEFAULT);
if (!comppane) {
delete fields;
return NULL;
}
XP_ASSERT(comppane->GetPaneType() == MSG_COMPOSITIONPANE);
return comppane;
}
extern "C" XP_Bool
MSG_ShouldAutoQuote(MSG_Pane* comppane)
{
return CastCompositionPane(comppane)->ShouldAutoQuote();
}
extern "C" const char*
MSG_GetCompHeader(MSG_Pane* comppane, MSG_HEADER_SET header)
{
return CastCompositionPane(comppane)->GetCompHeader(header);
}
extern "C" int
MSG_SetCompHeader(MSG_Pane* comppane, MSG_HEADER_SET header, const char* value)
{
return CastCompositionPane(comppane)->SetCompHeader(header, value);
}
extern "C" XP_Bool
MSG_GetCompBoolHeader(MSG_Pane* comppane, MSG_BOOL_HEADER_SET header)
{
return CastCompositionPane(comppane)->GetCompBoolHeader(header);
}
extern "C" int
MSG_SetCompBoolHeader(MSG_Pane* comppane, MSG_BOOL_HEADER_SET header, XP_Bool bValue)
{
return CastCompositionPane(comppane)->SetCompBoolHeader(header, bValue);
}
extern "C" const char*
MSG_GetCompBody(MSG_Pane* comppane)
{
return CastCompositionPane(comppane)->GetCompBody();
}
extern "C" int
MSG_SetCompBody(MSG_Pane* comppane, const char* value)
{
return CastCompositionPane(comppane)->SetCompBody(value);
}
extern "C" void
MSG_QuoteMessage(MSG_Pane* comppane,
int (*func)(void* closure, const char* data),
void* closure)
{
CastCompositionPane(comppane)->QuoteMessage(func, closure);
}
extern "C" int
MSG_SanityCheck(MSG_Pane* comppane, int skippast)
{
return CastCompositionPane(comppane)->SanityCheck(skippast);
}
extern "C" const char*
MSG_GetAssociatedURL(MSG_Pane* comppane)
{
return CastCompositionPane(comppane)->GetDefaultURL();
}
extern "C" void
MSG_MailCompositionAllConnectionsComplete(MSG_Pane* comppane)
{
CastCompositionPane(comppane)->MailCompositionAllConnectionsComplete();
}
extern "C" int
MSG_PastePlaintextQuotation(MSG_Pane* comppane, const char* string)
{
return CastCompositionPane(comppane)->PastePlaintextQuotation(string);
}
extern "C" char*
MSG_UpdateHeaderContents(MSG_Pane* comppane,
MSG_HEADER_SET header,
const char* value)
{
return CastCompositionPane(comppane)->UpdateHeaderContents(header, value);
}
extern "C" int
MSG_SetAttachmentList(MSG_Pane* comppane,
struct MSG_AttachmentData* list)
{
return CastCompositionPane(comppane)->SetAttachmentList(list);
}
extern "C" const struct MSG_AttachmentData*
MSG_GetAttachmentList(MSG_Pane* comppane)
{
return CastCompositionPane(comppane)->GetAttachmentList();
}
extern "C" MSG_HEADER_SET MSG_GetInterestingHeaders(MSG_Pane* comppane)
{
return CastCompositionPane(comppane)->GetInterestingHeaders();
}
extern "C" XP_Bool MSG_IsDuplicatePost(MSG_Pane* comppane) {
// if we're sending from the outbox, we don't have a compostion pane, so guess NO.
return (comppane->GetPaneType() == MSG_COMPOSITIONPANE)
? CastCompositionPane(comppane)->IsDuplicatePost()
: FALSE;
}
extern "C" void
MSG_ClearCompositionMessageID(MSG_Pane* comppane)
{
if (comppane->GetPaneType() == MSG_COMPOSITIONPANE)
CastCompositionPane(comppane)->ClearCompositionMessageID();
}
extern "C" const char*
MSG_GetCompositionMessageID(MSG_Pane* comppane)
{
return (comppane->GetPaneType() == MSG_COMPOSITIONPANE)
? CastCompositionPane(comppane)->GetCompositionMessageID()
: 0;
}
/* What are we going to do about error messages and codes? Internally, we'd
like a nice error range system, but we need to export errors too... ###
*/
extern "C"
int ConvertMsgErrToMKErr(MsgERR err)
{
switch (err)
{
case eSUCCESS:
return 0;
case eOUT_OF_MEMORY:
return MK_OUT_OF_MEMORY;
case eID_NOT_FOUND:
return MK_MSG_ID_NOT_IN_FOLDER;
case eUNKNOWN:
return -1;
}
// Well, most likely, someone returned a negative number that
// got cast somewhere into a MsgERR. If so, just return that value.
if (int(err) < 0) return int(err);
// Punt, and return the generic unknown error.
return -1;
}
extern "C"
int MSG_RetrieveStandardHeaders(MSG_Pane * pane, MSG_HeaderEntry ** return_list)
{
XP_ASSERT(pane && pane->GetPaneType() == MSG_COMPOSITIONPANE);
return CastCompositionPane(pane)->RetrieveStandardHeaders(return_list);
}
extern "C"
void MSG_SetHeaderEntries(MSG_Pane * pane,MSG_HeaderEntry * in_list,int count)
{
XP_ASSERT(pane && pane->GetPaneType() == MSG_COMPOSITIONPANE);
CastCompositionPane(pane)->SetHeaderEntries(in_list,count);
}
extern "C"
void MSG_ClearComposeHeaders(MSG_Pane * pane)
{
XP_ASSERT(pane && pane->GetPaneType() == MSG_COMPOSITIONPANE);
CastCompositionPane(pane)->ClearComposeHeaders();
}
extern "C"
int MSG_ProcessBackground(URL_Struct* urlstruct)
{
return msg_Background::ProcessBackground(urlstruct);
}
extern "C" XP_Bool MSG_RequestForReturnReceipt(MSG_Pane *pane)
{
return pane->GetRequestForReturnReceipt();
}
extern "C" XP_Bool MSG_SendingMDNInProgress(MSG_Pane *pane)
{
return pane->GetSendingMDNInProgress();
}
//
// NET_IsOffline() is declared in net.h, but libnet doesn't define it
// publically anywhere. There's one in network/protocols/nntp/mknews.c
// but it's declared MODULE_PRIVATE and we can't see it from here,
// at least not in MOZ_MAIL_COMPOSE mode.
//
#ifndef MOZ_MAIL_NEWS
XP_Bool NET_IsOffline() { return FALSE; }
#endif /* MOZ_MAIL_NEWS */

View File

@@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgHdr_H_
#define _MsgHdr_H_
const int kMaxSubject = 160;
const int kMaxAuthor = 160;
const int kMaxRecipient = 80;
const int kMaxMsgIdLen = 80;
const int kMaxReferenceLen = 10 * kMaxMsgIdLen;
typedef int32 MsgFlags; // try to keep flags view is going to care about
// in the first byte, so we can copy the flags over directly
const int32 kIsRead = 0x1; // same as MSG_FLAG_READ
const int32 kReplied = 0x2; // same as MSG_FLAG_REPLIED
const int32 kMsgMarked = 0x4; // same as MSG_FLAG_MARKED - (kMarked collides with IMAP)
const int32 kHasChildren = 0x8; // no equivalent (shares space with FLAG_EXPUNGED)
const int32 kIsThread = 0x10; // !!shares space with MSG_FLAG_HAS_RE
const int32 kElided = 0x20; // same as MSG_FLAG_ELIDED
const int32 kExpired = 0x40; // same as MSG_FLAG_EXPIRED
const int32 kOffline = 0x80; // this message has been downloaded
const int32 kWatched = 0x100;
const int32 kSenderAuthed = 0x200; // same as MSG_FLAG_SENDER_AUTHED
const int32 kExpunged = 0x400; // NOT same value as MSG_FLAG_EXPUNGED
const int32 kHasRe = 0x800; // Not same values as MSG_FLAG_HAS_RE
const int32 kForwarded = 0x1000; // this message has been forward (mail only)
const int32 kIgnored = 0x2000; // this message is ignored
const int32 kMDNNeeded = 0x4000; // this message needs MDN report
const int32 kMDNSent = 0x8000; // MDN report has been Sent
const int32 kNew = 0x10000; // used for status, never stored in db.
const int32 kAdded = 0x20000; // Just added to db - used in
// notifications, never set in msgHdr.
const int32 kTemplate = 0x40000; // this message is a template
const int32 kDirty = 0x80000;
const int32 kPartial = 0x100000; // NOT same value as MSG_FLAG_PARTIAL
const int32 kIMAPdeleted = 0x200000; // same value as MSG_FLAG_IMAP_DELETED
const int32 kHasAttachment = 0x10000000; // message has attachments
const int32 kSameAsMSG_FLAG = kHasAttachment|kIsRead|kMsgMarked|kExpired|kElided|kSenderAuthed|kReplied|kOffline|kForwarded|kWatched|kIMAPdeleted;
const int32 kMozillaSameAsMSG_FLAG = kIsRead|kMsgMarked|kExpired|kElided|kSenderAuthed|kReplied|kOffline|kForwarded|kWatched|kIMAPdeleted;
const int32 kExtraFlags = 0xFF;
struct MessageHdrStruct
{
MessageKey m_threadId;
MessageKey m_messageKey;
char m_subject[kMaxSubject];
char m_author[kMaxAuthor];
char m_messageId[kMaxMsgIdLen];
char m_references[kMaxReferenceLen];
char m_recipients[kMaxRecipient];
time_t m_date;
uint32 m_messageSize; // lines for news articles, bytes for mail messages
uint32 m_flags;
uint16 m_numChildren; // for top-level threads
uint16 m_numNewChildren; // for top-level threads
char m_level; // indentation level
MSG_PRIORITY m_priority;
public:
void SetSubject(const char * subject);
void SetAuthor(const char * author);
void SetMessageID(const char * msgID);
void SetReferences(const char * referencesStr);
void SetDate(const char * date);
void SetLines(uint32 lines);
void SetSize(uint32 size);
const char *GetReference(const char *nextRef, char *reference);
static void StripMessageId(const char *msgID, char *outMsgId, int msgIdLen);
};
#endif _MsgHdr_H_

View File

@@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define FORCE_PR_LOG /* Allow logging in the release build */
#include "rosetta.h"
#include "msg.h"
#include "errcode.h"
#include "msgmast.h"
#include "msgprefs.h"
#include "prtime.h"
#include "prefapi.h"
#include "rosetta.h"
#include HG99877
#include "msgurlq.h"
#include "xpgetstr.h"
#include "prlog.h"
#include "nslocks.h"
#include "pw_public.h"
extern "C" {
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_SET_HTML_NEWSGROUP_HEIRARCHY_CONFIRM;
extern int MK_MSG_FOLDER_ALREADY_EXISTS;
extern int MK_MSG_INBOX_L10N_NAME;
extern int MK_IMAP_UPGRADE_WAIT_WHILE_UPGRADE;
extern int MK_IMAP_UPGRADE_PROMPT_QUESTION;
extern int MK_IMAP_UPGRADE_CUSTOM;
extern int MK_POP3_USERNAME_UNDEFINED;
extern int XP_PASSWORD_FOR_POP3_USER;
extern int XP_MSG_CACHED_PASSWORD_NOT_MATCHED;
extern int XP_MSG_PASSWORD_FAILED;
extern int MK_POP3_PASSWORD_UNDEFINED;
}
#ifndef NSPR20
PR_LOG_DEFINE(IMAP);
#else
PRLogModuleInfo *IMAP;
#endif
MSG_Master::MSG_Master(MSG_Prefs* prefs)
{
XP_Bool purgeBodiesByAge;
int32 purgeMethod;
int32 daysToKeepHdrs;
int32 headersToKeep;
int32 daysToKeepBodies;
m_prefs = prefs;
m_prefs->AddNotify(this);
#ifndef NSPR20
PR_LogInit(&IMAPLog);
#else
IMAP = PR_NewLogModule("IMAP");
#endif
// on the mac, use this java script preference
// as an alternate to setenv
XP_Bool imapIOlogging;
PREF_GetBoolPref("imap.io.mac.logging", &imapIOlogging);
if (imapIOlogging)
IMAP->level = PR_LOG_ALWAYS;
}
MSG_Master::~MSG_Master()
{
m_prefs->RemoveNotify(this);
}
void
MSG_Master::SetFirstPane(MSG_Pane* pane)
{
m_firstpane = pane;
}
MSG_Pane*
MSG_Master::GetFirstPane()
{
return m_firstpane;
}
void MSG_Master::NotifyPrefsChange(NotifyCode )
{
}

View File

@@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgMast_H_
#define _MsgMast_H_
#include "errcode.h"
#include "msgprnot.h"
class MSG_Prefs;
class MSG_Pane;
class msg_HostTable;
typedef void * pw_ptr;
class MSG_Master : public MSG_PrefsNotify {
public:
MSG_Master(MSG_Prefs* prefs);
virtual ~MSG_Master();
MSG_Prefs* GetPrefs() {return m_prefs;}
void SetFirstPane(MSG_Pane* pane);
MSG_Pane* GetFirstPane();
MSG_Pane *FindPaneOfType(MSG_FolderInfo *id, MSG_PaneType type) ;
MSG_Pane *FindPaneOfType(const char *url, MSG_PaneType type) ;
MSG_Pane *FindFirstPaneOfType(MSG_PaneType type);
MSG_Pane *FindNextPaneOfType(MSG_Pane *startHere, MSG_PaneType type);
MSG_NewsHost* FindHost(const char* name, XP_Bool isSecure,
int32 port); // If port is negative, then we will
// look for a ":portnum" as part of the
// name. Otherwise, there had better
// not be a colon in the name.
MSG_NewsHost* GetDefaultNewsHost();
void NotifyPrefsChange(NotifyCode code);
protected:
private:
MSG_Prefs* m_prefs;
MSG_Pane* m_firstpane;
};
#endif /* _MsgMast_H_ */

View File

@@ -0,0 +1,885 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msgmdn.h"
#include "net.h"
#include "xp_time.h"
#include "prtime.h"
#include "prtypes.h"
#include "fe_proto.h"
#include "msg.h"
#include "msgpane.h"
#include "prefapi.h"
#include "intl_csi.h"
#include "msgurlq.h"
#include "gui.h"
#include "msgprefs.h"
#include "mkutils.h"
#include "mktcp.h"
#include "netutils.h"
extern "C"
{
extern int MK_MSG_MDN_DISPLAYED;
extern int MK_MSG_MDN_DISPATCHED;
extern int MK_MSG_MDN_PROCESSED;
extern int MK_MSG_MDN_DELETED;
extern int MK_MSG_MDN_DENIED;
extern int MK_MSG_MDN_FAILED;
extern int MK_MSG_MDN_WISH_TO_SEND;
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_DELIV_MAIL;
extern int MK_MDN_DISPLAYED_RECEIPT;
extern int MK_MDN_DISPATCHED_RECEIPT;
extern int MK_MDN_PROCESSED_RECEIPT;
extern int MK_MDN_DELETED_RECEIPT;
extern int MK_MDN_DENIED_RECEIPT;
extern int MK_MDN_FAILED_RECEIPT;
}
extern "C" char *mime_make_separator(const char *prefix);
extern "C" char *msg_generate_message_id();
extern "C" char *strip_continuations(char *original);
#define MH_ALLOC_COPY(dst, src) \
do { dst = (char *) XP_ALLOC(src->length+1); *(dst+src->length)=0; \
if (src->length) XP_MEMCPY(dst, src->value, src->length); } while (0)
#define PUSH_N_FREE_STRING(p) \
do { if (p) { status = WriteString(p); PR_smprintf_free(p); p=0; \
if (status<0) return status; } \
else { return MK_OUT_OF_MEMORY; } } while (0)
char DispositionTypes[7][16] = {
"displayed",
"dispatched",
"processed",
"deleted",
"denied",
"failed",
""
};
MSG_ProcessMdnNeededState::MSG_ProcessMdnNeededState(
EDisposeType intendedType,
MSG_Pane *pane,
MSG_FolderInfo *folder,
uint32 key,
MimeHeaders *srcHeaders,
XP_Bool autoAction)
{
XP_ASSERT (srcHeaders && pane);
if (!srcHeaders || !pane) return;
m_disposeType = intendedType;
m_pane = pane;
m_autoAction = autoAction;
m_returnPath = MimeHeaders_get (srcHeaders, HEADER_RETURN_PATH, FALSE,
FALSE);
m_dispositionNotificationTo =
MimeHeaders_get(srcHeaders, HEADER_DISPOSITION_NOTIFICATION_TO, FALSE,
FALSE);
if (!m_dispositionNotificationTo)
m_dispositionNotificationTo =
MimeHeaders_get(srcHeaders, HEADER_RETURN_RECEIPT_TO, FALSE,
FALSE);
m_date = MimeHeaders_get (srcHeaders, HEADER_DATE, FALSE, FALSE);
m_to = MimeHeaders_get (srcHeaders, HEADER_TO, FALSE, FALSE);
m_cc = MimeHeaders_get (srcHeaders, HEADER_CC, FALSE, FALSE);
m_subject = MimeHeaders_get (srcHeaders, HEADER_SUBJECT, FALSE, FALSE);
if (m_subject) strip_continuations(m_subject);
m_messageId = MimeHeaders_get (srcHeaders, HEADER_MESSAGE_ID, FALSE,
FALSE);
m_originalRecipient = MimeHeaders_get (srcHeaders,
HEADER_ORIGINAL_RECIPIENT, FALSE,
FALSE);
m_all_headers = (char *) XP_ALLOC(srcHeaders->all_headers_fp + 1);
*(m_all_headers+srcHeaders->all_headers_fp)=0;
m_all_headers_size = srcHeaders->all_headers_fp;
XP_MEMCPY(m_all_headers, srcHeaders->all_headers,
srcHeaders->all_headers_fp);
InitAndProcess();
}
MSG_ProcessMdnNeededState::MSG_ProcessMdnNeededState(
EDisposeType intendedType,
MSG_Pane *pane,
MSG_FolderInfo *folder,
uint32 key,
struct message_header *returnPath,
struct message_header *dnt,
struct message_header *to,
struct message_header *cc,
struct message_header *subject,
struct message_header *date,
struct message_header *originalRecipient,
struct message_header *messageId,
char *allHeaders,
int32 allHeadersSize,
XP_Bool autoAction)
{
XP_ASSERT (pane);
if (!pane) return;
m_disposeType = intendedType;
m_pane = pane;
m_autoAction = autoAction;
MH_ALLOC_COPY (m_returnPath, returnPath);
MH_ALLOC_COPY (m_dispositionNotificationTo, dnt);
MH_ALLOC_COPY (m_to, to);
MH_ALLOC_COPY (m_cc, cc);
MH_ALLOC_COPY (m_date, date);
MH_ALLOC_COPY (m_subject, subject);
MH_ALLOC_COPY (m_originalRecipient, originalRecipient);
MH_ALLOC_COPY (m_messageId, messageId);
m_all_headers = (char *) XP_ALLOC (allHeadersSize+1);
*(m_all_headers+allHeadersSize) = 0;
m_all_headers_size = allHeadersSize;
XP_MEMCPY(m_all_headers, allHeaders, allHeadersSize);
InitAndProcess();
}
void MSG_ProcessMdnNeededState::InitAndProcess()
{
XP_Bool mdnEnabled = FALSE;
m_outFile = 0;
m_csid = 0;
m_msgFileName = 0;
m_mimeSeparator = 0;
m_autoSend = FALSE;
m_reallySendMdn = FALSE;
PREF_GetBoolPref("mail.mdn.report.enabled", &mdnEnabled);
if (m_dispositionNotificationTo &&
mdnEnabled &&
ProcessSendMode() &&
ValidateReturnPath())
CreateMdnMsg();
}
int32 MSG_ProcessMdnNeededState::OutputAllHeaders()
{
XP_ASSERT(m_all_headers && m_all_headers_size);
// **** this is disgusting; I don't have a better way to deal with it
char *buf = m_all_headers, *buf_end =
m_all_headers+m_all_headers_size;
char *start = buf, *end = buf;
int32 count = 0, ret = 0;
while (buf < buf_end)
{
switch (*buf)
{
case 0:
if (*(buf+1) == LF)
{
// *buf = CR;
end = buf;
}
else if (*(buf+1) == 0)
{
// the case of message id
*buf = '>';
}
break;
case CR:
end = buf;
*buf = 0;
break;
case LF:
if (buf > start && *(buf-1) == 0)
{
start = buf + 1;
end = start;
}
else
{
end = buf;
}
break;
}
buf++;
if (end > start && (*end == LF || !*end))
{
// strip out private X-Mozilla-Status header & X-Mozilla-Draft-Info
if (!XP_STRNCASECMP(start, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) ||
!XP_STRNCASECMP(start, X_MOZILLA_DRAFT_INFO, X_MOZILLA_DRAFT_INFO_LEN))
{
// make sure we are also copying the last null terminated char
// XP_MEMCPY(start, end+2, (buf_end+1) - (end+2));
// buf_end -= (end+2 - start);
// m_all_headers_size -= (end+2 - start);
if (*end == LF)
start = end+1;
else
start = end+2;
}
else
{
XP_Bool endIsLF = *end == LF;
if (endIsLF)
*end = 0;
char *wrapped_string = (char *)
XP_WordWrap(m_csid, (unsigned char *) start, 72, FALSE);
if (wrapped_string)
{
ret = WriteString(wrapped_string);
if (ret < 0) return ret;
count += ret;
XP_FREEIF(wrapped_string);
ret = WriteString(CRLF);
if (ret < 0) return ret;
count += ret;
}
if (endIsLF)
start = end+1;
else
start = end+2;
}
buf = start;
end = start;
}
}
return count;
}
MSG_ProcessMdnNeededState::~MSG_ProcessMdnNeededState()
{
if (m_outFile)
{
XP_FileClose(m_outFile);
m_outFile = 0;
}
if (m_msgFileName)
{
XP_FileRemove(m_msgFileName, xpFileToPost);
XP_FREEIF(m_msgFileName);
}
XP_FREEIF(m_mimeSeparator);
XP_FREEIF(m_returnPath);
XP_FREEIF(m_dispositionNotificationTo);
XP_FREEIF(m_to);
XP_FREEIF(m_cc);
XP_FREEIF(m_subject);
XP_FREEIF(m_date);
XP_FREEIF(m_originalRecipient);
XP_FREEIF(m_messageId);
XP_FREEIF(m_all_headers);
}
int32
MSG_ProcessMdnNeededState::WriteString( const char *str )
{
XP_ASSERT (str);
if (!str) return 0;
int32 len = XP_STRLEN(str);
return XP_FileWrite(str, len, m_outFile);
}
XP_Bool
MSG_ProcessMdnNeededState::MailAddrMatch( const char *addr1, const char *addr2)
{
XP_Bool isMatched = TRUE;
const char *atSign1 = NULL, *atSign2 = NULL;
const char *lt = NULL, *local1 = NULL, *local2 = NULL;
const char *end1 = NULL, *end2 = NULL;
if (!addr1 || !addr2)
return FALSE;
lt = XP_STRCHR(addr1, '<');
if (!lt)
local1 = addr1;
else
local1 = lt+1;
lt = XP_STRCHR(addr2, '<');
if (!lt)
local2 = addr2;
else
local2 = lt+1;
end1 = XP_STRCHR(local1, '>');
if (!end1)
end1 = addr1 + XP_STRLEN(addr1);
end2 = XP_STRCHR(local2, '>');
if (!end2)
end2 = addr2 + XP_STRLEN(addr2);
atSign1 = XP_STRCHR(local1, '@');
atSign2 = XP_STRCHR(local2, '@');
if (!atSign1 || !atSign2 || // ill formed addr-spec
(atSign1 - local1) != (atSign2 - local2))
{
isMatched = FALSE;
}
else if (XP_STRNCMP(local1, local2, (atSign1-local1)))
{ // case sensitive compare for local part
isMatched = FALSE;
}
else if ((end1 - atSign1) != (end2 - atSign2) ||
XP_STRNCASECMP(atSign1, atSign2, (end1 - atSign1)))
{ // case insensitive compare for domain part
isMatched = FALSE;
}
return isMatched;
}
XP_Bool
MSG_ProcessMdnNeededState::ValidateReturnPath()
{
// ValidateReturnPath applies to Automatic Send Mode only
// if we were in manual mode by pass this check
if (!m_autoSend)
return m_reallySendMdn;
if (!m_returnPath || !m_dispositionNotificationTo ||
!*m_returnPath || !*m_dispositionNotificationTo)
{
m_autoSend = FALSE;
goto done;
}
m_autoSend = MailAddrMatch(m_returnPath, m_dispositionNotificationTo);
done:
return m_reallySendMdn;
}
XP_Bool
MSG_ProcessMdnNeededState::NotInToOrCc()
{
XP_ASSERT(m_pane);
msg_StringArray to_cc_list (TRUE);
MSG_Prefs *prefs = m_pane->GetPrefs();
XP_ASSERT(prefs);
char *reply_to = NULL;
char *to = m_to ? MSG_ExtractRFC822AddressMailboxes(m_to) : (char *)NULL;
char *cc = m_cc ? MSG_ExtractRFC822AddressMailboxes(m_cc) : (char *)NULL;
const char *usr_addr = FE_UsersMailAddress();
int i, size;
XP_Bool bRet = FALSE;
// start with a simple check
if (XP_STRCASESTR(m_to, usr_addr) || XP_STRCASESTR(m_cc, usr_addr))
goto done;
PREF_CopyCharPref("mail.identity.reply_to", &reply_to);
to_cc_list.ImportTokenList(to);
to_cc_list.ImportTokenList(cc);
for (i=0, size=to_cc_list.GetSize(); i < size; i++)
{
const char *addr = to_cc_list.GetAt(i);
if (prefs->IsEmailAddressAnAliasForMe(addr) ||
(reply_to && XP_STRCASESTR(reply_to, addr)))
goto done;
}
bRet = TRUE;
done:
XP_FREEIF(to);
XP_FREEIF(cc);
XP_FREEIF(reply_to);
return bRet;
}
XP_Bool
MSG_ProcessMdnNeededState::ProcessSendMode()
{
const char *user_addr = FE_UsersMailAddress();
const char *localDomain = NULL;
char *prefDomain = NULL;
int miscState = 0;
int32 intPref;
XP_ASSERT(user_addr);
if (!user_addr)
return m_reallySendMdn;
PREF_CopyCharPref("mail.identity.defaultdomain", &prefDomain);
localDomain = XP_STRCHR(user_addr, '@');
if (prefDomain && *prefDomain)
{
if (!XP_STRCASESTR(m_dispositionNotificationTo, prefDomain))
miscState |= MDN_OUTSIDE_DOMAIN;
XP_FREEIF(prefDomain);
}
else if (localDomain)
{
localDomain++; // advance after @ sign
if (!XP_STRCASESTR(m_dispositionNotificationTo, localDomain))
miscState |= MDN_OUTSIDE_DOMAIN;
}
if (NotInToOrCc())
{
miscState |= MDN_NOT_IN_TO_CC;
}
m_reallySendMdn = TRUE;
// *********
// How are we gona deal with the auto forwarding issues? Some server
// didn't bother to add addition header or modify existing header to the
// message when forwarding. They simply copy the exact same message to
// another user's mailbox. Some change To: to Apparently-To:
// *********
// starting from lowest denominator to highest
if (!miscState)
{ // under normal situation: recipient is in to and cc
// list, sender is from the same domain
intPref = 0;
PREF_GetIntPref("mail.mdn.report.other", &intPref);
switch (intPref)
{
default:
case 0:
m_reallySendMdn = FALSE;
break;
case 1:
m_autoSend = TRUE;
break;
case 2:
m_autoSend = FALSE;
break;
case 3:
m_autoSend = TRUE;
m_disposeType = eDenied;
break;
}
#ifdef CHECK_SENDER_AND_USER_ARE_SAME
// original sender is same as current user; doesn't make sense
if (m_reallySendMdn &&
MailAddrMatch(m_dispositionNotificationTo, user_addr))
m_reallySendMdn = FALSE;
#endif
}
else if (miscState == (MDN_OUTSIDE_DOMAIN | MDN_NOT_IN_TO_CC))
{
int32 intPref2 = 0;
intPref = 0;
PREF_GetIntPref("mail.mdn.report.outside_domain", &intPref);
PREF_GetIntPref("mail.mdn.report.not_in_to_cc", &intPref2);
if (intPref != intPref2)
{
m_autoSend = FALSE; // ambiguous; always ask
}
else
{
switch (intPref)
{
default:
case 0:
m_reallySendMdn = FALSE;
break;
case 1:
m_autoSend = TRUE;
break;
case 2:
m_autoSend = FALSE;
break;
}
}
}
else if (miscState & MDN_OUTSIDE_DOMAIN)
{
intPref = 0; // reset int pref to 0
PREF_GetIntPref("mail.mdn.report.outside_domain", &intPref);
switch (intPref)
{
default:
case 0:
m_reallySendMdn = FALSE;
break;
case 1:
m_autoSend = TRUE;
break;
case 2:
m_autoSend = FALSE;
break;
}
}
else if (miscState & MDN_NOT_IN_TO_CC)
{
intPref =0; // reset to 0
PREF_GetIntPref("mail.mdn.report.not_in_to_cc", &intPref);
switch (intPref)
{
case 0:
default:
m_reallySendMdn = FALSE;
break;
case 1:
m_autoSend = TRUE;
break;
case 2:
m_autoSend = FALSE;
break;
}
}
return m_reallySendMdn;
}
void
MSG_ProcessMdnNeededState::CreateMdnMsg()
{
int32 status = 0;
if (!m_autoSend)
m_reallySendMdn =
FE_Confirm(m_pane->GetContext(),
XP_GetString(MK_MSG_MDN_WISH_TO_SEND));
if (!m_reallySendMdn)
return;
m_msgFileName = WH_TempName (xpFileToPost, "mdnmsg");
if (!m_msgFileName)
return;
m_outFile = XP_FileOpen (m_msgFileName, xpFileToPost, XP_FILE_WRITE_BIN);
if (!m_outFile) goto done;
status = CreateFirstPart();
if (status < 0) goto done;
status = CreateSecondPart();
if (status < 0) goto done;
status = CreateThirdPart();
done:
if (m_outFile)
{
XP_FileClose(m_outFile);
m_outFile = 0;
}
if (status < 0)
{
// may want post out error message
XP_FileRemove(m_msgFileName, xpFileToPost);
XP_FREEIF(m_msgFileName);
}
else
{
DoSendMdn();
}
}
int32
MSG_ProcessMdnNeededState::CreateFirstPart()
{
int gmtoffset = XP_LocalZoneOffset();
char *convbuf = NULL, *tmpBuffer = NULL;
int16 win_csid;
char *parm = NULL;
char *firstPart = NULL;
int formatId = MK_MSG_MDN_DISPLAYED;
int32 status = 0;
char *receipt_string = NULL;
char *wrapped_string = NULL;
XP_ASSERT(m_outFile);
if (!m_mimeSeparator)
m_mimeSeparator = mime_make_separator("mdn");
if (!m_mimeSeparator)
return MK_OUT_OF_MEMORY;
tmpBuffer = (char *) XP_ALLOC(256);
if (!tmpBuffer)
return MK_OUT_OF_MEMORY;
win_csid = INTL_DefaultWinCharSetID(m_pane->GetContext());
m_csid = INTL_DefaultMailCharSetID(win_csid);
#ifndef NSPR20
PRTime now;
PR_ExplodeTime(&now, PR_Now());
#else
PRExplodedTime now;
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);
#endif /* NSPR20 */
/* Use PR_FormatTimeUSEnglish() to format the date in US English format,
then figure out what our local GMT offset is, and append it (since
PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as
per RFC 1123 (superceding RFC 822.)
*/
PR_FormatTimeUSEnglish(tmpBuffer, 100,
"Date: %a, %d %b %Y %H:%M:%S ",
&now);
PR_snprintf(tmpBuffer + XP_STRLEN(tmpBuffer), 100,
"%c%02d%02d" CRLF,
(gmtoffset >= 0 ? '+' : '-'),
((gmtoffset >= 0 ? gmtoffset : -gmtoffset) / 60),
((gmtoffset >= 0 ? gmtoffset : -gmtoffset) % 60));
status = WriteString(tmpBuffer);
XP_FREEIF(tmpBuffer);
if (status < 0) return status;
convbuf = IntlEncodeMimePartIIStr((char *) FE_UsersMailAddress(),
m_csid, TRUE);
parm = PR_smprintf("From: %s" CRLF, convbuf ? convbuf : FE_UsersMailAddress());
PUSH_N_FREE_STRING (parm);
XP_FREEIF(convbuf);
parm = msg_generate_message_id();
tmpBuffer = PR_smprintf("Message-ID: %s" CRLF, parm);
PUSH_N_FREE_STRING(tmpBuffer);
XP_FREEIF(parm);
receipt_string = XP_GetString(MK_MDN_DISPLAYED_RECEIPT + (int)
m_disposeType);
parm = PR_smprintf ("%s - %s", (receipt_string ? receipt_string :
"Return Receipt"), (m_subject ? m_subject
: ""));
convbuf =
IntlEncodeMimePartIIStr(parm ? parm : "Return Receipt",
m_csid, TRUE);
tmpBuffer = PR_smprintf("Subject: %s" CRLF, (convbuf ? convbuf : (parm ? parm :
"Return Receipt")));
PUSH_N_FREE_STRING(tmpBuffer);
if (parm)
{
PR_smprintf_free(parm);
parm = 0;
}
XP_FREEIF(convbuf);
convbuf = IntlEncodeMimePartIIStr(m_dispositionNotificationTo, m_csid,
TRUE);
tmpBuffer = PR_smprintf("To: %s" CRLF, convbuf ? convbuf : m_dispositionNotificationTo);
PUSH_N_FREE_STRING(tmpBuffer);
XP_FREEIF(convbuf);
// *** This is not in the spec. I am adding this so we could do
// threading
if (*m_messageId == '<')
tmpBuffer = PR_smprintf("References: %s" CRLF, m_messageId);
else
tmpBuffer = PR_smprintf("References: <%s>" CRLF, m_messageId);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF, "MIME-Version: 1.0");
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("Content-Type: multipart/report; \
report-type=disposition-notification;\r\n\tboundary=\"%s\"" CRLF CRLF,
m_mimeSeparator);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator);
PUSH_N_FREE_STRING(tmpBuffer);
char charset[30];
INTL_CharSetIDToName(m_csid, charset);
tmpBuffer = PR_smprintf("Content-Type: text/plain; charset=%s" CRLF, charset);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("Content-Transfer-Encoding: %s" CRLF CRLF, ENCODING_7BIT);
PUSH_N_FREE_STRING(tmpBuffer);
formatId = MK_MSG_MDN_DISPLAYED + ((int) m_disposeType - (int)
eDisplayed);
firstPart = XP_STRDUP(XP_GetString(formatId));
convbuf = IntlEncodeMimePartIIStr(firstPart, m_csid, TRUE);
wrapped_string = (char *) XP_WordWrap(m_csid, (unsigned char *)
(convbuf ? convbuf : firstPart),
72, FALSE);
tmpBuffer = PR_smprintf("%s" CRLF CRLF, wrapped_string ? wrapped_string : firstPart);
PUSH_N_FREE_STRING(tmpBuffer);
XP_FREEIF(firstPart);
XP_FREEIF(convbuf);
XP_FREEIF(wrapped_string);
return status;
}
int32
MSG_ProcessMdnNeededState::CreateSecondPart()
{
char *tmpBuffer = NULL;
char *convbuf = NULL;
int32 status = 0;
tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF, "Content-Type: message/disposition-notification");
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF, "Content-Disposition: inline");
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("Content-Transfer-Encoding: %s" CRLF CRLF, ENCODING_7BIT);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("Reporting-UA: %s; %s %s" CRLF,
NET_HostName(), XP_AppCodeName, XP_AppVersion);
PUSH_N_FREE_STRING(tmpBuffer);
if (m_originalRecipient && *m_originalRecipient)
{
tmpBuffer = PR_smprintf("Original-Recipient: %s" CRLF, m_originalRecipient);
PUSH_N_FREE_STRING(tmpBuffer);
}
convbuf = IntlEncodeMimePartIIStr((char *) FE_UsersMailAddress(), m_csid,
TRUE);
tmpBuffer = PR_smprintf("Final-Recipient: rfc822;%s" CRLF, convbuf ? convbuf :
FE_UsersMailAddress());
PUSH_N_FREE_STRING(tmpBuffer);
XP_FREEIF (convbuf);
if (*m_messageId == '<')
tmpBuffer = PR_smprintf("Original-Message-ID: %s" CRLF, m_messageId);
else
tmpBuffer = PR_smprintf("Original-Message-ID: <%s>" CRLF, m_messageId);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("Disposition: %s/%s; %s" CRLF CRLF,
(m_autoAction ? "automatic-action" : "manual-action"),
(m_autoSend ? "MDN-sent-automatically" : "MDN-sent-manually"),
DispositionTypes[(int) m_disposeType]);
PUSH_N_FREE_STRING(tmpBuffer);
return status;
}
int32
MSG_ProcessMdnNeededState::CreateThirdPart()
{
char *tmpBuffer = NULL;
int32 status = 0;
tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator);
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF, "Content-Type: text/rfc822-headers");
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF, "Content-Transfer-Encoding: 7bit");
PUSH_N_FREE_STRING(tmpBuffer);
tmpBuffer = PR_smprintf("%s" CRLF CRLF, "Content-Disposition: inline");
PUSH_N_FREE_STRING(tmpBuffer);
status = OutputAllHeaders();
if (status < 0) return status;
status = WriteString(CRLF);
if (status < 0) return status;
tmpBuffer = PR_smprintf("--%s--" CRLF, m_mimeSeparator);
PUSH_N_FREE_STRING(tmpBuffer);
return status;
}
void
MSG_ProcessMdnNeededState::DoSendMdn()
{
XP_ASSERT(m_dispositionNotificationTo);
if (!m_dispositionNotificationTo) return; // MK_OUT_OF_MEMORY
char *tmpBuffer = // 9 = mailto: + null + 1 extra
(char *) XP_ALLOC(XP_STRLEN(m_dispositionNotificationTo) + 9);
if (!tmpBuffer) return; // MK_OUT_OF_MEMORY
URL_Struct *url = NULL;
FE_Progress (m_pane->GetContext(), XP_GetString(MK_MSG_DELIV_MAIL));
XP_STRCPY(tmpBuffer, "mailto:");
XP_STRCAT(tmpBuffer, m_dispositionNotificationTo);
url = NET_CreateURLStruct (tmpBuffer, NET_DONT_RELOAD);
if (url)
{
url->post_data = XP_STRDUP(m_msgFileName);
url->post_data_size = XP_STRLEN(m_msgFileName);
url->post_data_is_file = TRUE;
url->method = URL_POST_METHOD;
url->fe_data = this;
url->internal_url = TRUE;
url->msg_pane = m_pane;
// clear m_msgFileName to prevent removing temp file too early
XP_FREEIF(m_msgFileName);
// Set sending MDN in progress so the smtp state machine can null out
// the address for MAIL FROM
m_pane->SetSendingMDNInProgress(TRUE);
MSG_UrlQueue::AddUrlToPane (url,
MSG_ProcessMdnNeededState::PostSendMdn,
m_pane,
TRUE);
}
XP_FREEIF(tmpBuffer);
}
/* static */ void
MSG_ProcessMdnNeededState::PostSendMdn(URL_Struct *url, int status, MWContext
*context)
{
if (url->msg_pane)
url->msg_pane->SetSendingMDNInProgress(FALSE);
if (status < 0)
{
char *error_msg = NET_ExplainErrorDetails(status, 0, 0, 0, 0);
if (error_msg)
FE_Alert(context, error_msg);
XP_FREEIF(error_msg);
}
if (url->post_data)
{
XP_FileRemove(url->post_data, xpFileToPost);
XP_FREEIF(url->post_data);
url->post_data_size = 0;
}
NET_FreeURLStruct(url);
}

127
mozilla/lib/mailto/msgmdn.h Normal file
View File

@@ -0,0 +1,127 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef MSGMDN_H
#define MSGMDN_H
#include "xp.h"
#include "msgzap.h"
#include "libmime.h"
class MSG_Pane;
class MSG_FolderInfo;
struct message_header;
#define MDN_NOT_IN_TO_CC ((int) 0x0001)
#define MDN_OUTSIDE_DOMAIN ((int) 0x0002)
#define HEADER_RETURN_PATH "Return-Path"
#define HEADER_DISPOSITION_NOTIFICATION_TO "Disposition-Notification-To"
#define HEADER_APPARENTLY_TO "Apparently-To"
#define HEADER_ORIGINAL_RECIPIENT "Original-Recipient"
#define HEADER_REPORTING_UA "Reporting-UA"
#define HEADER_MDN_GATEWAY "MDN-Gateway"
#define HEADER_FINAL_RECIPIENT "Final-Recipient"
#define HEADER_DISPOSITION "Disposition"
#define HEADER_ORIGINAL_MESSAGE_ID "Original-Message-ID"
#define HEADER_FAILURE "Failure"
#define HEADER_ERROR "Error"
#define HEADER_WARNING "Warning"
#define HEADER_RETURN_RECEIPT_TO "Return-Receipt-To"
class MSG_ProcessMdnNeededState : public MSG_ZapIt
{
public:
enum EDisposeType {
eDisplayed = 0x0,
eDispatched,
eProcessed,
eDeleted,
eDenied,
eFailed
};
public:
MSG_ProcessMdnNeededState (EDisposeType intendedType,
MSG_Pane *pane,
MSG_FolderInfo *folder,
uint32 key,
MimeHeaders *srcHeader,
XP_Bool autoAction = FALSE);
MSG_ProcessMdnNeededState (EDisposeType intendedType,
MSG_Pane *pane,
MSG_FolderInfo *folder,
uint32 key,
struct message_header *returnPath,
struct message_header *dnt,
struct message_header *to,
struct message_header *cc,
struct message_header *subject,
struct message_header *date,
struct message_header *originalRecipient,
struct message_header *messageId,
char *allHeaders,
int32 allHeadersSize,
XP_Bool autoAction = TRUE);
virtual ~MSG_ProcessMdnNeededState ();
static void PostSendMdn(URL_Struct *url, int status, MWContext *context);
protected:
XP_Bool ProcessSendMode(); // this should be called prior to
// ValidateReturnPath();
XP_Bool ValidateReturnPath();
XP_Bool MailAddrMatch(const char *addr1, const char *addr2);
XP_Bool NotInToOrCc();
void CreateMdnMsg();
int32 CreateFirstPart();
int32 CreateSecondPart();
int32 CreateThirdPart();
void DoSendMdn();
// helper fucntion
void InitAndProcess();
int32 OutputAllHeaders();
int32 WriteString(const char *str);
protected:
EDisposeType m_disposeType;
MSG_Pane *m_pane;
XP_File m_outFile;
int16 m_csid;
char *m_msgFileName;
char *m_mimeSeparator;
XP_Bool m_reallySendMdn; /* really send mdn? */
XP_Bool m_autoSend; /* automatic vs manual send mode */
XP_Bool m_autoAction; /* automatic vs manual action */
char *m_returnPath;
char *m_dispositionNotificationTo;
char *m_date;
char *m_to;
char *m_cc;
char *m_subject;
char *m_messageId;
char *m_originalRecipient;
char *m_all_headers;
int32 m_all_headers_size;
};
#endif

View File

@@ -0,0 +1,647 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "rosetta.h"
#include "msg.h"
#include "errcode.h"
#include "xpgetstr.h"
#include "libi18n.h"
#include "msgpane.h"
#include "msgprefs.h"
#include "msgmast.h"
#include "msghdr.h"
#include "xp_time.h"
#include "xplocale.h"
#include "msg.h"
#include "msgmast.h"
#include "prefapi.h"
#include "xp_qsort.h"
#include "intl_csi.h"
#include "xlate.h"
#include "msgurlq.h"
#include "pw_public.h"
#include "mime.h"
extern "C"
{
extern int MK_MSG_ADDRESS_BOOK;
extern int MK_MSG_COMPRESS_ALL_FOLDER;
extern int MK_MSG_EMPTY_TRASH_FOLDER;
extern int MK_MSG_ERROR_WRITING_MAIL_FOLDER;
extern int MK_MSG_GET_NEW_MAIL;
extern int MK_MSG_GET_NEW_DISCUSSION_MSGS;
extern int MK_MSG_NEW_MAIL_MESSAGE;
extern int MK_MSG_NO_POP_HOST;
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_SAVE_MESSAGE_AS;
extern int MK_MSG_SAVE_MESSAGES_AS;
extern int MK_MSG_OPEN_DRAFT;
extern int MK_MSG_ID_NOT_IN_FOLDER;
extern int MK_MSG_FOLDER_UNREADABLE;
extern int MK_MSG_DELIV_NEW_MSGS;
extern int MK_MSG_QUEUED_DELIVERY_FAILED;
extern int MK_MSG_NEWS_HOST_TABLE_INVALID;
extern int MK_MSG_CANCEL_MESSAGE;
extern int MK_MSG_MESSAGE_CANCELLED;
extern int MK_MSG_MARK_SEL_AS_READ;
extern int MK_MSG_MARK_SEL_AS_UNREAD;
extern int MK_MSG_MARK_THREAD_READ;
extern int MK_MSG_MARK_ALL_READ;
extern int MK_MSG_BACKTRACK;
extern int MK_MSG_GO_FORWARD;
extern int MK_MSG_UNABLE_MANAGE_MAIL_ACCOUNT;
extern int MK_POP3_NO_MESSAGES;
extern int MK_MSG_MANAGE_MAIL_ACCOUNT;
extern int MK_MSG_CANT_DELETE_RESERVED_FOLDER;
extern int MK_MSG_PANES_OPEN_ON_FOLDER;
extern int MK_MSG_DELETE_FOLDER_MESSAGES;
extern int MK_MSG_NO_POST_TO_DIFFERENT_HOSTS_ALLOWED;
extern int MK_MSG_GROUP_NOT_ON_SERVER;
extern int MK_MSG_NEW_NEWSGROUP;
extern int MK_MSG_ADVANCE_TO_NEXT_FOLDER;
extern int MK_MSG_FLAG_MESSAGE;
extern int MK_MSG_UNFLAG_MESSAGE;
extern int MK_MSG_RETRIEVE_FLAGGED;
extern int MK_MSG_RETRIEVE_SELECTED;
XP_Bool NET_IsNewsMessageURL (const char *url);
}
MSG_Pane* MSG_Pane::MasterList = NULL;
typedef struct msg_incorporate_state
{
MWContext *context;
MSG_FolderInfoMail *inbox;
MSG_Pane *pane;
const char* dest;
const char *destName;
int32 start_length;
// int numdup;
char *ibuffer;
uint32 ibuffer_size;
uint32 ibuffer_fp;
#ifdef MANGLE_INTERNAL_ENVELOPE_LINES
XP_Bool mangle_from; /* True if "From " lines need to be subject
to the Usual Mangling Conventions.*/
#endif /* MANGLE_INTERNAL_ENVELOPE_LINES */
char* headers;
uint32 headers_length;
uint32 headers_maxlength;
XP_Bool gathering_headers;
XP_Bool expect_multiple;
XP_Bool expect_envelope;
ParseMailboxState *incparsestate; /* Parse state for messages */
int status;
} msg_incorporate_state;
MSG_Pane::MSG_Pane(MWContext* context, MSG_Master* master) {
m_context = context;
m_nextInMasterList = MasterList;
MasterList = this;
m_master = master;
if (master) {
m_nextPane = master->GetFirstPane();
master->SetFirstPane(this);
m_prefs = master->GetPrefs();
m_prefs->AddNotify(this);
m_context->mailMaster = master;
}
}
MSG_Pane::~MSG_Pane() {
UnregisterFromPaneList();
if (m_master) {
m_master->GetPrefs()->RemoveNotify(this);
}
if (m_progressContext)
PW_DestroyProgressContext(m_progressContext);
}
MSG_Pane* MSG_Pane::GetFirstPaneForContext(MWContext *context)
{
if (context)
return GetNextPaneForContext(NULL, context);
return(NULL);
}
MSG_Pane* MSG_Pane::GetNextPaneForContext(MSG_Pane *startPane, MWContext *context)
{
MSG_Pane* result = NULL;
result = (startPane) ? startPane->m_nextInMasterList : MasterList;
for (; result ; result = result->m_nextInMasterList)
{
if (result->GetContext() == context)
return result;
}
return NULL;
}
// Remove a pane from the pane list
// Note that if after we remove ourselves from the list, the only pane left
// belongs to the Biff (Check for New Mail) Master then we tell it to go away, which will cause
// its own hidden progress window and context to be deleted.
void MSG_Pane::UnregisterFromPaneList()
{
if (m_master) {
MSG_Pane* tmp = m_master->GetFirstPane();
if (tmp == this) {
m_master->SetFirstPane(m_nextPane);
} else {
for (; tmp ; tmp = tmp->m_nextPane) {
if (tmp->m_nextPane == this) {
tmp->m_nextPane = m_nextPane;
break;
}
}
}
}
MSG_Pane** ptr;
for (ptr = &MasterList ; *ptr ; ptr = &((*ptr)->m_nextInMasterList)) {
if (*ptr == this) {
*ptr = this->m_nextInMasterList;
break;
}
}
}
// this method can be used to find out if a pane has been deleted...
/*static*/ XP_Bool MSG_Pane::PaneInMasterList(MSG_Pane *pane)
{
MSG_Pane* curPane;
XP_Bool ret = FALSE;
// it will return FALSE if pane is NULL
for (curPane = MasterList ; curPane ; curPane = curPane->m_nextInMasterList)
{
if (curPane == pane)
{
ret = TRUE;
break;
}
}
return ret;
}
MSG_Pane* MSG_Pane::FindPane(MWContext* context, MSG_PaneType type, XP_Bool contextMustMatch /* = FALSE */) {
MSG_Pane* result;
for (result = MasterList ; result ; result = result->m_nextInMasterList) {
if (result->GetContext() == context && (type == MSG_ANYPANE ||
result->GetPaneType() == type)) {
return result;
}
}
if (!contextMustMatch)
{
for (result = MasterList ; result ; result = result->m_nextInMasterList) {
if (type == MSG_ANYPANE || result->GetPaneType() == type) {
return result;
}
}
}
return NULL;
}
/* static */ MSG_PaneType MSG_Pane::PaneTypeForURL(const char *url)
{
MSG_PaneType retType = MSG_ANYPANE;
int urlType = NET_URL_Type(url);
char *folderName = NULL;
switch (urlType)
{
case MAILTO_TYPE_URL:
retType = MSG_COMPOSITIONPANE;
break;
default:
break;
}
FREEIF(folderName);
return retType;
}
/* inline virtuals moved to cpp file to help compilers that don't implement virtuals
defined in headers well.
*/
MSG_PaneType MSG_Pane::GetPaneType() {return MSG_PANE;}
void MSG_Pane::NotifyPrefsChange(NotifyCode /*code*/) {}
MSG_Pane* MSG_Pane::GetParentPane() {return NULL;}
void MSG_Pane::SetFEData(void* data) {
m_fedata = data;
}
void* MSG_Pane::GetFEData() {
return m_fedata;
}
XP_Bool MSG_Pane::IsLinePane() {
return FALSE;
}
MWContext* MSG_Pane::GetContext() {
return m_context;
}
MSG_Prefs* MSG_Pane::GetPrefs() {
return m_prefs;
}
MsgERR
MSG_Pane::ComposeNewMessage()
{
return (MSG_Mail(GetContext())) ? 0 : MK_OUT_OF_MEMORY;
}
//This is a long one. I'd like to break it down but some of the work
//that is done here just isn't really useful elsewhere. This handles
//serveral selection cases in the threadwindow of the Mail and News pane.
//If the individual selected something which we can use to populate the
//send to lines, it get added into the addressee fields with the group label.
//If nothing of any use was selected, the "mailto" label is used with a blank.
//They are not allowed to select groups across news servers. Such an act
//will result in an informative error message and bring you back to the
//mail and news pane.
MsgERR
MSG_Pane::ComposeMessageToMany(MSG_ViewIndex* , int32 )
{
return ComposeNewMessage();
}
char*
MSG_Pane::CreateForwardSubject(MessageHdrStruct* header)
{
char *fwd_subject = 0;
const char *subject = 0;
char *conv_subject = 0;
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(GetContext());
subject = header->m_subject;
while (XP_IS_SPACE(*subject)) subject++;
conv_subject = IntlDecodeMimePartIIStr(subject, INTL_GetCSIWinCSID(c), FALSE);
if (conv_subject == NULL)
conv_subject = (char *) subject;
fwd_subject =
(char *) XP_ALLOC((conv_subject ? XP_STRLEN(conv_subject) : 0) + 20);
if (!fwd_subject) goto FAIL;
XP_STRCPY (fwd_subject, "[Fwd: ");
if (header->m_flags & kHasRe) {
XP_STRCAT (fwd_subject, "Re: ");
}
XP_STRCAT (fwd_subject, conv_subject);
XP_STRCAT (fwd_subject, "]");
FAIL:
if (conv_subject != subject) {
FREEIF(conv_subject);
}
return fwd_subject;
}
void
MSG_Pane::InterruptContext(XP_Bool /*safetoo*/)
{
XP_InterruptContext(m_context);
}
MsgERR
MSG_Pane::DoCommand(MSG_CommandType command, MSG_ViewIndex* indices,
int32 numIndices)
{
MsgERR status = 0;
switch (command) {
break;
case MSG_MailNew:
status = ComposeMessageToMany(indices, numIndices);
break;
default:
#ifdef DEBUG
FE_Alert (GetContext(), "command not implemented");
#endif
break;
}
return status;
}
MsgERR
MSG_Pane::GetCommandStatus(MSG_CommandType command,
const MSG_ViewIndex* indices, int32 numIndices,
XP_Bool *selectable_pP,
MSG_COMMAND_CHECK_STATE *selected_pP,
const char **display_stringP,
XP_Bool *plural_pP)
{
const char *display_string = 0;
XP_Bool plural_p = FALSE;
XP_Bool selectable_p = FALSE;
XP_Bool selected_p = FALSE;
XP_Bool selected_used_p = FALSE;
switch(command) {
case MSG_MailNew:
display_string = XP_GetString(MK_MSG_NEW_MAIL_MESSAGE);
// don't enable compose if we're parsing a folder
selectable_p = TRUE;
break;
default:
// XP_ASSERT(0);
break;
}
if (selectable_pP)
*selectable_pP = selectable_p;
if (selected_pP)
{
if (selected_used_p)
{
if (selected_p)
*selected_pP = MSG_Checked;
else
*selected_pP = MSG_Unchecked;
}
else
{
*selected_pP = MSG_NotUsed;
}
}
if (display_stringP)
*display_stringP = display_string;
if (plural_pP)
*plural_pP = plural_p;
return 0;
}
MSG_COMMAND_CHECK_STATE
MSG_Pane::GetToggleStatus(MSG_CommandType command, MSG_ViewIndex* indices,
int32 numindices)
{
MSG_COMMAND_CHECK_STATE result = MSG_NotUsed;
if (GetCommandStatus(command, indices, numindices, NULL, &result,
NULL, NULL) != 0) {
return MSG_NotUsed;
}
return result;
}
MsgERR
MSG_Pane::SetToggleStatus(MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices,
MSG_COMMAND_CHECK_STATE value)
{
MsgERR status = eSUCCESS;
MSG_COMMAND_CHECK_STATE old = GetToggleStatus(command, indices, numindices);
if (old == MSG_NotUsed) return eUNKNOWN;
if (old != value)
{
if ((status = DoCommand(command, indices, numindices)) == eSUCCESS)
{
if (GetToggleStatus(command, indices, numindices) != value)
{
XP_ASSERT(0);
return eUNKNOWN;
}
}
}
return status;
}
void MSG_Pane::SetRequestForReturnReceipt(XP_Bool bRequested)
{
m_requestForReturnReceipt = bRequested;
}
XP_Bool MSG_Pane::GetRequestForReturnReceipt()
{
return m_requestForReturnReceipt;
}
void MSG_Pane::SetSendingMDNInProgress(XP_Bool inProgress)
{
m_sendingMDNInProgress = inProgress;
}
XP_Bool MSG_Pane::GetSendingMDNInProgress()
{
return m_sendingMDNInProgress;
}
char*
MSG_Pane::MakeMailto(const char *to, const char *cc,
const char *newsgroups,
const char *subject, const char *references,
const char *attachment, const char *host_data,
XP_Bool xxx_p, XP_Bool sign_p)
{
char *to2 = 0, *cc2 = 0;
char *out, *head;
char *qto, *qcc, *qnewsgroups, *qsubject, *qreferences;
char *qattachment, *qhost_data;
char *url;
char *me = MIME_MakeFromField();
char *to_plus_me = 0;
to2 = MSG_RemoveDuplicateAddresses (to, ((cc && *cc) ? me : 0), TRUE /*removeAliasesToMe*/);
if (to2 && !*to2) {
XP_FREE(to2);
to2 = 0;
}
/* This to_plus_me business is so that, in reply-to-all of a message
to which I was a recipient, I don't go into the CC field (that's
what BCC/FCC are for.) */
if (to2 && cc && me) {
to_plus_me = (char *) XP_ALLOC(XP_STRLEN(to2) + XP_STRLEN(me) + 10);
}
if (to_plus_me) {
XP_STRCPY(to_plus_me, me);
XP_STRCAT(to_plus_me, ", ");
XP_STRCAT(to_plus_me, to2);
}
FREEIF(me);
cc2 = MSG_RemoveDuplicateAddresses (cc, (to_plus_me ? to_plus_me : to2), TRUE /*removeAliasesToMe*/);
if (cc2 && !*cc2) {
XP_FREE(cc2);
cc2 = 0;
}
FREEIF(to_plus_me);
/* Catch the case of "Reply To All" on a message that was from me.
In that case, we've got an empty To: field at this point.
What we should do is, promote the first CC address to the To:
field. But I'll settle for promoting all of them.
*/
if (cc2 && *cc2 && (!to2 || !*to2)) {
FREEIF(to2);
to2 = cc2;
cc2 = 0;
}
qto = to2 ? NET_Escape (to2, URL_XALPHAS) : 0;
qcc = cc2 ? NET_Escape (cc2, URL_XALPHAS) : 0;
qnewsgroups = newsgroups ? NET_Escape (newsgroups, URL_XALPHAS) : 0;
qsubject = subject ? NET_Escape (subject, URL_XALPHAS) : 0;
qreferences = references ? NET_Escape (references, URL_XALPHAS) : 0;
qattachment = attachment ? NET_Escape (attachment, URL_XALPHAS) : 0;
qhost_data = host_data ? NET_Escape (host_data, URL_XALPHAS) : 0;
url = (char *)
XP_ALLOC ((qto ? XP_STRLEN(qto) + 15 : 0) +
(qcc ? XP_STRLEN(qcc) + 15 : 0) +
(qnewsgroups ? XP_STRLEN(qnewsgroups) + 15 : 0) +
(qsubject ? XP_STRLEN(qsubject) + 15 : 0) +
(qreferences ? XP_STRLEN(qreferences) + 15 : 0) +
(qhost_data ? XP_STRLEN(qhost_data) + 15 : 0) +
(qattachment ? XP_STRLEN(qattachment) + 15 : 0) +
60);
if (!url) goto FAIL;
XP_STRCPY (url, "mailto:");
head = url + XP_STRLEN (url);
out = head;
# define PUSH_STRING(S) XP_STRCPY(out, S), out += XP_STRLEN(S)
# define PUSH_PARM(prefix,var) \
if (var) { \
if (out == head) \
*out++ = '?'; \
else \
*out++ = '&'; \
PUSH_STRING (prefix); \
*out++ = '='; \
PUSH_STRING (var); \
} \
PUSH_PARM("to", qto);
PUSH_PARM("cc", qcc);
PUSH_PARM("newsgroups", qnewsgroups);
PUSH_PARM("subject", qsubject);
PUSH_PARM("references", qreferences);
PUSH_PARM("attachment", qattachment);
PUSH_PARM("newshost", qhost_data);
{
char *t = "true"; /* avoid silly compiler warning */
HG92725
if (sign_p) PUSH_PARM("sign", t);
}
# undef PUSH_PARM
# undef PUSH_STRING
FAIL:
FREEIF (to2);
FREEIF (cc2);
FREEIF (qto);
FREEIF (qcc);
FREEIF (qnewsgroups);
FREEIF (qsubject);
FREEIF (qreferences);
FREEIF (qattachment);
FREEIF (qhost_data);
return url;
}
#ifdef GENERATINGPOWERPC
#pragma global_optimizer off
#endif
MSG_PaneURLChain::MSG_PaneURLChain(MSG_Pane *pane)
{
m_pane = pane;
}
MSG_PaneURLChain::~MSG_PaneURLChain()
{
}
// override to chain urls. return non-zero to continue.
int MSG_PaneURLChain::GetNextURL()
{
return 0;
}
#ifndef MOZ_MAIL_NEWS
/* This is normally in mkpop3.c, of all the odd places!
But it's required for mail compose.
*/
int
msg_GrowBuffer (uint32 desired_size, uint32 element_size, uint32 quantum,
char **buffer, uint32 *size)
{
if (*size <= desired_size)
{
char *new_buf;
uint32 increment = desired_size - *size;
if (increment < quantum) /* always grow by a minimum of N bytes */
increment = quantum;
#ifdef TESTFORWIN16
if (((*size + increment) * (element_size / sizeof(char))) >= 64000)
{
/* Make sure we don't choke on WIN16 */
XP_ASSERT(0);
return MK_OUT_OF_MEMORY;
}
#endif /* DEBUG */
new_buf = (*buffer
? (char *) XP_REALLOC (*buffer, (*size + increment)
* (element_size / sizeof(char)))
: (char *) XP_ALLOC ((*size + increment)
* (element_size / sizeof(char))));
if (! new_buf)
return MK_OUT_OF_MEMORY;
*buffer = new_buf;
*size += increment;
}
return 0;
}
#endif /* ! MOZ_MAIL_NEWS */

View File

@@ -0,0 +1,200 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgPane_H_
#define _MsgPane_H_
#include "msg.h"
#include "errcode.h"
#include "msgzap.h"
#include "msgprnot.h"
class MSG_Master;
class MessageDBView;
class MSG_FolderInfo;
class MSG_NewsHost;
class ParseMailboxState;
class msg_Background;
class OfflineImapGoOnlineState;
class MSG_FolderInfoMail;
class MSG_PostDeliveryActionInfo;
struct tImapFilterClosure;
struct msg_incorporate_state;
struct MessageHdrStruct;
#ifdef MOZ_MAIL_NEWS
class PaneListener : public ChangeListener
{
public:
PaneListener(MSG_Pane *pPane);
virtual ~PaneListener();
virtual void OnViewChange(MSG_ViewIndex startIndex, int32 numChanged,
MSG_NOTIFY_CODE changeType, ChangeListener *instigator);
virtual void OnViewStartChange(MSG_ViewIndex startIndex, int32 numChanged,
MSG_NOTIFY_CODE changeType, ChangeListener *instigator);
virtual void OnViewEndChange(MSG_ViewIndex startIndex, int32 numChanged,
MSG_NOTIFY_CODE changeType, ChangeListener *instigator);
virtual void OnKeyChange(MessageKey keyChanged, int32 flags,
ChangeListener * instigator);
virtual void OnAnnouncerGoingAway (ChangeAnnouncer *instigator);
virtual void OnAnnouncerChangingView(ChangeAnnouncer * /* instigator */, MessageDBView * /* view */) ;
virtual void StartKeysChanging();
virtual void EndKeysChanging();
protected:
MSG_Pane *m_pPane;
XP_Bool m_keysChanging; // are keys changing?
XP_Bool m_keyChanged; // has a key changed since StartKeysChanging called?
};
#endif /* MOZ_MAIL_NEWS */
// If a MSG_Pane has its url chain ptr set to a non-null value,
// it calls the GetNextURL method whenever it finishes a url that is chainable.
// These include delivering queued mail, get new mail, and retrieving
// messages for offline use, oddly enough - the three kinds of urls I need to queue.
// Sadly, neither the msg_Background or MSG_UrlQueue do what I want,
// because I need to chain network urls that have their own exit functions
// and indeed chain urls themselves.
class MSG_PaneURLChain
{
public:
MSG_PaneURLChain(MSG_Pane *pane);
virtual ~MSG_PaneURLChain();
virtual int GetNextURL(); // return 0 to stop chaining.
protected:
MSG_Pane *m_pane;
};
class MSG_Pane : public MSG_PrefsNotify {
public:
// hack..
// Find a pane of the given type that matches the given context. If none,
// find some other pane of the given type (if !contextMustMatch).
static MSG_Pane* FindPane(MWContext* context,
MSG_PaneType type = MSG_ANYPANE,
XP_Bool contextMustMatch = FALSE);
static XP_Bool PaneInMasterList(MSG_Pane *pane);
static MSG_PaneType PaneTypeForURL(const char *url);
XP_Bool NavigationGoesToNextFolder(MSG_MotionType motionType);
MSG_Pane(MWContext* context, MSG_Master* master);
virtual ~MSG_Pane();
void SetFEData(void*);
void* GetFEData();
virtual XP_Bool IsLinePane();
virtual MSG_PaneType GetPaneType() ;
virtual void NotifyPrefsChange(NotifyCode /*code*/);
virtual MSG_Pane* GetParentPane();
MSG_Pane* GetNextPane() {return m_nextPane;}
MSG_Pane *GetFirstPaneForContext(MWContext *context);
MSG_Pane *GetNextPaneForContext(MSG_Pane *pane, MWContext *context);
virtual MWContext* GetContext();
MSG_Prefs* GetPrefs();
MSG_Master* GetMaster() {return m_master;}
virtual MsgERR DoCommand(MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices);
virtual MsgERR GetCommandStatus(MSG_CommandType command,
const MSG_ViewIndex* indices, int32 numindices,
XP_Bool *selectable_p,
MSG_COMMAND_CHECK_STATE *selected_p,
const char **display_string,
XP_Bool *plural_p);
virtual MsgERR SetToggleStatus(MSG_CommandType command,
MSG_ViewIndex* indices, int32 numindices,
MSG_COMMAND_CHECK_STATE value);
virtual MSG_COMMAND_CHECK_STATE GetToggleStatus(MSG_CommandType command,
MSG_ViewIndex* indices,
int32 numindices);
MsgERR ComposeNewMessage();
//ComposeMessageToMany calls ComposeNewMessage if nothing was selected
//otherwise it builds a string containing selected groups to post to.
MsgERR ComposeMessageToMany(MSG_ViewIndex* indices, int32 numIndices);
virtual void InterruptContext(XP_Bool safetoo);
char* CreateForwardSubject(MessageHdrStruct* header);
// Removes this pane from the main pane list. This is so that calls to
// MSG_Master::FindPaneOfType() won't find this one (because, for example,
// we know we're about to delete this one.)
void UnregisterFromPaneList();
// These routines should be used only by the msg_Background class.
msg_Background* GetCurrentBackgroundJob() {return m_background;}
void SetCurrentBackgroundJob(msg_Background* b) {m_background = b;}
void SetShowingProgress(XP_Bool showingProgress) {m_showingProgress = showingProgress;}
void SetRequestForReturnReceipt(XP_Bool isNeeded);
XP_Bool GetRequestForReturnReceipt();
void SetSendingMDNInProgress(XP_Bool inProgress);
XP_Bool GetSendingMDNInProgress();
char* MakeMailto(const char *to, const char *cc,
const char *newsgroups,
const char *subject, const char *references,
const char *attachment, const char *host_data,
XP_Bool xxx_p, XP_Bool sign_p);
protected:
static MSG_Pane* MasterList;
MSG_Pane* m_nextInMasterList;
MSG_Pane* m_nextPane; // Link of panes created with the same master.
MSG_Master* m_master;
MWContext* m_context;
MSG_Prefs* m_prefs;
void* m_fedata;
int m_numstack; // used for DEBUG, and to tell listeners
// if we're in an update block.
msg_Background* m_background;
XP_Bool m_requestForReturnReceipt;
XP_Bool m_showingProgress;
XP_Bool m_sendingMDNInProgress;
MSG_PostDeliveryActionInfo *m_actionInfo;
MWContext *m_progressContext;
};
#endif /* _MsgPane_H_ */

View File

@@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "msgppane.h"
MSG_ProgressPane::MSG_ProgressPane(MWContext* context, MSG_Master* master,
MSG_Pane *parentPane)
: MSG_Pane(context, master)
{
m_parentPane = parentPane;
// progress panes must not look appetizing to JavaScript
//XP_ASSERT(MWContextMailNewsProgress == context->type);
if (context->type != MWContextMailNewsProgress)
context->type = MWContextMailNewsProgress;
if (m_parentPane)
m_parentPane->SetShowingProgress(TRUE);
}
MSG_ProgressPane::~MSG_ProgressPane()
{
if (GetParentPane())
m_parentPane->SetShowingProgress(FALSE);
if (m_context->imapURLPane == this)
m_context->imapURLPane = NULL;
}
MsgERR
MSG_ProgressPane::DoCommand(MSG_CommandType command, MSG_ViewIndex* indices,
int32 numIndices)
{
return MSG_Pane::DoCommand(command, indices, numIndices);
}
MSG_Pane* MSG_ProgressPane::GetParentPane()
{
// parent pane may have been deleted w/o us knowing, so check if it's in master list.
if (!PaneInMasterList(m_parentPane))
m_parentPane = NULL;
return m_parentPane;
}

View File

@@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgProgressPane_H_
#define _MsgProgressPane_H_
#include "msgpane.h"
class MSG_ProgressPane : public MSG_Pane
{
public:
MSG_ProgressPane(MWContext* context, MSG_Master* master, MSG_Pane *parentPane);
virtual ~MSG_ProgressPane();
virtual MsgERR DoCommand(MSG_CommandType command, MSG_ViewIndex* indices,
int32 numIndices);
virtual MSG_Pane* GetParentPane();
protected:
MSG_Pane *m_parentPane;
};
#endif

View File

@@ -0,0 +1,979 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "errcode.h"
#include "rosetta.h"
#include "msgprefs.h"
#include "msgprnot.h"
#include "prefapi.h"
#include "msgmast.h"
#include "proto.h" // for XP_FindSomeContext
extern "C"
{
#include "mkreg.h"
}
#include "ptrarray.h"
#ifdef XP_MAC
#include "Memory.h"
#include "Files.h"
#include "ufilemgr.h"
#include "uprefd.h"
#else
extern "C"
{
const char *FE_GetFolderDirectory(MWContext *c);
void NET_SetMailRelayHost(char *);
void NET_SetNewsHost(const char *);
}
#endif
extern "C"
{
extern int MK_MSG_MAIL_DIRECTORY_CHANGED;
extern int MK_MSG_SENT_L10N_NAME;
extern void MIME_ConformToStandard(XP_Bool conform_p);
extern int MK_MSG_UNABLE_TO_SAVE_DRAFT;
extern int MK_MSG_UNABLE_TO_SAVE_TEMPLATE;
}
// Notify listeners that something got changed. updateCode is an int16 instead of
// a MSG_PrefsNotify::NotifyCode because it was deemed a Bad Thing to include all of
// msgprnot.h just to pick up that definition.
void MSG_Prefs::Notify(int16 updateCode)
{
int i;
// if we are changing mail servers, trash cached path to imap databases
// m_IMAPdirectory will be reset by next reload call
if ((updateCode == MSG_PrefsNotify::MailServerType) || (updateCode == MSG_PrefsNotify::PopHost))
FREEIF(m_IMAPdirectory);
// Do the notification in such a way that deleted listeners don't
// foul up the notification for everyone else. (m_notifying affects
// the behavior of RemoveNotify so that it only NULLs deleted listeners.)
m_notifying = TRUE;
for (i = 0; i < m_numnotify ; i++)
{
if (m_notify[i])
m_notify[i]->NotifyPrefsChange((MSG_PrefsNotify::NotifyCode) updateCode);
}
m_notifying = FALSE;
// Clean up after nulled pointers.
for(i=(m_numnotify-1);i >= 0; i--)
{
if (! m_notify[i])
{
if (i == (m_numnotify-1))
// last element is null, keep decrementing the count
m_numnotify--;
else
// replace this null element with the last in the list
m_notify[i] = m_notify[--m_numnotify];
}
}
}
char *headerPrefNames[] =
{
"mail.identity.reply_to",
"mail.default_cc",
"mail.default_fcc",
"mail.imap_sentmail_path",
"news.default_cc",
"news.default_fcc",
"news.imap_sentmail_path",
};
enum headerPrefIndices
{
mail_identity_reply_to=0,
mail_default_cc,
mail_default_fcc, // this is a mess don't change order
mail_imap_sentmail_path,
news_default_cc,
news_default_fcc, // this is a mess don't change order
news_imap_sentmail_path,
num_of_header_prefs
};
void MSG_Prefs::PlatformFileToURLPath(const char *platformFile, char **result)
{
*result = NULL;
char *tmp = XP_PlatformFileToURL(platformFile);
XP_ASSERT(tmp && !strncmp(tmp, "file://", 7));
if (tmp && !strncmp(tmp, "file://", 7))
*result = XP_STRDUP(&(tmp[7]));
#ifdef XP_UNIX
if ( *result && **result == '~' ) {
char buf[1024];
char* home_dir = getenv("HOME");
char* tmp = (*result) + 1;
while ( *tmp == '/' )
tmp++;
/* trim trailing slashes in home_dir */
while ( (tmp = strrchr(home_dir, '/')) && tmp[1] == '\0' )
*tmp = '\0';
PR_snprintf(buf, sizeof(buf), "%s/%s", home_dir ? home_dir : "", tmp);
XP_FREE(*result);
*result = XP_STRDUP(buf);
}
#endif
FREEIF(tmp);
}
static XP_Bool ShouldSavePrefAsBinaryAlias(const char* prefname)
{
#ifdef XP_MAC
// Return TRUE if path names are saved as binary alias prefs (the default).
// Return FALSE for the URL cases, now saved as a string (new in Nova). These are IMAP
// fccs, and all drafts and all templates.
if (XP_STRCMP(prefname, "mail.imap_sentmail_path") == 0)
return FALSE; // URL
else if (XP_STRCMP(prefname, "news.imap_sentmail_path") == 0)
return FALSE; // URL
else if (XP_STRCMP(prefname, "mail.default_drafts") == 0)
return FALSE; // URL
else if (XP_STRCMP(prefname, "mail.default_templates") == 0)
return FALSE; // URL
return TRUE;
#else
return FALSE;
#endif // XP_MAC
}
int MSG_Prefs::GetXPDirPathPref(const char *prefName, XP_Bool /*expectFile*/, char **result)
{
int returnVal = PREF_NOERROR;
char *tmp = NULL;
*result = NULL; // in case we fail
if (ShouldSavePrefAsBinaryAlias(prefName))
{
returnVal = PREF_CopyPathPref(prefName, &tmp);
if (returnVal == PREF_NOERROR)
*result = tmp;
return returnVal;
}
returnVal = PREF_CopyCharPref(prefName, &tmp); // paths are strings elsewhere
if (returnVal == PREF_NOERROR)
{
// Convert pathname to an xp path.
if (XP_STRLEN(tmp) > 0 && NET_URL_Type(tmp) != IMAP_TYPE_URL &&
NET_URL_Type(tmp) != MAILBOX_TYPE_URL)
{
PlatformFileToURLPath(tmp,result);
XP_FREEIF(tmp);
}
else
*result = tmp;
}
return returnVal;
}
int MSG_Prefs::SetXPMailFilePref(const char* /*prefName*/, char *xpPath)
{
int returnVal = PREF_NOERROR;
if (NET_URL_Type(xpPath) != IMAP_TYPE_URL)
{
// ## mwelch 4.0b2 hack! Create the mail file if it doesn't already exist.
// Mail parent folder was created at app startup, so it is
// safe to assume that the parent directory exists.
char *platformPath = WH_FileName(xpPath, xpMailFolder);
XP_File fp = XP_FileOpen(xpPath, xpMailFolder, XP_FILE_APPEND_BIN);
if (fp)
XP_FileClose(fp);
XP_FREEIF(platformPath);
}
return returnVal;
} // MSG_Prefs::SetXPMailFilePref
void MSG_Prefs::SetMailNewsProfileAgeFlag(int32 flag, XP_Bool set /* = TRUE */)
{
// each 'trick' uses this function to register that it is done, but we do not
// want one trick to erase the completion of another.
int32 currentAge = 0;
PREF_GetIntPref("mailnews.profile_age",&currentAge);
if (set)
{
if (!(currentAge & flag))
PREF_SetIntPref("mailnews.profile_age",(currentAge | flag));
}
else
{
if (currentAge & flag)
PREF_SetIntPref("mailnews.profile_age",(currentAge | ~flag));
}
m_dirty = TRUE;
}
int32 MSG_Prefs::GetStartingMailNewsProfileAge()
{
Reload();
return m_startingMailNewsProfileAge;
}
void MSG_Prefs::Reload()
{
if (m_dirty)
{
// Temp vars we need to convey pref values.
int32 intPref;
char *strPref;
int prefError = PREF_NOERROR;
// Load in boolean prefs.
PREF_GetBoolPref("mail.fixed_width_messages", &m_plainText);
PREF_GetBoolPref("mail.auto_quote", &m_autoQuote);
PREF_GetBoolPref("news.show_pretty_names", &m_showPrettyNames);
PREF_GetBoolPref("news.notify.on", &m_newsNotifyOn);
PREF_GetBoolPref("mail.cc_self", &m_mailBccSelf);
PREF_GetBoolPref("news.cc_self", &m_newsBccSelf);
PREF_GetBoolPref("mail.wrap_long_lines", &m_wraplonglines);
HG63256
PREF_GetBoolPref("mail.inline_attachments", &m_noinline);
PREF_GetBoolPref("mail.prompt_purge_threshhold", &m_purgeThreshholdEnabled); //Ask about compacting folders
m_noinline = !m_noinline;
// Load in int/enum prefs.
intPref = (int) MSG_ItalicFont; // make italic if pref call fails
PREF_GetIntPref("mail.quoted_style", &intPref);
m_citationFont = (MSG_FONT) intPref;
intPref = (int) MSG_NormalSize; // make normal size if pref call fails
PREF_GetIntPref("mail.quoted_size", &intPref);
m_citationFontSize = (MSG_CITATION_SIZE) intPref;
intPref = 1;
PREF_GetIntPref("mailnews.nav_crosses_folders", &intPref);
m_navCrossesFolders = intPref;
PREF_GetIntPref("mailnews.profile_age",&m_startingMailNewsProfileAge);
intPref = 1; // default in case we fail
prefError = PREF_GetIntPref("mail.show_headers", &intPref);
switch (intPref)
{
case 0: m_headerstyle = MSG_ShowMicroHeaders; break;
case 1: m_headerstyle = MSG_ShowSomeHeaders; break;
case 2: m_headerstyle = MSG_ShowAllHeaders; break;
default:
XP_ASSERT(FALSE);
break;
}
intPref = 0; // if no pref is set, return 0 - let the backend set the default port
HG87635
// Server preference.
// ### mwelch This used to use mail.use_imap, but we're switching
// to mail.server_type as of 4.0b2.
intPref = 0; // pop by default
prefError = PREF_GetIntPref("mail.server_type", &intPref);
m_mailInputType = intPref;
m_mailServerIsIMAP = (m_mailInputType == 1);
PREF_GetIntPref("mail.purge_threshhold", &m_purgeThreshhold);
// Get string prefs.
if (!m_freezeMailDirectory)
{
// m_localMailDirectory
strPref = m_localMailDirectory;
m_localMailDirectory = NULL;
// Get the m_localMailDirectory pref. Passing in TRUE (expectFile) since the flag
// tells the Mac-specific code to make use of the name (usually "\pMail") in the FSSpec
// as well as the parent directory ID.
GetXPDirPathPref("mail.directory", TRUE, &m_localMailDirectory);
#if defined (XP_MAC)
if (!m_localMailDirectory || !*m_localMailDirectory)
{
Assert_(FALSE); // can this happen? If not, remove this.
char *newDirURL = NULL;
// ### mwelch This is a hack, because the MacFE
// doesn't set the mail root directory by default.
FSSpec mailFolder = CPrefs::GetFolderSpec(CPrefs::MailFolder);
newDirURL = CFileMgr::EncodedPathNameFromFSSpec(mailFolder, true);
m_localMailDirectory = newDirURL;
}
#endif
// It is still possible to have a NULL directory at this
// point in the code. This is because the WinFE sets the default
// mail directory preference after creating the prefs object.
if (m_localMailDirectory)
{
// by arbitrary convention, the directory shouldn't have
// a trailing slash
int len = XP_STRLEN(m_localMailDirectory);
if (len && m_localMailDirectory[len-1] == '/')
m_localMailDirectory[len-1] = '\0';
#if !defined(XP_MAC) && !defined(XP_WIN) && !defined(XP_OS2)
if (!strPref || strcmp(m_localMailDirectory, strPref))
{
// Create the directory if it doesn't exist (Unix only)
XP_StatStruct dirStat;
if (-1 == XP_Stat(m_localMailDirectory, &dirStat, xpMailFolder))
XP_MakeDirectory (m_localMailDirectory, xpMailFolder);
}
#endif
}
if (strPref) XP_FREE(strPref);
}
HG93653
char onlineDir[256];
onlineDir[0] = '\0';
int stringSize = 256;
PREF_GetCharPref("mail.imap.server_sub_directory",
onlineDir, &stringSize);
if ( *onlineDir && (*(onlineDir + XP_STRLEN(onlineDir) - 1) != '/') )
XP_STRCAT(onlineDir, "/");
if ((!m_OnlineImapSubDir) ||
((m_OnlineImapSubDir) &&
XP_STRCMP(onlineDir, m_OnlineImapSubDir)))
{
FREEIF(m_OnlineImapSubDir);
m_OnlineImapSubDir = XP_STRDUP(onlineDir);
//if (XP_STRCMP(m_OnlineImapSubDir,"")) // only set it if it is not empty
// IMAP_SetNamespacesFromPrefs(GetPopHost(), m_OnlineImapSubDir, "", "");
}
PREF_GetBoolPref("mailnews.searchServer", &m_searchServer);
PREF_GetBoolPref("mailnews.searchSubFolders", &m_searchSubFolders);
PREF_GetBoolPref("mailnews.confirm.moveFoldersToTrash", &m_confirmMoveFoldersToTrash);
FREEIF(m_customHeaders);
PREF_CopyCharPref("mailnews.customHeaders",&m_customHeaders);
FREEIF(m_citationColor);
PREF_CopyCharPref("mail.citation_color", &m_citationColor);
FREEIF(m_popHost);
PREF_CopyCharPref("network.hosts.pop_server", &m_popHost);
PREF_GetBoolPref("mail.imap.delete_is_move_to_trash", &m_ImapDeleteMoveToTrash);
// Set the smtp and news (nntp) hosts.
strPref = NULL;
prefError = PREF_CopyCharPref("network.hosts.smtp_server", &strPref);
if (prefError == PREF_NOERROR)
NET_SetMailRelayHost(strPref);
XP_FREEIF(strPref);
for(int i=0;i<(int) num_of_header_prefs ;i++)
{
strPref = NULL;
// Only look at the path if the "use it" bool flag is set!
// Bug #45449 jrm
XP_Bool doingFccPath = TRUE, wantsFccPath = FALSE;
if (i == mail_default_fcc || i == mail_imap_sentmail_path)
#ifdef XP_MAC
PREF_GetBoolPref("mail.use_fcc", &wantsFccPath);
#else
wantsFccPath = TRUE;
#endif
else if (i == news_default_fcc || i == news_imap_sentmail_path)
#ifdef XP_MAC
PREF_GetBoolPref("news.use_fcc", &wantsFccPath);
#else
wantsFccPath = TRUE;
#endif
else
doingFccPath = FALSE;
if (doingFccPath && wantsFccPath)
{
prefError = GetXPDirPathPref(headerPrefNames[i], TRUE, &strPref);
if ((prefError != PREF_NOERROR) || (!strPref) || (!*strPref) ||
(m_localMailDirectory && !XP_STRCMP(strPref, m_localMailDirectory)))
{
// Take the directory preference and add "Sent" to it.
char *sent = XP_GetString(MK_MSG_SENT_L10N_NAME);
XP_FREEIF(strPref);
if (m_localMailDirectory && *m_localMailDirectory)
strPref = PR_smprintf("%s/%s", m_localMailDirectory, sent);
#ifdef XP_MAC
// Still may need to ensure the file exists.
SetXPMailFilePref(headerPrefNames[i], strPref);
#endif
}
}
else if (!doingFccPath)
PREF_CopyCharPref(headerPrefNames[i], &strPref);
FREEIF(m_defaultHeaders[i]);
m_defaultHeaders[i] = strPref;
}
// Collect all the email addresses which specify the user. We'll need to know them
// when checking the Reply recipients, or doing MDN receipts
if (PREF_NOERROR == PREF_CopyCharPref ("mail.identity.useremail.aliases", &strPref))
{
if (*strPref) // default is empty string. don't create an array for that
{
if (!m_emailAliases)
m_emailAliases = new msg_StringArray (TRUE /*ownsMemory*/);
if (m_emailAliases)
{
m_emailAliases->RemoveAll();
m_emailAliases->ImportTokenList (strPref);
}
}
XP_FREE (strPref);
}
// Collect the email addresses which can't be considered aliases for this user.
// This is intended to keep the email aliases feature from defeating the reply-to
// header in messages
char *replyTo = m_defaultHeaders[mail_identity_reply_to];
if (replyTo && *replyTo)
{
if (!m_emailAliasesNot)
m_emailAliasesNot = new msg_StringArray (TRUE);
if (m_emailAliasesNot)
{
char *addresses = NULL;
int num = 0;
if (0 != (num = MSG_ParseRFC822Addresses (replyTo, NULL, &addresses)))
{
// We're ignoring the name of the reply-to header, since the
// actual address is all we care about for the alias calculation
m_emailAliasesNot->RemoveAll();
for (int i = 0; i < num; i++)
{
m_emailAliasesNot->Add (addresses);
addresses += XP_STRLEN (addresses) + 1;
}
}
}
}
}
m_dirty = FALSE;
}
int PR_CALLBACK MSG_PrefsChangeCallback(const char * prefName, void *data)
{
MSG_Prefs *prefs = (MSG_Prefs *) data;
if (prefs)
prefs->m_dirty = TRUE;
// Depending on the preference being changed,
// notify listeners as to the change.
// Default headers first, since we have easy access to them.
for (int i=0;i<(int) num_of_header_prefs;i++)
{
if (!XP_STRCMP(prefName, headerPrefNames[i]))
{
prefs->Notify(MSG_PrefsNotify::DefaultHeader);
return PREF_NOERROR;
}
}
if (!XP_STRNCMP(prefName, "netw", 4))
{
// cause smtp and news host to be set to new values immediately
if (prefs) prefs->Reload();
}
else if (!XP_STRNCMP(prefName, "mail", 4))
{
if (0) ;
}
return PREF_NOERROR;
}
MSG_Prefs::MSG_Prefs()
{
m_citationFont = MSG_PlainFont;
m_citationFontSize = MSG_Bigger;
m_plainText = TRUE;
m_mailServerIsIMAP = FALSE;
HG98298
m_ImapDeleteMoveToTrash = TRUE;
m_IMAPdirectory = NULL;
m_headerstyle = MSG_ShowSomeHeaders;
m_masterForBiff = NULL;
m_notifying = FALSE;
// Set up dirty flag.
m_dirty = TRUE;
m_freezeMailDirectory = FALSE;
m_emailAliases = NULL;
m_emailAliasesNot = NULL;
// Set up prefs callback.
PREF_RegisterCallback("mail.", &MSG_PrefsChangeCallback, this);
PREF_RegisterCallback("news.", &MSG_PrefsChangeCallback, this);
PREF_RegisterCallback("mailnews.", &MSG_PrefsChangeCallback, this);
PREF_RegisterCallback("network.hosts.", &MSG_PrefsChangeCallback, this);
// Load pref values from the prefs api.
// (We can rely on the string members being NULL initially
// since we derive from MSG_Zap.)
Reload();
// we are only interested in what this prefs value was at startup so initialize it
// here rather than in Reload()
m_startingMailNewsProfileAge = 0;
PREF_GetIntPref("mailnews.profile_age",&m_startingMailNewsProfileAge);
HG92734
}
MSG_Prefs::~MSG_Prefs()
{
XP_ASSERT(m_numnotify == 0);
FREEIF(m_localMailDirectory);
FREEIF(m_citationColor);
FREEIF(m_popHost);
for (int i=0 ; i<sizeof(m_defaultHeaders)/sizeof(char*) ; i++)
FREEIF(m_defaultHeaders[i]);
XP_FREEIF(m_IMAPdirectory);
delete m_emailAliases;
m_emailAliases = NULL;
delete m_emailAliasesNot;
m_emailAliasesNot = NULL;
}
void MSG_Prefs::AddNotify(MSG_PrefsNotify* notify)
{
MSG_PrefsNotify** tmp = m_notify;
m_notify = new MSG_PrefsNotify* [m_numnotify + 1];
for (int i=0 ; i<m_numnotify ; i++) {
XP_ASSERT(tmp[i] != notify);
m_notify[i] = tmp[i];
}
m_notify[m_numnotify++] = notify;
delete [] tmp; // not sure why this wasn't here before.
// Could have used XP_PtrArray...
}
void MSG_Prefs::RemoveNotify(MSG_PrefsNotify* notify)
{
int i = 0;
if (m_notifying)
{
// We're in the process of notifying listeners, so we
// can't shuffle pointers around.
// Just null out the pointer in question, Notify will
// clean up after us.
for (; i<m_numnotify; i++)
{
if (m_notify[i] == notify)
m_notify[i] = NULL;
}
return;
}
// If we're not notifying listeners, just replace the
// dead element with the last in the list, then decrement
// the listener count.
for (; i<m_numnotify ; i++)
{
if (m_notify[i] == notify)
{
m_notify[i] = m_notify[--m_numnotify];
return;
}
}
XP_ASSERT(0);
}
XP_Bool MSG_Prefs::GetSearchServer()
{
Reload();
return m_searchServer;
}
XP_Bool MSG_Prefs::GetSearchSubFolders()
{
Reload();
return m_searchSubFolders;
}
int32 MSG_Prefs::GetNumCustomHeaders()
{
Reload();
// determine number of custom headers in the preference so far....
int count = 0;
if (!m_customHeaders)
return 0;
char * buffer = XP_STRDUP(m_customHeaders);
char * marker = buffer;
while (XP_STRTOK_R(nil, ":, ", &buffer))
count++;
XP_FREEIF(marker);
return count;
}
// caller must use XP_FREE to deallocate the header string this returns.
char * MSG_Prefs::GetNthCustomHeader(int offset)
{
Reload();
char * temp = NULL;
if (offset < 0)
return temp;
if (!m_customHeaders)
return NULL;
char * buffer = XP_STRDUP(m_customHeaders);
char * marker = buffer;
for (int count = 0; count <= offset; count++)
{
temp = XP_STRTOK_R(nil,",: ",&buffer);
if (!temp)
break;
}
// temp now points to the token string
if (temp)
temp = XP_STRDUP(temp); // make a copy of the string // caller must deallocate the space
XP_FREEIF(marker); // free our copy of the buffer...
return temp;
}
#ifdef XP_UNIX
void MSG_Prefs::SetFolderDirectory(const char* d)
{
PREF_SetCharPref("mail.directory", d);
m_dirty = TRUE;
}
#else
void MSG_Prefs::SetFolderDirectory(const char*)
{
}
#endif
const char *MSG_Prefs::GetFolderDirectory()
{
Reload();
return m_localMailDirectory;
}
const char *MSG_Prefs::GetIMAPFolderDirectory()
{
Reload();
if (!m_IMAPdirectory)
{
char *machinePathName = 0;
if (m_popHost)
{
// see if there's a :port in the server name. If so, strip it off when
// creating the server directory.
char *server = XP_STRDUP(m_popHost);
char *port = 0;
if (server)
{
port = XP_STRCHR(server,':');
if (port)
*port = 0;
machinePathName = WH_FileName(server, xpImapServerDirectory);
XP_FREE(server);
}
}
if (machinePathName)
{
char *imapUrl = XP_PlatformFileToURL (machinePathName);
if (imapUrl)
{
m_IMAPdirectory = XP_STRDUP(imapUrl + XP_STRLEN("file://"));
XP_FREE(imapUrl);
}
XP_FREE (machinePathName);
}
}
return m_IMAPdirectory;
}
void MSG_Prefs::GetCitationStyle(MSG_FONT* f, MSG_CITATION_SIZE* s, const char** c)
{
Reload();
if (f) *f = m_citationFont;
if (s) *s = m_citationFontSize;
if (c) *c = m_citationColor;
}
const char* MSG_Prefs::GetPopHost()
{
Reload();
return m_popHost;
}
XP_Bool MSG_Prefs::IMAPMessageDeleteIsMoveToTrash()
{
Reload();
return m_ImapDeleteMoveToTrash;
}
/*
const char *MSG_Prefs::GetOnlineImapSubDir()
{
Reload();
return m_OnlineImapSubDir;
}
*/
XP_Bool MSG_Prefs::GetMailServerIsIMAP4()
{
Reload();
return m_mailServerIsIMAP;
}
HG87637
const char *MSG_Prefs::GetCopyToSentMailFolderPath()
{
return GetDefaultHeaderContents(MSG_FCC_HEADER_MASK);
}
MSG_CommandType MSG_Prefs::GetHeaderStyle()
{
Reload();
return m_headerstyle;
}
XP_Bool MSG_Prefs::GetNoInlineAttachments()
{
Reload();
return m_noinline;
}
XP_Bool MSG_Prefs::GetWrapLongLines()
{
Reload();
return m_wraplonglines;
}
XP_Bool MSG_Prefs::GetAutoQuoteReply()
{
Reload();
return m_autoQuote;
}
const char* MSG_Prefs::GetDefaultHeaderContents(MSG_HEADER_SET header)
{
Reload();
int i = ConvertHeaderSetToSubscript(header);
if (i < 0)
return NULL;
return m_defaultHeaders[i];
}
XP_Bool MSG_Prefs::GetDefaultBccSelf(XP_Bool newsBcc)
{
Reload();
return newsBcc ? m_newsBccSelf : m_mailBccSelf;
}
int32 MSG_Prefs::GetPurgeThreshhold()
{
Reload();
return m_purgeThreshhold;
}
XP_Bool MSG_Prefs::GetPurgeThreshholdEnabled()
{
Reload();
return m_purgeThreshholdEnabled;
}
XP_Bool MSG_Prefs::GetShowPrettyNames()
{
Reload();
return m_showPrettyNames;
}
HG92435
XP_Bool MSG_Prefs::GetNewsNotifyOn()
{
Reload();
return m_newsNotifyOn;
}
void MSG_Prefs::SetNewsNotifyOn(XP_Bool notify)
{
PREF_SetBoolPref("news.notify.on", notify);
}
MSG_NCFValue MSG_Prefs::GetNavCrossesFolders()
{
Reload();
return (MSG_NCFValue) m_navCrossesFolders;
}
void MSG_Prefs::SetNavCrossesFolders(MSG_NCFValue cross)
{
PREF_SetIntPref("mailnews.nav_crosses_folders", (int32) cross);
}
MSG_Master *MSG_Prefs::GetMasterForBiff()
{
Reload();
return m_masterForBiff;
}
void MSG_Prefs::SetMasterForBiff(MSG_Master *mstr)
{
// Since we're dealing with a mail master, this by
// definition is a temporary preference. So, just
// set the member in this case.
m_masterForBiff = mstr;
}
XP_Bool MSG_Prefs::CopyStringIfChanged(char** str, const char* value)
{
if (*str == NULL && value == NULL) return FALSE;
if (*str && value && XP_STRCMP(*str, value) == 0) return FALSE;
if (*str)
delete [] *str;
if (value)
{
*str = new char[XP_STRLEN(value) + 1];
if (*str)
XP_STRCPY(*str, value);
}
else
*str = NULL;
return TRUE;
}
int MSG_Prefs::ConvertHeaderSetToSubscript(MSG_HEADER_SET header)
{
switch (header)
{
case MSG_REPLY_TO_HEADER_MASK:
return 0;
case MSG_BCC_HEADER_MASK:
return 1;
case MSG_FCC_HEADER_MASK:
{
XP_Bool use_imap_sentmail = FALSE;
PREF_GetBoolPref("mail.use_imap_sentmail", &use_imap_sentmail);
if (use_imap_sentmail)
return 3;
else
return 2;
}
case MSG_NEWS_BCC_HEADER_MASK:
return 4;
case MSG_NEWS_FCC_HEADER_MASK:
{
XP_Bool use_imap_sentmail = FALSE;
PREF_GetBoolPref("news.use_imap_sentmail", &use_imap_sentmail);
if (use_imap_sentmail)
return 6;
else
return 5;
}
default:
XP_ASSERT (0);
return -1;
}
}
msg_StringArray *MSG_Prefs::m_emailAliases = NULL;
msg_StringArray *MSG_Prefs::m_emailAliasesNot = NULL;
/*static*/ XP_Bool MSG_Prefs::IsEmailAddressAnAliasForMe (const char *addr)
{
// Does the address match one of the user's alias expressions (e.g. foo@*.netscape.com)
if (m_emailAliasesNot)
{
// Some addresses can't be considered aliases. Right now, this is just used
// for the Reply-To address, so that if you Reply All, your Reply-To address
// will be included, or if you send yourself an MDN request, you'll get one back
//
// NB: this list is guaranteed to hold only addresses, not names, so we can strcmp
// it without parsing it (here)
for (int i = 0; i < m_emailAliasesNot->GetSize(); i++)
if (!strcasecomp (addr, m_emailAliasesNot->GetAt(i)))
return FALSE;
}
if (m_emailAliases) // master/prefs may not have been initialized yet
{
for (int i = 0; i < m_emailAliases->GetSize(); i++)
{
char *alias = (char*) m_emailAliases->GetAt(i); //Hacky cast: regexp API isn't const
if (VALID_SXP == NET_RegExpValid (alias))
{
// The alias is a regular expression, so send it into the regexp evaluator
if (!NET_RegExpMatch ((char*) addr, alias, FALSE /*case sensitive*/))
return TRUE;
}
else
{
// The alias is not a regular expression, so just use a string compare
if (!strcasecomp (addr, alias))
return TRUE;
}
}
}
return FALSE;
}

View File

@@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgPrefs_H_
#define _MsgPrefs_H_
#include "msgzap.h"
#include "rosetta.h"
/*
mwelch 97 July:
Before adding anything new to MSG_Prefs, consider whether your
new preference can best be managed using the prefs API directly.
If you are not getting the preference value often or otherwise
have no need to cache the prefs value, you are probably better
off calling the prefs API everywhere and leaving this object
alone.
Having said that, if you want to add a new member variable and
its access functions to MSG_Prefs, here is the way you want to
do this, in order to keep the world happy. (Specific conditions,
of course, may apply to your preference; the instructions below
apply to most circumstances.)
If a change in your preference does not need to trigger an immediate
action:
1. Put a call to PREF_Get{Int,Bool,Char,etc.)Pref in the Reload()
method for your member variable and its corresponding JavaScript
preference name. This should be the only way by which your
member variable is set.
2. Your Get() accessor function must call Reload() before returning
the member value. This is the way by which you can be assured that
the most recently set preference value
3. If you must have a Set() accessor, implement it in such a way
that it calls PREF_Set{Int,Bool,Char,etc.}Pref, instead of
setting your member variable directly. This way, the prefs API
(and the user's preferences.js file) is properly updated. The
new value circulates back using Reload() and Get() as
described above.
If a change in your preference requires an immediate response (alert,
change in behavior, etc):
1. Implement the preference as described above.
2. In MSG_PrefsChangeCallback, there is a top-level parse tree (looking
for names beginning with "mail", "news", or "netw"). Find the clause
corresponding to your preference name and add a condition with code
that needs to run when your preference changes. Even if the code that
runs within MSG_PrefsChangeCallback always reloads on its own, you
still want to leave a load call within Reload() in order to load
the initial value at startup time.
If you have a transaction that spans across several preference changes,
be sure to tell the right people so that we can someday have calls to
transactionalize preference changes. Currently, all we can do is respond
to changes to individual preferences.
*/
class MSG_PrefsNotify;
class msg_StringArray;
int PR_CALLBACK MSG_PrefsChangeCallback(const char *prefName, void *data);
int PR_CALLBACK MSG_FccPrefChanged (const char *, void *msgPrefs);
int PR_CALLBACK MSG_MailServerTypeChanged (const char *, void *msgPrefs);
int PR_CALLBACK MSG_DraftsPrefChanged (const char *, void *msgPrefs);
int PR_CALLBACK MSG_TemplatesPrefChanged (const char *, void *msgPrefs);
int PR_CALLBACK MSG_UseImapSentmailPrefChanged (const char *prefName, void *msgPrefs);
int msg_FolderPrefChanged(const char *, void *msgPrefs, uint32 flag);
// Corresponds to pref("mailnews.nav_crosses_folders", 0)
// 0=do it, don't prompt 1=prompt, 2=don't do it, don't prompt
typedef enum {
MSG_NCFDoIt = 0,
MSG_NCFPrompt = 1,
MSG_NCFDont = 2
} MSG_NCFValue;
#define MSG_IMAP_DELETE_MODEL_UPGRADE_FLAG 0x00000001 // upgraded to imap delete model?
#define MSG_IMAP_SPECIAL_RESERVED_UPGRADE_FLAG 0x00000002 // RESERVED. DO NOT CHANGE THIS VALUE!
#define MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG 0x00000004 // upgraded to IMAP subscription?
#define MSG_IMAP_DEFAULT_HOST_UPGRADE_FLAG 0x00000008 // upgraded default host to new per host prefs
#define MSG_IMAP_CURRENT_START_FLAGS ( MSG_IMAP_DELETE_MODEL_UPGRADE_FLAG \
| MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG \
| MSG_IMAP_DEFAULT_HOST_UPGRADE_FLAG)
class MSG_Prefs : public MSG_ZapIt
{
public:
MSG_Prefs(void);
virtual ~MSG_Prefs();
void AddNotify(MSG_PrefsNotify* notify);
void RemoveNotify(MSG_PrefsNotify* notify);
void SetFolderDirectory(const char* directory);
const char* GetFolderDirectory();
const char* GetIMAPFolderDirectory();
// This preference is used to help decide when to perform one time tricks, based
// on the age of the current user profile.
// The theory is: On a fresh install (actually, the creation of a new user profile),
// we should never do any one-time upgrade tricks.
// On an install over a previous verison, we should run each of the upgrade tricks that
// haven't already been run, for each old profile.
// The first such example is dealing with the introduction of the imap delete messages
// model in 4.02. We wanted the imap delete model to be the default out of the box but
// we also wanted a painless upgrade for existing users who use the delete to trash model.
// The solution is to make the imap delete model the default but if you haven't run the
// IMAP delete model upgrade and you have a trash folder, then change the preference to the
// trash model. In either case, the profile age is now changed to reflect that we have made
// this upgrade, by setting the appropriate bit.
// We will do this in a bitwise manner, so that individual one-time tricks do not depend
// on the order in which we check for them.
// This preference should ALWAYS be written to the prefs.js file, unless the value is 0.
// A value of 0 indicates an upgrade from Communicator 4.0, in which no upgrades have ever
// been run.
// The value written out to the prefs should be the sum of all trick flags which have been run.
// On a fresh install, we automatically write out the following number:
// {sum of all flags used for an upgrade trick}
// We do this in config.js, in modules\libpref\src\init
// The default value (in all.js) should ALWAYS be 0. This is because if the preference isn't
// present in the prefs.js file, then it means the value is implicitly 0 (because we are
// upgrading from 4.0, and none of the one-time tricks have been run).
// So, when a new flag is added here, you should also modify "mailnews.profile_age" in config.js
// to be the following number:
// {sum of all flags used for an upgrade trick}
// The Flags
// see above for #definitions
// 0x00000001 (reserved for the imap delete model trick)
// 0x00000004 (reserved for migrating to IMAP subscription)
// 0x00000008 MSG_IMAP_DEFAULT_HOST_UPGRADE_FLAG (upgraded default host to new per host prefs)
//
//
// *(The special reserved upgrade flag is purposely not used for an upgrade anywhere, except in calculating
// the default value for all.js. This is because we always want the value of "mailnews.profile_age"
// written out to the prefs file -- it can NEVER take on the "default" value, or else it will be
// removed from prefs.js, and this will defeat the purpose of writing out the "current" profile age.
// If we were to ever upgrade, it would find the preference not written out, and assume that it is
// up-to-date.
// To ensure that it is always written out to the file, in the creation of the MSG_Master we will
// un-set this flag each time, so that on a fresh install, the preference will get written out.
// current total = 1+4+8 = 13 (see #define MSG_IMAP_CURRENT_START_FLAGS above)
int32 GetStartingMailNewsProfileAge();
void SetMailNewsProfileAgeFlag(int32 flag, XP_Bool set = TRUE); // call this when we perform an upgrade, to set that upgrade bit
HG97760
XP_Bool GetMailServerIsIMAP4();
MSG_CommandType GetHeaderStyle();
XP_Bool GetNoInlineAttachments();
XP_Bool GetWrapLongLines();
XP_Bool GetDefaultBccSelf(XP_Bool newsBcc);
XP_Bool GetAutoQuoteReply();
const char * GetDefaultHeaderContents(MSG_HEADER_SET header);
const char * GetCopyToSentMailFolderPath();
//const char * GetOnlineImapSubDir(); // online subdir for imap folders
int32 GetPurgeThreshhold();
XP_Bool GetPurgeThreshholdEnabled();
void GetCitationStyle(MSG_FONT* font, MSG_CITATION_SIZE* size, const char** color);
const char * GetPopHost();
XP_Bool IMAPMessageDeleteIsMoveToTrash();
XP_Bool GetSearchSubFolders();
XP_Bool GetSearchServer();
// Queries for things that are derived off of the preferences.
int32 GetNumCustomHeaders();
char * GetNthCustomHeader(int offset); // caller must use XP_FREEIF on the character string returned
// Get the full pathname of the folder implementing the given magic type.
// The result must be free'd with XP_FREE().
char * MagicFolderName(uint32 flag, int *pStatus = 0);
// I believe this should be a global preference and not per server
XP_Bool GetShowPrettyNames();
XP_Bool GetNewsNotifyOn();
void SetNewsNotifyOn(XP_Bool notifyOn);
MSG_NCFValue GetNavCrossesFolders();
void SetNavCrossesFolders(MSG_NCFValue navCrossesFoldersOn);
void SetMasterForBiff(MSG_Master *masterForBiff);
MSG_Master * GetMasterForBiff();
static XP_Bool IsEmailAddressAnAliasForMe (const char *addr);
static int GetXPDirPathPref(const char *prefName, XP_Bool expectFile, char ** result);
static int SetXPMailFilePref(const char *prefName, char * xpPath);
static void PlatformFileToURLPath(const char *src, char **dest);
HG82309
XP_Bool GetConfirmMoveFoldersToTrash() { Reload(); return m_confirmMoveFoldersToTrash; }
protected:
XP_Bool m_dirty; // need to reload prefs at next Get() call
// m_freezeMailDirectory, if TRUE, prevents (directory) from
// getting a new value. We set this TRUE in order to ensure that
// (directory) will only get one meaningful value within a session.
XP_Bool m_freezeMailDirectory;
void Reload(void); // reload if dirty flag is set
void Notify(int16 updateCode);
// callback when javascript prefs value(s) change
friend int PR_CALLBACK MSG_PrefsChangeCallback(const char *prefName, void *data);
friend int msg_FolderPrefChanged (const char *, void *msgPrefs, uint32 flag);
XP_Bool CopyStringIfChanged(char** str, const char* newvalue);
int ConvertHeaderSetToSubscript(MSG_HEADER_SET header);
HG72142
MSG_Master *m_masterForBiff;
// Notification prefs (is this all obsolete? or should it be?)
MSG_PrefsNotify **m_notify;
int m_numnotify;
XP_Bool m_notifying; // Are we in the middle of notifying listeners?
// IMAP prefs
char * m_IMAPdirectory;
char * m_OnlineImapSubDir;
XP_Bool m_ImapDeleteMoveToTrash;
XP_Bool m_mailServerIsIMAP;
HG29866
// Search and Filter prefs
char * m_customHeaders; // arbitrary headers list.
int32 m_numberCustomHeaders;
XP_Bool m_searchSubFolders;
XP_Bool m_searchServer; // when in online mode, search server or search locally (if false)
// Quoting prefs
XP_Bool m_autoQuote;
MSG_FONT m_citationFont;
MSG_CITATION_SIZE m_citationFontSize;
char * m_citationColor;
char * m_localMailDirectory;
XP_Bool m_plainText;
char * m_popHost;
char * m_defaultHeaders[7];
XP_Bool m_mailBccSelf;
XP_Bool m_newsBccSelf;
long m_mailInputType;
MSG_CommandType m_headerstyle;
XP_Bool m_noinline;
XP_Bool m_wraplonglines;
XP_Bool m_showPrettyNames;
XP_Bool m_purgeThreshholdEnabled;
int32 m_purgeThreshhold;
XP_Bool m_newsNotifyOn;
int32 m_navCrossesFolders;
int32 m_startingMailNewsProfileAge;
XP_Bool m_confirmMoveFoldersToTrash;
static msg_StringArray *m_emailAliases;
static msg_StringArray *m_emailAliasesNot;
char * m_draftsName;
char * m_sentName;
char * m_templatesName;
};
const char * msg_DefaultFolderName(uint32 flag);
#endif /* _MsgPrefs_H_ */

View File

@@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgPrNot_H_
#define _MsgPrNot_H_
#include "msgzap.h"
#include "rosetta.h"
class MSG_Prefs;
class MSG_PrefsNotify : public MSG_ZapIt {
public:
// Codes to notify us that a preference item has changed.
enum NotifyCode {
Directory,
CitationStyle,
PlaintextFont,
PopHost,
AutoQuote,
DefaultHeader,
DefaultBCC,
MailServerType,
ImapOnlineDir,
HG62422
WrapLongLines,
ChangeIMAPDeleteModel
};
virtual void NotifyPrefsChange(NotifyCode code) = 0;
};
#endif /* _MsgPrNot_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,252 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef __MSGSEND_H__
#define __MSGSEND_H__
#include "msgpane.h"
#include "mimeenc.h" /* For base64/QP encoder */
#include "mhtmlstm.h"
#include "rosetta.h"
class MSG_DeliverMimeAttachment;
class ParseOutgoingMessage;
class MailDB;
#define MIME_BUFFER_SIZE 4096
class MSG_SendMimeDeliveryState
{
public:
MSG_SendMimeDeliveryState();
~MSG_SendMimeDeliveryState();
static void StartMessageDelivery(MSG_Pane *pane,
void *fe_data,
MSG_CompositionFields *fields,
XP_Bool digest_p,
XP_Bool dont_deliver_p,
MSG_Deliver_Mode mode,
const char *attachment1_type,
const char *attachment1_body,
uint32 attachment1_body_length,
const struct MSG_AttachmentData
*attachments,
const struct MSG_AttachedFile
*preloaded_attachments,
//#ifdef MSG_SEND_MULTIPART_RELATED
MSG_SendPart *relatedPart,
//#endif
void (*message_delivery_done_callback)
(MWContext *context,
void *fe_data,
int status,
const char *error_message));
int Init(MSG_Pane *pane,
void *fe_data,
MSG_CompositionFields *fields,
XP_Bool digest_p,
XP_Bool dont_deliver_p,
MSG_Deliver_Mode mode,
const char *attachment1_type,
const char *attachment1_body,
uint32 attachment1_body_length,
const struct MSG_AttachmentData *attachments,
const struct MSG_AttachedFile *preloaded_attachments,
//#ifdef MSG_SEND_MULTIPART_RELATED
MSG_SendPart *relatedPart,
//#endif
void (*message_delivery_done_callback)
(MWContext *context,
void *fe_data,
int status,
const char *error_message));
void StartMessageDelivery();
int GatherMimeAttachments();
void DeliverMessage();
int HackAttachments(const struct MSG_AttachmentData *attachments,
const struct MSG_AttachedFile *preloaded_attachments);
void DeliverFileAsMail();
void DeliverFileAsNews();
void DeliverAsMailExit(URL_Struct *url, int status);
void DeliverAsNewsExit(URL_Struct *url, int status);
void Fail(int failure_code, char *error_msg);
void Clear();
// Callback from msgsendp.cpp into msgsend.cpp.
HG89377
MWContext *GetContext() { return m_pane->GetContext(); }
int SetMimeHeader(MSG_HEADER_SET header, const char *value);
MSG_Pane *m_pane; /* Pane to use when loading the URLs */
void *m_fe_data; /* passed in and passed to callback */
MSG_CompositionFields *m_fields;
XP_Bool m_dont_deliver_p; /* If set, we just return the name of the file
we created, instead of actually delivering
this message. */
MSG_Deliver_Mode m_deliver_mode; /* MSG_DeliverNow, MSG_QueueForLater,
MSG_SaveAsDraft, MSG_SaveAsTemplate
*/
XP_Bool m_attachments_only_p; /* If set, then we don't construct a complete
MIME message; instead, we just retrieve the
attachments from the network, store them in
tmp files, and return a list of
MSG_AttachedFile structs which describe
them. */
XP_Bool m_pre_snarfed_attachments_p; /* If true, then the attachments were
loaded by msg_DownloadAttachments()
and therefore we shouldn't delete
the tmp files (but should leave
that to the caller.) */
XP_Bool m_digest_p; /* Whether to be multipart/digest instead of
multipart/mixed. */
XP_Bool m_be_synchronous_p; /* If true, we will load one URL after another,
rather than starting all URLs going at once
and letting them load in parallel. This is
more efficient if (for example) all URLs are
known to be coming from the same news server
or mailbox: loading them in parallel would
cause multiple connections to the news
server to be opened, or would cause much
seek()ing.
*/
HG83623
/* The first attachment, if any (typed in by the user.)
*/
char *m_attachment1_type;
char *m_attachment1_encoding;
MimeEncoderData *m_attachment1_encoder_data;
char *m_attachment1_body;
uint32 m_attachment1_body_length;
// The plaintext form of the first attachment, if needed.
MSG_DeliverMimeAttachment* m_plaintext;
//#ifdef MSG_SEND_MULTIPART_RELATED
// The multipart/related save object for HTML text.
MSG_SendPart *m_related_part;
//#endif
// File where we stored our HTML so that we could make the plaintext form.
char* m_html_filename;
/* Subsequent attachments, if any.
*/
int32 m_attachment_count;
int32 m_attachment_pending_count;
MSG_DeliverMimeAttachment *m_attachments;
int32 m_status; /* in case some attachments fail but not all */
/* The caller's `exit' method. */
void (*m_message_delivery_done_callback) (MWContext *context,
void * fe_data, int status,
const char * error_msg);
/* The exit method used when downloading attachments only. */
void (*m_attachments_done_callback) (MWContext *context,
void * fe_data, int status,
const char * error_msg,
struct MSG_AttachedFile *attachments);
char *m_msg_file_name; /* Our temporary file */
XP_File m_msg_file;
};
class MSG_DeliverMimeAttachment
{
public:
MSG_DeliverMimeAttachment();
~MSG_DeliverMimeAttachment();
void UrlExit(URL_Struct *url, int status, MWContext *context);
int32 SnarfAttachment ();
void AnalyzeDataChunk (const char *chunk, int32 chunkSize);
void AnalyzeSnarfedFile (); /* Analyze a previously-snarfed file.
(Currently only used for plaintext
converted from HTML.) */
int PickEncoding (int16 mail_csid);
XP_Bool UseUUEncode_p(void);
char *m_url_string;
URL_Struct *m_url;
XP_Bool m_done;
MSG_SendMimeDeliveryState *m_mime_delivery_state;
char *m_type; /* The real type, once we know it. */
char *m_override_type; /* The type we should assume it to be
or 0, if we should get it from the
URL_Struct (from the server) */
char *m_override_encoding; /* Goes along with override_type */
char *m_desired_type; /* The type it should be converted to. */
char *m_description; /* For Content-Description header */
char *m_x_mac_type, *m_x_mac_creator; /* Mac file type/creator. */
char *m_real_name; /* The name for the headers, if different
from the URL. */
char *m_encoding; /* The encoding, once we've decided. */
XP_Bool m_already_encoded_p; /* If we attach a document that is already
encoded, we just pass it through. */
char *m_file_name; /* The temp file to which we save it */
XP_File m_file;
#ifdef XP_MAC
char *m_ap_filename; /* The temp file holds the appledouble
encoding of the file we want to post. */
#endif
HG93873
uint32 m_size; /* Some state used while filtering it */
uint32 m_unprintable_count;
uint32 m_highbit_count;
uint32 m_ctl_count;
uint32 m_null_count;
uint32 m_current_column;
uint32 m_max_column;
uint32 m_lines;
MimeEncoderData *m_encoder_data; /* Opaque state for base64/qp encoder. */
XP_Bool m_graph_progress_started;
PrintSetup m_print_setup; /* Used by HTML->Text and HTML->PS */
};
// These routines should only be used by the MSG_SendPart class.
extern XP_Bool mime_type_needs_charset (const char *type);
extern int mime_write_message_body(MSG_SendMimeDeliveryState *state,
char *buf, int32 size);
extern char* mime_get_stream_write_buffer(void);
#endif /* __MSGSEND_H__ */

View File

@@ -0,0 +1,768 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "ntypes.h"
#include "xlate.h" // Needed to compile msgsend.h
#include "msgsend.h"
#include "msgsendp.h"
#include "libi18n.h"
extern "C"
{
extern int MK_OUT_OF_MEMORY;
}
static char *mime_mailto_stream_read_buffer = 0;
int32 MSG_SendPart::M_counter = 0;
MSG_SendPart::MSG_SendPart(MSG_SendMimeDeliveryState* state, int16 part_csid)
{
m_csid = part_csid;
SetMimeDeliveryState(state);
}
MSG_SendPart::~MSG_SendPart()
{
if (m_encoder_data) {
MimeEncoderDestroy(m_encoder_data, FALSE);
m_encoder_data = NULL;
}
for (int i=0 ; i<m_numchildren ; i++) {
delete m_children[i];
}
delete [] m_children;
delete [] m_buffer;
delete [] m_other;
if (m_filename) delete [] m_filename;
FREEIF(m_type);
}
int MSG_SendPart::CopyString(char** dest, const char* src)
{
XP_ASSERT(src);
if (!src) src = "";
delete [] *dest;
*dest = new char [XP_STRLEN(src) + 1];
if (!*dest) return MK_OUT_OF_MEMORY;
XP_STRCPY(*dest, src);
return 0;
}
int MSG_SendPart::SetFile(const char* filename, XP_FileType type)
{
XP_ASSERT(m_buffer == NULL);
int status = CopyString(&m_filename, filename);
if (status < 0) return status;
m_filetype = type;
return status;
}
int MSG_SendPart::SetBuffer(const char* buffer)
{
XP_ASSERT(m_filename == NULL);
return CopyString(&m_buffer, buffer);
}
int MSG_SendPart::SetType(const char* type)
{
FREEIF(m_type);
m_type = XP_STRDUP(type);
return m_type ? 0 : MK_OUT_OF_MEMORY;
}
int MSG_SendPart::SetOtherHeaders(const char* other)
{
return CopyString(&m_other, other);
}
int MSG_SendPart::SetMimeDeliveryState(MSG_SendMimeDeliveryState *state)
{
m_state = state;
if (GetNumChildren() > 0)
{
for(int i = 0; i < GetNumChildren(); i++)
{
MSG_SendPart *part = GetChild(i);
if (part)
part->SetMimeDeliveryState(state);
}
}
return 0;
}
int MSG_SendPart::AppendOtherHeaders(const char* more)
{
if (!m_other) return SetOtherHeaders(more);
if (!more || !*more) return 0;
char* tmp = new char[XP_STRLEN(m_other) + XP_STRLEN(more) + 2];
if (!tmp) return MK_OUT_OF_MEMORY;
XP_STRCPY(tmp, m_other);
XP_STRCAT(tmp, more);
delete [] m_other;
m_other = tmp;
return 0;
}
int MSG_SendPart::SetEncoderData(MimeEncoderData* data)
{
m_encoder_data = data;
return 0;
}
int MSG_SendPart::SetMainPart(XP_Bool value)
{
m_mainpart = value;
return 0;
}
int MSG_SendPart::AddChild(MSG_SendPart* child)
{
m_numchildren++;
MSG_SendPart** tmp = new MSG_SendPart* [m_numchildren];
if (tmp == NULL) return MK_OUT_OF_MEMORY;
for (int i=0 ; i<m_numchildren-1 ; i++) {
tmp[i] = m_children[i];
}
delete [] m_children;
m_children = tmp;
m_children[m_numchildren - 1] = child;
child->m_parent = this;
return 0;
}
MSG_SendPart *
MSG_SendPart::DetachChild(int32 whichOne)
{
MSG_SendPart *returnValue = NULL;
XP_ASSERT(whichOne >= 0 && whichOne < m_numchildren);
if (whichOne >= 0 && whichOne < m_numchildren)
{
returnValue = m_children[whichOne];
if (m_numchildren > 1)
{
MSG_SendPart** tmp = new MSG_SendPart* [m_numchildren-1];
if (tmp != NULL)
{
// move all the other kids over
for (int i=0 ; i<m_numchildren-1 ; i++)
{
if (i >= whichOne)
tmp[i] = m_children[i+1];
else
tmp[i] = m_children[i];
}
delete [] m_children;
m_children = tmp;
m_numchildren--;
}
}
else
{
delete [] m_children;
m_children = NULL;
m_numchildren = 0;
}
}
if (returnValue)
returnValue->m_parent = NULL;
return returnValue;
}
MSG_SendPart* MSG_SendPart::GetChild(int32 which)
{
XP_ASSERT(which >= 0 && which < m_numchildren);
if (which >= 0 && which < m_numchildren) {
return m_children[which];
}
return NULL;
}
int MSG_SendPart::PushBody(char* buffer, int32 length)
{
int status = 0;
char* encoded_data = buffer;
/* if this is the first block, create the conversion object
*/
if (m_firstBlock) {
if (m_needIntlConversion) {
m_intlDocToMailConverter =
INTL_CreateDocToMailConverter(m_state->GetContext(),
(!strcasecomp(m_type,
TEXT_HTML)),
(unsigned char*) buffer,
length);
// No conversion is done when mail_csid (ToCSID for the converter) is JIS
// and type is HTML (usually csid is SJIS or EUC for Japanese HTML)
// in order to avoid mismatch META_TAG (bug#104255).
if (m_intlDocToMailConverter != NULL) {
XP_Bool Base64HtmlNoChconv = ((INTL_GetCCCToCSID(m_intlDocToMailConverter) == CS_JIS) &&
!strcasecomp(m_type, TEXT_HTML) &&
(m_encoder_data != NULL));
if (Base64HtmlNoChconv) {
INTL_DestroyCharCodeConverter(m_intlDocToMailConverter);
m_intlDocToMailConverter = NULL;
}
}
}
m_firstBlock = FALSE; /* No longer the first block */
}
if (m_intlDocToMailConverter) {
encoded_data =
(char*)INTL_CallCharCodeConverter(m_intlDocToMailConverter,
(unsigned char*)buffer,
length);
/* the return buffer is different from the */
/* origional one. The size needs to be change */
if(encoded_data && encoded_data != buffer) {
length = XP_STRLEN(encoded_data);
}
}
if (m_encoder_data) {
status = MimeEncoderWrite(m_encoder_data, encoded_data, length);
} else {
// Merely translate all linebreaks to CRLF.
int status = 0;
const char *in = encoded_data;
const char *end = in + length;
char *buffer, *out;
buffer = mime_get_stream_write_buffer();
if (!buffer) return MK_OUT_OF_MEMORY;
XP_ASSERT(encoded_data != buffer);
out = buffer;
for (; in < end; in++) {
if (m_just_hit_CR) {
m_just_hit_CR = FALSE;
if (*in == LF) {
// The last thing we wrote was a CRLF from hitting a CR.
// So, we don't want to do anything from a following LF;
// we want to ignore it.
continue;
}
}
if (*in == CR || *in == LF) {
/* Write out the newline. */
*out++ = CR;
*out++ = LF;
status = mime_write_message_body(m_state, buffer,
out - buffer);
if (status < 0) return status;
out = buffer;
if (*in == CR) {
m_just_hit_CR = TRUE;
}
out = buffer;
} else {
/* Fix for bug #95985. We can't assume that all lines are shorter
than 4096 chars (MIME_BUFFER_SIZE), so we need to test
for this here. sfraser.
*/
if (out - buffer >= MIME_BUFFER_SIZE)
{
status = mime_write_message_body(m_state, buffer, out - buffer);
if (status < 0) return status;
out = buffer;
}
*out++ = *in;
}
}
/* Flush the last line. */
if (out > buffer) {
status = mime_write_message_body(m_state, buffer, out - buffer);
if (status < 0) return status;
out = buffer;
}
}
if (encoded_data && encoded_data != buffer) {
XP_FREE(encoded_data);
}
return status;
}
/* Partition the headers into those which apply to the message as a whole;
those which apply to the message's contents; and the Content-Type header
itself. (This relies on the fact that all body-related headers begin with
"Content-".)
(How many header parsers are in this program now?)
*/
static int divide_content_headers(const char *headers,
char **message_headers,
char **content_headers,
char **content_type_header)
{
const char *tail;
char *message_tail, *content_tail, *type_tail;
int L = 0;
if (headers)
L = XP_STRLEN(headers);
if (L == 0)
return 0;
*message_headers = (char *)XP_ALLOC(L+1);
if (!*message_headers)
return MK_OUT_OF_MEMORY;
*content_headers = (char *)XP_ALLOC(L+1);
if (!*content_headers)
{
XP_FREE(*message_headers);
return MK_OUT_OF_MEMORY;
}
*content_type_header = (char *)XP_ALLOC(L+1);
if (!*content_type_header)
{
XP_FREE(*message_headers);
XP_FREE(*content_headers);
return MK_OUT_OF_MEMORY;
}
message_tail = *message_headers;
content_tail = *content_headers;
type_tail = *content_type_header;
tail = headers;
while (*tail)
{
const char *head = tail;
char **out;
while(1)
{
/* Loop until we reach a newline that is not followed by whitespace.
*/
if (tail[0] == 0 ||
((tail[0] == CR || tail[0] == LF) &&
!(tail[1] == ' ' || tail[1] == '\t' || tail[1] == LF)))
{
/* Swallow the whole newline. */
if (tail[0] == CR && tail[1] == LF)
tail++;
if (*tail)
tail++;
break;
}
tail++;
}
/* Decide which block this header goes into.
*/
if (!strncasecomp(head, "Content-Type:", 13))
out = &type_tail;
else if (!strncasecomp(head, "Content-", 8))
out = &content_tail;
else
out = &message_tail;
XP_MEMCPY(*out, head, (tail-head));
*out += (tail-head);
}
*message_tail = 0;
*content_tail = 0;
*type_tail = 0;
if (!**message_headers)
{
XP_FREE(*message_headers);
*message_headers = 0;
}
if (!**content_headers)
{
XP_FREE(*content_headers);
*content_headers = 0;
}
if (!**content_type_header)
{
XP_FREE(*content_type_header);
*content_type_header = 0;
}
#ifdef DEBUG
// ### mwelch Because of the extreme difficulty we've had with
// duplicate part headers, I'm going to put in an
// ASSERT here which makes sure that no duplicate
// Content-Type or Content-Transfer-Encoding headers
// leave here undetected.
const char* tmp;
if (*content_type_header)
{
tmp = XP_STRSTR(*content_type_header, "Content-Type");
if (tmp)
{
tmp++; // get past the first occurrence
XP_ASSERT(!XP_STRSTR(tmp, "Content-Type"));
}
}
if (*content_headers)
{
tmp = XP_STRSTR(*content_headers, "Content-Transfer-Encoding");
if (tmp)
{
tmp++; // get past the first occurrence
XP_ASSERT(!XP_STRSTR(tmp, "Content-Transfer-Encoding"));
}
}
#endif // DEBUG
return 0;
}
extern "C" {
extern char *mime_make_separator(const char *prefix);
}
int MSG_SendPart::Write()
{
int status = 0;
char *separator = 0;
XP_File file = NULL;
#define PUSHLEN(str, length) \
do { \
status = mime_write_message_body(m_state, str, length); \
if (status < 0) goto FAIL; \
} while (0) \
#define PUSH(str) PUSHLEN(str, XP_STRLEN(str))
if (m_mainpart && m_type && XP_STRCMP(m_type, TEXT_HTML) == 0) {
if (m_filename) {
// The "insert HTML links" code requires a memory buffer,
// so read the file into memory.
XP_ASSERT(m_buffer == NULL);
XP_StatStruct st;
st.st_size = 0;
XP_Stat (m_filename, &st, m_filetype);
int32 length = st.st_size;
m_buffer = new char[length + 1];
if (m_buffer) {
file = XP_FileOpen(m_filename, m_filetype, XP_FILE_READ_BIN);
if (file) {
XP_FileRead(m_buffer, length, file);
XP_FileClose(file);
m_buffer[length] = '\0';
file = NULL;
if (m_filename) delete [] m_filename;
m_filename = NULL;
} else {
delete [] m_buffer;
m_buffer = NULL;
}
}
}
if (m_buffer) {
char* tmp = NET_ScanHTMLForURLs(m_buffer);
if (tmp) {
SetBuffer(tmp);
XP_FREE(tmp);
}
}
}
if (m_parent && m_parent->m_type &&
!strcasecomp(m_parent->m_type, MULTIPART_DIGEST) &&
m_type &&
(!strcasecomp(m_type, MESSAGE_RFC822) ||
!strcasecomp(m_type, MESSAGE_NEWS))) {
/* If we're in a multipart/digest, and this document is of type
message/rfc822, then it's appropriate to emit no
headers.
*/
} else {
char *message_headers = 0;
char *content_headers = 0;
char *content_type_header = 0;
status = divide_content_headers(m_other,
&message_headers,
&content_headers,
&content_type_header);
if (status < 0)
goto FAIL;
/* First, write out all of the headers that refer to the message
itself (From, Subject, MIME-Version, etc.)
*/
if (message_headers)
{
PUSH(message_headers);
XP_FREE(message_headers);
message_headers = 0;
}
if (!m_parent)
{
HG78478
if (status < 0) goto FAIL;
}
/* Now make sure there's a Content-Type header.
*/
if (!content_type_header)
{
XP_ASSERT(m_type && *m_type);
XP_Bool needsCharset = mime_type_needs_charset(m_type ? m_type : TEXT_PLAIN);
if (needsCharset)
{
char tmpCSName[64];
tmpCSName[0] = '\0';
INTL_CharSetIDToName(m_csid, tmpCSName);
content_type_header =
PR_smprintf("Content-Type: %s; charset=%s" CRLF,
(m_type ? m_type : TEXT_PLAIN), tmpCSName);
}
else
content_type_header =
PR_smprintf("Content-Type: %s" CRLF,
(m_type ? m_type : TEXT_PLAIN));
if (!content_type_header)
{
if (content_headers)
XP_FREE(content_headers);
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
}
/* If this is a compound object, tack a boundary string onto the
Content-Type header.
*/
if (m_numchildren > 0)
{
int L;
char *ct2;
XP_ASSERT(m_type);
if (!separator)
{
separator = mime_make_separator("");
if (!separator)
{
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
}
L = XP_STRLEN(content_type_header);
if (content_type_header[L-1] == LF)
content_type_header[--L] = 0;
if (content_type_header[L-1] == CR)
content_type_header[--L] = 0;
ct2 = PR_smprintf("%s;\r\n boundary=\"%s\"" CRLF,
content_type_header, separator);
XP_FREE(content_type_header);
if (!ct2)
{
if (content_headers)
XP_FREE(content_headers);
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
content_type_header = ct2;
}
/* Now write out the Content-Type header...
*/
XP_ASSERT(content_type_header && *content_type_header);
PUSH(content_type_header);
XP_FREE(content_type_header);
content_type_header = 0;
/* ...followed by all of the other headers that refer to the body of
the message (Content-Transfer-Encoding, Content-Dispositon, etc.)
*/
if (content_headers)
{
PUSH(content_headers);
XP_FREE(content_headers);
content_headers = 0;
}
}
PUSH(CRLF); // A blank line, to mark the end of headers.
m_firstBlock = TRUE;
/* only convert if we need to tag charset */
m_needIntlConversion = mime_type_needs_charset(m_type);
m_intlDocToMailConverter = NULL;
if (m_buffer) {
XP_ASSERT(!m_filename);
status = PushBody(m_buffer, XP_STRLEN(m_buffer));
if (status < 0) goto FAIL;
} else if (m_filename) {
file = XP_FileOpen(m_filename, m_filetype, XP_FILE_READ_BIN);
if (!file) {
status = -1; // ### Better error code for a temp file
// mysteriously disappearing?
goto FAIL;
}
/* Hack to avoid having to allocate memory... */
if (!mime_mailto_stream_read_buffer) {
mime_mailto_stream_read_buffer = (char *)
XP_ALLOC(MIME_BUFFER_SIZE);
if (!mime_mailto_stream_read_buffer)
{
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
}
char* buffer = mime_mailto_stream_read_buffer;
if (m_strip_sensitive_headers) {
/* We are attaching a message, so we should be careful to
strip out certain sensitive internal header fields.
*/
XP_Bool skipping = FALSE;
XP_ASSERT(MIME_BUFFER_SIZE > 1000); /* SMTP (RFC821) limit */
while (1) {
char *line = XP_FileReadLine(buffer, MIME_BUFFER_SIZE-3, file);
if (!line) break; /* EOF */
if (skipping) {
if (*line == ' ' || *line == '\t') {
continue;
} else {
skipping = FALSE;
}
}
int hdrLen = XP_STRLEN(buffer);
if ((hdrLen < 2) || (buffer[hdrLen-2] != CR)) // if the line doesn't end with CRLF,
{
// ... make it end with CRLF.
if ( (hdrLen == 0)
|| ((buffer[hdrLen-1] != CR) && (buffer[hdrLen-1] != LF)) )
hdrLen++;
buffer[hdrLen-1] = '\015';
buffer[hdrLen] = '\012';
buffer[hdrLen+1] = '\0';
}
if (!strncasecomp(line, "BCC:", 4) ||
!strncasecomp(line, "FCC:", 4) ||
!strncasecomp(line, CONTENT_LENGTH ":",
CONTENT_LENGTH_LEN + 1) ||
!strncasecomp(line, "Lines:", 6) ||
!strncasecomp(line, "Status:", 7) ||
!strncasecomp(line, X_MOZILLA_STATUS ":",
X_MOZILLA_STATUS_LEN+1) ||
!strncasecomp(line, X_MOZILLA_NEWSHOST ":",
X_MOZILLA_NEWSHOST_LEN+1) ||
!strncasecomp(line, X_UIDL ":", X_UIDL_LEN+1) ||
!strncasecomp(line, "X-VM-", 5))
{
skipping = TRUE;
continue;
}
PUSH(line);
if (*line == CR || *line == LF) {
break; // Now can do normal reads for the body.
}
}
}
while (1) {
status = XP_FileRead(buffer, MIME_BUFFER_SIZE, file);
if (status < 0) {
goto FAIL;
} else if (status == 0) {
break;
}
status = PushBody(buffer, status);
if (status < 0) goto FAIL;
}
}
if (m_encoder_data) {
status = MimeEncoderDestroy(m_encoder_data, FALSE);
m_encoder_data = NULL;
if (status < 0) goto FAIL;
}
if (m_numchildren > 0) {
XP_ASSERT(separator);
for (int i=0 ; i<m_numchildren ; i++) {
PUSH(CRLF);
PUSH("--");
PUSH(separator);
PUSH(CRLF);
status = m_children[i]->Write();
if (status < 0) goto FAIL;
}
PUSH(CRLF);
PUSH("--");
PUSH(separator);
PUSH("--");
PUSH(CRLF);
}
FAIL:
FREEIF(separator);
if (file) XP_FileClose(file);
if (m_intlDocToMailConverter) {
INTL_DestroyCharCodeConverter(m_intlDocToMailConverter);
m_intlDocToMailConverter = NULL;
}
return status;
}

View File

@@ -0,0 +1,112 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef MSG_SENDP_H
#define MSG_SENDP_H
#include "msgzap.h"
#include "mimeenc.h"
class MSG_SendMimeDeliveryState;
typedef int (*MSG_SendPartWriteFunc)(const char* line, int32 size,
XP_Bool isheader, void* closure);
class MSG_SendPart : public MSG_ZapIt {
public:
MSG_SendPart(MSG_SendMimeDeliveryState* state, int16 part_csid = 0);
virtual ~MSG_SendPart(); // Note that the destructor also destroys
// any children that were added.
virtual int Write();
virtual int SetFile(const char* filename, XP_FileType filetype);
const char* GetFilename() {return m_filename;}
XP_FileType GetFiletype() {return m_filetype;}
virtual int SetBuffer(const char* buffer);
const char* GetBuffer() {return m_buffer;}
virtual int SetType(const char* type);
const char* GetType() {return m_type;}
int16 GetCSID() { return m_csid; }
virtual int SetOtherHeaders(const char* other);
const char* SetOtherHeaders() {return m_other;}
virtual int AppendOtherHeaders(const char* moreother);
virtual int SetMimeDeliveryState(MSG_SendMimeDeliveryState* state);
// Note that the MSG_SendPart class will take over ownership of the
// MimeEncoderData* object, deleting it when it chooses. (This is
// necessary because deleting these objects is the only current way to
// flush out the data in them.)
int SetEncoderData(MimeEncoderData* data);
MimeEncoderData *GetEncoderData() {return m_encoder_data;}
int SetStripSensitiveHeaders(XP_Bool value) {
m_strip_sensitive_headers = value;
return 0;
}
XP_Bool GetStripSensitiveHeaders() {return m_strip_sensitive_headers;}
virtual int AddChild(MSG_SendPart* child);
int32 GetNumChildren() {return m_numchildren;}
MSG_SendPart* GetChild(int32 which);
MSG_SendPart* DetachChild(int32 which);
virtual int SetMainPart(XP_Bool value);
XP_Bool IsMainPart() {return m_mainpart;}
protected:
int CopyString(char** dest, const char* src);
int PushBody(char* buffer, int32 length);
MSG_SendMimeDeliveryState* m_state;
MSG_SendPart* m_parent;
char* m_filename;
XP_FileType m_filetype;
char* m_buffer;
char* m_type;
char* m_other;
int16 m_csid; // charset ID associated with this part
XP_Bool m_strip_sensitive_headers;
MimeEncoderData *m_encoder_data; /* Opaque state for base64/qp encoder. */
MSG_SendPart** m_children;
int32 m_numchildren;
// Data used while actually writing.
XP_Bool m_firstBlock;
XP_Bool m_needIntlConversion;
CCCDataObject m_intlDocToMailConverter;
XP_Bool m_mainpart;
XP_Bool m_just_hit_CR;
static int32 M_counter;
};
#endif /* MSG_SENDP_H */

View File

@@ -0,0 +1,502 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
#include "msg.h"
#include "msgurlq.h"
#include "msgpane.h"
MSG_UrlQueueElement::MSG_UrlQueueElement (const char *url, MSG_UrlQueue *queue, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, NET_ReloadMethod reloadMethod, FO_Present_Types outputFormat)
{
m_queue = queue;
m_pane = pane;
m_urlString = XP_STRDUP(url);
m_exitFunction = exitFunction;
m_reloadMethod = reloadMethod;
m_url = NULL;
m_callGetURLDirectly = FALSE;
m_outputFormat = outputFormat;
}
MSG_UrlQueueElement::MSG_UrlQueueElement (URL_Struct *url, MSG_UrlQueue *queue, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, XP_Bool skipFE, FO_Present_Types outputFormat)
{
m_queue = queue;
m_pane = pane;
m_urlString = XP_STRDUP(url->address);
m_exitFunction = exitFunction;
m_reloadMethod = url->force_reload;
m_url = url;
m_callGetURLDirectly = skipFE;
m_outputFormat = outputFormat;
}
MSG_UrlQueueElement::MSG_UrlQueueElement (URL_Struct *urls, MSG_UrlQueue *q)
{
m_queue = q;
m_pane = urls->msg_pane;
m_urlString = XP_STRDUP(urls->address);;
m_url = urls;
m_exitFunction = NULL;
m_reloadMethod = NET_DONT_RELOAD;
m_callGetURLDirectly = FALSE;
m_outputFormat = FO_CACHE_AND_PRESENT;
}
MSG_UrlQueueElement::~MSG_UrlQueueElement()
{
FREEIF(m_urlString);
// if (m_url && m_callGetURLDirectly)
// NET_FreeURLStruct(m_url); // Tempting, but not our job
}
void MSG_UrlQueueElement::PrepareToRun()
{
// nothing we have to do right now for queue elements.
return;
}
char* MSG_UrlQueueElement::GetURLString()
{
if (m_urlString)
return m_urlString;
if (m_url)
return(m_url->address);
return(NULL);
}
URL_Struct* MSG_UrlQueueElement::GetURLStruct()
{
if (!m_url)
m_url = NET_CreateURLStruct( m_urlString, NET_DONT_RELOAD);
return(m_url);
}
MSG_UrlLocalMsgCopyQueueElement::MSG_UrlLocalMsgCopyQueueElement(MessageCopyInfo * info, const char * url, MSG_UrlQueue * q,
Net_GetUrlExitFunc * func, MSG_Pane * pane, NET_ReloadMethod reloadMethod)
: MSG_UrlQueueElement (url, q, func, pane, reloadMethod)
{
m_copyInfo = info;
}
MSG_UrlLocalMsgCopyQueueElement::MSG_UrlLocalMsgCopyQueueElement(MessageCopyInfo * info, URL_Struct * url, MSG_UrlQueue * q,
Net_GetUrlExitFunc * func, MSG_Pane * pane, XP_Bool skipFE)
: MSG_UrlQueueElement (url, q, func, pane, skipFE)
{
m_copyInfo = info;
}
MSG_UrlLocalMsgCopyQueueElement::MSG_UrlLocalMsgCopyQueueElement (MessageCopyInfo * info, URL_Struct * urls, MSG_UrlQueue * q)
: MSG_UrlQueueElement(urls, q)
{
m_copyInfo = info;
}
MSG_UrlLocalMsgCopyQueueElement::~MSG_UrlLocalMsgCopyQueueElement()
{
// should we delete the copy info? I don't think so!!
// when copy was finished, a call to MSG_FolderInfo::CleanUpCopy deletes
// the copy info in the current context. Assuming our queue element isn't deleted before
// it is executed upon......we don't need to delete it.
}
void MSG_UrlLocalMsgCopyQueueElement::PrepareToRun()
{
MWContext * context = m_pane->GetContext();
MessageCopyInfo * victim = NULL;
if (context)
{
victim = context->msgCopyInfo;
XP_ASSERT(!victim); // we actually should never have a victim....but if we do:
// the last copy info is done.
if (victim)
XP_FREEIF(victim); // local copies never have copy info chains, don't have to worry about nextCopyInfo
context->msgCopyInfo = m_copyInfo; // set ourselves up as the next copy info
}
}
//*****************************************************************************
// MSG_UrlQueue -- Intended to be a general purpose way to chain several
// URLs together using the exit functions
//*****************************************************************************
const int MSG_UrlQueue::kNoSpecialIndex = -1;
MSG_UrlQueue::MSG_UrlQueue (MSG_Pane *pane)
{
#ifdef DEBUG
MSG_UrlQueue *existingQueue = FindQueue(pane);
if (existingQueue)
{
MSG_UrlQueueElement *elem = existingQueue->GetAt (existingQueue->m_runningUrl);
if (elem)
XP_Trace("trying to create queue while %s is running\n", elem->m_urlString);
}
XP_ASSERT(!existingQueue);
#endif
m_pane = pane;
m_runningUrl = -1;
m_IndexOfNextUrl = kNoSpecialIndex;
m_inExitFunc = FALSE;
GetQueueArray()->Add (this);
}
MSG_UrlQueue::~MSG_UrlQueue ()
{
GetQueueArray()->Remove(this);
for (int i = 0; i < GetSize (); i++)
{
MSG_UrlQueueElement *e = GetAt(i);
delete e;
}
}
XPPtrArray *
MSG_UrlQueue::GetQueueArray()
{
if (!m_queueArray)
m_queueArray = new XPPtrArray();
return m_queueArray;
}
XP_Bool MSG_UrlQueue::IsIMAPLoadFolderUrlQueue()
{
return FALSE;
}
void MSG_UrlQueue::AddUrl (const char *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, NET_ReloadMethod reloadMethod)
{
MSG_UrlQueueElement *elem = NULL;
if (!pane)
pane = m_pane;
elem = new MSG_UrlQueueElement (url, this, exitFunction, pane, reloadMethod);
if (elem)
Add(elem);
}
void MSG_UrlQueue::AddUrl (URL_Struct *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, XP_Bool skipFE, FO_Present_Types outputFormat)
{
MSG_UrlQueueElement * elem = NULL;
if (!pane)
pane = m_pane;
elem = new MSG_UrlQueueElement(url, this, exitFunction, pane, skipFE, outputFormat);
if (elem)
Add(elem);
}
void MSG_UrlQueue::AddLocalMsgCopyUrl(MessageCopyInfo * info, const char *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane * pane, NET_ReloadMethod reloadMethod)
{
MSG_UrlLocalMsgCopyQueueElement *elem = NULL;
if (!pane)
pane = m_pane;
elem = new MSG_UrlLocalMsgCopyQueueElement (info, url, this, exitFunction, pane, reloadMethod);
if (elem)
Add(elem);
}
/* static */ MSG_UrlQueue * MSG_UrlQueue::FindQueueWithSameContext(MSG_Pane *pane)
{
MSG_UrlQueue * q = NULL;
XP_ASSERT(pane);
if (pane)
{
q = MSG_UrlQueue::FindQueue(pane);
MSG_Pane *QPane = pane->GetFirstPaneForContext(pane->GetContext());
while (!q && QPane)
{
q = MSG_UrlQueue::FindQueue(QPane);
if (!q)
QPane = pane->GetNextPaneForContext(QPane, pane->GetContext());
}
#ifdef DEBUG_bienvenu
if (q && QPane != pane)
XP_Trace("found queue for different pane with same context!\n");
#endif
}
return q;
}
/* static */ MSG_UrlQueue * MSG_UrlQueue::GetOrCreateUrlQueue (MSG_Pane * pane, XP_Bool * newQueue)
// The following code appeared in just about every AddUrl method or variant thereof. I've generalized it in this single
// routine.
// Returns: pointer to the queue for the pane. If we had to create the queue, then newQueue is set to TRUE;
{
*newQueue = FALSE;
MSG_UrlQueue *q = FindQueueWithSameContext(pane);
if (!q)
{
q = new MSG_UrlQueue(pane);
*newQueue = TRUE;
}
// we seem to get in this state where we're not running a url but the queue
// thinks we are.
if (! (q->m_inExitFunc || q->m_runningUrl == -1 || XP_IsContextBusy(pane->GetContext())))
{
#ifdef DEBUG
MSG_UrlQueueElement *runningElement = q->GetAt(q->m_runningUrl);
if (runningElement)
XP_Trace("q was running url %s\n", runningElement->GetURLString());
XP_ASSERT(FALSE);
#endif
}
return q;
}
/* static */ MSG_UrlQueue * MSG_UrlQueue::AddUrlToPane (const char *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, NET_ReloadMethod reloadMethod)
{
MSG_UrlQueue *q;
MSG_UrlQueueElement *elem = NULL;
XP_Bool newQ = FALSE;
q = GetOrCreateUrlQueue(pane, &newQ);
if (q)
{
elem = new MSG_UrlQueueElement (url, q, exitFunction, pane, reloadMethod);
if (elem)
q->Add(elem);
if (newQ)
q->GetNextUrl();
}
return q;
}
/* static*/ MSG_UrlQueue *MSG_UrlQueue::AddLocalMsgCopyUrlToPane (MessageCopyInfo * info, const char *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, NET_ReloadMethod reloadMethod)
{
MSG_UrlQueue *q;
MSG_UrlLocalMsgCopyQueueElement *elem = NULL;
XP_Bool newQ = FALSE;
q = GetOrCreateUrlQueue(pane, &newQ);
if (q)
{
elem = new MSG_UrlLocalMsgCopyQueueElement (info, url, q, exitFunction, pane, reloadMethod);
if (elem)
q->Add(elem);
if (newQ)
q->GetNextUrl();
}
return q;
}
/* static */ MSG_UrlQueue *MSG_UrlQueue::AddUrlToPane (URL_Struct *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, XP_Bool skipFE, FO_Present_Types outputFormat)
{
MSG_UrlQueue *q;
MSG_UrlQueueElement *elem = NULL;
XP_Bool newQ = FALSE;
q = GetOrCreateUrlQueue(pane, &newQ);
if (q)
{
elem = new MSG_UrlQueueElement (url, q, exitFunction, pane, skipFE, outputFormat);
if (elem)
q->Add(elem);
if (newQ)
q->GetNextUrl();
}
return q;
}
/* static */ MSG_UrlQueue *MSG_UrlQueue::AddLocalMsgCopyUrlToPane(MessageCopyInfo * info, URL_Struct * url, Net_GetUrlExitFunc * exitFunction, MSG_Pane * pane, XP_Bool skipFE)
{
MSG_UrlQueue *q;
MSG_UrlLocalMsgCopyQueueElement *elem = NULL;
XP_Bool newQ = FALSE;
q = GetOrCreateUrlQueue(pane, &newQ);
if (q)
{
elem = new MSG_UrlLocalMsgCopyQueueElement (info, url, q, exitFunction, pane, skipFE);
if (elem)
q->Add(elem);
if (newQ)
q->GetNextUrl();
}
return q;
}
void MSG_UrlQueue::AddUrlAt (int where, const char *url, Net_GetUrlExitFunc *exitFunction, MSG_Pane *pane, NET_ReloadMethod reloadMethod)
{
if (!pane)
pane = m_pane;
MSG_UrlQueueElement *elem = new MSG_UrlQueueElement (url, this, exitFunction, pane, reloadMethod);
if (elem)
InsertAt (where, elem);
}
void MSG_UrlQueue::AddLocalMsgCopyUrlAt (MessageCopyInfo * info, int where, const char * url, Net_GetUrlExitFunc * exitFunction, MSG_Pane * pane, NET_ReloadMethod reloadMethod)
{
if (!pane)
pane = m_pane;
MSG_UrlLocalMsgCopyQueueElement *elem = new MSG_UrlLocalMsgCopyQueueElement (info, url, this, exitFunction, pane, reloadMethod);
if (elem)
InsertAt (where, elem);
}
void MSG_UrlQueue::GetNextUrl()
{
int err = 0;
MSG_UrlQueueElement *elem = GetAt(++m_runningUrl);
XP_ASSERT(elem);
if (elem)
{
// we need to make sure the queue element is ready to be run!!!
elem->PrepareToRun();
if (!elem->m_url)
{
elem->m_url = NET_CreateURLStruct (elem->m_urlString, elem->m_reloadMethod);
if (!elem->m_url)
return; // (MsgERR) MK_OUT_OF_MEMORY;
}
if (elem->m_url && XP_STRLEN(elem->m_url->address) > 0)
{
elem->m_url->internal_url = TRUE;
elem->m_url->pre_exit_fn = &MSG_UrlQueue::ExitFunction;
if (elem->m_callGetURLDirectly)
{
elem->m_url->pre_exit_fn = NULL;
err = NET_GetURL(elem->m_url, elem->m_outputFormat, elem->m_pane->GetContext(), MSG_UrlQueue::ExitFunction);
} else
{
#ifdef MOZ_MAIL_NEWS
err = elem->m_pane->GetURL (elem->m_url, FALSE);
#else /* MOZ_MAIL_NEWS */
XP_ASSERT(0);
#endif /* MOZ_MAIL_NEWS */
}
}
else
{
elem->m_url->msg_pane = m_pane;
CallExitAndChain(elem->m_url, 0, elem->m_pane->GetContext());
}
}
}
void MSG_UrlQueue::HandleUrlQueueInterrupt(URL_Struct * URL_s, int status, MWContext * window_id)
{
for (int i = 0; i < m_interruptCallbacks.GetSize(); i++)
{
MSG_UrlQueueInterruptFunc *exitFunc = (MSG_UrlQueueInterruptFunc *) m_interruptCallbacks.GetAt(i);
if (exitFunc)
(*exitFunc) (this, URL_s, status, window_id);
}
// default is to do nothing
}
/*static*/ XPPtrArray *MSG_UrlQueue::m_queueArray = NULL;
/*static*/ MSG_UrlQueue *MSG_UrlQueue::FindQueue (const char *url, MWContext *context)
{
for (int i = 0; i < GetQueueArray()->GetSize(); i++)
{
MSG_UrlQueue *queue = (MSG_UrlQueue*)(GetQueueArray()->GetAt(i));
for (int j = 0; j < queue->GetSize(); j++)
{
MSG_UrlQueueElement *elem = queue->GetAt(j);
// pane has been deleted - remove element from queue
if (!MSG_Pane::PaneInMasterList(elem->m_pane))
{
#ifdef DEBUG_akkana
printf("FindQueue: Removing deleted pane\n");
#endif /* DEBUG */
queue->RemoveAt(j--);
delete elem;
}
else if (elem->m_pane->GetContext() == context)
{
if (elem->m_urlString && !XP_STRCMP(elem->m_urlString, url))
return queue;
}
}
}
return NULL;
}
/*static*/ MSG_UrlQueue *MSG_UrlQueue::FindQueue (MSG_Pane *pane)
{
for (int i = 0; i < GetQueueArray()->GetSize (); i++)
{
MSG_UrlQueue *queue = (MSG_UrlQueue*)(GetQueueArray()->GetAt(i));
if (queue->m_pane == pane)
return queue;
}
return NULL;
}
/*static*/ void MSG_UrlQueue::ExitFunction (URL_Struct *URL_s, int status, MWContext *window_id)
{
MSG_UrlQueue *queue = FindQueue (URL_s->address, window_id);
XP_ASSERT(queue);
if (queue)
queue->CallExitAndChain(URL_s, status, window_id);
}
// Note that this can delete itself if at the end of its list.
void MSG_UrlQueue::CallExitAndChain(URL_Struct *URL_s, int status, MWContext *window_id)
{
MSG_UrlQueueElement *elem = GetAt (m_runningUrl);
if (elem->m_exitFunction)
{
m_inExitFunc = TRUE;
elem->m_exitFunction (URL_s, status, window_id);
m_inExitFunc = FALSE;
}
if ((m_runningUrl >= GetSize() - 1) || status == MK_INTERRUPTED)
{
if (status == MK_INTERRUPTED)
HandleUrlQueueInterrupt(URL_s, status, window_id);
delete this;
}
else
GetNextUrl();
}
extern "C" int MSG_GetUrlQueueSize (const char *url, MWContext *context)
{
MSG_UrlQueue *queue = MSG_UrlQueue::FindQueue (url, context);
if (queue)
return queue->GetSize();
return 0;
}
void MSG_UrlQueue::AddInterruptCallback(MSG_UrlQueueInterruptFunc *interruptFunc)
{
m_interruptCallbacks.Add((void *) interruptFunc);
}

View File

@@ -0,0 +1,206 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
//
//
//
#ifndef _MSGURLQ_H_
#define _MSGURLQ_H_
#include "ptrarray.h"
#include "net.h"
class MSG_Pane;
class ABook;
class MSG_UrlQueue;
/********************************************************************************************************************
Notes: Each URL in a MSG_UrlQueue is represented by a queue element for any instance data it
needs. Since a pane can have one and only one URL queue, it would be nice to be able to have queue elements
for different types of URLs (local copy message urls, LDAP to AB, etc.) To support this effort, it will be common
practice to subclass MSG_UrlQueueElement with a queue element capable of handling your new type of url. In addition,
your new subclass should support a virtual method called PrepareToRun() if you need to make any specific changes to
things like the current context for your new url before it is run. MSG_UrlQueue will always call the element's
PrepareToRun method before actually running that URL in the queue. You will also need to modify MSG_UrlQueue to
add methods for adding urls of your new type.
*********************************************************************************************************************/
//*****************************************************************************
// MSG_UrlQueueElement -- Each URL in a MSG_UrlQueue is represented by a
// MSG_UrlQueueElement for any instance data it needs
//*****************************************************************************
class MSG_UrlQueueElement
{
friend MSG_UrlQueue;
public:
MSG_UrlQueueElement (const char *, MSG_UrlQueue *, Net_GetUrlExitFunc *, MSG_Pane *, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD, FO_Present_Types outputFormat = FO_CACHE_AND_PRESENT);
MSG_UrlQueueElement (URL_Struct *, MSG_UrlQueue *, Net_GetUrlExitFunc *, MSG_Pane *, XP_Bool skipFE = FALSE, FO_Present_Types outputFormat = FO_CACHE_AND_PRESENT);
MSG_UrlQueueElement (URL_Struct * urls, MSG_UrlQueue *q);
virtual ~MSG_UrlQueueElement ();
virtual URL_Struct* GetURLStruct();
virtual char* GetURLString();
virtual void PrepareToRun(); // the queue element is about to be run....(added in particular for subclasses)
protected:
char *m_urlString;
XP_Bool m_callGetURLDirectly;
MSG_Pane *m_pane;
URL_Struct *m_url;
MSG_UrlQueue *m_queue;
Net_GetUrlExitFunc *m_exitFunction;
NET_ReloadMethod m_reloadMethod;
FO_Present_Types m_outputFormat;
};
//************************************************************************************
// MSG_UrlLocalMsgCopyQueueElement - we want a queue element type which can handle
// LOCAL message copy urls. Don't try this with IMAP
// copy URLs.
//************************************************************************************
class MSG_UrlLocalMsgCopyQueueElement : public MSG_UrlQueueElement
{
public:
MSG_UrlLocalMsgCopyQueueElement (MessageCopyInfo *, const char *, MSG_UrlQueue *, Net_GetUrlExitFunc *,
MSG_Pane *, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
MSG_UrlLocalMsgCopyQueueElement (MessageCopyInfo *, URL_Struct *, MSG_UrlQueue *, Net_GetUrlExitFunc *,
MSG_Pane *, XP_Bool skipFE = FALSE);
MSG_UrlLocalMsgCopyQueueElement (MessageCopyInfo *, URL_Struct * urls, MSG_UrlQueue * q);
virtual ~MSG_UrlLocalMsgCopyQueueElement();
virtual void PrepareToRun(); // element is about to be run, we need to clobber context's copy info and replace with ours
protected:
MessageCopyInfo * m_copyInfo;
};
//******************************************************************************************************
// MSG_UrlQueue -- Handles a queue of URLs which get fired in serial. This is
// a stopgap measure to compensate for the lack of multiple running
// URLs per MWContext
//
// Note: Must always call the queue element's PrepareToRun method before running a URL for that element.
//*******************************************************************************************************
typedef void MSG_UrlQueueInterruptFunc (MSG_UrlQueue *queue, URL_Struct *URL_s, int status, MWContext *window_id);
class MSG_UrlQueue : public XPPtrArray
{
public:
MSG_UrlQueue (MSG_Pane *pane);
virtual ~MSG_UrlQueue ();
// it would be nice to use signature overloading for adding urls. Later, we might want to do this!!!
// Use this for regular add-to-tail functionality
static MSG_UrlQueue *AddUrlToPane (const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
static MSG_UrlQueue * AddLocalMsgCopyUrlToPane (MessageCopyInfo * info, const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
// Use this for regular add-to-tail functionality with URL_Struct filled in
static MSG_UrlQueue * AddUrlToPane (URL_Struct *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, XP_Bool skipFE = FALSE, FO_Present_Types outputFormat = FO_CACHE_AND_PRESENT);
static MSG_UrlQueue * AddLocalMsgCopyUrlToPane (MessageCopyInfo * info, URL_Struct * url, Net_GetUrlExitFunc * exitFunction = NULL, MSG_Pane * pane = NULL, XP_Bool skipFE = FALSE);
void AddUrl (const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
void AddUrl(URL_Struct *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, XP_Bool skipFE = FALSE, FO_Present_Types outputFormat = FO_CACHE_AND_PRESENT);
void AddLocalMsgCopyUrl(MessageCopyInfo * info, const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane * pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
// Use this if you need to insert a URL in the middle of the queue
virtual void AddUrlAt (int where, const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
virtual void AddLocalMsgCopyUrlAt (MessageCopyInfo * info, int where, const char * url, Net_GetUrlExitFunc * exitFunction = NULL, MSG_Pane * pane = NULL, NET_ReloadMethod reloadmethod = NET_DONT_RELOAD);
// Use this if you need to know which URL is running
virtual int GetCursor () { return m_runningUrl; }
// start the queue by calling this
virtual void GetNextUrl ();
// which pane is this queue running url's in?
virtual MSG_Pane* GetPane() { return m_pane; }
// Use this if you need to know which queue a URL is on
static MSG_UrlQueue *FindQueue (const char *url, MWContext *context);
static MSG_UrlQueue *FindQueue (MSG_Pane *pane);
static MSG_UrlQueue *FindQueueWithSameContext(MSG_Pane *pane);
// Use this if you need to know the queue for a pane
static MSG_UrlQueue *FindQueue (const char *url, MSG_Pane *pane);
// used by subclasses who are designed to use other meta data for ordering urls.
// an example is MSG_ImapLoadFolderUrlQueue
static const int kNoSpecialIndex;
void SetSpecialIndexOfNextUrl(int index) { m_IndexOfNextUrl = index; }
virtual XP_Bool IsIMAPLoadFolderUrlQueue();
static void HandleFolderLoadInterrupt(MSG_UrlQueue *queue, URL_Struct *URL_s, int status, MWContext *window_id);
virtual void AddInterruptCallback(MSG_UrlQueueInterruptFunc *interruptFunc);
protected:
MSG_UrlQueueElement *GetAt(int i) { return (MSG_UrlQueueElement*) XPPtrArray::GetAt(i); }
// called if ExitFunction status == MK_INTERRUPTED
virtual void HandleUrlQueueInterrupt(URL_Struct *URL_s, int status, MWContext *window_id);
static void ExitFunction (URL_Struct *URL_s, int status, MWContext *window_id);
void CallExitAndChain (URL_Struct *URL_s, int status, MWContext *window_id);
static MSG_UrlQueue * GetOrCreateUrlQueue (MSG_Pane * pane, XP_Bool * newQueue);
int m_runningUrl;
MSG_Pane *m_pane;
static XPPtrArray *m_queueArray;
int m_IndexOfNextUrl;
XP_Bool m_inExitFunc;
XPPtrArray m_interruptCallbacks;
static XPPtrArray *GetQueueArray();
};
class MSG_AddLdapToAddressBookQueue : public MSG_UrlQueue
{
public:
MSG_AddLdapToAddressBookQueue (MSG_Pane *);
virtual void GetNextUrl ();
ABook *m_addressBook;
};
class MSG_ImapLoadFolderUrlQueue : public MSG_UrlQueue
{
public:
MSG_ImapLoadFolderUrlQueue(MSG_Pane *pane);
// Use this for regular add-to-tail functionality, or use the index of it has been set.
// Used to ensure ordering of message copy urls when going offline
virtual void AddUrl (const char *url, Net_GetUrlExitFunc *exitFunction = NULL, MSG_Pane *pane = NULL, NET_ReloadMethod reloadMethod = NET_DONT_RELOAD);
virtual XP_Bool IsIMAPLoadFolderUrlQueue();
protected:
// called if ExitFunction status == MK_INTERRUPTED
// virtual void HandleUrlQueueInterrupt(URL_Struct *URL_s, int status, MWContext *window_id);
};
#endif

View File

@@ -0,0 +1,852 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* msgutils.c --- various and sundry
*/
#include "msg.h"
#include "xp_time.h"
#include "xpgetstr.h"
#include "xplocale.h"
#include "htmldlgs.h"
#include "prefapi.h"
#include "xp_qsort.h"
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_NON_MAIL_FILE_WRITE_QUESTION;
extern int MK_MSG_HTML_DOMAINS_DIALOG;
extern int MK_MSG_HTML_DOMAINS_DIALOG_TITLE;
#ifdef XP_MAC
#pragma warn_unusedarg off
#endif
int
msg_GetURL(MWContext* context, URL_Struct* url, XP_Bool issafe)
{
XP_ASSERT(context);
/* phil & bienvenu think issafe means "allowed to start another URL even if
one is already runing". e.g. delete from msgPane, and load next msg */
if (!issafe)
msg_InterruptContext (context, TRUE);
url->internal_url = TRUE;
if (!url->open_new_window_specified)
{
url->open_new_window_specified = TRUE;
url->open_new_window = FALSE;
}
return FE_GetURL(context, url);
}
void
msg_InterruptContext(MWContext* context, XP_Bool safetoo)
{
XP_InterruptContext(context);
#ifdef NOTDEF /* ###tw */
struct MSG_Frame *msg_frame;
if (!context) return;
if (safetoo || !context->msgframe ||
!context->msgframe->safe_background_activity) {
/* save msg_frame in case context gets deleted on interruption */
msg_frame = context->msgframe;
XP_InterruptContext(context);
if (msg_frame) {
msg_frame->safe_background_activity = FALSE;
}
}
#endif
}
XP_Bool
MSG_RequiresComposeWindow (const char *url)
{
if (!url) return FALSE;
if (!strncasecomp (url, "mailto:", 7))
{
return TRUE;
}
return FALSE;
}
XP_Bool
MSG_RequiresBrowserWindow (const char *url)
{
if (!url) return FALSE;
if (MSG_RequiresNewsWindow (url) ||
MSG_RequiresMailWindow (url) ||
!strncasecomp (url, "about:", 6) ||
!strncasecomp (url, "addbook:", 8) ||
!strncasecomp (url, "addbook-ldap", 12) || /* no colon so addbook-ldap and addbook-ldaps both match */
!strncasecomp (url, "mailto:", 7) ||
!strncasecomp (url, "view-source:", 12) ||
!strncasecomp (url, "internal-callback-handler:", 26) ||
!strncasecomp (url, "internal-panel-handler", 22) ||
!strncasecomp (url, "internal-dialog-handler", 23))
return FALSE;
else if (!strncasecomp (url, "news:", 5) ||
!strncasecomp (url, "snews:", 6) ||
!strncasecomp (url, "mailbox:", 8) ||
!strncasecomp (url, "IMAP:", 5))
{
/* Mail and news messages themselves don't require browser windows,
but their attachments do. */
if (XP_STRSTR(url, "?part=") || XP_STRSTR(url, "&part="))
return TRUE;
else
return FALSE;
}
else
return TRUE;
}
/* If we're in a mail window, and clicking on a link which will itself
require a mail window, then don't allow this to show up in a different
window - since there can only be one mail window.
*/
XP_Bool
MSG_NewWindowProhibited (MWContext *context, const char *url)
{
if (!context) return FALSE;
if ((context->type == MWContextMail &&
MSG_RequiresMailWindow (url)) ||
(context->type == MWContextNews &&
MSG_RequiresNewsWindow (url)) ||
(MSG_RequiresComposeWindow (url)))
return TRUE;
else
return FALSE;
}
char *
MSG_ConvertToQuotation (const char *string)
{
int32 column = 0;
int32 newlines = 0;
int32 chars = 0;
const char *in;
char *out;
char *new_string;
if (! string) return 0;
/* First, count up the lines in the string. */
for (in = string; *in; in++)
{
chars++;
if (*in == CR || *in == LF)
{
if (in[0] == CR && in[1] == LF) {
in++;
chars++;
}
newlines++;
column = 0;
}
else
{
column++;
}
}
/* If the last line doesn't end in a newline, pretend it does. */
if (column != 0)
newlines++;
/* 2 characters for each '> ', +1 for '\0', and + potential linebreak */
new_string = (char *) XP_ALLOC (chars + (newlines * 2) + 1 + LINEBREAK_LEN);
if (! new_string)
return 0;
column = 0;
out = new_string;
/* Now copy. */
for (in = string; *in; in++)
{
if (column == 0)
{
*out++ = '>';
*out++ = ' ';
}
*out++ = *in;
if (*in == CR || *in == LF)
{
if (in[0] == CR && in[1] == LF)
*out++ = *++in;
newlines++;
column = 0;
}
else
{
column++;
}
}
/* If the last line doesn't end in a newline, add one. */
if (column != 0)
{
XP_STRCPY (out, LINEBREAK);
out += LINEBREAK_LEN;
}
*out = 0;
return new_string;
}
/* Given a string and a length, removes any "Re:" strings from the front.
It also deals with that "Re[2]:" thing that some mailers do.
Returns TRUE if it made a change, FALSE otherwise.
The string is not altered: the pointer to its head is merely advanced,
and the length correspondingly decreased.
*/
XP_Bool
msg_StripRE(const char **stringP, uint32 *lengthP)
{
const char *s, *s_end;
const char *last;
uint32 L;
XP_Bool result = FALSE;
XP_ASSERT(stringP);
if (!stringP) return FALSE;
s = *stringP;
L = lengthP ? *lengthP : XP_STRLEN(s);
s_end = s + L;
last = s;
AGAIN:
while (s < s_end && XP_IS_SPACE(*s))
s++;
if (s < (s_end-2) &&
(s[0] == 'r' || s[0] == 'R') &&
(s[1] == 'e' || s[1] == 'E'))
{
if (s[2] == ':')
{
s = s+3; /* Skip over "Re:" */
result = TRUE; /* Yes, we stripped it. */
goto AGAIN; /* Skip whitespace and try again. */
}
else if (s[2] == '[' || s[2] == '(')
{
const char *s2 = s+3; /* Skip over "Re[" */
/* Skip forward over digits after the "[". */
while (s2 < (s_end-2) && XP_IS_DIGIT(*s2))
s2++;
/* Now ensure that the following thing is "]:"
Only if it is do we alter `s'.
*/
if ((s2[0] == ']' || s2[0] == ')') && s2[1] == ':')
{
s = s2+2; /* Skip over "]:" */
result = TRUE; /* Yes, we stripped it. */
goto AGAIN; /* Skip whitespace and try again. */
}
}
}
/* Decrease length by difference between current ptr and original ptr.
Then store the current ptr back into the caller. */
if (lengthP) *lengthP -= (s - (*stringP));
*stringP = s;
return result;
}
char*
msg_GetDummyEnvelope(void)
{
static char result[75];
char *ct;
time_t now = time ((time_t *) 0);
#if defined (XP_WIN)
if (now < 0 || now > 0x7FFFFFFF)
now = 0x7FFFFFFF;
#endif
ct = ctime(&now);
XP_ASSERT(ct[24] == CR || ct[24] == LF);
ct[24] = 0;
/* This value must be in ctime() format, with English abbreviations.
strftime("... %c ...") is no good, because it is localized. */
XP_STRCPY(result, "From - ");
XP_STRCPY(result + 7, ct);
XP_STRCPY(result + 7 + 24, LINEBREAK);
return result;
}
/* #define STRICT_ENVELOPE */
XP_Bool
msg_IsEnvelopeLine(const char *buf, int32 buf_size)
{
#ifdef STRICT_ENVELOPE
/* The required format is
From jwz Fri Jul 1 09:13:09 1994
But we should also allow at least:
From jwz Fri, Jul 01 09:13:09 1994
From jwz Fri Jul 1 09:13:09 1994 PST
From jwz Fri Jul 1 09:13:09 1994 (+0700)
We can't easily call XP_ParseTimeString() because the string is not
null terminated (ok, we could copy it after a quick check...) but
XP_ParseTimeString() may be too lenient for our purposes.
DANGER!! The released version of 2.0b1 was (on some systems,
some Unix, some NT, possibly others) writing out envelope lines
like "From - 10/13/95 11:22:33" which STRICT_ENVELOPE will reject!
*/
const char *date, *end;
if (buf_size < 29) return FALSE;
if (*buf != 'F') return FALSE;
if (XP_STRNCMP(buf, "From ", 5)) return FALSE;
end = buf + buf_size;
date = buf + 5;
/* Skip horizontal whitespace between "From " and user name. */
while ((*date == ' ' || *date == '\t') && date < end)
date++;
/* If at the end, it doesn't match. */
if (XP_IS_SPACE(*date) || date == end)
return FALSE;
/* Skip over user name. */
while (!XP_IS_SPACE(*date) && date < end)
date++;
/* Skip horizontal whitespace between user name and date. */
while ((*date == ' ' || *date == '\t') && date < end)
date++;
/* Don't want this to be localized. */
# define TMP_ISALPHA(x) (((x) >= 'A' && (x) <= 'Z') || \
((x) >= 'a' && (x) <= 'z'))
/* take off day-of-the-week. */
if (date >= end - 3)
return FALSE;
if (!TMP_ISALPHA(date[0]) || !TMP_ISALPHA(date[1]) || !TMP_ISALPHA(date[2]))
return FALSE;
date += 3;
/* Skip horizontal whitespace (and commas) between dotw and month. */
if (*date != ' ' && *date != '\t' && *date != ',')
return FALSE;
while ((*date == ' ' || *date == '\t' || *date == ',') && date < end)
date++;
/* take off month. */
if (date >= end - 3)
return FALSE;
if (!TMP_ISALPHA(date[0]) || !TMP_ISALPHA(date[1]) || !TMP_ISALPHA(date[2]))
return FALSE;
date += 3;
/* Skip horizontal whitespace between month and dotm. */
if (date == end || (*date != ' ' && *date != '\t'))
return FALSE;
while ((*date == ' ' || *date == '\t') && date < end)
date++;
/* Skip over digits and whitespace. */
while (((*date >= '0' && *date <= '9') || *date == ' ' || *date == '\t') &&
date < end)
date++;
/* Next character should be a colon. */
if (date >= end || *date != ':')
return FALSE;
/* Ok, that ought to be enough... */
# undef TMP_ISALPHA
#else /* !STRICT_ENVELOPE */
if (buf_size < 5) return FALSE;
if (*buf != 'F') return FALSE;
if (XP_STRNCMP(buf, "From ", 5)) return FALSE;
#endif /* !STRICT_ENVELOPE */
return TRUE;
}
XP_Bool
msg_ConfirmMailFile (MWContext *context, const char *file_name)
{
XP_File in = XP_FileOpen (file_name, xpMailFolder, XP_FILE_READ_BIN);
char buf[100];
char *s = buf;
int L;
if (!in) return TRUE;
L = XP_FileRead(buf, sizeof(buf)-2, in);
XP_FileClose (in);
if (L < 1) return TRUE;
buf[L] = 0;
while (XP_IS_SPACE(*s))
s++, L--;
if (L > 5 && msg_IsEnvelopeLine(s, L))
return TRUE;
PR_snprintf (buf, sizeof(buf),
XP_GetString (MK_MSG_NON_MAIL_FILE_WRITE_QUESTION), file_name);
return FE_Confirm (context, buf);
}
void msg_ClearMessageArea(MWContext* context)
{
/* ###tw This needs to be replaced by stuff that notifies FE's the
right way */
#ifndef _USRDLL
/* hack. Open a stream to layout, give it
whitespace (it needs something) and then close it
right away. This has the effect of getting the front end to
clear out the HTML display area.
*/
NET_StreamClass *stream;
static PA_InitData data;
URL_Struct *url;
if (!context)
return;
data.output_func = LO_ProcessTag;
url = NET_CreateURLStruct ("", NET_NORMAL_RELOAD);
if (!url) return;
stream = PA_BeginParseMDL (FO_PRESENT, &data, url, context);
if (stream)
{
char buf[] = "<BODY></BODY>";
int status = (*stream->put_block) (stream, buf, 13);
if (status < 0)
(*stream->abort) (stream, status);
else
(*stream->complete) (stream);
XP_FREE (stream);
}
NET_FreeURLStruct (url);
FE_SetProgressBarPercent (context, 0);
#endif
/* MSG_LoadMessage, with MSG_MESSAGEKEYNONE calls msg_ClearMessageArea, which
// has a bug (drawing the background in grey).  So I just changed MSG_LoadMessage() to
// do nothing for XP_MAC except set its m_Key to MSG_MESSAGEKEYNONE and exit.  This transfers
// the responsibility for clearing the message area to the front end.  So far, so good.
//
// Now, it's no good just painting the area, because the next refresh will redraw using the
// existing history entry.  So somehow we have to remove the history entry.
// There's no API for doing this, except calling SHIST_AddDocument with an entry whose
// address string is null or empty.
//
// If this state of affairs changes, this code will break, but I put in asserts to
// notify us about it. 98/01/21
// ---------------------------------------------------------------------------
*/
#if 0
/* It would be nice to do it this way, but we need to cause a refresh in the fe */
URL_Struct* url = NET_CreateURLStruct("", NET_NORMAL_RELOAD);
History_entry* newEntry;
LO_DiscardDocument(context);
XP_ASSERT(url);
newEntry = SHIST_CreateHistoryEntry(url, "Nobody Home");
XP_FREEIF(url);
XP_ASSERT(newEntry);
/* Using an empty address string will cause "AddDocument" to do a removal of the old entry,
 // then delete the new entry, and exit.
*/
SHIST_AddDocument(context, newEntry);
#endif
}
static MSG_HEADER_SET standard_header_set[] = {
MSG_TO_HEADER_MASK,
MSG_REPLY_TO_HEADER_MASK,
MSG_CC_HEADER_MASK,
MSG_BCC_HEADER_MASK,
MSG_NEWSGROUPS_HEADER_MASK,
MSG_FOLLOWUP_TO_HEADER_MASK
};
#define TOTAL_HEADERS (sizeof(standard_header_set)/sizeof(MSG_HEADER_SET))
extern int MSG_ExplodeHeaderField(MSG_HEADER_SET msg_header, const char * field, MSG_HeaderEntry ** return_list)
{
XP_ASSERT(return_list);
*return_list = NULL;
if (field && strlen(field)) {
MSG_HeaderEntry *list=NULL;
char * name;
char * address ;
int count;
count = MSG_ParseRFC822Addresses (field, &name, &address);
if (count > 0) {
char * address_start = address;
char * name_start = name;
int i;
list = (MSG_HeaderEntry*)XP_ALLOC(sizeof(MSG_HeaderEntry)*count);
if (!list)
return(-1);
for (i=0; i<count; i++) {
list[i].header_type = msg_header;
list[i].header_value = XP_STRDUP(address);
if (name && strlen(name))
list[i].header_value = PR_smprintf("%s <%s>", name, address);
else
list[i].header_value = XP_STRDUP(address);
while (*address != '\0')
address++;
address++;
while (*name != '\0')
name++;
name++;
}
if (name)
XP_FREE(name_start);
if (address)
XP_FREE(address_start);
}
*return_list = list;
return count;
}
return(0);
}
extern int MSG_CompressHeaderEntries( MSG_HeaderEntry * in_list, int list_size, MSG_HeaderEntry ** return_list)
{
int total = 0;
*return_list = NULL;
if (in_list != NULL && list_size > 0) {
MSG_HeaderEntry * list = NULL;
char * new_header_value;
int i,j;
for (i=0; i<TOTAL_HEADERS; i++) {
new_header_value = NULL;
for (j=0; j<list_size; j++) {
if (in_list[j].header_type == standard_header_set[i]) {
XP_Bool zero_init = FALSE;
int header_length = 0;
if (!new_header_value)
zero_init = TRUE;
else
header_length = XP_STRLEN(new_header_value)+1;
if (XP_STRLEN(in_list[j].header_value) == 0)
continue;
new_header_value = (char*)XP_REALLOC(
new_header_value,
header_length+XP_STRLEN(in_list[j].header_value)+XP_STRLEN(",")+1);
if (new_header_value == NULL) {
if (list != NULL)
XP_FREE(list);
/* don't forget to free up previous header_value entries */
return(-1);
}
if (zero_init)
new_header_value[0]='\0';
if (new_header_value && XP_STRLEN(new_header_value))
XP_STRCAT(new_header_value,",");
XP_STRCAT(new_header_value,in_list[j].header_value);
}
}
if (new_header_value) {
total++;
list = (MSG_HeaderEntry *)XP_REALLOC(list,total*sizeof(MSG_HeaderEntry));
if (list==NULL) {
if (new_header_value)
XP_FREE(new_header_value);
return(-1);
}
list[total-1].header_type = standard_header_set[i];
list[total-1].header_value = new_header_value;
}
}
*return_list = list;
}
return(total);
}
static int
msg_qsort_domains(const void* a, const void* b)
{
return XP_STRCMP(*((const char**) a), *((const char**) b));
}
static int
msg_generate_domains_list(char* domainlist, int* numfound, char*** returnlist)
{
int num;
int i;
int j;
char* ptr;
char* endptr;
char** list = NULL;
for (num=0 , ptr = domainlist ; ptr ; num++, ptr = endptr) {
endptr = XP_STRCHR(ptr, ',');
if (endptr) endptr++;
}
if (num > 0) {
list = (char**) XP_CALLOC(num, sizeof(char*));
if (!list) return MK_OUT_OF_MEMORY;
for (i=0 , ptr = domainlist ; ptr ; i++, ptr = endptr) {
endptr = XP_STRCHR(ptr, ',');
if (endptr) *endptr++ = '\0';
XP_ASSERT(i < num);
if (i < num) list[i] = ptr;
}
XP_QSORT(list, num, sizeof(char*), msg_qsort_domains);
/* Now, remove any empty entries or duplicates. */
for (i=0, j=0 ; i<num ; i++) {
ptr = list[i];
if (ptr && (j == 0 || XP_STRCMP(ptr, list[j - 1]) != 0)) {
list[j++] = ptr;
}
}
num = j;
}
*numfound = num;
*returnlist = list;
return 0;
}
static PRBool
HTMLDomainsDialogDone(XPDialogState* state, char** argv, int argc,
unsigned int button)
{
char* domainlist = NULL;
char* gone;
char* ptr;
char* endptr;
char** list = NULL;
int num;
int i;
int status;
if (button != XP_DIALOG_OK_BUTTON) return PR_FALSE;
PREF_CopyCharPref("mail.htmldomains", &domainlist);
if (!domainlist || !*domainlist) return PR_FALSE;
gone = XP_FindValueInArgs("gone", argv, argc);
XP_ASSERT(gone);
if (!gone || !*gone) return PR_FALSE;
status = msg_generate_domains_list(domainlist, &num, &list);
if (status < 0) goto FAIL;
for (ptr = gone ; ptr ; ptr = endptr) {
endptr = XP_STRCHR(ptr, ',');
if (endptr) *endptr++ = '\0';
if (*ptr) {
i = atoi(ptr);
XP_ASSERT(i >= 0 && i < num);
if (i >= 0 && i < num) {
XP_ASSERT(list[i]);
list[i] = NULL;
}
}
}
ptr = NULL;
for (i=0 ; i<num ; i++) {
if (list[i]) {
if (ptr) StrAllocCat(ptr, ",");
StrAllocCat(ptr, list[i]);
}
}
PREF_SetCharPref("mail.htmldomains", ptr ? ptr : "");
PREF_SavePrefFile();
FREEIF(ptr);
FAIL:
FREEIF(list);
FREEIF(domainlist);
return PR_FALSE;
}
int
MSG_DisplayHTMLDomainsDialog(MWContext* context)
{
static XPDialogInfo dialogInfo = {
XP_DIALOG_OK_BUTTON | XP_DIALOG_CANCEL_BUTTON,
HTMLDomainsDialogDone,
600,
440
};
int status = 0;
char* domainlist;
char* list = NULL;
char* tmp;
XPDialogStrings* strings;
int i;
int num = 0;
char** array = NULL;
PREF_CopyCharPref("mail.htmldomains", &domainlist);
status = msg_generate_domains_list(domainlist, &num, &array);
if (status < 0) goto FAIL;
for (i=0 ; i<num ; i++) {
tmp = PR_smprintf("<option value=%d>%s\n", i, array[i]);
if (!tmp) {
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
StrAllocCat(list, tmp);
XP_FREE(tmp);
}
strings = XP_GetDialogStrings(MK_MSG_HTML_DOMAINS_DIALOG);
if (!strings) {
status = MK_OUT_OF_MEMORY;
goto FAIL;
}
XP_CopyDialogString(strings, 0, list ? list : "");
XP_MakeHTMLDialog(context, &dialogInfo, MK_MSG_HTML_DOMAINS_DIALOG_TITLE,
strings, NULL,PR_FALSE);
FAIL:
FREEIF(array);
FREEIF(domainlist);
FREEIF(list);
return status;
}
/*
* Does in-place modification of input param to conform with son-of-1036 rules
*
* A newsgroup component is one portion of the newsgroup name, separated by
* dots. So mcom.dev.fouroh has three newsgroup components. This function is
* only concerned with one component because that's what we need for virtual
* newsgroups.
*/
void msg_MakeLegalNewsgroupComponent (char *name)
{
int i = 0;
char ch;
while ((ch = name[i]) != '\0')
{
/* legal chars are 0-9,a-z, and +,-,_ */
if (!(ch >= '0' && ch <= '9'))
if (!(ch >= 'a' && ch <= 'z'))
if (!(ch == '+' || ch == '-' || ch == '_'))
{
/* ch is illegal. We can lowercase an uppercase letter
* but everything else goes to some legal char, like '_'
*/
if (ch >= 'A' && ch <= 'Z')
name[i] += 32;
else
name[i] = '_';
}
i++;
/* a newsgroup component is limited to 14 chars */
if (i > 13)
{
name[i] = '\0';
break;
}
}
}
void MSG_SetPercentProgress(MWContext *context, int32 numerator, int32 denominator)
{
XP_ASSERT(numerator <= denominator && numerator >= 0 && denominator > 0);
if (numerator > denominator || numerator < 0 || denominator < 0)
{
FE_SetProgressBarPercent(context, -1);
}
else if (denominator > 0)
{
int32 percent;
if (denominator > 100L)
percent = (numerator / (denominator / 100L));
else
percent = (100L * numerator) / denominator;
FE_SetProgressBarPercent (context, percent);
}
}
const char* MSG_FormatDateFromContext(MWContext *context, time_t date)
{
/* fix i18n. Well, maybe. Isn't strftime() supposed to be i18n? */
/* ftong- Well.... strftime() in Mac and Window is not really i18n */
/* We need to use XP_StrfTime instead of strftime */
static char result[40]; /* 30 probably not enough */
time_t now = time ((time_t *) 0);
int32 offset = XP_LocalZoneOffset() * 60L; /* Number of seconds between
local and GMT. */
int32 secsperday = 24L * 60L * 60L;
int32 nowday = (now + offset) / secsperday;
int32 day = (date + offset) / secsperday;
if (day == nowday) {
XP_StrfTime(context, result, sizeof(result), XP_TIME_FORMAT,
localtime(&date));
} else if (day < nowday && day > nowday - 7) {
XP_StrfTime(context, result, sizeof(result), XP_WEEKDAY_TIME_FORMAT,
localtime(&date));
} else {
#if defined (XP_WIN)
if (date < 0 || date > 0x7FFFFFFF)
date = 0x7FFFFFFF;
#endif
XP_StrfTime(context, result, sizeof(result), XP_DATE_TIME_FORMAT,
localtime(&date));
}
return result;
}

View File

@@ -0,0 +1,84 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* msgutils.h --- various and sundry
*/
XP_BEGIN_PROTOS
/* Interface to FE_GetURL, which should never be called directly by anything
else in libmsg. The "issafe" argument is TRUE if this is a URL which we
consider very safe, and will never screw up or be screwed by any activity
going on in the foreground. Be very very sure of yourself before ever
passing TRUE to the "issafe" argument. */
extern int msg_GetURL(MWContext* context, URL_Struct* url, XP_Bool issafe);
/* Interface to XP_InterruptContext(), which should never be called directly
by anything else in libmsg. The "safetoo" argument is TRUE if we really
want to interrupt everything, even "safe" background streams. In most
cases, it should be False.*/
extern void msg_InterruptContext(MWContext* context, XP_Bool safetoo);
extern int msg_GrowBuffer (uint32 desired_size,
uint32 element_size, uint32 quantum,
char **buffer, uint32 *size);
extern int msg_LineBuffer (const char *net_buffer, int32 net_buffer_size,
char **bufferP, uint32 *buffer_sizeP,
uint32 *buffer_fpP,
XP_Bool convert_newlines_p,
int32 (*per_line_fn) (char *line, uint32
line_length, void *closure),
void *closure);
extern int msg_ReBuffer (const char *net_buffer, int32 net_buffer_size,
uint32 desired_buffer_size,
char **bufferP, uint32 *buffer_sizeP,
uint32 *buffer_fpP,
int32 (*per_buffer_fn) (char *buffer,
uint32 buffer_size,
void *closure),
void *closure);
extern NET_StreamClass *msg_MakeRebufferingStream (NET_StreamClass *next,
URL_Struct *url,
MWContext *context);
/* Given a string and a length, removes any "Re:" strings from the front.
(If the length is not given, then XP_STRLEN() is used on the string.)
It also deals with that "Re[2]:" thing that some mailers do.
Returns TRUE if it made a change, FALSE otherwise.
The string is not altered: the pointer to its head is merely advanced,
and the length correspondingly decreased.
*/
extern XP_Bool msg_StripRE(const char **stringP, uint32 *lengthP);
/*
* Does in-place modification of input param to conform with son-of-1036 rules
*/
extern void msg_MakeLegalNewsgroupComponent (char *name);
extern void MSG_SetPercentProgress(MWContext *context, int32 numerator, int32 denominator);
XP_END_PROTOS

View File

@@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "xp_mcom.h"
#include "msgzap.h"
#if defined(XP_OS2) && defined(__DEBUG_ALLOC__)
void* MSG_ZapIt::operator new(size_t size, const char *file, size_t line) {
void* rv = ::operator new(size, file, line);
if (rv) {
XP_MEMSET(rv, 0, size);
}
return rv;
}
#else
void* MSG_ZapIt::operator new(size_t size) {
void* rv = ::operator new(size);
if (rv) {
XP_MEMSET(rv, 0, size);
}
return rv;
}
#endif

View File

@@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MsgZap_H_
#define _MsgZap_H_
// The whole purpose of this class is to redefine operator new for any subclass
// so that it will automatically zero out the whole class for me; thanks.
class MSG_ZapIt {
public:
#if defined(XP_OS2) && defined(__DEBUG_ALLOC__)
static void* operator new(size_t size, const char *file, size_t line);
#else
static void* operator new(size_t size);
#endif
};
#endif /* _MsgZap_H_ */

View File

@@ -0,0 +1,525 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "msg.h"
#include "xp.h"
#include "ptrarray.h"
#include "xp_qsort.h"
#ifdef XP_WIN16
#define SIZE_T_MAX 0xFF80 // Maximum allocation size
#define MAX_ARR_ELEMS SIZE_T_MAX/sizeof(void *)
#endif
XPPtrArray::XPPtrArray()
{
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
XPPtrArray::~XPPtrArray()
{
SetSize(0);
}
/////////////////////////////////////////////////////////////////////////////
int XPPtrArray::GetSize() const
{
return m_nSize;
}
XP_Bool XPPtrArray::IsValidIndex(int32 nIndex)
{
return (nIndex < GetSize() && nIndex >= 0);
}
XP_Bool XPPtrArray::SetSize(int nSize)
{
XP_ASSERT(nSize >= 0);
#ifdef MAX_ARR_ELEMS
if (nSize > MAX_ARR_ELEMS);
{
XP_ASSERT(nSize <= MAX_ARR_ELEMS); // Will fail
return FALSE;
}
#endif
if (nSize == 0)
{
// Remove all elements
XP_FREE(m_pData);
m_nSize = 0;
m_nMaxSize = 0;
m_pData = NULL;
}
else if (m_pData == NULL)
{
// Create a new array
m_nMaxSize = MAX(8, nSize);
m_pData = (void **)XP_CALLOC(1, m_nMaxSize * sizeof(void *));
if (m_pData)
m_nSize = nSize;
else
m_nSize = m_nMaxSize = 0;
}
else if (nSize <= m_nMaxSize)
{
// The new size is within the current maximum size, make sure new
// elements are initialized to zero
if (nSize > m_nSize)
XP_MEMSET(&m_pData[m_nSize], 0, (nSize - m_nSize) * sizeof(void *));
m_nSize = nSize;
}
else
{
// The array needs to grow, figure out how much
int nGrowBy, nMaxSize;
nGrowBy = MIN(1024, MAX(8, m_nSize / 8));
nMaxSize = MAX(nSize, m_nMaxSize + nGrowBy);
#ifdef MAX_ARR_ELEMS
nMaxSize = MIN(MAX_ARR_ELEMS, nMaxSize);
#endif
void **pNewData = (void **)XP_ALLOC(nMaxSize * sizeof(void *));
if (pNewData)
{
// Copy the data from the old array to the new one
XP_MEMCPY(pNewData, m_pData, m_nSize * sizeof(void *));
// Zero out the remaining elements
XP_MEMSET(&pNewData[m_nSize], 0, (nSize - m_nSize) * sizeof(void *));
m_nSize = nSize;
m_nMaxSize = nMaxSize;
// Free the old array
XP_FREE(m_pData);
m_pData = pNewData;
}
}
return nSize == m_nSize;
}
/////////////////////////////////////////////////////////////////////////////
void*& XPPtrArray::ElementAt(int nIndex)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
int XPPtrArray::FindIndex (int nStartIndex, void *pToFind) const
{
for (int i = nStartIndex; i < GetSize(); i++)
if (m_pData[i] == pToFind)
return i;
return -1;
}
int XPPtrArray::FindIndexUsing(int nStartIndex, void* pToFind, XPCompareFunc* compare) const
{
for (int i = nStartIndex; i < GetSize(); i++)
if (compare(&m_pData[i], &pToFind) == 0)
return i;
return -1;
}
void *XPPtrArray::GetAt(int nIndex) const
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex];
}
void XPPtrArray::SetAt(int nIndex, void *newElement)
{
XP_ASSERT(nIndex >= 0 && nIndex < m_nSize);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
int XPPtrArray::Add(void *newElement)
{
int nIndex = m_nSize;
#ifdef MAX_ARR_ELEMS
if (nIndex >= MAX_ARR_ELEMS)
return -1;
#endif
SetAtGrow(nIndex, newElement);
return nIndex;
}
void XPPtrArray::InsertAt(int nIndex, void *newElement, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nCount > 0);
if (nIndex >= m_nSize)
{
// If the new element is after the end of the array, grow the array
SetSize(nIndex + nCount);
}
else
{
// The element is being insert inside the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount);
// Move the data after the insertion point
XP_MEMMOVE(&m_pData[nIndex + nCount], &m_pData[nIndex],
(nOldSize - nIndex) * sizeof(void *));
}
// Insert the new elements
XP_ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
void XPPtrArray::InsertAt(int nStartIndex, const XPPtrArray *pNewArray)
{
XP_ASSERT(nStartIndex >= 0);
XP_ASSERT(pNewArray != NULL);
if (pNewArray->GetSize() > 0)
{
InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
for (int i = 1; i < pNewArray->GetSize(); i++)
m_pData[nStartIndex + i] = pNewArray->GetAt(i);
}
}
XP_Bool XPPtrArray::Remove(void *pToRemove)
{
int index = FindIndex(0, pToRemove);
if (index != -1)
{
RemoveAt(index);
return TRUE;
}
else
return FALSE;
}
void XPPtrArray::RemoveAll()
{
SetSize(0);
}
void XPPtrArray::RemoveAt(int nIndex, int nCount)
{
XP_ASSERT(nIndex >= 0);
XP_ASSERT(nIndex + nCount <= m_nSize);
if (nCount > 0)
{
// Make sure not to overstep the end of the array
int nMoveCount = m_nSize - (nIndex + nCount);
if (nCount && nMoveCount)
XP_MEMMOVE(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(void*));
m_nSize -= nCount;
}
}
void XPPtrArray::RemoveAt(int nStartIndex, const XPPtrArray *pArray)
{
XP_ASSERT(nStartIndex >= 0);
XP_ASSERT(pArray != NULL);
for (int i = 0; i < pArray->GetSize(); i++)
{
int index = FindIndex(nStartIndex, pArray->GetAt(i));
if (index >= 0)
RemoveAt(index);
}
}
void XPPtrArray::SetAtGrow(int nIndex, void *newElement)
{
XP_ASSERT(nIndex >= 0);
if (nIndex >= m_nSize)
SetSize(nIndex+1);
m_pData[nIndex] = newElement;
}
/////////////////////////////////////////////////////////////////////////////
int XPPtrArray::InsertBinary(void *newElement, int ( *compare )(const void *elem1, const void *elem2))
{
int current = 0;
int left = 0;
int right = GetSize() - 1;
int comparison = 0;
while (left <= right)
{
current = (left + right) / 2;
void *pCurrent = GetAt(current);
comparison = compare(&pCurrent, &newElement);
if (comparison == 0)
break;
else if (comparison > 0)
right = current - 1;
else
left = current + 1;
}
if (comparison < 0)
current += 1;
XPPtrArray::InsertAt(current, newElement);
return current;
}
void XPPtrArray::QuickSort (int ( *compare )(const void *elem1, const void *elem2))
{
if (m_nSize > 1)
XP_QSORT (m_pData, m_nSize, sizeof(void*), compare);
}
/////////////////////////////////////////////////////////////////////////////
void *XPPtrArray::operator[](int nIndex) const
{
return GetAt(nIndex);
}
void *&XPPtrArray::operator[](int nIndex)
{
return ElementAt(nIndex);
}
/////////////////////////////////////////////////////////////////////////////
// XPSortedPtrArray
XPSortedPtrArray::XPSortedPtrArray(XPCompareFunc *compare)
:XPPtrArray()
{
m_CompareFunc = compare;
}
int XPSortedPtrArray::Add(void *newElement)
{
#ifdef MAX_ARR_ELEMS
if (m_nSize >= MAX_ARR_ELEMS)
return -1;
#endif
if (m_CompareFunc)
return InsertBinary(newElement, m_CompareFunc);
else
return XPPtrArray::Add (newElement);
}
int XPSortedPtrArray::FindIndex(int nStartIndex, void *pToFind) const
{
if (m_CompareFunc)
return FindIndexUsing(nStartIndex, pToFind, m_CompareFunc);
else
return XPPtrArray::FindIndex(nStartIndex, pToFind);
}
int XPSortedPtrArray::FindIndexUsing(int nStartIndex, void *pToFind, XPCompareFunc *compare) const
{
if (GetSize() == 0)
return -1;
if (!m_CompareFunc)
return TRUE;
int current = 0;
int left = nStartIndex;
int right = GetSize() - 1;
int comparison = 0;
while (left <= right)
{
current = (left + right) / 2;
void *pCurrent = GetAt(current);
comparison = compare(&pCurrent, &pToFind);
if (comparison == 0)
break;
else if (comparison > 0)
right = current - 1;
else
left = current + 1;
}
if (comparison != 0)
current = -1;
return current;
}
/////////////////////////////////////////////////////////////////////////////
//-----------------------------------
// These functions are not to be called if the array is sorted (i.e. has a compare func)
//-----------------------------------
void XPSortedPtrArray::SetAt(int index, void *newElement)
{
if (!m_CompareFunc)
XPPtrArray::SetAt (index, newElement);
else
XP_ASSERT(FALSE); // Illegal operation because the array is sorted
}
void XPSortedPtrArray::InsertAt(int index, void *newElement, int count)
{
if (!m_CompareFunc)
XPPtrArray::InsertAt (index, newElement, count);
else
XP_ASSERT(FALSE); // Illegal operation because the array is sorted
}
void XPSortedPtrArray::InsertAt(int index, const XPPtrArray *array)
{
if (!m_CompareFunc)
XPPtrArray::InsertAt (index, array);
else
XP_ASSERT(FALSE); // Illegal operation because the array is sorted
}
/////////////////////////////////////////////////////////////////////////////
// Diagnostics
#ifdef DEBUG
XP_Bool XPPtrArray::VerifySort() const
{
return TRUE;
}
XP_Bool XPSortedPtrArray::VerifySort() const
{
// Check that the assumption of sorting in the array is valid.
if (GetSize() > 0 && m_CompareFunc)
{
void *cur = GetAt(0);
for (int i = 1; i < GetSize(); i++)
{
void *prev = cur;
cur = GetAt(i);
if (m_CompareFunc(&cur, &prev) < 0)
{
XP_ASSERT(FALSE);
return FALSE;
}
}
}
return TRUE;
}
#endif
///////////////////////////////////////////////////////////////////////////////
msg_StringArray::msg_StringArray(XP_Bool ownsMemory, XPCompareFunc *compare)
:XPSortedPtrArray(compare)
{
m_ownsMemory = ownsMemory;
}
msg_StringArray::~msg_StringArray()
{
RemoveAll();
}
int msg_StringArray::Add(void *string)
{
return XPPtrArray::Add(m_ownsMemory ? XP_STRDUP((char *)string) : string);
}
void msg_StringArray::RemoveAll()
{
if (m_ownsMemory)
{
for (int i = 0; i < GetSize(); i++)
{
void *v = (void *)GetAt(i);
XP_FREEIF(v);
}
}
XPSortedPtrArray::RemoveAll(); // call the base class to shrink m_pData list
}
XP_Bool msg_StringArray::ImportTokenList(const char *list, const char *tokenSeparators /* = " ," */)
{
// Tokenizes the input string and builds up the array of strings based on the
// optional caller-provided token separators.
XP_ASSERT(m_ownsMemory); // must own the memory for the substrings
if (list && m_ownsMemory)
{
char *scratch = XP_STRDUP(list); // make a copy cause strtok will change it
if (scratch)
{
char *elem = XP_STRTOK(scratch, tokenSeparators);
if (elem)
{
Add (elem);
while (NULL != (elem = XP_STRTOK(NULL, tokenSeparators)))
Add (elem);
}
XP_FREE(scratch);
return TRUE;
}
}
return FALSE;
}
char *msg_StringArray::ExportTokenList(const char *separator /* = " ," */)
{
// Catenates all the member strings into a big string separated by optional
// caller-provided string. The return value must be freed by the caller
int i, len = 0;
int lenSep = XP_STRLEN(separator);
for (i = 0; i < GetSize(); i++)
len += XP_STRLEN(GetAt(i)) + lenSep;
char *list = (char *)XP_ALLOC(len + 1);
if (list)
{
*list = '\0';
for (i = 0; i < GetSize(); i++)
{
if (i > 0)
XP_STRCAT(list, separator);
XP_STRCAT(list, GetAt(i));
}
}
return list;
}

View File

@@ -0,0 +1,160 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// ptrarray.h
#ifndef PTR_ARRAY_H_
#define PTR_ARRAY_H_
#ifdef XP_UNIX
#define __cdecl
#endif
typedef int XPCompareFunc(const void *, const void *);
#ifdef DEBUG
// These are here to stop people calling
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif // DEBUG
//*****************************************************************************
class XPPtrArray
{
public:
// Construction/destruction
XPPtrArray();
virtual ~XPPtrArray();
// State/attribute member functions
int GetSize() const;
XP_Bool IsValidIndex(int32 nIndex);
VIRTUAL XP_Bool SetSize(int nNewSize);
// Accessor member functions
void *&ElementAt(int nIndex);
virtual int FindIndex (int nStartIndex, void *pToFind) const;
virtual int FindIndexUsing(int nStartIndex, void *pToFind, XPCompareFunc* compare) const;
void *GetAt(int nIndex) const;
VIRTUAL void SetAt(int nIndex, void *newElement);
// Insertion/deletion member functions
virtual int Add(void *newElement);
VIRTUAL void InsertAt(int nIndex, void *newElement, int nCount = 1);
VIRTUAL void InsertAt(int nStartIndex, const XPPtrArray *pNewArray);
XP_Bool Remove(void *pToRemove);
virtual void RemoveAll();
void RemoveAt(int nIndex, int nCount = 1);
void RemoveAt(int nStartIndex, const XPPtrArray *pNewArray);
VIRTUAL void SetAtGrow(int nIndex, void *newElement);
// Sorting member functions
int InsertBinary(void *newElement, XPCompareFunc *compare);
void QuickSort(XPCompareFunc *compare);
// Overloaded operators
void *operator[](int nIndex) const;
void *&operator[](int nIndex);
#ifdef DEBUG
virtual XP_Bool VerifySort() const;
#endif
protected:
// Member Variables
int m_nSize;
int m_nMaxSize;
void **m_pData;
};
//*****************************************************************************
class XPSortedPtrArray : public XPPtrArray
{
public:
XPSortedPtrArray(XPCompareFunc *compare);
virtual int Add(void *newElement);
// PROMISE: this class will always call the compare-func with pToFind as the
// second parameter.
virtual int FindIndex(int nStartIndex, void *pToFind) const;
// These functions can only be used on non-sorted PtrArray objects (i.e. compareFunc is NULL)
virtual void SetAt(int nIndex, void* newElement);
virtual void InsertAt(int nIndex, void* newElement, int nCount = 1);
virtual void InsertAt(int nStartIndex, const XPPtrArray* pNewArray);
#ifdef DEBUG
virtual XP_Bool VerifySort() const;
#endif
protected:
// Allows search to use a different compare func from the sort. This is used
// by MSG_FolderCache, to find the cache element corresponding to a folder.
// The corresponding element and folder have identical relative paths, and the
// relative path is used by both compare funcs, which is why it works.
// to the found element
int FindIndexUsing(int nStartIndex, void *pToFind,
XPCompareFunc *compare) const;
// Member Variables
XPCompareFunc* m_CompareFunc; // NULL to simulate unsorted base-class.
};
//*****************************************************************************
// msg_StringArray is a subclass of the generic pointer array class
// which is intended for string operations.
// - It can "own" the strings, or not.
// - It can be sorted, if you provide a CompareFunc, or not, if you don't
class msg_StringArray : public XPSortedPtrArray
{
public:
// Overrides from base class
msg_StringArray (XP_Bool ownsMemory, XPCompareFunc *compare = NULL);
virtual ~msg_StringArray ();
const char *GetAt (int i) const { return (const char*) XPPtrArray::GetAt(i); }
virtual int Add (void *string);
virtual void RemoveAll ();
XP_Bool ImportTokenList (const char *list, const char *tokenSeps = ", ");
char *ExportTokenList (const char *tokenSep = ", ");
protected:
XP_Bool m_ownsMemory;
};
//*****************************************************************************
class MSG_FolderInfo;
class MSG_FolderArray : public XPSortedPtrArray
{
public:
// Override constructor to allow folderArrays to be sorted
MSG_FolderArray (XPCompareFunc *compare = NULL) : XPSortedPtrArray (compare) {}
// Encapsulate this typecast, so we don't have to do it all over the place.
MSG_FolderInfo *GetAt(int i) const { return (MSG_FolderInfo*) XPPtrArray::GetAt(i); }
};
#endif