Back to index

lightning-sunbird  0.9+nobinonly
nsOutlookCompose.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "nscore.h"
00041 #include "prthread.h"
00042 #include "nsString.h"
00043 #include "nsReadableUtils.h"
00044 #include "nsUnicharUtils.h"
00045 #include "nsCOMPtr.h"
00046 #include "nsIFileSpec.h"
00047 #include "nsIComponentManager.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsIIOService.h"
00050 #include "nsIURI.h"
00051 #include "nsIProxyObjectManager.h"
00052 #include "nsProxiedService.h"
00053 #include "nsMsgI18N.h"
00054 #include "nsNativeCharsetUtils.h"
00055 
00056 #include "nsMsgBaseCID.h"
00057 #include "nsMsgCompCID.h"
00058 
00059 #include "nsIMsgCompose.h"
00060 #include "nsIMsgCompFields.h"
00061 #include "nsIMsgSend.h"
00062 #include "nsIMsgMailSession.h"
00063 #include "nsIMsgAccountManager.h"
00064 
00065 #include "nsNetCID.h"
00066 
00067 #include "nsOutlookCompose.h"
00068 
00069 #include "OutlookDebugLog.h"
00070 
00071 #include "nsMimeTypes.h"
00072 #include "nsMsgUtils.h"
00073 
00074 static NS_DEFINE_CID( kMsgSendCID, NS_MSGSEND_CID);
00075 static NS_DEFINE_CID( kMsgCompFieldsCID, NS_MSGCOMPFIELDS_CID); 
00076 static NS_DEFINE_CID( kIOServiceCID, NS_IOSERVICE_CID);
00077 static NS_DEFINE_CID( kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
00078 
00079 
00080 // We need to do some calculations to set these numbers to something reasonable!
00081 // Unless of course, CreateAndSendMessage will NEVER EVER leave us in the lurch
00082 #define kHungCount          100000
00083 #define kHungAbortCount     1000
00084 
00085 
00086 #ifdef IMPORT_DEBUG
00087 static char *p_test_headers = 
00088 "Received: from netppl.fi (IDENT:monitor@get.freebsd.because.microsoftsucks.net [209.3.31.115])\n\
00089        by mail4.sirius.com (8.9.1/8.9.1) with SMTP id PAA27232;\n\
00090        Mon, 17 May 1999 15:27:43 -0700 (PDT)\n\
00091 Message-ID: <ikGD3jRTsKklU.Ggm2HmE2A1Jsqd0p@netppl.fi>\n\
00092 From: \"adsales@qualityservice.com\" <adsales@qualityservice.com>\n\
00093 Subject: Re: Your College Diploma (36822)\n\
00094 Date: Mon, 17 May 1999 15:09:29 -0400 (EDT)\n\
00095 MIME-Version: 1.0\n\
00096 Content-Type: TEXT/PLAIN; charset=\"US-ASCII\"\n\
00097 Content-Transfer-Encoding: 7bit\n\
00098 X-UIDL: 19990517.152941\n\
00099 Status: RO";
00100 
00101 static char *p_test_body = 
00102 "Hello world?\n\
00103 ";
00104 #else
00105 #define       p_test_headers       nsnull
00106 #define       p_test_body nsnull
00107 #endif
00108 
00109 
00110 #define kWhitespace  "\b\t\r\n "
00111 
00112 
00113 // First off, a listener
00114 class OutlookSendListener : public nsIMsgSendListener
00115 {
00116 public:
00117        OutlookSendListener() {
00118               m_done = PR_FALSE;
00119               m_location = nsnull;
00120        }
00121 
00122        virtual ~OutlookSendListener() { NS_IF_RELEASE( m_location); }
00123 
00124        // nsISupports interface
00125        NS_DECL_ISUPPORTS
00126 
00127        /* void OnStartSending (in string aMsgID, in PRUint32 aMsgSize); */
00128        NS_IMETHOD OnStartSending(const char *aMsgID, PRUint32 aMsgSize) {return NS_OK;}
00129 
00130        /* void OnProgress (in string aMsgID, in PRUint32 aProgress, in PRUint32 aProgressMax); */
00131        NS_IMETHOD OnProgress(const char *aMsgID, PRUint32 aProgress, PRUint32 aProgressMax) {return NS_OK;}
00132 
00133        /* void OnStatus (in string aMsgID, in wstring aMsg); */
00134        NS_IMETHOD OnStatus(const char *aMsgID, const PRUnichar *aMsg) {return NS_OK;}
00135 
00136        /* void OnStopSending (in string aMsgID, in nsresult aStatus, in wstring aMsg, in nsIFileSpec returnFileSpec); */
00137        NS_IMETHOD OnStopSending(const char *aMsgID, nsresult aStatus, const PRUnichar *aMsg, 
00138                                              nsIFileSpec *returnFileSpec) {
00139               m_done = PR_TRUE;
00140               m_location = returnFileSpec;
00141               NS_IF_ADDREF( m_location);
00142               return NS_OK;
00143        }
00144 
00145    /* void OnSendNotPerformed */
00146    NS_IMETHOD OnSendNotPerformed(const char *aMsgID, nsresult aStatus) {return NS_OK;}
00147 
00148   /* void OnGetDraftFolderURI (); */
00149   NS_IMETHOD OnGetDraftFolderURI(const char *aFolderURI) {return NS_OK;}
00150 
00151        static nsresult CreateSendListener( nsIMsgSendListener **ppListener);
00152 
00153        void Reset() { m_done = PR_FALSE; NS_IF_RELEASE( m_location); m_location = nsnull;}
00154 
00155 public:
00156        PRBool               m_done;
00157        nsIFileSpec * m_location;
00158 };
00159 
00160 
00161 NS_IMPL_THREADSAFE_ISUPPORTS1( OutlookSendListener, nsIMsgSendListener)
00162 
00163 nsresult OutlookSendListener::CreateSendListener( nsIMsgSendListener **ppListener)
00164 {
00165     NS_PRECONDITION(ppListener != nsnull, "null ptr");
00166     if (! ppListener)
00167         return NS_ERROR_NULL_POINTER;
00168 
00169     *ppListener = new OutlookSendListener();
00170     if (! *ppListener)
00171         return NS_ERROR_OUT_OF_MEMORY;
00172 
00173     NS_ADDREF(*ppListener);
00174     return NS_OK;
00175 }
00176 
00177 
00182 
00183 
00184 
00185 nsOutlookCompose::nsOutlookCompose()
00186 {
00187        m_pIOService = nsnull;
00188        m_pAttachments = nsnull;
00189        m_pListener = nsnull;
00190        m_pMsgSend = nsnull;
00191        m_pSendProxy = nsnull;
00192        m_pMsgFields = nsnull;
00193        m_pIdentity = nsnull;
00194 #ifdef IMPORT_DEBUG
00195        m_Headers = p_test_headers;
00196        m_Body = p_test_body;
00197 #endif
00198 
00199        m_readHeaders.m_convertCRs = PR_TRUE;
00200 }
00201 
00202 
00203 nsOutlookCompose::~nsOutlookCompose()
00204 {
00205        NS_IF_RELEASE( m_pSendProxy);
00206        NS_IF_RELEASE( m_pIOService);
00207        NS_IF_RELEASE( m_pMsgSend);
00208        NS_IF_RELEASE( m_pListener);
00209        NS_IF_RELEASE( m_pMsgFields);
00210        if (m_pIdentity) {   
00211               nsresult rv = m_pIdentity->ClearAllValues();
00212         NS_ASSERTION(NS_SUCCEEDED(rv),"failed to clear values");
00213               if (NS_FAILED(rv)) return;
00214 
00215               NS_WITH_PROXIED_SERVICE(nsIMsgAccountManager, accMgr, NS_MSGACCOUNTMANAGER_CONTRACTID, NS_UI_THREAD_EVENTQ, &rv);
00216         NS_ASSERTION(NS_SUCCEEDED(rv) && accMgr,"failed to get account manager");
00217               if (NS_FAILED(rv) || !accMgr) return;
00218 
00219               rv = accMgr->RemoveIdentity(m_pIdentity);
00220         NS_ASSERTION(NS_SUCCEEDED(rv),"failed to remove identity");
00221               if (NS_FAILED(rv)) return;
00222 
00223            NS_RELEASE(m_pIdentity);
00224        }
00225 }
00226 
00227 nsresult nsOutlookCompose::CreateIdentity( void)
00228 {
00229        if (m_pIdentity)
00230               return( NS_OK);
00231 
00232        nsresult      rv;
00233     NS_WITH_PROXIED_SERVICE(nsIMsgAccountManager, accMgr, NS_MSGACCOUNTMANAGER_CONTRACTID, NS_UI_THREAD_EVENTQ, &rv);
00234     if (NS_FAILED(rv)) return( rv);
00235        rv = accMgr->CreateIdentity( &m_pIdentity);
00236        nsString      name;
00237        name.AssignLiteral("Import Identity");
00238        if (m_pIdentity) {
00239               m_pIdentity->SetFullName( name.get());
00240               m_pIdentity->SetIdentityName( name.get());
00241               m_pIdentity->SetEmail( "import@import.service");
00242        }
00243        
00244        return( rv);
00245 }
00246 
00247 nsresult nsOutlookCompose::CreateComponents( void)
00248 {
00249        nsresult      rv = NS_OK;
00250        
00251        if (!m_pIOService) {
00252               IMPORT_LOG0( "Creating nsIOService\n");
00253 
00254               NS_WITH_PROXIED_SERVICE(nsIIOService, service, kIOServiceCID, NS_UI_THREAD_EVENTQ, &rv);
00255               if (NS_FAILED(rv)) 
00256                      return( rv);
00257               m_pIOService = service;
00258               NS_IF_ADDREF( m_pIOService);
00259        }
00260        
00261        NS_IF_RELEASE( m_pMsgFields);
00262        if (!m_pMsgSend) {
00263               rv = CallCreateInstance( kMsgSendCID, &m_pMsgSend); 
00264               if (NS_SUCCEEDED( rv) && m_pMsgSend) {
00265                      nsCOMPtr<nsIProxyObjectManager> proxyMgr = 
00266                               do_GetService(kProxyObjectManagerCID, &rv);
00267                      if (NS_SUCCEEDED(rv)) {
00268                             rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgSend),
00269                                                                       m_pMsgSend, PROXY_SYNC, (void **)&m_pSendProxy);
00270                             if (NS_FAILED( rv)) {
00271                                    m_pSendProxy = nsnull;
00272                             }
00273                      }
00274                      if (NS_FAILED( rv)) {
00275                             NS_RELEASE( m_pMsgSend);
00276                             m_pMsgSend = nsnull;
00277                      }
00278               }
00279        }
00280        if (!m_pListener && NS_SUCCEEDED( rv)) {
00281               rv = OutlookSendListener::CreateSendListener( &m_pListener);
00282        }
00283 
00284        if (NS_SUCCEEDED(rv) && m_pMsgSend) { 
00285            rv = CallCreateInstance( kMsgCompFieldsCID, &m_pMsgFields); 
00286               if (NS_SUCCEEDED(rv) && m_pMsgFields) {
00287                      // IMPORT_LOG0( "nsOutlookCompose - CreateComponents succeeded\n");
00288                      m_pMsgFields->SetForcePlainText( PR_FALSE);
00289                      return( NS_OK);
00290               }
00291        }
00292 
00293        return( NS_ERROR_FAILURE);
00294 }
00295 
00296 void nsOutlookCompose::GetNthHeader( const char *pData, PRInt32 dataLen, PRInt32 n, nsCString& header, nsCString& val, PRBool unwrap)
00297 {
00298        header.Truncate();
00299        val.Truncate();
00300        if (!pData)
00301               return;
00302 
00303        PRInt32       index = 0;
00304        PRInt32       len;
00305        PRInt32       start = 0;
00306        const char *pChar = pData;
00307        const char *pStart;
00308        if (n == 0) {
00309               pStart = pChar;
00310               len = 0;
00311               while ((start < dataLen) && (*pChar != ':')) {
00312                      start++;
00313                      len++;
00314                      pChar++;
00315               }
00316               header.Append( pStart, len);
00317               header.Trim( kWhitespace);
00318               start++;
00319               pChar++;
00320        }
00321        else {
00322               while (start < dataLen) {
00323                      if ((*pChar != ' ') && (*pChar != 9)) {
00324                             if (n == index) {
00325                                    pStart = pChar;
00326                                    len = 0;
00327                                    while ((start < dataLen) && (*pChar != ':')) {
00328                                           start++;
00329                                           len++;
00330                                           pChar++;
00331                                    }
00332                                    header.Append( pStart, len);
00333                                    header.Trim( kWhitespace);
00334                                    start++;
00335                                    pChar++;
00336                                    break;
00337                             }
00338                             else
00339                                    index++;
00340                      }
00341 
00342                      while ((start < dataLen) && (*pChar != 0x0D) && (*pChar != 0x0A)) {
00343                             start++;
00344                             pChar++;
00345                      }
00346                      while ((start < dataLen) && ((*pChar == 0x0D) || (*pChar == 0x0A))) {
00347                             start++;
00348                             pChar++;
00349                      }
00350               }
00351        }
00352 
00353        if (start >= dataLen)
00354               return;
00355 
00356        PRInt32              lineEnd;
00357        PRInt32              end = start;
00358        while (end < dataLen) {
00359               while ((end < dataLen) && (*pChar != 0x0D) && (*pChar != 0x0A)) {
00360                      end++;
00361                      pChar++;
00362               }
00363               if (end > start) {
00364                      val.Append( pData + start, end - start);
00365               }
00366               
00367               lineEnd = end;
00368               pStart = pChar;
00369               while ((end < dataLen) && ((*pChar == 0x0D) || (*pChar == 0x0A))) {
00370                      end++;
00371                      pChar++;
00372               }
00373               
00374               start = end;
00375 
00376               while ((end < dataLen) && ((*pChar == ' ') || (*pChar == '\t'))) {
00377                      end++;
00378                      pChar++;
00379               }
00380 
00381               if (start == end)
00382                      break;
00383               
00384               if (unwrap)
00385                      val.Append( ' ');
00386               else {
00387                      val.Append( pStart, end - lineEnd);
00388               }
00389 
00390               start = end;
00391        }
00392        
00393        val.Trim( kWhitespace);
00394 }
00395 
00396 
00397 void nsOutlookCompose::GetHeaderValue( const char *pData, PRInt32 dataLen, const char *pHeader, nsCString& val, PRBool unwrap)
00398 {
00399        val.Truncate();
00400        if (!pData)
00401               return;
00402 
00403        PRInt32       start = 0;
00404        PRInt32 len = strlen( pHeader);
00405        const char *pChar = pData;
00406        if (!nsCRT::strncasecmp( pHeader, pData, len)) {
00407               start = len;
00408        }
00409        else {
00410               while (start < dataLen) {
00411                      while ((start < dataLen) && (*pChar != 0x0D) && (*pChar != 0x0A)) {
00412                             start++;
00413                             pChar++;
00414                      }
00415                      while ((start < dataLen) && ((*pChar == 0x0D) || (*pChar == 0x0A))) {
00416                             start++;
00417                             pChar++;
00418                      }
00419                      if ((start < dataLen) && !nsCRT::strncasecmp( pChar, pHeader, len))
00420                             break;
00421               }
00422               if (start < dataLen)
00423                      start += len;
00424        }
00425 
00426        if (start >= dataLen)
00427               return;
00428 
00429        PRInt32                     end = start;
00430        PRInt32                     lineEnd;
00431        const char *  pStart;
00432 
00433        pChar =              pData + start;
00434 
00435        while (end < dataLen) {
00436               while ((end < dataLen) && (*pChar != 0x0D) && (*pChar != 0x0A)) {
00437                      end++;
00438                      pChar++;
00439               }
00440               if (end > start) {
00441                      val.Append( pData + start, end - start);
00442               }
00443               
00444               lineEnd = end;
00445               pStart = pChar;
00446               while ((end < dataLen) && ((*pChar == 0x0D) || (*pChar == 0x0A))) {
00447                      end++;
00448                      pChar++;
00449               }
00450               
00451               start = end;
00452 
00453               while ((end < dataLen) && ((*pChar == ' ') || (*pChar == '\t'))) {
00454                      end++;
00455                      pChar++;
00456               }
00457 
00458               if (start == end)
00459                      break;
00460               
00461               if (unwrap)
00462                      val.Append( ' ');
00463               else {
00464                      val.Append( pStart, end - lineEnd);
00465               }
00466 
00467               start = end;
00468        }
00469               
00470        val.Trim( kWhitespace);
00471 }
00472 
00473 
00474 void nsOutlookCompose::ExtractCharset( nsString& str)
00475 {
00476        nsString      tStr;
00477        PRInt32 idx = str.Find( "charset=", PR_TRUE);
00478        if (idx != -1) {
00479               idx += 8;
00480               str.Right( tStr, str.Length() - idx);
00481               idx = tStr.FindChar( ';');
00482               if (idx != -1)
00483                      tStr.Left( str, idx);
00484               else
00485                      str = tStr;
00486               str.Trim( kWhitespace);
00487               if ((str.CharAt( 0) == '"') && (str.Length() > 2)) {
00488                      str.Mid( tStr, 1, str.Length() - 2);
00489                      str = tStr;
00490                      str.Trim( kWhitespace);
00491               }
00492        }
00493        else
00494               str.Truncate();
00495 }
00496 
00497 void nsOutlookCompose::ExtractType( nsString& str)
00498 {
00499        nsString      tStr;
00500        PRInt32       idx = str.FindChar( ';');
00501        if (idx != -1) {
00502               str.Left( tStr, idx);
00503               str = tStr;
00504        }
00505        str.Trim( kWhitespace);
00506 
00507        if ((str.CharAt( 0) == '"') && (str.Length() > 2)) {
00508               str.Mid( tStr, 1, str.Length() - 2);
00509               str = tStr;
00510               str.Trim( kWhitespace);
00511        }
00512 
00513        // if multipart then ignore it since no outlook message body is ever
00514        // valid multipart!
00515        if (str.Length() > 10) {
00516               str.Left( tStr, 10);
00517               if (tStr.LowerCaseEqualsLiteral("multipart/"))
00518                      str.Truncate();
00519        }
00520 }
00521 
00522 void nsOutlookCompose::CleanUpAttach( nsMsgAttachedFile *a, PRInt32 count)
00523 {
00524   for (PRInt32 i = 0; i < count; i++) 
00525   {
00526     a[i].orig_url=nsnull;
00527     if (a[i].type)
00528       nsCRT::free( a[i].type);
00529     if (a[i].description)
00530       nsCRT::free( a[i].description);
00531     if (a[i].encoding)
00532       nsCRT::free( a[i].encoding);
00533   }
00534   delete [] a;
00535 }
00536 
00537 nsMsgAttachedFile * nsOutlookCompose::GetLocalAttachments( void)
00538 {  
00539        /*
00540        nsIURI      *url = nsnull;
00541        */
00542 
00543        PRInt32              count = 0;
00544        if (m_pAttachments)
00545               count = m_pAttachments->Count();
00546        if (!count)
00547               return( nsnull);
00548 
00549        nsMsgAttachedFile *a = (nsMsgAttachedFile *) new nsMsgAttachedFile[count + 1];
00550        if (!a)
00551               return( nsnull);
00552        memset(a, 0, sizeof(nsMsgAttachedFile) * (count + 1));
00553        
00554        nsresult                    rv;
00555        nsXPIDLCString              urlStr;
00556        OutlookAttachment *  pAttach;
00557 
00558        for (PRInt32 i = 0; i < count; i++) {
00559               // nsMsgNewURL(&url, "file://C:/boxster.jpg");
00560               // a[i].orig_url = url;
00561 
00562               // NS_PRECONDITION( PR_FALSE, "Forced Break");
00563 
00564               pAttach = (OutlookAttachment *) m_pAttachments->ElementAt( i);
00565               a[i].file_spec = new nsFileSpec;
00566               pAttach->pAttachment->GetFileSpec( a[i].file_spec);
00567               urlStr.Adopt(0);
00568               pAttach->pAttachment->GetURLString(getter_Copies(urlStr));
00569               if (!urlStr) {
00570                      CleanUpAttach( a, count);
00571                      return( nsnull);
00572               }
00573               rv = m_pIOService->NewURI( urlStr, nsnull, nsnull, getter_AddRefs(a[i].orig_url));
00574               if (NS_FAILED( rv)) {
00575                      CleanUpAttach( a, count);
00576                      return( nsnull);
00577               }
00578 
00579               a[i].type = nsCRT::strdup( pAttach->mimeType);
00580               a[i].real_name = nsCRT::strdup( pAttach->description);
00581               a[i].encoding = nsCRT::strdup( ENCODING_BINARY);
00582        }
00583 
00584        return( a);
00585 }
00586 
00587 // Test a message send????
00588 nsresult nsOutlookCompose::SendTheMessage( nsIFileSpec *pMsg, nsMsgDeliverMode mode, nsCString &useThisCType)
00589 {
00590        nsresult      rv = CreateComponents();
00591        if (NS_SUCCEEDED( rv))
00592               rv = CreateIdentity();
00593        if (NS_FAILED( rv))
00594               return( rv);
00595        
00596        // IMPORT_LOG0( "Outlook Compose created necessary components\n");
00597 
00598        nsAutoString  bodyType;
00599        nsAutoString  charSet;
00600        nsAutoString  headerVal;
00601     nsCAutoString asciiHeaderVal;
00602 
00603        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "From:", headerVal);
00604        if (!headerVal.IsEmpty())
00605               m_pMsgFields->SetFrom( headerVal);
00606        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "To:", headerVal);
00607        if (!headerVal.IsEmpty())
00608               m_pMsgFields->SetTo( headerVal);
00609        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "Subject:", headerVal);
00610        if (!headerVal.IsEmpty())
00611               m_pMsgFields->SetSubject( headerVal);
00612        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "Content-type:", headerVal);
00613 
00614   // If callers pass in a content type then use it, else get it from the header.
00615   if (!useThisCType.IsEmpty())
00616     CopyASCIItoUTF16(useThisCType, bodyType);
00617   else
00618   {
00619        bodyType = headerVal;
00620        ExtractType( bodyType);
00621   }
00622        ExtractCharset( headerVal);
00623   // Use platform charset as default if the msg doesn't specify one
00624   // (ie, no 'charset' param in the Content-Type: header). As the last
00625   // resort we'll use the mail default charset.
00626   if (headerVal.IsEmpty())
00627   {
00628     headerVal.AssignWithConversion(nsMsgI18NFileSystemCharset());
00629     if (headerVal.IsEmpty())
00630     { // last resort
00631       nsXPIDLString defaultCharset;
00632       NS_GetLocalizedUnicharPreferenceWithDefault(nsnull, "mailnews.view_default_charset",
00633                                                   NS_LITERAL_STRING("ISO-8859-1"), defaultCharset);
00634       headerVal = defaultCharset;
00635     }
00636   }
00637   m_pMsgFields->SetCharacterSet( NS_LossyConvertUTF16toASCII(headerVal).get() );
00638   charSet = headerVal;
00639        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "CC:", headerVal);
00640        if (!headerVal.IsEmpty())
00641               m_pMsgFields->SetCc( headerVal);
00642        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "Message-ID:", headerVal);
00643        if (!headerVal.IsEmpty()) {
00644         LossyCopyUTF16toASCII(headerVal, asciiHeaderVal);
00645               m_pMsgFields->SetMessageId(asciiHeaderVal.get());
00646     }
00647        GetHeaderValue( m_Headers.get(), m_Headers.Length(), "Reply-To:", headerVal);
00648        if (!headerVal.IsEmpty())
00649               m_pMsgFields->SetReplyTo( headerVal);
00650 
00651        // what about all of the other headers?!?!?!?!?!?!
00652        char *pMimeType = nsnull;
00653        if (!bodyType.IsEmpty())
00654               pMimeType = ToNewCString(bodyType);
00655        
00656         if (!pMimeType)
00657           pMimeType = strdup ("text/plain");
00658        // IMPORT_LOG0( "Outlook compose calling CreateAndSendMessage\n");
00659        nsMsgAttachedFile *pAttach = GetLocalAttachments();
00660 
00661   // Do body conversion here
00662   nsString    uniBody;
00663   NS_CopyNativeToUnicode( m_Body, uniBody);
00664 
00665   nsCString body;
00666   rv = nsMsgI18NConvertFromUnicode( NS_LossyConvertUTF16toASCII(charSet).get(),
00667                                     uniBody, body);
00668   uniBody.Truncate();
00669 
00670        rv = m_pSendProxy->CreateAndSendMessage(
00671                     nsnull,                                 // no editor shell
00672                                                                       m_pIdentity,                  // dummy identity
00673                                                                                 nsnull,                         // account key
00674                                                                       m_pMsgFields,                 // message fields
00675                                                                       PR_FALSE,                              // digest = NO
00676                                                                       PR_TRUE,                               // dont_deliver = YES, make a file
00677                                                                       mode,                          // mode
00678                                                                       nsnull,                                       // no message to replace
00679                                                                       pMimeType,                           // body type
00680                     NS_FAILED(rv) ? m_Body.get() : body.get(), // body pointer
00681                     NS_FAILED(rv) ? m_Body.Length() : body.Length(),  // body length
00682                                                                       nsnull,                                       // remote attachment data
00683                                                                       pAttach,                               // local attachments
00684                                                                       nsnull,                                       // related part
00685                                                                       nsnull,                       // parent window
00686                                                                       nsnull,                       // progress listener
00687                                                                       m_pListener,                       // listener
00688                                                                       nsnull,                       // password
00689                                                                       EmptyCString(),               // originalMsgURI
00690                     nsnull);                      // message compose type
00691 
00692 
00693        // IMPORT_LOG0( "Returned from CreateAndSendMessage\n");
00694 
00695        if (pAttach)
00696               delete [] pAttach;
00697 
00698        OutlookSendListener *pListen = (OutlookSendListener *)m_pListener;
00699        if (NS_FAILED( rv)) {
00700               IMPORT_LOG1( "*** Error, CreateAndSendMessage FAILED: 0x%lx\n", rv);
00701        }
00702        else {
00703               // wait for the listener to get done!
00704               PRInt32       abortCnt = 0;
00705               PRInt32       cnt = 0;
00706               PRInt32       sleepCnt = 1;        
00707               while (!pListen->m_done && (abortCnt < kHungAbortCount)) {
00708                      PR_Sleep( sleepCnt);
00709                      cnt++;
00710                      if (cnt > kHungCount) {
00711                             abortCnt++;
00712                             sleepCnt *= 2;
00713                             cnt = 0;
00714                      }
00715               }
00716 
00717               if (abortCnt >= kHungAbortCount) {
00718                      IMPORT_LOG0( "**** Create and send message hung\n");
00719                      IMPORT_LOG1( "Headers: %s\n", m_Headers.get());
00720                      IMPORT_LOG1( "Body: %s\n", m_Body.get());
00721                      rv = NS_ERROR_FAILURE;
00722               }
00723 
00724        }
00725 
00726        if (pMimeType)
00727               nsCRT::free( pMimeType);
00728 
00729        if (pListen->m_location) {
00730               pMsg->FromFileSpec( pListen->m_location);
00731               rv = NS_OK;
00732        }
00733        else {
00734               rv = NS_ERROR_FAILURE;
00735               IMPORT_LOG0( "*** Error, Outlook compose unsuccessful\n");
00736        }
00737        
00738        pListen->Reset();
00739               
00740        return( rv);
00741 }
00742 
00743 
00744 PRBool SimpleBufferTonyRCopiedTwice::SpecialMemCpy( PRInt32 offset, const char *pData, PRInt32 len, PRInt32 *pWritten)
00745 {
00746        // Arg!!!!!  Mozilla can't handle plain CRs in any mail messages.  Particularly a 
00747        // problem with Eudora since it doesn't give a rats a**
00748        *pWritten = len;
00749        PRInt32       sz = offset + len;
00750        if (offset) {
00751               if ((m_pBuffer[offset - 1] == 0x0D) && (*pData != 0x0A)) {
00752                      sz++;
00753                      if (!Grow( sz)) return( PR_FALSE);
00754                      m_pBuffer[offset] = 0x0A;
00755                      offset++;
00756                      (*pWritten)++;
00757               }
00758        }
00759        while (len > 0) {
00760               if ((*pData == 0x0D) && (*(pData + 1) != 0x0A)) {
00761                      sz++;
00762                      if (!Grow( sz)) return( PR_FALSE);
00763                      m_pBuffer[offset] = 0x0D;
00764                      offset++;
00765                      m_pBuffer[offset] = 0x0A;                                                    
00766                      (*pWritten)++;
00767               }
00768               else {
00769                      m_pBuffer[offset] = *pData;
00770               }
00771               offset++;
00772               pData++;
00773               len--;
00774        }
00775        
00776        return( PR_TRUE);
00777 }
00778 
00779 nsresult nsOutlookCompose::ReadHeaders( ReadFileState *pState, SimpleBufferTonyRCopiedTwice& copy, SimpleBufferTonyRCopiedTwice& header)
00780 {
00781        // This should be the headers...
00782        header.m_writeOffset = 0;
00783 
00784        nsresult      rv;
00785        PRInt32              lineLen;
00786        PRInt32              endLen = -1;
00787        PRInt8        endBuffer = 0;
00788 
00789        while ((endLen = IsEndHeaders( copy)) == -1) {
00790               while ((lineLen = FindNextEndLine( copy)) == -1) {
00791                      copy.m_writeOffset = copy.m_bytesInBuf;
00792                      if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
00793                             IMPORT_LOG0( "*** ERROR, writing headers\n");
00794                             return( NS_ERROR_FAILURE);
00795                      }
00796                      if (NS_FAILED( rv = FillMailBuffer( pState, copy))) {
00797                             IMPORT_LOG0( "*** Error reading message headers\n");
00798                             return( rv);
00799                      }
00800                      if (!copy.m_bytesInBuf) {
00801                             IMPORT_LOG0( "*** Error, end of file while reading headers\n");
00802                             return( NS_ERROR_FAILURE);
00803                      }
00804               }
00805               copy.m_writeOffset += lineLen;
00806               if ((copy.m_writeOffset + 4) >= copy.m_bytesInBuf) {
00807                      if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
00808                             IMPORT_LOG0( "*** ERROR, writing headers 2\n");
00809                             return( NS_ERROR_FAILURE);
00810                      }
00811                      if (NS_FAILED( rv = FillMailBuffer( pState, copy))) {
00812                             IMPORT_LOG0( "*** Error reading message headers 2\n");
00813                             return( rv);
00814                      }
00815               }
00816        }
00817 
00818        if (!header.Write( copy.m_pBuffer, copy.m_writeOffset)) {
00819               IMPORT_LOG0( "*** Error writing final headers\n");
00820               return( NS_ERROR_FAILURE);
00821        }
00822        if (!header.Write( (const char *)&endBuffer, 1)) {
00823               IMPORT_LOG0( "*** Error writing header trailing null\n");
00824               return( NS_ERROR_FAILURE);
00825        }
00826 
00827        copy.m_writeOffset += endLen;
00828        
00829        return( NS_OK);
00830 }
00831 
00832 PRInt32 nsOutlookCompose::FindNextEndLine( SimpleBufferTonyRCopiedTwice& data)
00833 {
00834        PRInt32 len = data.m_bytesInBuf - data.m_writeOffset;
00835        if (!len)
00836               return( -1);
00837        PRInt32       count = 0;
00838        const char *pData = data.m_pBuffer + data.m_writeOffset;
00839        while (((*pData == 0x0D) || (*pData == 0x0A)) && (count < len)) {
00840               pData++;
00841               count++;
00842        }
00843        while ((*pData != 0x0D) && (*pData != 0x0A) && (count < len)) {
00844               pData++;
00845               count++;
00846        }
00847        
00848        if (count < len)
00849               return( count);
00850 
00851        return( -1);
00852 }
00853 
00854 PRInt32 nsOutlookCompose::IsEndHeaders( SimpleBufferTonyRCopiedTwice& data)
00855 {
00856        PRInt32 len = data.m_bytesInBuf - data.m_writeOffset;
00857        if (len < 2)
00858               return( -1);
00859        const char *pChar = data.m_pBuffer + data.m_writeOffset;
00860        if ((*pChar == 0x0D) && (*(pChar + 1) == 0x0D))
00861               return( 2);
00862 
00863        if (len < 4)
00864               return( -1);
00865        if ((*pChar == 0x0D) && (*(pChar + 1) == 0x0A) &&
00866               (*(pChar + 2) == 0x0D) && (*(pChar + 3) == 0x0A))
00867               return( 4);
00868 
00869        return( -1);
00870 }
00871 
00872 
00873 nsresult nsOutlookCompose::CopyComposedMessage( nsCString& fromLine, nsIFileSpec *pSrc, nsIFileSpec *pDst, SimpleBufferTonyRCopiedTwice& copy)
00874 {
00875        copy.m_bytesInBuf = 0;
00876        copy.m_writeOffset = 0;
00877        ReadFileState state;
00878        state.pFile = pSrc;
00879        state.offset = 0;
00880        state.size = 0;
00881        pSrc->GetFileSize( &state.size);
00882        if (!state.size) {
00883               IMPORT_LOG0( "*** Error, unexpected zero file size for composed message\n");
00884               return( NS_ERROR_FAILURE);
00885        }
00886 
00887        nsresult rv = pSrc->OpenStreamForReading();
00888        if (NS_FAILED( rv)) {
00889               IMPORT_LOG0( "*** Error, unable to open composed message file\n");
00890               return( NS_ERROR_FAILURE);
00891        }
00892        
00893        PRInt32 written;
00894        rv = pDst->Write( fromLine.get(), fromLine.Length(), &written);
00895 
00896        // well, isn't this a hoot!
00897        // Read the headers from the new message, get the ones we like
00898        // and write out only the headers we want from the new message,
00899        // along with all of the other headers from the "old" message!
00900        if (NS_SUCCEEDED( rv))
00901               rv = FillMailBuffer( &state, copy);
00902        if (NS_SUCCEEDED( rv))
00903               rv = ReadHeaders( &state, copy, m_readHeaders);
00904        
00905        if (NS_SUCCEEDED( rv)) {
00906               rv = WriteHeaders( pDst, m_readHeaders);
00907        }
00908 
00909        // We need to go ahead and write out the rest of the copy buffer
00910        // so that the following will properly copy the rest of the body
00911        char   lastChar = 0;
00912 
00913        if (NS_SUCCEEDED( rv)) {
00914     rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf);
00915               if (copy.m_bytesInBuf)
00916                      lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1];
00917     if (NS_SUCCEEDED(rv))
00918       copy.m_writeOffset = copy.m_bytesInBuf;
00919        }
00920 
00921        while ((state.offset < state.size) && NS_SUCCEEDED( rv)) {
00922               rv = FillMailBuffer( &state, copy);
00923               if (NS_SUCCEEDED( rv)) {
00924       rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf);
00925                      lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1];
00926                      if (NS_SUCCEEDED( rv))
00927                   copy.m_writeOffset = copy.m_bytesInBuf;
00928            else
00929         IMPORT_LOG0( "*** Error writing to destination mailbox\n");
00930               }
00931        }
00932 
00933        pSrc->CloseStream();
00934        
00935        if ((lastChar != 0x0A) && NS_SUCCEEDED( rv)) {
00936               rv = pDst->Write( "\x0D\x0A", 2, &written);
00937               if (written != 2)
00938                      rv = NS_ERROR_FAILURE;
00939        }
00940 
00941        return( rv);
00942 }
00943 
00944 nsresult nsOutlookCompose::FillMailBuffer( ReadFileState *pState, SimpleBufferTonyRCopiedTwice& read)
00945 {
00946        if (read.m_writeOffset >= read.m_bytesInBuf) {
00947               read.m_writeOffset = 0;
00948               read.m_bytesInBuf = 0;
00949        }
00950        else if (read.m_writeOffset) {
00951               memcpy( read.m_pBuffer, read.m_pBuffer + read.m_writeOffset, read.m_bytesInBuf - read.m_writeOffset);
00952               read.m_bytesInBuf -= read.m_writeOffset;
00953               read.m_writeOffset = 0;
00954        }
00955 
00956        PRInt32       count = read.m_size - read.m_bytesInBuf;
00957        if (((PRUint32)count + pState->offset) > pState->size)
00958               count = pState->size - pState->offset;
00959        if (count) {
00960               PRInt32              bytesRead = 0;
00961               char *        pBuffer = read.m_pBuffer + read.m_bytesInBuf;
00962               nsresult      rv = pState->pFile->Read( &pBuffer, count, &bytesRead);
00963               if (NS_FAILED( rv)) return( rv);
00964               if (bytesRead != count) return( NS_ERROR_FAILURE);
00965               read.m_bytesInBuf += bytesRead;
00966               pState->offset += bytesRead;
00967        }
00968 
00969        return( NS_OK);
00970 }
00971 
00972 
00973 #define kMaxSpecialHeaders  3
00974 static const char *gSpecialHeaders[kMaxSpecialHeaders] = {
00975        "Content-type",
00976        "MIME-Version",
00977        "Content-transfer-encoding"
00978 };
00979 // consider "X-Accept-Language"?
00980 
00981 #define kMaxReplaceHeaders  5
00982 static const char *gReplaceHeaders[kMaxReplaceHeaders] = {
00983        "From",
00984        "To",
00985        "Subject",
00986        "Reply-to",
00987        "cc"
00988 };
00989 
00990 PRBool nsOutlookCompose::IsReplaceHeader( const char *pHeader)
00991 {
00992        for (int i = 0; i < kMaxReplaceHeaders; i++) {
00993               if (!nsCRT::strcasecmp( pHeader, gReplaceHeaders[i]))
00994                      return( PR_TRUE);
00995        }
00996 
00997        return( PR_FALSE);
00998 }
00999 
01000 PRInt32 nsOutlookCompose::IsSpecialHeader( const char *pHeader)
01001 {
01002        for (int i = 0; i < kMaxSpecialHeaders; i++) {
01003               if (!nsCRT::strcasecmp( pHeader, gSpecialHeaders[i]))
01004                      return( (PRInt32) i);
01005        }
01006 
01007        return( -1);
01008 }
01009 
01010 
01011 nsresult nsOutlookCompose::WriteHeaders( nsIFileSpec *pDst, SimpleBufferTonyRCopiedTwice& newHeaders)
01012 {
01013        // Well, ain't this a peach?
01014        // This is rather disgusting but there really isn't much to be done about it....
01015 
01016        // 1. For each "old" header, replace it with the new one if we want,
01017        // then right it out.
01018        // 2. Then if we haven't written the "important" new headers, write them out
01019        // 3. Terminate the headers with an extra eol.
01020        
01021        PRInt32              n = 0;
01022        nsCString     header;
01023        nsCString     val;
01024        nsCString     replaceVal;
01025        PRInt32              written;
01026        nsresult      rv = NS_OK; // it's ok if we don't have the first header on the predefined lists.
01027        PRInt32              specialHeader;
01028        PRBool        specials[kMaxSpecialHeaders];
01029        int                  i;
01030 
01031        for (i = 0; i < kMaxSpecialHeaders; i++)
01032               specials[i] = PR_FALSE;
01033 
01034        do {
01035               GetNthHeader( m_Headers.get(), m_Headers.Length(), n, header, val, PR_FALSE);
01036               // GetNthHeader( newHeaders.m_pBuffer, newHeaders.m_writeOffset, n, header.get(), val, PR_FALSE);
01037               if (!header.IsEmpty()) {
01038                      if ((specialHeader = IsSpecialHeader( header.get())) != -1) {
01039                             header.Append( ':');
01040                             GetHeaderValue( newHeaders.m_pBuffer, newHeaders.m_writeOffset - 1, header.get(), val, PR_FALSE);
01041         // Bug 145150 - Turn "Content-Type: application/ms-tnef" into "Content-Type: text/plain"
01042         //              so the body text can be displayed normally (instead of in an attachment).
01043         if (!PL_strcasecmp(header.get(), "Content-Type:") && !PL_strcasecmp(val.get(), "application/ms-tnef"))
01044           val.Assign("text/plain");
01045                             header.Truncate( header.Length() - 1);
01046                             specials[specialHeader] = PR_TRUE;
01047                      }
01048                      else if (IsReplaceHeader( header.get())) {
01049                             replaceVal.Truncate( 0);
01050                             header.Append( ':');
01051                             GetHeaderValue( newHeaders.m_pBuffer, newHeaders.m_writeOffset - 1, header.get(), replaceVal, PR_FALSE);
01052                             header.Truncate( header.Length() - 1);
01053                             if (!replaceVal.IsEmpty())
01054                                    val = replaceVal;
01055                      }
01056                      if (!val.IsEmpty()) {
01057                             rv = pDst->Write( header.get(), header.Length(), &written);
01058                             if (NS_SUCCEEDED( rv))
01059                                    rv = pDst->Write( ": ", 2, &written);
01060                             if (NS_SUCCEEDED( rv))
01061                                    rv = pDst->Write( val.get(), val.Length(), &written);
01062                             if (NS_SUCCEEDED( rv))
01063                                    rv = pDst->Write( "\x0D\x0A", 2, &written);
01064 
01065                      }
01066               }
01067               n++;
01068        } while (NS_SUCCEEDED( rv) && !header.IsEmpty());
01069 
01070        for (i = 0; (i < kMaxSpecialHeaders) && NS_SUCCEEDED( rv); i++) {
01071               if (!specials[i]) {
01072                      header = gSpecialHeaders[i];
01073                      header.Append( ':');
01074                      GetHeaderValue( newHeaders.m_pBuffer, newHeaders.m_writeOffset - 1, header.get(), val, PR_FALSE);
01075                      header.Truncate( header.Length() - 1);
01076                      if (!val.IsEmpty()) {
01077                             rv = pDst->Write( header.get(), header.Length(), &written);
01078                             if (NS_SUCCEEDED( rv))
01079                                    rv = pDst->Write( ": ", 2, &written);
01080                             if (NS_SUCCEEDED( rv))
01081                                    rv = pDst->Write( val.get(), val.Length(), &written);
01082                             if (NS_SUCCEEDED( rv))
01083                                    rv = pDst->Write( "\x0D\x0A", 2, &written);
01084                      }
01085               }
01086        }
01087        
01088 
01089        if (NS_SUCCEEDED( rv))
01090               rv = pDst->Write( "\x0D\x0A", 2, &written);
01091        return( rv);
01092 }
01093 
01094