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