Back to index

lightning-sunbird  0.9+nobinonly
MapiMessage.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037  
00038 #include "nscore.h"
00039 #include <time.h>
00040 #include "nsString.h"
00041 #include "nsFileSpec.h"
00042 #include "nsSpecialSystemDirectory.h"
00043 
00044 #include "MapiDbgLog.h"
00045 #include "MapiApi.h"
00046 #include "MapiMessage.h"
00047 
00048 #include "MapiMimeTypes.h"
00049 
00050 // needed for the call the OpenStreamOnFile
00051 extern LPMAPIALLOCATEBUFFER gpMapiAllocateBuffer;
00052 extern LPMAPIFREEBUFFER            gpMapiFreeBuffer;
00053 
00054 // Sample From line: From - 1 Jan 1965 00:00:00
00055 
00056 typedef const char * PC_S8;
00057 
00058 static const char *  kWhitespace = "\b\t\r\n ";
00059 static const char *  sFromLine = "From - ";
00060 static const char *  sFromDate = "Mon Jan 1 00:00:00 1965";
00061 static const char *  sDaysOfWeek[7] = {
00062        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00063 };
00064 
00065 static const char *sMonths[12] = {
00066        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00067 };
00068 
00069 
00070 CMapiMessage::CMapiMessage( LPMESSAGE lpMsg)
00071 {
00072        m_lpMsg = lpMsg;
00073        m_pAttachTable = NULL;
00074        m_bMimeEncoding = FALSE;
00075        m_bMimeVersion = FALSE;
00076        m_ownsAttachFile = FALSE;
00077        m_whitespace = kWhitespace;
00078 }
00079 
00080 CMapiMessage::~CMapiMessage()
00081 {
00082        if (m_pAttachTable)
00083               m_pAttachTable->Release();
00084        if (m_lpMsg)
00085               m_lpMsg->Release();
00086 
00087        ClearTempAttachFile();
00088 }
00089 
00090 
00091 void CMapiMessage::FormatDateTime( SYSTEMTIME & tm, nsCString& s, BOOL includeTZ)
00092 {
00093        long offset = _timezone;
00094        s += sDaysOfWeek[tm.wDayOfWeek];
00095        s += ", ";
00096        s.AppendInt( (PRInt32) tm.wDay);
00097        s += " ";
00098        s += sMonths[tm.wMonth - 1];
00099        s += " ";
00100        s.AppendInt( (PRInt32) tm.wYear);
00101        s += " ";
00102        int val = tm.wHour;
00103        if (val < 10)
00104               s += "0";
00105        s.AppendInt( (PRInt32) val);
00106        s += ":";
00107        val = tm.wMinute;
00108        if (val < 10)
00109               s += "0";
00110        s.AppendInt( (PRInt32) val);
00111        s += ":";
00112        val = tm.wSecond;
00113        if (val < 10)
00114               s += "0";
00115        s.AppendInt( (PRInt32) val);
00116        if (includeTZ) {
00117               s += " ";
00118               if (offset < 0) {
00119                      offset *= -1;
00120                      s += "+";
00121               }
00122               else
00123                      s += "-";
00124               offset /= 60;
00125               val = (int) (offset / 60);
00126               if (val < 10)
00127                      s += "0";
00128               s.AppendInt( (PRInt32) val);
00129               val = (int) (offset % 60);
00130               if (val < 10)
00131                      s += "0";
00132               s.AppendInt( (PRInt32) val);
00133        }
00134 }
00135 
00136 
00137        // Headers - fetch will get PR_TRANSPORT_MESSAGE_HEADERS
00138        // or if they do not exist will build a header from
00139        //     PR_DISPLAY_TO, _CC, _BCC
00140        //     PR_SUBJECT
00141        //  PR_MESSAGE_RECIPIENTS
00142        // and PR_CREATION_TIME if needed?
00143 void CMapiMessage::BuildHeaders( void)
00144 {
00145        // Try to the to line.
00146        m_headers.Truncate();
00147        AddHeader( m_headers, PR_DISPLAY_TO, "To: ");
00148        AddHeader( m_headers, PR_DISPLAY_CC, "CC: ");
00149        AddHeader( m_headers, PR_DISPLAY_BCC, "BCC: ");
00150        AddDate( m_headers);
00151        AddSubject( m_headers);
00152        AddFrom( m_headers);
00153 }
00154 
00155 BOOL CMapiMessage::AddHeader( nsCString& str, ULONG tag, const char *pPrefix)
00156 {
00157        nsCString            value;
00158        LPSPropValue  pVal = CMapiApi::GetMapiProperty( m_lpMsg, tag);
00159        if (CMapiApi::GetStringFromProp( pVal, value) && !value.IsEmpty()) {
00160               str.Trim( kWhitespace, PR_FALSE, PR_TRUE);
00161               if (!str.IsEmpty())
00162                      str += "\x0D\x0A";
00163               str += pPrefix;
00164               str += value;
00165               return( TRUE);
00166        }      
00167 
00168        return( FALSE);
00169 }
00170 
00171 void CMapiMessage::AddSubject( nsCString& str)
00172 {
00173        AddHeader( str, PR_SUBJECT, "Subject: "); 
00174 }
00175 
00176 void CMapiMessage::AddFrom( nsCString& str)
00177 {
00178        if (!AddHeader( str, PR_SENDER_NAME, "From: "))
00179               AddHeader( str, PR_SENDER_EMAIL_ADDRESS, "From: ");
00180 }
00181 
00182 void CMapiMessage::AddDate( nsCString& str)
00183 {
00184        LPSPropValue pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_MESSAGE_DELIVERY_TIME);
00185        if (!pVal)
00186               pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_CREATION_TIME);
00187        if (pVal) {
00188               SYSTEMTIME    st;
00189               ::FileTimeToSystemTime( &(pVal->Value.ft), &st);
00190               CMapiApi::MAPIFreeBuffer( pVal);
00191               str.Trim( kWhitespace, PR_FALSE, PR_TRUE);
00192               if (!str.IsEmpty())
00193                      str += "\x0D\x0A";
00194               str += "Date: ";
00195               FormatDateTime( st, str);
00196        }
00197 }
00198 
00199 
00200 void CMapiMessage::BuildFromLine( void)
00201 {
00202        m_fromLine = sFromLine;
00203        LPSPropValue  pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_CREATION_TIME);
00204        if (pVal) {
00205               SYSTEMTIME    st;
00206               ::FileTimeToSystemTime( &(pVal->Value.ft), &st);
00207               CMapiApi::MAPIFreeBuffer( pVal);
00208               FormatDateTime( st, m_fromLine, FALSE);
00209        }
00210        else
00211               m_fromLine += sFromDate;
00212        m_fromLine += "\x0D\x0A";
00213 
00214 }
00215 
00216 BOOL CMapiMessage::FetchHeaders( void)
00217 {
00218        LPSPropValue  pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_TRANSPORT_MESSAGE_HEADERS);
00219        if (pVal && CMapiApi::IsLargeProperty( pVal)) {
00220               m_headers.Truncate();
00221               CMapiApi::GetLargeStringProperty( m_lpMsg, PR_TRANSPORT_MESSAGE_HEADERS, m_headers);
00222        }
00223        else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ))) {
00224               m_headers = pVal->Value.LPSZ;
00225        }
00226        else {
00227               // Need to build the headers from the other stuff
00228               m_headers.Truncate();
00229               BuildHeaders();
00230        }
00231        
00232        if (pVal)
00233               CMapiApi::MAPIFreeBuffer( pVal);
00234 
00235        m_fromLine.Truncate();
00236        if (NeedsFromLine()) {
00237               BuildFromLine();
00238        }
00239 
00240        if (!m_fromLine.IsEmpty()) {
00241               MAPI_DUMP_STRING( m_fromLine);
00242        }
00243        MAPI_DUMP_STRING( m_headers);
00244        MAPI_TRACE0( "\r\n");
00245 
00246        ProcessHeaders();
00247 
00248        if (!m_headers.IsEmpty()) {
00249               if (!m_bHasSubject)
00250                      AddSubject( m_headers);
00251               if (!m_bHasFrom)
00252                      AddFrom( m_headers);
00253               if (!m_bHasDate)
00254                      AddDate( m_headers);
00255               m_headers.Trim( kWhitespace, PR_FALSE, PR_TRUE);
00256               m_headers += "\x0D\x0A";
00257        }
00258 
00259 #ifdef _DEBUG
00260        // CMapiApi::ListProperties( m_lpMsg);
00261        // MAPI_TRACE0( "--------------------\r\n");
00262 #endif
00263 
00264        return( !m_headers.IsEmpty());
00265 }
00266 
00267        // TRUE if a From line needs to precede the headers, FALSE
00268        // if the headers already include a from line    
00269 BOOL CMapiMessage::NeedsFromLine( void)
00270 {
00271        nsCString     l;
00272        m_headers.Left( l, 5);
00273        if (l.Equals("From "))
00274               return( FALSE);
00275        else
00276               return( TRUE);
00277 }
00278 
00279 BOOL CMapiMessage::IsMultipart( void)
00280 {
00281        nsCString     left;
00282        m_mimeContentType.Left( left, 10);
00283        if (left.Equals(NS_LITERAL_CSTRING("multipart/"), nsCaseInsensitiveCStringComparator()))
00284               return( TRUE);
00285        return( FALSE);
00286 }
00287 
00288 void CMapiMessage::GenerateBoundary( void)
00289 {
00290        m_mimeBoundary = "===============_NSImport_Boundary_";
00291        PRUint32 t = ::GetTickCount();
00292        nsCString     hex;
00293        hex.AppendInt( (PRInt32) t, 16);
00294        m_mimeBoundary += hex;
00295        m_mimeBoundary += "====";
00296 }
00297 
00298 BOOL CMapiMessage::GetAttachFileLoc( nsIFileSpec * pLoc)
00299 {
00300        if (m_attachPath.IsEmpty())
00301               return( FALSE);
00302        pLoc->SetNativePath( m_attachPath.get());
00303        m_ownsAttachFile = FALSE;
00304        return( TRUE);
00305 }
00306 
00307 // Mime-Version: 1.0
00308 // Content-Type: text/plain; charset="US-ASCII"
00309 // Content-Type: multipart/mixed; boundary="=====================_874475278==_"
00310 
00311 void CMapiMessage::ProcessHeaderLine( nsCString& line)
00312 {
00313        PRUint32             len, start;
00314        nsCString            tStr;
00315        nsCString            left13;
00316        nsCString            left26;
00317        nsCString            left8;
00318        nsCString            left5;
00319 
00320        line.Left( left13, 13);
00321        line.Left( left26, 26);
00322        line.Left( left8, 8);
00323        line.Left( left5, 5);
00324 
00325        if (left13.Equals(NS_LITERAL_CSTRING("Mime-Version:"), nsCaseInsensitiveCStringComparator()))
00326               m_bMimeVersion = TRUE;
00327        else if (left13.Equals(NS_LITERAL_CSTRING("Content-Type:"), nsCaseInsensitiveCStringComparator())) {
00328               // Note: this isn't a complete parser, the content type
00329               // we extract could have rfc822 comments in it
00330               len = 13;
00331               while ((len < line.Length()) && IsSpace( line.CharAt( len)))
00332                      len++;
00333               start = len;
00334               while ((len < line.Length()) && (line.CharAt( len) != ';'))
00335                      len++;
00336               line.Mid( m_mimeContentType, start, len - start);
00337               len++;
00338               // look for "boundary="
00339               BOOL   haveB;
00340               BOOL   haveC;
00341               while (len < line.Length()) {
00342                      haveB = FALSE;
00343                      haveC = FALSE;
00344                      while ((len < line.Length()) && IsSpace( line.CharAt( len)))
00345                             len++;
00346                      start = len;
00347                      while ((len < line.Length()) && (line.CharAt( len) != '='))
00348                             len++;
00349                      if (len - start) {
00350                             line.Mid( tStr, start, len - start);
00351                             if (tStr.Equals(NS_LITERAL_CSTRING("boundary"), nsCaseInsensitiveCStringComparator()))
00352                                    haveB = TRUE;
00353                             else if (tStr.Equals(NS_LITERAL_CSTRING("charset"), nsCaseInsensitiveCStringComparator()))
00354                                    haveC = TRUE;
00355                      }
00356                      len++;
00357                      while ((len < line.Length()) && IsSpace( line.CharAt( len)))
00358                             len++;
00359                      if ((len < line.Length()) && (line.CharAt( len) == '"')) {
00360                             len++;
00361                             BOOL slash = FALSE;
00362                             tStr.Truncate();
00363                             while (len < line.Length()) {
00364                                    if (slash) {
00365                                           slash = FALSE;
00366                                           tStr.Append(line.CharAt( len));
00367                                    }
00368                                    else if (line.CharAt( len) == '"')
00369                                           break;
00370                                    else if (line.CharAt( len) != '\\')
00371                                           tStr.Append(line.CharAt( len));
00372                                    else
00373                                           slash = TRUE;
00374                                    len++;
00375                             }
00376                             len++;
00377                             if (haveB) {
00378                                    m_mimeBoundary = tStr;
00379                                    haveB = FALSE;
00380                             }
00381                             if (haveC) {
00382                                    m_mimeCharset = tStr;
00383                                    haveC = FALSE;
00384                             }
00385                      }
00386                      tStr.Truncate();
00387                      while ((len < line.Length()) && (line.CharAt( len) != ';')) {
00388                             tStr.Append(line.CharAt( len));
00389                             len++;
00390                      }
00391                      len++;
00392                      if (haveB) {
00393                             tStr.Trim( kWhitespace);
00394                             m_mimeBoundary = tStr;
00395                      }
00396                      if (haveC) {
00397                             tStr.Trim( kWhitespace);
00398                             m_mimeCharset = tStr;
00399                      }
00400 
00401               }
00402        }
00403        else if (left26.Equals(NS_LITERAL_CSTRING("Content-Transfer-Encoding:"), nsCaseInsensitiveCStringComparator())) {
00404               m_bMimeEncoding = TRUE;
00405        }
00406        else if (left8.Equals(NS_LITERAL_CSTRING("Subject:"), nsCaseInsensitiveCStringComparator()))
00407               m_bHasSubject = TRUE;
00408        else if (left5.Equals(NS_LITERAL_CSTRING("From:"), nsCaseInsensitiveCStringComparator()))
00409               m_bHasFrom = TRUE;
00410        else if (left5.Equals(NS_LITERAL_CSTRING("Date:"), nsCaseInsensitiveCStringComparator()))
00411               m_bHasDate = TRUE;
00412 }
00413 
00414 void CMapiMessage::ProcessHeaders( void)
00415 {
00416        m_bHasSubject = FALSE;
00417        m_bHasFrom = FALSE;
00418        m_bHasDate = FALSE;
00419 
00420        PC_S8         pChar = (PC_S8) m_headers.get();
00421        int                  start = 0;
00422        int                  len = 0;
00423   int     hdrLen = strlen(pChar);
00424        nsCString     line;
00425        nsCString     mid;
00426        while (*pChar) {
00427               if ((*pChar == 0x0D) && (*(pChar + 1) == 0x0A)) {
00428                      if ((*(pChar + 2) != ' ') && (*(pChar + 2) != 9)) {
00429                             m_headers.Mid( mid, start, len);
00430                             line += mid;
00431                             ProcessHeaderLine( line);
00432                             line.Truncate();
00433                             pChar++; // subsequent increment will move pChar to the next line
00434                             start += len;
00435                             start += 2;
00436                             len = -1;
00437                      }
00438               }
00439               pChar++;
00440               len++;
00441        }
00442 
00443   // See if we still have data to be processed.
00444   if (start < hdrLen)
00445   {
00446     line.Assign(m_headers.get()+start);
00447     ProcessHeaderLine(line);
00448   }
00449 
00450        if (!m_mimeContentType.IsEmpty() || !m_mimeBoundary.IsEmpty() || !m_mimeCharset.IsEmpty()) {
00451               MAPI_TRACE1( "\tDecoded mime content type: %s\r\n", (PC_S8)m_mimeContentType);
00452               MAPI_TRACE1( "\tDecoded mime boundary: %s\r\n", (PC_S8)m_mimeBoundary);
00453               MAPI_TRACE1( "\tDecoded mime charset: %s\r\n", (PC_S8)m_mimeCharset);
00454        }
00455 }
00456 
00457 BOOL CMapiMessage::FetchBody( void)
00458 {
00459   m_bodyIsHtml = FALSE;
00460   m_body.Truncate();
00461   // Is it html?
00462   LPSPropValue pVal = CMapiApi::GetMapiProperty( m_lpMsg, 0x1013001e);
00463   if (pVal && CMapiApi::IsLargeProperty( pVal))
00464     CMapiApi::GetLargeStringProperty( m_lpMsg, 0x1013001e, m_body);
00465   else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ)))
00466     m_body = pVal->Value.LPSZ;
00467 
00468   // kind-hearted Outlook will give us html even for a plain text message. But it will include
00469   // a comment saying it did the conversion. We'll use this as a hack to really use
00470   // the plain text part.
00471   if (!m_body.IsEmpty() && m_body.Find("<!-- Converted from text/plain format -->") == kNotFound)
00472     m_bodyIsHtml = TRUE;
00473   else
00474   {
00475     pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_BODY);
00476     if (pVal) 
00477     {
00478       if (pVal && CMapiApi::IsLargeProperty( pVal)) {
00479         CMapiApi::GetLargeStringProperty( m_lpMsg, PR_BODY, m_body);
00480       }
00481       else {
00482         if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ))) {
00483           m_body = pVal->Value.LPSZ;
00484         }
00485       }
00486     }
00487   }
00488   
00489   if (pVal)
00490     CMapiApi::MAPIFreeBuffer( pVal);
00491   
00492   MAPI_DUMP_STRING( m_body);
00493   MAPI_TRACE0( "\r\n");
00494   
00495   return( TRUE);
00496 }
00497 
00498 enum {
00499     ieidPR_ATTACH_NUM = 0,
00500     ieidAttachMax
00501 };
00502 
00503 static const SizedSPropTagArray(ieidAttachMax, ptaEid)=
00504 {
00505     ieidAttachMax,
00506     {
00507         PR_ATTACH_NUM
00508     }
00509 };
00510 
00511 int CMapiMessage::CountAttachments( void)
00512 {
00513        m_attachNums.RemoveAll();
00514 
00515        LPSPropValue  pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_HASATTACH);
00516        BOOL                 has = TRUE;
00517 
00518        if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_BOOLEAN)) {
00519               has = (pVal->Value.b != 0);
00520        }
00521        if (pVal)
00522               CMapiApi::MAPIFreeBuffer( pVal);
00523 
00524        if (has) {
00525               // Get the attachment table?
00526               HRESULT                     hr;
00527               LPMAPITABLE          pTable = NULL;
00528 
00529               hr = m_lpMsg->GetAttachmentTable( 0, &pTable);
00530               if (FAILED( hr))
00531                      return( 0);
00532               m_pAttachTable = pTable;
00533               IterateAttachTable();
00534        }
00535 
00536        return( m_attachNums.GetSize());
00537 }
00538 
00539 
00540 BOOL CMapiMessage::IterateAttachTable( void)
00541 {
00542        LPMAPITABLE lpTable = m_pAttachTable;
00543        ULONG rowCount;
00544        HRESULT hr = lpTable->GetRowCount( 0, &rowCount);
00545        if (!rowCount) {
00546               return( TRUE);
00547        }
00548 
00549        hr = lpTable->SetColumns( (LPSPropTagArray)&ptaEid, 0);
00550        if (FAILED(hr)) {
00551               MAPI_TRACE2( "SetColumns for attachment table failed: 0x%lx, %d\r\n", (long)hr, (int)hr);
00552               return( FALSE);
00553        }
00554 
00555        hr = lpTable->SeekRow( BOOKMARK_BEGINNING, 0, NULL);
00556        if (FAILED(hr)) {
00557               MAPI_TRACE2( "SeekRow for attachment table failed: 0x%lx, %d\r\n", (long)hr, (int)hr);
00558               return( FALSE);
00559        }
00560 
00561        int                  cNumRows = 0;
00562        LPSRowSet     lpRow;
00563        BOOL          bResult = TRUE;
00564        do {
00565               
00566               lpRow = NULL;
00567               hr = lpTable->QueryRows( 1, 0, &lpRow);
00568 
00569         if(HR_FAILED(hr)) {
00570                      MAPI_TRACE2( "QueryRows for attachment table failed: 0x%lx, %d\n", (long)hr, (int)hr);
00571             bResult = FALSE;
00572                      break;
00573               }
00574 
00575         if(lpRow) {
00576             cNumRows = lpRow->cRows;
00577 
00578                   if (cNumRows) {
00579                 LONG aNum = lpRow->aRow[0].lpProps[ieidPR_ATTACH_NUM].Value.l;
00580                             m_attachNums.Add( (PRUint32)aNum);
00581                             MAPI_TRACE1( "\t\t****Attachment found - #%d\r\n", (int)aNum);
00582                   }
00583                      CMapiApi::FreeProws( lpRow);              
00584         }
00585 
00586        } while ( SUCCEEDED(hr) && cNumRows && lpRow);
00587 
00588        return( bResult);
00589 }
00590 
00591 void CMapiMessage::ClearTempAttachFile( void)
00592 {
00593        if (m_ownsAttachFile && !m_attachPath.IsEmpty()) {
00594               nsFileSpec    spec( m_attachPath.get());
00595               spec.Delete( PR_FALSE);
00596        }
00597        m_ownsAttachFile = FALSE;   
00598        m_attachPath.Truncate();
00599 }
00600 
00601 BOOL CMapiMessage::CopyBinAttachToFile( LPATTACH lpAttach)
00602 {
00603        LPSTREAM      lpStreamFile;
00604 
00605        m_ownsAttachFile = FALSE;
00606        m_attachPath.Truncate();
00607 
00608         const char *tFileName = "mapiattach.tmp";
00609 
00610         nsFileSpec tmpSpec = nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_TemporaryDirectory); 
00611         tmpSpec += tFileName;
00612         tmpSpec.MakeUnique();
00613 
00614        HRESULT hr = CMapiApi::OpenStreamOnFile( gpMapiAllocateBuffer, gpMapiFreeBuffer, STGM_READWRITE | STGM_CREATE,
00615                                           (char *) tmpSpec.GetNativePathCString(), NULL, &lpStreamFile);
00616        if (HR_FAILED(hr)) {
00617               MAPI_TRACE1( "~~ERROR~~ OpenStreamOnFile failed - temp path: %s\r\n", tPath);
00618               return( FALSE);
00619        }
00620        MAPI_TRACE1( "\t\t** Attachment extracted to temp file: %s\r\n", (const char *)m_attachPath);
00621 
00622        BOOL          bResult = TRUE;
00623        LPSTREAM      lpAttachStream;
00624        hr = lpAttach->OpenProperty( PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN *)&lpAttachStream);
00625 
00626        if (HR_FAILED( hr)) {
00627               MAPI_TRACE0( "~~ERROR~~ OpenProperty failed for PR_ATTACH_DATA_BIN.\r\n");
00628               lpAttachStream = NULL;
00629               bResult = FALSE;
00630        }
00631        else {
00632               STATSTG              st;
00633               hr = lpAttachStream->Stat( &st, STATFLAG_NONAME);
00634               if (HR_FAILED( hr)) {
00635                      MAPI_TRACE0( "~~ERROR~~ Stat failed for attachment stream\r\n");
00636                      bResult = FALSE;
00637               }
00638               else {
00639                      hr = lpAttachStream->CopyTo( lpStreamFile, st.cbSize, NULL, NULL);
00640                      if (HR_FAILED( hr)) {
00641                             MAPI_TRACE0( "~~ERROR~~ Attach Stream CopyTo temp file failed.\r\n");
00642                             bResult = FALSE;
00643                      }
00644               }
00645        }
00646 
00647        m_attachPath = tmpSpec.GetNativePathCString();
00648        if (lpAttachStream)
00649               lpAttachStream->Release();
00650        lpStreamFile->Release();
00651        if (!bResult) {
00652               nsFileSpec    spec( m_attachPath.get());
00653               spec.Delete( PR_FALSE);
00654        }
00655        else
00656               m_ownsAttachFile = TRUE;
00657 
00658        return( bResult);
00659 }
00660 
00661 BOOL CMapiMessage::GetAttachmentInfo( int idx)
00662 {
00663        ClearTempAttachFile();
00664 
00665        BOOL   bResult = TRUE;
00666        if ((idx < 0) || (idx >= (int)m_attachNums.GetSize())) {
00667               return( FALSE);      
00668        }
00669 
00670        DWORD         aNum = m_attachNums.GetAt( idx);
00671        LPATTACH      lpAttach = NULL;
00672        HRESULT              hr = m_lpMsg->OpenAttach( aNum, NULL, 0, &lpAttach);
00673        if (HR_FAILED( hr)) {
00674               MAPI_TRACE2( "\t\t****Attachment error, unable to open attachment: %d, 0x%lx\r\n", idx, hr);
00675               return( FALSE);
00676        }
00677        
00678        LPSPropValue  pVal;
00679        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_MIME_TAG);
00680        if (pVal)
00681               CMapiApi::GetStringFromProp( pVal, m_attachMimeType);
00682        else
00683               m_attachMimeType.Truncate();
00684 
00685        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_METHOD);
00686        if (pVal) {
00687               LONG   aMethod = CMapiApi::GetLongFromProp( pVal);
00688               if ((aMethod == ATTACH_BY_REF_ONLY) || (aMethod == ATTACH_BY_REFERENCE) || (aMethod == ATTACH_BY_REF_RESOLVE)) {
00689                      m_attachPath.Truncate();
00690                      pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_PATHNAME);
00691                      if (pVal)
00692                             CMapiApi::GetStringFromProp( pVal, m_attachPath);
00693                      MAPI_TRACE2( "\t\t** Attachment #%d by ref: %s\r\n", idx, (const char *)m_attachPath);
00694                      m_ownsAttachFile = FALSE;
00695               }
00696               else if (aMethod == ATTACH_BY_VALUE) {
00697                      MAPI_TRACE1( "\t\t** Attachment #%d by value.\r\n", idx);
00698                      bResult = CopyBinAttachToFile( lpAttach);
00699               }
00700               else if (aMethod == ATTACH_OLE) {
00701                      MAPI_TRACE1( "\t\t** Attachment #%d by OLE - yuck!!!\r\n", idx);
00702               }
00703               else if (aMethod == ATTACH_EMBEDDED_MSG) {
00704                      MAPI_TRACE1( "\t\t** Attachment #%d by Embedded Message??\r\n", idx);
00705               }
00706               else {
00707                      MAPI_TRACE2( "\t\t** Attachment #%d unknown attachment method - 0x%lx\r\n", idx, aMethod);
00708                      bResult = FALSE;
00709               }
00710        }
00711        else
00712               bResult = FALSE;
00713        
00714        nsCString     fName, fExt;
00715        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_LONG_FILENAME);
00716        if (pVal)
00717               CMapiApi::GetStringFromProp( pVal, fName);
00718        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_EXTENSION);
00719        if (pVal)
00720               CMapiApi::GetStringFromProp( pVal, fExt);
00721        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_SIZE);
00722        long sz = 0;
00723        if (pVal)
00724               sz = CMapiApi::GetLongFromProp( pVal);
00725 
00726        /*
00727               // I have no idea how this tag is used, how to interpret it's value, etc.
00728               // Fortunately, the Microsoft documentation is ABSOLUTELY NO HELP AT ALL.  In fact,
00729               // if one goes by the docs and sample code, this tag is completely 100% useless.  I'm
00730               // sure it has some important meaning which will one day be obvious, but for now,
00731               // it is ignored.
00732        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_TAG);
00733        if (pVal) {
00734               ::MAPIFreeBuffer( pVal);
00735        }
00736        */
00737 
00738        MAPI_TRACE1( "\t\t\t--- Mime type: %s\r\n", (const char *)m_attachMimeType);
00739        MAPI_TRACE2( "\t\t\t--- File name: %s, extension: %s\r\n", (const char *)fName, (const char *)fExt);
00740        MAPI_TRACE1( "\t\t\t--- Size: %ld\r\n", sz);
00741 
00742        if (fExt.IsEmpty()) {
00743               int idx = fName.RFindChar( '.');
00744               if (idx != -1)
00745                      fName.Right( fExt, fName.Length() - idx);
00746        }
00747        
00748        if ((fName.RFindChar( '.') == -1) && !fExt.IsEmpty()) {
00749               fName += ".";
00750               fName += fExt;
00751        }
00752 
00753        m_attachFileName = fName;
00754 
00755        if (m_attachMimeType.IsEmpty()) {
00756               PRUint8 *pType = NULL;
00757               if (!fExt.IsEmpty()) {
00758                      pType = CMimeTypes::GetMimeType( fExt);
00759               }
00760               if (pType)
00761                      m_attachMimeType = (PC_S8)pType;
00762               else
00763                      m_attachMimeType = "application/octet-stream";
00764        }
00765 
00766        pVal = CMapiApi::GetMapiProperty( lpAttach, PR_ATTACH_TRANSPORT_NAME);
00767        if (pVal) {
00768               CMapiApi::GetStringFromProp( pVal, fName);
00769               MAPI_TRACE1( "\t\t\t--- Transport name: %s\r\n", (const char *)fName);
00770        }
00771 
00772        lpAttach->Release();
00773 
00774        return( bResult);
00775 }
00776 
00777 void nsSimpleUInt32Array::Allocate( void)
00778 {
00779        if (m_used < m_allocated)
00780               return;
00781        if (!m_pData) {
00782               m_pData = new PRUint32[m_growBy];
00783               m_allocated = m_growBy;
00784        }
00785        else {
00786               m_allocated += m_growBy;
00787               PRUint32 *pData = new PRUint32[m_allocated];
00788               memcpy( pData, m_pData, (m_allocated - m_growBy) * sizeof( PRUint32));
00789               delete [] m_pData;
00790               m_pData = pData;
00791        }
00792 }