Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,55 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'nsComposeStrings.h',
'nsMsgAttachmentHandler.h',
'nsMsgCompFields.h',
'nsMsgCompose.h',
'nsMsgSend.h',
]
SOURCES += [
'nsComposeStrings.cpp',
'nsMsgAttachment.cpp',
'nsMsgAttachmentHandler.cpp',
'nsMsgCompFields.cpp',
'nsMsgCompose.cpp',
'nsMsgComposeContentHandler.cpp',
'nsMsgComposeParams.cpp',
'nsMsgComposeProgressParams.cpp',
'nsMsgComposeService.cpp',
'nsMsgCompUtils.cpp',
'nsMsgCopy.cpp',
'nsMsgPrompts.cpp',
'nsMsgQuote.cpp',
'nsMsgSend.cpp',
'nsMsgSendLater.cpp',
'nsMsgSendPart.cpp',
'nsMsgSendReport.cpp',
'nsSmtpProtocol.cpp',
'nsSmtpServer.cpp',
'nsSmtpService.cpp',
'nsSmtpUrl.cpp',
'nsURLFetcher.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
SOURCES += [
'nsMsgAppleDoubleEncode.cpp',
'nsMsgAppleEncode.cpp',
]
EXPORTS += [
'nsMsgAppleCodes.h',
'nsMsgAppleDouble.h',
]
EXTRA_COMPONENTS += [
'nsSMTPProtocolHandler.js',
'nsSMTPProtocolHandler.manifest',
]
FINAL_LIBRARY = 'mail'

View file

@ -0,0 +1,116 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsComposeStrings.h"
const char16_t* errorStringNameForErrorCode(nsresult aCode)
{
#ifdef __GNUC__
// Temporary workaroung until bug 783526 is fixed.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
#endif
switch(aCode)
{
case NS_MSG_UNABLE_TO_OPEN_FILE:
return u"unableToOpenFile";
case NS_MSG_UNABLE_TO_OPEN_TMP_FILE:
return u"unableToOpenTmpFile";
case NS_MSG_UNABLE_TO_SAVE_TEMPLATE:
return u"unableToSaveTemplate";
case NS_MSG_UNABLE_TO_SAVE_DRAFT:
return u"unableToSaveDraft";
case NS_MSG_COULDNT_OPEN_FCC_FOLDER:
return u"couldntOpenFccFolder";
case NS_MSG_NO_SENDER:
return u"noSender";
case NS_MSG_NO_RECIPIENTS:
return u"noRecipients";
case NS_MSG_ERROR_WRITING_FILE:
return u"errorWritingFile";
case NS_ERROR_SENDING_FROM_COMMAND:
return u"errorSendingFromCommand";
case NS_ERROR_SENDING_DATA_COMMAND:
return u"errorSendingDataCommand";
case NS_ERROR_SENDING_MESSAGE:
return u"errorSendingMessage";
case NS_ERROR_POST_FAILED:
return u"postFailed";
case NS_ERROR_QUEUED_DELIVERY_FAILED:
return u"errorQueuedDeliveryFailed";
case NS_ERROR_SEND_FAILED:
return u"sendFailed";
case NS_ERROR_SMTP_SERVER_ERROR:
return u"smtpServerError";
case NS_MSG_UNABLE_TO_SEND_LATER:
return u"unableToSendLater";
case NS_ERROR_COMMUNICATIONS_ERROR:
return u"communicationsError";
case NS_ERROR_BUT_DONT_SHOW_ALERT:
return u"dontShowAlert";
case NS_ERROR_TCP_READ_ERROR:
return u"tcpReadError";
case NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS:
return u"couldNotGetUsersMailAddress";
case NS_ERROR_MIME_MPART_ATTACHMENT_ERROR:
return u"mimeMpartAttachmentError";
case NS_MSG_FAILED_COPY_OPERATION:
return u"failedCopyOperation";
case NS_ERROR_NNTP_NO_CROSS_POSTING:
return u"nntpNoCrossPosting";
case NS_MSG_CANCELLING:
return u"msgCancelling";
case NS_ERROR_SEND_FAILED_BUT_NNTP_OK:
return u"sendFailedButNntpOk";
case NS_MSG_ERROR_READING_FILE:
return u"errorReadingFile";
case NS_MSG_ERROR_ATTACHING_FILE:
return u"errorAttachingFile";
case NS_ERROR_SMTP_GREETING:
return u"incorrectSmtpGreeting";
case NS_ERROR_SENDING_RCPT_COMMAND:
return u"errorSendingRcptCommand";
case NS_ERROR_STARTTLS_FAILED_EHLO_STARTTLS:
return u"startTlsFailed";
case NS_ERROR_SMTP_PASSWORD_UNDEFINED:
return u"smtpPasswordUndefined";
case NS_ERROR_SMTP_TEMP_SIZE_EXCEEDED:
return u"smtpTempSizeExceeded";
case NS_ERROR_SMTP_PERM_SIZE_EXCEEDED_1:
return u"smtpPermSizeExceeded1";
case NS_ERROR_SMTP_PERM_SIZE_EXCEEDED_2:
return u"smtpPermSizeExceeded2";
case NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_SERVER:
return u"smtpSendFailedUnknownServer";
case NS_ERROR_SMTP_SEND_FAILED_REFUSED:
return u"smtpSendRequestRefused";
case NS_ERROR_SMTP_SEND_FAILED_INTERRUPTED:
return u"smtpSendInterrupted";
case NS_ERROR_SMTP_SEND_FAILED_TIMEOUT:
return u"smtpSendTimeout";
case NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_REASON:
return u"smtpSendFailedUnknownReason";
case NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_NO_SSL:
return u"smtpHintAuthEncryptToPlainNoSsl";
case NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_SSL:
return u"smtpHintAuthEncryptToPlainSsl";
case NS_ERROR_SMTP_AUTH_CHANGE_PLAIN_TO_ENCRYPT:
return u"smtpHintAuthPlainToEncrypt";
case NS_ERROR_SMTP_AUTH_FAILURE:
return u"smtpAuthFailure";
case NS_ERROR_SMTP_AUTH_GSSAPI:
return u"smtpAuthGssapi";
case NS_ERROR_SMTP_AUTH_MECH_NOT_SUPPORTED:
return u"smtpAuthMechNotSupported";
case NS_ERROR_SMTP_AUTH_NOT_SUPPORTED:
return u"smtpAuthenticationNotSupported";
case NS_ERROR_ILLEGAL_LOCALPART:
return u"illegalLocalPart";
default:
return u"sendFailed";
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}

View file

@ -0,0 +1,77 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
String Ids used by mailnews\compose
To Do: Convert the callers to use names instead of ids and then make this file obsolete.
*/
#ifndef _nsComposeStrings_H__
#define _nsComposeStrings_H__
#include "msgCore.h"
#define NS_MSG_UNABLE_TO_OPEN_FILE NS_MSG_GENERATE_FAILURE(12500)
#define NS_MSG_UNABLE_TO_OPEN_TMP_FILE NS_MSG_GENERATE_FAILURE(12501)
#define NS_MSG_UNABLE_TO_SAVE_TEMPLATE NS_MSG_GENERATE_FAILURE(12502)
#define NS_MSG_UNABLE_TO_SAVE_DRAFT NS_MSG_GENERATE_FAILURE(12503)
#define NS_MSG_COULDNT_OPEN_FCC_FOLDER NS_MSG_GENERATE_FAILURE(12506)
#define NS_MSG_NO_SENDER NS_MSG_GENERATE_FAILURE(12510)
#define NS_MSG_NO_RECIPIENTS NS_MSG_GENERATE_FAILURE(12511)
#define NS_MSG_ERROR_WRITING_FILE NS_MSG_GENERATE_FAILURE(12512)
#define NS_ERROR_SENDING_FROM_COMMAND NS_MSG_GENERATE_FAILURE(12514)
#define NS_ERROR_SENDING_DATA_COMMAND NS_MSG_GENERATE_FAILURE(12516)
#define NS_ERROR_SENDING_MESSAGE NS_MSG_GENERATE_FAILURE(12517)
#define NS_ERROR_POST_FAILED NS_MSG_GENERATE_FAILURE(12518)
#define NS_ERROR_QUEUED_DELIVERY_FAILED NS_MSG_GENERATE_FAILURE(12519)
#define NS_ERROR_SEND_FAILED NS_MSG_GENERATE_FAILURE(12520)
#define NS_ERROR_SMTP_SERVER_ERROR NS_MSG_GENERATE_FAILURE(12524)
#define NS_MSG_UNABLE_TO_SEND_LATER NS_MSG_GENERATE_FAILURE(12525)
#define NS_ERROR_COMMUNICATIONS_ERROR NS_MSG_GENERATE_FAILURE(12526)
#define NS_ERROR_BUT_DONT_SHOW_ALERT NS_MSG_GENERATE_FAILURE(12527)
#define NS_ERROR_TCP_READ_ERROR NS_MSG_GENERATE_FAILURE(12528)
#define NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS NS_MSG_GENERATE_FAILURE(12529)
#define NS_ERROR_MIME_MPART_ATTACHMENT_ERROR NS_MSG_GENERATE_FAILURE(12531)
#define NS_MSG_FAILED_COPY_OPERATION NS_MSG_GENERATE_FAILURE(12532)
/* 12554 is taken by NS_ERROR_NNTP_NO_CROSS_POSTING. use 12555 as the next one */
#define NS_MSG_CANCELLING NS_MSG_GENERATE_SUCCESS(12555)
// For message sending report
#define NS_ERROR_SEND_FAILED_BUT_NNTP_OK NS_MSG_GENERATE_FAILURE(12560)
#define NS_MSG_ERROR_READING_FILE NS_MSG_GENERATE_FAILURE(12563)
#define NS_MSG_ERROR_ATTACHING_FILE NS_MSG_GENERATE_FAILURE(12570)
#define NS_ERROR_SMTP_GREETING NS_MSG_GENERATE_FAILURE(12572)
#define NS_ERROR_SENDING_RCPT_COMMAND NS_MSG_GENERATE_FAILURE(12575)
#define NS_ERROR_STARTTLS_FAILED_EHLO_STARTTLS NS_MSG_GENERATE_FAILURE(12582)
#define NS_ERROR_SMTP_PASSWORD_UNDEFINED NS_MSG_GENERATE_FAILURE(12584)
#define NS_ERROR_SMTP_TEMP_SIZE_EXCEEDED NS_MSG_GENERATE_FAILURE(12586)
#define NS_ERROR_SMTP_PERM_SIZE_EXCEEDED_1 NS_MSG_GENERATE_FAILURE(12587)
#define NS_ERROR_SMTP_PERM_SIZE_EXCEEDED_2 NS_MSG_GENERATE_FAILURE(12588)
#define NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_SERVER NS_MSG_GENERATE_FAILURE(12589)
#define NS_ERROR_SMTP_SEND_FAILED_REFUSED NS_MSG_GENERATE_FAILURE(12590)
#define NS_ERROR_SMTP_SEND_FAILED_INTERRUPTED NS_MSG_GENERATE_FAILURE(12591)
#define NS_ERROR_SMTP_SEND_FAILED_TIMEOUT NS_MSG_GENERATE_FAILURE(12592)
#define NS_ERROR_SMTP_SEND_FAILED_UNKNOWN_REASON NS_MSG_GENERATE_FAILURE(12593)
#define NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_NO_SSL NS_MSG_GENERATE_FAILURE(12594)
#define NS_ERROR_SMTP_AUTH_CHANGE_ENCRYPT_TO_PLAIN_SSL NS_MSG_GENERATE_FAILURE(12595)
#define NS_ERROR_SMTP_AUTH_CHANGE_PLAIN_TO_ENCRYPT NS_MSG_GENERATE_FAILURE(12596)
#define NS_ERROR_SMTP_AUTH_FAILURE NS_MSG_GENERATE_FAILURE(12597)
#define NS_ERROR_SMTP_AUTH_GSSAPI NS_MSG_GENERATE_FAILURE(12598)
#define NS_ERROR_SMTP_AUTH_MECH_NOT_SUPPORTED NS_MSG_GENERATE_FAILURE(12599)
#define NS_ERROR_SMTP_AUTH_NOT_SUPPORTED NS_MSG_GENERATE_FAILURE(12600)
#define NS_ERROR_ILLEGAL_LOCALPART NS_MSG_GENERATE_FAILURE(12601)
const char16_t* errorStringNameForErrorCode(nsresult aCode);
#endif /* _nsComposeStrings_H__ */

View file

@ -0,0 +1,106 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
** AD_Codes.h
**
** ---------------
**
** Head file for Apple Decode/Encode essential codes.
**
**
*/
#ifndef ad_codes_h
#define ad_codes_h
/*
** applefile definitions used
*/
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#endif
#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_t magic;
int32_t version;
char fill[16];
int16_t entries;
} ap_header;
typedef struct ap_entry
{
int32_t id;
int32_t offset;
int32_t length;
} ap_entry;
typedef struct ap_dates
{
int32_t create, modify, backup, access;
} ap_dates;
typedef struct myFInfo /* the mac FInfo structure for the cross platform. */
{
int32_t fdType, fdCreator;
int16_t fdFlags;
int32_t fdLocation; /* it really should be a pointer, but just a place-holder */
int16_t fdFldr;
} myFInfo;
PR_BEGIN_EXTERN_C
/*
** string utils.
*/
int write_stream(appledouble_encode_object *p_ap_encode_obj, const 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, bool firstTime);
int ap_encode_data( appledouble_encode_object* p_ap_encode_obj, 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, bool firstime);
int ap_parse_header(appledouble_decode_object* p_ap_decode_obj,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, bool firstime);
int ap_decode_process_data( appledouble_decode_object* p_ap_decode_obj, bool firstime);
PR_END_EXTERN_C
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#endif
#endif /* ad_codes_h */

View file

@ -0,0 +1,207 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* AppleDouble.h
* -------------
*
* The header file for a stream based apple single/double encodor/decodor.
*
* 2aug95 mym
*
*/
#ifndef AppleDouble_h
#define AppleDouble_h
#include "msgCore.h"
#include "nsComposeStrings.h"
#include "nsIOutputStream.h"
#include "nsCOMPtr.h"
#include <CoreServices/CoreServices.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 errFileOpen NS_ERROR_GET_CODE(NS_MSG_UNABLE_TO_OPEN_TMP_FILE)
#define errFileWrite -202 /*Error writing temporary file.*/
#define errUsrCancel -2 /*MK_INTERRUPTED */
#define errDecoding -1
/*
** The envirment block data type.
*/
enum
{
kInit,
kDoingHeaderPortion,
kDoneHeaderPortion,
kDoingDataPortion,
kDoneDataPortion
};
typedef struct _appledouble_encode_object
{
char fname[256];
FSIORefNum 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];
// nsIOFileStream *fileSpec; /* the stream for data fork work. */
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. */
nsCOMPtr <nsIFile> tmpFile; /* the temp file to hold the decode data fork */
/* when doing the binhex exporting. */
nsCOMPtr <nsIOutputStream> tmpFileStream; /* The output File Stream */
int32_t data_size; /* the size of the data in the tmp file. */
} appledouble_decode_object;
/*
** The protypes.
*/
PR_BEGIN_EXTERN_C
int ap_encode_init(appledouble_encode_object *p_ap_encode_obj,
const char* fname,
char* separator);
int ap_encode_next(appledouble_encode_object* p_ap_encode_obj,
char *to_buff,
int32_t buff_size,
int32_t* real_size);
int ap_encode_end(appledouble_encode_object* p_ap_encode_obj,
bool is_aborting);
int ap_decode_init(appledouble_decode_object* p_ap_decode_obj,
bool is_apple_single,
bool write_as_bin_hex,
void *closure);
int ap_decode_next(appledouble_decode_object* p_ap_decode_obj,
char *in_buff,
int32_t buff_size);
int ap_decode_end(appledouble_decode_object* p_ap_decode_obj,
bool is_aborting);
PR_END_EXTERN_C
#endif

View file

@ -0,0 +1,266 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
*
* apple-double.c
* --------------
*
* The codes to do apple double encoding/decoding.
*
* 02aug95 mym created.
*
*/
#include "nsID.h"
#include "nscore.h"
#include "nsStringGlue.h"
#include "nsMsgAppleDouble.h"
#include "nsMsgAppleCodes.h"
#include "nsMsgCompUtils.h"
#include "nsCExternalHandlerService.h"
#include "nsIMIMEService.h"
#include "nsMimeTypes.h"
#include "prmem.h"
#include "nsNetUtil.h"
void
MacGetFileType(nsIFile *fs,
bool *useDefault,
char **fileType,
char **encoding)
{
if ((fs == NULL) || (fileType == NULL) || (encoding == NULL))
return;
bool exists = false;
fs->Exists(&exists);
if (!exists)
return;
*useDefault = TRUE;
*fileType = NULL;
*encoding = NULL;
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(fs);
FSRef fsRef;
FSCatalogInfo catalogInfo;
OSErr err = errFileOpen;
if (NS_SUCCEEDED(macFile->GetFSRef(&fsRef)))
err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr);
if ( (err != noErr) || (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT') )
*fileType = strdup(APPLICATION_OCTET_STREAM);
else
{
// At this point, we should call the mime service and
// see what we can find out?
nsresult rv;
nsCOMPtr <nsIURI> tURI;
if (NS_SUCCEEDED(NS_NewFileURI(getter_AddRefs(tURI), fs)) && tURI)
{
nsCOMPtr<nsIMIMEService> mimeFinder (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv) && mimeFinder)
{
nsAutoCString mimeType;
rv = mimeFinder->GetTypeFromURI(tURI, mimeType);
if (NS_SUCCEEDED(rv))
{
*fileType = ToNewCString(mimeType);
return;
}
}
}
// If we hit here, return something...default to this...
*fileType = strdup(APPLICATION_OCTET_STREAM);
}
}
//#pragma cplusplus reset
/*
* ap_encode_init
* --------------
*
* Setup the encode envirment
*/
int ap_encode_init( appledouble_encode_object *p_ap_encode_obj,
const char *fname,
char *separator)
{
nsCOMPtr <nsIFile> myFile;
NS_NewNativeLocalFile(nsDependentCString(fname), true, getter_AddRefs(myFile));
bool exists;
if (myFile && NS_SUCCEEDED(myFile->Exists(&exists)) && !exists)
return -1;
nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(myFile);
nsAutoCString path;
macFile->GetNativePath(path);
memset(p_ap_encode_obj, 0, sizeof(appledouble_encode_object));
/*
** Fill out the source file inforamtion.
*/
memcpy(p_ap_encode_obj->fname, path.get(), path.Length());
p_ap_encode_obj->fname[path.Length()] = '\0';
p_ap_encode_obj->boundary = 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_t buff_size,
int32_t* 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,
(const char*)(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:
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,
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. */
::FSCloseFork(p_ap_encode_obj->fileId);
PR_FREEIF(p_ap_encode_obj->boundary); /* the boundary string. */
return noErr;
}

View file

@ -0,0 +1,703 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
*
* apple_double_encode.c
* ---------------------
*
* The routines doing the Apple Double Encoding.
*
* 2aug95 mym Created.
*
*/
#include "nscore.h"
#include "nsStringGlue.h"
#include "nsMimeTypes.h"
#include "prprf.h"
#include "nsServiceManagerUtils.h"
#include "nsMsgAppleDouble.h"
#include "nsMsgAppleCodes.h"
#include "nsILocalFileMac.h"
/*
** Local Functions prototypes.
*/
static int output64chunk( appledouble_encode_object* p_ap_encode_obj,
int c1, int c2, int c3, int pads);
static int to64(appledouble_encode_object* p_ap_encode_obj,
char *p,
int in_size);
static 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,
const char *out_string,
int len)
{
if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff)
{
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;
memcpy(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
out_string,
s_len);
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;
PR_snprintf(tmpstr, sizeof(tmpstr),
"Content-Type: multipart/appledouble; boundary=\"=\"; name=\"");
status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr));
if (status != noErr)
return status;
status = write_stream(p_ap_encode_obj,
p_ap_encode_obj->fname,
strlen(p_ap_encode_obj->fname));
if (status != noErr)
return status;
PR_snprintf(tmpstr, sizeof(tmpstr),
"\"\r\nContent-Disposition: inline; filename=\"%s\"\r\n\r\n\r\n--=\r\n",
p_ap_encode_obj->fname);
#endif /* 0 */
PR_snprintf(tmpstr, sizeof(tmpstr), "--%s" CRLF, p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj, (const char*)tmpstr, strlen(tmpstr));
return status;
}
int ap_encode_file_infor(
appledouble_encode_object *p_ap_encode_obj)
{
ap_header head;
ap_entry entries[NUM_ENTRIES];
ap_dates dates;
short i;
long comlen;
char comment[256];
int status;
nsCOMPtr <nsIFile> resFile;
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true,
getter_AddRefs(resFile));
if (!resFile)
return errFileOpen;
FSRef ref;
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(resFile);
if (NS_FAILED(macFile->GetFSRef(&ref)))
return errFileOpen;
FSCatalogInfo catalogInfo;
if (::FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr) != noErr)
{
return errFileOpen;
}
/* get a file comment, if possible */
#if 1
// Carbon doesn't support GetWDInfo(). (Bug 555684)
// not sure why working directories are needed here...
comlen = 0;
#else
long procID;
procID = 0;
GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID);
IOParam vinfo;
memset((void *) &vinfo, '\0', sizeof (vinfo));
GetVolParmsInfoBuffer vp;
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))
{
DTPBRec dtp;
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;
}
}
#endif /* ! 1 */
/* 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 */
nsAutoCString leafname;
macFile->GetNativeLeafName(leafname);
entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries;
entries[0].id = ENT_NAME;
entries[0].length = leafname.Length();
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 = catalogInfo.rsrcLogicalSize;
entries[5].id = ENT_DFORK;
entries[5].length = catalogInfo.dataLogicalSize;
/* 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 *) leafname.get(),
leafname.Length());
if (status != noErr)
return status;
/* write finder info */
status = to64(p_ap_encode_obj,
(char *) &catalogInfo.finderInfo,
sizeof (FInfo));
if (status != noErr)
return status;
status = to64(p_ap_encode_obj,
(char *) &catalogInfo.extFinderInfo,
sizeof (FXInfo));
if (status != noErr)
return status;
/* write dates */
dates.create = catalogInfo.createDate.lowSeconds + CONVERT_TIME;
dates.modify = catalogInfo.contentModDate.lowSeconds + CONVERT_TIME;
dates.backup = catalogInfo.backupDate.lowSeconds + CONVERT_TIME;
dates.access = catalogInfo.accessDate.lowSeconds + 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 (((FileInfo*)(&catalogInfo.finderInfo))->fileType == 'TEXT' ||
((FileInfo*)(&catalogInfo.finderInfo))->fileType == '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,
bool firstime)
{
char rd_buff[256];
FSIORefNum fileId;
OSErr retval = noErr;
int status;
ByteCount inCount;
if (firstime)
{
PL_strcpy(rd_buff,
"Content-Type: application/applefile\r\nContent-Transfer-Encoding: base64\r\n\r\n");
status = write_stream(p_ap_encode_obj, (const char*)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.
*/
nsCOMPtr <nsIFile> myFile;
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true, getter_AddRefs(myFile));
if (!myFile)
return errFileOpen;
FSRef ref;
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(myFile);
if (NS_FAILED(macFile->GetFSRef(&ref)))
return errFileOpen;
HFSUniStr255 forkName;
::FSGetResourceForkName(&forkName);
retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &p_ap_encode_obj->fileId);
if (retval != noErr)
return retval;
}
fileId = p_ap_encode_obj->fileId;
while (retval == noErr)
{
if (BUFF_LEFT(p_ap_encode_obj) < 400)
break;
inCount = 0;
retval = ::FSReadFork(fileId, fsAtMark, 0, 256, rd_buff, &inCount);
if (inCount)
{
status = to64(p_ap_encode_obj,
rd_buff,
inCount);
if (status != noErr)
return status;
}
}
if (retval == eofErr)
{
::FSCloseFork(fileId);
p_ap_encode_obj->fileId = 0;
status = finish64(p_ap_encode_obj);
if (status != noErr)
return status;
/*
** write out the boundary
*/
PR_snprintf(rd_buff, sizeof(rd_buff),
CRLF "--%s" CRLF,
p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
if (status == noErr)
status = errDone;
}
return status;
}
#if 0
// This is unused for now and Clang complains about that is it is ifdefed out
static void replace(char *p, int len, char frm, char to)
{
for (; len > 0; len--, p++)
if (*p == frm) *p = to;
}
#endif
/* Description of the various file formats and their magic numbers */
struct magic
{
const char *name; /* Name of the file format */
const 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 = MOZ_ARRAY_LENGTH(magic);
static const char *text_type = TEXT_PLAIN; /* the text file type. */
static const 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.
*/
static const 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 = 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,
bool firstime)
{
char rd_buff[256];
FSIORefNum fileId;
OSErr retval = noErr;
ByteCount in_count;
int status;
if (firstime)
{
const char* magic_type;
/*
** preparing to encode the data fork.
*/
nsCOMPtr <nsIFile> resFile;
NS_NewNativeLocalFile(nsDependentCString(p_ap_encode_obj->fname), true,
getter_AddRefs(resFile));
if (!resFile)
return errFileOpen;
FSRef ref;
nsCOMPtr <nsILocalFileMac> macFile = do_QueryInterface(resFile);
if (NS_FAILED(macFile->GetFSRef(&ref)))
return errFileOpen;
HFSUniStr255 forkName;
::FSGetDataForkName(&forkName);
retval = ::FSOpenFork(&ref, forkName.length, forkName.unicode, fsRdPerm, &fileId);
if (retval != noErr)
return retval;
p_ap_encode_obj->fileId = fileId;
if (!p_ap_encode_obj->text_file_type)
{
/*
** do a smart check for the file type.
*/
in_count = 0;
retval = ::FSReadFork(fileId, fsFromStart, 0, 256, rd_buff, &in_count);
magic_type = magic_look(rd_buff, in_count);
/* don't forget to rewind the index to start point. */
::FSSetForkPosition(fileId, fsFromStart, 0);
/* and reset retVal just in case... */
if (retval == eofErr)
retval = noErr;
}
else
{
magic_type = text_type; /* we already know it is a text type. */
}
/*
** the data portion header information.
*/
nsAutoCString leafName;
resFile->GetNativeLeafName(leafName);
PR_snprintf(rd_buff, sizeof(rd_buff),
"Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\"" CRLF CRLF,
magic_type,
leafName.get(),
leafName.get());
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, strlen(rd_buff));
if (status != noErr)
return status;
}
while (retval == noErr)
{
if (BUFF_LEFT(p_ap_encode_obj) < 400)
break;
in_count = 0;
retval = ::FSReadFork(p_ap_encode_obj->fileId, fsAtMark, 0, 256, rd_buff, &in_count);
if (in_count)
{
#if 0
/* replace(rd_buff, in_count, '\r', '\n'); */
#endif
/* ** 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)
{
::FSCloseFork(p_ap_encode_obj->fileId);
p_ap_encode_obj->fileId = 0;
status = finish64(p_ap_encode_obj);
if (status != noErr)
return status;
/* write out the boundary */
PR_snprintf(rd_buff, sizeof(rd_buff),
CRLF "--%s--" CRLF CRLF,
p_ap_encode_obj->boundary);
status = write_stream(p_ap_encode_obj, (const char*)rd_buff, 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.
*/
static 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.
*/
static 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;
}
static 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, (const char*) tmpstr, p-tmpstr);
}

View file

@ -0,0 +1,262 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgAttachment.h"
#include "nsIFile.h"
#include "nsNetUtil.h"
NS_IMPL_ISUPPORTS(nsMsgAttachment, nsIMsgAttachment)
nsMsgAttachment::nsMsgAttachment()
{
mTemporary = false;
mSendViaCloud = false;
mSize = -1;
}
nsMsgAttachment::~nsMsgAttachment()
{
if (mTemporary && !mSendViaCloud)
(void)DeleteAttachment();
}
/* attribute wstring name; */
NS_IMETHODIMP nsMsgAttachment::GetName(nsAString & aName)
{
aName = mName;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetName(const nsAString & aName)
{
mName = aName;
return NS_OK;
}
/* attribute string url; */
NS_IMETHODIMP nsMsgAttachment::GetUrl(nsACString & aUrl)
{
aUrl = mUrl;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetUrl(const nsACString & aUrl)
{
mUrl = aUrl;
return NS_OK;
}
/* attribute string urlCharset; */
NS_IMETHODIMP nsMsgAttachment::GetUrlCharset(nsACString & aUrlCharset)
{
aUrlCharset = mUrlCharset;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetUrlCharset(const nsACString & aUrlCharset)
{
mUrlCharset = aUrlCharset;
return NS_OK;
}
/* attribute boolean temporary; */
NS_IMETHODIMP nsMsgAttachment::GetTemporary(bool *aTemporary)
{
NS_ENSURE_ARG_POINTER(aTemporary);
*aTemporary = mTemporary;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetTemporary(bool aTemporary)
{
mTemporary = aTemporary;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::GetSendViaCloud(bool *aSendViaCloud)
{
NS_ENSURE_ARG_POINTER(aSendViaCloud);
*aSendViaCloud = mSendViaCloud;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetSendViaCloud(bool aSendViaCloud)
{
mSendViaCloud = aSendViaCloud;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetHtmlAnnotation(const nsAString &aAnnotation)
{
mHtmlAnnotation = aAnnotation;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::GetHtmlAnnotation(nsAString &aAnnotation)
{
aAnnotation = mHtmlAnnotation;
return NS_OK;
}
NS_IMETHODIMP
nsMsgAttachment::SetCloudProviderKey(const nsACString &aCloudProviderKey)
{
mCloudProviderKey = aCloudProviderKey;
return NS_OK;
}
NS_IMETHODIMP
nsMsgAttachment::GetCloudProviderKey(nsACString &aCloudProviderKey)
{
aCloudProviderKey = mCloudProviderKey;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::GetContentLocation(nsACString &aContentLocation)
{
aContentLocation = mContentLocation;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetContentLocation(const nsACString &aContentLocation)
{
mContentLocation = aContentLocation;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::GetContentType(char * *aContentType)
{
NS_ENSURE_ARG_POINTER(aContentType);
*aContentType = ToNewCString(mContentType);
return (*aContentType ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
NS_IMETHODIMP nsMsgAttachment::SetContentType(const char * aContentType)
{
mContentType = aContentType;
/* a full content type could also contains parameters but we need to
keep only the content type alone. Therefore we need to cleanup it.
*/
int32_t offset = mContentType.FindChar(';');
if (offset >= 0)
mContentType.SetLength(offset);
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::GetContentTypeParam(char * *aContentTypeParam)
{
NS_ENSURE_ARG_POINTER(aContentTypeParam);
*aContentTypeParam = ToNewCString(mContentTypeParam);
return (*aContentTypeParam ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
NS_IMETHODIMP nsMsgAttachment::SetContentTypeParam(const char * aContentTypeParam)
{
if (aContentTypeParam)
while (*aContentTypeParam == ';' || *aContentTypeParam == ' ')
aContentTypeParam ++;
mContentTypeParam = aContentTypeParam;
return NS_OK;
}
/* attribute string charset; */
NS_IMETHODIMP nsMsgAttachment::GetCharset(char * *aCharset)
{
NS_ENSURE_ARG_POINTER(aCharset);
*aCharset = ToNewCString(mCharset);
return (*aCharset ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
NS_IMETHODIMP nsMsgAttachment::SetCharset(const char * aCharset)
{
mCharset = aCharset;
return NS_OK;
}
/* attribute string macType; */
NS_IMETHODIMP nsMsgAttachment::GetMacType(char * *aMacType)
{
NS_ENSURE_ARG_POINTER(aMacType);
*aMacType = ToNewCString(mMacType);
return (*aMacType ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
NS_IMETHODIMP nsMsgAttachment::SetMacType(const char * aMacType)
{
mMacType = aMacType;
return NS_OK;
}
/* attribute string macCreator; */
NS_IMETHODIMP nsMsgAttachment::GetMacCreator(char * *aMacCreator)
{
NS_ENSURE_ARG_POINTER(aMacCreator);
*aMacCreator = ToNewCString(mMacCreator);
return (*aMacCreator ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
}
NS_IMETHODIMP nsMsgAttachment::SetMacCreator(const char * aMacCreator)
{
mMacCreator = aMacCreator;
return NS_OK;
}
/* attribute int64_t size; */
NS_IMETHODIMP nsMsgAttachment::GetSize(int64_t *aSize)
{
NS_ENSURE_ARG_POINTER(aSize);
*aSize = mSize;
return NS_OK;
}
NS_IMETHODIMP nsMsgAttachment::SetSize(int64_t aSize)
{
mSize = aSize;
return NS_OK;
}
/* boolean equalsUrl (in nsIMsgAttachment attachment); */
NS_IMETHODIMP nsMsgAttachment::EqualsUrl(nsIMsgAttachment *attachment, bool *_retval)
{
NS_ENSURE_ARG_POINTER(attachment);
NS_ENSURE_ARG_POINTER(_retval);
nsAutoCString url;
attachment->GetUrl(url);
*_retval = mUrl.Equals(url);
return NS_OK;
}
nsresult nsMsgAttachment::DeleteAttachment()
{
nsresult rv;
bool isAFile = false;
nsCOMPtr<nsIFile> urlFile;
rv = NS_GetFileFromURLSpec(mUrl, getter_AddRefs(urlFile));
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't nsIFile from URL string");
if (NS_SUCCEEDED(rv))
{
bool bExists = false;
rv = urlFile->Exists(&bExists);
NS_ASSERTION(NS_SUCCEEDED(rv), "Exists() call failed!");
if (NS_SUCCEEDED(rv) && bExists)
{
rv = urlFile->IsFile(&isAFile);
NS_ASSERTION(NS_SUCCEEDED(rv), "IsFile() call failed!");
}
}
// remove it if it's a valid file
if (isAFile)
rv = urlFile->Remove(false);
return rv;
}

View file

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgAttachment_H_
#define _nsMsgAttachment_H_
#include "nsIMsgAttachment.h"
#include "nsStringGlue.h"
class nsMsgAttachment : public nsIMsgAttachment
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGATTACHMENT
nsMsgAttachment();
private:
virtual ~nsMsgAttachment();
nsresult DeleteAttachment();
nsString mName;
nsCString mUrl;
nsCString mUrlCharset;
bool mTemporary;
bool mSendViaCloud;
nsCString mCloudProviderKey;
nsCString mContentLocation;
nsCString mContentType;
nsCString mContentTypeParam;
nsCString mCharset;
nsCString mMacType;
nsCString mMacCreator;
nsString mHtmlAnnotation;
int64_t mSize;
};
#endif /* _nsMsgAttachment_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,194 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgAttachmentHandler_H_
#define _nsMsgAttachmentHandler_H_
#include "nsIURL.h"
#include "nsMsgCompFields.h"
#include "nsIMsgStatusFeedback.h"
#include "nsIChannel.h"
#include "nsIMsgSend.h"
#include "nsIFileStreams.h"
#include "nsIStreamConverter.h"
#include "nsAutoPtr.h"
#include "nsIMsgAttachmentHandler.h"
#ifdef XP_MACOSX
#include "nsMsgAppleDouble.h"
#include "nsILocalFileMac.h"
class AppleDoubleEncodeObject
{
public:
appledouble_encode_object ap_encode_obj;
char *buff; // the working buff
int32_t s_buff; // the working buff size
nsCOMPtr <nsIOutputStream> fileStream; // file to hold the encoding
};
class nsILocalFileMac;
class nsIZipWriter;
/* Simple utility class that will synchronously zip any file
(or folder hierarchy) you give it. */
class nsSimpleZipper
{
public:
// Synchronously zips the input file/folder and writes all
// data to the output file.
static nsresult Zip(nsIFile *aInputFile, nsIFile *aOutputFile);
private:
// Recursively adds the file or folder to aZipWriter.
static nsresult AddToZip(nsIZipWriter *aZipWriter,
nsIFile *aFile,
const nsACString &aPath);
};
#endif // XP_MACOSX
namespace mozilla {
namespace mailnews {
class MimeEncoder;
}
}
//
// This is a class that deals with processing remote attachments. It implements
// an nsIStreamListener interface to deal with incoming data
//
class nsMsgAttachmentHandler : public nsIMsgAttachmentHandler
{
typedef mozilla::mailnews::MimeEncoder MimeEncoder;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMSGATTACHMENTHANDLER
nsMsgAttachmentHandler();
public:
nsresult SnarfAttachment(nsMsgCompFields *compFields);
nsresult PickEncoding(const char *charset, nsIMsgSend* mime_delivery_state);
nsresult PickCharset();
void AnalyzeSnarfedFile (); // Analyze a previously-snarfed file.
// (Currently only used for plaintext
// converted from HTML.)
nsresult Abort();
nsresult UrlExit(nsresult status, const char16_t* aMsg);
// if there's an intermediate temp file left, takes care to remove it from disk.
//
// NOTE: this takes care of the mEncodedWorkingFile temp file, but not mTmpFile which seems
// to be used by lots of other classes at the moment.
void CleanupTempFile();
private:
virtual ~nsMsgAttachmentHandler();
// use when a message (e.g. original message in a reply) is attached as a rfc822 attachment.
nsresult SnarfMsgAttachment(nsMsgCompFields *compFields);
bool UseUUEncode_p(void);
void AnalyzeDataChunk (const char *chunk, int32_t chunkSize);
nsresult LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion); //A similar function already exist in nsMsgCompose!
#ifdef XP_MACOSX
nsresult ConvertToAppleEncoding(const nsCString &aFileSpecURI,
const nsCString &aFilePath,
nsILocalFileMac *aSourceFile);
// zips this attachment and does the work to make this attachment handler handle it properly.
nsresult ConvertToZipFile(nsILocalFileMac *aSourceFile);
bool HasResourceFork(FSRef *fsRef);
#endif
//
public:
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIFile> mTmpFile; // The temp file to which we save it
nsCOMPtr<nsIOutputStream> mOutFile;
nsCOMPtr<nsIRequest> mRequest; // The live request used while fetching an attachment
nsMsgCompFields *mCompFields; // Message composition fields for the sender
bool m_bogus_attachment; // This is to catch problem children...
#ifdef XP_MACOSX
// if we need to encode this file into for example an appledouble, or zip file,
// this file is our working file. currently only needed on mac.
nsCOMPtr<nsIFile> mEncodedWorkingFile;
#endif
nsCString m_xMacType; // Mac file type
nsCString m_xMacCreator; // Mac file creator
bool m_done;
nsCString m_charset; // charset name
nsCString m_contentId; // This is for mutipart/related Content-ID's
nsCString m_type; // The real type, once we know it.
nsCString m_typeParam; // Any addition parameters to add to the content-type (other than charset, macType and maccreator)
nsCString m_overrideType; // The type we should assume it to be
// or 0, if we should get it from the
// server)
nsCString m_overrideEncoding; // Goes along with override_type
nsCString m_desiredType; // The type it should be converted to.
nsCString m_description; // For Content-Description header
nsCString m_realName; // The name for the headers, if different
// from the URL.
nsCString m_encoding; // The encoding, once we've decided. */
bool m_already_encoded_p; // If we attach a document that is already
// encoded, we just pass it through.
bool m_decrypted_p; /* S/MIME -- when attaching a message that was
encrypted, it's necessary to decrypt it first
(since nobody but the original recipient can
read it -- if you forward it to someone in the
raw, it will be useless to them.) This flag
indicates whether decryption occurred, so that
libmsg can issue appropriate warnings about
doing a cleartext forward of a message that was
originally encrypted. */
bool mDeleteFile; // If this is true, Delete the file...its
// NOT the original file!
bool mMHTMLPart; // This is true if its an MHTML part, otherwise, false
bool mPartUserOmissionOverride; // This is true if the user send send the email without this part
bool mMainBody; // True if this is a main body.
// true if this should be sent as a link to a file.
bool mSendViaCloud;
nsString mHtmlAnnotation;
nsCString mCloudProviderKey;
nsCString mCloudUrl;
int32_t mNodeIndex; //If this is an embedded image, this is the index of the
// corresponding domNode in the editor's
//GetEmbeddedObjects. Otherwise, it will be -1.
//
// Vars for analyzing file data...
//
uint32_t m_size; /* Some state used while filtering it */
uint32_t m_unprintable_count;
uint32_t m_highbit_count;
uint32_t m_ctl_count;
uint32_t m_null_count;
uint8_t m_have_cr, m_have_lf, m_have_crlf;
bool m_prev_char_was_cr;
uint32_t m_current_column;
uint32_t m_max_column;
uint32_t m_lines;
bool m_file_analyzed;
nsAutoPtr<MimeEncoder> m_encoder;
nsCString m_uri; // original uri string
nsresult GetMimeDeliveryState(nsIMsgSend** _retval);
nsresult SetMimeDeliveryState(nsIMsgSend* mime_delivery_state);
private:
nsCOMPtr<nsIMsgSend> m_mime_delivery_state;
nsCOMPtr<nsIStreamConverter> m_mime_parser;
nsCOMPtr<nsIChannel> m_converter_channel;
};
#endif /* _nsMsgAttachmentHandler_H_ */

View file

@ -0,0 +1,693 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgCompose.h"
#include "nsMsgCompFields.h"
#include "nsMsgI18N.h"
#include "nsMsgCompUtils.h"
#include "nsMsgUtils.h"
#include "prmem.h"
#include "nsIFileChannel.h"
#include "nsIMsgAttachment.h"
#include "nsIMsgMdnGenerator.h"
#include "nsServiceManagerUtils.h"
#include "nsMsgMimeCID.h"
#include "nsArrayEnumerator.h"
#include "nsMemory.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
struct HeaderInfo {
/// Header name
const char *mName;
/// If true, nsMsgCompFields should reflect the raw header value instead of
/// the unstructured header value.
bool mStructured;
};
// This is a mapping of the m_headers local set to the actual header name we
// store on the structured header object.
static HeaderInfo kHeaders[] = {
{ "From", true },
{ "Reply-To", true },
{ "To", true },
{ "Cc", true },
{ "Bcc", true },
{ nullptr, false }, // FCC
{ nullptr, false }, // FCC2
{ "Newsgroups", true },
{ "Followup-To", true },
{ "Subject", false },
{ "Organization", false },
{ "References", true },
{ "X-Mozilla-News-Host", false },
{ "X-Priority", false },
{ nullptr, false }, // CHARACTER_SET
{ "Message-Id", true },
{ "X-Template", true },
{ nullptr, false }, // DRAFT_ID
{ "Content-Language", true },
{ nullptr, false } // CREATOR IDENTITY KEY
};
static_assert(MOZ_ARRAY_LENGTH(kHeaders) ==
nsMsgCompFields::MSG_MAX_HEADERS,
"These two arrays need to be kept in sync or bad things will happen!");
NS_IMPL_ISUPPORTS(nsMsgCompFields, nsIMsgCompFields, msgIStructuredHeaders,
msgIWritableStructuredHeaders)
nsMsgCompFields::nsMsgCompFields()
: mStructuredHeaders(do_CreateInstance(NS_ISTRUCTUREDHEADERS_CONTRACTID))
{
m_body.Truncate();
m_attachVCard = false;
m_forcePlainText = false;
m_useMultipartAlternative = false;
m_returnReceipt = false;
m_receiptHeaderType = nsIMsgMdnGenerator::eDntType;
m_DSN = false;
m_bodyIsAsciiOnly = false;
m_forceMsgEncoding = false;
m_needToCheckCharset = true;
m_attachmentReminder = false;
m_deliveryFormat = nsIMsgCompSendFormat::AskUser;
// Get the default charset from pref, use this as a mail charset.
nsString charset;
NS_GetLocalizedUnicharPreferenceWithDefault(nullptr, "mailnews.send_default_charset",
NS_LITERAL_STRING("UTF-8"), charset);
LossyCopyUTF16toASCII(charset, m_DefaultCharacterSet); // Charsets better be ASCII
SetCharacterSet(m_DefaultCharacterSet.get());
}
nsMsgCompFields::~nsMsgCompFields()
{
}
nsresult nsMsgCompFields::SetAsciiHeader(MsgHeaderID header, const char *value)
{
NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS,
"Invalid message header index!");
// If we are storing this on the structured header object, we need to set the
// value on that object as well. Note that the value may be null, which we'll
// take as an attempt to delete the header.
const char *headerName = kHeaders[header].mName;
if (headerName)
{
if (!value || !*value)
return mStructuredHeaders->DeleteHeader(headerName);
return mStructuredHeaders->SetRawHeader(headerName,
nsDependentCString(value), "UTF-8");
}
// Not on the structurd header object, so save it locally.
m_headers[header] = value;
return NS_OK;
}
const char* nsMsgCompFields::GetAsciiHeader(MsgHeaderID header)
{
NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS,
"Invalid message header index!");
const char *headerName = kHeaders[header].mName;
if (headerName)
{
// We may be out of sync with the structured header object. Retrieve the
// header value.
if (kHeaders[header].mStructured)
{
mStructuredHeaders->GetRawHeader(headerName, m_headers[header]);
}
else
{
nsString value;
mStructuredHeaders->GetUnstructuredHeader(headerName, value);
CopyUTF16toUTF8(value, m_headers[header]);
}
}
return m_headers[header].get();
}
nsresult nsMsgCompFields::SetUnicodeHeader(MsgHeaderID header, const nsAString& value)
{
return SetAsciiHeader(header, NS_ConvertUTF16toUTF8(value).get());
}
nsresult nsMsgCompFields::GetUnicodeHeader(MsgHeaderID header, nsAString& aResult)
{
CopyUTF8toUTF16(nsDependentCString(GetAsciiHeader(header)), aResult);
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetFrom(const nsAString &value)
{
return SetUnicodeHeader(MSG_FROM_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetFrom(nsAString &_retval)
{
return GetUnicodeHeader(MSG_FROM_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetReplyTo(const nsAString &value)
{
return SetUnicodeHeader(MSG_REPLY_TO_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetReplyTo(nsAString &_retval)
{
return GetUnicodeHeader(MSG_REPLY_TO_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetTo(const nsAString &value)
{
return SetUnicodeHeader(MSG_TO_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetTo(nsAString &_retval)
{
return GetUnicodeHeader(MSG_TO_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetCc(const nsAString &value)
{
return SetUnicodeHeader(MSG_CC_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetCc(nsAString &_retval)
{
return GetUnicodeHeader(MSG_CC_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetBcc(const nsAString &value)
{
return SetUnicodeHeader(MSG_BCC_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetBcc(nsAString &_retval)
{
return GetUnicodeHeader(MSG_BCC_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetFcc(const nsAString &value)
{
return SetUnicodeHeader(MSG_FCC_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetFcc(nsAString &_retval)
{
return GetUnicodeHeader(MSG_FCC_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetFcc2(const nsAString &value)
{
return SetUnicodeHeader(MSG_FCC2_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetFcc2(nsAString &_retval)
{
return GetUnicodeHeader(MSG_FCC2_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetNewsgroups(const nsAString &aValue)
{
return SetUnicodeHeader(MSG_NEWSGROUPS_HEADER_ID, aValue);
}
NS_IMETHODIMP nsMsgCompFields::GetNewsgroups(nsAString &aGroup)
{
return GetUnicodeHeader(MSG_NEWSGROUPS_HEADER_ID, aGroup);
}
NS_IMETHODIMP nsMsgCompFields::SetFollowupTo(const nsAString &aValue)
{
return SetUnicodeHeader(MSG_FOLLOWUP_TO_HEADER_ID, aValue);
}
NS_IMETHODIMP nsMsgCompFields::GetFollowupTo(nsAString &_retval)
{
return GetUnicodeHeader(MSG_FOLLOWUP_TO_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::GetHasRecipients(bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = NS_SUCCEEDED(mime_sanity_check_fields_recipients(
GetTo(), GetCc(), GetBcc(), GetNewsgroups()));
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetCreatorIdentityKey(const char *value)
{
return SetAsciiHeader(MSG_CREATOR_IDENTITY_KEY_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetCreatorIdentityKey(char **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = strdup(GetAsciiHeader(MSG_CREATOR_IDENTITY_KEY_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetSubject(const nsAString &value)
{
return SetUnicodeHeader(MSG_SUBJECT_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetSubject(nsAString &_retval)
{
return GetUnicodeHeader(MSG_SUBJECT_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetOrganization(const nsAString &value)
{
return SetUnicodeHeader(MSG_ORGANIZATION_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetOrganization(nsAString &_retval)
{
return GetUnicodeHeader(MSG_ORGANIZATION_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetReferences(const char *value)
{
return SetAsciiHeader(MSG_REFERENCES_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetReferences(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_REFERENCES_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetNewspostUrl(const char *value)
{
return SetAsciiHeader(MSG_NEWSPOSTURL_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetNewspostUrl(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_NEWSPOSTURL_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetPriority(const char *value)
{
return SetAsciiHeader(MSG_PRIORITY_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetPriority(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_PRIORITY_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetCharacterSet(const char *value)
{
return SetAsciiHeader(MSG_CHARACTER_SET_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetCharacterSet(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_CHARACTER_SET_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetMessageId(const char *value)
{
return SetAsciiHeader(MSG_MESSAGE_ID_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetMessageId(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_MESSAGE_ID_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetTemplateName(const nsAString &value)
{
return SetUnicodeHeader(MSG_X_TEMPLATE_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetTemplateName(nsAString &_retval)
{
return GetUnicodeHeader(MSG_X_TEMPLATE_HEADER_ID, _retval);
}
NS_IMETHODIMP nsMsgCompFields::SetDraftId(const char *value)
{
return SetAsciiHeader(MSG_DRAFT_ID_HEADER_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetDraftId(char **_retval)
{
*_retval = strdup(GetAsciiHeader(MSG_DRAFT_ID_HEADER_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetReturnReceipt(bool value)
{
m_returnReceipt = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetReturnReceipt(bool *_retval)
{
*_retval = m_returnReceipt;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetReceiptHeaderType(int32_t value)
{
m_receiptHeaderType = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetReceiptHeaderType(int32_t *_retval)
{
*_retval = m_receiptHeaderType;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetDSN(bool value)
{
m_DSN = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetDSN(bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = m_DSN;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetAttachVCard(bool value)
{
m_attachVCard = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetAttachVCard(bool *_retval)
{
*_retval = m_attachVCard;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetAttachmentReminder(bool *_retval)
{
*_retval = m_attachmentReminder;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetAttachmentReminder(bool value)
{
m_attachmentReminder = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetDeliveryFormat(int32_t value)
{
switch (value) {
case nsIMsgCompSendFormat::AskUser:
case nsIMsgCompSendFormat::PlainText:
case nsIMsgCompSendFormat::HTML:
case nsIMsgCompSendFormat::Both:
m_deliveryFormat = value;
break;
default:
m_deliveryFormat = nsIMsgCompSendFormat::AskUser;
}
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetDeliveryFormat(int32_t *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = m_deliveryFormat;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetContentLanguage(const char *value)
{
return SetAsciiHeader(MSG_CONTENT_LANGUAGE_ID, value);
}
NS_IMETHODIMP nsMsgCompFields::GetContentLanguage(char **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = strdup(GetAsciiHeader(MSG_CONTENT_LANGUAGE_ID));
return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::SetForcePlainText(bool value)
{
m_forcePlainText = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetForcePlainText(bool *_retval)
{
*_retval = m_forcePlainText;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetForceMsgEncoding(bool value)
{
m_forceMsgEncoding = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetForceMsgEncoding(bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = m_forceMsgEncoding;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetUseMultipartAlternative(bool value)
{
m_useMultipartAlternative = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetUseMultipartAlternative(bool *_retval)
{
*_retval = m_useMultipartAlternative;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetBodyIsAsciiOnly(bool value)
{
m_bodyIsAsciiOnly = value;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetBodyIsAsciiOnly(bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = m_bodyIsAsciiOnly;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetBody(const nsAString &value)
{
CopyUTF16toUTF8(value, m_body);
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetBody(nsAString &_retval)
{
CopyUTF8toUTF16(m_body, _retval);
return NS_OK;
}
nsresult nsMsgCompFields::SetBody(const char *value)
{
if (value)
m_body = value;
else
m_body.Truncate();
return NS_OK;
}
const char* nsMsgCompFields::GetBody()
{
return m_body.get();
}
/* readonly attribute nsISimpleEnumerator attachmentsArray; */
NS_IMETHODIMP nsMsgCompFields::GetAttachments(nsISimpleEnumerator * *aAttachmentsEnum)
{
return aAttachmentsEnum ? NS_NewArrayEnumerator(aAttachmentsEnum, m_attachments) : NS_ERROR_NULL_POINTER;
}
/* void addAttachment (in nsIMsgAttachment attachment); */
NS_IMETHODIMP nsMsgCompFields::AddAttachment(nsIMsgAttachment *attachment)
{
int32_t attachmentCount = m_attachments.Count();
//Don't add twice the same attachment.
nsCOMPtr<nsIMsgAttachment> element;
bool sameUrl;
for (int32_t i = 0; i < attachmentCount; i ++)
{
m_attachments[i]->EqualsUrl(attachment, &sameUrl);
if (sameUrl)
return NS_OK;
}
m_attachments.AppendObject(attachment);
return NS_OK;
}
/* void removeAttachment (in nsIMsgAttachment attachment); */
NS_IMETHODIMP nsMsgCompFields::RemoveAttachment(nsIMsgAttachment *attachment)
{
int32_t attachmentCount = m_attachments.Count();
nsCOMPtr<nsIMsgAttachment> element;
bool sameUrl;
for (int32_t i = 0; i < attachmentCount; i ++)
{
m_attachments[i]->EqualsUrl(attachment, &sameUrl);
if (sameUrl)
{
m_attachments.RemoveObjectAt(i);
break;
}
}
return NS_OK;
}
/* void removeAttachments (); */
NS_IMETHODIMP nsMsgCompFields::RemoveAttachments()
{
m_attachments.Clear();
return NS_OK;
}
// This method is called during the creation of a new window.
NS_IMETHODIMP
nsMsgCompFields::SplitRecipients(const nsAString &aRecipients,
bool aEmailAddressOnly,
uint32_t *aLength,
char16_t*** aResult)
{
NS_ENSURE_ARG_POINTER(aLength);
NS_ENSURE_ARG_POINTER(aResult);
*aLength = 0;
*aResult = nullptr;
nsCOMArray<msgIAddressObject> header(EncodedHeader(NS_ConvertUTF16toUTF8(aRecipients)));
nsTArray<nsString> results;
if (aEmailAddressOnly)
ExtractEmails(header, results);
else
ExtractDisplayAddresses(header, results);
uint32_t count = results.Length();
char16_t **result = (char16_t **)NS_Alloc(sizeof(char16_t *) * count);
for (uint32_t i = 0; i < count; ++i)
result[i] = ToNewUnicode(results[i]);
*aResult = result;
*aLength = count;
return NS_OK;
}
// This method is called during the sending of message from nsMsgCompose::CheckAndPopulateRecipients()
nsresult nsMsgCompFields::SplitRecipientsEx(const nsAString &recipients,
nsTArray<nsMsgRecipient> &aResult)
{
nsTArray<nsString> names, addresses;
ExtractAllAddresses(EncodedHeader(NS_ConvertUTF16toUTF8(recipients)), names,
addresses);
uint32_t numAddresses = names.Length();
for (uint32_t i = 0; i < numAddresses; ++i)
{
nsMsgRecipient msgRecipient;
msgRecipient.mEmail = addresses[i];
msgRecipient.mName = names[i];
aResult.AppendElement(msgRecipient);
}
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::ConvertBodyToPlainText()
{
nsresult rv = NS_OK;
if (!m_body.IsEmpty())
{
nsAutoString body;
rv = GetBody(body);
if (NS_SUCCEEDED(rv))
{
bool flowed, delsp, formatted, disallowBreaks;
GetSerialiserFlags(GetCharacterSet(), &flowed, &delsp, &formatted, &disallowBreaks);
rv = ConvertBufToPlainText(body, flowed, delsp, formatted, disallowBreaks);
if (NS_SUCCEEDED(rv))
rv = SetBody(body);
}
}
return rv;
}
NS_IMETHODIMP nsMsgCompFields::GetSecurityInfo(nsISupports ** aSecurityInfo)
{
NS_ENSURE_ARG_POINTER(aSecurityInfo);
*aSecurityInfo = mSecureCompFields;
NS_IF_ADDREF(*aSecurityInfo);
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetSecurityInfo(nsISupports * aSecurityInfo)
{
mSecureCompFields = aSecurityInfo;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::GetDefaultCharacterSet(char * *aDefaultCharacterSet)
{
NS_ENSURE_ARG_POINTER(aDefaultCharacterSet);
*aDefaultCharacterSet = ToNewCString(m_DefaultCharacterSet);
return *aDefaultCharacterSet ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMETHODIMP nsMsgCompFields::GetNeedToCheckCharset(bool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = m_needToCheckCharset;
return NS_OK;
}
NS_IMETHODIMP nsMsgCompFields::SetNeedToCheckCharset(bool aCheck)
{
m_needToCheckCharset = aCheck;
return NS_OK;
}

View file

@ -0,0 +1,172 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MsgCompFields_H_
#define _MsgCompFields_H_
#include "nsIMsgCompFields.h"
#include "msgCore.h"
#include "nsIAbCard.h"
#include "nsIAbDirectory.h"
#include "nsTArray.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
struct nsMsgRecipient
{
nsString mName;
nsString mEmail;
nsCOMPtr<nsIAbCard> mCard;
nsCOMPtr<nsIAbDirectory> mDirectory;
};
/* 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 nsMsgCompFields : public nsIMsgCompFields {
public:
nsMsgCompFields();
/* this macro defines QueryInterface, AddRef and Release for this class */
NS_DECL_THREADSAFE_ISUPPORTS
NS_FORWARD_MSGISTRUCTUREDHEADERS(mStructuredHeaders->)
NS_FORWARD_MSGIWRITABLESTRUCTUREDHEADERS(mStructuredHeaders->)
NS_DECL_NSIMSGCOMPFIELDS
// Allow the C++ utility methods for people who use a concrete class instead
// of the interfaces.
using msgIStructuredHeaders::GetAddressingHeader;
using msgIWritableStructuredHeaders::SetAddressingHeader;
typedef enum MsgHeaderID
{
MSG_FROM_HEADER_ID = 0,
MSG_REPLY_TO_HEADER_ID,
MSG_TO_HEADER_ID,
MSG_CC_HEADER_ID,
MSG_BCC_HEADER_ID,
MSG_FCC_HEADER_ID,
MSG_FCC2_HEADER_ID,
MSG_NEWSGROUPS_HEADER_ID,
MSG_FOLLOWUP_TO_HEADER_ID,
MSG_SUBJECT_HEADER_ID,
MSG_ORGANIZATION_HEADER_ID,
MSG_REFERENCES_HEADER_ID,
MSG_NEWSPOSTURL_HEADER_ID,
MSG_PRIORITY_HEADER_ID,
MSG_CHARACTER_SET_HEADER_ID,
MSG_MESSAGE_ID_HEADER_ID,
MSG_X_TEMPLATE_HEADER_ID,
MSG_DRAFT_ID_HEADER_ID,
MSG_CONTENT_LANGUAGE_ID,
MSG_CREATOR_IDENTITY_KEY_ID,
MSG_MAX_HEADERS //Must be the last one.
} MsgHeaderID;
nsresult SetAsciiHeader(MsgHeaderID header, const char *value);
const char* GetAsciiHeader(MsgHeaderID header); //just return the address of the internal header variable, don't dispose it
nsresult SetUnicodeHeader(MsgHeaderID header, const nsAString &value);
nsresult GetUnicodeHeader(MsgHeaderID header, nsAString &_retval);
/* Convenience routines to get and set header's value...
IMPORTANT:
all routines const char* GetXxx(void) will return a pointer to the header, please don't free it.
*/
nsresult SetFrom(const char *value) {return SetAsciiHeader(MSG_FROM_HEADER_ID, value);}
const char* GetFrom(void) {return GetAsciiHeader(MSG_FROM_HEADER_ID);}
nsresult SetReplyTo(const char *value) {return SetAsciiHeader(MSG_REPLY_TO_HEADER_ID, value);}
const char* GetReplyTo() {return GetAsciiHeader(MSG_REPLY_TO_HEADER_ID);}
nsresult SetTo(const char *value) {return SetAsciiHeader(MSG_TO_HEADER_ID, value);}
const char* GetTo() {return GetAsciiHeader(MSG_TO_HEADER_ID);}
nsresult SetCc(const char *value) {return SetAsciiHeader(MSG_CC_HEADER_ID, value);}
const char* GetCc() {return GetAsciiHeader(MSG_CC_HEADER_ID);}
nsresult SetBcc(const char *value) {return SetAsciiHeader(MSG_BCC_HEADER_ID, value);}
const char* GetBcc() {return GetAsciiHeader(MSG_BCC_HEADER_ID);}
nsresult SetFcc(const char *value) {return SetAsciiHeader(MSG_FCC_HEADER_ID, value);}
const char* GetFcc() {return GetAsciiHeader(MSG_FCC_HEADER_ID);}
nsresult SetFcc2(const char *value) {return SetAsciiHeader(MSG_FCC2_HEADER_ID, value);}
const char* GetFcc2() {return GetAsciiHeader(MSG_FCC2_HEADER_ID);}
nsresult SetNewsgroups(const char *aValue) {return SetAsciiHeader(MSG_NEWSGROUPS_HEADER_ID, aValue);}
const char* GetNewsgroups() {return GetAsciiHeader(MSG_NEWSGROUPS_HEADER_ID);}
nsresult SetFollowupTo(const char *aValue) {return SetAsciiHeader(MSG_FOLLOWUP_TO_HEADER_ID, aValue);}
const char* GetFollowupTo() {return GetAsciiHeader(MSG_FOLLOWUP_TO_HEADER_ID);}
nsresult SetSubject(const char *value) {return SetAsciiHeader(MSG_SUBJECT_HEADER_ID, value);}
const char* GetSubject() {return GetAsciiHeader(MSG_SUBJECT_HEADER_ID);}
nsresult SetOrganization(const char *value) {return SetAsciiHeader(MSG_ORGANIZATION_HEADER_ID, value);}
const char* GetOrganization() {return GetAsciiHeader(MSG_ORGANIZATION_HEADER_ID);}
const char* GetReferences() {return GetAsciiHeader(MSG_REFERENCES_HEADER_ID);}
const char* GetNewspostUrl() {return GetAsciiHeader(MSG_NEWSPOSTURL_HEADER_ID);}
const char* GetPriority() {return GetAsciiHeader(MSG_PRIORITY_HEADER_ID);}
const char* GetCharacterSet() {return GetAsciiHeader(MSG_CHARACTER_SET_HEADER_ID);}
const char* GetMessageId() {return GetAsciiHeader(MSG_MESSAGE_ID_HEADER_ID);}
nsresult SetTemplateName(const char *value) {return SetAsciiHeader(MSG_X_TEMPLATE_HEADER_ID, value);}
const char* GetTemplateName() {return GetAsciiHeader(MSG_X_TEMPLATE_HEADER_ID);}
const char* GetDraftId() {return GetAsciiHeader(MSG_DRAFT_ID_HEADER_ID);}
const char* GetContentLanguage() {return GetAsciiHeader(MSG_CONTENT_LANGUAGE_ID);}
bool GetReturnReceipt() {return m_returnReceipt;}
bool GetDSN() {return m_DSN;}
bool GetAttachVCard() {return m_attachVCard;}
bool GetAttachmentReminder() {return m_attachmentReminder;}
int32_t GetDeliveryFormat() {return m_deliveryFormat;}
bool GetForcePlainText() {return m_forcePlainText;}
bool GetUseMultipartAlternative() {return m_useMultipartAlternative;}
bool GetBodyIsAsciiOnly() {return m_bodyIsAsciiOnly;}
bool GetForceMsgEncoding() {return m_forceMsgEncoding;}
nsresult SetBody(const char *value);
const char* GetBody();
nsresult SplitRecipientsEx(const nsAString &recipients,
nsTArray<nsMsgRecipient> &aResult);
protected:
virtual ~nsMsgCompFields();
nsCString m_headers[MSG_MAX_HEADERS];
nsCString m_body;
nsCOMArray<nsIMsgAttachment> m_attachments;
bool m_attachVCard;
bool m_attachmentReminder;
int32_t m_deliveryFormat;
bool m_forcePlainText;
bool m_useMultipartAlternative;
bool m_returnReceipt;
bool m_DSN;
bool m_bodyIsAsciiOnly;
bool m_forceMsgEncoding;
int32_t m_receiptHeaderType; /* receipt header type */
nsCString m_DefaultCharacterSet;
bool m_needToCheckCharset;
nsCOMPtr<nsISupports> mSecureCompFields;
nsCOMPtr<msgIWritableStructuredHeaders> mStructuredHeaders;
};
#endif /* _MsgCompFields_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgCompUtils_H_
#define _nsMsgCompUtils_H_
#include "nscore.h"
#include "nsMsgSend.h"
#include "nsMsgCompFields.h"
#include "nsIMsgSend.h"
#include "nsIMsgCompUtils.h"
class nsIPrompt;
#define ANY_SERVER "anyfolder://"
// these are msg hdr property names for storing the original
// msg uri's and disposition(replied/forwarded) when queuing
// messages to send later.
#define ORIG_URI_PROPERTY "origURIs"
#define QUEUED_DISPOSITION_PROPERTY "queuedDisposition"
class nsMsgCompUtils : public nsIMsgCompUtils
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGCOMPUTILS
nsMsgCompUtils();
private:
virtual ~nsMsgCompUtils();
};
PR_BEGIN_EXTERN_C
//
// Create a file spec or file name using the name passed
// in as a template
//
nsresult nsMsgCreateTempFile(const char *tFileName, nsIFile **tFile);
char *nsMsgCreateTempFileName(const char *tFileName);
//
// Various utilities for building parts of MIME encoded
// messages during message composition
//
nsresult mime_sanity_check_fields_recipients (
const char *to,
const char *cc,
const char *bcc,
const char *newsgroups);
nsresult mime_sanity_check_fields (
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 * /*subject*/,
const char * /*references*/,
const char * /*organization*/,
const char * /*other_random_headers*/);
nsresult mime_generate_headers(nsIMsgCompFields *fields,
nsMsgDeliverMode deliver_mode,
msgIWritableStructuredHeaders *headers);
char *mime_make_separator(const char *prefix);
char *mime_gen_content_id(uint32_t aPartNum, const char *aEmailAddress);
char *mime_generate_attachment_headers (
const char *type,
const char *type_param,
const char *encoding,
const char *description,
const char *x_mac_type,
const char *x_mac_creator,
const char *real_name,
const char *base_url,
bool digest_p,
nsMsgAttachmentHandler *ma,
const char *attachmentCharset, // charset of the attachment (can be null)
const char *bodyCharset, // charset of the main body
bool bodyIsAsciiOnly,
const char *content_id,
bool aBodyDocument);
char *msg_generate_message_id (nsIMsgIdentity*);
bool mime_7bit_data_p (const char *string, uint32_t size);
char *mime_fix_header_1 (const char *string, bool addr_p, bool news_p);
char *mime_fix_header (const char *string);
char *mime_fix_addr_header (const char *string);
char *mime_fix_news_header (const char *string);
bool mime_type_requires_b64_p (const char *type);
bool mime_type_needs_charset (const char *type);
char *msg_make_filename_qtext(const char *srcText, bool stripCRLFs);
// Rip apart the URL and extract a reasonable value for the `real_name' slot.
void msg_pick_real_name (nsMsgAttachmentHandler *attachment, const char16_t *proposedName, const char *charset);
//
// Informational calls...
//
void nsMsgMIMESetConformToStandard (bool conform_p);
bool nsMsgMIMEGetConformToStandard (void);
//
// network service type calls...
//
nsresult nsMsgNewURL(nsIURI** aInstancePtrResult, const char * aSpec);
bool nsMsgIsLocalFile(const char *url);
char *nsMsgGetLocalFileFromURL(const char *url);
char *nsMsgParseURLHost(const char *url);
char *GenerateFileNameFromURI(nsIURI *aURL);
//
// Folder calls...
//
void GetFolderURIFromUserPrefs(nsMsgDeliverMode aMode, nsIMsgIdentity *identity, nsCString& uri);
// Check if we should use format=flowed
void GetSerialiserFlags(const char *charset, bool *flowed, bool *delsp, bool *formatted, bool *disallowBreaks);
PR_END_EXTERN_C
#endif /* _nsMsgCompUtils_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,246 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgCompose_H_
#define _nsMsgCompose_H_
#include "nsIMsgCompose.h"
#include "nsCOMArray.h"
#include "nsTObserverArray.h"
#include "nsWeakReference.h"
#include "nsMsgCompFields.h"
#include "nsIOutputStream.h"
#include "nsIMsgQuote.h"
#include "nsIMsgCopyServiceListener.h"
#include "nsIBaseWindow.h"
#include "nsIAbDirectory.h"
#include "nsIWebProgressListener.h"
#include "nsIMimeConverter.h"
#include "nsIUnicodeDecoder.h"
#include "nsIMsgFolder.h"
#include "nsIDOMNode.h"
#include "mozIDOMWindow.h"
// Forward declares
class QuotingOutputStreamListener;
class nsMsgComposeSendListener;
class nsIEditorMailSupport;
class nsIRDFService;
class nsIArray;
struct nsMsgMailList;
class nsMsgCompose : public nsIMsgCompose, public nsSupportsWeakReference
{
public:
nsMsgCompose();
/* this macro defines QueryInterface, AddRef and Release for this class */
NS_DECL_THREADSAFE_ISUPPORTS
/*** nsIMsgCompose pure virtual functions */
NS_DECL_NSIMSGCOMPOSE
/* nsIMsgSendListener interface */
NS_DECL_NSIMSGSENDLISTENER
protected:
virtual ~nsMsgCompose();
// Deal with quoting issues...
nsresult QuoteOriginalMessage(); // New template
nsresult SetQuotingToFollow(bool aVal);
nsresult ConvertHTMLToText(nsIFile *aSigFile, nsString &aSigData);
nsresult ConvertTextToHTML(nsIFile *aSigFile, nsString &aSigData);
bool IsEmbeddedObjectSafe(const char * originalScheme,
const char * originalHost,
const char * originalPath,
nsIDOMNode * object);
nsresult ResetUrisForEmbeddedObjects();
nsresult TagEmbeddedObjects(nsIEditorMailSupport *aMailEditor);
nsCString mQuoteCharset;
nsCString mOriginalMsgURI; // used so we can mark message disposition flags after we send the message
int32_t mWhatHolder;
nsresult LoadDataFromFile(nsIFile *file,
nsString &sigData,
bool aAllowUTF8 = true,
bool aAllowUTF16 = true);
bool CheckIncludeSignaturePrefs(nsIMsgIdentity *identity);
//m_folderName to store the value of the saved drafts folder.
nsCString m_folderName;
void InsertDivWrappedTextAtSelection(const nsAString &aText,
const nsAString &classStr);
protected:
nsresult CreateMessage(const char * originalMsgURI, MSG_ComposeType type, nsIMsgCompFields* compFields);
void CleanUpRecipients(nsString& recipients);
nsresult GetABDirAndMailLists(const nsACString& aDirUri,
nsCOMArray<nsIAbDirectory>& aDirArray,
nsTArray<nsMsgMailList>& aMailListArray);
nsresult ResolveMailList(nsIAbDirectory* aMailList,
nsCOMArray<nsIAbDirectory>& allDirectoriesArray,
nsTArray<nsMsgMailList>& allMailListArray,
nsTArray<nsMsgMailList>& mailListResolved,
nsTArray<nsMsgRecipient>& aListMembers);
nsresult TagConvertible(nsIDOMElement *node, int32_t *_retval);
nsresult _NodeTreeConvertible(nsIDOMElement *node, int32_t *_retval);
nsresult MoveToAboveQuote(void);
nsresult MoveToBeginningOfDocument(void);
nsresult MoveToEndOfDocument(void);
nsresult ReplaceFileURLs(nsAutoString &sigData);
nsresult DataURLForFileURL(const nsAString &aFileURL, nsAString &aDataURL);
// 3 = To, Cc, Bcc
#define MAX_OF_RECIPIENT_ARRAY 3
typedef nsTArray<nsMsgRecipient> RecipientsArray[MAX_OF_RECIPIENT_ARRAY];
/**
* This method parses the compose fields and associates email addresses with
* the relevant cards from the address books.
*/
nsresult LookupAddressBook(RecipientsArray &recipientList);
bool IsLastWindow();
// Helper function. Parameters are not checked.
bool mConvertStructs; // for TagConvertible
nsCOMPtr<nsIEditor> m_editor;
mozIDOMWindowProxy *m_window;
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIBaseWindow> m_baseWindow;
nsMsgCompFields *m_compFields;
nsCOMPtr<nsIMsgIdentity> m_identity;
bool m_composeHTML;
QuotingOutputStreamListener *mQuoteStreamListener;
nsCOMPtr<nsIOutputStream> mBaseStream;
nsCOMPtr<nsIMsgSend> mMsgSend; // for composition back end
nsCOMPtr<nsIMsgProgress> mProgress; // use by the back end to report progress to the front end
// Deal with quoting issues...
nsString mCiteReference;
nsCOMPtr<nsIMsgQuote> mQuote;
bool mQuotingToFollow; // Quoting indicator
MSG_ComposeType mType; // Message type
bool mCharsetOverride;
bool mAnswerDefaultCharset;
bool mDeleteDraft;
nsMsgDispositionState mDraftDisposition;
nsCOMPtr <nsIMsgDBHdr> mOrigMsgHdr;
nsCString mSmtpPassword;
nsCString mHtmlToQuote;
nsTObserverArray<nsCOMPtr<nsIMsgComposeStateListener> > mStateListeners;
nsTObserverArray<nsCOMPtr<nsIMsgSendListener> > mExternalSendListeners;
bool mInsertingQuotedContent;
MSG_DeliverMode mDeliverMode; // nsIMsgCompDeliverMode long.
friend class QuotingOutputStreamListener;
friend class nsMsgComposeSendListener;
};
////////////////////////////////////////////////////////////////////////////////////
// THIS IS THE CLASS THAT IS THE STREAM Listener OF THE HTML OUPUT
// FROM LIBMIME. THIS IS FOR QUOTING
////////////////////////////////////////////////////////////////////////////////////
class QuotingOutputStreamListener : public nsIMsgQuotingOutputStreamListener
{
public:
QuotingOutputStreamListener(const char *originalMsgURI,
nsIMsgDBHdr *origMsgHdr,
bool quoteHeaders,
bool headersOnly,
nsIMsgIdentity *identity,
nsIMsgQuote* msgQuote,
bool charsetFixed,
bool quoteOriginal,
const nsACString& htmlToQuote);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIMSGQUOTINGOUTPUTSTREAMLISTENER
NS_IMETHOD SetComposeObj(nsIMsgCompose *obj);
NS_IMETHOD ConvertToPlainText(bool formatflowed,
bool delsp,
bool formatted,
bool disallowBreaks);
NS_IMETHOD InsertToCompose(nsIEditor *aEditor, bool aHTMLEditor);
NS_IMETHOD AppendToMsgBody(const nsCString &inStr);
private:
virtual ~QuotingOutputStreamListener();
nsWeakPtr mWeakComposeObj;
nsString mMsgBody;
nsString mCitePrefix;
nsString mSignature;
bool mQuoteHeaders;
bool mHeadersOnly;
bool mCharsetFixed;
nsCOMPtr<nsIMsgQuote> mQuote;
nsCOMPtr<nsIMimeHeaders> mHeaders;
nsCOMPtr<nsIMsgIdentity> mIdentity;
nsCOMPtr<nsIMsgDBHdr> mOrigMsgHdr;
nsString mCiteReference;
nsCOMPtr<nsIMimeConverter> mMimeConverter;
nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
int32_t mUnicodeBufferCharacterLength;
char16_t* mUnicodeConversionBuffer;
bool mQuoteOriginal;
nsCString mHtmlToQuote;
};
////////////////////////////////////////////////////////////////////////////////////
// This is the listener class for the send operation. We have to create this class
// to listen for message send completion and eventually notify the caller
////////////////////////////////////////////////////////////////////////////////////
class nsMsgComposeSendListener : public nsIMsgComposeSendListener, public nsIMsgSendListener, public nsIMsgCopyServiceListener, public nsIWebProgressListener
{
public:
nsMsgComposeSendListener(void);
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIMsgComposeSendListener interface
NS_DECL_NSIMSGCOMPOSESENDLISTENER
// nsIMsgSendListener interface
NS_DECL_NSIMSGSENDLISTENER
// nsIMsgCopyServiceListener interface
NS_DECL_NSIMSGCOPYSERVICELISTENER
// nsIWebProgressListener interface
NS_DECL_NSIWEBPROGRESSLISTENER
nsresult RemoveCurrentDraftMessage(nsIMsgCompose *compObj, bool calledByCopy);
nsresult GetMsgFolder(nsIMsgCompose *compObj, nsIMsgFolder **msgFolder);
private:
virtual ~nsMsgComposeSendListener();
nsWeakPtr mWeakComposeObj;
MSG_DeliverMode mDeliverMode;
};
/******************************************************************************
* nsMsgMailList
******************************************************************************/
struct nsMsgMailList
{
explicit nsMsgMailList(nsIAbDirectory* directory);
nsString mName;
nsString mDescription;
nsCOMPtr<nsIAbDirectory> mDirectory;
};
#endif /* _nsMsgCompose_H_ */

View file

@ -0,0 +1,125 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgComposeContentHandler.h"
#include "nsMsgComposeService.h"
#include "nsMsgBaseCID.h"
#include "nsMsgCompCID.h"
#include "nsIChannel.h"
#include "nsIURI.h"
#include "plstr.h"
#include "nsServiceManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsPIDOMWindow.h"
#include "mozIDOMWindow.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsNetUtil.h"
#include "nsIMsgFolder.h"
#include "nsIMsgIncomingServer.h"
#include "nsIMsgAccountManager.h"
static NS_DEFINE_CID(kMsgComposeServiceCID, NS_MSGCOMPOSESERVICE_CID);
nsMsgComposeContentHandler::nsMsgComposeContentHandler()
{
}
// The following macro actually implement addref, release and query interface
// for our component.
NS_IMPL_ISUPPORTS(nsMsgComposeContentHandler, nsIContentHandler)
nsMsgComposeContentHandler::~nsMsgComposeContentHandler()
{
}
// Try to get an appropriate nsIMsgIdentity by going through the window, getting
// the document's URI, then the corresponding nsIMsgDBHdr. Then find the server
// associated with that header and get the first identity for it.
nsresult nsMsgComposeContentHandler::GetBestIdentity(
nsIInterfaceRequestor* aWindowContext, nsIMsgIdentity **aIdentity)
{
nsresult rv;
nsCOMPtr<mozIDOMWindowProxy> domWindow = do_GetInterface(aWindowContext);
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(domWindow);
nsAutoString documentURIString;
rv = window->GetDoc()->GetDocumentURI(documentURIString);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> documentURI;
rv = NS_NewURI(getter_AddRefs(documentURI), documentURIString);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgMessageUrl> msgURI = do_QueryInterface(documentURI);
if (!msgURI)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMsgDBHdr> msgHdr;
rv = msgURI->GetMessageHeader(getter_AddRefs(msgHdr));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgFolder> folder;
rv = msgHdr->GetFolder(getter_AddRefs(folder));
NS_ENSURE_SUCCESS(rv, rv);
// nsIMsgDBHdrs from .eml messages have a null folder, so bail out if that's
// the case.
if (!folder)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = folder->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(
NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = accountManager->GetFirstIdentityForServer(server, aIdentity);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
NS_IMETHODIMP nsMsgComposeContentHandler::HandleContent(const char * aContentType,
nsIInterfaceRequestor* aWindowContext, nsIRequest *request)
{
nsresult rv = NS_OK;
if (!request)
return NS_ERROR_NULL_POINTER;
// First of all, get the content type and make sure it is a content type we
// know how to handle!
if (PL_strcasecmp(aContentType, "application/x-mailto") == 0) {
nsCOMPtr<nsIMsgIdentity> identity;
if (aWindowContext)
GetBestIdentity(aWindowContext, getter_AddRefs(identity));
nsCOMPtr<nsIURI> aUri;
nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
if(!aChannel) return NS_ERROR_FAILURE;
rv = aChannel->GetURI(getter_AddRefs(aUri));
if (aUri)
{
nsCOMPtr<nsIMsgComposeService> composeService =
do_GetService(kMsgComposeServiceCID, &rv);
if (NS_SUCCEEDED(rv))
rv = composeService->OpenComposeWindowWithURI(nullptr, aUri, identity);
}
} else {
// The content-type was not application/x-mailto...
return NS_ERROR_WONT_HANDLE_CONTENT;
}
return rv;
}

View file

@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIContentHandler.h"
#include "nsIMsgIdentity.h"
class nsMsgComposeContentHandler : public nsIContentHandler
{
public:
nsMsgComposeContentHandler();
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTHANDLER
private:
virtual ~nsMsgComposeContentHandler();
nsresult GetBestIdentity(nsIInterfaceRequestor* aWindowContext,
nsIMsgIdentity **identity);
};

View file

@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgComposeParams.h"
nsMsgComposeParams::nsMsgComposeParams() :
mType(nsIMsgCompType::New),
mFormat(nsIMsgCompFormat::Default),
mBodyIsLink(false)
{
}
/* the following macro actually implement addref, release and query interface for our component. */
NS_IMPL_ISUPPORTS(nsMsgComposeParams, nsIMsgComposeParams)
nsMsgComposeParams::~nsMsgComposeParams()
{
}
/* attribute MSG_ComposeType type; */
NS_IMETHODIMP nsMsgComposeParams::GetType(MSG_ComposeType *aType)
{
NS_ENSURE_ARG_POINTER(aType);
*aType = mType;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetType(MSG_ComposeType aType)
{
mType = aType;
return NS_OK;
}
/* attribute MSG_ComposeFormat format; */
NS_IMETHODIMP nsMsgComposeParams::GetFormat(MSG_ComposeFormat *aFormat)
{
NS_ENSURE_ARG_POINTER(aFormat);
*aFormat = mFormat;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetFormat(MSG_ComposeFormat aFormat)
{
mFormat = aFormat;
return NS_OK;
}
/* attribute string originalMsgURI; */
NS_IMETHODIMP nsMsgComposeParams::GetOriginalMsgURI(char * *aOriginalMsgURI)
{
NS_ENSURE_ARG_POINTER(aOriginalMsgURI);
*aOriginalMsgURI = ToNewCString(mOriginalMsgUri);
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetOriginalMsgURI(const char * aOriginalMsgURI)
{
mOriginalMsgUri = aOriginalMsgURI;
return NS_OK;
}
/* attribute nsIMsgIdentity identity; */
NS_IMETHODIMP nsMsgComposeParams::GetIdentity(nsIMsgIdentity * *aIdentity)
{
NS_ENSURE_ARG_POINTER(aIdentity);
NS_IF_ADDREF(*aIdentity = mIdentity);
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetIdentity(nsIMsgIdentity * aIdentity)
{
mIdentity = aIdentity;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetOrigMsgHdr(nsIMsgDBHdr *aMsgHdr)
{
mOrigMsgHdr = aMsgHdr;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::GetOrigMsgHdr(nsIMsgDBHdr * *aMsgHdr)
{
NS_ENSURE_ARG_POINTER(aMsgHdr);
NS_IF_ADDREF(*aMsgHdr = mOrigMsgHdr);
return NS_OK;
}
/* attribute ACString htmlToQuote; */
NS_IMETHODIMP nsMsgComposeParams::GetHtmlToQuote(nsACString& aHtmlToQuote)
{
aHtmlToQuote = mHtmlToQuote;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetHtmlToQuote(const nsACString& aHtmlToQuote)
{
mHtmlToQuote = aHtmlToQuote;
return NS_OK;
}
/* attribute nsIMsgCompFields composeFields; */
NS_IMETHODIMP nsMsgComposeParams::GetComposeFields(nsIMsgCompFields * *aComposeFields)
{
NS_ENSURE_ARG_POINTER(aComposeFields);
if (mComposeFields)
{
*aComposeFields = mComposeFields;
NS_ADDREF(*aComposeFields);
}
else
*aComposeFields = nullptr;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetComposeFields(nsIMsgCompFields * aComposeFields)
{
mComposeFields = aComposeFields;
return NS_OK;
}
/* attribute boolean bodyIsLink; */
NS_IMETHODIMP nsMsgComposeParams::GetBodyIsLink(bool *aBodyIsLink)
{
NS_ENSURE_ARG_POINTER(aBodyIsLink);
*aBodyIsLink = mBodyIsLink;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetBodyIsLink(bool aBodyIsLink)
{
mBodyIsLink = aBodyIsLink;
return NS_OK;
}
/* attribute nsIMsgSendLisneter sendListener; */
NS_IMETHODIMP nsMsgComposeParams::GetSendListener(nsIMsgSendListener * *aSendListener)
{
NS_ENSURE_ARG_POINTER(aSendListener);
if (mSendListener)
{
*aSendListener = mSendListener;
NS_ADDREF(*aSendListener);
}
else
*aSendListener = nullptr;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetSendListener(nsIMsgSendListener * aSendListener)
{
mSendListener = aSendListener;
return NS_OK;
}
/* attribute string smtpPassword; */
NS_IMETHODIMP nsMsgComposeParams::GetSmtpPassword(char * *aSmtpPassword)
{
NS_ENSURE_ARG_POINTER(aSmtpPassword);
*aSmtpPassword = ToNewCString(mSMTPPassword);
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeParams::SetSmtpPassword(const char * aSmtpPassword)
{
mSMTPPassword = aSmtpPassword;
return NS_OK;
}

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIMsgComposeParams.h"
#include "nsStringGlue.h"
#include "nsIMsgHdr.h"
#include "nsCOMPtr.h"
class nsMsgComposeParams : public nsIMsgComposeParams
{
public:
nsMsgComposeParams();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGCOMPOSEPARAMS
private:
virtual ~nsMsgComposeParams();
MSG_ComposeType mType;
MSG_ComposeFormat mFormat;
nsCString mOriginalMsgUri;
nsCOMPtr<nsIMsgIdentity> mIdentity;
nsCOMPtr<nsIMsgCompFields> mComposeFields;
bool mBodyIsLink;
nsCOMPtr<nsIMsgSendListener> mSendListener;
nsCString mSMTPPassword;
nsCOMPtr<nsIMsgDBHdr> mOrigMsgHdr;
nsCString mHtmlToQuote;
};

View file

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgComposeProgressParams.h"
#include "nsServiceManagerUtils.h"
NS_IMPL_ISUPPORTS(nsMsgComposeProgressParams, nsIMsgComposeProgressParams)
nsMsgComposeProgressParams::nsMsgComposeProgressParams() :
m_deliveryMode(nsIMsgCompDeliverMode::Now)
{
}
nsMsgComposeProgressParams::~nsMsgComposeProgressParams()
{
}
/* attribute wstring subject; */
NS_IMETHODIMP nsMsgComposeProgressParams::GetSubject(char16_t * *aSubject)
{
NS_ENSURE_ARG(aSubject);
*aSubject = ToNewUnicode(m_subject);
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeProgressParams::SetSubject(const char16_t * aSubject)
{
m_subject = aSubject;
return NS_OK;
}
/* attribute MSG_DeliverMode deliveryMode; */
NS_IMETHODIMP nsMsgComposeProgressParams::GetDeliveryMode(MSG_DeliverMode *aDeliveryMode)
{
NS_ENSURE_ARG(aDeliveryMode);
*aDeliveryMode = m_deliveryMode;
return NS_OK;
}
NS_IMETHODIMP nsMsgComposeProgressParams::SetDeliveryMode(MSG_DeliverMode aDeliveryMode)
{
m_deliveryMode = aDeliveryMode;
return NS_OK;
}

View file

@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIMsgComposeProgressParams.h"
class nsMsgComposeProgressParams : public nsIMsgComposeProgressParams
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGCOMPOSEPROGRESSPARAMS
nsMsgComposeProgressParams();
private:
virtual ~nsMsgComposeProgressParams();
nsString m_subject;
MSG_DeliverMode m_deliveryMode;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define MSGCOMP_TRACE_PERFORMANCE 1
#include "nsIMsgComposeService.h"
#include "nsCOMPtr.h"
#include "mozIDOMWindow.h"
#include "nsIXULWindow.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsIMimeStreamConverter.h"
#include "nsInterfaceHashtable.h"
#include "nsICommandLineHandler.h"
#define ICOMMANDLINEHANDLER nsICommandLineHandler
class nsMsgComposeService :
public nsIMsgComposeService,
public ICOMMANDLINEHANDLER,
public nsSupportsWeakReference
{
public:
nsMsgComposeService();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGCOMPOSESERVICE
NS_DECL_NSICOMMANDLINEHANDLER
nsresult Init();
void Reset();
void DeleteCachedWindows();
nsresult AddGlobalHtmlDomains();
private:
virtual ~nsMsgComposeService();
bool mLogComposePerformance;
nsresult LoadDraftOrTemplate(const nsACString& aMsgURI, nsMimeOutputType aOutType,
nsIMsgIdentity * aIdentity, const char * aOriginalMsgURI,
nsIMsgDBHdr * aOrigMsgHdr, bool aForwardInline,
bool overrideComposeFormat,
nsIMsgWindow *aMsgWindow);
nsresult RunMessageThroughMimeDraft(const nsACString& aMsgURI,
nsMimeOutputType aOutType,
nsIMsgIdentity * aIdentity,
const char * aOriginalMsgURI,
nsIMsgDBHdr * aOrigMsgHdr,
bool aForwardInline,
const nsAString &forwardTo,
bool overrideComposeFormat,
nsIMsgWindow *aMsgWindow);
// hash table mapping dom windows to nsIMsgCompose objects
nsInterfaceHashtable<nsISupportsHashKey, nsIWeakReference> mOpenComposeWindows;
// When doing a reply and the settings are enabled, get the HTML of the selected text
// in the original message window so that it can be quoted instead of the entire message.
nsresult GetOrigWindowSelection(MSG_ComposeType type, nsIMsgWindow *aMsgWindow, nsACString& aSelHTML);
#ifdef MSGCOMP_TRACE_PERFORMANCE
PRIntervalTime mStartTime;
PRIntervalTime mPreviousTime;
#endif
};

View file

@ -0,0 +1,553 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgCopy.h"
#include "nsCOMPtr.h"
#include "nsMsgBaseCID.h"
#include "nsMsgFolderFlags.h"
#include "nsIMsgFolder.h"
#include "nsIMsgAccountManager.h"
#include "nsIMsgFolder.h"
#include "nsIMsgIncomingServer.h"
#include "nsIMsgProtocolInfo.h"
#include "nsISupports.h"
#include "nsIRDFService.h"
#include "nsIRDFResource.h"
#include "nsRDFCID.h"
#include "nsIURL.h"
#include "nsNetCID.h"
#include "nsMsgCompUtils.h"
#include "prcmon.h"
#include "nsIMsgImapMailFolder.h"
#include "nsThreadUtils.h"
#include "nsIMsgWindow.h"
#include "nsIMsgProgress.h"
#include "nsComposeStrings.h"
#include "prmem.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
#include "nsArrayUtils.h"
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
////////////////////////////////////////////////////////////////////////////////////
// This is the listener class for the copy operation. We have to create this class
// to listen for message copy completion and eventually notify the caller
////////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS(CopyListener, nsIMsgCopyServiceListener)
CopyListener::CopyListener(void)
{
mCopyInProgress = false;
}
CopyListener::~CopyListener(void)
{
}
nsresult
CopyListener::OnStartCopy()
{
#ifdef NS_DEBUG
printf("CopyListener::OnStartCopy()\n");
#endif
if (mComposeAndSend)
mComposeAndSend->NotifyListenerOnStartCopy();
return NS_OK;
}
nsresult
CopyListener::OnProgress(uint32_t aProgress, uint32_t aProgressMax)
{
#ifdef NS_DEBUG
printf("CopyListener::OnProgress() %d of %d\n", aProgress, aProgressMax);
#endif
if (mComposeAndSend)
mComposeAndSend->NotifyListenerOnProgressCopy(aProgress, aProgressMax);
return NS_OK;
}
nsresult
CopyListener::SetMessageKey(nsMsgKey aMessageKey)
{
if (mComposeAndSend)
mComposeAndSend->SetMessageKey(aMessageKey);
return NS_OK;
}
NS_IMETHODIMP
CopyListener::GetMessageId(nsACString& aMessageId)
{
if (mComposeAndSend)
mComposeAndSend->GetMessageId(aMessageId);
return NS_OK;
}
nsresult
CopyListener::OnStopCopy(nsresult aStatus)
{
if (NS_SUCCEEDED(aStatus))
{
#ifdef NS_DEBUG
printf("CopyListener: SUCCESSFUL ON THE COPY OPERATION!\n");
#endif
}
else
{
#ifdef NS_DEBUG
printf("CopyListener: COPY OPERATION FAILED!\n");
#endif
}
if (mCopyInProgress)
{
PR_CEnterMonitor(this);
PR_CNotifyAll(this);
mCopyInProgress = false;
PR_CExitMonitor(this);
}
if (mComposeAndSend)
mComposeAndSend->NotifyListenerOnStopCopy(aStatus);
return NS_OK;
}
nsresult
CopyListener::SetMsgComposeAndSendObject(nsIMsgSend *obj)
{
if (obj)
mComposeAndSend = obj;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////////
// END END END END END END END END END END END END END END END
// This is the listener class for the copy operation. We have to create this class
// to listen for message copy completion and eventually notify the caller
////////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS(nsMsgCopy, nsIUrlListener)
nsMsgCopy::nsMsgCopy()
{
mFile = nullptr;
mMode = nsIMsgSend::nsMsgDeliverNow;
mSavePref = nullptr;
}
nsMsgCopy::~nsMsgCopy()
{
PR_Free(mSavePref);
}
nsresult
nsMsgCopy::StartCopyOperation(nsIMsgIdentity *aUserIdentity,
nsIFile *aFile,
nsMsgDeliverMode aMode,
nsIMsgSend *aMsgSendObj,
const char *aSavePref,
nsIMsgDBHdr *aMsgToReplace)
{
nsCOMPtr<nsIMsgFolder> dstFolder;
bool isDraft = false;
bool waitForUrl = false;
nsresult rv;
if (!aMsgSendObj)
return NS_ERROR_INVALID_ARG;
// Store away the server location...
if (aSavePref)
mSavePref = PL_strdup(aSavePref);
//
// Vars for implementation...
//
// QueueForLater (Outbox)
if (aMode == nsIMsgSend::nsMsgQueueForLater ||
aMode == nsIMsgSend::nsMsgDeliverBackground)
{
rv = GetUnsentMessagesFolder(aUserIdentity, getter_AddRefs(dstFolder), &waitForUrl);
isDraft = false;
if (!dstFolder || NS_FAILED(rv)) {
return NS_MSG_UNABLE_TO_SEND_LATER;
}
}
else if (aMode == nsIMsgSend::nsMsgSaveAsDraft) // SaveAsDraft (Drafts)
{
rv = GetDraftsFolder(aUserIdentity, getter_AddRefs(dstFolder), &waitForUrl);
isDraft = true;
if (!dstFolder || NS_FAILED(rv))
return NS_MSG_UNABLE_TO_SAVE_DRAFT;
}
else if (aMode == nsIMsgSend::nsMsgSaveAsTemplate) // SaveAsTemplate (Templates)
{
rv = GetTemplatesFolder(aUserIdentity, getter_AddRefs(dstFolder), &waitForUrl);
isDraft = false;
if (!dstFolder || NS_FAILED(rv))
return NS_MSG_UNABLE_TO_SAVE_TEMPLATE;
}
else // SaveInSentFolder (Sent) - nsMsgDeliverNow or nsMsgSendUnsent
{
rv = GetSentFolder(aUserIdentity, getter_AddRefs(dstFolder), &waitForUrl);
isDraft = false;
if (!dstFolder || NS_FAILED(rv))
return NS_MSG_COULDNT_OPEN_FCC_FOLDER;
}
nsCOMPtr <nsIMsgWindow> msgWindow;
if (aMsgSendObj)
{
nsCOMPtr <nsIMsgProgress> progress;
aMsgSendObj->GetProgress(getter_AddRefs(progress));
if (progress)
progress->GetMsgWindow(getter_AddRefs(msgWindow));
}
mMode = aMode;
mFile = aFile;
mDstFolder = dstFolder;
mMsgToReplace = aMsgToReplace;
mIsDraft = isDraft;
mMsgSendObj = aMsgSendObj;
if (!waitForUrl)
{
// cache info needed for DoCopy and call DoCopy when OnStopUrl is called.
rv = DoCopy(aFile, dstFolder, aMsgToReplace, isDraft, msgWindow, aMsgSendObj);
// N.B. "this" may be deleted when this call returns.
}
return rv;
}
nsresult
nsMsgCopy::DoCopy(nsIFile *aDiskFile, nsIMsgFolder *dstFolder,
nsIMsgDBHdr *aMsgToReplace, bool aIsDraft,
nsIMsgWindow *msgWindow,
nsIMsgSend *aMsgSendObj)
{
nsresult rv = NS_OK;
// Check sanity
if ((!aDiskFile) || (!dstFolder))
return NS_ERROR_INVALID_ARG;
//Call copyservice with dstFolder, disk file, and txnManager
if(NS_SUCCEEDED(rv))
{
RefPtr<CopyListener> copyListener = new CopyListener();
if (!copyListener)
return NS_ERROR_OUT_OF_MEMORY;
copyListener->SetMsgComposeAndSendObject(aMsgSendObj);
nsCOMPtr<nsIThread> thread;
if (aIsDraft)
{
nsCOMPtr<nsIMsgImapMailFolder> imapFolder =
do_QueryInterface(dstFolder);
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
bool shutdownInProgress = false;
rv = accountManager->GetShutdownInProgress(&shutdownInProgress);
if (NS_SUCCEEDED(rv) && shutdownInProgress && imapFolder)
{
// set the following only when we were in the middle of shutdown
// process
copyListener->mCopyInProgress = true;
thread = do_GetCurrentThread();
}
}
nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = copyService->CopyFileMessage(aDiskFile, dstFolder, aMsgToReplace,
aIsDraft,
aIsDraft ? 0 : nsMsgMessageFlags::Read,
EmptyCString(), copyListener, msgWindow);
// copyListener->mCopyInProgress can only be set when we are in the
// middle of the shutdown process
while (copyListener->mCopyInProgress)
{
PR_CEnterMonitor(copyListener);
PR_CWait(copyListener, PR_MicrosecondsToInterval(1000UL));
PR_CExitMonitor(copyListener);
if (thread)
NS_ProcessPendingEvents(thread);
}
}
return rv;
}
// nsIUrlListener methods
NS_IMETHODIMP
nsMsgCopy::OnStartRunningUrl(nsIURI * aUrl)
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgCopy::OnStopRunningUrl(nsIURI * aUrl, nsresult aExitCode)
{
nsresult rv = aExitCode;
if (NS_SUCCEEDED(aExitCode))
{
rv = DoCopy(mFile, mDstFolder, mMsgToReplace, mIsDraft, nullptr, mMsgSendObj);
}
return rv;
}
nsresult
nsMsgCopy::GetUnsentMessagesFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **folder, bool *waitForUrl)
{
nsresult ret = LocateMessageFolder(userIdentity, nsIMsgSend::nsMsgQueueForLater, mSavePref, folder);
if (*folder)
(*folder)->SetFlag(nsMsgFolderFlags::Queue);
CreateIfMissing(folder, waitForUrl);
return ret;
}
nsresult
nsMsgCopy::GetDraftsFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **folder, bool *waitForUrl)
{
nsresult ret = LocateMessageFolder(userIdentity, nsIMsgSend::nsMsgSaveAsDraft, mSavePref, folder);
if (*folder)
(*folder)->SetFlag(nsMsgFolderFlags::Drafts);
CreateIfMissing(folder, waitForUrl);
return ret;
}
nsresult
nsMsgCopy::GetTemplatesFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **folder, bool *waitForUrl)
{
nsresult ret = LocateMessageFolder(userIdentity, nsIMsgSend::nsMsgSaveAsTemplate, mSavePref, folder);
if (*folder)
(*folder)->SetFlag(nsMsgFolderFlags::Templates);
CreateIfMissing(folder, waitForUrl);
return ret;
}
nsresult
nsMsgCopy::GetSentFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **folder, bool *waitForUrl)
{
nsresult ret = LocateMessageFolder(userIdentity, nsIMsgSend::nsMsgDeliverNow, mSavePref, folder);
if (*folder)
{
// If mSavePref is the same as the identity's fcc folder, set the sent flag.
nsCString identityFccUri;
userIdentity->GetFccFolder(identityFccUri);
if (identityFccUri.Equals(mSavePref))
(*folder)->SetFlag(nsMsgFolderFlags::SentMail);
}
CreateIfMissing(folder, waitForUrl);
return ret;
}
nsresult
nsMsgCopy::CreateIfMissing(nsIMsgFolder **folder, bool *waitForUrl)
{
nsresult rv = NS_OK;
if (folder && *folder)
{
nsCOMPtr<nsIMsgFolder> parent;
(*folder)->GetParent(getter_AddRefs(parent));
if (!parent)
{
nsCOMPtr<nsIFile> folderPath;
// for local folders, path is to the berkeley mailbox.
// for imap folders, path needs to have .msf appended to the name
(*folder)->GetFilePath(getter_AddRefs(folderPath));
nsCOMPtr<nsIMsgIncomingServer> server;
rv = (*folder)->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgProtocolInfo> protocolInfo;
rv = server->GetProtocolInfo(getter_AddRefs(protocolInfo));
NS_ENSURE_SUCCESS(rv, rv);
bool isAsyncFolder;
rv = protocolInfo->GetFoldersCreatedAsync(&isAsyncFolder);
NS_ENSURE_SUCCESS(rv, rv);
// if we can't get the path from the folder, then try to create the storage.
// for imap, it doesn't matter if the .msf file exists - it still might not
// exist on the server, so we should try to create it
bool exists = false;
if (!isAsyncFolder && folderPath)
folderPath->Exists(&exists);
if (!exists)
{
(*folder)->CreateStorageIfMissing(this);
if (isAsyncFolder)
*waitForUrl = true;
rv = NS_OK;
}
}
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////////
// Utility Functions for MsgFolders
////////////////////////////////////////////////////////////////////////////////////
nsresult
LocateMessageFolder(nsIMsgIdentity *userIdentity,
nsMsgDeliverMode aFolderType,
const char *aFolderURI,
nsIMsgFolder **msgFolder)
{
nsresult rv = NS_OK;
if (!msgFolder) return NS_ERROR_NULL_POINTER;
*msgFolder = nullptr;
if (!aFolderURI || !*aFolderURI)
return NS_ERROR_INVALID_ARG;
// as long as it doesn't start with anyfolder://
if (PL_strncasecmp(ANY_SERVER, aFolderURI, strlen(aFolderURI)) != 0)
{
nsCOMPtr<nsIRDFService> rdf(do_GetService(kRDFServiceCID, &rv));
if (NS_FAILED(rv)) return rv;
// get the corresponding RDF resource
// RDF will create the folder resource if it doesn't already exist
nsCOMPtr<nsIRDFResource> resource;
rv = rdf->GetResource(nsDependentCString(aFolderURI), getter_AddRefs(resource));
if (NS_FAILED(rv)) return rv;
nsCOMPtr <nsIMsgFolder> folderResource;
folderResource = do_QueryInterface(resource, &rv);
if (NS_SUCCEEDED(rv) && folderResource)
{
// don't check validity of folder - caller will handle creating it
nsCOMPtr<nsIMsgIncomingServer> server;
//make sure that folder hierarchy is built so that legitimate parent-child relationship is established
rv = folderResource->GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv,rv);
return server->GetMsgFolderFromURI(folderResource, nsDependentCString(aFolderURI), msgFolder);
}
else
{
return NS_ERROR_FAILURE;
}
}
else
{
uint32_t cnt = 0;
uint32_t i;
if (!userIdentity)
return NS_ERROR_INVALID_ARG;
// get the account manager
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// If any folder will do, go look for one.
nsCOMPtr<nsIArray> retval;
accountManager->GetServersForIdentity(userIdentity, getter_AddRefs(retval));
if (!retval) return NS_ERROR_FAILURE;
// Ok, we have to look through the servers and try to find the server that
// has a valid folder of the type that interests us...
rv = retval->GetLength(&cnt);
if (NS_FAILED(rv)) return rv;
for (i=0; i<cnt; i++) {
// Now that we have the server...we need to get the named message folder
nsCOMPtr<nsIMsgIncomingServer> inServer;
inServer = do_QueryElementAt(retval, i, &rv);
if(NS_FAILED(rv) || (!inServer))
continue;
//
// If aFolderURI is passed in, then the user has chosen a specific
// mail folder to save the message, but if it is null, just find the
// first one and make that work. The folder is specified as a URI, like
// the following:
//
// mailbox://nobody@Local Folders/Sent
// imap://rhp@nsmail-2/Drafts
// newsgroup://news.mozilla.org/netscape.test
//
nsCString serverURI;
rv = inServer->GetServerURI(serverURI);
if (NS_FAILED(rv) || serverURI.IsEmpty())
continue;
nsCOMPtr<nsIMsgFolder> rootFolder;
rv = inServer->GetRootFolder(getter_AddRefs(rootFolder));
if(NS_FAILED(rv) || (!rootFolder))
continue;
// use the defaults by getting the folder by flags
if (aFolderType == nsIMsgSend::nsMsgQueueForLater ||
aFolderType == nsIMsgSend::nsMsgDeliverBackground)
{
// QueueForLater (Outbox)
rootFolder->GetFolderWithFlags(nsMsgFolderFlags::Queue, msgFolder);
}
else if (aFolderType == nsIMsgSend::nsMsgSaveAsDraft) // SaveAsDraft (Drafts)
{
rootFolder->GetFolderWithFlags(nsMsgFolderFlags::Drafts, msgFolder);
}
else if (aFolderType == nsIMsgSend::nsMsgSaveAsTemplate) // SaveAsTemplate (Templates)
{
rootFolder->GetFolderWithFlags(nsMsgFolderFlags::Templates, msgFolder);
}
else // SaveInSentFolder (Sent) - nsMsgDeliverNow or nsMsgSendUnsent
{
rootFolder->GetFolderWithFlags(nsMsgFolderFlags::SentMail, msgFolder);
}
if (*msgFolder)
{
return NS_OK;
}
}
}
return NS_ERROR_FAILURE;
}
//
// Figure out if a folder is local or not and return a boolean to
// say so.
//
nsresult
MessageFolderIsLocal(nsIMsgIdentity *userIdentity,
nsMsgDeliverMode aFolderType,
const char *aFolderURI,
bool *aResult)
{
nsresult rv;
if (!aFolderURI) return NS_ERROR_NULL_POINTER;
nsCOMPtr <nsIURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = url->SetSpec(nsDependentCString(aFolderURI));
if (NS_FAILED(rv)) return rv;
/* mailbox:/ means its local (on disk) */
rv = url->SchemeIs("mailbox", aResult);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}

View file

@ -0,0 +1,120 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgCopy_H_
#define _nsMsgCopy_H_
#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsIFile.h"
#include "nsMsgSend.h"
#include "nsIMsgFolder.h"
#include "nsITransactionManager.h"
#include "nsIMsgCopyServiceListener.h"
#include "nsIMsgCopyService.h"
// {0874C3B5-317D-11d3-8EFB-00A024A7D144}
#define NS_IMSGCOPY_IID \
{ 0x874c3b5, 0x317d, 0x11d3, \
{ 0x8e, 0xfb, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 } };
// Forward declarations...
class nsMsgCopy;
////////////////////////////////////////////////////////////////////////////////////
// This is the listener class for the copy operation. We have to create this class
// to listen for message copy completion and eventually notify the caller
////////////////////////////////////////////////////////////////////////////////////
class CopyListener : public nsIMsgCopyServiceListener
{
public:
CopyListener(void);
// nsISupports interface
NS_DECL_THREADSAFE_ISUPPORTS
NS_IMETHOD OnStartCopy() override;
NS_IMETHOD OnProgress(uint32_t aProgress, uint32_t aProgressMax) override;
NS_IMETHOD SetMessageKey(nsMsgKey aMessageKey) override;
NS_IMETHOD GetMessageId(nsACString& aMessageId) override;
NS_IMETHOD OnStopCopy(nsresult aStatus) override;
NS_IMETHOD SetMsgComposeAndSendObject(nsIMsgSend *obj);
bool mCopyInProgress;
private:
virtual ~CopyListener();
nsCOMPtr<nsIMsgSend> mComposeAndSend;
};
//
// This is a class that deals with processing remote attachments. It implements
// an nsIStreamListener interface to deal with incoming data
//
class nsMsgCopy : public nsIUrlListener
{
public:
nsMsgCopy();
// nsISupports interface
NS_DECL_ISUPPORTS
NS_DECL_NSIURLLISTENER
//////////////////////////////////////////////////////////////////////
// Object methods...
//////////////////////////////////////////////////////////////////////
//
nsresult StartCopyOperation(nsIMsgIdentity *aUserIdentity,
nsIFile *aFile,
nsMsgDeliverMode aMode,
nsIMsgSend *aMsgSendObj,
const char *aSavePref,
nsIMsgDBHdr *aMsgToReplace);
nsresult DoCopy(nsIFile *aDiskFile, nsIMsgFolder *dstFolder,
nsIMsgDBHdr *aMsgToReplace, bool aIsDraft,
nsIMsgWindow *msgWindow,
nsIMsgSend *aMsgSendObj);
nsresult GetUnsentMessagesFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **msgFolder, bool *waitForUrl);
nsresult GetDraftsFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **msgFolder, bool *waitForUrl);
nsresult GetTemplatesFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **msgFolder, bool *waitForUrl);
nsresult GetSentFolder(nsIMsgIdentity *userIdentity, nsIMsgFolder **msgFolder, bool *waitForUrl);
nsresult CreateIfMissing(nsIMsgFolder **folder, bool *waitForUrl);
//
// Vars for implementation...
//
nsIFile *mFile; // the file we are sending...
nsMsgDeliverMode mMode;
nsCOMPtr<nsIMsgFolder> mDstFolder;
nsCOMPtr<nsIMsgDBHdr> mMsgToReplace;
bool mIsDraft;
nsCOMPtr<nsIMsgSend> mMsgSendObj;
char *mSavePref;
private:
virtual ~nsMsgCopy();
};
// Useful function for the back end...
nsresult LocateMessageFolder(nsIMsgIdentity *userIdentity,
nsMsgDeliverMode aFolderType,
const char *aSaveURI,
nsIMsgFolder **msgFolder);
nsresult MessageFolderIsLocal(nsIMsgIdentity *userIdentity,
nsMsgDeliverMode aFolderType,
const char *aSaveURI,
bool *aResult);
#endif /* _nsMsgCopy_H_ */

View file

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgPrompts.h"
#include "nsMsgCopy.h"
#include "nsIPrompt.h"
#include "nsIWindowWatcher.h"
#include "nsMsgCompCID.h"
#include "nsComposeStrings.h"
#include "nsIStringBundle.h"
#include "nsServiceManagerUtils.h"
#include "nsMsgUtils.h"
#include "mozilla/Services.h"
nsresult
nsMsgGetMessageByName(const char16_t* aName, nsString& aResult)
{
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(
"chrome://messenger/locale/messengercompose/composeMsgs.properties",
getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
return bundle->GetStringFromName(aName, getter_Copies(aResult));
}
static nsresult
nsMsgBuildMessageByName(const char16_t *aName, nsIFile *aFile, nsString& aResult)
{
NS_ENSURE_ARG_POINTER(aFile);
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
nsString path;
aFile->GetPath(path);
const char16_t *params[1] = {path.get()};
return bundle->FormatStringFromName(aName, params, 1, getter_Copies(aResult));
}
nsresult
nsMsgBuildMessageWithFile(nsIFile *aFile, nsString& aResult)
{
return nsMsgBuildMessageByName(u"unableToOpenFile", aFile, aResult);
}
nsresult
nsMsgBuildMessageWithTmpFile(nsIFile *aFile, nsString& aResult)
{
return nsMsgBuildMessageByName(u"unableToOpenTmpFile", aFile, aResult);
}
nsresult
nsMsgDisplayMessageByName(nsIPrompt *aPrompt, const char16_t* aName, const char16_t *windowTitle)
{
nsString msg;
nsMsgGetMessageByName(aName, msg);
return nsMsgDisplayMessageByString(aPrompt, msg.get(), windowTitle);
}
nsresult
nsMsgDisplayMessageByString(nsIPrompt * aPrompt, const char16_t * msg, const char16_t * windowTitle)
{
NS_ENSURE_ARG_POINTER(msg);
nsresult rv = NS_OK;
nsCOMPtr<nsIPrompt> prompt = aPrompt;
if (!prompt)
{
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
if (wwatch)
wwatch->GetNewPrompter(0, getter_AddRefs(prompt));
}
if (prompt)
rv = prompt->Alert(windowTitle, msg);
return rv;
}
nsresult
nsMsgAskBooleanQuestionByString(nsIPrompt * aPrompt, const char16_t * msg, bool *answer, const char16_t * windowTitle)
{
NS_ENSURE_TRUE(msg && *msg, NS_ERROR_INVALID_ARG);
nsresult rv = NS_OK;
nsCOMPtr<nsIPrompt> dialog = aPrompt;
if (!dialog)
{
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
if (wwatch)
wwatch->GetNewPrompter(0, getter_AddRefs(dialog));
}
if (dialog) {
rv = dialog->Confirm(windowTitle, msg, answer);
}
return rv;
}

View file

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgPrompts_H_
#define _nsMsgPrompts_H_
#include "nscore.h"
#include "nsError.h"
#include "nsStringGlue.h"
class nsIPrompt;
nsresult nsMsgGetMessageByName(const char16_t* aName, nsString& aResult);
nsresult nsMsgBuildMessageWithFile(nsIFile * aFile, nsString& aResult);
nsresult nsMsgBuildMessageWithTmpFile(nsIFile * aFile, nsString& aResult);
nsresult nsMsgDisplayMessageByName(nsIPrompt *aPrompt, const char16_t *aName, const char16_t *windowTitle = nullptr);
nsresult nsMsgDisplayMessageByString(nsIPrompt * aPrompt, const char16_t * msg, const char16_t * windowTitle = nullptr);
nsresult nsMsgAskBooleanQuestionByString(nsIPrompt * aPrompt, const char16_t * msg, bool *answer, const char16_t * windowTitle = nullptr);
#endif /* _nsMsgPrompts_H_ */

View file

@ -0,0 +1,233 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIURL.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIServiceManager.h"
#include "nsIStreamListener.h"
#include "nsIStreamConverter.h"
#include "nsIStreamConverterService.h"
#include "nsIMimeStreamConverter.h"
#include "nsMimeTypes.h"
#include "nsICharsetConverterManager.h"
#include "prprf.h"
#include "nsMsgQuote.h"
#include "nsMsgCompUtils.h"
#include "nsIMsgMessageService.h"
#include "nsMsgUtils.h"
#include "nsNetUtil.h"
#include "nsMsgMimeCID.h"
#include "nsMsgCompCID.h"
#include "nsMsgCompose.h"
#include "nsMsgMailNewsUrl.h"
#include "mozilla/Services.h"
#include "nsIScriptSecurityManager.h"
NS_IMPL_ISUPPORTS(nsMsgQuoteListener, nsIMsgQuoteListener,
nsIMimeStreamConverterListener)
nsMsgQuoteListener::nsMsgQuoteListener()
{
}
nsMsgQuoteListener::~nsMsgQuoteListener()
{
}
NS_IMETHODIMP nsMsgQuoteListener::SetMsgQuote(nsIMsgQuote * msgQuote)
{
mMsgQuote = do_GetWeakReference(msgQuote);
return NS_OK;
}
NS_IMETHODIMP nsMsgQuoteListener::GetMsgQuote(nsIMsgQuote ** aMsgQuote)
{
nsresult rv = NS_OK;
if (aMsgQuote)
{
nsCOMPtr<nsIMsgQuote> msgQuote = do_QueryReferent(mMsgQuote);
*aMsgQuote = msgQuote;
NS_IF_ADDREF(*aMsgQuote);
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
nsresult nsMsgQuoteListener::OnHeadersReady(nsIMimeHeaders * headers)
{
nsCOMPtr<nsIMsgQuotingOutputStreamListener> quotingOutputStreamListener;
nsCOMPtr<nsIMsgQuote> msgQuote = do_QueryReferent(mMsgQuote);
if (msgQuote)
msgQuote->GetStreamListener(getter_AddRefs(quotingOutputStreamListener));
if (quotingOutputStreamListener)
quotingOutputStreamListener->SetMimeHeaders(headers);
return NS_OK;
}
//
// Implementation...
//
nsMsgQuote::nsMsgQuote()
{
mQuoteHeaders = false;
mQuoteListener = nullptr;
}
nsMsgQuote::~nsMsgQuote()
{
}
NS_IMPL_ISUPPORTS(nsMsgQuote, nsIMsgQuote, nsISupportsWeakReference)
NS_IMETHODIMP nsMsgQuote::GetStreamListener(nsIMsgQuotingOutputStreamListener ** aStreamListener)
{
nsresult rv = NS_OK;
if (aStreamListener)
{
*aStreamListener = mStreamListener;
NS_IF_ADDREF(*aStreamListener);
}
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
nsresult
nsMsgQuote::QuoteMessage(const char *msgURI, bool quoteHeaders,
nsIMsgQuotingOutputStreamListener * aQuoteMsgStreamListener,
const char * aMsgCharSet, bool headersOnly,
nsIMsgDBHdr *aMsgHdr)
{
nsresult rv;
if (!msgURI)
return NS_ERROR_INVALID_ARG;
mQuoteHeaders = quoteHeaders;
mStreamListener = aQuoteMsgStreamListener;
nsAutoCString msgUri(msgURI);
bool fileUrl = !strncmp(msgURI, "file:", 5);
bool forwardedMessage = PL_strstr(msgURI, "&realtype=message/rfc822") != nullptr;
nsCOMPtr<nsIURI> aURL;
if (fileUrl)
{
msgUri.Replace(0, 5, NS_LITERAL_CSTRING("mailbox:"));
msgUri.AppendLiteral("?number=0");
rv = NS_NewURI(getter_AddRefs(aURL), msgUri);
nsCOMPtr<nsIMsgMessageUrl> mailUrl(do_QueryInterface(aURL));
if (mailUrl)
mailUrl->SetMessageHeader(aMsgHdr);
}
else if (forwardedMessage)
rv = NS_NewURI(getter_AddRefs(aURL), msgURI);
else
{
nsCOMPtr <nsIMsgMessageService> msgService;
rv = GetMessageServiceFromURI(nsDependentCString(msgURI), getter_AddRefs(msgService));
if (NS_FAILED(rv)) return rv;
rv = msgService->GetUrlForUri(msgURI, getter_AddRefs(aURL), nullptr);
}
if (NS_FAILED(rv)) return rv;
nsCOMPtr <nsIURL> mailNewsUrl = do_QueryInterface(aURL, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsAutoCString queryPart;
rv = mailNewsUrl->GetQuery(queryPart);
if (!queryPart.IsEmpty())
queryPart.Append('&');
if (headersOnly) /* We don't need to quote the message body but we still need to extract the headers */
queryPart.Append("header=only");
else if (quoteHeaders)
queryPart.Append("header=quote");
else
queryPart.Append("header=quotebody");
rv = mailNewsUrl->SetQuery(queryPart);
NS_ENSURE_SUCCESS(rv,rv);
// if we were given a non empty charset, then use it
if (aMsgCharSet && *aMsgCharSet)
{
nsCOMPtr<nsIMsgI18NUrl> i18nUrl (do_QueryInterface(aURL));
if (i18nUrl)
i18nUrl->SetCharsetOverRide(aMsgCharSet);
}
mQuoteListener = do_CreateInstance(NS_MSGQUOTELISTENER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
mQuoteListener->SetMsgQuote(this);
// funky magic go get the isupports for this class which inherits from multiple interfaces.
nsISupports * supports;
QueryInterface(NS_GET_IID(nsISupports), (void **) &supports);
nsCOMPtr<nsISupports> quoteSupport = supports;
NS_IF_RELEASE(supports);
// now we want to create a necko channel for this url and we want to open it
nsCOMPtr<nsIScriptSecurityManager> secMan(
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIPrincipal> systemPrincipal;
rv = secMan->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
NS_ENSURE_SUCCESS(rv,rv);
mQuoteChannel = nullptr;
nsCOMPtr<nsIIOService> netService = mozilla::services::GetIOService();
NS_ENSURE_TRUE(netService, NS_ERROR_UNEXPECTED);
rv = netService->NewChannelFromURI2(aURL,
nullptr,
systemPrincipal,
nullptr,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
getter_AddRefs(mQuoteChannel));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupports> ctxt = do_QueryInterface(aURL);
nsCOMPtr<nsIStreamConverterService> streamConverterService =
do_GetService("@mozilla.org/streamConverters;1", &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIStreamListener> convertedListener;
rv = streamConverterService->AsyncConvertData("message/rfc822",
"application/vnd.mozilla.xul+xml",
mStreamListener,
quoteSupport,
getter_AddRefs(convertedListener));
if (NS_FAILED(rv)) return rv;
// now try to open the channel passing in our display consumer as the listener
rv = mQuoteChannel->AsyncOpen(convertedListener, ctxt);
return rv;
}
NS_IMETHODIMP
nsMsgQuote::GetQuoteListener(nsIMimeStreamConverterListener** aQuoteListener)
{
if (!aQuoteListener || !mQuoteListener)
return NS_ERROR_NULL_POINTER;
*aQuoteListener = mQuoteListener;
NS_ADDREF(*aQuoteListener);
return NS_OK;
}
NS_IMETHODIMP
nsMsgQuote::GetQuoteChannel(nsIChannel** aQuoteChannel)
{
if (!aQuoteChannel || !mQuoteChannel)
return NS_ERROR_NULL_POINTER;
*aQuoteChannel = mQuoteChannel;
NS_ADDREF(*aQuoteChannel);
return NS_OK;
}

View file

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsMsgQuote_h__
#define __nsMsgQuote_h__
#include "nsIMsgQuote.h"
#include "nsIMsgMessageService.h"
#include "nsIStreamListener.h"
#include "nsIMimeStreamConverter.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
class nsMsgQuote;
class nsMsgQuoteListener: public nsIMsgQuoteListener
{
public:
nsMsgQuoteListener();
NS_DECL_THREADSAFE_ISUPPORTS
// nsIMimeStreamConverterListener support
NS_DECL_NSIMIMESTREAMCONVERTERLISTENER
NS_DECL_NSIMSGQUOTELISTENER
private:
virtual ~nsMsgQuoteListener();
nsWeakPtr mMsgQuote;
};
class nsMsgQuote: public nsIMsgQuote, public nsSupportsWeakReference {
public:
nsMsgQuote();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMSGQUOTE
private:
virtual ~nsMsgQuote();
//
// Implementation data...
//
nsCOMPtr<nsIMsgQuotingOutputStreamListener> mStreamListener;
bool mQuoteHeaders;
nsCOMPtr<nsIMsgQuoteListener> mQuoteListener;
nsCOMPtr<nsIChannel> mQuoteChannel;
};
#endif /* __nsMsgQuote_h__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,405 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __MSGSEND_H__
#define __MSGSEND_H__
/* Asynchronous mailing of messages with attached URLs.
- If there are any attachments, start their URLs going, and write each
of them to a temp file.
- While writing to their files, examine the data going by and decide
what kind of encoding, if any, they need. Also remember their content
types.
- Once that URLs has been saved to a temp file (or, if there were no
attachments) generate a final temp file, of the actual message:
- Generate a string of the headers.
- Open the final temp file.
- Write the headers.
- Examine the first part, and decide whether to encode it.
- Write the first part to the file, possibly encoded.
- Write the second and subsequent parts to the file, possibly encoded.
(Open the first temp file and copy it to the final temp file, and so
on, through an encoding filter.)
- Delete the attachment temp file(s) as we finish with them.
- Close the final temp file.
- Open the news: url.
- Send the final temp file to NNTP.
If there's an error, run the callback with "failure" status.
- If mail succeeded, open the mailto: url.
- Send the final temp file to SMTP.
If there's an error, run the callback with "failure" status.
- Otherwise, run the callback with "success" status.
- Free everything, delete the final temp file.
The theory behind the encoding logic:
=====================================
If the document is of type text/html, and the user has asked to attach it
as source or postscript, it will be run through the appropriate converter
(which will result in a document of type text/plain.)
An attachment will be encoded if:
- it is of a non-text type (in which case we will use base64); or
- The "use QP" option has been selected and high-bit characters exist; or
- any NULLs exist in the document; or
- any line is longer than 990 bytes (see LINELENGTH_ENCODING_THRESHOLD below)
and it is not of type message/rfc822.
- If we are encoding, and more than 10% of the document consists of
non-ASCII characters, then we always use base64 instead of QP.
We eschew quoted-printable in favor of base64 for documents which are likely
to always be binary (images, sound) because, on the off chance that a GIF
file (for example) might contain primarily bytes in the ASCII range, using
the quoted-printable representation might cause corruption due to the
translation of CR or LF to CRLF. So, when we don't know that the document
has "lines", we don't use quoted-printable.
*/
/* For maximal compatibility, it helps to emit both
Content-Type: <type>; name="<original-file-name>"
as well as
Content-Disposition: inline; filename="<original-file-name>"
The lossage here is, RFC1341 defined the "name" parameter to Content-Type,
but then RFC1521 deprecated it in anticipation of RFC1806, which defines
Content-Type and the "filename" parameter. But, RFC1521 is "Standards Track"
while RFC1806 is still "Experimental." So, it's probably best to just
implement both.
*/
#define EMIT_NAME_IN_CONTENT_TYPE
/* Whether the contents of the BCC header should be preserved in the FCC'ed
copy of a message. See comments below, in mime_do_fcc_1().
*/
#define SAVE_BCC_IN_FCC_FILE
/* When attaching an HTML document, one must indicate the original URL of
that document, if the receiver is to have any chance of being able to
retreive and display the inline images, or to click on any links in the
HTML.
The way we have done this in the past is by inserting a <BASE> tag as the
first line of all HTML documents we attach. (This is kind of bad in that
we're actually modifying the document, and it really isn't our place to
do that.)
The sanctioned *new* way of doing this is to insert a Content-Base header
field on the attachment. This is (will be) a part of the forthcoming MHTML
spec.
If GENERATE_CONTENT_BASE, we generate a Content-Base header.
We used to have a MANGLE_HTML_ATTACHMENTS_WITH_BASE_TAG symbol that we
defined, which added a BASE tag to the bodies. We stopped doing this in
4.0. */
#define GENERATE_CONTENT_BASE
//
// Necessary includes
//
#include "nsCOMPtr.h"
#include "nsIMsgSend.h"
#include "nsIStringBundle.h"
#include "msgCore.h"
#include "prprf.h"
#include "nsIOutputStream.h"
#include "nsMsgMessageFlags.h"
#include "nsIURL.h"
#include "nsMsgAttachmentHandler.h"
#include "nsMsgCompFields.h"
#include "nsIMsgSendListener.h"
#include "nsIDOMNode.h"
#include "nsIEditor.h"
#include "nsIUrlListener.h"
#include "nsIMsgStatusFeedback.h"
#include "nsIMsgIdentity.h"
#include "nsIMsgHdr.h"
#include "nsIMsgIdentity.h"
#include "nsWeakReference.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsIMsgComposeSecure.h"
#include "nsAutoPtr.h"
#include "nsMsgAttachmentData.h"
#include "nsIMsgFilterService.h"
#include "nsIMsgOperationListener.h"
//
// Some necessary defines...
//
#define MIME_BUFFER_SIZE 4096 // must be greater than 1000
// SMTP (RFC821) limit
// Maximum number of bytes we allow in a line before we force
// encoding to base64 if not already QR-encoded or of type message/rfc822.
#define LINELENGTH_ENCODING_THRESHOLD 990
//
// Utilities for string handling
//
#define PUSH_STRING(S) \
do { PL_strcpy (buffer_tail, S); buffer_tail += PL_strlen (S); } while(0)
#define PUSH_STRINGN(S,N) \
do { memcpy(buffer_tail, (S), (N)); buffer_tail += (N); } while(0)
#define PUSH_NEWLINE() \
do { *buffer_tail++ = '\r'; *buffer_tail++ = '\n'; *buffer_tail = '\0'; } while(0)
//
// Forward declarations...
//
class nsMsgSendPart;
class nsMsgCopy;
class nsIPrompt;
class nsIInterfaceRequestor;
namespace mozilla {
namespace mailnews {
class MimeEncoder;
}
}
class nsMsgComposeAndSend : public nsIMsgSend,
public nsIMsgOperationListener,
public nsSupportsWeakReference
{
typedef mozilla::mailnews::MimeEncoder MimeEncoder;
public:
//
// Define QueryInterface, AddRef and Release for this class
//
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIMSGSEND
NS_DECL_NSIMSGOPERATIONLISTENER
nsMsgComposeAndSend();
// Delivery and completion callback routines...
NS_IMETHOD DeliverMessage();
NS_IMETHOD DeliverFileAsMail();
NS_IMETHOD DeliverFileAsNews();
void DoDeliveryExitProcessing(nsIURI * aUrl, nsresult aExitCode, bool aCheckForMail);
nsresult FormatStringWithSMTPHostNameByName(const char16_t* aMsgName, char16_t **aString);
nsresult DoFcc();
nsresult StartMessageCopyOperation(nsIFile *aFileSpec,
nsMsgDeliverMode mode,
const nsCString& dest_uri);
nsresult SendToMagicFolder(nsMsgDeliverMode flag);
// Check to see if it's ok to save msgs to the configured folder.
bool CanSaveMessagesToFolder(const char *folderURL);
//
// FCC operations...
//
nsresult MimeDoFCC (nsIFile *input_file,
nsMsgDeliverMode mode,
const char *bcc_header,
const char *fcc_header,
const char *news_url);
// Init() will allow for either message creation without delivery or full
// message creation and send operations
//
nsresult Init(
nsIMsgIdentity *aUserIdentity,
const char *aAccountKey,
nsMsgCompFields *fields,
nsIFile *sendFile,
bool digest_p,
bool dont_deliver_p,
nsMsgDeliverMode mode,
nsIMsgDBHdr *msgToReplace,
const char *attachment1_type,
const nsACString &attachment1_body,
nsIArray *attachments,
nsIArray *preloaded_attachments,
const char *password,
const nsACString &aOriginalMsgURI,
MSG_ComposeType aType);
//
// Setup the composition fields
//
nsresult InitCompositionFields(nsMsgCompFields *fields,
const nsACString &aOriginalMsgURI,
MSG_ComposeType aType);
NS_IMETHOD GetBodyFromEditor();
//
// Attachment processing...
//
nsresult HackAttachments(nsIArray *attachments,
nsIArray *preloaded_attachments);
nsresult CountCompFieldAttachments();
nsresult AddCompFieldLocalAttachments();
nsresult AddCompFieldRemoteAttachments(uint32_t aStartLocation, int32_t *aMailboxCount, int32_t *aNewsCount);
// Deal with multipart related data
nsresult ProcessMultipartRelated(int32_t *aMailboxCount, int32_t *aNewsCount);
nsresult GetEmbeddedObjectInfo(nsIDOMNode *node, nsMsgAttachmentData *attachment, bool *acceptObject);
uint32_t GetMultipartRelatedCount(bool forceToBeCalculated = false);
nsCOMPtr<nsIArray> mEmbeddedObjectList; // it's initialized when calling GetMultipartRelatedCount
// Body processing
nsresult SnarfAndCopyBody(const nsACString &attachment1_body,
const char *attachment1_type);
int32_t PreProcessPart(nsMsgAttachmentHandler *ma,
nsMsgSendPart *toppart); // The very top most container of the message
// For part processing
nsresult SetStatusMessage(const nsString &aMsgString); // Status message method
//
// All vars necessary for this implementation
//
nsMsgKey m_messageKey; // jt -- Draft/Template support; newly created key
nsCOMPtr<nsIMsgIdentity> mUserIdentity;
nsCString mAccountKey;
RefPtr<nsMsgCompFields> mCompFields; // All needed composition fields (header, etc...)
nsCOMPtr<nsIFile> mTempFile; // our temporary file
nsCOMPtr<nsIOutputStream> mOutputFile; // the actual output file stream
uint32_t mMessageWarningSize; // Warn if a message is over this size!
bool m_dont_deliver_p; // If set, we just return the nsIFile of the file
// created, instead of actually delivering message.
nsMsgDeliverMode m_deliver_mode; // nsMsgDeliverNow, nsMsgQueueForLater, nsMsgSaveAsDraft,
// nsMsgSaveAsTemplate and nsMsgSendUnsent
nsCOMPtr<nsIMsgDBHdr> mMsgToReplace; // If the mode is nsMsgSaveAsDraft, this is the message it will
// replace
nsString mSavedToFolderName; // Name of folder we're saving to, used when
// displaying error on save.
// These are needed for callbacks to the FE...
nsCOMPtr<nsPIDOMWindowOuter> mParentWindow;
nsCOMPtr<nsIMsgProgress> mSendProgress;
nsCOMPtr<nsIMsgSendListener> mListener;
nsCOMPtr<nsIMsgStatusFeedback> mStatusFeedback;
nsCOMPtr<nsIRequest> mRunningRequest;
bool mSendMailAlso;
nsCOMPtr<nsIFile> mReturnFile; // a holder for file spec's to be returned to caller
// File where we stored our HTML so that we could make the plaintext form.
nsCOMPtr<nsIFile> mHTMLFile;
// Variable for storing the draft name;
nsCString m_folderName;
// mapping between editor dom node indexes and saved mime part numbers.
nsTArray<nsCString> m_partNumbers;
//
// These variables are needed for message Copy operations!
//
nsCOMPtr<nsIFile> mCopyFile;
nsCOMPtr<nsIFile> mCopyFile2;
RefPtr<nsMsgCopy> mCopyObj;
bool mNeedToPerformSecondFCC;
bool mPerformingSecondFCC;
// For MHTML message creation
nsCOMPtr<nsIEditor> mEditor;
//
// The first attachment, if any (typed in by the user.)
//
char *m_attachment1_type;
char *m_attachment1_encoding;
nsAutoPtr<MimeEncoder> m_attachment1_encoder;
char *m_attachment1_body;
uint32_t m_attachment1_body_length;
char *mOriginalHTMLBody;
// The plaintext form of the first attachment, if needed.
RefPtr<nsMsgAttachmentHandler> m_plaintext;
// The multipart/related save object for HTML text.
nsMsgSendPart *m_related_part;
nsMsgSendPart *m_related_body_part;
//
// Subsequent attachments, if any.
//
uint32_t m_attachment_count;
uint32_t m_attachment_pending_count;
nsTArray< RefPtr<nsMsgAttachmentHandler> > m_attachments;
nsresult m_status; // in case some attachments fail but not all
uint32_t mPreloadedAttachmentCount;
uint32_t mRemoteAttachmentCount;
int32_t mMultipartRelatedAttachmentCount; // the number of mpart related attachments, -1 means it has not been yet initialized
uint32_t mCompFieldLocalAttachments; // the number of file:// attachments in the comp fields
uint32_t mCompFieldRemoteAttachments; // the number of remote attachments in the comp fields
//
// attachment states and other info...
//
bool m_pre_snarfed_attachments_p; // If true, then the attachments were
// loaded by in the background and therefore
// we shouldn't delete the tmp files (but should
// leave that to the caller.)
bool m_digest_p; // Whether to be multipart/digest instead of
// multipart/mixed.
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.
bool mGUINotificationEnabled; // Should we throw up the GUI alerts on errors?
bool mAbortInProcess; // Used by Abort to avoid reentrance.
nsCOMPtr<nsIMsgComposeSecure> m_crypto_closure;
protected:
nsCOMPtr<nsIStringBundle> mComposeBundle;
nsresult GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks);
virtual ~nsMsgComposeAndSend();
nsresult FilterSentMessage();
nsresult MaybePerformSecondFCC(nsresult aStatus);
// generates a message id for our message, if necessary
void GenerateMessageId( );
// add default custom headers to the message
nsresult AddDefaultCustomHeaders();
// add Mail-Followup-To and Mail-Reply-To header
nsresult AddMailFollowupToHeader();
nsresult AddMailReplyToHeader();
nsresult AddXForwardedMessageIdHeader();
nsCOMPtr<nsIMsgSendReport> mSendReport;
nsCString mSmtpPassword; // store the smtp Password use during a send
};
//
// These C routines should only be used by the nsMsgSendPart class.
//
extern nsresult mime_write_message_body(nsIMsgSend *state, const char *buf, uint32_t size);
extern char *mime_get_stream_write_buffer(void);
extern nsresult mime_encoder_output_fn (const char *buf, int32_t size, void *closure);
extern bool UseQuotedPrintable(void);
#endif /* __MSGSEND_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,144 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsMsgSendLater_H_
#define _nsMsgSendLater_H_
#include "nsCOMArray.h"
#include "nsIMsgFolder.h"
#include "nsIMsgSendListener.h"
#include "nsIMsgSendLaterListener.h"
#include "nsIMsgSendLater.h"
#include "nsIMsgStatusFeedback.h"
#include "nsTObserverArray.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsIMsgShutdown.h"
////////////////////////////////////////////////////////////////////////////////////
// This is the listener class for the send operation. We have to create this class
// to listen for message send completion and eventually notify the caller
////////////////////////////////////////////////////////////////////////////////////
class nsMsgSendLater;
class SendOperationListener : public nsIMsgSendListener,
public nsIMsgCopyServiceListener
{
public:
SendOperationListener(nsMsgSendLater *aSendLater);
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGSENDLISTENER
NS_DECL_NSIMSGCOPYSERVICELISTENER
private:
virtual ~SendOperationListener();
nsMsgSendLater *mSendLater;
};
class nsMsgSendLater: public nsIMsgSendLater,
public nsIFolderListener,
public nsIObserver,
public nsIUrlListener,
public nsIMsgShutdownTask
{
public:
nsMsgSendLater();
nsresult Init();
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGSENDLATER
NS_DECL_NSIFOLDERLISTENER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIOBSERVER
NS_DECL_NSIURLLISTENER
NS_DECL_NSIMSGSHUTDOWNTASK
// Methods needed for implementing interface...
nsresult StartNextMailFileSend(nsresult prevStatus);
nsresult CompleteMailFileSend();
nsresult DeleteCurrentMessage();
nsresult SetOrigMsgDisposition();
// Necessary for creating a valid list of recipients
nsresult BuildHeaders();
nsresult DeliverQueuedLine(char *line, int32_t length);
nsresult RebufferLeftovers(char *startBuf, uint32_t aLen);
nsresult BuildNewBuffer(const char* aBuf, uint32_t aCount, uint32_t *totalBufSize);
// methods for listener array processing...
void NotifyListenersOnStartSending(uint32_t aTotalMessageCount);
void NotifyListenersOnMessageStartSending(uint32_t aCurrentMessage,
uint32_t aTotalMessage,
nsIMsgIdentity *aIdentity);
void NotifyListenersOnProgress(uint32_t aCurrentMessage,
uint32_t aTotalMessage,
uint32_t aSendPercent,
uint32_t aCopyPercent);
void NotifyListenersOnMessageSendError(uint32_t aCurrentMessage,
nsresult aStatus,
const char16_t *aMsg);
void EndSendMessages(nsresult aStatus, const char16_t *aMsg,
uint32_t aTotalTried, uint32_t aSuccessful);
bool OnSendStepFinished(nsresult aStatus);
void OnCopyStepFinished(nsresult aStatus);
// counters and things for enumeration
uint32_t mTotalSentSuccessfully;
uint32_t mTotalSendCount;
nsCOMArray<nsIMsgDBHdr> mMessagesToSend;
nsCOMPtr<nsISimpleEnumerator> mEnumerator;
nsCOMPtr<nsIMsgFolder> mMessageFolder;
nsCOMPtr<nsIMsgStatusFeedback> mFeedback;
// Private Information
private:
virtual ~nsMsgSendLater();
nsresult GetIdentityFromKey(const char *aKey, nsIMsgIdentity **aIdentity);
nsresult ReparseDBIfNeeded(nsIUrlListener *aListener);
nsresult InternalSendMessages(bool aUserInitiated,
nsIMsgIdentity *aIdentity);
nsTObserverArray<nsCOMPtr<nsIMsgSendLaterListener> > mListenerArray;
nsCOMPtr<nsIMsgDBHdr> mMessage;
nsCOMPtr<nsITimer> mTimer;
bool mTimerSet;
nsCOMPtr<nsIUrlListener> mShutdownListener;
//
// File output stuff...
//
nsCOMPtr<nsIFile> mTempFile;
nsCOMPtr<nsIOutputStream> mOutFile;
// For building headers and stream parsing...
char *m_to;
char *m_bcc;
char *m_fcc;
char *m_newsgroups;
char *m_newshost;
char *m_headers;
int32_t m_flags;
int32_t m_headersFP;
bool m_inhead;
int32_t m_headersPosition;
int32_t m_bytesRead;
int32_t m_position;
int32_t m_flagsPosition;
int32_t m_headersSize;
char *mLeftoverBuffer;
char *mIdentityKey;
char *mAccountKey;
bool mSendingMessages;
bool mUserInitiated;
nsCOMPtr<nsIMsgIdentity> mIdentity;
};
#endif /* _nsMsgSendLater_H_ */

View file

@ -0,0 +1,779 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgLocalFolderHdrs.h"
#include "nsMsgSend.h"
#include "nsMsgSendPart.h"
#include "nsIMimeConverter.h"
#include "nsCOMPtr.h"
#include "nsIComponentManager.h"
#include "nsMsgI18N.h"
#include "nsMsgCompUtils.h"
#include "nsMsgMimeCID.h"
#include "nsMimeTypes.h"
#include "prmem.h"
#include "nsMsgPrompts.h"
#include "nsNativeCharsetUtils.h"
#include "nsNetUtil.h"
#include "nsISeekableStream.h"
#include "nsReadLine.h"
#include "nsILineInputStream.h"
#include "nsComposeStrings.h"
#include "mozilla/mailnews/MimeEncoder.h"
static char *mime_mailto_stream_read_buffer = 0;
int32_t nsMsgSendPart::M_counter = 0;
nsMsgSendPart::nsMsgSendPart(nsIMsgSend* state, const char *part_charset)
{
PL_strncpy(m_charset_name, (part_charset ? part_charset : "UTF-8"), sizeof(m_charset_name)-1);
m_charset_name[sizeof(m_charset_name)-1] = '\0';
m_children = nullptr;
m_numchildren = 0;
// if we're not added as a child, the default part number will be "1".
m_partNum = "1";
SetMimeDeliveryState(state);
m_parent = nullptr;
m_buffer = nullptr;
m_type = nullptr;
m_other = nullptr;
m_strip_sensitive_headers = false;
m_firstBlock = false;
m_needIntlConversion = false;
m_mainpart = false;
m_just_hit_CR = false;
}
nsMsgSendPart::~nsMsgSendPart()
{
for (int i=0 ; i < m_numchildren; i++)
delete m_children[i];
delete [] m_children;
PR_FREEIF(m_buffer);
PR_FREEIF(m_other);
PR_FREEIF(m_type);
}
nsresult nsMsgSendPart::CopyString(char** dest, const char* src)
{
NS_ASSERTION(src, "src null");
PR_FREEIF(*dest);
if (!src)
*dest = PL_strdup("");
else
*dest = PL_strdup(src);
return *dest? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult nsMsgSendPart::SetFile(nsIFile *file)
{
m_file = file;
return NS_OK;
}
nsresult nsMsgSendPart::SetBuffer(const char* buffer)
{
PR_FREEIF(m_buffer);
return CopyString(&m_buffer, buffer);
}
nsresult nsMsgSendPart::SetType(const char* type)
{
PR_FREEIF(m_type);
m_type = PL_strdup(type);
return m_type ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult nsMsgSendPart::SetOtherHeaders(const char* other)
{
return CopyString(&m_other, other);
}
nsresult nsMsgSendPart::SetMimeDeliveryState(nsIMsgSend *state)
{
m_state = state;
if (GetNumChildren() > 0)
{
for (int i = 0; i < GetNumChildren(); i++)
{
nsMsgSendPart *part = GetChild(i);
if (part)
part->SetMimeDeliveryState(state);
}
}
return NS_OK;
}
nsresult nsMsgSendPart::AppendOtherHeaders(const char* more)
{
if (!m_other)
return SetOtherHeaders(more);
if (!more || !*more)
return NS_OK;
char* tmp = (char *) PR_Malloc(sizeof(char) * (PL_strlen(m_other) + PL_strlen(more) + 2));
if (!tmp)
return NS_ERROR_OUT_OF_MEMORY;
PL_strcpy(tmp, m_other);
PL_strcat(tmp, more);
PR_FREEIF(m_other);
m_other = tmp;
return NS_OK;
}
nsresult nsMsgSendPart::SetMainPart(bool value)
{
m_mainpart = value;
return NS_OK;
}
nsresult nsMsgSendPart::AddChild(nsMsgSendPart* child)
{
m_numchildren++;
nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren];
if (tmp == nullptr) return NS_ERROR_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;
nsCString partNum(m_partNum);
partNum.Append(".");
partNum.AppendInt(m_numchildren);
child->m_partNum = partNum;
return NS_OK;
}
nsMsgSendPart * nsMsgSendPart::DetachChild(int32_t whichOne)
{
nsMsgSendPart *returnValue = nullptr;
NS_ASSERTION(whichOne >= 0 && whichOne < m_numchildren, "parameter out of range");
if (whichOne >= 0 && whichOne < m_numchildren)
{
returnValue = m_children[whichOne];
if (m_numchildren > 1)
{
nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren-1];
if (tmp != nullptr)
{
// 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 = nullptr;
m_numchildren = 0;
}
}
if (returnValue)
returnValue->m_parent = nullptr;
return returnValue;
}
nsMsgSendPart* nsMsgSendPart::GetChild(int32_t which)
{
NS_ASSERTION(which >= 0 && which < m_numchildren, "parameter out of range");
if (which >= 0 && which < m_numchildren) {
return m_children[which];
}
return nullptr;
}
nsresult nsMsgSendPart::PushBody(const char* buffer, int32_t length)
{
nsresult status = NS_OK;
const char* encoded_data = buffer;
if (m_encoder)
{
status = m_encoder->Write(encoded_data, length);
}
else
{
// Merely translate all linebreaks to CRLF.
const char *in = encoded_data;
const char *end = in + length;
char *buffer, *out;
buffer = mime_get_stream_write_buffer();
// XXX -1 is not a valid nsresult
NS_ENSURE_TRUE(buffer, static_cast<nsresult>(-1));
NS_ASSERTION(encoded_data != buffer, "encoded_data == buffer");
out = buffer;
for (; in < end; in++) {
if (m_just_hit_CR) {
m_just_hit_CR = false;
if (*in == '\n') {
// 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 == '\r' || *in == '\n') {
/* Write out the newline. */
*out++ = '\r';
*out++ = '\n';
status = mime_write_message_body(m_state, buffer,
out - buffer);
if (NS_FAILED(status)) return status;
out = buffer;
if (*in == '\r') {
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 (NS_FAILED(status)) return status;
out = buffer;
}
*out++ = *in;
}
}
/* Flush the last line. */
if (out > buffer) {
status = mime_write_message_body(m_state, buffer, out - buffer);
if (NS_FAILED(status)) return status;
out = buffer;
}
}
if (encoded_data && encoded_data != buffer) {
PR_Free((char *) 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 nsresult
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 = PL_strlen(headers);
if (L == 0)
return NS_OK;
*message_headers = (char *)PR_Malloc(L+1);
if (!*message_headers)
return NS_ERROR_OUT_OF_MEMORY;
*content_headers = (char *)PR_Malloc(L+1);
if (!*content_headers) {
PR_Free(*message_headers);
return NS_ERROR_OUT_OF_MEMORY;
}
*content_type_header = (char *)PR_Malloc(L+1);
if (!*content_type_header) {
PR_Free(*message_headers);
PR_Free(*content_headers);
return NS_ERROR_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(true) {
/* Loop until we reach a newline that is not followed by whitespace.
*/
if (tail[0] == 0 ||
((tail[0] == '\r' || tail[0] == '\n') &&
!(tail[1] == ' ' || tail[1] == '\t' || tail[1] == '\n')))
{
/* Swallow the whole newline. */
if (tail[0] == '\r' && tail[1] == '\n')
tail++;
if (*tail)
tail++;
break;
}
tail++;
}
/* Decide which block this header goes into.
*/
if (!PL_strncasecmp(head, "Content-Type:", 13))
out = &type_tail;
else
if (!PL_strncasecmp(head, "Content-", 8))
out = &content_tail;
else
out = &message_tail;
memcpy(*out, head, (tail-head));
*out += (tail-head);
}
*message_tail = 0;
*content_tail = 0;
*type_tail = 0;
if (!**message_headers) {
PR_Free(*message_headers);
*message_headers = 0;
}
if (!**content_headers) {
PR_Free(*content_headers);
*content_headers = 0;
}
if (!**content_type_header) {
PR_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 = PL_strstr(*content_type_header, "Content-Type");
if (tmp) {
tmp++; // get past the first occurrence
NS_ASSERTION(!PL_strstr(tmp, "Content-Type"), "Content-part already present");
}
}
if (*content_headers) {
tmp = PL_strstr(*content_headers, "Content-Transfer-Encoding");
if (tmp) {
tmp++; // get past the first occurrence
NS_ASSERTION(!PL_strstr(tmp, "Content-Transfer-Encoding"), "Content-Transfert already present");
}
}
#endif // DEBUG
return NS_OK;
}
#define SKIP_EMPTY_PART 1966
nsresult
nsMsgSendPart::Write()
{
nsresult status = NS_OK;
char *separator = nullptr;
bool needToWriteCRLFAfterEncodedBody = false;
#define PUSHLEN(str, length) \
do { \
status = mime_write_message_body(m_state, str, length); \
if (NS_FAILED(status)) goto FAIL; \
} while (0) \
#define PUSH(str) PUSHLEN(str, PL_strlen(str))
// rhp: Suppress the output of parts that are empty!
if ( (m_parent) &&
(m_numchildren == 0) &&
( (!m_buffer) || (!*m_buffer) ) &&
(!m_file) &&
(!m_mainpart) )
// XXX SKIP_EMPTY_PART (= 1966) is not a valid nsresult
return static_cast<nsresult>(SKIP_EMPTY_PART);
if (m_mainpart && m_type && PL_strcmp(m_type, TEXT_HTML) == 0)
{
if (m_file)
{
// The "insert HTML links" code requires a memory buffer,
// so read the file into memory.
NS_ASSERTION(m_buffer == nullptr, "not-null buffer");
int32_t length = 0;
int64_t fileSize;
if (NS_SUCCEEDED(m_file->GetFileSize(&fileSize)))
length = fileSize;
m_buffer = (char *) PR_Malloc(sizeof(char) * (length + 1));
if (m_buffer)
{
nsCOMPtr<nsIInputStream> inputFile;
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputFile), m_file);
if (NS_SUCCEEDED(rv))
{
uint32_t bytesRead;
rv = inputFile->Read(m_buffer, length, &bytesRead);
inputFile->Close();
m_buffer[length] = '\0';
}
else
PR_Free(m_buffer);
}
}
}
if (m_parent && m_parent->m_type &&
!PL_strcasecmp(m_parent->m_type, MULTIPART_DIGEST) &&
m_type &&
(!PL_strcasecmp(m_type, MESSAGE_RFC822) ||
!PL_strcasecmp(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 (NS_FAILED(status))
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);
PR_Free(message_headers);
message_headers = 0;
}
/* Now allow the crypto library to (potentially) insert some text
(it may want to wrap the body in an envelope.) */
if (!m_parent) {
status = m_state->BeginCryptoEncapsulation();
if (NS_FAILED(status)) goto FAIL;
}
/* Now make sure there's a Content-Type header.
*/
if (!content_type_header)
{
NS_ASSERTION(m_type && *m_type, "null ptr");
bool needsCharset = mime_type_needs_charset(m_type ? m_type : TEXT_PLAIN);
if (needsCharset)
{
content_type_header = PR_smprintf("Content-Type: %s; charset=%s" CRLF,
(m_type ? m_type : TEXT_PLAIN), m_charset_name);
}
else
content_type_header = PR_smprintf("Content-Type: %s" CRLF,
(m_type ? m_type : TEXT_PLAIN));
if (!content_type_header)
{
if (content_headers)
PR_Free(content_headers);
status = NS_ERROR_OUT_OF_MEMORY;
goto FAIL;
}
}
/* If this is a compound object, tack a boundary string onto the
Content-Type header. this
*/
if (m_numchildren > 0)
{
int L;
char *ct2;
NS_ASSERTION(m_type, "null ptr");
if (!separator)
{
separator = mime_make_separator("");
if (!separator)
{
status = NS_ERROR_OUT_OF_MEMORY;
goto FAIL;
}
}
L = PL_strlen(content_type_header);
if (content_type_header[L-1] == '\n')
content_type_header[--L] = 0;
if (content_type_header[L-1] == '\r')
content_type_header[--L] = 0;
ct2 = PR_smprintf("%s;\r\n boundary=\"%s\"" CRLF, content_type_header, separator);
PR_Free(content_type_header);
if (!ct2)
{
if (content_headers)
PR_Free(content_headers);
status = NS_ERROR_OUT_OF_MEMORY;
goto FAIL;
}
content_type_header = ct2;
}
// Now write out the Content-Type header...
NS_ASSERTION(content_type_header && *content_type_header, "null ptr");
PUSH(content_type_header);
PR_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);
PR_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);
if (m_buffer)
{
status = PushBody(m_buffer, PL_strlen(m_buffer));
if (NS_FAILED(status))
goto FAIL;
}
else if (m_file)
{
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), m_file);
if (NS_FAILED(rv))
{
// mysteriously disappearing?
nsCOMPtr<nsIMsgSendReport> sendReport;
m_state->GetSendReport(getter_AddRefs(sendReport));
if (sendReport)
{
nsAutoString error_msg;
nsMsgBuildMessageWithTmpFile(m_file, error_msg);
sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
}
status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
goto FAIL;
}
nsCString curLine;
bool more = true;
/* Kludge to avoid having to allocate memory on the toy computers... */
if (!mime_mailto_stream_read_buffer)
{
mime_mailto_stream_read_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
if (!mime_mailto_stream_read_buffer)
{
status = NS_ERROR_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.
bool skipping = false;
nsAutoPtr<nsLineBuffer<char> > lineBuffer(new nsLineBuffer<char>);
NS_ENSURE_TRUE(lineBuffer, NS_ERROR_OUT_OF_MEMORY);
while (more)
{
// NS_ReadLine doesn't return line termination chars.
rv = NS_ReadLine(inputStream.get(), lineBuffer.get(), curLine, &more);
curLine.Append(CRLF);
char *line = (char *) curLine.get();
if (skipping) {
if (*line == ' ' || *line == '\t')
continue;
else
skipping = false;
}
if (!PL_strncasecmp(line, "From -", 6) ||
!PL_strncasecmp(line, "BCC:", 4) ||
!PL_strncasecmp(line, "FCC:", 4) ||
!PL_strncasecmp(line, CONTENT_LENGTH ":", CONTENT_LENGTH_LEN+1) ||
!PL_strncasecmp(line, "Lines:", 6) ||
!PL_strncasecmp(line, "Status:", 7) ||
!PL_strncasecmp(line, X_MOZILLA_STATUS ":", X_MOZILLA_STATUS_LEN+1) ||
!PL_strncasecmp(line, X_MOZILLA_STATUS2 ":", X_MOZILLA_STATUS2_LEN+1) ||
!PL_strncasecmp(line, X_MOZILLA_DRAFT_INFO ":", X_MOZILLA_DRAFT_INFO_LEN+1) ||
!PL_strncasecmp(line, X_MOZILLA_NEWSHOST ":", X_MOZILLA_NEWSHOST_LEN+1) ||
!PL_strncasecmp(line, X_UIDL ":", X_UIDL_LEN+1) ||
!PL_strncasecmp(line, "X-VM-", 5)) /* hi Kyle */
{
skipping = true;
continue;
}
PUSH(line);
if (curLine.Length() == 2) {
nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream);
// seek back the amount of data left in the line buffer...
seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, lineBuffer->start - lineBuffer->end);
break; // Now can do normal reads for the body.
}
}
lineBuffer = nullptr;
}
while (NS_SUCCEEDED(status))
{
uint32_t bytesRead;
nsresult rv = inputStream->Read(buffer, MIME_BUFFER_SIZE, &bytesRead);
if (NS_FAILED(rv))
{
nsCOMPtr<nsIMsgSendReport> sendReport;
m_state->GetSendReport(getter_AddRefs(sendReport));
if (sendReport)
{
nsAutoString error_msg;
nsMsgBuildMessageWithFile(m_file, error_msg);
sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
status = NS_MSG_UNABLE_TO_OPEN_FILE;
goto FAIL;
}
}
status = PushBody(buffer, bytesRead);
if (NS_FAILED(status))
goto FAIL;
if (bytesRead < MIME_BUFFER_SIZE)
break;
}
}
if (m_encoder)
{
nsresult rv = m_encoder->Flush();
m_encoder = nullptr;
needToWriteCRLFAfterEncodedBody = !m_parent;
if (NS_FAILED(rv))
{
// XXX -1 is not a valid nsresult
status = static_cast<nsresult>(-1);
goto FAIL;
}
}
//
// Ok, from here we loop and drive the the output of all children
// for this message.
//
if (m_numchildren > 0)
{
bool writeSeparator = true;
for (int i = 0 ; i < m_numchildren ; i ++)
{
if (writeSeparator)
{
PUSH(CRLF);
PUSH("--");
PUSH(separator);
PUSH(CRLF);
}
status = m_children[i]->Write();
if (NS_FAILED(status))
goto FAIL;
// XXX SKIP_EMPTY_PART (= 1966) is not a valid nsresult
if (status == static_cast<nsresult>(SKIP_EMPTY_PART))
writeSeparator = false;
else
writeSeparator = true;
}
PUSH(CRLF);
PUSH("--");
PUSH(separator);
PUSH("--");
PUSH(CRLF);
}
else if (needToWriteCRLFAfterEncodedBody)
PUSH(CRLF);
FAIL:
PR_FREEIF(separator);
return status;
}

View file

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MsgSendPart_H_
#define _MsgSendPart_H_
#include "msgCore.h"
#include "prprf.h" /* should be defined into msgCore.h? */
#include "nsMsgSend.h"
namespace mozilla {
namespace mailnews {
class MimeEncoder;
}
}
typedef int (*MSG_SendPartWriteFunc)(const char* line, int32_t size,
bool isheader, void* closure);
class nsMsgSendPart {
typedef mozilla::mailnews::MimeEncoder MimeEncoder;
public:
nsMsgSendPart(nsIMsgSend* state, const char *part_charset = NULL);
virtual ~nsMsgSendPart(); // Note that the destructor also destroys
// any children that were added.
virtual nsresult Write();
virtual nsresult SetFile(nsIFile *filename);
const nsIFile *GetFile() {return m_file;}
virtual nsresult SetBuffer(const char* buffer);
const char *GetBuffer() {return m_buffer;}
virtual nsresult SetType(const char* type);
const char *GetType() {return m_type;}
const char *GetCharsetName() {return m_charset_name;}
virtual nsresult SetOtherHeaders(const char* other);
const char *SetOtherHeaders() {return m_other;}
virtual nsresult AppendOtherHeaders(const char* moreother);
virtual nsresult SetMimeDeliveryState(nsIMsgSend* state);
// Note that the nsMsgSendPart 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.)
void SetEncoder(MimeEncoder* encoder) {m_encoder = encoder;}
MimeEncoder *GetEncoder() {return m_encoder;}
void SetStripSensitiveHeaders(bool value)
{
m_strip_sensitive_headers = value;
}
bool GetStripSensitiveHeaders() {return m_strip_sensitive_headers;}
virtual nsresult AddChild(nsMsgSendPart* child);
int32_t GetNumChildren() {return m_numchildren;}
nsMsgSendPart *GetChild(int32_t which);
nsMsgSendPart *DetachChild(int32_t which);
virtual nsresult SetMainPart(bool value);
bool IsMainPart()
{
return m_mainpart;
}
nsCString m_partNum;
protected:
nsresult CopyString(char** dest, const char* src);
nsresult PushBody(const char* buffer, int32_t length);
nsCOMPtr<nsIMsgSend> m_state;
nsMsgSendPart *m_parent;
nsCOMPtr <nsIFile> m_file;
char *m_buffer;
char *m_type;
char *m_other;
char m_charset_name[64+1]; // charset name associated with this part
bool m_strip_sensitive_headers;
nsAutoPtr<MimeEncoder> m_encoder;
nsMsgSendPart **m_children;
int32_t m_numchildren;
// Data used while actually writing.
bool m_firstBlock;
bool m_needIntlConversion;
bool m_mainpart;
bool m_just_hit_CR;
static int32_t M_counter;
};
#endif /* _MsgSendPart_H_ */

View file

@ -0,0 +1,437 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsMsgSendReport.h"
#include "msgCore.h"
#include "nsIMsgCompose.h"
#include "nsMsgCompCID.h"
#include "nsMsgPrompts.h"
#include "nsError.h"
#include "nsComposeStrings.h"
#include "nsIStringBundle.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/Services.h"
NS_IMPL_ISUPPORTS(nsMsgProcessReport, nsIMsgProcessReport)
nsMsgProcessReport::nsMsgProcessReport()
{
Reset();
}
nsMsgProcessReport::~nsMsgProcessReport()
{
}
/* attribute boolean proceeded; */
NS_IMETHODIMP nsMsgProcessReport::GetProceeded(bool *aProceeded)
{
NS_ENSURE_ARG_POINTER(aProceeded);
*aProceeded = mProceeded;
return NS_OK;
}
NS_IMETHODIMP nsMsgProcessReport::SetProceeded(bool aProceeded)
{
mProceeded = aProceeded;
return NS_OK;
}
/* attribute nsresult error; */
NS_IMETHODIMP nsMsgProcessReport::GetError(nsresult *aError)
{
NS_ENSURE_ARG_POINTER(aError);
*aError = mError;
return NS_OK;
}
NS_IMETHODIMP nsMsgProcessReport::SetError(nsresult aError)
{
mError = aError;
return NS_OK;
}
/* attribute wstring message; */
NS_IMETHODIMP nsMsgProcessReport::GetMessage(char16_t * *aMessage)
{
NS_ENSURE_ARG_POINTER(aMessage);
*aMessage = ToNewUnicode(mMessage);
return NS_OK;
}
NS_IMETHODIMP nsMsgProcessReport::SetMessage(const char16_t * aMessage)
{
mMessage = aMessage;
return NS_OK;
}
/* void Reset (); */
NS_IMETHODIMP nsMsgProcessReport::Reset()
{
mProceeded = false;
mError = NS_OK;
mMessage.Truncate();
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsMsgSendReport, nsIMsgSendReport)
nsMsgSendReport::nsMsgSendReport()
{
uint32_t i;
for (i = 0; i <= SEND_LAST_PROCESS; i ++)
mProcessReport[i] = new nsMsgProcessReport();
Reset();
}
nsMsgSendReport::~nsMsgSendReport()
{
uint32_t i;
for (i = 0; i <= SEND_LAST_PROCESS; i ++)
mProcessReport[i] = nullptr;
}
/* attribute long currentProcess; */
NS_IMETHODIMP nsMsgSendReport::GetCurrentProcess(int32_t *aCurrentProcess)
{
NS_ENSURE_ARG_POINTER(aCurrentProcess);
*aCurrentProcess = mCurrentProcess;
return NS_OK;
}
NS_IMETHODIMP nsMsgSendReport::SetCurrentProcess(int32_t aCurrentProcess)
{
if (aCurrentProcess < 0 || aCurrentProcess > SEND_LAST_PROCESS)
return NS_ERROR_ILLEGAL_VALUE;
mCurrentProcess = aCurrentProcess;
if (mProcessReport[mCurrentProcess])
mProcessReport[mCurrentProcess]->SetProceeded(true);
return NS_OK;
}
/* attribute long deliveryMode; */
NS_IMETHODIMP nsMsgSendReport::GetDeliveryMode(int32_t *aDeliveryMode)
{
NS_ENSURE_ARG_POINTER(aDeliveryMode);
*aDeliveryMode = mDeliveryMode;
return NS_OK;
}
NS_IMETHODIMP nsMsgSendReport::SetDeliveryMode(int32_t aDeliveryMode)
{
mDeliveryMode = aDeliveryMode;
return NS_OK;
}
/* void Reset (); */
NS_IMETHODIMP nsMsgSendReport::Reset()
{
uint32_t i;
for (i = 0; i <= SEND_LAST_PROCESS; i ++)
if (mProcessReport[i])
mProcessReport[i]->Reset();
mCurrentProcess = 0;
mDeliveryMode = 0;
mAlreadyDisplayReport = false;
return NS_OK;
}
/* void setProceeded (in long process, in boolean proceeded); */
NS_IMETHODIMP nsMsgSendReport::SetProceeded(int32_t process, bool proceeded)
{
if (process < process_Current || process > SEND_LAST_PROCESS)
return NS_ERROR_ILLEGAL_VALUE;
if (process == process_Current)
process = mCurrentProcess;
if (!mProcessReport[process])
return NS_ERROR_NOT_INITIALIZED;
return mProcessReport[process]->SetProceeded(proceeded);
}
/* void setError (in long process, in nsresult error, in boolean overwriteError); */
NS_IMETHODIMP nsMsgSendReport::SetError(int32_t process, nsresult newError, bool overwriteError)
{
if (process < process_Current || process > SEND_LAST_PROCESS)
return NS_ERROR_ILLEGAL_VALUE;
if (process == process_Current)
{
if (mCurrentProcess == process_Current)
// We don't know what we're currently trying to do
return NS_ERROR_ILLEGAL_VALUE;
process = mCurrentProcess;
}
if (!mProcessReport[process])
return NS_ERROR_NOT_INITIALIZED;
nsresult currError = NS_OK;
mProcessReport[process]->GetError(&currError);
if (overwriteError || NS_SUCCEEDED(currError))
return mProcessReport[process]->SetError(newError);
else
return NS_OK;
}
/* void setMessage (in long process, in wstring message, in boolean overwriteMessage); */
NS_IMETHODIMP nsMsgSendReport::SetMessage(int32_t process, const char16_t *message, bool overwriteMessage)
{
if (process < process_Current || process > SEND_LAST_PROCESS)
return NS_ERROR_ILLEGAL_VALUE;
if (process == process_Current)
{
if (mCurrentProcess == process_Current)
// We don't know what we're currently trying to do
return NS_ERROR_ILLEGAL_VALUE;
process = mCurrentProcess;
}
if (!mProcessReport[process])
return NS_ERROR_NOT_INITIALIZED;
nsString currMessage;
mProcessReport[process]->GetMessage(getter_Copies(currMessage));
if (overwriteMessage || currMessage.IsEmpty())
return mProcessReport[process]->SetMessage(message);
else
return NS_OK;
}
/* nsIMsgProcessReport getProcessReport (in long process); */
NS_IMETHODIMP nsMsgSendReport::GetProcessReport(int32_t process, nsIMsgProcessReport **_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
if (process < process_Current || process > SEND_LAST_PROCESS)
return NS_ERROR_ILLEGAL_VALUE;
if (process == process_Current)
{
if (mCurrentProcess == process_Current)
// We don't know what we're currently trying to do
return NS_ERROR_ILLEGAL_VALUE;
process = mCurrentProcess;
}
NS_IF_ADDREF(*_retval = mProcessReport[process]);
return NS_OK;
}
/* nsresult displayReport (in nsIPrompt prompt, in boolean showErrorOnly, in boolean dontShowReportTwice); */
NS_IMETHODIMP nsMsgSendReport::DisplayReport(nsIPrompt *prompt, bool showErrorOnly, bool dontShowReportTwice, nsresult *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
NS_ENSURE_TRUE(mCurrentProcess >= 0 && mCurrentProcess <= SEND_LAST_PROCESS,
NS_ERROR_NOT_INITIALIZED);
nsresult currError = NS_OK;
mProcessReport[mCurrentProcess]->GetError(&currError);
*_retval = currError;
if (dontShowReportTwice && mAlreadyDisplayReport)
return NS_OK;
if (showErrorOnly && NS_SUCCEEDED(currError))
return NS_OK;
nsString currMessage;
mProcessReport[mCurrentProcess]->GetMessage(getter_Copies(currMessage));
nsresult rv; // don't step on currError.
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
if (NS_FAILED(rv))
{
//TODO need to display a generic hardcoded message
mAlreadyDisplayReport = true;
return NS_OK;
}
nsString dialogTitle;
nsString dialogMessage;
if (NS_SUCCEEDED(currError))
{
//TODO display a success error message
return NS_OK;
}
//Do we have an explanation of the error? if no, try to build one...
if (currMessage.IsEmpty())
{
#ifdef __GNUC__
// Temporary workaroung until bug 783526 is fixed.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
#endif
switch (currError)
{
case NS_BINDING_ABORTED:
case NS_ERROR_SEND_FAILED:
case NS_ERROR_SEND_FAILED_BUT_NNTP_OK:
case NS_MSG_FAILED_COPY_OPERATION:
case NS_MSG_UNABLE_TO_SEND_LATER:
case NS_MSG_UNABLE_TO_SAVE_DRAFT:
case NS_MSG_UNABLE_TO_SAVE_TEMPLATE:
//Ignore, don't need to repeat ourself.
break;
default:
const char16_t* errorString = errorStringNameForErrorCode(currError);
nsMsgGetMessageByName(errorString, currMessage);
break;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
if (mDeliveryMode == nsIMsgCompDeliverMode::Now || mDeliveryMode == nsIMsgCompDeliverMode::SendUnsent)
{
// SMTP is taking care of it's own error message and will return NS_ERROR_BUT_DONT_SHOW_ALERT as error code.
// In that case, we must not show an alert ourself.
if (currError == NS_ERROR_BUT_DONT_SHOW_ALERT)
{
mAlreadyDisplayReport = true;
return NS_OK;
}
bundle->GetStringFromName(u"sendMessageErrorTitle",
getter_Copies(dialogTitle));
const char16_t* preStrName = u"sendFailed";
bool askToGoBackToCompose = false;
switch (mCurrentProcess)
{
case process_BuildMessage :
preStrName = u"sendFailed";
askToGoBackToCompose = false;
break;
case process_NNTP :
preStrName = u"sendFailed";
askToGoBackToCompose = false;
break;
case process_SMTP :
bool nntpProceeded;
mProcessReport[process_NNTP]->GetProceeded(&nntpProceeded);
if (nntpProceeded)
preStrName = u"sendFailedButNntpOk";
else
preStrName = u"sendFailed";
askToGoBackToCompose = false;
break;
case process_Copy:
preStrName = u"failedCopyOperation";
askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
break;
case process_FCC:
preStrName = u"failedCopyOperation";
askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
break;
}
bundle->GetStringFromName(preStrName, getter_Copies(dialogMessage));
//Do we already have an error message?
if (!askToGoBackToCompose && currMessage.IsEmpty())
{
//we don't have an error description but we can put a generic explanation
bundle->GetStringFromName(u"genericFailureExplanation",
getter_Copies(currMessage));
}
if (!currMessage.IsEmpty())
{
//Don't need to repeat ourself!
if (!currMessage.Equals(dialogMessage))
{
if (!dialogMessage.IsEmpty())
dialogMessage.Append(char16_t('\n'));
dialogMessage.Append(currMessage);
}
}
if (askToGoBackToCompose)
{
bool oopsGiveMeBackTheComposeWindow = true;
nsString text1;
bundle->GetStringFromName(u"returnToComposeWindowQuestion",
getter_Copies(text1));
if (!dialogMessage.IsEmpty())
dialogMessage.AppendLiteral("\n");
dialogMessage.Append(text1);
nsMsgAskBooleanQuestionByString(prompt, dialogMessage.get(), &oopsGiveMeBackTheComposeWindow, dialogTitle.get());
if (!oopsGiveMeBackTheComposeWindow)
*_retval = NS_OK;
}
else
nsMsgDisplayMessageByString(prompt, dialogMessage.get(), dialogTitle.get());
}
else
{
const char16_t* title;
const char16_t* messageName;
switch (mDeliveryMode)
{
case nsIMsgCompDeliverMode::Later:
title = u"sendLaterErrorTitle";
messageName = u"unableToSendLater";
break;
case nsIMsgCompDeliverMode::AutoSaveAsDraft:
case nsIMsgCompDeliverMode::SaveAsDraft:
title = u"saveDraftErrorTitle";
messageName = u"unableToSaveDraft";
break;
case nsIMsgCompDeliverMode::SaveAsTemplate:
title = u"saveTemplateErrorTitle";
messageName = u"unableToSaveTemplate";
break;
default:
/* This should never happen! */
title = u"sendMessageErrorTitle";
messageName = u"sendFailed";
break;
}
bundle->GetStringFromName(title, getter_Copies(dialogTitle));
bundle->GetStringFromName(messageName,
getter_Copies(dialogMessage));
//Do we have an error message...
if (currMessage.IsEmpty())
{
//we don't have an error description but we can put a generic explanation
bundle->GetStringFromName(u"genericFailureExplanation",
getter_Copies(currMessage));
}
if (!currMessage.IsEmpty())
{
if (!dialogMessage.IsEmpty())
dialogMessage.Append(char16_t('\n'));
dialogMessage.Append(currMessage);
}
nsMsgDisplayMessageByString(prompt, dialogMessage.get(), dialogTitle.get());
}
mAlreadyDisplayReport = true;
return NS_OK;
}

View file

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsMsgSendReport_h__
#define __nsMsgSendReport_h__
#include "nsIMsgSendReport.h"
#include "nsStringGlue.h"
#include "nsCOMPtr.h"
class nsMsgProcessReport : public nsIMsgProcessReport
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGPROCESSREPORT
nsMsgProcessReport();
private:
virtual ~nsMsgProcessReport();
bool mProceeded;
nsresult mError;
nsString mMessage;
};
class nsMsgSendReport : public nsIMsgSendReport
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGSENDREPORT
nsMsgSendReport();
private:
virtual ~nsMsgSendReport();
#define SEND_LAST_PROCESS process_FCC
nsCOMPtr<nsIMsgProcessReport> mProcessReport[SEND_LAST_PROCESS + 1];
int32_t mDeliveryMode;
int32_t mCurrentProcess;
bool mAlreadyDisplayReport;
};
#endif

View file

@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var kNetworkProtocolCIDPrefix = "@mozilla.org/network/protocol;1?name=";
var nsIProtocolHandler = Components.interfaces.nsIProtocolHandler;
function makeProtocolHandler(aProtocol, aDefaultPort, aClassID) {
return {
classID: Components.ID(aClassID),
QueryInterface: XPCOMUtils.generateQI([nsIProtocolHandler]),
scheme: aProtocol,
defaultPort: aDefaultPort,
protocolFlags: nsIProtocolHandler.URI_NORELATIVE |
nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
nsIProtocolHandler.URI_NON_PERSISTABLE |
nsIProtocolHandler.ALLOWS_PROXY |
nsIProtocolHandler.URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT,
newURI: function (aSpec, aOriginCharset, aBaseURI) {
var url = Components.classes["@mozilla.org/messengercompose/smtpurl;1"]
.createInstance(Components.interfaces.nsIURI);
url.spec = aSpec;
return url;
},
newChannel: function (aURI) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
newChannel2: function(aURI, aLoadInfo)
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
allowPort: function (port, scheme) {
return port == aDefaultPort;
}
};
}
function nsSMTPProtocolHandler() {}
nsSMTPProtocolHandler.prototype =
makeProtocolHandler("smtp",
Components.interfaces.nsISmtpUrl.DEFAULT_SMTP_PORT,
"b14c2b67-8680-4c11-8d63-9403c7d4f757");
function nsSMTPSProtocolHandler() {}
nsSMTPSProtocolHandler.prototype =
makeProtocolHandler("smtps",
Components.interfaces.nsISmtpUrl.DEFAULT_SMTPS_PORT,
"057d0997-9e3a-411e-b4ee-2602f53fe05f");
var components = [nsSMTPProtocolHandler, nsSMTPSProtocolHandler];
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View file

@ -0,0 +1,4 @@
component {b14c2b67-8680-4c11-8d63-9403c7d4f757} nsSMTPProtocolHandler.js
contract @mozilla.org/network/protocol;1?name=smtp {b14c2b67-8680-4c11-8d63-9403c7d4f757}
component {057d0997-9e3a-411e-b4ee-2602f53fe05f} nsSMTPProtocolHandler.js
contract @mozilla.org/network/protocol;1?name=smtps {057d0997-9e3a-411e-b4ee-2602f53fe05f}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,225 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsSmtpProtocol_h___
#define nsSmtpProtocol_h___
#include "mozilla/Attributes.h"
#include "msgIOAuth2Module.h"
#include "nsMsgProtocol.h"
#include "nsIStreamListener.h"
#include "nsISmtpUrl.h"
#include "nsIMsgStatusFeedback.h"
#include "nsMsgLineBuffer.h"
#include "nsIAuthModule.h"
#include "MailNewsTypes2.h" // for nsMsgSocketType
#include "nsCOMPtr.h"
#include "nsTArray.h"
class nsIVariant;
class nsIWritableVariant;
/* states of the machine
*/
typedef enum _SmtpState {
SMTP_RESPONSE = 0, // 0
SMTP_START_CONNECT, // 1
SMTP_FINISH_CONNECT, // 2
SMTP_SEND_HELO_RESPONSE, // 3
SMTP_SEND_EHLO_RESPONSE, // 4
SMTP_SEND_MAIL_RESPONSE, // 5
SMTP_SEND_RCPT_RESPONSE, // 6
SMTP_SEND_DATA_RESPONSE, // 7
SMTP_SEND_POST_DATA, // 8
SMTP_SEND_MESSAGE_RESPONSE, // 9
SMTP_DONE, // 10
SMTP_ERROR_DONE, // 11
SMTP_FREE, // 12
SMTP_AUTH_LOGIN_STEP0_RESPONSE, // 13
SMTP_EXTN_LOGIN_RESPONSE, // 14
SMTP_SEND_AUTH_LOGIN_STEP0, // 15
SMTP_SEND_AUTH_LOGIN_STEP1, // 16
SMTP_SEND_AUTH_LOGIN_STEP2, // 17
SMTP_AUTH_LOGIN_RESPONSE, // 18
SMTP_TLS_RESPONSE, // 19
SMTP_AUTH_EXTERNAL_RESPONSE, // 20
SMTP_AUTH_PROCESS_STATE, // 21
SMTP_AUTH_CRAM_MD5_CHALLENGE_RESPONSE, // 22
SMTP_SEND_AUTH_GSSAPI_FIRST, // 23
SMTP_SEND_AUTH_GSSAPI_STEP, // 24
SMTP_SUSPENDED, // 25
SMTP_AUTH_OAUTH2_STEP, // 26
SMTP_AUTH_OAUTH2_RESPONSE, // 27
} SmtpState;
// State Flags (Note, I use the word state in terms of storing
// state information about the connection (authentication, have we sent
// commands, etc. I do not intend it to refer to protocol state)
#define SMTP_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
#define SMTP_ESMTP_SERVER 0x00000002
#define SMTP_EHLO_DSN_ENABLED 0x00000004
#define SMTP_EHLO_STARTTLS_ENABLED 0x00000008
#define SMTP_EHLO_SIZE_ENABLED 0x00000010
#define SMTP_EHLO_8BIT_ENABLED 0x00000020
// insecure mechanisms follow
#define SMTP_AUTH_LOGIN_ENABLED 0x00000100
#define SMTP_AUTH_PLAIN_ENABLED 0x00000200
#define SMTP_AUTH_EXTERNAL_ENABLED 0x00000400
// secure mechanisms follow
#define SMTP_AUTH_GSSAPI_ENABLED 0x00000800
#define SMTP_AUTH_DIGEST_MD5_ENABLED 0x00001000
#define SMTP_AUTH_CRAM_MD5_ENABLED 0x00002000
#define SMTP_AUTH_NTLM_ENABLED 0x00004000
#define SMTP_AUTH_MSN_ENABLED 0x00008000
#define SMTP_AUTH_OAUTH2_ENABLED 0x00010000
// sum of all above auth mechanisms
#define SMTP_AUTH_ANY 0x0001FF00
// indicates that AUTH has been advertised
#define SMTP_AUTH 0x00020000
// No login necessary (pref)
#define SMTP_AUTH_NONE_ENABLED 0x00040000
class nsSmtpProtocol : public nsMsgAsyncWriteProtocol,
public msgIOAuth2ModuleListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_MSGIOAUTH2MODULELISTENER
// Creating a protocol instance requires the URL which needs to be run.
nsSmtpProtocol(nsIURI * aURL);
virtual nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer = nullptr) override;
virtual nsresult SendData(const char * dataBuffer, bool aSuppressLogging = false) override;
////////////////////////////////////////////////////////////////////////////////////////
// we suppport the nsIStreamListener interface
////////////////////////////////////////////////////////////////////////////////////////
// stop binding is a "notification" informing us that the stream associated with aURL is going away.
NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status) override;
private:
virtual ~nsSmtpProtocol();
// if we are asked to load a url while we are blocked waiting for redirection information,
// then we'll store the url consumer in mPendingConsumer until we can actually load
// the url.
nsCOMPtr<nsISupports> mPendingConsumer;
// the nsISmtpURL that is currently running
nsCOMPtr<nsISmtpUrl> m_runningURL;
// the error state we want to set on the url
nsresult m_urlErrorState;
nsCOMPtr<nsIMsgStatusFeedback> m_statusFeedback;
// Generic state information -- What state are we in? What state do we want to go to
// after the next response? What was the last response code? etc.
SmtpState m_nextState;
SmtpState m_nextStateAfterResponse;
int32_t m_responseCode; /* code returned from Smtp server */
int32_t m_previousResponseCode;
int32_t m_continuationResponse;
nsCString m_responseText; /* text returned from Smtp server */
nsMsgLineStreamBuffer *m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream
nsTArray<nsCString> m_addresses;
uint32_t m_addressesLeft;
nsCString m_mailAddr;
nsCString m_helloArgument;
int32_t m_sizelimit;
// *** the following should move to the smtp server when we support
// multiple smtp servers
bool m_usernamePrompted;
int32_t m_prefSocketType;
bool m_tlsEnabled;
bool m_tlsInitiated;
bool m_sendDone;
int32_t m_totalAmountRead;
int64_t m_totalMessageSize;
char *m_dataBuf;
uint32_t m_dataBufSize;
int32_t m_originalContentLength; /* the content length at the time of calling graph progress */
// initialization function given a new url and transport layer
void Initialize(nsIURI * aURL);
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
uint64_t sourceOffset, uint32_t length) override;
////////////////////////////////////////////////////////////////////////////////////////
// Communication methods --> Reading and writing protocol
////////////////////////////////////////////////////////////////////////////////////////
void UpdateStatus(const char16_t* aStatusName);
void UpdateStatusWithString(const char16_t * aStatusString);
////////////////////////////////////////////////////////////////////////////////////////
// Protocol Methods --> This protocol is state driven so each protocol method is
// designed to re-act to the current "state". I've attempted to
// group them together based on functionality.
////////////////////////////////////////////////////////////////////////////////////////
nsresult SmtpResponse(nsIInputStream * inputStream, uint32_t length);
nsresult ExtensionLoginResponse(nsIInputStream * inputStream, uint32_t length);
nsresult SendHeloResponse(nsIInputStream * inputStream, uint32_t length);
nsresult SendEhloResponse(nsIInputStream * inputStream, uint32_t length);
nsresult SendQuit(SmtpState aNextStateAfterResponse = SMTP_DONE);
nsresult AuthGSSAPIFirst();
nsresult AuthGSSAPIStep();
nsresult AuthLoginStep0();
void AuthLoginStep0Response();
nsresult AuthLoginStep1();
nsresult AuthLoginStep2();
nsresult AuthLoginResponse(nsIInputStream * stream, uint32_t length);
nsresult AuthOAuth2Step1();
nsresult SendTLSResponse();
nsresult SendMailResponse();
nsresult SendRecipientResponse();
nsresult SendDataResponse();
void SendPostData();
nsresult SendMessageResponse();
nsresult ProcessAuth();
////////////////////////////////////////////////////////////////////////////////////////
// End of Protocol Methods
////////////////////////////////////////////////////////////////////////////////////////
void SendMessageInFile();
void AppendHelloArgument(nsACString& aResult);
nsresult GetPassword(nsCString &aPassword);
nsresult GetUsernamePassword(nsACString &aUsername, nsACString &aPassword);
nsresult PromptForPassword(nsISmtpServer *aSmtpServer, nsISmtpUrl *aSmtpUrl,
const char16_t **formatStrings,
nsACString &aPassword);
void InitPrefAuthMethods(int32_t authMethodPrefValue);
nsresult ChooseAuthMethod();
void MarkAuthMethodAsFailed(int32_t failedAuthMethod);
void ResetAuthMethods();
virtual const char* GetType() override {return "smtp";}
int32_t m_prefAuthMethods; // set of capability flags for auth methods
int32_t m_failedAuthMethods; // ditto
int32_t m_currentAuthMethod; // exactly one capability flag, or 0
// The support module for OAuth2 logon, only present if OAuth2 is enabled
// and working.
nsCOMPtr<msgIOAuth2Module> mOAuth2Support;
};
#endif // nsSmtpProtocol_h___

View file

@ -0,0 +1,629 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsSmtpServer.h"
#include "nsNetUtil.h"
#include "nsIAuthPrompt.h"
#include "nsMsgUtils.h"
#include "nsIMsgAccountManager.h"
#include "nsMsgBaseCID.h"
#include "nsISmtpService.h"
#include "nsMsgCompCID.h"
#include "nsILoginInfo.h"
#include "nsILoginManager.h"
#include "nsIArray.h"
#include "nsArrayUtils.h"
NS_IMPL_ADDREF(nsSmtpServer)
NS_IMPL_RELEASE(nsSmtpServer)
NS_INTERFACE_MAP_BEGIN(nsSmtpServer)
NS_INTERFACE_MAP_ENTRY(nsISmtpServer)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISmtpServer)
NS_INTERFACE_MAP_END
nsSmtpServer::nsSmtpServer():
mKey("")
{
m_logonFailed = false;
getPrefs();
}
nsSmtpServer::~nsSmtpServer()
{
}
NS_IMETHODIMP
nsSmtpServer::GetKey(char * *aKey)
{
if (!aKey) return NS_ERROR_NULL_POINTER;
if (mKey.IsEmpty())
*aKey = nullptr;
else
*aKey = ToNewCString(mKey);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetKey(const char * aKey)
{
NS_ASSERTION(aKey, "Bad key pointer");
mKey = aKey;
return getPrefs();
}
nsresult nsSmtpServer::getPrefs()
{
nsresult rv;
nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
nsAutoCString branchName;
branchName.AssignLiteral("mail.smtpserver.");
branchName += mKey;
branchName.Append('.');
rv = prefs->GetBranch(branchName.get(), getter_AddRefs(mPrefBranch));
if (NS_FAILED(rv))
return rv;
if(!mDefPrefBranch) {
branchName.AssignLiteral("mail.smtpserver.default.");
rv = prefs->GetBranch(branchName.get(), getter_AddRefs(mDefPrefBranch));
if (NS_FAILED(rv))
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetHostname(nsACString &aHostname)
{
nsCString result;
nsresult rv = mPrefBranch->GetCharPref("hostname", getter_Copies(result));
if (NS_FAILED(rv))
aHostname.Truncate();
else
aHostname = result;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetHostname(const nsACString &aHostname)
{
if (!aHostname.IsEmpty())
return mPrefBranch->SetCharPref("hostname", PromiseFlatCString(aHostname).get());
// If the pref value is already empty, ClearUserPref will return
// NS_ERROR_UNEXPECTED, so don't check the rv here.
mPrefBranch->ClearUserPref("hostname");
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetDescription(nsACString &aDescription)
{
nsCString temp;
mPrefBranch->GetCharPref("description", getter_Copies(temp));
aDescription.Assign(temp);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetDescription(const nsACString &aDescription)
{
if (!aDescription.IsEmpty())
return mPrefBranch->SetCharPref("description", PromiseFlatCString(aDescription).get());
else
mPrefBranch->ClearUserPref("description");
return NS_OK;
}
// if GetPort returns 0, it means default port
NS_IMETHODIMP
nsSmtpServer::GetPort(int32_t *aPort)
{
NS_ENSURE_ARG_POINTER(aPort);
if (NS_FAILED(mPrefBranch->GetIntPref("port", aPort)))
*aPort = 0;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetPort(int32_t aPort)
{
if (aPort)
return mPrefBranch->SetIntPref("port", aPort);
mPrefBranch->ClearUserPref("port");
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetDisplayname(char * *aDisplayname)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aDisplayname);
nsCString hostname;
rv = mPrefBranch->GetCharPref("hostname", getter_Copies(hostname));
if (NS_FAILED(rv)) {
*aDisplayname=nullptr;
return NS_OK;
}
int32_t port;
rv = mPrefBranch->GetIntPref("port", &port);
if (NS_FAILED(rv))
port = 0;
if (port) {
hostname.Append(':');
hostname.AppendInt(port);
}
*aDisplayname = ToNewCString(hostname);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetSocketType(int32_t *socketType)
{
NS_ENSURE_ARG_POINTER(socketType);
getIntPrefWithDefault("try_ssl", socketType, 0);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetSocketType(int32_t socketType)
{
return mPrefBranch->SetIntPref("try_ssl", socketType);
}
NS_IMETHODIMP
nsSmtpServer::GetHelloArgument(char * *aHelloArgument)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(aHelloArgument);
rv = mPrefBranch->GetCharPref("hello_argument", aHelloArgument);
if (NS_FAILED(rv))
{
rv = mDefPrefBranch->GetCharPref("hello_argument", aHelloArgument);
if (NS_FAILED(rv))
*aHelloArgument = nullptr;
}
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetAuthMethod(int32_t *authMethod)
{
NS_ENSURE_ARG_POINTER(authMethod);
getIntPrefWithDefault("authMethod", authMethod, 3);
return NS_OK;
}
void
nsSmtpServer::getIntPrefWithDefault(const char *prefName,
int32_t *val,
int32_t defVal)
{
nsresult rv = mPrefBranch->GetIntPref(prefName, val);
if (NS_SUCCEEDED(rv))
return;
rv = mDefPrefBranch->GetIntPref(prefName, val);
if (NS_FAILED(rv))
// last resort
*val = defVal;
}
NS_IMETHODIMP
nsSmtpServer::SetAuthMethod(int32_t authMethod)
{
return mPrefBranch->SetIntPref("authMethod", authMethod);
}
NS_IMETHODIMP
nsSmtpServer::GetUsername(nsACString &aUsername)
{
nsCString result;
nsresult rv = mPrefBranch->GetCharPref("username", getter_Copies(result));
if (NS_FAILED(rv))
aUsername.Truncate();
else
aUsername = result;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::SetUsername(const nsACString &aUsername)
{
if (!aUsername.IsEmpty())
return mPrefBranch->SetCharPref("username", PromiseFlatCString(aUsername).get());
// If the pref value is already empty, ClearUserPref will return
// NS_ERROR_UNEXPECTED, so don't check the rv here.
mPrefBranch->ClearUserPref("username");
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetPassword(nsACString& aPassword)
{
if (m_password.IsEmpty() && !m_logonFailed)
{
// try to avoid prompting the user for another password. If the user has set
// the appropriate pref, we'll use the password from an incoming server, if
// the user has already logged onto that server.
// if this is set, we'll only use this, and not the other prefs
// user_pref("mail.smtpserver.smtp1.incomingAccount", "server1");
// if this is set, we'll accept an exact match of user name and server
// user_pref("mail.smtp.useMatchingHostNameServer", true);
// if this is set, and we don't find an exact match of user and host name,
// we'll accept a match of username and domain, where domain
// is everything after the first '.'
// user_pref("mail.smtp.useMatchingDomainServer", true);
nsCString accountKey;
bool useMatchingHostNameServer = false;
bool useMatchingDomainServer = false;
mPrefBranch->GetCharPref("incomingAccount", getter_Copies(accountKey));
nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID);
nsCOMPtr<nsIMsgIncomingServer> incomingServerToUse;
if (accountManager)
{
if (!accountKey.IsEmpty())
accountManager->GetIncomingServer(accountKey, getter_AddRefs(incomingServerToUse));
else
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
prefBranch->GetBoolPref("mail.smtp.useMatchingHostNameServer", &useMatchingHostNameServer);
prefBranch->GetBoolPref("mail.smtp.useMatchingDomainServer", &useMatchingDomainServer);
if (useMatchingHostNameServer || useMatchingDomainServer)
{
nsCString userName;
nsCString hostName;
GetHostname(hostName);
GetUsername(userName);
if (useMatchingHostNameServer)
// pass in empty type and port=0, to match imap and pop3.
accountManager->FindRealServer(userName, hostName, EmptyCString(), 0, getter_AddRefs(incomingServerToUse));
int32_t dotPos = -1;
if (!incomingServerToUse && useMatchingDomainServer
&& (dotPos = hostName.FindChar('.')) != kNotFound)
{
hostName.Cut(0, dotPos);
nsCOMPtr<nsIArray> allServers;
accountManager->GetAllServers(getter_AddRefs(allServers));
if (allServers)
{
uint32_t count = 0;
allServers->GetLength(&count);
uint32_t i;
for (i = 0; i < count; i++)
{
nsCOMPtr<nsIMsgIncomingServer> server = do_QueryElementAt(allServers, i);
if (server)
{
nsCString serverUserName;
nsCString serverHostName;
server->GetRealUsername(serverUserName);
server->GetRealHostName(serverHostName);
if (serverUserName.Equals(userName))
{
int32_t serverDotPos = serverHostName.FindChar('.');
if (serverDotPos != kNotFound)
{
serverHostName.Cut(0, serverDotPos);
if (serverHostName.Equals(hostName))
{
incomingServerToUse = server;
break;
}
}
}
}
}
}
}
}
}
}
if (incomingServerToUse)
return incomingServerToUse->GetPassword(aPassword);
}
aPassword = m_password;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::VerifyLogon(nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
nsresult rv;
nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
return smtpService->VerifyLogon(this, aUrlListener, aMsgWindow, aURL);
}
NS_IMETHODIMP
nsSmtpServer::SetPassword(const nsACString& aPassword)
{
m_password = aPassword;
return NS_OK;
}
nsresult
nsSmtpServer::GetPasswordWithoutUI()
{
nsresult rv;
nsCOMPtr<nsILoginManager> loginMgr(do_GetService(NS_LOGINMANAGER_CONTRACTID,
&rv));
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertASCIItoUTF16 serverUri(GetServerURIInternal(false));
uint32_t numLogins = 0;
nsILoginInfo** logins = nullptr;
rv = loginMgr->FindLogins(&numLogins, serverUri, EmptyString(),
serverUri, &logins);
// Login manager can produce valid fails, e.g. NS_ERROR_ABORT when a user
// cancels the master password dialog. Therefore handle that here, but don't
// warn about it.
if (NS_FAILED(rv))
return rv;
// Don't abort here, if we didn't find any or failed, then we'll just have
// to prompt.
if (numLogins > 0)
{
nsCString serverCUsername;
rv = GetUsername(serverCUsername);
NS_ConvertASCIItoUTF16 serverUsername(serverCUsername);
nsString username;
for (uint32_t i = 0; i < numLogins; ++i)
{
rv = logins[i]->GetUsername(username);
NS_ENSURE_SUCCESS(rv, rv);
if (username.Equals(serverUsername))
{
nsString password;
rv = logins[i]->GetPassword(password);
NS_ENSURE_SUCCESS(rv, rv);
LossyCopyUTF16toASCII(password, m_password);
break;
}
}
}
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(numLogins, logins);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetPasswordWithUI(const char16_t *aPromptMessage,
const char16_t *aPromptTitle,
nsIAuthPrompt* aDialog,
nsACString &aPassword)
{
if (!m_password.IsEmpty())
return GetPassword(aPassword);
// We need to get a password, but see if we can get it from the password
// manager without requiring a prompt.
nsresult rv = GetPasswordWithoutUI();
if (rv == NS_ERROR_ABORT)
return NS_MSG_PASSWORD_PROMPT_CANCELLED;
// Now re-check if we've got a password or not, if we have, then we
// don't need to prompt the user.
if (!m_password.IsEmpty())
{
aPassword = m_password;
return NS_OK;
}
NS_ENSURE_ARG_POINTER(aDialog);
// PromptPassword needs the username as well.
nsCString serverUri(GetServerURIInternal(true));
bool okayValue = true;
nsString uniPassword;
rv = aDialog->PromptPassword(aPromptTitle, aPromptMessage,
NS_ConvertASCIItoUTF16(serverUri).get(),
nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
getter_Copies(uniPassword), &okayValue);
NS_ENSURE_SUCCESS(rv, rv);
// If the user pressed cancel, just return an empty string.
if (!okayValue)
{
aPassword.Truncate();
return NS_MSG_PASSWORD_PROMPT_CANCELLED;
}
NS_LossyConvertUTF16toASCII password(uniPassword);
rv = SetPassword(password);
NS_ENSURE_SUCCESS(rv, rv);
aPassword = password;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::GetUsernamePasswordWithUI(const char16_t * aPromptMessage, const
char16_t *aPromptTitle,
nsIAuthPrompt* aDialog,
nsACString &aUsername,
nsACString &aPassword)
{
nsresult rv;
if (!m_password.IsEmpty())
{
rv = GetUsername(aUsername);
NS_ENSURE_SUCCESS(rv, rv);
return GetPassword(aPassword);
}
NS_ENSURE_ARG_POINTER(aDialog);
nsCString serverUri;
rv = GetServerURI(serverUri);
NS_ENSURE_SUCCESS(rv, rv);
nsString uniUsername;
nsString uniPassword;
bool okayValue = true;
rv = aDialog->PromptUsernameAndPassword(aPromptTitle, aPromptMessage,
NS_ConvertASCIItoUTF16(serverUri).get(),
nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY,
getter_Copies(uniUsername),
getter_Copies(uniPassword),
&okayValue);
NS_ENSURE_SUCCESS(rv, rv);
// If the user pressed cancel, just return emtpy strings.
if (!okayValue)
{
aUsername.Truncate();
aPassword.Truncate();
return rv;
}
// We got a username and password back...so remember them.
NS_LossyConvertUTF16toASCII username(uniUsername);
rv = SetUsername(username);
NS_ENSURE_SUCCESS(rv, rv);
NS_LossyConvertUTF16toASCII password(uniPassword);
rv = SetPassword(password);
NS_ENSURE_SUCCESS(rv, rv);
aUsername = username;
aPassword = password;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpServer::ForgetPassword()
{
nsresult rv;
nsCOMPtr<nsILoginManager> loginMgr =
do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Get the current server URI without the username
nsAutoCString serverUri(NS_LITERAL_CSTRING("smtp://"));
nsCString hostname;
rv = GetHostname(hostname);
if (NS_SUCCEEDED(rv) && !hostname.IsEmpty()) {
nsCString escapedHostname;
MsgEscapeString(hostname, nsINetUtil::ESCAPE_URL_PATH, escapedHostname);
// not all servers have a hostname
serverUri.Append(escapedHostname);
}
uint32_t count;
nsILoginInfo** logins;
NS_ConvertUTF8toUTF16 currServer(serverUri);
nsCString serverCUsername;
rv = GetUsername(serverCUsername);
NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF8toUTF16 serverUsername(serverCUsername);
rv = loginMgr->FindLogins(&count, currServer, EmptyString(),
currServer, &logins);
NS_ENSURE_SUCCESS(rv, rv);
// There should only be one-login stored for this url, however just in case
// there isn't.
nsString username;
for (uint32_t i = 0; i < count; ++i)
{
if (NS_SUCCEEDED(logins[i]->GetUsername(username)) &&
username.Equals(serverUsername))
{
// If this fails, just continue, we'll still want to remove the password
// from our local cache.
loginMgr->RemoveLogin(logins[i]);
}
}
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(count, logins);
rv = SetPassword(EmptyCString());
m_logonFailed = true;
return rv;
}
NS_IMETHODIMP
nsSmtpServer::GetServerURI(nsACString &aResult)
{
aResult = GetServerURIInternal(true);
return NS_OK;
}
nsCString
nsSmtpServer::GetServerURIInternal(const bool aIncludeUsername)
{
nsCString uri(NS_LITERAL_CSTRING("smtp://"));
nsresult rv;
if (aIncludeUsername)
{
nsCString username;
rv = GetUsername(username);
if (NS_SUCCEEDED(rv) && !username.IsEmpty()) {
nsCString escapedUsername;
MsgEscapeString(username, nsINetUtil::ESCAPE_XALPHAS, escapedUsername);
// not all servers have a username
uri.Append(escapedUsername);
uri.AppendLiteral("@");
}
}
nsCString hostname;
rv = GetHostname(hostname);
if (NS_SUCCEEDED(rv) && !hostname.IsEmpty()) {
nsCString escapedHostname;
MsgEscapeString(hostname, nsINetUtil::ESCAPE_URL_PATH, escapedHostname);
// not all servers have a hostname
uri.Append(escapedHostname);
}
return uri;
}
NS_IMETHODIMP
nsSmtpServer::ClearAllValues()
{
return mPrefBranch->DeleteBranch("");
}

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsSmtpServer_h_
#define __nsSmtpServer_h_
#include "nsStringGlue.h"
#include "nsISmtpServer.h"
#include "nsIPrefBranch.h"
#include "nsWeakReference.h"
class nsSmtpServer : public nsISmtpServer,
public nsSupportsWeakReference
{
public:
nsSmtpServer();
NS_DECL_ISUPPORTS
NS_DECL_NSISMTPSERVER
private:
virtual ~nsSmtpServer();
nsCString mKey;
nsCOMPtr<nsIPrefBranch> mPrefBranch;
nsCOMPtr<nsIPrefBranch> mDefPrefBranch;
nsresult getPrefs();
void getIntPrefWithDefault(const char *prefName, int32_t *val,
int32_t defval);
nsresult GetPasswordWithoutUI();
nsCString GetServerURIInternal(const bool aIncludeUsername);
nsCString m_password;
bool m_logonFailed;
};
#endif

View file

@ -0,0 +1,772 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h" // precompiled header...
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIIOService.h"
#include "nsIPipe.h"
#include "nsNetCID.h"
#include "nsMsgUtils.h"
#include "nsNetUtil.h"
#include "nsSmtpService.h"
#include "nsMsgBaseCID.h"
#include "nsMsgCompCID.h"
#include "nsArrayEnumerator.h"
#include "nsSmtpUrl.h"
#include "nsSmtpProtocol.h"
#include "nsCOMPtr.h"
#include "nsIMsgIdentity.h"
#include "nsIPrompt.h"
#include "nsIWindowWatcher.h"
#include "nsIUTF8ConverterService.h"
#include "nsUConvCID.h"
#include "nsAutoPtr.h"
#include "nsComposeStrings.h"
#include "nsIAsyncInputStream.h"
#include "nsIPrincipal.h"
#define SERVER_DELIMITER ','
#define APPEND_SERVERS_VERSION_PREF_NAME "append_preconfig_smtpservers.version"
#define MAIL_ROOT_PREF "mail."
#define PREF_MAIL_SMTPSERVERS "mail.smtpservers"
#define PREF_MAIL_SMTPSERVERS_APPEND_SERVERS "mail.smtpservers.appendsmtpservers"
#define PREF_MAIL_SMTP_DEFAULTSERVER "mail.smtp.defaultserver"
typedef struct _findServerByKeyEntry {
const char *key;
nsISmtpServer *server;
} findServerByKeyEntry;
typedef struct _findServerByHostnameEntry {
nsCString hostname;
nsCString username;
nsISmtpServer *server;
} findServerByHostnameEntry;
static NS_DEFINE_CID(kCSmtpUrlCID, NS_SMTPURL_CID);
static NS_DEFINE_CID(kCMailtoUrlCID, NS_MAILTOURL_CID);
// foward declarations...
nsresult
NS_MsgBuildSmtpUrl(nsIFile * aFilePath,
nsISmtpServer *aServer,
const char* aRecipients,
nsIMsgIdentity * aSenderIdentity,
nsIUrlListener * aUrlListener,
nsIMsgStatusFeedback *aStatusFeedback,
nsIInterfaceRequestor* aNotificationCallbacks,
nsIURI ** aUrl,
bool aRequestDSN);
nsresult NS_MsgLoadSmtpUrl(nsIURI * aUrl, nsISupports * aConsumer, nsIRequest ** aRequest);
nsSmtpService::nsSmtpService() :
mSmtpServersLoaded(false)
{
}
nsSmtpService::~nsSmtpService()
{
// save the SMTP servers to disk
}
NS_IMPL_ISUPPORTS(nsSmtpService, nsISmtpService, nsIProtocolHandler)
NS_IMETHODIMP nsSmtpService::SendMailMessage(nsIFile * aFilePath,
const char * aRecipients,
nsIMsgIdentity * aSenderIdentity,
const char * aPassword,
nsIUrlListener * aUrlListener,
nsIMsgStatusFeedback *aStatusFeedback,
nsIInterfaceRequestor* aNotificationCallbacks,
bool aRequestDSN,
nsIURI ** aURL,
nsIRequest ** aRequest)
{
nsIURI * urlToRun = nullptr;
nsresult rv = NS_OK;
nsCOMPtr<nsISmtpServer> smtpServer;
rv = GetServerByIdentity(aSenderIdentity, getter_AddRefs(smtpServer));
if (NS_SUCCEEDED(rv) && smtpServer)
{
if (aPassword && *aPassword)
smtpServer->SetPassword(nsDependentCString(aPassword));
// this ref counts urlToRun
rv = NS_MsgBuildSmtpUrl(aFilePath, smtpServer, aRecipients, aSenderIdentity,
aUrlListener, aStatusFeedback,
aNotificationCallbacks, &urlToRun, aRequestDSN);
if (NS_SUCCEEDED(rv) && urlToRun)
rv = NS_MsgLoadSmtpUrl(urlToRun, nullptr, aRequest);
if (aURL) // does the caller want a handle on the url?
*aURL = urlToRun; // transfer our ref count to the caller....
else
NS_IF_RELEASE(urlToRun);
}
return rv;
}
// The following are two convience functions I'm using to help expedite building and running a mail to url...
// short cut function for creating a mailto url...
nsresult NS_MsgBuildSmtpUrl(nsIFile * aFilePath,
nsISmtpServer *aSmtpServer,
const char * aRecipients,
nsIMsgIdentity * aSenderIdentity,
nsIUrlListener * aUrlListener,
nsIMsgStatusFeedback *aStatusFeedback,
nsIInterfaceRequestor* aNotificationCallbacks,
nsIURI ** aUrl,
bool aRequestDSN)
{
// mscott: this function is a convience hack until netlib actually dispatches
// smtp urls. in addition until we have a session to get a password, host and
// other stuff from, we need to use default values....
// ..for testing purposes....
nsCString smtpHostName;
nsCString smtpUserName;
int32_t smtpPort;
int32_t socketType;
aSmtpServer->GetHostname(smtpHostName);
aSmtpServer->GetUsername(smtpUserName);
aSmtpServer->GetPort(&smtpPort);
aSmtpServer->GetSocketType(&socketType);
if (!smtpPort)
smtpPort = (socketType == nsMsgSocketType::SSL) ?
nsISmtpUrl::DEFAULT_SMTPS_PORT : nsISmtpUrl::DEFAULT_SMTP_PORT;
nsresult rv;
nsCOMPtr<nsISmtpUrl> smtpUrl(do_CreateInstance(kCSmtpUrlCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString urlSpec("smtp://");
if (!smtpUserName.IsEmpty())
{
nsCString escapedUsername;
MsgEscapeString(smtpUserName, nsINetUtil::ESCAPE_XALPHAS,
escapedUsername);
urlSpec.Append(escapedUsername);
urlSpec.Append('@');
}
urlSpec.Append(smtpHostName);
if (smtpHostName.FindChar(':') == -1)
{
urlSpec.Append(':');
urlSpec.AppendInt(smtpPort);
}
nsCOMPtr<nsIMsgMailNewsUrl> url(do_QueryInterface(smtpUrl, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = url->SetSpec(urlSpec);
NS_ENSURE_SUCCESS(rv, rv);
smtpUrl->SetRecipients(aRecipients);
smtpUrl->SetRequestDSN(aRequestDSN);
smtpUrl->SetPostMessageFile(aFilePath);
smtpUrl->SetSenderIdentity(aSenderIdentity);
if (aNotificationCallbacks)
smtpUrl->SetNotificationCallbacks(aNotificationCallbacks);
smtpUrl->SetSmtpServer(aSmtpServer);
nsCOMPtr<nsIPrompt> smtpPrompt(do_GetInterface(aNotificationCallbacks));
nsCOMPtr<nsIAuthPrompt> smtpAuthPrompt(do_GetInterface(aNotificationCallbacks));
if (!smtpPrompt || !smtpAuthPrompt)
{
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
if (!smtpPrompt)
wwatch->GetNewPrompter(0, getter_AddRefs(smtpPrompt));
if (!smtpAuthPrompt)
wwatch->GetNewAuthPrompter(0, getter_AddRefs(smtpAuthPrompt));
}
smtpUrl->SetPrompt(smtpPrompt);
smtpUrl->SetAuthPrompt(smtpAuthPrompt);
if (aUrlListener)
url->RegisterListener(aUrlListener);
if (aStatusFeedback)
url->SetStatusFeedback(aStatusFeedback);
return CallQueryInterface(smtpUrl, aUrl);
}
nsresult NS_MsgLoadSmtpUrl(nsIURI * aUrl, nsISupports * aConsumer, nsIRequest ** aRequest)
{
NS_ENSURE_ARG_POINTER(aUrl);
// For now, assume the url is an smtp url and load it.
nsresult rv;
nsCOMPtr<nsISmtpUrl> smtpUrl(do_QueryInterface(aUrl, &rv));
NS_ENSURE_SUCCESS(rv, rv);
// Create a smtp protocol instance to run the url in.
RefPtr<nsSmtpProtocol> smtpProtocol = new nsSmtpProtocol(aUrl);
if (!smtpProtocol)
return NS_ERROR_OUT_OF_MEMORY;
// Protocol will get destroyed when url is completed.
rv = smtpProtocol->LoadUrl(aUrl, aConsumer);
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(smtpProtocol.get(), aRequest);
}
NS_IMETHODIMP nsSmtpService::VerifyLogon(nsISmtpServer *aServer,
nsIUrlListener *aUrlListener,
nsIMsgWindow *aMsgWindow,
nsIURI **aURL)
{
NS_ENSURE_ARG_POINTER(aServer);
nsCString popHost;
nsCString popUser;
nsCOMPtr <nsIURI> urlToRun;
nsresult rv = NS_MsgBuildSmtpUrl(nullptr, aServer,
nullptr, nullptr, aUrlListener, nullptr,
nullptr , getter_AddRefs(urlToRun), false);
if (NS_SUCCEEDED(rv) && urlToRun)
{
nsCOMPtr<nsIMsgMailNewsUrl> url(do_QueryInterface(urlToRun, &rv));
NS_ENSURE_SUCCESS(rv, rv);
url->SetMsgWindow(aMsgWindow);
rv = NS_MsgLoadSmtpUrl(urlToRun, nullptr, nullptr /* aRequest */);
if (aURL)
urlToRun.forget(aURL);
}
return rv;
}
NS_IMETHODIMP nsSmtpService::GetScheme(nsACString &aScheme)
{
aScheme = "mailto";
return NS_OK;
}
NS_IMETHODIMP nsSmtpService::GetDefaultPort(int32_t *aDefaultPort)
{
nsresult rv = NS_OK;
if (aDefaultPort)
*aDefaultPort = nsISmtpUrl::DEFAULT_SMTP_PORT;
else
rv = NS_ERROR_NULL_POINTER;
return rv;
}
NS_IMETHODIMP
nsSmtpService::AllowPort(int32_t port, const char *scheme, bool *_retval)
{
// allow smtp to run on any port
*_retval = true;
return NS_OK;
}
NS_IMETHODIMP nsSmtpService::GetProtocolFlags(uint32_t *result)
{
*result = URI_NORELATIVE | ALLOWS_PROXY | URI_LOADABLE_BY_ANYONE |
URI_NON_PERSISTABLE | URI_DOES_NOT_RETURN_DATA |
URI_FORBIDS_COOKIE_ACCESS;
return NS_OK;
}
// the smtp service is also the protocol handler for mailto urls....
NS_IMETHODIMP nsSmtpService::NewURI(const nsACString &aSpec,
const char *aOriginCharset,
nsIURI *aBaseURI,
nsIURI **_retval)
{
// get a new smtp url
nsresult rv;
nsCOMPtr<nsIURI> mailtoUrl = do_CreateInstance(kCMailtoUrlCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString utf8Spec;
if (aOriginCharset)
{
nsCOMPtr<nsIUTF8ConverterService>
utf8Converter(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv))
rv = utf8Converter->ConvertURISpecToUTF8(aSpec, aOriginCharset, utf8Spec);
}
// utf8Spec is filled up only when aOriginCharset is specified and
// the conversion is successful. Otherwise, fall back to aSpec.
if (aOriginCharset && NS_SUCCEEDED(rv))
rv = mailtoUrl->SetSpec(utf8Spec);
else
rv = mailtoUrl->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv, rv);
mailtoUrl.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP nsSmtpService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{
return NewChannel2(aURI, nullptr, _retval);
}
NS_IMETHODIMP nsSmtpService::NewChannel2(nsIURI *aURI,
nsILoadInfo* aLoadInfo,
nsIChannel **_retval)
{
NS_ENSURE_ARG_POINTER(aURI);
// create an empty pipe for use with the input stream channel.
nsCOMPtr<nsIAsyncInputStream> pipeIn;
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
nsCOMPtr<nsIPipe> pipe = do_CreateInstance("@mozilla.org/pipe;1");
nsresult rv = pipe->Init(false, false, 0, 0);
NS_ENSURE_SUCCESS(rv, rv);
// These always succeed because the pipe is initialized above.
MOZ_ALWAYS_SUCCEEDS(pipe->GetInputStream(getter_AddRefs(pipeIn)));
MOZ_ALWAYS_SUCCEEDS(pipe->GetOutputStream(getter_AddRefs(pipeOut)));
pipeOut->Close();
if (aLoadInfo) {
return NS_NewInputStreamChannelInternal(_retval,
aURI,
pipeIn,
NS_LITERAL_CSTRING("application/x-mailto"),
EmptyCString(),
aLoadInfo);
}
nsCOMPtr<nsIPrincipal> nullPrincipal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
NS_ASSERTION(NS_SUCCEEDED(rv), "CreateInstance of nullprincipal failed.");
if (NS_FAILED(rv))
return rv;
return NS_NewInputStreamChannel(_retval, aURI, pipeIn,
nullPrincipal, nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING("application/x-mailto"));
}
NS_IMETHODIMP
nsSmtpService::GetServers(nsISimpleEnumerator **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// now read in the servers from prefs if necessary
uint32_t serverCount = mSmtpServers.Count();
if (serverCount <= 0)
loadSmtpServers();
return NS_NewArrayEnumerator(aResult, mSmtpServers);
}
nsresult
nsSmtpService::loadSmtpServers()
{
if (mSmtpServersLoaded)
return NS_OK;
nsresult rv;
nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIPrefBranch> prefRootBranch;
prefService->GetBranch(nullptr, getter_AddRefs(prefRootBranch));
if (NS_FAILED(rv))
return rv;
nsCString serverList;
rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS, getter_Copies(serverList));
serverList.StripWhitespace();
nsTArray<nsCString> servers;
ParseString(serverList, SERVER_DELIMITER, servers);
/**
* Check to see if we need to add pre-configured smtp servers.
* Following prefs are important to note in understanding the procedure here.
*
* 1. pref("mailnews.append_preconfig_smtpservers.version", version number);
* This pref registers the current version in the user prefs file. A default value
* is stored in mailnews.js file. If a given vendor needs to add more preconfigured
* smtp servers, the default version number can be increased. Comparing version
* number from user's prefs file and the default one from mailnews.js, we
* can add new smtp servers and any other version level changes that need to be done.
*
* 2. pref("mail.smtpservers.appendsmtpservers", <comma separated servers list>);
* This pref contains the list of pre-configured smp servers that ISP/Vendor wants to
* to add to the existing servers list.
*/
nsCOMPtr<nsIPrefBranch> defaultsPrefBranch;
rv = prefService->GetDefaultBranch(MAIL_ROOT_PREF, getter_AddRefs(defaultsPrefBranch));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrefBranch> prefBranch;
rv = prefService->GetBranch(MAIL_ROOT_PREF, getter_AddRefs(prefBranch));
NS_ENSURE_SUCCESS(rv,rv);
int32_t appendSmtpServersCurrentVersion = 0;
int32_t appendSmtpServersDefaultVersion = 0;
rv = prefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersCurrentVersion);
NS_ENSURE_SUCCESS(rv,rv);
rv = defaultsPrefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersDefaultVersion);
NS_ENSURE_SUCCESS(rv,rv);
// Update the smtp server list if needed
if (appendSmtpServersCurrentVersion <= appendSmtpServersDefaultVersion) {
// If there are pre-configured servers, add them to the existing server list
nsCString appendServerList;
rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS_APPEND_SERVERS, getter_Copies(appendServerList));
appendServerList.StripWhitespace();
ParseString(appendServerList, SERVER_DELIMITER, servers);
// Increase the version number so that updates will happen as and when needed
prefBranch->SetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, appendSmtpServersCurrentVersion + 1);
}
// use GetServerByKey to check if the key (pref) is already in
// in the list. If not it calls createKeyedServer directly.
for (uint32_t i = 0; i < servers.Length(); i++) {
nsCOMPtr<nsISmtpServer> server;
GetServerByKey(servers[i].get(), getter_AddRefs(server));
}
saveKeyList();
mSmtpServersLoaded = true;
return NS_OK;
}
// save the list of keys
nsresult
nsSmtpService::saveKeyList()
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
return prefBranch->SetCharPref(PREF_MAIL_SMTPSERVERS, mServerKeyList.get());
}
nsresult
nsSmtpService::createKeyedServer(const char *key, nsISmtpServer** aResult)
{
if (!key) return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsISmtpServer> server = do_CreateInstance(NS_SMTPSERVER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
server->SetKey(key);
mSmtpServers.AppendObject(server);
if (mServerKeyList.IsEmpty())
mServerKeyList = key;
else {
mServerKeyList.Append(',');
mServerKeyList += key;
}
if (aResult)
server.swap(*aResult);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpService::GetSessionDefaultServer(nsISmtpServer **aServer)
{
NS_ENSURE_ARG_POINTER(aServer);
if (!mSessionDefaultServer)
return GetDefaultServer(aServer);
NS_ADDREF(*aServer = mSessionDefaultServer);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpService::SetSessionDefaultServer(nsISmtpServer *aServer)
{
mSessionDefaultServer = aServer;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpService::GetDefaultServer(nsISmtpServer **aServer)
{
NS_ENSURE_ARG_POINTER(aServer);
loadSmtpServers();
*aServer = nullptr;
// always returns NS_OK, just leaving *aServer at nullptr
if (!mDefaultSmtpServer) {
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) return rv;
// try to get it from the prefs
nsCString defaultServerKey;
rv = prefBranch->GetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, getter_Copies(defaultServerKey));
if (NS_SUCCEEDED(rv) &&
!defaultServerKey.IsEmpty()) {
nsCOMPtr<nsISmtpServer> server;
rv = GetServerByKey(defaultServerKey.get(),
getter_AddRefs(mDefaultSmtpServer));
} else {
// no pref set, so just return the first one, and set the pref
// Ensure the list of servers is loaded
loadSmtpServers();
// nothing in the array, we had better create a new server
// (which will add it to the array & prefs anyway)
if (mSmtpServers.Count() == 0)
// if there are no smtp servers then don't create one for the default.
return NS_OK;
mDefaultSmtpServer = mSmtpServers[0];
NS_ENSURE_TRUE(mDefaultSmtpServer, NS_ERROR_NULL_POINTER);
// now we have a default server, set the prefs correctly
nsCString serverKey;
mDefaultSmtpServer->GetKey(getter_Copies(serverKey));
if (NS_SUCCEEDED(rv))
prefBranch->SetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, serverKey.get());
}
}
// at this point:
// * mDefaultSmtpServer has a valid server
// * the key has been set in the prefs
NS_IF_ADDREF(*aServer = mDefaultSmtpServer);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpService::SetDefaultServer(nsISmtpServer *aServer)
{
NS_ENSURE_ARG_POINTER(aServer);
mDefaultSmtpServer = aServer;
nsCString serverKey;
nsresult rv = aServer->GetKey(getter_Copies(serverKey));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv,rv);
prefBranch->SetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, serverKey.get());
return NS_OK;
}
bool
nsSmtpService::findServerByKey(nsISmtpServer *aServer, void *aData)
{
findServerByKeyEntry *entry = (findServerByKeyEntry*) aData;
nsCString key;
nsresult rv = aServer->GetKey(getter_Copies(key));
if (NS_FAILED(rv))
return true;
if (key.Equals(entry->key))
{
entry->server = aServer;
return false;
}
return true;
}
NS_IMETHODIMP
nsSmtpService::CreateServer(nsISmtpServer **aResult)
{
if (!aResult) return NS_ERROR_NULL_POINTER;
loadSmtpServers();
nsresult rv;
int32_t i = 0;
bool unique = false;
findServerByKeyEntry entry;
nsAutoCString key;
do {
key = "smtp";
key.AppendInt(++i);
entry.key = key.get();
entry.server = nullptr;
mSmtpServers.EnumerateForwards(findServerByKey, (void *)&entry);
if (!entry.server) unique=true;
} while (!unique);
rv = createKeyedServer(key.get(), aResult);
NS_ENSURE_SUCCESS(rv, rv);
return saveKeyList();
}
nsresult
nsSmtpService::GetServerByKey(const char* aKey, nsISmtpServer **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
if (!aKey || !*aKey)
{
NS_ASSERTION(false, "bad key");
return NS_ERROR_FAILURE;
}
findServerByKeyEntry entry;
entry.key = aKey;
entry.server = nullptr;
mSmtpServers.EnumerateForwards(findServerByKey, (void *)&entry);
if (entry.server) {
NS_ADDREF(*aResult = entry.server);
return NS_OK;
}
// not found in array, I guess we load it
return createKeyedServer(aKey, aResult);
}
NS_IMETHODIMP
nsSmtpService::DeleteServer(nsISmtpServer *aServer)
{
if (!aServer) return NS_OK;
int32_t idx = mSmtpServers.IndexOf(aServer);
if (idx == -1)
return NS_OK;
nsCString serverKey;
aServer->GetKey(getter_Copies(serverKey));
mSmtpServers.RemoveObjectAt(idx);
if (mDefaultSmtpServer.get() == aServer)
mDefaultSmtpServer = nullptr;
if (mSessionDefaultServer.get() == aServer)
mSessionDefaultServer = nullptr;
nsAutoCString newServerList;
nsCString tmpStr = mServerKeyList;
char *newStr = tmpStr.BeginWriting();
char *token = NS_strtok(",", &newStr);
while (token) {
// only re-add the string if it's not the key
if (strcmp(token, serverKey.get()) != 0) {
if (newServerList.IsEmpty())
newServerList = token;
else {
newServerList += ',';
newServerList += token;
}
}
token = NS_strtok(",", &newStr);
}
// make sure the server clears out it's values....
aServer->ClearAllValues();
mServerKeyList = newServerList;
saveKeyList();
return NS_OK;
}
bool
nsSmtpService::findServerByHostname(nsISmtpServer *aServer, void *aData)
{
findServerByHostnameEntry *entry = (findServerByHostnameEntry*)aData;
nsCString hostname;
nsresult rv = aServer->GetHostname(hostname);
if (NS_FAILED(rv))
return true;
nsCString username;
rv = aServer->GetUsername(username);
if (NS_FAILED(rv))
return true;
bool checkHostname = !entry->hostname.IsEmpty();
bool checkUsername = !entry->username.IsEmpty();
if ((!checkHostname ||
(entry->hostname.Equals(hostname, nsCaseInsensitiveCStringComparator()))) &&
(!checkUsername ||
entry->username.Equals(username, nsCaseInsensitiveCStringComparator())))
{
entry->server = aServer;
return false; // stop when found
}
return true;
}
NS_IMETHODIMP
nsSmtpService::FindServer(const char *aUsername,
const char *aHostname, nsISmtpServer ** aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
findServerByHostnameEntry entry;
entry.server = nullptr;
entry.hostname = aHostname;
entry.username = aUsername;
mSmtpServers.EnumerateForwards(findServerByHostname, (void *)&entry);
// entry.server may be null, but that's ok.
// just return null if no server is found
NS_IF_ADDREF(*aResult = entry.server);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpService::GetServerByIdentity(nsIMsgIdentity *aSenderIdentity,
nsISmtpServer **aSmtpServer)
{
NS_ENSURE_ARG_POINTER(aSmtpServer);
nsresult rv = NS_ERROR_FAILURE;
// First try the identity's preferred server
if (aSenderIdentity)
{
nsCString smtpServerKey;
rv = aSenderIdentity->GetSmtpServerKey(smtpServerKey);
if (NS_SUCCEEDED(rv) && !(smtpServerKey.IsEmpty()))
rv = GetServerByKey(smtpServerKey.get(), aSmtpServer);
}
// Fallback to the default
if (NS_FAILED(rv) || !(*aSmtpServer))
rv = GetDefaultServer(aSmtpServer);
return rv;
}

View file

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsSmtpService_h___
#define nsSmtpService_h___
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsISmtpService.h"
#include "nsISmtpServer.h"
#include "nsIProtocolHandler.h"
////////////////////////////////////////////////////////////////////////////////////////
// The Smtp Service is an interfaced designed to make building and running mail to urls
// easier. I'm not sure if this service will go away when the new networking model comes
// on line (as part of the N2 project). So I reserve the right to change my mind and take
// this service away =).
////////////////////////////////////////////////////////////////////////////////////////
class nsSmtpService : public nsISmtpService, public nsIProtocolHandler
{
public:
nsSmtpService();
NS_DECL_ISUPPORTS
////////////////////////////////////////////////////////////////////////
// we suppport the nsISmtpService interface
////////////////////////////////////////////////////////////////////////
NS_DECL_NSISMTPSERVICE
//////////////////////////////////////////////////////////////////////////
// we suppport the nsIProtocolHandler interface
//////////////////////////////////////////////////////////////////////////
NS_DECL_NSIPROTOCOLHANDLER
protected:
nsresult loadSmtpServers();
private:
virtual ~nsSmtpService();
static bool findServerByKey(nsISmtpServer *aServer, void *aData);
static bool findServerByHostname(nsISmtpServer *aServer, void *aData);
nsresult createKeyedServer(const char* key,
nsISmtpServer **aResult = nullptr);
nsresult saveKeyList();
nsCOMArray<nsISmtpServer> mSmtpServers;
nsCOMPtr<nsISmtpServer> mDefaultSmtpServer;
nsCOMPtr<nsISmtpServer> mSessionDefaultServer;
nsCString mServerKeyList;
bool mSmtpServersLoaded;
};
#endif /* nsSmtpService_h___ */

View file

@ -0,0 +1,778 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h"
#include "nsIURI.h"
#include "nsNetCID.h"
#include "nsSmtpUrl.h"
#include "nsStringGlue.h"
#include "nsMsgUtils.h"
#include "nsIMimeConverter.h"
#include "nsMsgMimeCID.h"
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsCRT.h"
#include "nsAutoPtr.h"
/////////////////////////////////////////////////////////////////////////////////////
// mailto url definition
/////////////////////////////////////////////////////////////////////////////////////
nsMailtoUrl::nsMailtoUrl()
{
mFormat = nsIMsgCompFormat::Default;
m_baseURL = do_CreateInstance(NS_SIMPLEURI_CONTRACTID);
}
nsMailtoUrl::~nsMailtoUrl()
{
}
NS_IMPL_ISUPPORTS(nsMailtoUrl, nsIMailtoUrl, nsIURI)
static void UnescapeAndConvert(nsIMimeConverter *mimeConverter,
const nsACString &escaped, nsACString &out)
{
NS_ASSERTION(mimeConverter, "Set mimeConverter before calling!");
// If the string is empty, do absolutely nothing.
if (escaped.IsEmpty())
return;
MsgUnescapeString(escaped, 0, out);
nsAutoCString decodedString;
nsresult rv = mimeConverter->DecodeMimeHeaderToUTF8(out, "UTF_8", false,
true, decodedString);
if (NS_SUCCEEDED(rv) && !decodedString.IsEmpty())
out = decodedString;
}
nsresult nsMailtoUrl::ParseMailtoUrl(char * searchPart)
{
char *rest = searchPart;
nsCString escapedInReplyToPart;
nsCString escapedToPart;
nsCString escapedCcPart;
nsCString escapedSubjectPart;
nsCString escapedNewsgroupPart;
nsCString escapedNewsHostPart;
nsCString escapedReferencePart;
nsCString escapedBodyPart;
nsCString escapedBccPart;
nsCString escapedFollowUpToPart;
nsCString escapedFromPart;
nsCString escapedHtmlPart;
nsCString escapedOrganizationPart;
nsCString escapedReplyToPart;
nsCString escapedPriorityPart;
// okay, first, free up all of our old search part state.....
CleanupMailtoState();
// m_toPart has the escaped address from before the query string, copy it
// over so we can add on any additional to= addresses and unescape them all.
escapedToPart = m_toPart;
if (rest && *rest == '?')
{
/* start past the '?' */
rest++;
}
if (rest)
{
char *token = NS_strtok("&", &rest);
while (token && *token)
{
char *value = 0;
char *eq = PL_strchr(token, '=');
if (eq)
{
value = eq+1;
*eq = 0;
}
nsCString decodedName;
MsgUnescapeString(nsDependentCString(token), 0, decodedName);
if (decodedName.Length() == 0)
break;
switch (NS_ToUpper(decodedName.First()))
{
/* DO NOT support attachment= in mailto urls. This poses a security fire hole!!!
case 'A':
if (!PL_strcasecmp (token, "attachment"))
m_attachmentPart = value;
break;
*/
case 'B':
if (decodedName.LowerCaseEqualsLiteral("bcc"))
{
if (!escapedBccPart.IsEmpty())
{
escapedBccPart += ", ";
escapedBccPart += value;
}
else
escapedBccPart = value;
}
else if (decodedName.LowerCaseEqualsLiteral("body"))
{
if (!escapedBodyPart.IsEmpty())
{
escapedBodyPart +="\n";
escapedBodyPart += value;
}
else
escapedBodyPart = value;
}
break;
case 'C':
if (decodedName.LowerCaseEqualsLiteral("cc"))
{
if (!escapedCcPart.IsEmpty())
{
escapedCcPart += ", ";
escapedCcPart += value;
}
else
escapedCcPart = value;
}
break;
case 'F':
if (decodedName.LowerCaseEqualsLiteral("followup-to"))
escapedFollowUpToPart = value;
else if (decodedName.LowerCaseEqualsLiteral("from"))
escapedFromPart = value;
break;
case 'H':
if (decodedName.LowerCaseEqualsLiteral("html-part") ||
decodedName.LowerCaseEqualsLiteral("html-body"))
{
// escapedHtmlPart holds the body for both html-part and html-body.
escapedHtmlPart = value;
mFormat = nsIMsgCompFormat::HTML;
}
break;
case 'I':
if (decodedName.LowerCaseEqualsLiteral("in-reply-to"))
escapedInReplyToPart = value;
break;
case 'N':
if (decodedName.LowerCaseEqualsLiteral("newsgroups"))
escapedNewsgroupPart = value;
else if (decodedName.LowerCaseEqualsLiteral("newshost"))
escapedNewsHostPart = value;
break;
case 'O':
if (decodedName.LowerCaseEqualsLiteral("organization"))
escapedOrganizationPart = value;
break;
case 'R':
if (decodedName.LowerCaseEqualsLiteral("references"))
escapedReferencePart = value;
else if (decodedName.LowerCaseEqualsLiteral("reply-to"))
escapedReplyToPart = value;
break;
case 'S':
if(decodedName.LowerCaseEqualsLiteral("subject"))
escapedSubjectPart = value;
break;
case 'P':
if (decodedName.LowerCaseEqualsLiteral("priority"))
escapedPriorityPart = PL_strdup(value);
break;
case 'T':
if (decodedName.LowerCaseEqualsLiteral("to"))
{
if (!escapedToPart.IsEmpty())
{
escapedToPart += ", ";
escapedToPart += value;
}
else
escapedToPart = value;
}
break;
default:
break;
} // end of switch statement...
if (eq)
*eq = '='; /* put it back */
token = NS_strtok("&", &rest);
} // while we still have part of the url to parse...
} // if rest && *rest
// Get a global converter
nsCOMPtr<nsIMimeConverter> mimeConverter =
do_GetService(NS_MIME_CONVERTER_CONTRACTID);
// Now unescape everything, and mime-decode the things that can be encoded.
UnescapeAndConvert(mimeConverter, escapedToPart, m_toPart);
UnescapeAndConvert(mimeConverter, escapedCcPart, m_ccPart);
UnescapeAndConvert(mimeConverter, escapedBccPart, m_bccPart);
UnescapeAndConvert(mimeConverter, escapedSubjectPart, m_subjectPart);
UnescapeAndConvert(mimeConverter, escapedNewsgroupPart, m_newsgroupPart);
UnescapeAndConvert(mimeConverter, escapedReferencePart, m_referencePart);
if (!escapedBodyPart.IsEmpty())
MsgUnescapeString(escapedBodyPart, 0, m_bodyPart);
if (!escapedHtmlPart.IsEmpty())
MsgUnescapeString(escapedHtmlPart, 0, m_htmlPart);
UnescapeAndConvert(mimeConverter, escapedNewsHostPart, m_newsHostPart);
UnescapeAndConvert(mimeConverter, escapedFollowUpToPart, m_followUpToPart);
UnescapeAndConvert(mimeConverter, escapedFromPart, m_fromPart);
UnescapeAndConvert(mimeConverter, escapedOrganizationPart, m_organizationPart);
UnescapeAndConvert(mimeConverter, escapedReplyToPart, m_replyToPart);
UnescapeAndConvert(mimeConverter, escapedPriorityPart, m_priorityPart);
nsCString inReplyToPart; // Not a member like the others...
UnescapeAndConvert(mimeConverter, escapedInReplyToPart, inReplyToPart);
if (!inReplyToPart.IsEmpty())
{
// Ensure that References and In-Reply-To are consistent... The last
// reference will be used as In-Reply-To header.
if (m_referencePart.IsEmpty())
{
// If References is not set, set it to be the In-Reply-To.
m_referencePart = inReplyToPart;
}
else
{
// References is set. Add the In-Reply-To as last header unless it's
// set as last reference already.
int32_t lastRefStart = m_referencePart.RFindChar('<');
nsAutoCString lastReference;
if (lastRefStart != -1)
lastReference = StringTail(m_referencePart, lastRefStart);
else
lastReference = m_referencePart;
if (lastReference != inReplyToPart)
{
m_referencePart += " ";
m_referencePart += inReplyToPart;
}
}
}
return NS_OK;
}
NS_IMETHODIMP nsMailtoUrl::SetSpec(const nsACString &aSpec)
{
nsresult rv = m_baseURL->SetSpec(aSpec);
NS_ENSURE_SUCCESS(rv, rv);
return ParseUrl();
}
nsresult nsMailtoUrl::CleanupMailtoState()
{
m_ccPart = "";
m_subjectPart = "";
m_newsgroupPart = "";
m_newsHostPart = "";
m_referencePart = "";
m_bodyPart = "";
m_bccPart = "";
m_followUpToPart = "";
m_fromPart = "";
m_htmlPart = "";
m_organizationPart = "";
m_replyToPart = "";
m_priorityPart = "";
return NS_OK;
}
nsresult nsMailtoUrl::ParseUrl()
{
// we can get the path from the simple url.....
nsCString escapedPath;
m_baseURL->GetPath(escapedPath);
int32_t startOfSearchPart = escapedPath.FindChar('?');
if (startOfSearchPart >= 0)
{
// now parse out the search field...
nsAutoCString searchPart(Substring(escapedPath, startOfSearchPart));
if (!searchPart.IsEmpty())
{
// now we need to strip off the search part from the
// to part....
escapedPath.SetLength(startOfSearchPart);
MsgUnescapeString(escapedPath, 0, m_toPart);
ParseMailtoUrl(searchPart.BeginWriting());
}
}
else if (!escapedPath.IsEmpty())
{
MsgUnescapeString(escapedPath, 0, m_toPart);
}
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetMessageContents(nsACString &aToPart, nsACString &aCcPart,
nsACString &aBccPart, nsACString &aSubjectPart,
nsACString &aBodyPart, nsACString &aHtmlPart,
nsACString &aReferencePart,
nsACString &aNewsgroupPart,
MSG_ComposeFormat *aFormat)
{
NS_ENSURE_ARG_POINTER(aFormat);
aToPart = m_toPart;
aCcPart = m_ccPart;
aBccPart = m_bccPart;
aSubjectPart = m_subjectPart;
aBodyPart = m_bodyPart;
aHtmlPart = m_htmlPart;
aReferencePart = m_referencePart;
aNewsgroupPart = m_newsgroupPart;
*aFormat = mFormat;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetFromPart(nsACString &aResult)
{
aResult = m_fromPart;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetFollowUpToPart(nsACString &aResult)
{
aResult = m_followUpToPart;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetOrganizationPart(nsACString &aResult)
{
aResult = m_organizationPart;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetReplyToPart(nsACString &aResult)
{
aResult = m_replyToPart;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetPriorityPart(nsACString &aResult)
{
aResult = m_priorityPart;
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::GetNewsHostPart(nsACString &aResult)
{
aResult = m_newsHostPart;
return NS_OK;
}
//////////////////////////////////////////////////////////////////////////////
// Begin nsIURI support
//////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsMailtoUrl::GetSpec(nsACString &aSpec)
{
return m_baseURL->GetSpec(aSpec);
}
NS_IMETHODIMP nsMailtoUrl::GetPrePath(nsACString &aPrePath)
{
return m_baseURL->GetPrePath(aPrePath);
}
NS_IMETHODIMP nsMailtoUrl::GetScheme(nsACString &aScheme)
{
return m_baseURL->GetScheme(aScheme);
}
NS_IMETHODIMP nsMailtoUrl::SetScheme(const nsACString &aScheme)
{
m_baseURL->SetScheme(aScheme);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetUserPass(nsACString &aUserPass)
{
return m_baseURL->GetUserPass(aUserPass);
}
NS_IMETHODIMP nsMailtoUrl::SetUserPass(const nsACString &aUserPass)
{
m_baseURL->SetUserPass(aUserPass);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetUsername(nsACString &aUsername)
{
return m_baseURL->GetUsername(aUsername);
}
NS_IMETHODIMP nsMailtoUrl::SetUsername(const nsACString &aUsername)
{
m_baseURL->SetUsername(aUsername);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetPassword(nsACString &aPassword)
{
return m_baseURL->GetPassword(aPassword);
}
NS_IMETHODIMP nsMailtoUrl::SetPassword(const nsACString &aPassword)
{
m_baseURL->SetPassword(aPassword);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetHostPort(nsACString &aHostPort)
{
return m_baseURL->GetHost(aHostPort);
}
NS_IMETHODIMP nsMailtoUrl::SetHostPort(const nsACString &aHostPort)
{
m_baseURL->SetHost(aHostPort);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::SetHostAndPort(const nsACString &aHostPort)
{
m_baseURL->SetHostAndPort(aHostPort);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetHost(nsACString &aHost)
{
return m_baseURL->GetHost(aHost);
}
NS_IMETHODIMP nsMailtoUrl::SetHost(const nsACString &aHost)
{
m_baseURL->SetHost(aHost);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetPort(int32_t *aPort)
{
return m_baseURL->GetPort(aPort);
}
NS_IMETHODIMP nsMailtoUrl::SetPort(int32_t aPort)
{
m_baseURL->SetPort(aPort);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetPath(nsACString &aPath)
{
return m_baseURL->GetPath(aPath);
}
NS_IMETHODIMP nsMailtoUrl::SetPath(const nsACString &aPath)
{
m_baseURL->SetPath(aPath);
return ParseUrl();
}
NS_IMETHODIMP nsMailtoUrl::GetAsciiHost(nsACString &aHostA)
{
return m_baseURL->GetAsciiHost(aHostA);
}
NS_IMETHODIMP nsMailtoUrl::GetAsciiHostPort(nsACString &aHostPortA)
{
return m_baseURL->GetAsciiHostPort(aHostPortA);
}
NS_IMETHODIMP nsMailtoUrl::GetAsciiSpec(nsACString &aSpecA)
{
return m_baseURL->GetAsciiSpec(aSpecA);
}
NS_IMETHODIMP nsMailtoUrl::GetOriginCharset(nsACString &aOriginCharset)
{
return m_baseURL->GetOriginCharset(aOriginCharset);
}
NS_IMETHODIMP nsMailtoUrl::SchemeIs(const char *aScheme, bool *_retval)
{
return m_baseURL->SchemeIs(aScheme, _retval);
}
NS_IMETHODIMP nsMailtoUrl::Equals(nsIURI *other, bool *_retval)
{
// The passed-in URI might be an nsMailtoUrl. Pass our inner URL to its
// Equals method. The other nsMailtoUrl will then pass its inner URL to
// to the Equals method of our inner URL. Other URIs will return false.
if (other)
return other->Equals(m_baseURL, _retval);
return m_baseURL->Equals(other, _retval);
}
nsresult
nsMailtoUrl::CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** _retval)
{
NS_ENSURE_ARG_POINTER(_retval);
RefPtr<nsMailtoUrl> clone = new nsMailtoUrl();
NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
nsresult rv;
if (aRefHandlingMode == eHonorRef) {
rv = m_baseURL->Clone(getter_AddRefs(clone->m_baseURL));
} else if (aRefHandlingMode == eReplaceRef) {
rv = m_baseURL->CloneWithNewRef(newRef, getter_AddRefs(clone->m_baseURL));
} else {
rv = m_baseURL->CloneIgnoringRef(getter_AddRefs(clone->m_baseURL));
}
NS_ENSURE_SUCCESS(rv, rv);
clone->ParseUrl();
clone.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP
nsMailtoUrl::Clone(nsIURI **_retval)
{
return CloneInternal(eHonorRef, EmptyCString(), _retval);
}
NS_IMETHODIMP
nsMailtoUrl::CloneIgnoringRef(nsIURI** _retval)
{
return CloneInternal(eIgnoreRef, EmptyCString(), _retval);
}
NS_IMETHODIMP
nsMailtoUrl::CloneWithNewRef(const nsACString& newRef, nsIURI** _retval)
{
return CloneInternal(eReplaceRef, newRef, _retval);
}
NS_IMETHODIMP nsMailtoUrl::Resolve(const nsACString &relativePath, nsACString &result)
{
return m_baseURL->Resolve(relativePath, result);
}
NS_IMETHODIMP nsMailtoUrl::SetRef(const nsACString &aRef)
{
return m_baseURL->SetRef(aRef);
}
NS_IMETHODIMP
nsMailtoUrl::GetRef(nsACString &result)
{
return m_baseURL->GetRef(result);
}
NS_IMETHODIMP nsMailtoUrl::EqualsExceptRef(nsIURI *other, bool *result)
{
// The passed-in URI might be an nsMailtoUrl. Pass our inner URL to its
// Equals method. The other nsMailtoUrl will then pass its inner URL to
// to the Equals method of our inner URL. Other URIs will return false.
if (other)
return other->EqualsExceptRef(m_baseURL, result);
return m_baseURL->EqualsExceptRef(other, result);
}
NS_IMETHODIMP
nsMailtoUrl::GetSpecIgnoringRef(nsACString &result)
{
return m_baseURL->GetSpecIgnoringRef(result);
}
NS_IMETHODIMP
nsMailtoUrl::GetHasRef(bool *result)
{
return m_baseURL->GetHasRef(result);
}
/////////////////////////////////////////////////////////////////////////////////////
// smtp url definition
/////////////////////////////////////////////////////////////////////////////////////
nsSmtpUrl::nsSmtpUrl() : nsMsgMailNewsUrl()
{
// nsISmtpUrl specific state...
m_isPostMessage = true;
m_requestDSN = false;
m_verifyLogon = false;
}
nsSmtpUrl::~nsSmtpUrl()
{
}
NS_IMPL_ISUPPORTS_INHERITED(nsSmtpUrl, nsMsgMailNewsUrl, nsISmtpUrl)
////////////////////////////////////////////////////////////////////////////////////
// Begin nsISmtpUrl specific support
////////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsSmtpUrl::SetRecipients(const char * aRecipientsList)
{
NS_ENSURE_ARG(aRecipientsList);
MsgUnescapeString(nsDependentCString(aRecipientsList), 0, m_toPart);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetRecipients(char ** aRecipientsList)
{
NS_ENSURE_ARG_POINTER(aRecipientsList);
if (aRecipientsList)
*aRecipientsList = ToNewCString(m_toPart);
return NS_OK;
}
NS_IMPL_GETSET(nsSmtpUrl, PostMessage, bool, m_isPostMessage)
NS_IMPL_GETSET(nsSmtpUrl, VerifyLogon, bool, m_verifyLogon)
// the message can be stored in a file....allow accessors for getting and setting
// the file name to post...
NS_IMETHODIMP nsSmtpUrl::SetPostMessageFile(nsIFile * aFile)
{
NS_ENSURE_ARG_POINTER(aFile);
m_fileName = aFile;
return NS_OK;
}
NS_IMETHODIMP nsSmtpUrl::GetPostMessageFile(nsIFile ** aFile)
{
NS_ENSURE_ARG_POINTER(aFile);
if (m_fileName)
{
// Clone the file so nsLocalFile stat caching doesn't make the caller get
// the wrong file size.
m_fileName->Clone(aFile);
return *aFile ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
return NS_ERROR_NULL_POINTER;
}
NS_IMPL_GETSET(nsSmtpUrl, RequestDSN, bool, m_requestDSN)
NS_IMETHODIMP
nsSmtpUrl::SetDsnEnvid(const nsACString &aDsnEnvid)
{
m_dsnEnvid = aDsnEnvid;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetDsnEnvid(nsACString &aDsnEnvid)
{
aDsnEnvid = m_dsnEnvid;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetSenderIdentity(nsIMsgIdentity **aSenderIdentity)
{
NS_ENSURE_ARG_POINTER(aSenderIdentity);
*aSenderIdentity = m_senderIdentity;
NS_ADDREF(*aSenderIdentity);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::SetSenderIdentity(nsIMsgIdentity *aSenderIdentity)
{
NS_ENSURE_ARG_POINTER(aSenderIdentity);
m_senderIdentity = aSenderIdentity;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::SetPrompt(nsIPrompt *aNetPrompt)
{
NS_ENSURE_ARG_POINTER(aNetPrompt);
m_netPrompt = aNetPrompt;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetPrompt(nsIPrompt **aNetPrompt)
{
NS_ENSURE_ARG_POINTER(aNetPrompt);
NS_ENSURE_TRUE(m_netPrompt, NS_ERROR_NULL_POINTER);
*aNetPrompt = m_netPrompt;
NS_ADDREF(*aNetPrompt);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::SetAuthPrompt(nsIAuthPrompt *aNetAuthPrompt)
{
NS_ENSURE_ARG_POINTER(aNetAuthPrompt);
m_netAuthPrompt = aNetAuthPrompt;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetAuthPrompt(nsIAuthPrompt **aNetAuthPrompt)
{
NS_ENSURE_ARG_POINTER(aNetAuthPrompt);
NS_ENSURE_TRUE(m_netAuthPrompt, NS_ERROR_NULL_POINTER);
*aNetAuthPrompt = m_netAuthPrompt;
NS_ADDREF(*aNetAuthPrompt);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
{
NS_ENSURE_ARG_POINTER(aCallbacks);
m_callbacks = aCallbacks;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
{
NS_ENSURE_ARG_POINTER(aCallbacks);
NS_ENSURE_TRUE(m_callbacks, NS_ERROR_NULL_POINTER);
*aCallbacks = m_callbacks;
NS_ADDREF(*aCallbacks);
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::SetSmtpServer(nsISmtpServer * aSmtpServer)
{
NS_ENSURE_ARG_POINTER(aSmtpServer);
m_smtpServer = aSmtpServer;
return NS_OK;
}
NS_IMETHODIMP
nsSmtpUrl::GetSmtpServer(nsISmtpServer ** aSmtpServer)
{
NS_ENSURE_ARG_POINTER(aSmtpServer);
NS_ENSURE_TRUE(m_smtpServer, NS_ERROR_NULL_POINTER);
*aSmtpServer = m_smtpServer;
NS_ADDREF(*aSmtpServer);
return NS_OK;
}

View file

@ -0,0 +1,100 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsSmtpUrl_h__
#define nsSmtpUrl_h__
#include "nsISmtpUrl.h"
#include "nsIURI.h"
#include "nsMsgMailNewsUrl.h"
#include "nsIMsgIdentity.h"
#include "nsCOMPtr.h"
#include "nsIPrompt.h"
#include "nsIAuthPrompt.h"
#include "nsISmtpServer.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
class nsMailtoUrl : public nsIMailtoUrl, public nsIURI
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIURI
NS_DECL_NSIMAILTOURL
nsMailtoUrl();
protected:
enum RefHandlingEnum {
eIgnoreRef,
eHonorRef,
eReplaceRef
};
virtual ~nsMailtoUrl();
nsresult ParseUrl();
nsresult CleanupMailtoState();
nsresult ParseMailtoUrl(char * searchPart);
nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
const nsACString& newRef, nsIURI** _retval);
nsCOMPtr<nsIURI> m_baseURL;
// data retrieved from parsing the url: (Note the url could be a post from file or it could be in the url)
nsCString m_toPart;
nsCString m_ccPart;
nsCString m_subjectPart;
nsCString m_newsgroupPart;
nsCString m_newsHostPart;
nsCString m_referencePart;
nsCString m_bodyPart;
nsCString m_bccPart;
nsCString m_followUpToPart;
nsCString m_fromPart;
nsCString m_htmlPart;
nsCString m_organizationPart;
nsCString m_replyToPart;
nsCString m_priorityPart;
MSG_ComposeFormat mFormat;
};
class nsSmtpUrl : public nsISmtpUrl, public nsMsgMailNewsUrl
{
public:
NS_DECL_ISUPPORTS_INHERITED
// From nsISmtpUrl
NS_DECL_NSISMTPURL
// nsSmtpUrl
nsSmtpUrl();
protected:
virtual ~nsSmtpUrl();
// data retrieved from parsing the url: (Note the url could be a post from
// file or it could be in the url)
nsCString m_toPart;
bool m_isPostMessage;
bool m_requestDSN;
nsCString m_dsnEnvid;
bool m_verifyLogon;
// Smtp specific event sinks
nsCOMPtr<nsIFile> m_fileName;
nsCOMPtr<nsIMsgIdentity> m_senderIdentity;
nsCOMPtr<nsIPrompt> m_netPrompt;
nsCOMPtr<nsIAuthPrompt> m_netAuthPrompt;
nsCOMPtr<nsIInterfaceRequestor> m_callbacks;
nsCOMPtr<nsISmtpServer> m_smtpServer;
// it is possible to encode the message to parse in the form of a url.
// This function is used to decompose the search and path part into the bare
// message components (to, fcc, bcc, etc.)
nsresult ParseMessageToPost(char * searchPart);
};
#endif // nsSmtpUrl_h__

View file

@ -0,0 +1,526 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsURLFetcher.h"
#include "msgCore.h" // for pre-compiled headers
#include "nsCOMPtr.h"
#include "nsNullPrincipal.h"
#include <stdio.h>
#include "nscore.h"
#include "nsIFactory.h"
#include "nsISupports.h"
#include "prmem.h"
#include "plstr.h"
#include "nsIComponentManager.h"
#include "nsStringGlue.h"
#include "nsIIOService.h"
#include "nsIChannel.h"
#include "nsNetUtil.h"
#include "nsMimeTypes.h"
#include "nsIHttpChannel.h"
#include "nsIWebProgress.h"
#include "nsMsgAttachmentHandler.h"
#include "nsMsgSend.h"
#include "nsISeekableStream.h"
#include "nsIStreamConverterService.h"
#include "nsIMsgProgress.h"
#include "nsMsgUtils.h"
NS_IMPL_ISUPPORTS(nsURLFetcher,
nsIURLFetcher,
nsIStreamListener,
nsIRequestObserver,
nsIURIContentListener,
nsIInterfaceRequestor,
nsIWebProgressListener,
nsISupportsWeakReference)
/*
* Inherited methods for nsMimeConverter
*/
nsURLFetcher::nsURLFetcher()
{
// Init member variables...
mTotalWritten = 0;
mBuffer = nullptr;
mBufferSize = 0;
mStillRunning = true;
mCallback = nullptr;
mOnStopRequestProcessed = false;
mIsFile=false;
nsURLFetcherStreamConsumer *consumer = new nsURLFetcherStreamConsumer(this);
mConverter = do_QueryInterface(consumer);
}
nsURLFetcher::~nsURLFetcher()
{
mStillRunning = false;
PR_FREEIF(mBuffer);
// Remove the DocShell as a listener of the old WebProgress...
if (mLoadCookie)
{
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress)
webProgress->RemoveProgressListener(this);
}
}
NS_IMETHODIMP nsURLFetcher::GetInterface(const nsIID & aIID, void * *aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
return QueryInterface(aIID, aInstancePtr);
}
// nsIURIContentListener support
NS_IMETHODIMP
nsURLFetcher::OnStartURIOpen(nsIURI* aURI, bool* aAbortOpen)
{
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::IsPreferred(const char * aContentType,
char ** aDesiredContentType,
bool * aCanHandleContent)
{
return CanHandleContent(aContentType, true, aDesiredContentType,
aCanHandleContent);
}
NS_IMETHODIMP
nsURLFetcher::CanHandleContent(const char * aContentType,
bool aIsContentPreferred,
char ** aDesiredContentType,
bool * aCanHandleContent)
{
if (!mIsFile && PL_strcasecmp(aContentType, MESSAGE_RFC822) == 0)
*aDesiredContentType = strdup("text/html");
// since we explicilty loaded the url, we always want to handle it!
*aCanHandleContent = true;
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::DoContent(const nsACString& aContentType,
bool aIsContentPreferred,
nsIRequest *request,
nsIStreamListener ** aContentHandler,
bool * aAbortProcess)
{
nsresult rv = NS_OK;
if (aAbortProcess)
*aAbortProcess = false;
QueryInterface(NS_GET_IID(nsIStreamListener), (void **) aContentHandler);
/*
Check the content-type to see if we need to insert a converter
*/
if (PL_strcasecmp(PromiseFlatCString(aContentType).get(), UNKNOWN_CONTENT_TYPE) == 0 ||
PL_strcasecmp(PromiseFlatCString(aContentType).get(), MULTIPART_MIXED_REPLACE) == 0 ||
PL_strcasecmp(PromiseFlatCString(aContentType).get(), MULTIPART_MIXED) == 0 ||
PL_strcasecmp(PromiseFlatCString(aContentType).get(), MULTIPART_BYTERANGES) == 0)
{
rv = InsertConverter(PromiseFlatCString(aContentType).get());
if (NS_SUCCEEDED(rv))
mConverterContentType = PromiseFlatCString(aContentType).get();
}
return rv;
}
NS_IMETHODIMP
nsURLFetcher::GetParentContentListener(nsIURIContentListener** aParent)
{
*aParent = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::SetParentContentListener(nsIURIContentListener* aParent)
{
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::GetLoadCookie(nsISupports ** aLoadCookie)
{
*aLoadCookie = mLoadCookie;
NS_IF_ADDREF(*aLoadCookie);
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::SetLoadCookie(nsISupports * aLoadCookie)
{
// Remove the DocShell as a listener of the old WebProgress...
if (mLoadCookie)
{
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress)
webProgress->RemoveProgressListener(this);
}
mLoadCookie = aLoadCookie;
// Add the DocShell as a listener to the new WebProgress...
if (mLoadCookie)
{
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress)
webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL);
}
return NS_OK;
}
nsresult
nsURLFetcher::StillRunning(bool *running)
{
*running = mStillRunning;
return NS_OK;
}
// Methods for nsIStreamListener...
nsresult
nsURLFetcher::OnDataAvailable(nsIRequest *request, nsISupports * ctxt, nsIInputStream *aIStream,
uint64_t sourceOffset, uint32_t aLength)
{
/* let our converter or consumer process the data */
if (!mConverter)
return NS_ERROR_FAILURE;
return mConverter->OnDataAvailable(request, ctxt, aIStream, sourceOffset, aLength);
}
// Methods for nsIStreamObserver
nsresult
nsURLFetcher::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
/* check if the user has canceld the operation */
if (mTagData)
{
nsCOMPtr<nsIMsgSend> sendPtr;
mTagData->GetMimeDeliveryState(getter_AddRefs(sendPtr));
if (sendPtr)
{
nsCOMPtr<nsIMsgProgress> progress;
sendPtr->GetProgress(getter_AddRefs(progress));
if (progress)
{
bool cancel = false;
progress->GetProcessCanceledByUser(&cancel);
if (cancel)
return request->Cancel(NS_ERROR_ABORT);
}
}
mTagData->mRequest = request;
}
/* call our converter or consumer */
if (mConverter)
return mConverter->OnStartRequest(request, ctxt);
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::OnStopRequest(nsIRequest *request, nsISupports * ctxt, nsresult aStatus)
{
// it's possible we could get in here from the channel calling us with an OnStopRequest and from our
// onStatusChange method (in the case of an error). So we should protect against this to make sure we
// don't process the on stop request twice...
if (mOnStopRequestProcessed)
return NS_OK;
mOnStopRequestProcessed = true;
/* first, call our converter or consumer */
if (mConverter)
(void) mConverter->OnStopRequest(request, ctxt, aStatus);
if (mTagData)
mTagData->mRequest = nullptr;
//
// Now complete the stream!
//
mStillRunning = false;
// time to close the output stream...
if (mOutStream)
{
mOutStream->Close();
mOutStream = nullptr;
/* In case of multipart/x-mixed-replace, we need to truncate the file to the current part size */
if (MsgLowerCaseEqualsLiteral(mConverterContentType, MULTIPART_MIXED_REPLACE))
{
mLocalFile->SetFileSize(mTotalWritten);
}
}
// Now if there is a callback, we need to call it...
if (mCallback)
mCallback (aStatus, mContentType, mCharset, mTotalWritten, nullptr, mTagData);
// Time to return...
return NS_OK;
}
nsresult
nsURLFetcher::Initialize(nsIFile *localFile,
nsIOutputStream *outputStream,
nsAttachSaveCompletionCallback cb,
nsMsgAttachmentHandler *tagData)
{
if (!outputStream || !localFile)
return NS_ERROR_INVALID_ARG;
mOutStream = outputStream;
mLocalFile = localFile;
mCallback = cb; //JFD: Please, no more callback, use a listener...
mTagData = tagData;
return NS_OK;
}
nsresult
nsURLFetcher::FireURLRequest(nsIURI *aURL, nsIFile *localFile, nsIOutputStream *outputStream,
nsAttachSaveCompletionCallback cb, nsMsgAttachmentHandler *tagData)
{
nsresult rv;
rv = Initialize(localFile, outputStream, cb, tagData);
NS_ENSURE_SUCCESS(rv, rv);
//check to see if aURL is a local file or not
aURL->SchemeIs("file", &mIsFile);
// we're about to fire a new url request so make sure the on stop request flag is cleared...
mOnStopRequestProcessed = false;
// let's try uri dispatching...
nsCOMPtr<nsIURILoader> pURILoader (do_GetService(NS_URI_LOADER_CONTRACTID));
NS_ENSURE_TRUE(pURILoader, NS_ERROR_FAILURE);
nsCOMPtr<nsIPrincipal> nullPrincipal =
do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel),
aURL,
nullPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aLoadGroup
this); // aCallbacks
NS_ENSURE_SUCCESS(rv, rv);
return pURILoader->OpenURI(channel, false, this);
}
nsresult
nsURLFetcher::InsertConverter(const char * aContentType)
{
nsresult rv;
nsCOMPtr<nsIStreamConverterService> convServ(do_GetService("@mozilla.org/streamConverters;1", &rv));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIStreamListener> toListener(mConverter);
nsCOMPtr<nsIStreamListener> fromListener;
rv = convServ->AsyncConvertData(aContentType,
"*/*",
toListener,
nullptr,
getter_AddRefs(fromListener));
if (NS_SUCCEEDED(rv))
mConverter = fromListener;
}
return rv;
}
// web progress listener implementation
NS_IMETHODIMP
nsURLFetcher::OnProgressChange(nsIWebProgress *aProgress, nsIRequest *aRequest,
int32_t aCurSelfProgress, int32_t aMaxSelfProgress,
int32_t aCurTotalProgress, int32_t aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::OnStateChange(nsIWebProgress *aProgress, nsIRequest *aRequest,
uint32_t aStateFlags, nsresult aStatus)
{
// all we care about is the case where an error occurred (as in we were unable to locate the
// the url....
if (NS_FAILED(aStatus))
OnStopRequest(aRequest, nullptr, aStatus);
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI *aURI,
uint32_t aFlags)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsresult aStatus,
const char16_t* aMessage)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsURLFetcher::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
uint32_t state)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
/**
* Stream consumer used for handling special content type like multipart/x-mixed-replace
*/
NS_IMPL_ISUPPORTS(nsURLFetcherStreamConsumer, nsIStreamListener, nsIRequestObserver)
nsURLFetcherStreamConsumer::nsURLFetcherStreamConsumer(nsURLFetcher* urlFetcher) :
mURLFetcher(urlFetcher)
{
}
nsURLFetcherStreamConsumer::~nsURLFetcherStreamConsumer()
{
}
/** nsIRequestObserver methods **/
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP nsURLFetcherStreamConsumer::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
{
if (!mURLFetcher || !mURLFetcher->mOutStream)
return NS_ERROR_FAILURE;
/* In case of multipart/x-mixed-replace, we need to erase the output file content */
if (MsgLowerCaseEqualsLiteral(mURLFetcher->mConverterContentType, MULTIPART_MIXED_REPLACE))
{
nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(mURLFetcher->mOutStream);
if (seekStream)
seekStream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
mURLFetcher->mTotalWritten = 0;
}
return NS_OK;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */
NS_IMETHODIMP nsURLFetcherStreamConsumer::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, nsresult status)
{
if (!mURLFetcher)
return NS_ERROR_FAILURE;
// Check the content type!
nsAutoCString contentType;
nsAutoCString charset;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if(!channel) return NS_ERROR_FAILURE;
if (NS_SUCCEEDED(channel->GetContentType(contentType)) &&
!contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE))
{
nsAutoCString uriSpec;
nsCOMPtr <nsIURI> channelURI;
channel->GetURI(getter_AddRefs(channelURI));
nsresult rv = channelURI->GetSpec(uriSpec);
NS_ENSURE_SUCCESS(rv, rv);
if (uriSpec.Find("&realtype=message/rfc822") >= 0)
mURLFetcher->mContentType = MESSAGE_RFC822;
else
mURLFetcher->mContentType = contentType;
}
if (NS_SUCCEEDED(channel->GetContentCharset(charset)) && !charset.IsEmpty())
{
mURLFetcher->mCharset = charset;
}
return NS_OK;
}
/** nsIStreamListener methods **/
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long long sourceOffset, in unsigned long count); */
NS_IMETHODIMP nsURLFetcherStreamConsumer::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, nsIInputStream *inStr, uint64_t sourceOffset, uint32_t count)
{
uint32_t readLen = count;
uint32_t wroteIt;
if (!mURLFetcher)
return NS_ERROR_FAILURE;
if (!mURLFetcher->mOutStream)
return NS_ERROR_INVALID_ARG;
if (mURLFetcher->mBufferSize < count)
{
PR_FREEIF(mURLFetcher->mBuffer);
if (count > 0x1000)
mURLFetcher->mBufferSize = count;
else
mURLFetcher->mBufferSize = 0x1000;
mURLFetcher->mBuffer = (char *)PR_Malloc(mURLFetcher->mBufferSize);
if (!mURLFetcher->mBuffer)
return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */
}
// read the data from the input stram...
nsresult rv = inStr->Read(mURLFetcher->mBuffer, count, &readLen);
if (NS_FAILED(rv))
return rv;
// write to the output file...
mURLFetcher->mOutStream->Write(mURLFetcher->mBuffer, readLen, &wroteIt);
if (wroteIt != readLen)
return NS_ERROR_FAILURE;
else
{
mURLFetcher->mTotalWritten += wroteIt;
return NS_OK;
}
}

View file

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsURLFetcher_h_
#define nsURLFetcher_h_
#include "nsIURLFetcher.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsIInputStream.h"
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsCURILoader.h"
#include "nsIURIContentListener.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
#include "nsStringGlue.h"
class nsMsgAttachmentHandler;
class nsURLFetcher : public nsIURLFetcher,
public nsIStreamListener,
public nsIURIContentListener,
public nsIInterfaceRequestor,
public nsIWebProgressListener,
public nsSupportsWeakReference
{
public:
nsURLFetcher();
/* this macro defines QueryInterface, AddRef and Release for this class */
NS_DECL_ISUPPORTS
// Methods for nsIURLFetcher
NS_DECL_NSIURLFETCHER
// Methods for nsIStreamListener
NS_DECL_NSISTREAMLISTENER
// Methods for nsIRequestObserver
NS_DECL_NSIREQUESTOBSERVER
// Methods for nsIURICOntentListener
NS_DECL_NSIURICONTENTLISTENER
// Methods for nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
// Methods for nsIWebProgressListener
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
nsresult InsertConverter(const char * aContentType);
private:
virtual ~nsURLFetcher();
nsCOMPtr<nsIOutputStream> mOutStream; // the output file stream
nsCOMPtr<nsIFile> mLocalFile; // the output file itself
nsCOMPtr<nsIStreamListener> mConverter; // the stream converter, if needed
nsCString mConverterContentType; // The content type of the converter
bool mStillRunning; // Are we still running?
int32_t mTotalWritten; // Size counter variable
char *mBuffer; // Buffer used for reading the data
uint32_t mBufferSize; // Buffer size;
nsCString mContentType; // The content type retrieved from the server
nsCString mCharset; // The charset retrieved from the server
RefPtr<nsMsgAttachmentHandler> mTagData; // Tag data for callback...
nsAttachSaveCompletionCallback mCallback; // Callback to call once the file is saved...
nsCOMPtr<nsISupports> mLoadCookie; // load cookie used by the uri loader when we fetch the url
bool mOnStopRequestProcessed; // used to prevent calling OnStopRequest multiple times
bool mIsFile; // This is used to check whether the URI is a local file.
friend class nsURLFetcherStreamConsumer;
};
/**
* Stream consumer used for handling special content type like multipart/x-mixed-replace
*/
class nsURLFetcherStreamConsumer : public nsIStreamListener
{
public:
nsURLFetcherStreamConsumer(nsURLFetcher* urlFetcher);
/* additional members */
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
private:
virtual ~nsURLFetcherStreamConsumer();
nsURLFetcher* mURLFetcher;
};
#endif /* nsURLFetcher_h_ */