diff --git a/mailnews/compose/build/nsMsgCompCID.h b/mailnews/compose/build/nsMsgCompCID.h index 1b433d6a38c1..06f91c517406 100644 --- a/mailnews/compose/build/nsMsgCompCID.h +++ b/mailnews/compose/build/nsMsgCompCID.h @@ -38,6 +38,11 @@ 0x935284e0, 0xc5d8, 0x11d2, \ {0x82, 0x97, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}} +#define NS_MSGSENDLATER_CID \ +{ /* E15C83F1-1CF4-11d3-8EF0-00A024A7D144 */ \ + 0xe15c83f1, 0x1cf4, 0x11d3, \ + {0x8e, 0xf0, 0x0, 0xa0, 0x24, 0xa7, 0xd1, 0x44 }} + #define NS_MSGPOST_CID \ { /* 80a368c0-f1bf-11d2-8921-004005263078 */ \ 0x80a368c0, 0xf1bf, 0x11d2, \ diff --git a/mailnews/compose/build/nsMsgCompFactory.cpp b/mailnews/compose/build/nsMsgCompFactory.cpp index e28ba3a4074a..f6433a24b9ab 100644 --- a/mailnews/compose/build/nsMsgCompFactory.cpp +++ b/mailnews/compose/build/nsMsgCompFactory.cpp @@ -31,6 +31,7 @@ #include "nsMsgComposeFact.h" #include "nsMsgCompFieldsFact.h" #include "nsMsgSendFact.h" +#include "nsMsgSendLaterFact.h" #include "nsIServiceManager.h" #include "nsCOMPtr.h" @@ -40,6 +41,7 @@ static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); static NS_DEFINE_CID(kCMsgComposeCID, NS_MSGCOMPOSE_CID); static NS_DEFINE_CID(kCMsgCompFieldsCID, NS_MSGCOMPFIELDS_CID); static NS_DEFINE_CID(kCMsgSendCID, NS_MSGSEND_CID); +static NS_DEFINE_CID(kCMsgSendLaterCID, NS_MSGSENDLATER_CID); static NS_DEFINE_CID(kCSmtpServiceCID, NS_SMTPSERVICE_CID); static NS_DEFINE_CID(kCComposeAppCoreCID, NS_COMPOSEAPPCORE_CID); static NS_DEFINE_CID(kCComposerBootstrapCID, NS_COMPOSERBOOTSTRAP_CID); @@ -150,10 +152,10 @@ nsresult nsMsgComposeFactory::CreateInstance(nsISupports *aOuter, const nsIID &a return smtpService->QueryInterface(kISupportsIID, aResult); } // do they want a Message Compose interface ? - else if (mClassID.Equals(kCMsgComposeCID)) - { - return NS_NewMsgCompose(aIID, aResult); - } + // RICHIE - not any more else if (mClassID.Equals(kCMsgComposeCID)) + // RICHIE - not any more { + // RICHIE - not any more return NS_NewMsgCompose(aIID, aResult); + // RICHIE - not any more } // do they want a Message Compose Fields interface ? else if (mClassID.Equals(kCMsgCompFieldsCID)) @@ -166,6 +168,12 @@ nsresult nsMsgComposeFactory::CreateInstance(nsISupports *aOuter, const nsIID &a { return NS_NewMsgSend(aIID, aResult); } + // do they want a Message Send Later interface ? + else if (mClassID.Equals(kCMsgSendLaterCID)) + { + return NS_NewMsgSendLater(aIID, aResult); + } + // do they want a Compose AppCore interface ? else if (mClassID.Equals(kCComposeAppCoreCID)) { @@ -243,6 +251,11 @@ extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char* nsnull, path, PR_TRUE, PR_TRUE); if (NS_FAILED(rv)) finalResult = rv; + rv = compMgr->RegisterComponent(kCMsgSendLaterCID, + "Message Send Later", + nsnull, path, PR_TRUE, PR_TRUE); + if (NS_FAILED(rv)) finalResult = rv; + rv = compMgr->RegisterComponent(kCMsgComposeCID, "Message Compose", nsnull, @@ -303,6 +316,9 @@ NSUnregisterSelf(nsISupports* aServMgr, const char* path) rv = compMgr->UnregisterComponent(kCMsgSendCID, path); if (NS_FAILED(rv)) finalResult = rv; + rv = compMgr->UnregisterComponent(kCMsgSendLaterCID, path); + if (NS_FAILED(rv)) finalResult = rv; + rv = compMgr->UnregisterComponent(kCMsgCompFieldsCID, path); if (NS_FAILED(rv)) finalResult = rv; diff --git a/mailnews/compose/public/nsMsgSendLaterFact.h b/mailnews/compose/public/nsMsgSendLaterFact.h new file mode 100644 index 000000000000..ffb06e87f330 --- /dev/null +++ b/mailnews/compose/public/nsMsgSendLaterFact.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/******************************************************************************************************** + + Message Send Later Class Factory. + +*********************************************************************************************************/ + +#ifndef _MsgSendLaterFact_H_ +#define _MsgSendLaterFact_H_ + +#include "nsIMsgSendLater.h" + +extern nsresult NS_NewMsgSendLater(const nsIID &aIID, void ** aInstancePtrResult); + + +#endif + diff --git a/mailnews/compose/src/Makefile.in b/mailnews/compose/src/Makefile.in index cc1dd47029ad..759dd2c9bde1 100644 --- a/mailnews/compose/src/Makefile.in +++ b/mailnews/compose/src/Makefile.in @@ -31,11 +31,21 @@ EXPORTS = \ nsComposeAppCore.h \ nsComposer.h \ nsMsgCompPrefs.h \ + nsMsgZapIt.h \ + nsMsgCreate.h \ + nsMsgCopy.h \ + nsMsgSendLater.h \ + nsMsgDeliveryListener.h \ + nsMsgComposeStringBundle.h \ + nsMsgEncoders.h \ + nsMsgUtils.h \ + nsMsgI18N.h \ + nsMsgAttachmentHandler.h \ + nsMsgPrompts.h \ $(NULL) CPPSRCS = \ nsMsgCompFields.cpp \ - nsMsgCompose.cpp \ msgCompGlue.cpp \ nsSmtpUrl.cpp \ nsSmtpProtocol.cpp \ @@ -48,6 +58,17 @@ CPPSRCS = \ nsComposerNameSet.cpp \ nsMsgCompPrefs.cpp \ nsIComposer.cpp \ + nsMsgZapIt.cpp \ + nsMsgCreate.cpp \ + nsMsgCopy.cpp \ + nsMsgSendLater.cpp \ + nsMsgDeliveryListener.cpp \ + nsMsgComposeStringBundle.cpp \ + nsMsgEncoders.cpp \ + nsMsgUtils.cpp \ + nsMsgI18N.cpp \ + nsMsgAttachmentHandler.cpp \ + nsMsgPrompts.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff --git a/mailnews/compose/src/makefile.win b/mailnews/compose/src/makefile.win index 5d71970590a7..e5afc3999f51 100644 --- a/mailnews/compose/src/makefile.win +++ b/mailnews/compose/src/makefile.win @@ -27,10 +27,13 @@ include <$(DEPTH)\config\config.mak> EXPORTS= nsSmtpUrl.h \ nsSmtpProtocol.h \ - nsSmtpService.h \ - nsComposeAppCore.h \ - nsComposer.h \ - nsMsgCompPrefs.h \ + nsSmtpService.h \ + nsComposeAppCore.h \ + nsComposer.h \ + nsMsgCompPrefs.h \ + nsMsgZapIt.h \ + nsMsgCreate.h \ + nsMsgSendLater.h \ $(NULL) ################################################################################ @@ -44,18 +47,28 @@ LCFLAGS = \ $(NULL) CPP_OBJS= .\$(OBJDIR)\nsMsgCompFields.obj \ - .\$(OBJDIR)\nsMsgCompose.obj \ .\$(OBJDIR)\nsSmtpUrl.obj \ .\$(OBJDIR)\MsgCompGlue.obj \ - .\$(OBJDIR)\nsSmtpProtocol.obj \ - .\$(OBJDIR)\nsMsgSend.obj \ - .\$(OBJDIR)\nsMsgSendPart.obj \ - .\$(OBJDIR)\nsSmtpService.obj \ - .\$(OBJDIR)\nsJSComposeAppCore.obj \ - .\$(OBJDIR)\nsComposeAppCore.obj \ - .\$(OBJDIR)\nsComposer.obj \ - .\$(OBJDIR)\nsComposerNameSet.obj \ - .\$(OBJDIR)\nsMsgCompPrefs.obj \ + .\$(OBJDIR)\nsSmtpProtocol.obj \ + .\$(OBJDIR)\nsMsgSend.obj \ + .\$(OBJDIR)\nsMsgSendPart.obj \ + .\$(OBJDIR)\nsSmtpService.obj \ + .\$(OBJDIR)\nsJSComposeAppCore.obj \ + .\$(OBJDIR)\nsComposeAppCore.obj \ + .\$(OBJDIR)\nsComposer.obj \ + .\$(OBJDIR)\nsComposerNameSet.obj \ + .\$(OBJDIR)\nsMsgCompPrefs.obj \ + .\$(OBJDIR)\nsMsgZapIt.obj \ + .\$(OBJDIR)\nsMsgCreate.obj \ + .\$(OBJDIR)\nsMsgCopy.obj \ + .\$(OBJDIR)\nsMsgSendLater.obj \ + .\$(OBJDIR)\nsMsgDeliveryListener.obj \ + .\$(OBJDIR)\nsMsgComposeStringBundle.obj \ + .\$(OBJDIR)\nsMsgEncoders.obj \ + .\$(OBJDIR)\nsMsgUtils.obj \ + .\$(OBJDIR)\nsMsgI18N.obj \ + .\$(OBJDIR)\nsMsgAttachmentHandler.obj \ + .\$(OBJDIR)\nsMsgPrompts.obj \ $(NULL) diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp new file mode 100644 index 000000000000..59085ba145ae --- /dev/null +++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -0,0 +1,756 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsMsgCopy.h" +#include "nsIPref.h" +#include "nsMsgCompPrefs.h" +#include "nsMsgAttachmentHandler.h" +#include "nsMsgSend.h" +#include "nsMsgUtils.h" +#include "nsIPref.h" +#include "nsMsgCompose.h" +#include "nsMsgEncoders.h" +#include "nsMsgI18N.h" + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); + +nsMsgAttachmentHandler::nsMsgAttachmentHandler() +{ + m_url_string = NULL; + m_url = NULL; + m_done = PR_FALSE; + m_type = NULL; + m_charset = NULL; + m_override_type = NULL; + m_override_encoding = NULL; + m_desired_type = NULL; + m_description = NULL; + m_x_mac_type = NULL; + m_x_mac_creator = NULL; + m_encoding = NULL; + m_real_name = NULL; + m_mime_delivery_state = NULL; + m_encoding = NULL; + m_already_encoded_p = PR_FALSE; + m_file_name = NULL; + m_file = 0; +#ifdef XP_MAC + m_ap_filename = NULL; +#endif + m_decrypted_p = PR_FALSE; + m_size = 0; + m_unprintable_count = 0; + m_highbit_count = 0; + m_ctl_count = 0; + m_null_count = 0; + m_current_column = 0; + m_max_column = 0; + m_lines = 0; + + m_encoder_data = NULL; + + m_graph_progress_started = PR_FALSE; +} + +nsMsgAttachmentHandler::~nsMsgAttachmentHandler() +{ +} + + +PRBool nsMsgAttachmentHandler::UseUUEncode_p(void) +{ +printf("RICHIE: commenting out GetCompBoolHeader() call for now...\n"); + PRBool returnVal = (m_mime_delivery_state) && + (m_mime_delivery_state->m_pane) + && + PR_FALSE; + +// ((nsMsgCompose*)(m_mime_delivery_state->m_pane))-> +// GetCompBoolHeader(MSG_UUENCODE_BINARY_BOOL_HEADER_MASK); + + return returnVal; +} + +static void +msg_escape_file_name (URL_Struct *m_url) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + (void)prefs; + + NS_ASSERTION (m_url->address && !PL_strncasecmp(m_url->address, "file:", 5), "Invalid URL type"); + if (!m_url->address || PL_strncasecmp(m_url->address, "file:", 5)) + return; + + char * new_address = nsEscape(PL_strchr(m_url->address, ':') + 1, url_Path); + NS_ASSERTION(new_address, "null ptr"); + if (!new_address) + return; + + PR_FREEIF(m_url->address); + m_url->address = PR_smprintf("file:%s", new_address); + PR_FREEIF(new_address); +} + +PRInt32 +nsMsgAttachmentHandler::SnarfAttachment () +{ + PRInt32 status = 0; + NS_ASSERTION (! m_done, "Already done"); + + m_file_name = nsMsgCreateTempFileName("nsmail.tmp"); + if (! m_file_name) + return (MK_OUT_OF_MEMORY); + + m_file = PR_Open (m_file_name, PR_CREATE_FILE | PR_RDWR, 493); + if (! m_file) + return MK_UNABLE_TO_OPEN_TMP_FILE; /* #### how do we pass file name? */ + + m_url->fe_data = this; + + /* #### m_type is still unknown at this point. + We *really* need to find a way to make the textfe not blow + up on documents that are not text/html!! + */ + +#ifdef XP_MAC + if (NET_IsLocalFileURL(m_url->address) && // do we need to add IMAP: to this list? NET_IsLocalFileURL returns PR_FALSE always for IMAP - DMB + (PL_strncasecmp(m_url->address, "mailbox:", 8) != 0)) + { + /* convert the apple file to AppleDouble first, and then patch the + address in the url. + */ + char* src_filename = NET_GetLocalFileFromURL (m_url->address); + + // ### mwelch Only use appledouble if we aren't uuencoding. + if(/*JFD isMacFile(src_filename) && */ (! UseUUEncode_p())) + { + + char *separator, tmp[128]; + NET_StreamClass *ad_encode_stream; + + separator = mime_make_separator("ad"); + if (!separator) + return MK_OUT_OF_MEMORY; + + m_ap_filename = nsMsgCreateTempFileName("nsmail.tmp"); + ad_encode_stream = (NET_StreamClass *) /* need a prototype */ +NULL; /* JFD fe_MakeAppleDoubleEncodeStream (FO_CACHE_AND_MAIL_TO, + (void*)NULL, + m_url, + m_mime_delivery_state->GetContext(), + src_filename, + m_ap_filename, + separator, + m_real_name); +JFD */ + + if (ad_encode_stream == NULL) + { + PR_FREEIF(separator); + return MK_OUT_OF_MEMORY; + } + + do { + status = (*ad_encode_stream->put_block) + ((NET_StreamClass *)ad_encode_stream->data_object, NULL, 1024); + } while (status == noErr); + + if (status >= 0) + ad_encode_stream->complete ((NET_StreamClass *)ad_encode_stream->data_object); + else + ad_encode_stream->abort ((NET_StreamClass *)ad_encode_stream->data_object, status); + + PR_Free(ad_encode_stream); + + if (status < 0) + { + PR_FREEIF(separator); + return status; + } + + PR_Free(m_url->address); + { + char * temp = WH_FileName(m_ap_filename, xpFileToPost ); + m_url->address = XP_PlatformFileToURL(temp); // jrm 97/02/08 + if (temp) + PR_Free(temp); + } + /* and also patch the types. + */ + + PR_snprintf(tmp, sizeof(tmp),, MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", + separator); + + PR_FREEIF(separator); + + PR_FREEIF (m_type); + m_type = PL_strdup(tmp); + } + else + { +//JFD if (isMacFile(src_filename)) + { + // The only time we want to send just the data fork of a two-fork + // Mac file is if uuencoding has been requested. + NS_ASSERTION(UseUUEncode_p(), "not UseUUEncode_p"); + if (!((nsMsgCompose *) m_mime_delivery_state->m_pane)->m_confirmed_uuencode_p) + { +#ifdef UNREADY_CODE + PRBool confirmed = FE_Confirm(m_mime_delivery_state->m_pane->GetContext(), + XP_GetString(MK_MSG_MAC_PROMPT_UUENCODE)); +#else + PRBool confirmed = PR_TRUE; +#endif + + // only want to do this once + ((nsMsgCompose *) m_mime_delivery_state->m_pane)->m_confirmed_uuencode_p = PR_TRUE; + + if (! confirmed) // cancelled + return MK_INTERRUPTED; + } + } + /* make sure the file type and create are set. */ + char filetype[32]; + FSSpec fsSpec; + FInfo info; + Bool useDefault; + char *macType, *macEncoding; + +/*JFD + my_FSSpecFromPathname(src_filename, &fsSpec); +*/ + if (FSpGetFInfo (&fsSpec, &info) == noErr) + { + PR_snprintf(filetype, sizeof(filetype), "%X", info.fdType); + PR_FREEIF(m_x_mac_type); + m_x_mac_type = PL_strdup(filetype); + + PR_snprintf(filetype, sizeof(filetype), "%X", info.fdCreator); + PR_FREEIF(m_x_mac_creator); + m_x_mac_creator = PL_strdup(filetype); + if (m_type == NULL || + !PL_strcasecmp (m_type, TEXT_PLAIN)) + { +# define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */ +# define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */ + + if (info.fdType != TEXT_TYPE && info.fdType != text_TYPE) + { +/*JFD + FE_FileType(m_url->address, &useDefault, + &macType, &macEncoding); +*/ + + PR_FREEIF(m_type); + m_type = macType; + } + } + } + + /* don't bother to set the types if we failed in getting the file + info. */ + } + PR_FREEIF(src_filename); + src_filename = 0; + } +#else + + /* if we are attaching a local file make sure the file name are escaped + * properly + */ + if (NET_IsLocalFileURL(m_url->address) && + PL_strncasecmp (m_url->address, "file:", 5) == 0) + { + msg_escape_file_name(m_url); + } + +#endif /* XP_MAC */ + + if (m_desired_type && + !PL_strcasecmp (m_desired_type, TEXT_PLAIN) ) + { + /* Conversion to plain text desired. + */ +/*JFD + m_print_setup.url = m_url; + m_print_setup.carg = this; + m_print_setup.completion = mime_text_attachment_url_exit; + m_print_setup.filename = NULL; + m_print_setup.out = m_file; + m_print_setup.eol = CRLF; +JFD */ + PRInt32 width = 72; + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetIntPref("mailnews.wraplength", &width); + if (width == 0) width = 72; + else if (width < 10) width = 10; + else if (width > 30000) width = 30000; + + if (m_mime_delivery_state->m_pane->GetPaneType() == MSG_COMPOSITIONPANE) + { + int lineWidth = ((nsMsgCompose *) m_mime_delivery_state->m_pane) + ->GetLineWidth(); + if (lineWidth > width) + width = lineWidth; + } +/*JFD + m_print_setup.width = width; + + m_url->savedData.FormList = 0; +#ifdef _USRDLL + if (! NDLLXL_TranslateText (m_mime_delivery_state->GetContext(), m_url, + &m_print_setup)) + return MK_ATTACHMENT_LOAD_FAILED; +#else + if (! XL_TranslateText (m_mime_delivery_state->GetContext(), m_url, + &m_print_setup)) + return MK_ATTACHMENT_LOAD_FAILED; +#endif +JFD */ + if (m_type) PR_Free (m_type); + m_type = m_desired_type; + m_desired_type = 0; + if (m_encoding) PR_Free (m_encoding); + m_encoding = 0; + } +/* this used to be XP_UNIX? */ +#if 0 + else if (m_desired_type && + !PL_strcasecmp (m_desired_type, APPLICATION_POSTSCRIPT) ) + { + SHIST_SavedData saved_data; + + /* Make sure layout saves the current state of form elements. */ + LO_SaveFormData(m_mime_delivery_state->GetContext()); + + /* Hold on to the saved data. */ + memcpy(&saved_data, &m_url->savedData, sizeof(SHIST_SavedData)); + + /* Conversion to postscript desired. + */ +/*JFD + XFE_InitializePrintSetup (&m_print_setup); + m_print_setup.url = m_url; + m_print_setup.carg = this; + m_print_setup.completion = mime_text_attachment_url_exit; + m_print_setup.filename = NULL; + m_print_setup.out = m_file; + m_print_setup.eol = CRLF; + memset (&m_url->savedData, 0, sizeof (SHIST_SavedData)); + XL_TranslatePostscript (m_mime_delivery_state->GetContext(), + m_url, &saved_data, + &m_print_setup); +JFD*/ + if (m_type) PR_Free (m_type); + m_type = m_desired_type; + m_desired_type = 0; + if (m_encoding) PR_Free (m_encoding); + m_encoding = 0; + } +#endif /* XP_UNIX */ + else + { + m_url->allow_content_change = PR_FALSE; // don't use modified content + + if (NET_URL_Type (m_url->address) == NEWS_TYPE_URL && !m_url->msg_pane) + m_url->msg_pane = m_mime_delivery_state->m_pane; + +/*JFD + MSG_UrlQueue::AddUrlToPane(m_url, mime_attachment_url_exit, + m_mime_delivery_state->m_pane, PR_TRUE, + FO_CACHE_AND_MAIL_TO); +JFD*/ + return 0; + } + return status; +} + +void nsMsgAttachmentHandler::UrlExit(URL_Struct *url, int status, + MWContext *context) +{ + char *error_msg = url->error_msg; + url->error_msg = 0; + url->fe_data = 0; + + NS_ASSERTION(m_mime_delivery_state != NULL, "not-null m_mime_delivery_state"); + NS_ASSERTION(m_mime_delivery_state->GetContext() != NULL, "not-null context"); + NS_ASSERTION(m_url != NULL, "not-null m_url"); + + if (m_graph_progress_started) + { + m_graph_progress_started = PR_FALSE; + FE_GraphProgressDestroy (m_mime_delivery_state->GetContext(), m_url, + m_url->content_length, m_size); + } + + if (status < 0) + /* If any of the attachment URLs fail, kill them all. */ + NET_InterruptWindow (context); + + /* Close the file, but don't delete it (or the file name.) */ + PR_Close (m_file); + m_file = 0; + NET_FreeURLStruct (m_url); + /* I'm pretty sure m_url == url */ + m_url = 0; + url = 0; + + + + if (status < 0) { + if (m_mime_delivery_state->m_status >= 0) + m_mime_delivery_state->m_status = status; + PR_Delete(m_file_name); + PR_FREEIF(m_file_name); + } + + m_done = PR_TRUE; + + NS_ASSERTION (m_mime_delivery_state->m_attachment_pending_count > 0, "no more pending attachment"); + m_mime_delivery_state->m_attachment_pending_count--; + + if (status >= 0 && m_mime_delivery_state->m_be_synchronous_p) + { + /* Find the next attachment which has not yet been loaded, + if any, and start it going. + */ + PRInt32 i; + nsMsgAttachmentHandler *next = 0; + for (i = 0; i < m_mime_delivery_state->m_attachment_count; i++) + if (!m_mime_delivery_state->m_attachments[i].m_done) + { + next = &m_mime_delivery_state->m_attachments[i]; + break; + } + if (next) + { + int status = next->SnarfAttachment (); + if (status < 0) + { + m_mime_delivery_state->Fail(status, 0); + return; + } + } + } + + if (m_mime_delivery_state->m_attachment_pending_count == 0) + { + /* If this is the last attachment, then either complete the + delivery (if successful) or report the error by calling + the exit routine and terminating the delivery. + */ + if (status < 0) + { + m_mime_delivery_state->Fail(status, error_msg); + error_msg = 0; + } + else + { + m_mime_delivery_state->GatherMimeAttachments (); + } + } + else + { + /* If this is not the last attachment, but it got an error, + then report that error and continue (we won't actually + abort the delivery until all the other pending URLs have + caught up with the NET_InterruptWindow() we did up above.) + if (status < 0 && error_msg) + FE_Alert (context, error_msg); + */ + + if (status < 0) + { + m_mime_delivery_state->Fail(status, error_msg); + error_msg = 0; + } + } + PR_FREEIF (error_msg); +} + +void +nsMsgAttachmentHandler::AnalyzeDataChunk(const char *chunk, PRInt32 length) +{ + unsigned char *s = (unsigned char *) chunk; + unsigned char *end = s + length; + for (; s < end; s++) + { + if (*s > 126) + { + m_highbit_count++; + m_unprintable_count++; + } + else if (*s < ' ' && *s != '\t' && *s != CR && *s != LF) + { + m_unprintable_count++; + m_ctl_count++; + if (*s == 0) + m_null_count++; + } + + if (*s == CR || *s == LF) + { + if (s+1 < end && s[0] == CR && s[1] == LF) + s++; + if (m_max_column < m_current_column) + m_max_column = m_current_column; + m_current_column = 0; + m_lines++; + } + else + { + m_current_column++; + } + } +} + +void +nsMsgAttachmentHandler::AnalyzeSnarfedFile(void) +{ + char chunk[256]; + PRFileDesc *fileHdl = NULL; + PRInt32 numRead = 0; + + if (m_file_name && *m_file_name) + { + fileHdl = PR_Open(m_file_name, PR_RDONLY, 0); + if (fileHdl) + { + do + { + numRead = PR_Read(fileHdl, chunk, 256); + if (numRead > 0) + AnalyzeDataChunk(chunk, numRead); + } + while (numRead > 0); + PR_Close(fileHdl); + } + } +} + +/* Given a content-type and some info about the contents of the document, + decide what encoding it should have. + */ +int +nsMsgAttachmentHandler::PickEncoding (const char *charset) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + // use the boolean so we only have to test for uuencode vs base64 once + PRBool needsB64 = PR_FALSE; + PRBool forceB64 = PR_FALSE; + + if (m_already_encoded_p) + goto DONE; + + /* Allow users to override our percentage-wise guess on whether + the file is text or binary */ + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetBoolPref ("mail.file_attach_binary", &forceB64); + + if (forceB64 || mime_type_requires_b64_p (m_type)) + { + /* If the content-type is "image/" or something else known to be binary, + always use base64 (so that we don't get confused by newline + conversions.) + */ + needsB64 = PR_TRUE; + } + else + { + /* Otherwise, we need to pick an encoding based on the contents of + the document. + */ + + PRBool encode_p; + + if (m_max_column > 900) + encode_p = PR_TRUE; + else if (UseQuotedPrintable() && m_unprintable_count) + encode_p = PR_TRUE; + + else if (m_null_count) /* If there are nulls, we must always encode, + because sendmail will blow up. */ + encode_p = PR_TRUE; +#if 0 + else if (m_ctl_count) /* Should we encode if random other control + characters are present? Probably... */ + encode_p = PR_TRUE; +#endif + else + encode_p = PR_FALSE; + + /* MIME requires a special case that these types never be encoded. + */ + if (!PL_strncasecmp (m_type, "message", 7) || + !PL_strncasecmp (m_type, "multipart", 9)) + { + encode_p = PR_FALSE; + if (m_desired_type && !PL_strcasecmp (m_desired_type, TEXT_PLAIN)) + { + PR_Free (m_desired_type); + m_desired_type = 0; + } + } + /* If the Mail charset is ISO_2022_JP we force it to use Base64 for attachments (bug#104255). + Use 7 bit for other STATFUL charsets ( e.g. ISO_2022_KR). */ + if ((PL_strcasecmp(charset, "iso-2022-jp") == 0) && + (PL_strcasecmp(m_type, TEXT_HTML) == 0)) + needsB64 = PR_TRUE; + else if((nsMsgI18Nstateful_charset(charset)) && + ((PL_strcasecmp(m_type, TEXT_HTML) == 0) || + (PL_strcasecmp(m_type, TEXT_MDL) == 0) || + (PL_strcasecmp(m_type, TEXT_PLAIN) == 0) || + (PL_strcasecmp(m_type, TEXT_RICHTEXT) == 0) || + (PL_strcasecmp(m_type, TEXT_ENRICHED) == 0) || + (PL_strcasecmp(m_type, TEXT_VCARD) == 0) || + (PL_strcasecmp(m_type, APPLICATION_DIRECTORY) == 0) || /* text/x-vcard synonym */ + (PL_strcasecmp(m_type, TEXT_CSS) == 0) || + (PL_strcasecmp(m_type, TEXT_JSSS) == 0) || + (PL_strcasecmp(m_type, MESSAGE_RFC822) == 0) || + (PL_strcasecmp(m_type, MESSAGE_NEWS) == 0))) + { + PR_FREEIF(m_encoding); + m_encoding = PL_strdup (ENCODING_7BIT); + } + else if (encode_p && + m_size > 500 && + m_unprintable_count > (m_size / 10)) + /* If the document contains more than 10% unprintable characters, + then that seems like a good candidate for base64 instead of + quoted-printable. + */ + needsB64 = PR_TRUE; + else if (encode_p) { + PR_FREEIF(m_encoding); + m_encoding = PL_strdup (ENCODING_QUOTED_PRINTABLE); + } + else if (m_highbit_count > 0) { + PR_FREEIF(m_encoding); + m_encoding = PL_strdup (ENCODING_8BIT); + } + else { + PR_FREEIF(m_encoding); + m_encoding = PL_strdup (ENCODING_7BIT); + } + } + + if (needsB64) + { + /* + ### mwelch We might have to uuencode instead of + base64 the binary data. + */ + PR_FREEIF(m_encoding); + if (UseUUEncode_p()) + m_encoding = PL_strdup (ENCODING_UUENCODE); + else + m_encoding = PL_strdup (ENCODING_BASE64); + } + + /* Now that we've picked an encoding, initialize the filter. + */ + NS_ASSERTION(!m_encoder_data, "not-null m_encoder_data"); + if (!PL_strcasecmp(m_encoding, ENCODING_BASE64)) + { + m_encoder_data = MIME_B64EncoderInit(mime_encoder_output_fn, + m_mime_delivery_state); + if (!m_encoder_data) return MK_OUT_OF_MEMORY; + } + else if (!PL_strcasecmp(m_encoding, ENCODING_UUENCODE)) + { + char *tailName = NULL; + + if (m_url_string) + { + tailName = PL_strrchr(m_url_string, '/'); + if (tailName) { + char * tmp = tailName; + tailName = PL_strdup(tailName+1); + PR_FREEIF(tmp); + } + } + + if (m_url && !tailName) + { + tailName = PL_strrchr(m_url->address, '/'); + if (tailName) { + char * tmp = tailName; + tailName = PL_strdup(tailName+1); + PR_FREEIF(tmp); + } + } + + m_encoder_data = MIME_UUEncoderInit((char *)(tailName ? tailName : ""), + mime_encoder_output_fn, + m_mime_delivery_state); + PR_FREEIF(tailName); + if (!m_encoder_data) return MK_OUT_OF_MEMORY; + } + else if (!PL_strcasecmp(m_encoding, ENCODING_QUOTED_PRINTABLE)) + { + m_encoder_data = MIME_QPEncoderInit(mime_encoder_output_fn, + m_mime_delivery_state); + if (!m_encoder_data) return MK_OUT_OF_MEMORY; + } + else + { + m_encoder_data = 0; + } + + + /* Do some cleanup for documents with unknown content type. + + There are two issues: how they look to MIME users, and how they look to + non-MIME users. + + If the user attaches a "README" file, which has unknown type because it + has no extension, we still need to send it with no encoding, so that it + is readable to non-MIME users. + + But if the user attaches some random binary file, then base64 encoding + will have been chosen for it (above), and in this case, it won't be + immediately readable by non-MIME users. However, if we type it as + text/plain instead of application/octet-stream, it will show up inline + in a MIME viewer, which will probably be ugly, and may possibly have + bad charset things happen as well. + + So, the heuristic we use is, if the type is unknown, then the type is + set to application/octet-stream for data which needs base64 (binary data) + and is set to text/plain for data which didn't need base64 (unencoded or + lightly encoded data.) + */ + DONE: + if (!m_type || !*m_type || !PL_strcasecmp(m_type, UNKNOWN_CONTENT_TYPE)) + { + PR_FREEIF(m_type); + if (m_already_encoded_p) + m_type = PL_strdup (APPLICATION_OCTET_STREAM); + else if (m_encoding && + (!PL_strcasecmp(m_encoding, ENCODING_BASE64) || + !PL_strcasecmp(m_encoding, ENCODING_UUENCODE))) + m_type = PL_strdup (APPLICATION_OCTET_STREAM); + else + m_type = PL_strdup (TEXT_PLAIN); + } + return 0; +} + diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h new file mode 100644 index 000000000000..046745567b8a --- /dev/null +++ b/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgAttachment_H_ +#define _nsMsgAttachment_H_ + +#include "net.h" +#include "nsIMimeConverter.h" + + +class nsMsgComposeAndSend; + +class nsMsgAttachmentHandler +{ +public: + + nsMsgAttachmentHandler(); + ~nsMsgAttachmentHandler(); + + void UrlExit(URL_Struct *url, int status, MWContext *context); + PRInt32 SnarfAttachment (); + void AnalyzeDataChunk (const char *chunk, PRInt32 chunkSize); + void AnalyzeSnarfedFile (); /* Analyze a previously-snarfed file. + (Currently only used for plaintext + converted from HTML.) */ + int PickEncoding (const char *charset); + + PRBool UseUUEncode_p(void); + + char *m_url_string; + URL_Struct *m_url; + PRBool m_done; + + nsMsgComposeAndSend *m_mime_delivery_state; + + char *m_charset; /* charset name */ + char *m_type; /* The real type, once we know it. */ + char *m_override_type; /* The type we should assume it to be + or 0, if we should get it from the + URL_Struct (from the server) */ + char *m_override_encoding; /* Goes along with override_type */ + + char *m_desired_type; /* The type it should be converted to. */ + char *m_description; /* For Content-Description header */ + char *m_x_mac_type, *m_x_mac_creator; /* Mac file type/creator. */ + char *m_real_name; /* The name for the headers, if different + from the URL. */ + char *m_encoding; /* The encoding, once we've decided. */ + PRBool m_already_encoded_p; /* If we attach a document that is already + encoded, we just pass it through. */ + + char *m_file_name; /* The temp file to which we save it */ + PRFileDesc *m_file; + +#ifdef XP_MAC + char *m_ap_filename; /* The temp file holds the appledouble + encoding of the file we want to post. */ +#endif + + PRBool 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. + */ + PRUint32 m_size; /* Some state used while filtering it */ + PRUint32 m_unprintable_count; + PRUint32 m_highbit_count; + PRUint32 m_ctl_count; + PRUint32 m_null_count; + PRUint32 m_current_column; + PRUint32 m_max_column; + PRUint32 m_lines; + + MimeEncoderData *m_encoder_data; /* Opaque state for base64/qp encoder. */ + + PRBool m_graph_progress_started; +}; + + +#endif /* _nsMsgAttachment_H_ */ diff --git a/mailnews/compose/src/nsMsgComposeStringBundle.cpp b/mailnews/compose/src/nsMsgComposeStringBundle.cpp new file mode 100644 index 000000000000..81bdda946611 --- /dev/null +++ b/mailnews/compose/src/nsMsgComposeStringBundle.cpp @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "prprf.h" +#include "prmem.h" +#include "nsCOMPtr.h" +#include "nsINetService.h" +#include "nsIStringBundle.h" +#include "nsMsgComposeStringBundle.h" +#include "nsIServiceManager.h" +#include "nsIPref.h" + +/* This is the next generation string retrieval call */ +static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID); +static NS_DEFINE_CID(kNetServiceCID, NS_NETSERVICE_CID); +static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID); +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); + +#define COMPOSE_BE_URL "resource:/res/mailnews/messenger/compose_be.properties" + +extern "C" +char * +ComposeBEGetStringByIDREAL(PRInt32 stringID) +{ + nsresult res; + char* propertyURL = NULL; + + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &res); + if (NS_SUCCEEDED(res) && prefs) + res = prefs->CopyCharPref("mail.strings.compose_be", &propertyURL); + + if (!NS_SUCCEEDED(res) || !prefs) + propertyURL = COMPOSE_BE_URL; + + NS_WITH_SERVICE(nsINetService, pNetService, kNetServiceCID, &res); + if (!NS_SUCCEEDED(res) || (nsnull == pNetService)) + { + return PL_strdup("???"); // Don't I18N this string...failsafe return value + } + + NS_WITH_SERVICE(nsIStringBundleService, sBundleService, kStringBundleServiceCID, &res); + if (NS_SUCCEEDED(res) && (nsnull != sBundleService)) + { + nsIURL *url = nsnull; + nsILocale *locale = nsnull; + + res = pNetService->CreateURL(&url, nsString(propertyURL), nsnull, nsnull, nsnull); + // cleanup...if necessary + if (propertyURL != COMPOSE_BE_URL) + PR_FREEIF(propertyURL); + + // Cleanup property URL + PR_FREEIF(propertyURL); + + if (NS_FAILED(res)) + { + return PL_strdup("???"); // Don't I18N this string...failsafe return value + } + + nsIStringBundle* sBundle = nsnull; + res = sBundleService->CreateBundle(url, locale, &sBundle); + if (NS_FAILED(res)) + { + return PL_strdup("???"); // Don't I18N this string...failsafe return value + } + + nsAutoString v(""); + res = sBundle->GetStringFromID(stringID, v); + if (NS_FAILED(res)) + { + char buf[128]; + + PR_snprintf(buf, sizeof(buf), "[StringID %d?]", stringID); + return PL_strdup(buf); + } + + // Here we need to return a new copy of the string + char *returnBuffer = NULL; + PRInt32 bufferLen = v.Length() + 1; + + returnBuffer = (char *)PR_MALLOC(bufferLen); + if (returnBuffer) + { + v.ToCString(returnBuffer, bufferLen); + return returnBuffer; + } + } + + return PL_strdup("???"); // Don't I18N this string...failsafe return value +} + +extern "C" +char * +ComposeBEGetStringByID(PRInt32 stringID) +{ + if (-1000 == stringID) return PL_strdup("Application is out of memory."); + if (-1001 == stringID) return PL_strdup("Unable to open the temporary file\n.\n%s\nCheck your `Temporary Directory' setting and try again."); + if (-1002 == stringID) return PL_strdup("Error writing temporary file."); + if (1000 == stringID) return PL_strdup("Subject"); + if (1001 == stringID) return PL_strdup("Resent-Comments"); + if (1002 == stringID) return PL_strdup("Resent-Date"); + if (1003 == stringID) return PL_strdup("Resent-Sender"); + if (1004 == stringID) return PL_strdup("Resent-From"); + if (1005 == stringID) return PL_strdup("Resent-To"); + if (1006 == stringID) return PL_strdup("Resent-CC"); + if (1007 == stringID) return PL_strdup("Date"); + if (1008 == stringID) return PL_strdup("Sender"); + if (1009 == stringID) return PL_strdup("From"); + if (1010 == stringID) return PL_strdup("Reply-To"); + if (1011 == stringID) return PL_strdup("Organization"); + if (1012 == stringID) return PL_strdup("To"); + if (1013 == stringID) return PL_strdup("CC"); + if (1014 == stringID) return PL_strdup("Newsgroups"); + if (1015 == stringID) return PL_strdup("Followup-To"); + if (1016 == stringID) return PL_strdup("References"); + if (1017 == stringID) return PL_strdup("Name"); + if (1018 == stringID) return PL_strdup("Type"); + if (1019 == stringID) return PL_strdup("Encoding"); + if (1020 == stringID) return PL_strdup("Description"); + if (1021 == stringID) return PL_strdup("Message-ID"); + if (1022 == stringID) return PL_strdup("Resent-Message-ID"); + if (1023 == stringID) return PL_strdup("BCC"); + if (1024 == stringID) return PL_strdup("Download Status"); + if (1025 == stringID) return PL_strdup("Not Downloaded Inline"); + if (1026 == stringID) return PL_strdup("Link to Document"); + if (1027 == stringID) return PL_strdup("Document Info:"); + if (1028 == stringID) return PL_strdup("Attachment"); + if (1029 == stringID) return PL_strdup("forward.msg"); + if (1030 == stringID) return PL_strdup("Add %s to your Address Book"); + if (1031 == stringID) return PL_strdup("      Internal"); + if (1032 == stringID) return PL_strdup("In message wrote:

"); + if (1033 == stringID) return PL_strdup(" wrote:

"); + if (1034 == stringID) return PL_strdup("(no headers)"); + if (1035 == stringID) return PL_strdup("Toggle Attachment Pane"); + + char buf[128]; + + PR_snprintf(buf, sizeof(buf), "[StringID %d?]", stringID); + return PL_strdup(buf); +} diff --git a/mailnews/compose/src/nsMsgComposeStringBundle.h b/mailnews/compose/src/nsMsgComposeStringBundle.h new file mode 100644 index 000000000000..e3a03eba2de1 --- /dev/null +++ b/mailnews/compose/src/nsMsgComposeStringBundle.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgComposeStringBundle_H_ +#define _nsMsgComposeStringBundle_H_ + +#include "nscore.h" + +NS_BEGIN_EXTERN_C + +char *ComposeBEGetStringByID(PRInt32 stringID); + +NS_END_EXTERN_C + +#endif /* _nsMsgComposeStringBundle_H_ */ diff --git a/mailnews/compose/src/nsMsgCopy.cpp b/mailnews/compose/src/nsMsgCopy.cpp new file mode 100644 index 000000000000..54c93dc701a0 --- /dev/null +++ b/mailnews/compose/src/nsMsgCopy.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsMsgCopy.h" +#include "nsIPref.h" +#include "nsMsgCompPrefs.h" +#include "nsMsgCopy.h" + +//#include "nsCopyMessageStreamListener.h" +#include "nsICopyMessageListener.h" + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); + +/*** +nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + nsMsgCompPrefs pCompPrefs; + char* result = NULL; + PRBool useBcc, mailBccSelf, newsBccSelf = PR_FALSE; + + if (newsBcc) + { + if (NS_SUCCEEDED(rv) && prefs) + { + prefs->GetBoolPref("news.use_default_cc", &useBcc); + } +****/ + +/************* + +nsresult +CopyFileToFolder() +{ + NS_IMETHODIMP +nsMsgAppCore::CopyMessages(nsIDOMXULElement *srcFolderElement, nsIDOMXULElement *dstFolderElement, + nsIDOMNodeList *nodeList, PRBool isMove) + nsresult rv; + + if(!srcFolderElement || !dstFolderElement || !nodeList) + return NS_ERROR_NULL_POINTER; + + nsIRDFResource *srcResource, *dstResource; + nsICopyMessageListener *dstFolder; + nsIMsgFolder *srcFolder; + nsISupportsArray *resourceArray; + + if(NS_FAILED(rv = dstFolderElement->GetResource(&dstResource))) + return rv; + + if(NS_FAILED(rv = dstResource->QueryInterface(nsICopyMessageListener::GetIID(), (void**)&dstFolder))) + return rv; + + if(NS_FAILED(rv = srcFolderElement->GetResource(&srcResource))) + return rv; + + if(NS_FAILED(rv = srcResource->QueryInterface(nsIMsgFolder::GetIID(), (void**)&srcFolder))) + return rv; + + if(NS_FAILED(rv =ConvertDOMListToResourceArray(nodeList, &resourceArray))) + return rv; + + //Call the mailbox service to copy first message. In the future we should call CopyMessages. + //And even more in the future we need to distinguish between the different types of URI's, i.e. + //local, imap, and news, and call the appropriate copy function. + + PRUint32 cnt; + rv = resourceArray->Count(&cnt); + if (NS_SUCCEEDED(rv) && cnt > 0) + { + nsIRDFResource * firstMessage = (nsIRDFResource*)resourceArray->ElementAt(0); + char *uri; + firstMessage->GetValue(&uri); + nsCopyMessageStreamListener* copyStreamListener = new nsCopyMessageStreamListener(srcFolder, dstFolder, nsnull); + + nsIMsgMessageService * messageService = nsnull; + rv = GetMessageServiceFromURI(uri, &messageService); + + if (NS_SUCCEEDED(rv) && messageService) + { + nsIURL * url = nsnull; + messageService->CopyMessage(uri, copyStreamListener, isMove, nsnull, &url); + ReleaseMessageServiceFromURI(uri, messageService); + } + + } + + NS_RELEASE(srcResource); + NS_RELEASE(srcFolder); + NS_RELEASE(dstResource); + NS_RELEASE(dstFolder); + NS_RELEASE(resourceArray); + return rv; +} + +FindFolderWithFlag +nsIMsgHeader + +identity +server (nsIMsgIncommingServer) +folder (nsIMsgFolder) +GetFolderWithFlags() - nsMsgFolderFlags.h (public) + +GetMessages() on folder + +nsIMessages returned +get URI, key, header (nsIMsgHdr - ) +get message key + +nsMsg + +get POP service - extract from Berkely mail folder + +nsIPop3Service + + +smtptest.cpp - setup as a url listener + +********/ diff --git a/mailnews/compose/src/nsMsgCopy.h b/mailnews/compose/src/nsMsgCopy.h new file mode 100644 index 000000000000..69e645d8fba9 --- /dev/null +++ b/mailnews/compose/src/nsMsgCopy.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgCopy_H_ +#define _nsMsgCopy_H_ + + + + +#endif /* _nsMsgCopy_H_ */ diff --git a/mailnews/compose/src/nsMsgCreate.cpp b/mailnews/compose/src/nsMsgCreate.cpp new file mode 100644 index 000000000000..488c96508043 --- /dev/null +++ b/mailnews/compose/src/nsMsgCreate.cpp @@ -0,0 +1,746 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "rosetta_mailnews.h" +#include "nsMsgSend.h" +#include "nsMsgSendPart.h" +#include "nsIPref.h" +#include "nsMsgCompPrefs.h" +#include "nsMsgCreate.h" + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); + + +static void +msg_delete_attached_files(struct nsMsgAttachedFile *attachments) +{ + struct nsMsgAttachedFile *tmp; + if (!attachments) return; + for (tmp = attachments; tmp->orig_url; tmp++) { + PR_FREEIF(tmp->orig_url); + PR_FREEIF(tmp->type); + PR_FREEIF(tmp->real_name); + PR_FREEIF(tmp->encoding); + PR_FREEIF(tmp->description); + PR_FREEIF(tmp->x_mac_type); + PR_FREEIF(tmp->x_mac_creator); + if (tmp->file_name) { + PR_Delete(tmp->file_name); + PR_Free(tmp->file_name); + } + } + PR_FREEIF(attachments); +} + +/************** + +PRInt32 +CreateVcardAttachment() +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + nsMsgCompPrefs pCompPrefs; + char* name; + int status = 0; + + if (!m_haveAttachedVcard && AB_UserHasVCard() ) // don't attach a vcard if the user does not have a vcard + { + + char * vCard = NULL; + char * filename = NULL; + AB_LoadIdentityVCard(&vCard); + if (vCard) + { + AB_ExportVCardToTempFile (vCard, &filename); + if (vCard) + PR_Free(vCard); // free our allocated VCardString... + char buf [ 2 * kMaxFullNameLength ]; + if (pCompPrefs.GetUserFullName()) + name = PL_strdup (pCompPrefs.GetUserFullName()); + // write out a content description string +#ifdef UNREADY_CODE + PR_snprintf(buf, sizeof(buf), XP_GetString (MK_ADDR_BOOK_CARD), name); +#endif + PR_FREEIF(name); + + + char* temp = WH_FileName(filename, xpFileToPost); + char * fileurl = NULL; + if (temp) + { + fileurl = XP_PlatformFileToURL (temp); + PR_Free(temp); + } + else + return -1; + + // Send the vCard out with a filename which distinguishes this user. e.g. jsmith.vcf + // The main reason to do this is for interop with Eudora, which saves off + // the attachments separately from the message body + char *vCardFileName = NULL; + char *mailIdentityUserEmail = NULL; + char *atSign = NULL; + if (NS_SUCCEEDED(rv) && prefs) + prefs->CopyCharPref("mail.identity.useremail", &mailIdentityUserEmail); + if (mailIdentityUserEmail) + { + atSign = PL_strchr(mailIdentityUserEmail, '@'); + if (atSign) *atSign = 0; + vCardFileName = PR_smprintf ("%s.vcf", mailIdentityUserEmail); + PR_Free(mailIdentityUserEmail); + } + if (!vCardFileName) + { + vCardFileName = PL_strdup("vcard.vcf"); + if (!vCardFileName) + return MK_OUT_OF_MEMORY; + } + + char * origurl = XP_PlatformFileToURL (vCardFileName); + int datacount = 0, filecount = 0; + for (nsMsgAttachmentData *tmp1 = m_attachData; tmp1 && tmp1->url; tmp1++) datacount++; + for (nsMsgAttachedFile *tmp = m_attachedFiles; tmp && tmp->orig_url; tmp++) filecount++; + + nsMsgAttachmentData *alist; + if (datacount) { + alist = (nsMsgAttachmentData *) + PR_REALLOC(m_attachData, (datacount + 2) * sizeof(nsMsgAttachmentData)); + } + else { + alist = (nsMsgAttachmentData *) + PR_Malloc((datacount + 2) * sizeof(nsMsgAttachmentData)); + } + if (!alist) + return MK_OUT_OF_MEMORY; + m_attachData = alist; + memset (m_attachData + datacount, 0, 2 * sizeof (nsMsgAttachmentData)); + m_attachData[datacount].url = fileurl; + m_attachData[datacount].real_type = PL_strdup(vCardMimeFormat); + m_attachData[datacount].description = PL_strdup (buf); + m_attachData[datacount].real_name = PL_strdup (vCardFileName); + m_attachData[datacount + 1].url = NULL; + + nsMsgAttachedFile *aflist; + if (filecount) { + aflist = (struct nsMsgAttachedFile *) + PR_REALLOC(m_attachedFiles, (filecount + 2) * sizeof(nsMsgAttachedFile)); + } + else { + aflist = (struct nsMsgAttachedFile *) + PR_Malloc((filecount + 2) * sizeof(nsMsgAttachedFile)); + } + + if (!aflist) + return MK_OUT_OF_MEMORY; + + m_attachedFiles = aflist; + memset (m_attachedFiles + filecount, 0, 2 * sizeof (nsMsgAttachedFile)); + m_attachedFiles[filecount].orig_url = origurl; + m_attachedFiles[filecount].file_name = filename; + m_attachedFiles[filecount].type = PL_strdup(vCardMimeFormat); + m_attachedFiles[filecount].description = PL_strdup (buf); + m_attachedFiles[filecount].real_name = PL_strdup (vCardFileName); + m_attachedFiles[filecount + 1].orig_url = NULL; + + m_haveAttachedVcard = PR_TRUE; + + PR_Free(vCardFileName); + } + } + return status; +} + + + +char* +FigureBcc(PRBool newsBcc) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + nsMsgCompPrefs pCompPrefs; + char* result = NULL; + PRBool useBcc, mailBccSelf, newsBccSelf = PR_FALSE; + + if (newsBcc) + { + if (NS_SUCCEEDED(rv) && prefs) + { + prefs->GetBoolPref("news.use_default_cc", &useBcc); + } + } + else + { + if (NS_SUCCEEDED(rv) && prefs) + { + prefs->GetBoolPref("mail.use_default_cc", &useBcc); + } + } + + prefs->GetBoolPref("mail.cc_self", &mailBccSelf); + prefs->GetBoolPref("news.cc_self", &newsBccSelf); + + if (useBcc || mailBccSelf || newsBccSelf ) + { + const char* tmp = useBcc ? + GetPrefs()->GetDefaultHeaderContents( + newsBcc ? MSG_NEWS_BCC_HEADER_MASK : MSG_BCC_HEADER_MASK) : NULL; + + if (! (mailBccSelf || newsBccSelf) ) + { + result = PL_strdup(tmp ? tmp : ""); + } + else if (!tmp || !*tmp) + { + result = PL_strdup(pCompPrefs.GetUserEmail()); + } + else + { + result = PR_smprintf("%s, %s", pCompPrefs.GetUserEmail(), tmp); + } + } + return result; +} + +void +InitializeHeaders(MWContext* old_context, const nsIMsgCompFields* fields) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + nsMsgCompPrefs pCompPrefs; + + PR_ASSERT(m_fields == NULL); + PR_ASSERT(m_initfields == NULL); + + const char *real_addr = pCompPrefs.GetUserEmail(); + char *real_return_address; + const char* sig; + PRBool forward_quoted; + forward_quoted = PR_FALSE; + + m_fields = new nsMsgCompFields; + if (!m_fields) + return; + m_fields->AddRef(); + if (fields) + m_fields->Copy((nsIMsgCompFields*)fields); + m_fields->SetOwner(this); + + m_oldContext = old_context; + // hack for forward quoted. Checks the attachment field for a cookie + // string indicating that this is a forward quoted operation. If a cookie + // is found, the attachment string is slid back down over the cookie. This + // will put the original string back in tact. + + const char* attachment = m_fields->GetAttachments(); + + if (attachment && *attachment) { + if (!PL_strncmp(attachment, MSG_FORWARD_COOKIE, + PL_strlen(MSG_FORWARD_COOKIE))) { + attachment += PL_strlen(MSG_FORWARD_COOKIE); + forward_quoted = PR_TRUE; // set forward with quote flag + m_fields->SetAttachments((char *)attachment, NULL); + attachment = m_fields->GetAttachments(); + } + } + + m_status = -1; + + if (MISC_ValidateReturnAddress(old_context, real_addr) < 0) { + return; + } + +//JFD +// real_return_address = MIME_MakeFromField(old_context->win_csid); +// real_return_address = (char *)pCompPrefs.GetUserEmail(); + + PR_ASSERT (m_context->type == MWContextMessageComposition); + PR_ASSERT (XP_FindContextOfType(0, MWContextMessageComposition)); + PR_ASSERT (!m_context->msg_cframe); + + + PRInt32 count = m_fields->GetNumForwardURL(); + if (count > 0) { + // if forwarding one or more messages + PR_ASSERT(*attachment == '\0'); + nsMsgAttachmentData *alist = (struct nsMsgAttachmentData *) + PR_Malloc((count + 1) * sizeof(nsMsgAttachmentData)); + if (alist) { + memset(alist, 0, (count + 1) * sizeof(*alist)); + for (count--; count >= 0; count--) { + alist[count].url = (char*) m_fields->GetForwardURL(count); + alist[count].real_name = (char*) m_fields->GetForwardURL(count); + } + SetAttachmentList(alist); + // Don't call msg_free_attachment_list because we are not duplicating + // url & real_name + PR_Free(alist);; + } + } else if (*attachment) { + // forwarding a single url + // typically a web page + nsMsgAttachmentData *alist; + count = 1; + alist = (struct nsMsgAttachmentData *) + PR_Malloc((count + 1) * sizeof(nsMsgAttachmentData)); + if (alist) { + memset(alist, 0, (count + 1) * sizeof(*alist)); + alist[0].url = (char *)attachment; + alist[0].real_name = (char *)attachment; + SetAttachmentList(alist); + // Don't call msg_free_attachment_list because we are not duplicating + // url & real_name + PR_Free(alist); + } + } // else if (*attachment) + + if (*attachment) { + if (*attachment != '(') { + m_defaultUrl = PL_strdup(attachment); + } + } + else if (old_context) { + History_entry *h = SHIST_GetCurrent(&old_context->hist); + if (h && h->address) { + m_defaultUrl = PL_strdup(h->address); + } + if (m_defaultUrl) + { + MSG_Pane *msg_pane = MSG_FindPane(old_context, + MSG_MESSAGEPANE); + if (msg_pane) + m_fields->SetHTMLPart((char *)msg_pane->GetHTMLPart(), NULL); + } + } + + if (!*m_fields->GetFrom()) { + m_fields->SetFrom(real_return_address, NULL); + } + + // Guess what kind of reply this is based on the headers we passed in. + + + const char* newsgroups = m_fields->GetNewsgroups(); + const char* to = m_fields->GetTo(); + const char* cc = m_fields->GetCc(); + const char* references = m_fields->GetReferences(); + + if (count > 0 || *attachment) { + // if an attachment exists and the forward_quoted flag is set, this + is a forward quoted operation. + if (forward_quoted) { + m_replyType = MSG_ForwardMessageQuoted; + // clear out the attachment list for forward quoted messages. + SetAttachmentList(NULL); + m_pendingAttachmentsCount = 0; + } else { + m_replyType = MSG_ForwardMessageAttachment; + } + } else if (*references && *newsgroups && (*to || *cc)) { + m_replyType = MSG_PostAndMailReply; + } else if (*references && *newsgroups) { + m_replyType = MSG_PostReply; + } else if (*references && *cc) { + m_replyType = MSG_ReplyToAll; + } else if (*references && *to) { + m_replyType = MSG_ReplyToSender; + } else if (*newsgroups) { + m_replyType = MSG_PostNew; + } else { + m_replyType = MSG_MailNew; + } + + +#ifdef UNREADY_CODE + HJ77855 +#endif + + if (!*m_fields->GetOrganization()) { + m_fields->SetOrganization((char *)pCompPrefs.GetOrganization(), NULL); + } + + if (!*m_fields->GetReplyTo()) { + m_fields-> + SetReplyTo((char *)GetPrefs()-> + GetDefaultHeaderContents(MSG_REPLY_TO_HEADER_MASK), NULL); + } + if (!*m_fields->GetFcc()) + { + PRBool useDefaultFcc = PR_TRUE; + // int prefError = + if (NS_SUCCEEDED(rv) && prefs) + { + prefs->GetBoolPref(*newsgroups ? "news.use_fcc" : "mail.use_fcc", + &useDefaultFcc); + } + + if (useDefaultFcc) + { + m_fields->SetFcc((char *)GetPrefs()-> + GetDefaultHeaderContents(*newsgroups ? + MSG_NEWS_FCC_HEADER_MASK : MSG_FCC_HEADER_MASK), NULL); + } + } + if (!*m_fields->GetBcc()) { + char* bcc = FigureBcc(*newsgroups); + m_fields->SetBcc(bcc, NULL); + PR_FREEIF(bcc); + } + + m_fields->SetFcc((char *)CheckForLosingFcc(m_fields->GetFcc()), NULL); + + { + const char *body = m_fields->GetDefaultBody(); + if (body && *body) + { + m_fields->AppendBody((char *)body); + m_fields->AppendBody(MSG_LINEBREAK); + // m_bodyEdited = PR_TRUE; + } + } + + sig = FE_UsersSignature (); + if (sig && *sig) { + m_fields->AppendBody(MSG_LINEBREAK); + //If the sig doesn't begin with "--" followed by whitespace or a + // newline, insert "-- \n" (the pseudo-standard sig delimiter.) + if (sig[0] != '-' || sig[1] != '-' || + (sig[2] != ' ' && sig[2] != CR && sig[2] != LF)) { + m_fields->AppendBody("-- " MSG_LINEBREAK); + } + m_fields->AppendBody((char *)sig); + } + + PR_FREEIF (real_return_address); + + + if (m_context) + FE_SetDocTitle(m_context, (char*) GetWindowTitle()); + + + m_initfields = new nsMsgCompFields; + if (m_initfields) { + m_initfields->AddRef(); + m_fields->Copy((nsIMsgCompFields*)m_fields); + m_initfields->SetOwner(this); + } +} + +PRBool +ShouldAutoQuote() { + if (m_haveQuoted) return PR_FALSE; + if (m_replyType == MSG_ForwardMessageQuoted || + GetPrefs()->GetAutoQuoteReply()) { + switch (m_replyType) { + case MSG_ForwardMessageQuoted: + case MSG_PostAndMailReply: + case MSG_PostReply: + case MSG_ReplyToAll: + case MSG_ReplyToSender: + return PR_TRUE; + + default: + break; + } + } + return PR_FALSE; +} + + +PRBool nsMsgCompose::SanityCheckNewsgroups (const char *newsgroups) +{ + // This function just does minor syntax checking on the names of newsgroup + // to make sure they conform to Son Of 1036: + // http://www.stud.ifi.uio.no/~larsi/notes/son-of-rfc1036.txt + // + // It isn't really possible to tell whether the group actually exists, + // so we're not going to try. + // + // According to the URL given above, uppercase characters A-Z are not + // allowed in newsgroup names, but when we tried to enforce that, we got + // bug reports from people who were trying to post to groups with capital letters + + PRBool valid = PR_TRUE; + if (newsgroups) + { + while (*newsgroups && valid) + { + if (!(*newsgroups >= 'a' && *newsgroups <= 'z') && !(*newsgroups >= 'A' && *newsgroups <= 'Z')) + { + if (!(*newsgroups >= '0' && *newsgroups <= '9')) + { + switch (*newsgroups) + { + case '+': + case '-': + case '/': + case '_': + case '=': + case '?': + case '.': + break; // valid char + case ' ': + case ',': + break; // ok to separate names in list + default: + valid = PR_FALSE; + } + } + } + newsgroups++; + } + } + return valid; +} + +int +MungeThroughRecipients(PRBool* someNonHTML, + PRBool* groupNonHTML) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + PRBool foo; + if (!someNonHTML) someNonHTML = &foo; + if (!groupNonHTML) groupNonHTML = &foo; + *someNonHTML = PR_FALSE; + *groupNonHTML = PR_FALSE; + int status = 0; + char* names = NULL; + char* addresses = NULL; + const char* groups; + char* name = NULL; + char* end; + PRBool match = PR_FALSE; + m_host = NULL; // Pure paranoia, in case we some day actually + // have a UI that lets people change this. + + static PRInt32 masks[] = { + MSG_TO_HEADER_MASK, + MSG_CC_HEADER_MASK, + MSG_BCC_HEADER_MASK + }; + char* domainlist = NULL; + + delete m_htmlrecip; + m_htmlrecip = new nsMsgHTMLRecipients(); + if (!m_htmlrecip) return MK_OUT_OF_MEMORY; + + PRUint32 i; + for (i=0 ; i < sizeof(masks) / sizeof(masks[0]) ; i++) { + const char* orig = m_fields->GetHeader(masks[i]); + if (!orig || !*orig) continue; + char* value = NULL; + value = PL_strdup(orig); + if (!value) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + int num = 0 // JFD = MSG_ParseRFC822Addresses(value, &names, &addresses); + PR_Free(value); + value = NULL; + char* addr = NULL; + for (int j=0 ; jAddOne(tmp, addr, Address, match); + if (status < 0) goto FAIL; + PR_Free(tmp); + tmp = NULL; + + if (!at) { + // ###tw We got to decide what to do in these cases. But + // for now, I'm just gonna ignore them. Which is probably + // exactly the wrong thing. Fortunately, these cases are + // now very rare, as we have code that inserts a default + // domain. + continue; + } + if (!domainlist) { + if (NS_SUCCEEDED(rv) && prefs) + prefs->CopyCharPref("mail.htmldomains", &domainlist); + } + char* domain = at + 1; + for (;;) { + char* dot = PL_strchr(domain, '.'); + if (!dot) break; + PRInt32 domainlength = PL_strlen(domain); + char* ptr; + char* endptr = NULL; + PRBool found = PR_FALSE; + for (ptr = domainlist ; ptr && *ptr ; ptr = endptr) { + endptr = PL_strchr(ptr, ','); + int length; + if (endptr) { + length = endptr - ptr; + endptr++; + } else { + length = PL_strlen(ptr); + } + if (length == domainlength) { + if (PL_strncasecmp(domain, ptr, length) == 0) { + found = PR_TRUE; + match = PR_TRUE; + break; + } + } + } +#ifdef UNREADY_CODE + char* tmp = PR_smprintf("%s@%s", + XP_GetString(MK_MSG_EVERYONE), + domain); +#endif + if (!tmp) return MK_OUT_OF_MEMORY; + status = m_htmlrecip->AddOne(domain, tmp, Domain, found); + PR_Free(tmp); + if (status < 0) goto FAIL; + domain = dot + 1; + } + if (!match) *someNonHTML = PR_TRUE; + } + } + + groups = m_fields->GetHeader(MSG_NEWSGROUPS_HEADER_MASK); + if (groups && *groups && !m_host) + { + m_host = InferNewsHost (groups); + if (!m_host) + goto FAIL; + } + + end = NULL; + for ( ; groups && *groups ; groups = end) { + end = PL_strchr(groups, ','); + if (end) *end = '\0'; + name = PL_strdup(groups); + if (end) *end++ = ','; + if (!name) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + char* group = XP_StripLine(name); + match = m_host->IsHTMLOKGroup(group); + + status = m_htmlrecip->AddOne(group, group, Newsgroup, match); + if (status < 0) goto FAIL; + char* tmp = PL_strdup(group); + if (!tmp) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + for (;;) { + PRBool found = m_host->IsHTMLOKTree(tmp); + + char* desc = PR_smprintf("%s.*", tmp); + if (!desc) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + status = m_htmlrecip->AddOne(tmp, desc, GroupHierarchy, found); + + PR_Free(desc); + if (status < 0) { + PR_Free(tmp); + tmp = NULL; + goto FAIL; + } + if (found) match = PR_TRUE; + + char* p = PL_strrchr(tmp, '.'); + if (p) *p = '\0'; + else break; + } + PR_Free(tmp); + tmp = NULL; + if (!match) { + *someNonHTML = PR_TRUE; + *groupNonHTML = PR_TRUE; + } + } + + FAIL: + PR_FREEIF(names); + PR_FREEIF(domainlist); + PR_FREEIF(addresses); + PR_FREEIF(name); + return status; +} + + + +MSG_HTMLComposeAction +DetermineHTMLAction() +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + PRBool someNonHTML, groupNonHTML; + int status; + + MSG_HTMLComposeAction result = GetHTMLAction(); + + + if (result == MSG_HTMLAskUser) { + // Well, before we ask, see if we can figure out what to do for + // ourselves. + + status = MungeThroughRecipients(&someNonHTML, &groupNonHTML); + if (status < 0) return MSG_HTMLAskUser; // ### + if (!someNonHTML) return MSG_HTMLSendAsHTML; + if (HasNoMarkup()) { + // No point in sending this message as HTML; send it plain. + return MSG_HTMLConvertToPlaintext; + } + // See if a preference has been set to tell us what to do. Note that + // we do not honor that preference for newsgroups, only for e-mail + // addresses. + if (!groupNonHTML) { + PRInt32 value = 0; + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetIntPref("mail.default_html_action", &value); + if (value >= 0) { + switch (value) { + case 1: // Force plaintext. + return MSG_HTMLConvertToPlaintext; + case 2: // Force HTML. + return MSG_HTMLSendAsHTML; + case 3: // Force multipart/alternative. + return MSG_HTMLUseMultipartAlternative; + } + } + } + } + return result; +} +**/ + diff --git a/mailnews/compose/src/nsMsgCreate.h b/mailnews/compose/src/nsMsgCreate.h new file mode 100644 index 000000000000..a221bb39b592 --- /dev/null +++ b/mailnews/compose/src/nsMsgCreate.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgCreate_H_ +#define _nsMsgCreate_H_ + + + + +#endif /* _nsMsgCreate_H_ */ diff --git a/mailnews/compose/src/nsMsgDeliveryListener.cpp b/mailnews/compose/src/nsMsgDeliveryListener.cpp new file mode 100644 index 000000000000..308434ae4886 --- /dev/null +++ b/mailnews/compose/src/nsMsgDeliveryListener.cpp @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "prprf.h" +#include "nsCOMPtr.h" +#include "nsMsgDeliveryListener.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsMsgPrompts.h" + +NS_IMPL_ISUPPORTS(nsMsgDeliveryListener, nsIUrlListener::GetIID()) + +nsresult +nsMsgDeliveryListener::OnStartRunningUrl(nsIURL * aUrl) +{ +#ifdef NS_DEBUG + printf("Starting to run the delivery operation\n"); +#endif + + return NS_OK; +} + +nsresult +nsMsgDeliveryListener::OnStopRunningUrl(nsIURL * aUrl, nsresult aExitCode) +{ + nsresult rv; +#ifdef NS_DEBUG + printf("\nOnStopRunningUrl() called!\n"); +#endif + + // First, stop being a listener since we are done. + if (aUrl) + { + // query it for a mailnews interface for now.... + nsCOMPtr mailUrl = do_QueryInterface(aUrl); + if (mailUrl) + mailUrl->UnRegisterListener(this); + } + + // + // Now, important, if there was a callback registered, call the + // creators exit routine. + // + if (mCompletionCallback) + rv = (*mCompletionCallback) (aUrl, aExitCode, mTagData); + + return rv; +} + +nsMsgDeliveryListener::nsMsgDeliveryListener(nsMsgDeliveryCompletionCallback callback, + nsMsgDeliveryType delivType, void *tagData) +{ + mTempFileSpec = nsnull; + mDeliveryType = delivType; + mTagData = tagData; + mCompletionCallback = callback; +} + +nsMsgDeliveryListener::~nsMsgDeliveryListener() +{ + delete mTempFileSpec; +} + diff --git a/mailnews/compose/src/nsMsgDeliveryListener.h b/mailnews/compose/src/nsMsgDeliveryListener.h new file mode 100644 index 000000000000..46b7579285d1 --- /dev/null +++ b/mailnews/compose/src/nsMsgDeliveryListener.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgDeliveryListener_H_ +#define _nsMsgDeliveryListener_H_ + +#include "nsIUrlListener.h" +#include "nsFileSpec.h" + +// For various delivery types +enum nsMsgDeliveryType +{ + nsMailDelivery, + nsNewsDelivery, + nsLocalFCCDelivery, + nsImapFCCDelivery, + nsFileSaveDelivery, + nsExternalDelivery +}; + +// +// This is the generic callback that will be called when the URL processing operation +// is complete. The tagData is what was passed in by the caller at creation time. +// +typedef nsresult (*nsMsgDeliveryCompletionCallback) (nsIURL *aUrl, nsresult aExitCode, void *tagData); + +class nsMsgDeliveryListener: public nsIUrlListener +{ +public: + nsMsgDeliveryListener(nsMsgDeliveryCompletionCallback callback, + nsMsgDeliveryType delivType, + void *tagData); + virtual ~nsMsgDeliveryListener(); + + NS_DECL_ISUPPORTS + + // nsIUrlListener support + NS_IMETHOD OnStartRunningUrl(nsIURL * aUrl); + NS_IMETHOD OnStopRunningUrl(nsIURL * aUrl, nsresult aExitCode); + +private: + // Private Information + void *mTagData; + nsFileSpec *mTempFileSpec; + nsMsgDeliveryType mDeliveryType; + nsMsgDeliveryCompletionCallback mCompletionCallback; +}; + + +#endif /* _nsMsgDeliveryListener_H_ */ diff --git a/mailnews/compose/src/nsMsgEncoders.cpp b/mailnews/compose/src/nsMsgEncoders.cpp new file mode 100644 index 000000000000..901b25dcf1e1 --- /dev/null +++ b/mailnews/compose/src/nsMsgEncoders.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "prprf.h" +#include "prmem.h" +#include "nsCOMPtr.h" +#include "nsINetService.h" +#include "nsIStringBundle.h" +#include "nsMsgComposeStringBundle.h" +#include "nsIServiceManager.h" +#include "nsIMimeConverter.h" + +/* This is the next generation string retrieval call */ +static NS_DEFINE_CID(kCMimeConverterCID, NS_MIME_CONVERTER_CID); + +extern "C" MimeEncoderData * +MIME_B64EncoderInit(int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure) +{ + MimeEncoderData *returnEncoderData = nsnull; + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) + { + res = converter->B64EncoderInit(output_fn, closure, &returnEncoderData); + NS_RELEASE(converter); + } + return NS_SUCCEEDED(res) ? returnEncoderData : nsnull; +} + +extern "C" MimeEncoderData * +MIME_QPEncoderInit(int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure) +{ + MimeEncoderData *returnEncoderData = nsnull; + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) + { + res = converter->QPEncoderInit(output_fn, closure, &returnEncoderData); + NS_RELEASE(converter); + } + return NS_SUCCEEDED(res) ? returnEncoderData : nsnull; +} + +extern "C" MimeEncoderData * +MIME_UUEncoderInit(char *filename, int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure) +{ + MimeEncoderData *returnEncoderData = nsnull; + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) + { + res = converter->UUEncoderInit(filename, output_fn, closure, &returnEncoderData); + NS_RELEASE(converter); + } + return NS_SUCCEEDED(res) ? returnEncoderData : nsnull; +} + +extern "C" nsresult +MIME_EncoderDestroy(MimeEncoderData *data, PRBool abort_p) +{ + MimeEncoderData *returnEncoderData = nsnull; + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) + { + res = converter->EncoderDestroy(data, abort_p); + NS_RELEASE(converter); + } + + return NS_SUCCEEDED(res) ? 0 : -1; +} diff --git a/mailnews/compose/src/nsMsgEncoders.h b/mailnews/compose/src/nsMsgEncoders.h new file mode 100644 index 000000000000..efcf8e2519c8 --- /dev/null +++ b/mailnews/compose/src/nsMsgEncoders.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgEncoders_H_ +#define _nsMsgEncoders_H_ + +extern "C" MimeEncoderData * +MIME_B64EncoderInit(int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure); + +extern "C" MimeEncoderData * +MIME_QPEncoderInit(int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure); + +extern "C" MimeEncoderData * +MIME_UUEncoderInit(char *filename, int (*output_fn) (const char *buf, PRInt32 size, void *closure), void *closure); + +extern "C" nsresult +MIME_EncoderDestroy(MimeEncoderData *data, PRBool abort_p); + + +#endif /* _nsMsgEncoders_H_ */ diff --git a/mailnews/compose/src/nsMsgI18N.cpp b/mailnews/compose/src/nsMsgI18N.cpp new file mode 100644 index 000000000000..4ce4a29c477d --- /dev/null +++ b/mailnews/compose/src/nsMsgI18N.cpp @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsISupports.h" +#include "nsIServiceManager.h" +#include "nsICharsetConverterManager.h" +#include "nsIPref.h" +#include "nsIMimeConverter.h" +#include "msgCore.h" +#include "rosetta_mailnews.h" +#include "nsMsgCompose.h" +#include "nsMsgI18N.h" + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); +static NS_DEFINE_CID(kCMimeConverterCID, NS_MIME_CONVERTER_CID); + +// +// International functions necessary for composition +// + +// Convert an unicode string to a C string with a given charset. +nsresult ConvertFromUnicode(const nsString& aCharset, + const nsString& inString, + char** outCString) +{ + nsresult res; + + NS_WITH_SERVICE(nsICharsetConverterManager, ccm, kCharsetConverterManagerCID, &res); + + if(NS_SUCCEEDED(res) && (nsnull != ccm)) { + nsIUnicodeEncoder* encoder = nsnull; + nsString convCharset; + + // map to converter charset + if (aCharset.EqualsIgnoreCase("us-ascii")) { + convCharset.SetString("iso-8859-1"); + } + else { + convCharset = aCharset; + } + + // get an unicode converter + res = ccm->GetUnicodeEncoder(&convCharset, &encoder); + if(NS_SUCCEEDED(res) && (nsnull != encoder)) { + const PRUnichar *unichars = inString.GetUnicode(); + PRInt32 unicharLength = inString.Length(); + PRInt32 dstLength; + res = encoder->GetMaxLength(unichars, unicharLength, &dstLength); + // allocale an output buffer + *outCString = (char *) PR_Malloc(dstLength + 1); + if (*outCString != nsnull) { + PRInt32 originalLength = unicharLength; + // convert from unicode + res = encoder->Convert(unichars, &unicharLength, *outCString, &dstLength); + // estimation of GetMaxLength was incorrect + if (unicharLength < originalLength) { + PR_Free(*outCString); + res = NS_ERROR_FAILURE; + } + else { + (*outCString)[dstLength] = '\0'; + } + } + else { + res = NS_ERROR_OUT_OF_MEMORY; + } + NS_IF_RELEASE(encoder); + } + } + return res; +} + +// Convert a C string to an unicode string. +nsresult ConvertToUnicode(const nsString& aCharset, + const char* inCString, + nsString& outString) +{ + nsresult res; + NS_WITH_SERVICE(nsICharsetConverterManager, ccm, kCharsetConverterManagerCID, &res); + + if(NS_SUCCEEDED(res) && (nsnull != ccm)) { + nsIUnicodeDecoder* decoder = nsnull; + PRUnichar *unichars; + PRInt32 unicharLength; + nsString convCharset; + + // map to converter charset + if (aCharset.EqualsIgnoreCase("us-ascii")) { + convCharset.SetString("iso-8859-1"); + } + else { + convCharset = aCharset; + } + // get an unicode converter + res = ccm->GetUnicodeDecoder(&convCharset, &decoder); + if(NS_SUCCEEDED(res) && (nsnull != decoder)) { + PRInt32 srcLen = PL_strlen(inCString); + res = decoder->Length(inCString, 0, srcLen, &unicharLength); + // allocale an output buffer + unichars = (PRUnichar *) PR_Malloc(unicharLength * sizeof(PRUnichar)); + if (unichars != nsnull) { + // convert to unicode + res = decoder->Convert(unichars, 0, &unicharLength, inCString, 0, &srcLen); + outString.SetString(unichars, unicharLength); + PR_Free(unichars); + } + else { + res = NS_ERROR_OUT_OF_MEMORY; + } + NS_IF_RELEASE(decoder); + } + } + return res; +} + +// Charset to be used for the internatl processing. +const char *msgCompHeaderInternalCharset() +{ + // UTF-8 is a super set of us-ascii. + // We can use the same string manipulation methods as us-ascii without breaking non us-ascii characters. + return "UTF-8"; +} + +// MIME encoder, output string should be freed by PR_FREE +char * nsMsgI18NEncodeMimePartIIStr(const char *header, const char *charset, PRBool bUseMime) +{ + // No MIME, just duplicate the string. + if (PR_FALSE == bUseMime) { + return PL_strdup(header); + } + + char *encodedString = nsnull; + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) { + res = converter->EncodeMimePartIIStr_UTF8(header, charset, kMIME_ENCODED_WORD_SIZE, &encodedString); + NS_RELEASE(converter); + } + return NS_SUCCEEDED(res) ? encodedString : nsnull; +} + +// MIME decoder +nsresult nsMsgI18NDecodeMimePartIIStr(const nsString& header, nsString& charset, nsString& decodedString) +{ + nsIMimeConverter *converter; + nsresult res = nsComponentManager::CreateInstance(kCMimeConverterCID, nsnull, + nsIMimeConverter::GetIID(), (void **)&converter); + if (NS_SUCCEEDED(res) && nsnull != converter) { + res = converter->DecodeMimePartIIStr(header, charset, decodedString); + NS_RELEASE(converter); + } + return res; +} + +// Get a default mail character set. +char * nsMsgI18NGetDefaultMailCharset() +{ + nsresult res = NS_OK; + char * retVal = nsnull; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &res); + if (nsnull != prefs && NS_SUCCEEDED(res)) + { + char *prefValue; + res = prefs->CopyCharPref("intl.character_set_name", &prefValue); + + if (NS_SUCCEEDED(res)) + { + //TODO: map to mail charset (e.g. Shift_JIS -> ISO-2022-JP) bug#3941. + retVal = prefValue; + } + else + retVal = PL_strdup("us-ascii"); + } + + return (nsnull != retVal) ? retVal : PL_strdup("us-ascii"); +} + +// Return True if a charset is stateful (e.g. JIS). +PRBool nsMsgI18Nstateful_charset(const char *charset) +{ + //TODO: use charset manager's service + return (PL_strcasecmp(charset, "iso-2022-jp") == 0); +} + +// Check 7bit in a given buffer. +// This is expensive (both memory and performance). +// The check would be very simple if applied to an unicode text (e.g. nsString or utf-8). +// Possible optimazaion is to search ESC(0x1B) in case of iso-2022-jp and iso-2022-kr. +// Or convert and check line by line. +PRBool nsMsgI18N7bit_data_part(const char *charset, const char *inString, const PRUint32 size) +{ + char *aCString; + nsString aCharset(charset); + nsString outString; + nsresult res; + + aCString = (char *) PR_Malloc(size + 1); + if (nsnull != aCString) { + PL_strncpy(aCString, inString, size); // make a C string + res = ConvertToUnicode(aCharset, aCString, outString); + PR_Free(aCString); + if (NS_SUCCEEDED(res)) { + for (PRInt32 i = 0; i < outString.Length(); i++) { + if (outString.CharAt(i) > 127) { + return PR_FALSE; + } + } + } + } + return PR_TRUE; // all 7 bit +} + +// RICHIE - not sure about this one?? need to see what it did in the old +// world. +char * +nsMsgI18NGetAcceptLanguage(void) +{ + return "en"; +} + +/////////////////////////////////////////////////////// +// RICHIE -MAKE THESE GO AWAY!!!! +/////////////////////////////////////////////////////// +void nsMsgI18NDestroyCharCodeConverter(CCCDataObject) {return;} +unsigned char * nsMsgI18NCallCharCodeConverter(CCCDataObject,const unsigned char *,int32) {return NULL;} +int nsMsgI18NGetCharCodeConverter(int16 ,int16 ,CCCDataObject) {return nsnull;} +CCCDataObject nsMsgI18NCreateCharCodeConverter() {return NULL;} +int16 nsMsgI18NGetCSIWinCSID(INTL_CharSetInfo) {return 2;} +INTL_CharSetInfo LO_GetDocumentCharacterSetInfo(MWContext *) {return NULL;} +int16 nsMsgI18NGetCSIDocCSID(INTL_CharSetInfo obj) {return 2;} +int16 nsMsgI18NDefaultWinCharSetID(MWContext *) {return 2;} +int16 nsMsgI18NDefaultMailCharSetID(int16 csid) {return 2;} +int16 nsMsgI18NDefaultNewsCharSetID(int16 csid) {return 2;} +void nsMsgI18NMessageSendToNews(XP_Bool toNews) {return;} +CCCDataObject nsMsgI18NCreateDocToMailConverter(iDocumentContext context, XP_Bool isHTML, unsigned char *buffer, + uint32 buffer_size) {return NULL;} diff --git a/mailnews/compose/src/nsMsgI18N.h b/mailnews/compose/src/nsMsgI18N.h new file mode 100644 index 000000000000..d8830d5daac1 --- /dev/null +++ b/mailnews/compose/src/nsMsgI18N.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgI18N_H_ +#define _nsMsgI18N_H_ + +NS_BEGIN_EXTERN_C + +char *nsMsgI18NEncodeMimePartIIStr(const char *header, const char *charset, PRBool bUseMime); +PRBool nsMsgI18Nstateful_charset(const char *charset); +PRBool nsMsgI18N7bit_data_part(const char *charset, const char *string, const PRUint32 size); +char *nsMsgI18NGetAcceptLanguage(void); + + +// +// THIS IS BAD STUFF...MAKE IT GO AWAY!!! +// +void nsMsgI18NDestroyCharCodeConverter(CCCDataObject); +unsigned char * nsMsgI18NCallCharCodeConverter(CCCDataObject,const unsigned char *,int32); +int nsMsgI18NGetCharCodeConverter(int16 ,int16 ,CCCDataObject); +CCCDataObject nsMsgI18NCreateCharCodeConverter(); +int16 nsMsgI18NGetCSIWinCSID(INTL_CharSetInfo); +INTL_CharSetInfo LO_GetDocumentCharacterSetInfo(MWContext *); +int16 nsMsgI18NGetCSIDocCSID(INTL_CharSetInfo obj); +int16 nsMsgI18NDefaultWinCharSetID(MWContext *); +int16 nsMsgI18NDefaultMailCharSetID(int16 csid); +int16 nsMsgI18NDefaultNewsCharSetID(int16 csid); +void nsMsgI18NMessageSendToNews(XP_Bool toNews); +CCCDataObject nsMsgI18NCreateDocToMailConverter(iDocumentContext context, XP_Bool isHTML, unsigned char *buffer, + uint32 buffer_size); + + +NS_END_EXTERN_C + +#endif /* _nsMsgI18N_H_ */ diff --git a/mailnews/compose/src/nsMsgPrompts.cpp b/mailnews/compose/src/nsMsgPrompts.cpp new file mode 100644 index 000000000000..a4eae3049817 --- /dev/null +++ b/mailnews/compose/src/nsMsgPrompts.cpp @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsMsgCopy.h" +#include "nsIPref.h" +#include "nsMsgCompPrefs.h" +#include "nsMsgPrompts.h" +#include "nsINetSupportDialogService.h" +#include "nsMsgComposeStringBundle.h" + +static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); + +nsresult +nsMsgDisplayMessageByID(PRInt32 msgID) +{ + nsresult rv; + + char *msg = ComposeBEGetStringByID(msgID); + if (!msg) + return NS_ERROR_FAILURE; + + NS_WITH_SERVICE(nsINetSupportDialogService, dialog, kNetSupportDialogCID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsAutoString alertText(msg); + if (dialog) + { + rv = dialog->Alert(alertText); + } + + PR_FREEIF(msg); + return NS_OK; +} + +nsresult +nsMsgDisplayMessageByString(char *msg) +{ + nsresult rv; + + if ((!msg) || (!*msg)) + return NS_ERROR_FAILURE; + + NS_WITH_SERVICE(nsINetSupportDialogService, dialog, kNetSupportDialogCID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsAutoString alertText(msg); + if (dialog) + { + rv = dialog->Alert(alertText); + } + + return NS_OK; +} + +nsresult +nsMsgAskBooleanQuestionByID(PRInt32 msgID, PRBool *answer) +{ + nsresult rv; + PRInt32 result; + + char *msg = ComposeBEGetStringByID(msgID); + if (!msg) + return NS_ERROR_FAILURE; + + NS_WITH_SERVICE(nsINetSupportDialogService, dialog, kNetSupportDialogCID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsAutoString confirmText(msg); + if (dialog) + { + rv = dialog->Confirm(confirmText, &result); + if (result == 1) + { + *answer = PR_TRUE; + } + else + { + *answer = PR_FALSE; + } + } + + PR_FREEIF(msg); + return NS_OK; +} + +nsresult +nsMsgAskBooleanQuestionByID(char *msg, PRBool *answer) +{ + nsresult rv; + PRInt32 result; + + if ((!msg) || (!*msg)) + return NS_ERROR_FAILURE; + + NS_WITH_SERVICE(nsINetSupportDialogService, dialog, kNetSupportDialogCID, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsAutoString confirmText(msg); + if (dialog) + { + rv = dialog->Confirm(confirmText, &result); + if (result == 1) + { + *answer = PR_TRUE; + } + else + { + *answer = PR_FALSE; + } + } + + PR_FREEIF(msg); + return NS_OK; +} diff --git a/mailnews/compose/src/nsMsgPrompts.h b/mailnews/compose/src/nsMsgPrompts.h new file mode 100644 index 000000000000..86f24df5fd4c --- /dev/null +++ b/mailnews/compose/src/nsMsgPrompts.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgPrompts_H_ +#define _nsMsgPrompts_H_ + +nsresult nsMsgDisplayMessageByID(PRInt32 msgID); +nsresult nsMsgDisplayMessageByString(char *msg); +nsresult nsMsgAskBooleanQuestionByID(PRInt32 msgID, PRBool *answer); +nsresult nsMsgAskBooleanQuestionByID(char *msg, PRBool *answer); + +#endif /* _nsMsgPrompts_H_ */ diff --git a/mailnews/compose/src/nsMsgSendLater.cpp b/mailnews/compose/src/nsMsgSendLater.cpp new file mode 100644 index 000000000000..5a2ed95a559b --- /dev/null +++ b/mailnews/compose/src/nsMsgSendLater.cpp @@ -0,0 +1,434 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsCOMPtr.h" +#include "nsMsgCopy.h" +#include "nsIPref.h" +#include "nsMsgCompPrefs.h" +#include "nsMsgSendLater.h" +#include "nsIEnumerator.h" +#include "nsIFileSpec.h" +#include "nsISmtpService.h" +#include "nsIMsgMailNewsUrl.h" +#include "nsMsgDeliveryListener.h" +#include "nsIMsgIncomingServer.h" +#include "nsICopyMessageListener.h" +#include "nsIMsgMessageService.h" + +#include "nsIMsgMailSession.h" +#include "nsMsgBaseCID.h" + + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); +static NS_DEFINE_CID(kCMsgMailSessionCID, NS_MSGMAILSESSION_CID); + +#include "nsIMsgAccountManager.h" + +nsIMsgFolder * +GetUnsentMessagesFolder(nsIMsgIdentity *userIdentity) +{ + nsresult rv = NS_OK; + nsIMsgFolder *msgFolder= nsnull; + + //****************************************************************** + // This should really be passed in, but for now, we are going + // to use this hack call...should go away! + //****************************************************************** + // get the current identity from the mail session.... +/***** + NS_WITH_SERVICE(nsIMsgMailSession, mailSession, kCMsgMailSessionCID, &rv); + if (NS_SUCCEEDED(rv) && mailSession) + rv = mailSession->GetCurrentIdentity(getter_AddRefs(identity)); + if (NS_FAILED(rv)) + return nsnull; + //****************************************************************** + // This should really be passed in, but for now, we are going + // to use this hack call...should go away! + //****************************************************************** + + nsCOMPtr accountManager; + rv = mailSession->GetAccountManager(getter_AddRefs(accountManager)); + if (NS_FAILED(rv)) + return nsnull; + + nsISupportsArray *retval; + accountManager->GetServersForIdentity(identity, &retval); + + if (retval->ElementAt(0) != nsnull) + (retval->ElementAt(0))->QueryInterface(nsIMsgFolder::GetIID(), (void **)&msgFolder); +**/ + nsCOMPtr identity = nsnull; + + NS_WITH_SERVICE(nsIMsgMailSession, session, kCMsgMailSessionCID, &rv); + if (NS_FAILED(rv)) return nsnull; + nsCOMPtr accountManager; + rv = session->GetAccountManager(getter_AddRefs(accountManager)); + if (NS_FAILED(rv)) return nsnull; + rv = session->GetCurrentIdentity(getter_AddRefs(identity)); + if (NS_FAILED(rv)) return nsnull; + + nsISupportsArray *retval; + accountManager->GetServersForIdentity(identity, &retval); + +/** + + nsIMsgIncomingServer * incomingServer = nsnull; + rv = mailSession->GetCurrentServer(&incomingServer); + if (NS_SUCCEEDED(rv) && incomingServer) + { + char * value = nsnull; + incomingServer->GetPrettyName(&value); + printf("Server pretty name: %s\n", value ? value : ""); + incomingServer->GetUsername(&value); + printf("User Name: %s\n", value ? value : ""); + incomingServer->GetHostName(&value); + printf("Pop Server: %s\n", value ? value : ""); + incomingServer->GetPassword(&value); + printf("Pop Password: %s\n", value ? value : ""); + + nsIFolder *folder; + nsIFolder *aRootFolder; + + incomingServer->GetRootFolder(&aRootFolder); + if (aRootFolder) + aRootFolder->FindSubFolder("Inbox", &folder); + + NS_RELEASE(incomingServer); + } + +**/ + + return msgFolder; +} + +static NS_DEFINE_CID(kSmtpServiceCID, NS_SMTPSERVICE_CID); + +nsresult +SendIndividualMailFile() +{ + nsFileSpec fileSpec; + nsresult rv; + +// nsIFileSpec fileSpec (m_msg_file_name ? m_msg_file_name : ""); //need to convert to unix path +// nsFilePath filePath (fileSpec); + + NS_WITH_SERVICE(nsISmtpService, smtpService, kSmtpServiceCID, &rv); + if (NS_FAILED(rv) || !smtpService) + return NS_ERROR_FAILURE; + +// rv = smtpService->SaveMessageToDisk(filePath, buf, nsnull, nsnull); +// SaveMessageToDisk(const char *aMessageURI, nsIFileSpec *aFile, PR_FALSE, + // nsIUrlListener *aUrlListener, nsnull); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + char *buf = "rhp@netscape.com"; + nsFilePath filePath ("c:\\temp\\nsmail01.txt"); + rv = smtpService->SendMailMessage(filePath, buf, nsnull, nsnull); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// +// If you pass in the user identity, then the "Outbox" will be +// sent at this time. +// +nsresult +SendUnsentMessages(nsIMsgIdentity *userIdentity) +{ + nsresult ret; + nsIMsgFolder *outboxFolder; + nsIEnumerator *enumerator = nsnull; + + outboxFolder = GetUnsentMessagesFolder(userIdentity); + if (!outboxFolder) + return NS_ERROR_FAILURE; + + // + // Now, enumerate over the messages and send each via + // SMTP... + // + ret = outboxFolder->GetMessages(&enumerator); + if (NS_SUCCEEDED(ret) && (enumerator)) + { + for (enumerator->First(); enumerator->IsDone() != NS_OK; enumerator->Next()) + { + nsIMsgDBHdr *pMessage = nsnull; + ret = enumerator->CurrentItem((nsISupports**)&pMessage); + + NS_ASSERTION(NS_SUCCEEDED(ret), "nsMsgDBEnumerator broken"); + if (NS_FAILED(ret)) + break; + + if (pMessage) + { + nsMsgKey key; + nsString subject; + + (void)pMessage->GetMessageKey(&key); + pMessage->GetSubject(subject); + + printf("message in thread %u %s\n", key, (const char *) &nsAutoString(subject)); + } + + pMessage = nsnull; + } + + NS_RELEASE(enumerator); + } + + return NS_OK; + + + +/* +*/ + + + + + /**** + identity +server (nsIMsgIncomingServer) +folder (nsIMsgFolder) +GetFolderWithFlags() - nsMsgFolderFlags.h (public) + +GetMessages() on folder + +nsIMessages returned +get URI, key, header (nsIMsgHdr - ) +get message key + +nsMsg + +get POP service - extract from Berkely mail folder + +nsIPop3Service + + +smtptest.cpp - setup as a url listener + + + + + + +nsresult OnIdentityCheck() +{ + NS_WITH_SERVICE(nsIMsgMailSession, mailSession, kCMsgMailSessionCID, &result); + if (NS_SUCCEEDED(result) && mailSession) + { + // mscott: we really don't check an identity, we check + // for an outgoing + result = mailSession->GetCurrentServer(&incomingServer); + if (NS_SUCCEEDED(result) && incomingServer) + { + char * value = nsnull; + incomingServer->GetPrettyName(&value); + printf("Server pretty name: %s\n", value ? value : ""); + incomingServer->GetUsername(&value); + printf("User Name: %s\n", value ? value : ""); + incomingServer->GetHostName(&value); + printf("Pop Server: %s\n", value ? value : ""); + incomingServer->GetPassword(&value); + printf("Pop Password: %s\n", value ? value : ""); + + NS_RELEASE(incomingServer); + } + else + printf("Unable to retrieve the outgoing server interface....\n"); + } + else + printf("Unable to retrieve the mail session service....\n"); + + return result; +} + + + + + + + + + + + + + + + + + + + + + + + NS_IMETHODIMP +nsMsgAppCore::CopyMessages(nsIDOMXULElement *srcFolderElement, nsIDOMXULElement *dstFolderElement, + nsIDOMNodeList *nodeList, PRBool isMove) + nsresult rv; + + if(!srcFolderElement || !dstFolderElement || !nodeList) + return NS_ERROR_NULL_POINTER; + + nsIRDFResource *srcResource, *dstResource; + nsICopyMessageListener *dstFolder; + nsIMsgFolder *srcFolder; + nsISupportsArray *resourceArray; + + if(NS_FAILED(rv = dstFolderElement->GetResource(&dstResource))) + return rv; + + if(NS_FAILED(rv = dstResource->QueryInterface(nsICopyMessageListener::GetIID(), (void**)&dstFolder))) + return rv; + + if(NS_FAILED(rv = srcFolderElement->GetResource(&srcResource))) + return rv; + + if(NS_FAILED(rv = srcResource->QueryInterface(nsIMsgFolder::GetIID(), (void**)&srcFolder))) + return rv; + + if(NS_FAILED(rv =ConvertDOMListToResourceArray(nodeList, &resourceArray))) + return rv; + + //Call the mailbox service to copy first message. In the future we should call CopyMessages. + //And even more in the future we need to distinguish between the different types of URI's, i.e. + //local, imap, and news, and call the appropriate copy function. + + PRUint32 cnt; + rv = resourceArray->Count(&cnt); + if (NS_SUCCEEDED(rv) && cnt > 0) + { + nsIRDFResource * firstMessage = (nsIRDFResource*)resourceArray->ElementAt(0); + char *uri; + firstMessage->GetValue(&uri); + nsCopyMessageStreamListener* copyStreamListener = new nsCopyMessageStreamListener(srcFolder, dstFolder, nsnull); + + nsIMsgMessageService * messageService = nsnull; + rv = GetMessageServiceFromURI(uri, &messageService); + + if (NS_SUCCEEDED(rv) && messageService) + { + nsIURL * url = nsnull; + messageService->CopyMessage(uri, copyStreamListener, isMove, nsnull, &url); + ReleaseMessageServiceFromURI(uri, messageService); + } + + } + + NS_RELEASE(srcResource); + NS_RELEASE(srcFolder); + NS_RELEASE(dstResource); + NS_RELEASE(dstFolder); + NS_RELEASE(resourceArray); + return rv; + **********/ +return NS_OK; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +static NS_DEFINE_IID(kIMsgSendLater, NS_IMSGSENDLATER_IID); + +// +// This function will be used by the factory to generate the +// nsMsgComposeAndSend Object.... +// +nsresult NS_NewMsgSendLater(const nsIID &aIID, void ** aInstancePtrResult) +{ + /* note this new macro for assertions...they can take a string describing the assertion */ + NS_PRECONDITION(nsnull != aInstancePtrResult, "nsnull ptr"); + if (nsnull != aInstancePtrResult) + { + nsMsgSendLater *pSendLater = new nsMsgSendLater(); + if (pSendLater) + return pSendLater->QueryInterface(kIMsgSendLater, aInstancePtrResult); + else + return NS_ERROR_OUT_OF_MEMORY; /* we couldn't allocate the object */ + } + else + return NS_ERROR_NULL_POINTER; /* aInstancePtrResult was NULL....*/ +} + +NS_IMPL_ISUPPORTS(nsMsgSendLater, nsIMsgSendLater::GetIID()) + +nsMsgSendLater::nsMsgSendLater() +{ + mIdentity = nsnull; + mSmtpServer = nsnull; + + NS_INIT_REFCNT(); +} + +nsMsgSendLater::~nsMsgSendLater() +{ + PR_FREEIF(mSmtpServer); +} + +nsresult +nsMsgSendLater::SendUnsentMessages(nsIMsgIdentity *identity, char *unsentFolder, + char *smtpServer) +{ + if ( (!identity) || (!smtpServer) || (!*smtpServer)) + return NS_ERROR_FAILURE; + + mIdentity = identity; + mSmtpServer = PL_strdup(smtpServer); + if (!mSmtpServer) + return NS_ERROR_FAILURE; + + return NS_OK; +} + diff --git a/mailnews/compose/src/nsMsgSendLater.h b/mailnews/compose/src/nsMsgSendLater.h new file mode 100644 index 000000000000..0cfc992a6567 --- /dev/null +++ b/mailnews/compose/src/nsMsgSendLater.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgSendLater_H_ +#define _nsMsgSendLater_H_ + +#include "nsIMsgIdentity.h" +#include "nsIMsgSendLater.h" + +class nsMsgSendLater: public nsIMsgSendLater +{ +public: + nsMsgSendLater(); + virtual ~nsMsgSendLater(); + + NS_DECL_ISUPPORTS + + // nsIMsgSendLater support + NS_IMETHOD SendUnsentMessages(nsIMsgIdentity *identity, char *unsentFolder, char *smtpServer); + +private: + // Private Information + nsIMsgIdentity *mIdentity; + char *mSmtpServer; +}; + + +#endif /* _nsMsgSendLater_H_ */ diff --git a/mailnews/compose/src/nsMsgUtils.cpp b/mailnews/compose/src/nsMsgUtils.cpp new file mode 100644 index 000000000000..e110cbee3bb8 --- /dev/null +++ b/mailnews/compose/src/nsMsgUtils.cpp @@ -0,0 +1,1915 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsCOMPtr.h" +#include "nsMsgUtils.h" +#include "nsIPref.h" +#include "prmem.h" +#include "nsMsgSend.h" +#include "nsINetService.h" +#include "nsMsgCompose.h" +#include "nsMailHeaders.h" +#include "nsMsgI18N.h" +#include "xp_time.h" +#include "nsMsgCompPrefs.h" +#include "nsIMsgHeaderParser.h" + +static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); +static NS_DEFINE_CID(kNetServiceCID, NS_NETSERVICE_CID); +static NS_DEFINE_CID(kMsgHeaderParserCID, NS_MSGHEADERPARSER_CID); + +// +// Hopefully, someone will write and XP call like this eventually! +// +#define TPATH_LEN 1024 + +#ifdef WIN32 +#include "windows.h" +#endif + +static char * +GetTheTempDirectoryOnTheSystem(void) +{ + char *retPath = (char *)PR_Malloc(TPATH_LEN); + if (!retPath) + return nsnull; + + retPath[0] = '\0'; +#ifdef WIN32 + if (getenv("TEMP")) + PL_strncpy(retPath, getenv("TEMP"), TPATH_LEN); // environment variable + else if (getenv("TMP")) + PL_strncpy(retPath, getenv("TMP"), TPATH_LEN); // How about this environment variable? + else + GetWindowsDirectory(retPath, TPATH_LEN); +#endif + +#ifdef XP_UNIX + PL_strncpy(retPath, "/tmp/", TPATH_LEN); +#endif + +#ifdef XP_MAC + PL_strncpy(retPath, "", TPATH_LEN); +#endif + + return retPath; +} + +// +// Create a file spec for the a unique temp file +// on the local machine. Caller must free memory +// +nsFileSpec * +nsMsgCreateTempFileSpec(char *tFileName) +{ + if ((!tFileName) || (!*tFileName)) + tFileName = "nsmail.tmp"; + + // Age old question, where to store temp files....ugh! + char *tDir = GetTheTempDirectoryOnTheSystem(); + if (!tDir) + return (new nsFileSpec("mozmail.tmp")); // No need to I18N + + nsFileSpec *tmpSpec = new nsFileSpec(tDir); + if (!tmpSpec) + { + PR_FREEIF(tDir); + return (new nsFileSpec("mozmail.tmp")); // No need to I18N + } + + *tmpSpec += tFileName; + tmpSpec->MakeUnique(); + + PR_FREEIF(tDir); + return tmpSpec; +} + +// +// Create a file spec for the a unique temp file +// on the local machine. Caller must free memory +// returned +// +char * +nsMsgCreateTempFileName(char *tFileName) +{ + if ((!tFileName) || (!*tFileName)) + tFileName = "nsmail.tmp"; + + // Age old question, where to store temp files....ugh! + char *tDir = GetTheTempDirectoryOnTheSystem(); + if (!tDir) + return "mozmail.tmp"; // No need to I18N + + nsFileSpec tmpSpec(tDir); + tmpSpec += tFileName; + tmpSpec.MakeUnique(); + + PR_FREEIF(tDir); + char *tString = (char *)PL_strdup(tmpSpec.GetNativePathCString()); + if (!tString) + return PL_strdup("mozmail.tmp"); // No need to I18N + else + return tString; +} + +static PRBool mime_headers_use_quoted_printable_p = PR_FALSE; + +PRBool +nsMsgMIMEGetConformToStandard (void) +{ + return mime_headers_use_quoted_printable_p; +} + +void +nsMsgMIMESetConformToStandard (PRBool conform_p) +{ + /* + * If we are conforming to mime standard no matter what we set + * for the headers preference when generating mime headers we should + * also conform to the standard. Otherwise, depends the preference + * we set. For now, the headers preference is not accessible from UI. + */ + if (conform_p) + mime_headers_use_quoted_printable_p = PR_TRUE; + else { + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + if (NS_SUCCEEDED(rv) && prefs) { + rv = prefs->GetBoolPref("mail.strictly_mime_headers", &mime_headers_use_quoted_printable_p); + } + } +} + +int 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*/) +{ + if (from) + while (IS_SPACE (*from)) + from++; + if (reply_to) + while (IS_SPACE (*reply_to)) + reply_to++; + if (to) + while (IS_SPACE (*to)) + to++; + if (cc) + while (IS_SPACE (*cc)) + cc++; + if (bcc) + while (IS_SPACE (*bcc)) + bcc++; + if (fcc) + while (IS_SPACE (*fcc)) + fcc++; + if (newsgroups) + while (IS_SPACE (*newsgroups)) + newsgroups++; + if (followup_to) + while (IS_SPACE (*followup_to)) + followup_to++; + + /* #### sanity check other_random_headers for newline conventions */ + if (!from || !*from) + return MK_MIME_NO_SENDER; + else + if ((!to || !*to) && (!cc || !*cc) && + (!bcc || !*bcc) && (!newsgroups || !*newsgroups)) + return MK_MIME_NO_RECIPIENTS; + else + return 0; +} + +static char * +nsMsgStripLine (char * string) +{ + char * ptr; + + /* remove leading blanks */ + while(*string=='\t' || *string==' ' || *string=='\r' || *string=='\n') + string++; + + for(ptr=string; *ptr; ptr++) + ; /* NULL BODY; Find end of string */ + + /* remove trailing blanks */ + for(ptr--; ptr >= string; ptr--) + { + if(*ptr=='\t' || *ptr==' ' || *ptr=='\r' || *ptr=='\n') + *ptr = '\0'; + else + break; + } + + return string; +} + +char * +mime_generate_headers (nsMsgCompFields *fields, + const char *charset, + nsMsgDeliverMode deliver_mode) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + int size = 0; + char *buffer = 0, *buffer_tail = 0; + PRBool isDraft = deliver_mode == nsMsgSaveAsDraft || + deliver_mode == nsMsgSaveAsTemplate || + deliver_mode == nsMsgQueueForLater; + + const char* pFrom; + const char* pTo; + const char* pCc; + const char* pMessageID; + const char* pReplyTo; + const char* pOrg; + const char* pNewsGrp; + const char* pFollow; + const char* pSubject; + const char* pPriority; + const char* pReference; + const char* pOtherHdr; + + NS_ASSERTION (fields, "null fields"); + if (!fields) + return NULL; + + /* Multiply by 3 here to make enough room for MimePartII conversion */ + pFrom = fields->GetFrom(); if (pFrom) size += 3 * PL_strlen (pFrom); + pReplyTo =fields->GetReplyTo(); if (pReplyTo) size += 3 * PL_strlen (pReplyTo); + pTo = fields->GetTo(); if (pTo) size += 3 * PL_strlen (pTo); + pCc = fields->GetCc(); if (pCc) size += 3 * PL_strlen (pCc); + pNewsGrp = fields->GetNewsgroups(); if (pNewsGrp) size += 3 * PL_strlen (pNewsGrp); + pFollow= fields->GetFollowupTo(); if (pFollow) size += 3 * PL_strlen (pFollow); + pSubject = fields->GetSubject(); if (pSubject) size += 3 * PL_strlen (pSubject); + pReference = fields->GetReferences(); if (pReference) size += 3 * PL_strlen (pReference); + pOrg= fields->GetOrganization(); if (pOrg) size += 3 * PL_strlen (pOrg); + pOtherHdr= fields->GetOtherRandomHeaders(); if (pOtherHdr) size += 3 * PL_strlen (pOtherHdr); + pPriority = fields->GetPriority(); if (pPriority) size += 3 * PL_strlen (pPriority); +#ifdef GENERATE_MESSAGE_ID + pMessageID = fields->GetMessageId(); if (pMessageID) size += PL_strlen (pMessageID); +#endif /* GENERATE_MESSAGE_ID */ + + /* Add a bunch of slop for the static parts of the headers. */ + /* size += 2048; */ + size += 2560; + + buffer = (char *) PR_Malloc (size); + if (!buffer) + return 0; /* MK_OUT_OF_MEMORY */ + + buffer_tail = buffer; + +#ifdef GENERATE_MESSAGE_ID + if (pMessageID && *pMessageID) { + char *convbuf = NULL; + PUSH_STRING ("Message-ID: "); + PUSH_STRING (pMessageID); + PUSH_NEWLINE (); + /* MDN request header requires to have MessageID header presented + * in the message in order to + * coorelate the MDN reports to the original message. Here will be + * the right place + */ + if (fields->GetReturnReceipt() && + (fields->GetReturnReceiptType() == 2 || + fields->GetReturnReceiptType() == 3) && + (deliver_mode != nsMsgSaveAsDraft && + deliver_mode != nsMsgSaveAsTemplate)) + { + PRInt32 receipt_header_type = 0; + + if (prefs) + prefs->GetIntPref("mail.receipt.request_header_type", &receipt_header_type); + + // 0 = MDN Disposition-Notification-To: ; 1 = Return-Receipt-To: ; 2 = + // both MDN DNT & RRT headers + if (receipt_header_type == 1) { + RRT_HEADER: + PUSH_STRING ("Return-Receipt-To: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pFrom, charset, nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_FREEIF(convbuf); + } + else + PUSH_STRING (pFrom); + PUSH_NEWLINE (); + } + else { + PUSH_STRING ("Disposition-Notification-To: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pFrom, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_FREEIF(convbuf); + } + else + PUSH_STRING (pFrom); + PUSH_NEWLINE (); + if (receipt_header_type == 2) + goto RRT_HEADER; + } + } +#ifdef SUPPORT_X_TEMPLATE_NAME + if (deliver_mode == MSG_SaveAsTemplate) { + PUSH_STRING ("X-Template: "); + char * pStr = fields->GetTemplateName(); + if (pStr) { + convbuf = nsMsgI18NEncodeMimePartIIStr((char *) + pStr, + charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { + PUSH_STRING (convbuf); + PR_FREEIF(convbuf); + } + else + PUSH_STRING(pStr); + } + PUSH_NEWLINE (); + } +#endif /* SUPPORT_X_TEMPLATE_NAME */ + } +#endif /* GENERATE_MESSAGE_ID */ + + PRExplodedTime now; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now); + int gmtoffset = now.tm_params.tp_gmt_offset / 60; /*We need the offset in minute and not in second! */ + + /* Use PR_FormatTimeUSEnglish() to format the date in US English format, + then figure out what our local GMT offset is, and append it (since + PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as + per RFC 1123 (superceding RFC 822.) + */ + PR_FormatTimeUSEnglish(buffer_tail, 100, + "Date: %a, %d %b %Y %H:%M:%S ", + &now); + + buffer_tail += PL_strlen (buffer_tail); + PR_snprintf(buffer_tail, buffer + size - buffer_tail, + "%c%02d%02d" CRLF, + (gmtoffset >= 0 ? '+' : '-'), + ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) / 60), + ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) % 60)); + buffer_tail += PL_strlen (buffer_tail); + + if (pFrom && *pFrom) { + char *convbuf; + PUSH_STRING ("From: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pFrom, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pFrom); + PUSH_NEWLINE (); + } + + if (pReplyTo && *pReplyTo) + { + char *convbuf; + PUSH_STRING ("Reply-To: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pReplyTo, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pReplyTo); + PUSH_NEWLINE (); + } + + if (pOrg && *pOrg) + { + char *convbuf; + PUSH_STRING ("Organization: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pOrg, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pOrg); + PUSH_NEWLINE (); + } + + // X-Sender tag + if (fields->GetOwner()) + { + PRBool bUseXSender = PR_FALSE; + + if (prefs) + prefs->GetBoolPref("mail.use_x_sender", &bUseXSender); + + if (bUseXSender) { + char *convbuf; + char *tmpBuffer=nsnull; + + PUSH_STRING ("X-Sender: "); + + PUSH_STRING("\""); + + if (prefs) + prefs->CopyCharPref("mail.identity.username", &tmpBuffer); + convbuf = nsMsgI18NEncodeMimePartIIStr(tmpBuffer, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (tmpBuffer); + if (tmpBuffer) PL_strfree(tmpBuffer); + tmpBuffer=nsnull; + + PUSH_STRING("\" <"); + + if (NS_SUCCEEDED(rv) && prefs) + prefs->CopyCharPref("mail.smtp_name", &tmpBuffer); + convbuf = nsMsgI18NEncodeMimePartIIStr(tmpBuffer, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (tmpBuffer); + if (tmpBuffer) PL_strfree(tmpBuffer); + tmpBuffer=nsnull; + + PUSH_STRING ("@"); + + if (NS_SUCCEEDED(rv) && prefs) + prefs->CopyCharPref("network.hosts.smtp_server", &tmpBuffer); + convbuf = nsMsgI18NEncodeMimePartIIStr(tmpBuffer, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (tmpBuffer); + + PUSH_STRING(">"); + + convbuf = nsMsgI18NEncodeMimePartIIStr(tmpBuffer, charset, + nsMsgMIMEGetConformToStandard()); + if (tmpBuffer) PL_strfree(tmpBuffer); + tmpBuffer=nsnull; + + if (!fields->GetOwner()->GetMaster()->IsUserAuthenticated()) + PUSH_STRING (" (Unverified)"); + PUSH_NEWLINE (); + } + } + + // X-Mozilla-Draft-Info + if (isDraft) { + char *htmlAction = 0; + char *lineWidth = 0; // force plain text hard line break info + + PUSH_STRING(HEADER_X_MOZILLA_DRAFT_INFO); + PUSH_STRING(": internal/draft; "); + if (fields->GetAttachVCard()) + PUSH_STRING("vcard=1"); + else + PUSH_STRING("vcard=0"); + PUSH_STRING("; "); + if (fields->GetReturnReceipt()) { + char *type = PR_smprintf("%d", (int) fields->GetReturnReceiptType()); + if (type) + { + PUSH_STRING("receipt="); + PUSH_STRING(type); + PR_FREEIF(type); + } + } + else + PUSH_STRING("receipt=0"); + PUSH_STRING("; "); + if (fields->GetBoolHeader(MSG_UUENCODE_BINARY_BOOL_HEADER_MASK)) + PUSH_STRING("uuencode=1"); + else + PUSH_STRING("uuencode=0"); + + htmlAction = PR_smprintf("html=%d", + ((nsMsgCompose*)fields->GetOwner())->GetHTMLAction()); + if (htmlAction) { + PUSH_STRING("; "); + PUSH_STRING(htmlAction); + PR_FREEIF(htmlAction); + } + + lineWidth = PR_smprintf("; linewidth=%d", + ((nsMsgCompose*)fields->GetOwner())->GetLineWidth()); + if (lineWidth) { + PUSH_STRING(lineWidth); + PR_FREEIF(lineWidth); + } + PUSH_NEWLINE (); + } + + + NS_WITH_SERVICE(nsINetService, pNetService, kNetServiceCID, &rv); + if (NS_SUCCEEDED(rv) && pNetService) + { + nsString aNSStr; + char* sCStr; + + pNetService->GetAppCodeName(aNSStr); + sCStr = aNSStr.ToNewCString(); + if (sCStr) { + PUSH_STRING ("X-Mailer: "); + PUSH_STRING(sCStr); + delete [] sCStr; + + pNetService->GetAppVersion(aNSStr); + sCStr = aNSStr.ToNewCString(); + if (sCStr) { + PUSH_STRING (" "); + PUSH_STRING(sCStr); + delete [] sCStr; + } + PUSH_NEWLINE (); + } + } + + /* for Netscape Server, Accept-Language data sent in Mail header */ + char *acceptlang = nsMsgI18NGetAcceptLanguage(); + if( (acceptlang != NULL) && ( *acceptlang != '\0') ){ + PUSH_STRING( "X-Accept-Language: " ); + PUSH_STRING( acceptlang ); + PUSH_NEWLINE(); + } + + PUSH_STRING ("MIME-Version: 1.0" CRLF); + + if (pNewsGrp && *pNewsGrp) { + /* turn whitespace into a comma list + */ + char *ptr, *ptr2; + char *n2; + char *convbuf; + + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pNewsGrp, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) + n2 = nsMsgStripLine (convbuf); + else { + ptr = PL_strdup(pNewsGrp); + if (!ptr) { + PR_FREEIF(buffer); + return 0; /* MK_OUT_OF_MEMORY */ + } + n2 = nsMsgStripLine(ptr); + NS_ASSERTION(n2 == ptr, "n2 != ptr"); /* Otherwise, the PR_Free below is + gonna choke badly. */ + } + + for(ptr=n2; *ptr != '\0'; ptr++) { + /* find first non white space */ + while(!IS_SPACE(*ptr) && *ptr != ',' && *ptr != '\0') + ptr++; + + if(*ptr == '\0') + break; + + if(*ptr != ',') + *ptr = ','; + + /* find next non white space */ + ptr2 = ptr+1; + while(IS_SPACE(*ptr2)) + ptr2++; + + if(ptr2 != ptr+1) + PL_strcpy(ptr+1, ptr2); + } + + PUSH_STRING ("Newsgroups: "); + PUSH_STRING (n2); + PR_Free (n2); + PUSH_NEWLINE (); + } + + /* #### shamelessly duplicated from above */ + if (pFollow && *pFollow) { + /* turn whitespace into a comma list + */ + char *ptr, *ptr2; + char *n2; + char *convbuf; + + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pFollow, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) + n2 = nsMsgStripLine (convbuf); + else { + ptr = PL_strdup(pFollow); + if (!ptr) { + PR_FREEIF(buffer); + return 0; /* MK_OUT_OF_MEMORY */ + } + n2 = nsMsgStripLine (ptr); + NS_ASSERTION(n2 == ptr, "n2 != ptr"); /* Otherwise, the PR_Free below is + gonna choke badly. */ + } + + for (ptr=n2; *ptr != '\0'; ptr++) { + /* find first non white space */ + while(!IS_SPACE(*ptr) && *ptr != ',' && *ptr != '\0') + ptr++; + + if(*ptr == '\0') + break; + + if(*ptr != ',') + *ptr = ','; + + /* find next non white space */ + ptr2 = ptr+1; + while(IS_SPACE(*ptr2)) + ptr2++; + + if(ptr2 != ptr+1) + PL_strcpy(ptr+1, ptr2); + } + + PUSH_STRING ("Followup-To: "); + PUSH_STRING (n2); + PR_Free (n2); + PUSH_NEWLINE (); + } + + if (pTo && *pTo) { + char *convbuf; + PUSH_STRING ("To: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pTo, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pTo); + + PUSH_NEWLINE (); + } + + if (pCc && *pCc) { + char *convbuf; + PUSH_STRING ("CC: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pCc, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pCc); + PUSH_NEWLINE (); + } + + if (pSubject && *pSubject) { + char *convbuf; + PUSH_STRING ("Subject: "); + convbuf = nsMsgI18NEncodeMimePartIIStr((char *)pSubject, charset, + nsMsgMIMEGetConformToStandard()); + if (convbuf) { /* MIME-PartII conversion */ + PUSH_STRING (convbuf); + PR_Free(convbuf); + } + else + PUSH_STRING (pSubject); + PUSH_NEWLINE (); + } + + if (pPriority && *pPriority) + if (!PL_strcasestr(pPriority, "normal")) { + PUSH_STRING ("X-Priority: "); + /* Important: do not change the order of the + * following if statements + */ + if (PL_strcasestr (pPriority, "highest")) + PUSH_STRING("1 ("); + else if (PL_strcasestr(pPriority, "high")) + PUSH_STRING("2 ("); + else if (PL_strcasestr(pPriority, "lowest")) + PUSH_STRING("5 ("); + else if (PL_strcasestr(pPriority, "low")) + PUSH_STRING("4 ("); + + PUSH_STRING (pPriority); + PUSH_STRING(")"); + PUSH_NEWLINE (); + } + + if (pReference && *pReference) { + PUSH_STRING ("References: "); + if (PL_strlen(pReference) >= 986) { + char *references = PL_strdup(pReference); + char *trimAt = PL_strchr(references+1, '<'); + char *ptr; + // per sfraser, RFC 1036 - a message header line should not exceed + // 998 characters including the header identifier + // retiring the earliest reference one after the other + // but keep the first one for proper threading + while (references && PL_strlen(references) >= 986 && trimAt) { + ptr = PL_strchr(trimAt+1, '<'); + if (ptr) + XP_MEMMOVE(trimAt, ptr, PL_strlen(ptr)+1); // including the + else + break; + } + NS_ASSERTION(references, "null references"); + if (references) { + PUSH_STRING (references); + PR_Free(references); + } + } + else + PUSH_STRING (pReference); + PUSH_NEWLINE (); + } + + if (pOtherHdr && *pOtherHdr) { + /* Assume they already have the right newlines and continuations + and so on. */ + PUSH_STRING (pOtherHdr); + } + + if (buffer_tail > buffer + size - 1) + abort (); + + /* realloc it smaller... */ + buffer = (char*)PR_REALLOC (buffer, buffer_tail - buffer + 1); + + return buffer; +} + +static void +GenerateGlobalRandomBytes(unsigned char *buf, PRInt32 len) +{ + PRBool firstTime = PR_TRUE; + + if (firstTime) + { + /* Seed the random-number generator with current time so that + * the numbers will be different every time we run. */ + srand( (unsigned)time( NULL ) ); + firstTime = PR_FALSE; + } + + for( PRInt32 i = 0; i < len; i++ ) + buf[i] = rand() % 10; +} + +char +*mime_make_separator(const char *prefix) +{ + unsigned char rand_buf[13]; + GenerateGlobalRandomBytes(rand_buf, 12); + + return PR_smprintf("------------%s" + "%02X%02X%02X%02X" + "%02X%02X%02X%02X" + "%02X%02X%02X%02X", + prefix, + rand_buf[0], rand_buf[1], rand_buf[2], rand_buf[3], + rand_buf[4], rand_buf[5], rand_buf[6], rand_buf[7], + rand_buf[8], rand_buf[9], rand_buf[10], rand_buf[11]); +} + +char * +mime_generate_attachment_headers (const char *type, const char *encoding, + const char *description, + const char *x_mac_type, + const char *x_mac_creator, + const char *real_name, + const char *base_url, + PRBool /*digest_p*/, + nsMsgAttachmentHandler * /*ma*/, + const char *charset) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + + PRInt32 buffer_size = 2048 + (base_url ? 2*PL_strlen(base_url) : 0); + char *buffer = (char *) PR_Malloc (buffer_size); + char *buffer_tail = buffer; + + if (! buffer) + return 0; /* MK_OUT_OF_MEMORY */ + + NS_ASSERTION (encoding, "null encoding"); + + PUSH_STRING ("Content-Type: "); + PUSH_STRING (type); + + if (mime_type_needs_charset (type)) { + + char charset_label[65]; // Content-Type: charset + PL_strcpy(charset_label, charset); + + /* If the characters are all 7bit, then it's better (and true) to + claim the charset to be US- rather than Latin1. Should we + do this all the time, for all charsets? I'm not sure. But we + should definitely do it for Latin1. */ + if (encoding && + !PL_strcasecmp (encoding, "7bit") && + !PL_strcasecmp (charset, "iso-8859-1")) + PL_strcpy (charset_label, "us-ascii"); + + // If charset is JIS and and type is HTML + // then no charset to be specified (apply base64 instead) + // in order to avoid mismatch META_TAG (bug#104255). + if ((PL_strcasecmp(charset, "iso-2022-jp") != 0) || + (PL_strcasecmp(type, TEXT_HTML) != 0) || + (PL_strcasecmp(encoding, ENCODING_BASE64) != 0)) { + PUSH_STRING ("; charset="); + PUSH_STRING (charset_label); + } + } + + if (x_mac_type && *x_mac_type) { + PUSH_STRING ("; x-mac-type=\""); + PUSH_STRING (x_mac_type); + PUSH_STRING ("\""); + } + + if (x_mac_creator && *x_mac_creator) { + PUSH_STRING ("; x-mac-creator=\""); + PUSH_STRING (x_mac_creator); + PUSH_STRING ("\""); + } + + PRInt32 parmFolding = 0; + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetIntPref("mail.strictly_mime.parm_folding", &parmFolding); + +#ifdef EMIT_NAME_IN_CONTENT_TYPE + if (real_name && *real_name) { + if (parmFolding == 0 || parmFolding == 1) { + PUSH_STRING (";\r\n name=\""); + PUSH_STRING (real_name); + PUSH_STRING ("\""); + } + else // if (parmFolding == 2) + { + char *rfc2231Parm = RFC2231ParmFolding("name", charset, + nsMsgI18NGetAcceptLanguage(), real_name); + if (rfc2231Parm) { + PUSH_STRING(";\r\n "); + PUSH_STRING(rfc2231Parm); + PR_Free(rfc2231Parm); + } + } + } +#endif /* EMIT_NAME_IN_CONTENT_TYPE */ + + PUSH_NEWLINE (); + + PUSH_STRING ("Content-Transfer-Encoding: "); + PUSH_STRING (encoding); + PUSH_NEWLINE (); + + if (description && *description) { + char *s = mime_fix_header (description); + if (s) { + PUSH_STRING ("Content-Description: "); + PUSH_STRING (s); + PUSH_NEWLINE (); + PR_Free(s); + } + } + + if (real_name && *real_name) { + char *period = PL_strrchr(real_name, '.'); + PRInt32 pref_content_disposition = 0; + + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetIntPref("mail.content_disposition_type", &pref_content_disposition); + PUSH_STRING ("Content-Disposition: "); + + if (pref_content_disposition == 1) + PUSH_STRING ("attachment"); + else + if (pref_content_disposition == 2 && + (!PL_strcasecmp(type, TEXT_PLAIN) || + (period && !PL_strcasecmp(period, ".txt")))) + PUSH_STRING("attachment"); + + /* If this document is an anonymous binary file or a vcard, + then always show it as an attachment, never inline. */ + else + if (!PL_strcasecmp(type, APPLICATION_OCTET_STREAM) || + !PL_strcasecmp(type, TEXT_VCARD) || + !PL_strcasecmp(type, APPLICATION_DIRECTORY)) /* text/x-vcard synonym */ + PUSH_STRING ("attachment"); + else + PUSH_STRING ("inline"); + + if (parmFolding == 0 || parmFolding == 1) { + PUSH_STRING (";\r\n filename=\""); + PUSH_STRING (real_name); + PUSH_STRING ("\"" CRLF); + } + else // if (parmFolding == 2) + { + char *rfc2231Parm = RFC2231ParmFolding("filename", charset, + nsMsgI18NGetAcceptLanguage(), real_name); + if (rfc2231Parm) { + PUSH_STRING(";\r\n "); + PUSH_STRING(rfc2231Parm); + PUSH_NEWLINE (); + PR_Free(rfc2231Parm); + } + } + } + else + if (type && + (!PL_strcasecmp (type, MESSAGE_RFC822) || + !PL_strcasecmp (type, MESSAGE_NEWS))) + PUSH_STRING ("Content-Disposition: inline" CRLF); + +#ifdef GENERATE_CONTENT_BASE + /* If this is an HTML document, and we know the URL it originally + came from, write out a Content-Base header. */ + if (type && + (!PL_strcasecmp (type, TEXT_HTML) || + !PL_strcasecmp (type, TEXT_MDL)) && + base_url && *base_url) + { + PRInt32 col = 0; + const char *s = base_url; + const char *colon = PL_strchr (s, ':'); + PRBool useContentLocation = PR_FALSE; /* rhp - add this */ + + if (!colon) + goto GIVE_UP_ON_CONTENT_BASE; /* malformed URL? */ + + /* Don't emit a content-base that points to (or into) a news or + mail message. */ + if (!PL_strncasecmp (s, "news:", 5) || + !PL_strncasecmp (s, "snews:", 6) || + !PL_strncasecmp (s, "IMAP:", 5) || + !PL_strncasecmp (s, "file:", 5) || /* rhp: fix targets from included HTML files */ + !PL_strncasecmp (s, "mailbox:", 8)) + goto GIVE_UP_ON_CONTENT_BASE; + + /* rhp - Put in a pref for using Content-Location instead of Content-Base. + This will get tweaked to default to true in 5.0 + */ + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetBoolPref("mail.use_content_location_on_send", &useContentLocation); + + if (useContentLocation) + PUSH_STRING ("Content-Location: \""); + else + PUSH_STRING ("Content-Base: \""); + /* rhp - Pref for Content-Location usage */ + +/* rhp: this is to work with the Content-Location stuff */ +CONTENT_LOC_HACK: + + while (*s != 0 && *s != '#') + { + const char *ot = buffer_tail; + + /* URLs must be wrapped at 40 characters or less. */ + if (col >= 38) { + PUSH_STRING(CRLF "\t"); + col = 0; + } + + if (*s == ' ') + PUSH_STRING("%20"); + else if (*s == '\t') + PUSH_STRING("%09"); + else if (*s == '\n') + PUSH_STRING("%0A"); + else if (*s == '\r') + PUSH_STRING("%0D"); + else { + *buffer_tail++ = *s; + *buffer_tail = '\0'; + } + s++; + col += (buffer_tail - ot); + } + PUSH_STRING ("\"" CRLF); + + /* rhp: this is to try to get around this fun problem with Content-Location */ + if (!useContentLocation) { + PUSH_STRING ("Content-Location: \""); + s = base_url; + col = 0; + useContentLocation = PR_TRUE; + goto CONTENT_LOC_HACK; + } + /* rhp: this is to try to get around this fun problem with Content-Location */ + +GIVE_UP_ON_CONTENT_BASE: + ; + } +#endif /* GENERATE_CONTENT_BASE */ + + /* realloc it smaller... */ + buffer = (char*) PR_REALLOC (buffer, buffer_tail - buffer + 1); + + return buffer; +} + +char * +msg_generate_message_id (void) +{ + time_t now = XP_TIME(); + PRUint32 salt = 0; + nsMsgCompPrefs pCompPrefs; + const char *host = 0; + const char *from = pCompPrefs.GetUserEmail(); + + GenerateGlobalRandomBytes((unsigned char *) &salt, sizeof(salt)); + if (from) { + host = PL_strchr (from, '@'); + if (host) { + const char *s; + for (s = ++host; *s; s++) + if (!XP_IS_ALPHA(*s) && !XP_IS_DIGIT(*s) && + *s != '-' && *s != '_' && *s != '.') { + host = 0; + break; + } + } + } + + if (! host) + /* If we couldn't find a valid host name to use, we can't generate a + valid message ID, so bail, and let NNTP and SMTP generate them. */ + return 0; + + return PR_smprintf("<%lX.%lX@%s>", + (unsigned long) now, (unsigned long) salt, host); +} + +char * +RFC2231ParmFolding(const char *parmName, const char *charset, + const char *language, const char *parmValue) +{ +#define PR_MAX_FOLDING_LEN 75 // this is to gurantee the folded line will + // never be greater than 78 = 75 + CRLFLWSP + char *foldedParm = NULL; + char *dupParm = NULL; + PRInt32 parmNameLen = 0; + PRInt32 parmValueLen = 0; + PRInt32 charsetLen = 0; + PRInt32 languageLen = 0; + PRBool needEscape = PR_FALSE; + + NS_ASSERTION(parmName && *parmName && parmValue && *parmValue, "null parameters"); + if (!parmName || !*parmName || !parmValue || !*parmValue) + return NULL; + if ((charset && *charset && PL_strcasecmp(charset, "us-ascii") != 0) || + (language && *language && PL_strcasecmp(language, "en") != 0 && + PL_strcasecmp(language, "en-us") != 0)) + needEscape = PR_TRUE; + + if (needEscape) + dupParm = nsEscape(parmValue, url_Path); + else + dupParm = PL_strdup(parmValue); + + if (!dupParm) + return NULL; + + if (needEscape) + { + parmValueLen = PL_strlen(dupParm); + parmNameLen = PL_strlen(parmName); + } + + if (needEscape) + parmNameLen += 5; // *=__'__'___ or *[0]*=__'__'__ or *[1]*=___ + else + parmNameLen += 5; // *[0]="___"; + charsetLen = charset ? PL_strlen(charset) : 0; + languageLen = language ? PL_strlen(language) : 0; + + if ((parmValueLen + parmNameLen + charsetLen + languageLen) < + PR_MAX_FOLDING_LEN) + { + foldedParm = PL_strdup(parmName); + if (needEscape) + { + StrAllocCat(foldedParm, "*="); + if (charsetLen) + StrAllocCat(foldedParm, charset); + StrAllocCat(foldedParm, "'"); + if (languageLen) + StrAllocCat(foldedParm, language); + StrAllocCat(foldedParm, "'"); + } + else + StrAllocCat(foldedParm, "=\""); + StrAllocCat(foldedParm, dupParm); + if (!needEscape) + StrAllocCat(foldedParm, "\""); + goto done; + } + else + { + int curLineLen = 0; + int counter = 0; + char digits[32]; + char *start = dupParm; + char *end = NULL; + char tmp = 0; + + while (parmValueLen > 0) + { + curLineLen = 0; + if (counter == 0) { + PR_FREEIF(foldedParm) + foldedParm = PL_strdup(parmName); + } + else { + if (needEscape) + StrAllocCat(foldedParm, "\r\n "); + else + StrAllocCat(foldedParm, ";\r\n "); + StrAllocCat(foldedParm, parmName); + } + PR_snprintf(digits, sizeof(digits), "*%d", counter); + StrAllocCat(foldedParm, digits); + curLineLen += PL_strlen(digits); + if (needEscape) + { + StrAllocCat(foldedParm, "*="); + if (counter == 0) + { + if (charsetLen) + StrAllocCat(foldedParm, charset); + StrAllocCat(foldedParm, "'"); + if (languageLen) + StrAllocCat(foldedParm, language); + StrAllocCat (foldedParm, "'"); + curLineLen += charsetLen; + curLineLen += languageLen; + } + } + else + { + StrAllocCat(foldedParm, "=\""); + } + counter++; + curLineLen += parmNameLen; + if (parmValueLen <= PR_MAX_FOLDING_LEN - curLineLen) + end = start + parmValueLen; + else + end = start + (PR_MAX_FOLDING_LEN - curLineLen); + + tmp = 0; + if (*end && needEscape) + { + // check to see if we are in the middle of escaped char + if (*end == '%') + { + tmp = '%'; *end = nsnull; + } + else if (end-1 > start && *(end-1) == '%') + { + end -= 1; tmp = '%'; *end = nsnull; + } + else if (end-2 > start && *(end-2) == '%') + { + end -= 2; tmp = '%'; *end = nsnull; + } + else + { + tmp = *end; *end = nsnull; + } + } + else + { + tmp = *end; *end = nsnull; + } + StrAllocCat(foldedParm, start); + if (!needEscape) + StrAllocCat(foldedParm, "\""); + + parmValueLen -= (end-start); + if (tmp) + *end = tmp; + start = end; + } + } + +done: + PR_FREEIF(dupParm); + return foldedParm; +} + +PRBool +mime_7bit_data_p (const char *string, PRUint32 size) +{ + const unsigned char *s = (const unsigned char *) string; + const unsigned char *end = s + size; + if (s) + for (; s < end; s++) + if (*s > 0x7F) + return PR_FALSE; + return PR_TRUE; +} + +/* Strips whitespace, and expands newlines into newline-tab for use in + mail headers. Returns a new string or 0 (if it would have been empty.) + If addr_p is true, the addresses will be parsed and reemitted as + rfc822 mailboxes. + */ +char * +mime_fix_header_1 (const char *string, PRBool addr_p, PRBool news_p) +{ + char *new_string; + const char *in; + char *out; + PRInt32 i, old_size, new_size; + + if (!string || !*string) + return 0; + + if (addr_p) { + nsIMsgHeaderParser * pHeader; + nsresult rv = nsComponentManager::CreateInstance(kMsgHeaderParserCID, + NULL, + nsIMsgHeaderParser::GetIID(), + (void **) &pHeader); + if (NS_SUCCEEDED(rv)) { + char *n; + pHeader->ReformatHeaderAddresses(nsnull, string, &n); + pHeader->Release(); + if (n) + return n; + } + } + + old_size = PL_strlen (string); + new_size = old_size; + for (i = 0; i < old_size; i++) + if (string[i] == CR || string[i] == LF) + new_size += 2; + + new_string = (char *) PR_Malloc (new_size + 1); + if (! new_string) + return 0; + + in = string; + out = new_string; + + /* strip leading whitespace. */ + while (IS_SPACE (*in)) + in++; + + /* replace CR, LF, or CRLF with CRLF-TAB. */ + while (*in) { + if (*in == CR || *in == LF) { + if (*in == CR && in[1] == LF) + in++; + in++; + *out++ = CR; + *out++ = LF; + *out++ = '\t'; + } + else + if (news_p && *in == ',') { + *out++ = *in++; + /* skip over all whitespace after a comma. */ + while (IS_SPACE (*in)) + in++; + } + else + *out++ = *in++; + } + *out = 0; + + /* strip trailing whitespace. */ + while (out > in && IS_SPACE (out[-1])) + *out-- = 0; + + /* If we ended up throwing it all away, use 0 instead of "". */ + if (!*new_string) { + PR_Free (new_string); + new_string = 0; + } + + return new_string; +} + +char * +mime_fix_header (const char *string) +{ + return mime_fix_header_1 (string, PR_FALSE, PR_FALSE); +} + +char * +mime_fix_addr_header (const char *string) +{ + return mime_fix_header_1 (string, PR_TRUE, PR_FALSE); +} + +char * +mime_fix_news_header (const char *string) +{ + return mime_fix_header_1 (string, PR_FALSE, PR_TRUE); +} + +PRBool +mime_type_requires_b64_p (const char *type) +{ + if (!type || !PL_strcasecmp (type, UNKNOWN_CONTENT_TYPE)) + /* Unknown types don't necessarily require encoding. (Note that + "unknown" and "application/octet-stream" aren't the same.) */ + return PR_FALSE; + + else if (!PL_strncasecmp (type, "image/", 6) || + !PL_strncasecmp (type, "audio/", 6) || + !PL_strncasecmp (type, "video/", 6) || + !PL_strncasecmp (type, "application/", 12)) + { + /* The following types are application/ or image/ types that are actually + known to contain textual data (meaning line-based, not binary, where + CRLF conversion is desired rather than disasterous.) So, if the type + is any of these, it does not *require* base64, and if we do need to + encode it for other reasons, we'll probably use quoted-printable. + But, if it's not one of these types, then we assume that any subtypes + of the non-"text/" types are binary data, where CRLF conversion would + corrupt it, so we use base64 right off the bat. + + The reason it's desirable to ship these as text instead of just using + base64 all the time is mainly to preserve the readability of them for + non-MIME users: if I mail a /bin/sh script to someone, it might not + need to be encoded at all, so we should leave it readable if we can. + + This list of types was derived from the comp.mail.mime FAQ, section + 10.2.2, "List of known unregistered MIME types" on 2-Feb-96. + */ + static const char *app_and_image_types_which_are_really_text[] = { + "application/mac-binhex40", /* APPLICATION_BINHEX */ + "application/pgp", /* APPLICATION_PGP */ + "application/x-pgp-message", /* APPLICATION_PGP2 */ + "application/postscript", /* APPLICATION_POSTSCRIPT */ + "application/x-uuencode", /* APPLICATION_UUENCODE */ + "application/x-uue", /* APPLICATION_UUENCODE2 */ + "application/uue", /* APPLICATION_UUENCODE4 */ + "application/uuencode", /* APPLICATION_UUENCODE3 */ + "application/sgml", + "application/x-csh", + "application/x-javascript", + "application/x-latex", + "application/x-macbinhex40", + "application/x-ns-proxy-autoconfig", + "application/x-www-form-urlencoded", + "application/x-perl", + "application/x-sh", + "application/x-shar", + "application/x-tcl", + "application/x-tex", + "application/x-texinfo", + "application/x-troff", + "application/x-troff-man", + "application/x-troff-me", + "application/x-troff-ms", + "application/x-troff-ms", + "application/x-wais-source", + "image/x-bitmap", + "image/x-pbm", + "image/x-pgm", + "image/x-portable-anymap", + "image/x-portable-bitmap", + "image/x-portable-graymap", + "image/x-portable-pixmap", /* IMAGE_PPM */ + "image/x-ppm", + "image/x-xbitmap", /* IMAGE_XBM */ + "image/x-xbm", /* IMAGE_XBM2 */ + "image/xbm", /* IMAGE_XBM3 */ + "image/x-xpixmap", + "image/x-xpm", + 0 }; + const char **s; + for (s = app_and_image_types_which_are_really_text; *s; s++) + if (!PL_strcasecmp (type, *s)) + return PR_FALSE; + + /* All others must be assumed to be binary formats, and need Base64. */ + return PR_TRUE; + } + + else + return PR_FALSE; +} + +// +// Some types should have a "charset=" parameter, and some shouldn't. +// This is what decides. +// +PRBool +mime_type_needs_charset (const char *type) +{ + /* Only text types should have charset. */ + if (!type || !*type) + return PR_FALSE; + else + if (!PL_strncasecmp (type, "text", 4)) + return PR_TRUE; + else + return PR_FALSE; +} + +// +// Generate headers for a form post to a mailto: URL. +// This lets the URL specify additional headers, but is careful to +// ignore headers which would be dangerous. It may modify the URL +// (because of CC) so a new URL to actually post to is returned. +// +int +nsMsgMIMEGenerateMailtoFormPostHeaders (const char *old_post_url, + const char * /*referer*/, + char **new_post_url_return, + char **headers_return) +{ + char *from = 0, *to = 0, *cc = 0, *body = 0, *search = 0; + char *extra_headers = 0; + char *s; + PRBool subject_p = PR_FALSE; + PRBool sign_p = PR_FALSE, encrypt_p = PR_FALSE; + char *rest; + int status = 0; + nsMsgCompFields *fields = NULL; + static const char *forbidden_headers[] = { + "Apparently-To", + "BCC", + "Content-Encoding", + HEADER_CONTENT_LENGTH, + "Content-Transfer-Encoding", + "Content-Type", + "Date", + "Distribution", + "FCC", + "Followup-To", + "From", + "Lines", + "MIME-Version", + "Message-ID", + "Newsgroups", + "Organization", + "Reply-To", + "Sender", + HEADER_X_MOZILLA_STATUS, + HEADER_X_MOZILLA_STATUS2, + HEADER_X_MOZILLA_NEWSHOST, + HEADER_X_UIDL, + "XRef", + 0 }; + + from = MIME_MakeFromField (CS_DEFAULT); + if (!from) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + to = NET_ParseURL (old_post_url, GET_PATH_PART); + if (!to) { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + if (!*to) + { + status = MK_MIME_NO_RECIPIENTS; /* rb -1; */ + goto FAIL; + } + + search = NET_ParseURL (old_post_url, GET_SEARCH_PART); + + rest = search; + if (rest && *rest == '?') + { + /* start past the '?' */ + rest++; + rest = XP_STRTOK (rest, "&"); + while (rest && *rest) + { + char *token = rest; + char *value = 0; + char *eq; + + rest = XP_STRTOK (0, "&"); + + eq = PL_strchr (token, '='); + if (eq) + { + value = eq+1; + *eq = 0; + } + + if (!PL_strcasecmp (token, "subject")) + subject_p = PR_TRUE; + + if (value) + /* Don't allow newlines or control characters in the value. */ + for (s = value; *s; s++) + if (*s < ' ' && *s != '\t') + *s = ' '; + + if (!PL_strcasecmp (token, "to")) + { + if (to && *to) + { + StrAllocCat (to, ", "); + StrAllocCat (to, value); + } + else + { + PR_FREEIF(to); + to = PL_strdup(value); + } + } + else if (!PL_strcasecmp (token, "cc")) + { + if (cc && *cc) + { + StrAllocCat (cc, ", "); + StrAllocCat (cc, value); + } + else + { + PR_FREEIF(cc); + cc = PL_strdup (value); + } + } + else if (!PL_strcasecmp (token, "body")) + { + if (body && *body) + { + StrAllocCat (body, "\n"); + StrAllocCat (body, value); + } + else + { + PR_FREEIF(body); + body = PL_strdup (value); + } + } + else if (!PL_strcasecmp (token, "encrypt") || + !PL_strcasecmp (token, "encrypted")) + { + encrypt_p = (!PL_strcasecmp(value, "true") || + !PL_strcasecmp(value, "yes")); + } + else if (!PL_strcasecmp (token, "sign") || + !PL_strcasecmp (token, "signed")) + { + sign_p = (!PL_strcasecmp(value, "true") || + !PL_strcasecmp(value, "yes")); + } + else + { + const char **fh = forbidden_headers; + PRBool ok = PR_TRUE; + while (*fh) + if (!PL_strcasecmp (token, *fh++)) + { + ok = PR_FALSE; + break; + } + if (ok) + { + PRBool upper_p = PR_FALSE; + char *s; + for (s = token; *s; s++) + { + if (*s >= 'A' && *s <= 'Z') + upper_p = PR_TRUE; + else if (*s <= ' ' || *s >= '~' || *s == ':') + goto NOT_OK; /* bad character in header! */ + } + if (!upper_p && *token >= 'a' && *token <= 'z') + *token -= ('a' - 'A'); + + StrAllocCat (extra_headers, token); + StrAllocCat (extra_headers, ": "); + if (value) + StrAllocCat (extra_headers, value); + StrAllocCat (extra_headers, CRLF); + NOT_OK: ; + } + } + } + } + + if (!subject_p) + { + char* sAppName = nsnull; + nsresult rv = NS_OK; + NS_WITH_SERVICE(nsINetService, pNetService, kNetServiceCID, &rv); + + if (NS_SUCCEEDED(rv) && pNetService) + { + nsString aNSStr; + + pNetService->GetAppCodeName(aNSStr); + sAppName = aNSStr.ToNewCString(); + } + /* If the URL didn't provide a subject, we will. */ + StrAllocCat (extra_headers, "Subject: Form posted from "); + NS_ASSERTION (sAppName, "null XP_AppCodeName"); + StrAllocCat (extra_headers, sAppName); + StrAllocCat (extra_headers, CRLF); + } + + /* Note: the `encrypt', `sign', and `body' parameters are currently + ignored in mailto form submissions. */ + + *new_post_url_return = 0; + + /*JFD + nsMsgCompPrefs pCompPrefs; + fields = MSG_CreateCompositionFields(from, 0, to, cc, 0, 0, 0, 0, + (char *)pCompPrefs.GetOrganization(), 0, 0, + extra_headers, 0, 0, 0, + encrypt_p, sign_p); + */ + if (!fields) + { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + fields->SetDefaultBody(body, NULL); + + *headers_return = mime_generate_headers (fields, 0, nsMsgDeliverNow); + if (*headers_return == 0) + { + status = MK_OUT_OF_MEMORY; + goto FAIL; + } + + StrAllocCat ((*new_post_url_return), "mailto:"); + if (to) + StrAllocCat ((*new_post_url_return), to); + if (to && cc) + StrAllocCat ((*new_post_url_return), ","); + if (cc) + StrAllocCat ((*new_post_url_return), cc); + + FAIL: + PR_FREEIF (from); + PR_FREEIF (to); + PR_FREEIF (cc); + PR_FREEIF (body); + PR_FREEIF (search); + PR_FREEIF (extra_headers); + /*JFD + if (fields) + MSG_DestroyCompositionFields(fields); +*/ + + return status; +} + +/* Given a string, convert it to 'qtext' (quoted text) for RFC822 header purposes. */ +char * +msg_make_filename_qtext(const char *srcText, PRBool stripCRLFs) +{ + /* newString can be at most twice the original string (every char quoted). */ + char *newString = (char *) PR_Malloc(PL_strlen(srcText)*2 + 1); + if (!newString) return NULL; + + const char *s = srcText; + const char *end = srcText + PL_strlen(srcText); + char *d = newString; + + while(*s) + { + /* Put backslashes in front of existing backslashes, or double quote + characters. + If stripCRLFs is true, don't write out CRs or LFs. Otherwise, + write out a backslash followed by the CR but not + linear-white-space. + We might already have quoted pair of "\ " or "\\t" skip it. + */ + if (*s == '\\' || *s == '"' || + (!stripCRLFs && + (*s == CR && (*(s+1) != LF || + (*(s+1) == LF && (s+2) < end && !IS_SPACE(*(s+2))))))) + *d++ = '\\'; + + if (*s == CR) + { + if (stripCRLFs && *(s+1) == LF && (s+2) < end && IS_SPACE(*(s+2))) + s += 2; // skip CRLFLWSP + } + else + { + *d++ = *s; + } + s++; + } + *d = 0; + + return newString; +} + +/* Rip apart the URL and extract a reasonable value for the `real_name' slot. + */ +void +msg_pick_real_name (nsMsgAttachmentHandler *attachment, const char *charset) +{ + nsresult rv; + NS_WITH_SERVICE(nsIPref, prefs, kPrefCID, &rv); + const char *s, *s2; + char *s3; + char *url; + + if (attachment->m_real_name) + return; + + url = attachment->m_url_string; + + /* Perhaps the MIME parser knows a better name than the URL itself? + This can happen when one attaches a MIME part from one message + directly into another message. + + ### mwelch Note that this function simply duplicates and returns an existing + MIME header, so we don't need to process it. */ + attachment->m_real_name = + MimeGuessURLContentName(attachment->m_mime_delivery_state->GetContext(), + url); + if (attachment->m_real_name) + return; + + /* Otherwise, extract a name from the URL. */ + + s = url; + s2 = PL_strchr (s, ':'); + if (s2) s = s2 + 1; + /* If we know the URL doesn't have a sensible file name in it, + don't bother emitting a content-disposition. */ + if (!PL_strncasecmp (url, "news:", 5) || + !PL_strncasecmp (url, "snews:", 6) || + !PL_strncasecmp (url, "IMAP:", 5) || + !PL_strncasecmp (url, "mailbox:", 8)) + return; + + /* Take the part of the file name after the last / or \ */ + s2 = PL_strrchr (s, '/'); + if (s2) s = s2+1; + s2 = PL_strrchr (s, '\\'); + +#if 0 +//TODO: convert to unicode to do the truncation + if (csid & MULTIBYTE) + { + // We don't want to truncate the file name in case of the double + // byte file name + while ( s2 != NULL && + s2 > s && + nsMsgI18NIsLeadByte(csid, *(s2-1))) + { + s3 = (char *) s2; + *s3 = 0; + s2 = PL_strrchr(s, '\\'); + *s3 = '\\'; + } + } +#endif + + if (s2) s = s2+1; + /* Copy it into the attachment struct. */ + PR_FREEIF(attachment->m_real_name); + attachment->m_real_name = PL_strdup (s); + /* Now trim off any named anchors or search data. */ + s3 = PL_strchr (attachment->m_real_name, '?'); + if (s3) *s3 = 0; + s3 = PL_strchr (attachment->m_real_name, '#'); + if (s3) *s3 = 0; + + /* Now lose the %XX crap. */ + nsUnescape (attachment->m_real_name); + + PRInt32 parmFolding = 0; + if (NS_SUCCEEDED(rv) && prefs) + prefs->GetIntPref("mail.strictly_mime.parm_folding", &parmFolding); + + if (parmFolding == 0 || parmFolding == 1) + { + /* Try to MIME-2 encode the filename... */ + char *mime2Name = nsMsgI18NEncodeMimePartIIStr(attachment->m_real_name, charset, + nsMsgMIMEGetConformToStandard()); + if (mime2Name && (mime2Name != attachment->m_real_name)) + { + PR_Free(attachment->m_real_name); + attachment->m_real_name = mime2Name; + } + + /* ... and then put backslashes before special characters (RFC 822 tells us + to). */ + + char *qtextName = NULL; + + qtextName = msg_make_filename_qtext(attachment->m_real_name, + (parmFolding == 0 ? PR_TRUE : PR_FALSE)); + + if (qtextName) + { + PR_Free(attachment->m_real_name); + attachment->m_real_name = qtextName; + } + } + + /* Now a special case for attaching uuencoded files... + + If we attach a file "foo.txt.uu", we will send it out with + Content-Type: text/plain; Content-Transfer-Encoding: x-uuencode. + When saving such a file, a mail reader will generally decode it first + (thus removing the uuencoding.) So, let's make life a little easier by + removing the indication of uuencoding from the file name itself. (This + will presumably make the file name in the Content-Disposition header be + the same as the file name in the "begin" line of the uuencoded data.) + + However, since there are mailers out there (including earlier versions of + Mozilla) that will use "foo.txt.uu" as the file name, we still need to + cope with that; the code which copes with that is in the MIME parser, in + libmime/mimei.c. + */ + if (attachment->m_already_encoded_p && + attachment->m_encoding) + { + char *result = attachment->m_real_name; + PRInt32 L = PL_strlen(result); + const char **exts = 0; + + /* #### TOTAL KLUDGE. + I'd like to ask the mime.types file, "what extensions correspond + to obj->encoding (which happens to be "x-uuencode") but doing that + in a non-sphagetti way would require brain surgery. So, since + currently uuencode is the only content-transfer-encoding which we + understand which traditionally has an extension, we just special- + case it here! + + Note that it's special-cased in a similar way in libmime/mimei.c. + */ + if (!PL_strcasecmp(attachment->m_encoding, ENCODING_UUENCODE) || + !PL_strcasecmp(attachment->m_encoding, ENCODING_UUENCODE2) || + !PL_strcasecmp(attachment->m_encoding, ENCODING_UUENCODE3) || + !PL_strcasecmp(attachment->m_encoding, ENCODING_UUENCODE4)) + { + static const char *uue_exts[] = { "uu", "uue", 0 }; + exts = uue_exts; + } + + while (exts && *exts) + { + const char *ext = *exts; + PRInt32 L2 = PL_strlen(ext); + if (L > L2 + 1 && /* long enough */ + result[L - L2 - 1] == '.' && /* '.' in right place*/ + !PL_strcasecmp(ext, result + (L - L2))) /* ext matches */ + { + result[L - L2 - 1] = 0; /* truncate at '.' and stop. */ + break; + } + exts++; + } + } +} diff --git a/mailnews/compose/src/nsMsgUtils.h b/mailnews/compose/src/nsMsgUtils.h new file mode 100644 index 000000000000..b654c2bd6eeb --- /dev/null +++ b/mailnews/compose/src/nsMsgUtils.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgUtils_H_ +#define _nsMsgUtils_H_ + +#include "nscore.h" +#include "nsMsgSend.h" +#include "nsFileSpec.h" +#include "nsMsgCompFields.h" +#include "nsIMsgSend.h" + +NS_BEGIN_EXTERN_C + +// +// Create a file spec or file name using the name passed +// in as a template +// +nsFileSpec *nsMsgCreateTempFileSpec(char *tFileName); +char *nsMsgCreateTempFileName(char *tFileName); + + +// +// Various utilities for building parts of MIME encoded +// messages during message composition +// +int 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*/); + +char *mime_generate_headers (nsMsgCompFields *fields, + const char *charset, + nsMsgDeliverMode deliver_mode); + +char *mime_make_separator(const char *prefix); + +char *mime_generate_attachment_headers (const char *type, + const char *encoding, + const char *description, + const char *x_mac_type, + const char *x_mac_creator, + const char *real_name, + const char *base_url, + PRBool digest_p, + nsMsgAttachmentHandler *ma, + const char *charset); + +char *msg_generate_message_id (void); + +char *RFC2231ParmFolding(const char *parmName, const char *charset, + const char *language, const char *parmValue); + +PRBool mime_7bit_data_p (const char *string, PRUint32 size); + +char *mime_fix_header_1 (const char *string, PRBool addr_p, PRBool 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); + +PRBool mime_type_requires_b64_p (const char *type); +PRBool mime_type_needs_charset (const char *type); + +int nsMsgMIMEGenerateMailtoFormPostHeaders (const char *old_post_url, + const char * /*referer*/, + char **new_post_url_return, + char **headers_return); + +char *msg_make_filename_qtext(const char *srcText, PRBool stripCRLFs); + +// Rip apart the URL and extract a reasonable value for the `real_name' slot. +void msg_pick_real_name (nsMsgAttachmentHandler *attachment, const char *charset); + +// +// Informational calls... +// +void nsMsgMIMESetConformToStandard (PRBool conform_p); +PRBool nsMsgMIMEGetConformToStandard (void); + + +NS_END_EXTERN_C + + +#endif /* _nsMsgUtils_H_ */ + diff --git a/mailnews/compose/src/nsMsgZapIt.cpp b/mailnews/compose/src/nsMsgZapIt.cpp new file mode 100644 index 000000000000..5166b112b30e --- /dev/null +++ b/mailnews/compose/src/nsMsgZapIt.cpp @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "msgCore.h" +#include "nsMsgZapIt.h" +#include "nsCRT.h" + +#if defined(XP_OS2) && defined(__DEBUG_ALLOC__) +void* nsMsgZapIt::operator new(size_t size, const char *file, size_t line) { + void* rv = ::operator new(size, file, line); + if (rv) { + nsCRT::memset(rv, 0, size); + } + return rv; +} +#else +void* nsMsgZapIt::operator new(size_t size) { + void* rv = ::operator new(size); + if (rv) { + nsCRT::memset(rv, 0, size); + } + return rv; +} + +#endif + \ No newline at end of file diff --git a/mailnews/compose/src/nsMsgZapIt.h b/mailnews/compose/src/nsMsgZapIt.h new file mode 100644 index 000000000000..f3c005b8f182 --- /dev/null +++ b/mailnews/compose/src/nsMsgZapIt.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef _nsMsgZapIt_H_ +#define _nsMsgZapIt_H_ + +// The whole purpose of this class is to redefine operator new for any subclass +// so that it will automatically zero out the whole class for me; thanks. + +class nsMsgZapIt { +public: +#if defined(XP_OS2) && defined(__DEBUG_ALLOC__) + static void* operator new(size_t size, const char *file, size_t line); +#else + static void* operator new(size_t size); +#endif +}; + + + +#endif /* _nsMsgZapIt_H_ */ diff --git a/mailnews/compose/tests/compose/test.cpp b/mailnews/compose/tests/compose/test.cpp index 693e6a9a7aa2..0f7fb7978b91 100644 --- a/mailnews/compose/tests/compose/test.cpp +++ b/mailnews/compose/tests/compose/test.cpp @@ -17,6 +17,9 @@ #include "nsIServiceManager.h" #include "nscore.h" #include "nsIMsgMailSession.h" +#include "nsINetSupportDialogService.h" +#include "nsIAppShellService.h" +#include "nsAppShellCIDs.h" #include "nsINetService.h" @@ -35,6 +38,7 @@ #include "prmem.h" #include "nsIMimeURLUtils.h" +#include "nsMsgSendLater.h" #ifdef XP_PC @@ -64,8 +68,8 @@ static NS_DEFINE_CID(kNetServiceCID, NS_NETSERVICE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kSmtpServiceCID, NS_SMTPSERVICE_CID); -static NS_DEFINE_IID(kFileLocatorCID, NS_FILELOCATOR_CID); -static NS_DEFINE_IID(kEventQueueCID, NS_EVENTQUEUE_CID); +static NS_DEFINE_CID(kFileLocatorCID, NS_FILELOCATOR_CID); +static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); static NS_DEFINE_IID(kIMsgComposeIID, NS_IMSGCOMPOSE_IID); static NS_DEFINE_CID(kCMsgMailSessionCID, NS_MSGMAILSESSION_CID); static NS_DEFINE_CID(kMsgComposeCID, NS_MSGCOMPOSE_CID); @@ -75,6 +79,29 @@ static NS_DEFINE_IID(kIMsgSendIID, NS_IMSGSEND_IID); static NS_DEFINE_CID(kMsgSendCID, NS_MSGSEND_CID); static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); static NS_DEFINE_CID(kMimeURLUtilsCID, NS_IMIME_URLUTILS_CID); +static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); +static NS_DEFINE_CID(kAppShellServiceCID, NS_APPSHELL_SERVICE_CID); +static NS_DEFINE_IID(kIAppShellServiceIID, NS_IAPPSHELL_SERVICE_IID); + + +static NS_DEFINE_IID(kIMsgSendLaterIID, NS_IMSGSENDLATER_IID); +static NS_DEFINE_CID(kMsgSendLaterCID, NS_MSGSENDLATER_CID); + + +void +DoIT() +{ + nsresult rv = NS_OK; + nsIMsgSendLater *pMsgSendLater; + + rv = nsComponentManager::CreateInstance(kMsgSendLaterCID, NULL, kIMsgSendLaterIID, (void **) &pMsgSendLater); + if (rv == NS_OK && pMsgSendLater) + { + printf("We succesfully obtained a nsIMsgSendLater interface....\n"); + nsIMsgIdentity *identity = nsnull; + pMsgSendLater->SendUnsentMessages(identity, "Outbox", "nsmail-2"); + } +} nsresult OnIdentityCheck() { @@ -119,8 +146,8 @@ GetAttachments(void) return NULL; nsCRT::memset(attachments, 0, sizeof(MSG_AttachedFile) * 2); - attachments[0].orig_url = PL_strdup("file://C:/big.bmp"); - attachments[0].file_name = PL_strdup("C:\\big.bmp"); + attachments[0].orig_url = PL_strdup("file://C:/boxster.jpg"); + attachments[0].file_name = PL_strdup("C:\\boxster.jpg"); attachments[0].type = PL_strdup("image/jpeg"); attachments[0].encoding = PL_strdup(ENCODING_BINARY); attachments[0].description = PL_strdup("Boxster Image"); @@ -150,6 +177,7 @@ int main(int argc, char *argv[]) nsIMsgCompFields *pMsgCompFields; nsIMsgSend *pMsgSend; nsresult rv = NS_OK; + nsIAppShellService* appShell = nsnull; nsComponentManager::RegisterComponent(kNetServiceCID, NULL, NULL, NETLIB_DLL, PR_FALSE, PR_FALSE); nsComponentManager::RegisterComponent(kEventQueueServiceCID, NULL, NULL, XPCOM_DLL, PR_FALSE, PR_FALSE); @@ -157,6 +185,19 @@ int main(int argc, char *argv[]) nsComponentManager::RegisterComponent(kPrefCID, nsnull, nsnull, PREF_DLL, PR_TRUE, PR_TRUE); nsComponentManager::RegisterComponent(kFileLocatorCID, NULL, NULL, APPSHELL_DLL, PR_FALSE, PR_FALSE); nsComponentManager::RegisterComponent(kMimeURLUtilsCID, NULL, NULL, MIME_DLL, PR_FALSE, PR_FALSE); + nsComponentManager::RegisterComponent(kNetSupportDialogCID, NULL, NULL, APPSHELL_DLL, PR_FALSE, PR_FALSE); + nsComponentManager::RegisterComponent(kAppShellServiceCID, NULL, NULL, APPSHELL_DLL, PR_FALSE, PR_FALSE); + + /* + * Create the Application Shell instance... + */ + nsIWebShellWindow* newWindow; + rv = nsServiceManager::GetService(kAppShellServiceCID, + kIAppShellServiceIID, + (nsISupports**)&appShell); + if (NS_SUCCEEDED(rv)) + appShell->CreateTopLevelWindow(nsnull, nsnull, PR_TRUE, newWindow, + nsnull, nsnull, 200, 200); // Create the Event Queue for this thread... NS_WITH_SERVICE(nsIEventQueueService, pEventQService, kEventQueueServiceCID, &rv); @@ -195,6 +236,8 @@ int main(int argc, char *argv[]) OnIdentityCheck(); + DoIT(); + rv = nsComponentManager::CreateInstance(kMsgCompFieldsCID, NULL, nsIMsgCompFields::GetIID(), (void **) &pMsgCompFields); if (rv == NS_OK && pMsgCompFields) { @@ -236,7 +279,7 @@ int main(int argc, char *argv[]) else nBodyLength = 0; - // nsMsgAttachmentData *ptr = GetAttachments(); + //nsMsgAttachedFile *ptr = NULL; nsMsgAttachedFile *ptr = GetAttachments(); pMsgSend->SendMessage(pMsgCompFields,