Back to index

lightning-sunbird  0.9+nobinonly
nsImportMimeEncode.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  *   Pierre Phaneuf <pp@ludusdesign.com>
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 #include "nscore.h"
00040 #include "nsString.h"
00041 #include "nsCRT.h"
00042 #include "nsImportMimeEncode.h"
00043 
00044 #include "ImportCharSet.h"
00045 #include "ImportTranslate.h"
00046 
00047 #define       kNoState             0
00048 #define       kStartState          1
00049 #define       kEncodeState  2
00050 #define kDoneState          3
00051 
00052 #define kEncodeBufferSz     (8192 * 8)
00053 
00054 nsImportMimeEncode::nsImportMimeEncode()
00055 {
00056        m_pOut = nsnull;
00057        m_state = kNoState;
00058        m_bytesProcessed = 0;
00059        m_pInputBuf = nsnull;
00060        m_pMimeFile = nsnull;
00061 }
00062 
00063 nsImportMimeEncode::~nsImportMimeEncode()
00064 {
00065        NS_IF_RELEASE( m_pMimeFile);
00066        if (m_pInputBuf)
00067               delete [] m_pInputBuf;
00068 }
00069 
00070 void nsImportMimeEncode::EncodeFile( nsIFileSpec *pInFile, ImportOutFile *pOut, const char *pFileName, const char *pMimeType)
00071 {
00072        m_fileName = pFileName;
00073        m_mimeType = pMimeType;
00074 
00075        m_pMimeFile = pInFile;
00076        NS_IF_ADDREF( m_pMimeFile);
00077 
00078        m_pOut = pOut;
00079        m_state = kStartState;
00080 }
00081 
00082 void nsImportMimeEncode::CleanUp( void)
00083 {
00084        CleanUpEncodeScan();
00085 }
00086 
00087 PRBool nsImportMimeEncode::SetUpEncode( void)
00088 {
00089        nsCString            errStr;
00090        if (!m_pInputBuf) {
00091               m_pInputBuf = new PRUint8[kEncodeBufferSz];
00092        }
00093        
00094        m_appleSingle = PR_FALSE;
00095 
00096 #ifdef _MAC_IMPORT_CODE
00097        // First let's see just what kind of beast we have?
00098        // For files with only a data fork and a known mime type
00099        // proceed with normal mime encoding just as on the PC.
00100        // For unknown mime types and files with both forks,
00101        // encode as AppleSingle format.
00102        if (m_filePath.GetMacFileSize( UFileLocation::eResourceFork) || !pMimeType) {
00103               m_appleSingle = TRUE;
00104               m_mimeType = "application/applefile";
00105        }
00106 #endif
00107        
00108        if (!InitEncodeScan( m_appleSingle, m_pMimeFile, m_fileName.get(), m_pInputBuf, kEncodeBufferSz)) {
00109               return( PR_FALSE);
00110        }
00111               
00112        m_state = kEncodeState;
00113        m_lineLen = 0;
00114        
00115        // Write out the boundary header
00116        PRBool bResult = PR_TRUE;
00117        bResult = m_pOut->WriteStr( "Content-type: ");
00118        if (bResult)
00119               bResult = m_pOut->WriteStr( m_mimeType.get());
00120 
00121 #ifdef _MAC_IMPORT_CODE
00122        // include the type an creator here
00123        if (bResult)
00124               bResult = m_pOut->WriteStr( "; x-mac-type=\"");
00125        U8     hex[8];
00126        LongToHexBytes( m_filePath.GetFileType(), hex);
00127        if (bResult)
00128               bResult = m_pOut->WriteData( hex, 8);
00129        LongToHexBytes( m_filePath.GetFileCreator(), hex);
00130        if (bResult)
00131               bResult = m_pOut->WriteStr( "\"; x-mac-creator=\"");
00132        if (bResult)
00133               bResult = m_pOut->WriteData( hex, 8);
00134        if (bResult)
00135               bResult = m_pOut->WriteStr( "\"");
00136 #endif
00137 
00138        /*
00139        if (bResult)
00140               bResult = m_pOut->WriteStr( gMimeTypeFileName);
00141        */
00142        if (bResult)
00143               bResult = m_pOut->WriteStr( ";\x0D\x0A");
00144 
00145        nsCString            fName;
00146        PRBool               trans = TranslateFileName( m_fileName, fName);
00147        if (bResult)
00148               bResult = WriteFileName( fName, trans, "name");
00149        if (bResult)
00150               bResult = m_pOut->WriteStr( "Content-transfer-encoding: base64");
00151        if (bResult)
00152               bResult = m_pOut->WriteEol();
00153        if (bResult)
00154               bResult = m_pOut->WriteStr( "Content-Disposition: attachment;\x0D\x0A");
00155        if (bResult)
00156               bResult = WriteFileName( fName, trans, "filename");
00157        if (bResult)
00158               bResult = m_pOut->WriteEol();
00159 
00160        if (!bResult) {
00161               CleanUp();
00162        }
00163 
00164        return( bResult);
00165 }
00166 
00167 PRBool nsImportMimeEncode::DoWork( PRBool *pDone)
00168 {      
00169        *pDone = PR_FALSE;
00170        switch( m_state) {
00171        case kNoState:
00172               return( PR_FALSE);
00173               break;
00174        case kStartState:
00175               return( SetUpEncode());
00176               break;
00177        case kEncodeState:
00178               if (!Scan( pDone)) {
00179                      CleanUp();
00180                      return( PR_FALSE);
00181               }
00182               if (*pDone) {
00183                      *pDone = PR_FALSE;
00184                      m_state = kDoneState;
00185               }
00186               break;
00187        case kDoneState:
00188               CleanUp();
00189               m_state = kNoState;
00190               *pDone = PR_TRUE;
00191               break;
00192        }
00193 
00194        return( PR_TRUE);
00195 }
00196 
00197 static PRUint8 gBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00198 
00199 PRBool nsImportMimeEncode::ScanBuffer( PRBool *pDone)
00200 {
00201 
00202        PRUint32      pos = m_pos;
00203        PRUint32      start = pos;
00204        PRUint8 *     pChar = m_pBuf + pos;
00205        PRUint32      max = m_bytesInBuf;
00206        PRUint8              byte[4];
00207        PRUint32      lineLen = m_lineLen;
00208 
00209        while ((pos + 2) < max) {
00210               // Encode 3 bytes
00211               byte[0] = gBase64[*pChar >> 2];
00212               byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
00213               pChar++;
00214               byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
00215               pChar++;
00216               byte[3] = gBase64[(*pChar) & 0x3F];
00217               if (!m_pOut->WriteData( byte, 4))
00218                      return( PR_FALSE);
00219               pos += 3;
00220               pChar++;
00221               lineLen += 4;
00222               if (lineLen > 71) {
00223                      if (!m_pOut->WriteEol())
00224                             return( PR_FALSE);
00225                      lineLen = 0;
00226               }
00227        }
00228 
00229        if ((pos < max) && m_eof) {
00230               // Get the last few bytes!
00231               byte[0] = gBase64[*pChar >> 2];
00232               pos++;
00233               if (pos < max) {
00234                      byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
00235                      pChar++;
00236                      pos++;
00237                      if (pos < max) {
00238                             // Should be dead code!! (Then why is it here doofus?)
00239                             byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
00240                             pChar++;
00241                             byte[3] = gBase64[(*pChar) & 0x3F];
00242                             pos++;
00243                      }
00244                      else {
00245                             byte[2] = gBase64[(((*pChar) & 0xF) << 2)];
00246                             byte[3] = '=';
00247                      }
00248               }
00249               else {
00250                      byte[1] = gBase64[(((*pChar) & 0x3)<< 4)];
00251                      byte[2] = '=';
00252                      byte[3] = '=';
00253               }
00254               
00255               if (!m_pOut->WriteData( byte, 4))
00256                      return( PR_FALSE);
00257               if (!m_pOut->WriteEol())
00258                      return( PR_FALSE);
00259        }
00260        else if (m_eof) {
00261               /*
00262               byte[0] = '=';
00263               if (!m_pOut->WriteData( byte, 1))
00264                      return( FALSE);
00265               */
00266               if (!m_pOut->WriteEol())
00267                      return( PR_FALSE);
00268        }
00269        
00270        m_lineLen = (int) lineLen;
00271        m_pos = pos;
00272        m_bytesProcessed += (pos - start);
00273        return( PR_TRUE);
00274 }
00275 
00276 PRBool nsImportMimeEncode::TranslateFileName( nsCString& inFile, nsCString& outFile)
00277 {
00278        const PRUint8 * pIn = (const PRUint8 *) inFile.get();
00279        int      len = inFile.Length();
00280        
00281        while (len) {
00282               if (!ImportCharSet::IsUSAscii( *pIn))
00283                      break;
00284               len--;
00285               pIn++;
00286        }
00287        if (len) {
00288               // non US ascii!
00289               // assume this string needs translating...
00290               if (!ImportTranslate::ConvertString( inFile, outFile, PR_TRUE)) {
00291                      outFile = inFile;
00292                      return( PR_FALSE);
00293               }
00294               else {
00295                      return( PR_TRUE);
00296               }
00297        }
00298        else {
00299               outFile = inFile;
00300               return( PR_FALSE);
00301        }
00302 }
00303 
00304 PRBool nsImportMimeEncode::WriteFileName( nsCString& fName, PRBool wasTrans, const char *pTag)
00305 {
00306        int                  tagNum = 0;
00307        int                  idx = 0;
00308        PRBool        result = PR_TRUE;
00309        int                  len;
00310        nsCString     numStr;
00311 
00312        while ((((fName.Length() - idx) + strlen( pTag)) > 70) && result) {
00313               len = 68 - strlen( pTag) - 5;
00314               if (wasTrans) {
00315                      if (fName.CharAt( idx + len - 1) == '%')
00316                             len--;
00317                      else if (fName.CharAt( idx + len - 2) == '%')
00318                             len -= 2;
00319               }
00320 
00321               if (result)
00322                      result = m_pOut->WriteStr( "\x09");
00323               if (result)
00324                      result = m_pOut->WriteStr( pTag);
00325               numStr = "*";
00326               numStr.AppendInt( tagNum);
00327               if (result)
00328                      result = m_pOut->WriteStr( numStr.get());
00329               if (wasTrans && result)
00330                      result = m_pOut->WriteStr( "*=");
00331               else if (result)
00332                      result = m_pOut->WriteStr( "=\"");
00333               if (result)
00334                      result = m_pOut->WriteData( ((const PRUint8 *)fName.get()) + idx, len);
00335               if (wasTrans && result)
00336                      result = m_pOut->WriteStr( "\x0D\x0A");
00337               else if (result)
00338                      result = m_pOut->WriteStr( "\"\x0D\x0A");
00339               idx += len;
00340               tagNum++;
00341        }
00342        
00343        if (idx) {
00344               if ((fName.Length() - idx) > 0) {
00345                      if (result)
00346                             result = m_pOut->WriteStr( "\x09");
00347                      if (result)
00348                             result = m_pOut->WriteStr( pTag);
00349                      numStr = "*";
00350                      numStr.AppendInt( tagNum);
00351                      if (result)
00352                             result = m_pOut->WriteStr( numStr.get());
00353                      if (wasTrans && result)
00354                             result = m_pOut->WriteStr( "*=");
00355                      else if (result)
00356                             result = m_pOut->WriteStr( "=\"");
00357                      if (result)
00358                             result = m_pOut->WriteData( ((const PRUint8 *)fName.get()) + idx, fName.Length() - idx);
00359                      if (wasTrans && result)
00360                             result = m_pOut->WriteStr( "\x0D\x0A");
00361                      else if (result)
00362                             result = m_pOut->WriteStr( "\"\x0D\x0A");
00363               }
00364        }
00365        else {
00366               if (result)
00367                      result = m_pOut->WriteStr( "\x09");
00368               if (result)
00369                      result = m_pOut->WriteStr( pTag);
00370               if (wasTrans && result)
00371                      result = m_pOut->WriteStr( "*=");
00372               else if (result)
00373                      result = m_pOut->WriteStr( "=\"");
00374               if (result)
00375                      result = m_pOut->WriteStr( fName.get());
00376               if (wasTrans && result)
00377                      result = m_pOut->WriteStr( "\x0D\x0A");
00378               else if (result)
00379                      result = m_pOut->WriteStr( "\"\x0D\x0A"); 
00380        }
00381 
00382        return( result);
00383 
00384 }
00385 
00386 
00389 nsIImportMimeEncodeImpl::nsIImportMimeEncodeImpl()
00390 {
00391        m_pOut = nsnull;
00392        m_pEncode = nsnull;
00393 }
00394 
00395 nsIImportMimeEncodeImpl::~nsIImportMimeEncodeImpl()
00396 {
00397        if (m_pOut)
00398               delete m_pOut;
00399        if (m_pEncode)
00400               delete m_pEncode;
00401 }
00402 
00403 NS_IMPL_ISUPPORTS1(nsIImportMimeEncodeImpl, nsIImportMimeEncode)
00404 
00405 NS_METHOD nsIImportMimeEncodeImpl::EncodeFile(nsIFileSpec *inFile, nsIFileSpec *outFile, const char *fileName, const char *mimeType)
00406 {
00407        return( Initialize( inFile, outFile, fileName, mimeType));
00408 }
00409 
00410 NS_METHOD nsIImportMimeEncodeImpl::DoWork(PRBool *done, PRBool *_retval)
00411 {
00412        if (done && _retval && m_pEncode) {
00413               *_retval = m_pEncode->DoWork( done);
00414               return( NS_OK);
00415        }
00416        else
00417               return( NS_ERROR_FAILURE);
00418 }
00419 
00420 NS_METHOD nsIImportMimeEncodeImpl::NumBytesProcessed(PRInt32 *_retval)
00421 {
00422        if (m_pEncode && _retval)
00423               *_retval = m_pEncode->NumBytesProcessed();
00424        return( NS_OK);
00425 }
00426 
00427 NS_METHOD nsIImportMimeEncodeImpl::DoEncoding(PRBool *_retval)
00428 {
00429        if (_retval && m_pEncode) {
00430               PRBool done = PR_FALSE;
00431               while (m_pEncode->DoWork( &done) && !done);
00432               *_retval = done;
00433               return( NS_OK);
00434        }
00435        else
00436               return( NS_ERROR_FAILURE);
00437 }
00438 
00439 NS_METHOD nsIImportMimeEncodeImpl::Initialize(nsIFileSpec *inFile, nsIFileSpec *outFile, const char *fileName, const char *mimeType)
00440 {
00441        if (m_pEncode)
00442               delete m_pEncode;
00443        if (m_pOut)
00444               delete m_pOut;
00445 
00446        m_pOut = new ImportOutFile();
00447        m_pOut->InitOutFile( outFile);
00448 
00449        m_pEncode = new nsImportMimeEncode();
00450        m_pEncode->EncodeFile( inFile, m_pOut, fileName, mimeType);
00451 
00452        return( NS_OK);
00453 }
00454