Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Private Member Functions | Private Attributes
nsMsgAttachmentHandler Class Reference

#include <nsMsgAttachmentHandler.h>

Collaboration diagram for nsMsgAttachmentHandler:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsMsgAttachmentHandler ()
 ~nsMsgAttachmentHandler ()
nsresult SnarfAttachment (nsMsgCompFields *compFields)
int PickEncoding (const char *charset, nsIMsgSend *mime_delivery_state)
void AnalyzeSnarfedFile ()
nsresult Abort ()
nsresult UrlExit (nsresult status, const PRUnichar *aMsg)
nsresult GetMimeDeliveryState (nsIMsgSend **_retval)
nsresult SetMimeDeliveryState (nsIMsgSend *mime_delivery_state)

Public Attributes

nsCOMPtr< nsIURImURL
nsFileSpecmFileSpec
nsCOMPtr< nsIFileOutputStreammOutFile
nsIRequestmRequest
nsMsgCompFieldsmCompFields
PRBool m_bogus_attachment
char * m_x_mac_type
char * m_x_mac_creator
PRBool m_done
char * m_charset
char * m_content_id
char * m_type
char * m_type_param
char * m_override_type
char * m_override_encoding
char * m_desired_type
char * m_description
char * m_real_name
char * m_encoding
PRBool m_already_encoded_p
PRBool m_decrypted_p
PRBool mDeleteFile
PRBool mMHTMLPart
PRBool mPartUserOmissionOverride
PRBool mMainBody
PRUint32 m_size
PRUint32 m_unprintable_count
PRUint32 m_highbit_count
PRUint32 m_ctl_count
PRUint32 m_null_count
PRUint8 m_have_cr
PRUint8 m_have_lf
PRUint8 m_have_crlf
PRBool m_prev_char_was_cr
PRUint32 m_current_column
PRUint32 m_max_column
PRUint32 m_lines
PRBool m_file_analyzed
MimeEncoderDatam_encoder_data
char * m_uri

Private Member Functions

nsresult SnarfMsgAttachment (nsMsgCompFields *compFields)
PRBool UseUUEncode_p (void)
void AnalyzeDataChunk (const char *chunk, PRInt32 chunkSize)
nsresult LoadDataFromFile (nsFileSpec &fSpec, nsString &sigData, PRBool charsetConversion)

Private Attributes

nsCOMPtr< nsIMsgSendm_mime_delivery_state
nsCOMPtr< nsIStreamConverterm_mime_parser
nsCOMPtr< nsIChannelm_converter_channel

Detailed Description

Definition at line 68 of file nsMsgAttachmentHandler.h.


Constructor & Destructor Documentation

Definition at line 93 of file nsMsgAttachmentHandler.cpp.

{
#if defined(DEBUG_ducarroz)
  printf("CREATE nsMsgAttachmentHandler: %x\n", this);
#endif
  mMHTMLPart = PR_FALSE;
  mPartUserOmissionOverride = PR_FALSE;
  mMainBody = PR_FALSE;

  m_charset = nsnull;
  m_override_type = nsnull;
  m_override_encoding = nsnull;
  m_desired_type = nsnull;
  m_description = nsnull;
  m_encoding = nsnull;
  m_real_name = nsnull;
  m_encoding = nsnull;
  m_content_id = nsnull;
  m_already_encoded_p = PR_FALSE;
  m_decrypted_p = PR_FALSE;
  
  // For analyzing the attachment file...
  m_file_analyzed = PR_FALSE;
  m_ctl_count = 0;
  m_null_count = 0;
  m_have_cr = m_have_lf = m_have_crlf = 0;
  m_prev_char_was_cr = PR_FALSE;
  m_current_column = 0;
  m_max_column = 0;
  m_lines = 0;
  m_unprintable_count = 0;
  m_highbit_count = 0;

  // Mime encoder...
  m_encoder_data = nsnull;

  m_done = PR_FALSE;
  m_type = nsnull;
  m_type_param = nsnull;
  m_size = 0;

  mCompFields = nsnull;   // Message composition fields for the sender
  mFileSpec = nsnull;
  mURL = nsnull;
  mRequest = nsnull;

  m_x_mac_type = nsnull;
  m_x_mac_creator = nsnull;

#if defined(XP_MAC) || defined(XP_MACOSX)
  mAppleFileSpec = nsnull;
#endif

  mDeleteFile = PR_FALSE;
  m_uri = nsnull;
}

Definition at line 150 of file nsMsgAttachmentHandler.cpp.

{
#if defined(DEBUG_ducarroz)
  printf("DISPOSE nsMsgAttachmentHandler: %x\n", this);
#endif
#if defined(XP_MAC) || defined(XP_MACOSX)
  if (mAppleFileSpec)
    delete mAppleFileSpec;
#endif

  if (mFileSpec && mDeleteFile)
    mFileSpec->Delete(PR_FALSE);

  delete mFileSpec;
  mFileSpec=nsnull;

  PR_Free(m_charset);
  PR_Free(m_type);
  PR_Free(m_type_param);
  PR_Free(m_content_id);
  PR_Free(m_desired_type);
  PR_Free(m_encoding);
  PR_Free(m_override_type);
  PR_Free(m_description);
  PR_Free(m_real_name);
  PR_Free(m_override_encoding);
  PR_Free(m_x_mac_type);
  PR_Free(m_x_mac_creator);
  PR_Free(m_uri);
}

Member Function Documentation

Definition at line 1030 of file nsMsgAttachmentHandler.cpp.

{
  NS_ASSERTION(m_mime_delivery_state != nsnull, "not-null m_mime_delivery_state");

  if (m_done)
    return NS_OK;

  if (mRequest)
    return mRequest->Cancel(NS_ERROR_ABORT);
  else
    if (m_mime_delivery_state)
    {
      m_mime_delivery_state->SetStatus(NS_ERROR_ABORT);
      m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, NS_ERROR_ABORT, 0, nsnull);
    }

  return NS_OK;

}
void nsMsgAttachmentHandler::AnalyzeDataChunk ( const char *  chunk,
PRInt32  chunkSize 
) [private]

Definition at line 182 of file nsMsgAttachmentHandler.cpp.

{
  unsigned char *s = (unsigned char *) chunk;
  unsigned char *end = s + length;
  for (; s < end; s++)
  {
    if (*s > 126)
    {
      m_highbit_count++;
      m_unprintable_count++;
    }
    else if (*s < ' ' && *s != '\t' && *s != nsCRT::CR && *s != nsCRT::LF)
    {
      m_unprintable_count++;
      m_ctl_count++;
      if (*s == 0)
        m_null_count++;
    }

    if (*s == nsCRT::CR || *s == nsCRT::LF)
    {
      if (*s == nsCRT::CR)
      {
        if (m_prev_char_was_cr)
          m_have_cr = 1;
        else
          m_prev_char_was_cr = PR_TRUE;
      }
      else
      {
        if (m_prev_char_was_cr)
        {
          if (m_current_column == 0)
          {
            m_have_crlf = 1;
            m_lines--;
          }
          else
            m_have_cr = m_have_lf = 1;
          m_prev_char_was_cr = PR_FALSE;
        }
        else
          m_have_lf = 1;
      }
      if (m_max_column < m_current_column)
        m_max_column = m_current_column;
      m_current_column = 0;
      m_lines++;
    }
    else
    {
      m_current_column++;
    }
  }
}

Here is the caller graph for this function:

Definition at line 239 of file nsMsgAttachmentHandler.cpp.

{
  char chunk[1024];
  PRInt32 numRead = 0;

  if (m_file_analyzed)
    return;

  if (mFileSpec)
  {
    m_size = mFileSpec->GetFileSize();
    nsInputFileStream fileHdl(*mFileSpec, PR_RDONLY, 0);
    if (fileHdl.is_open())
    {
      do
      {
        numRead = fileHdl.read(chunk, sizeof(chunk));
        if (numRead > 0)
          AnalyzeDataChunk(chunk, numRead);
      }
      while (numRead > 0);
      if (m_prev_char_was_cr)
        m_have_cr = 1;

      fileHdl.close();
      m_file_analyzed = PR_TRUE;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1321 of file nsMsgAttachmentHandler.cpp.

{
  NS_ENSURE_ARG(_retval);
  *_retval = m_mime_delivery_state;
  NS_IF_ADDREF(*_retval);
  return NS_OK;
}
nsresult nsMsgAttachmentHandler::LoadDataFromFile ( nsFileSpec fSpec,
nsString sigData,
PRBool  charsetConversion 
) [private]

Definition at line 999 of file nsMsgAttachmentHandler.cpp.

{
  PRInt32       readSize;
  char          *readBuf;

  nsInputFileStream tempFile(fSpec);
  if (!tempFile.is_open())
    return NS_MSG_ERROR_WRITING_FILE;        
  
  readSize = fSpec.GetFileSize();
  readBuf = (char *)PR_Malloc(readSize + 1);
  if (!readBuf)
    return NS_ERROR_OUT_OF_MEMORY;
  memset(readBuf, 0, readSize + 1);

  readSize = tempFile.read(readBuf, readSize);
  tempFile.close();

  if (charsetConversion)
  {
    if (NS_FAILED(ConvertToUnicode(m_charset, nsDependentCString(readBuf), sigData)))
      CopyASCIItoUTF16(readBuf, sigData);
  }
  else
    CopyASCIItoUTF16(readBuf, sigData);

  PR_FREEIF(readBuf);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int nsMsgAttachmentHandler::PickEncoding ( const char *  charset,
nsIMsgSend mime_delivery_state 
)

Definition at line 274 of file nsMsgAttachmentHandler.cpp.

{
  nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
  
  // use the boolean so we only have to test for uuencode vs base64 once
  PRBool needsB64 = PR_FALSE;
  PRBool forceB64 = PR_FALSE;
  
  if (m_already_encoded_p)
    goto DONE;
  
  AnalyzeSnarfedFile();

  /* Allow users to override our percentage-wise guess on whether
  the file is text or binary */
  if (pPrefBranch) 
    pPrefBranch->GetBoolPref ("mail.file_attach_binary", &forceB64);
  
  if (!mMainBody && (forceB64 || mime_type_requires_b64_p (m_type) ||
    m_have_cr+m_have_lf+m_have_crlf != 1 || m_current_column != 0))
  {
  /* If the content-type is "image/" or something else known to be binary
  or several flavors of newlines are present or last line is incomplete,
  always use base64 (so that we don't get confused by newline
  conversions.)
     */
    needsB64 = PR_TRUE;
  }
  else
  {
  /* Otherwise, we need to pick an encoding based on the contents of
  the document.
     */
    
    PRBool encode_p;
    PRBool force_p = PR_FALSE;
    
    /*
      force quoted-printable if the sender does not allow
      conversion to 7bit
    */
    if (mCompFields) {
      if (mCompFields->GetForceMsgEncoding())
        force_p = PR_TRUE;
    }
    else if (mime_delivery_state) {
      if (((nsMsgComposeAndSend *)mime_delivery_state)->mCompFields->GetForceMsgEncoding())
        force_p = PR_TRUE;
    }
    
    if (force_p || (m_max_column > 900))
      encode_p = PR_TRUE;
    else if (UseQuotedPrintable() && m_unprintable_count)
      encode_p = PR_TRUE;
    
      else if (m_null_count)  /* If there are nulls, we must always encode,
        because sendmail will blow up. */
        encode_p = PR_TRUE;
      else
        encode_p = PR_FALSE;
      
        /* MIME requires a special case that these types never be encoded.
      */
      if (!PL_strncasecmp (m_type, "message", 7) ||
        !PL_strncasecmp (m_type, "multipart", 9))
      {
        encode_p = PR_FALSE;
        if (m_desired_type && !PL_strcasecmp (m_desired_type, TEXT_PLAIN))
        {
          PR_Free (m_desired_type);
          m_desired_type = 0;
        }
      }

      // If the Mail charset is multibyte, we force it to use Base64 for attachments.
      if ((!mMainBody && charset && nsMsgI18Nmultibyte_charset(charset)) &&
        ((PL_strcasecmp(m_type, TEXT_HTML) == 0) ||
        (PL_strcasecmp(m_type, TEXT_MDL) == 0) ||
        (PL_strcasecmp(m_type, TEXT_PLAIN) == 0) ||
        (PL_strcasecmp(m_type, TEXT_RICHTEXT) == 0) ||
        (PL_strcasecmp(m_type, TEXT_ENRICHED) == 0) ||
        (PL_strcasecmp(m_type, TEXT_VCARD) == 0) ||
        (PL_strcasecmp(m_type, APPLICATION_DIRECTORY) == 0) || /* text/x-vcard synonym */
        (PL_strcasecmp(m_type, TEXT_CSS) == 0) ||
        (PL_strcasecmp(m_type, TEXT_JSSS) == 0)))
      {
        needsB64 = PR_TRUE;
      }
      else if (charset && nsMsgI18Nstateful_charset(charset)) 
      {
        PR_FREEIF(m_encoding);
        m_encoding = PL_strdup (ENCODING_7BIT);
      }
      else if (encode_p &&
        m_unprintable_count > (m_size / 10))
        /* If the document contains more than 10% unprintable characters,
        then that seems like a good candidate for base64 instead of
        quoted-printable.
        */
        needsB64 = PR_TRUE;
      else if (encode_p) {
        PR_FREEIF(m_encoding);
        m_encoding = PL_strdup (ENCODING_QUOTED_PRINTABLE);
      }
      else if (m_highbit_count > 0) {
        PR_FREEIF(m_encoding);
        m_encoding = PL_strdup (ENCODING_8BIT);
      }
      else {
        PR_FREEIF(m_encoding);
        m_encoding = PL_strdup (ENCODING_7BIT);
      }
  }
  
  if (needsB64)
  {
    //
    // We might have to uuencode instead of base64 the binary data.
    //
    PR_FREEIF(m_encoding);
    if (UseUUEncode_p())
      m_encoding = PL_strdup (ENCODING_UUENCODE);
    else
      m_encoding = PL_strdup (ENCODING_BASE64);
  }
  
  /* Now that we've picked an encoding, initialize the filter.
  */
  NS_ASSERTION(!m_encoder_data, "not-null m_encoder_data");
  if (!PL_strcasecmp(m_encoding, ENCODING_BASE64))
  {
    m_encoder_data = MIME_B64EncoderInit(mime_encoder_output_fn,
      mime_delivery_state);
    if (!m_encoder_data) return NS_ERROR_OUT_OF_MEMORY;
  }
  else if (!PL_strcasecmp(m_encoding, ENCODING_UUENCODE))
  {
    char        *tailName = NULL;
    nsXPIDLCString turl;
    
    if (mURL)
    {
      mURL->GetSpec(turl);
      
      tailName = PL_strrchr(turl, '/');
      if (tailName) 
      {
        char * tmp = tailName;
        tailName = PL_strdup(tailName+1);
        PR_FREEIF(tmp);
      }
    }
    
    if (mURL && !tailName)
    {
      tailName = PL_strrchr(turl, '/');
      if (tailName) 
      {
        char * tmp = tailName;
        tailName = PL_strdup(tailName+1);
        PR_FREEIF(tmp);
      }
    }

    m_encoder_data = MIME_UUEncoderInit((char *)(tailName ? tailName : ""),
      mime_encoder_output_fn,
      mime_delivery_state);
    PR_FREEIF(tailName);
    if (!m_encoder_data) return NS_ERROR_OUT_OF_MEMORY;
  }
  else if (!PL_strcasecmp(m_encoding, ENCODING_QUOTED_PRINTABLE))
  {
    m_encoder_data = MIME_QPEncoderInit(mime_encoder_output_fn,
      mime_delivery_state);
    if (!m_encoder_data) return NS_ERROR_OUT_OF_MEMORY;
  }
  else
  {
    m_encoder_data = 0;
  }  
  
  /* Do some cleanup for documents with unknown content type.
    There are two issues: how they look to MIME users, and how they look to
    non-MIME users.
    
      If the user attaches a "README" file, which has unknown type because it
      has no extension, we still need to send it with no encoding, so that it
      is readable to non-MIME users.
      
        But if the user attaches some random binary file, then base64 encoding
        will have been chosen for it (above), and in this case, it won't be
        immediately readable by non-MIME users.  However, if we type it as
        text/plain instead of application/octet-stream, it will show up inline
        in a MIME viewer, which will probably be ugly, and may possibly have
        bad charset things happen as well.
        
          So, the heuristic we use is, if the type is unknown, then the type is
          set to application/octet-stream for data which needs base64 (binary data)
          and is set to text/plain for data which didn't need base64 (unencoded or
          lightly encoded data.)
  */
DONE:
  if (!m_type || !*m_type || !PL_strcasecmp(m_type, UNKNOWN_CONTENT_TYPE))
  {
    PR_FREEIF(m_type);
    if (m_already_encoded_p)
      m_type = PL_strdup (APPLICATION_OCTET_STREAM);
    else if (m_encoding &&
         (!PL_strcasecmp(m_encoding, ENCODING_BASE64) ||
         !PL_strcasecmp(m_encoding, ENCODING_UUENCODE)))
         m_type = PL_strdup (APPLICATION_OCTET_STREAM);
    else
      m_type = PL_strdup (TEXT_PLAIN);
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1330 of file nsMsgAttachmentHandler.cpp.

{
  /*
    Because setting m_mime_delivery_state to null could destroy ourself as
    m_mime_delivery_state it's our parent, we need to protect ourself against
    that!

    This extra comptr is necessary,
    see bug http://bugzilla.mozilla.org/show_bug.cgi?id=78967
  */
  nsCOMPtr<nsIMsgSend> temp = m_mime_delivery_state; /* Should lock our parent until the end of the function */
  m_mime_delivery_state = mime_delivery_state;
  return NS_OK;
}

Here is the caller graph for this function:

Definition at line 671 of file nsMsgAttachmentHandler.cpp.

{
  nsresult      status = 0;
  nsXPIDLCString url_string;

  NS_ASSERTION (! m_done, "Already done");

  if (!mURL)
    return SnarfMsgAttachment(compFields);

  mCompFields = compFields;

  // First, get as file spec and create the stream for the
  // temp file where we will save this data
    mFileSpec = nsMsgCreateTempFileSpec("nsmail.tmp");
  if (! mFileSpec )
    return (NS_ERROR_FAILURE);
  mDeleteFile = PR_TRUE;

  nsCOMPtr<nsILocalFile> localFile;
  nsCOMPtr<nsIOutputStream> outputStream;
  NS_FileSpecToIFile(mFileSpec, getter_AddRefs(localFile));
  status = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), localFile, -1, 00600);
  if (NS_FAILED(status) || !outputStream || CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_3))
  {
    if (m_mime_delivery_state)
    {
      nsCOMPtr<nsIMsgSendReport> sendReport;
      m_mime_delivery_state->GetSendReport(getter_AddRefs(sendReport));
      if (sendReport)
      {
        nsAutoString error_msg;
        nsAutoString path;
        NS_CopyNativeToUnicode(
          nsDependentCString(mFileSpec->GetNativePathCString()), path);
        nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
        sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
      }
    }
    mFileSpec->Delete(PR_FALSE);
    delete mFileSpec;
    mFileSpec = nsnull;
    return NS_MSG_UNABLE_TO_OPEN_TMP_FILE; 
  }
  mOutFile = do_QueryInterface(outputStream);

  mURL->GetSpec(url_string);

#if defined(XP_MAC) || defined(XP_MACOSX)
  if ( !m_bogus_attachment && nsMsgIsLocalFile(url_string))
  {
    // convert the apple file to AppleDouble first, and then patch the
    // address in the url.
    char *src_filename = nsMsgGetLocalFileFromURL (url_string);
    if (!src_filename)
      return NS_ERROR_OUT_OF_MEMORY;

    // Unescape the name before making FSSpec
    nsCAutoString escapedFilename(src_filename);
    nsUnescape(escapedFilename.BeginWriting());

    //We need to retrieve the file type and creator...
    nsFileSpec scr_fileSpec(escapedFilename.get());
    FSSpec fsSpec;
#if defined(XP_MAC)
    fsSpec = scr_fileSpec.GetFSSpec();
#elif defined(XP_MACOSX)
    Boolean isDir;
    FSPathMakeFSSpec((UInt8 *)escapedFilename.get(), &fsSpec, &isDir);
#endif
    FInfo info;
    if (FSpGetFInfo (&fsSpec, &info) == noErr)
    {
      char filetype[32];
      PR_snprintf(filetype, sizeof(filetype), "%X", info.fdType);
      PR_FREEIF(m_x_mac_type);
      m_x_mac_type = PL_strdup(filetype);

      PR_snprintf(filetype, sizeof(filetype), "%X", info.fdCreator);
      PR_FREEIF(m_x_mac_creator);
      m_x_mac_creator = PL_strdup(filetype);
    }

    PRBool sendResourceFork = PR_TRUE;
    PRBool icGaveNeededInfo = PR_FALSE;
    nsCOMPtr<nsIInternetConfigService> icService (do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID));
    if (icService)
    {
      PRInt32 icFlags;
      // be sure to look up by extension first (so pass in PR_TRUE). See Bug #229855
      nsresult rv = icService->GetFileMappingFlags(&fsSpec, PR_TRUE, &icFlags);
      if (NS_SUCCEEDED(rv) && icFlags != -1 && !(icFlags & nsIInternetConfigService::eIICMapFlag_NotOutgoingMask))
      {
        sendResourceFork = (icFlags & nsIInternetConfigService::eIICMapFlag_ResourceForkMask);

        if (sendResourceFork)
        {
          // before deciding to send the resource fork along the data fork, check if we have one,
          // else don't need to use apple double.
#if defined(XP_MAC) || defined(XP_MACOSX)
          sendResourceFork = HasResourceFork(&fsSpec);
#endif
        }
        
        icGaveNeededInfo = PR_TRUE;
      }
    }
    
    if (! icGaveNeededInfo)
    {
      // If InternetConfig cannot help us, then just try our best...
      // first check if we have a resource fork
      sendResourceFork = HasResourceFork(&fsSpec);

      // then, if we have a resource fork, check the filename extension, maybe we don't need the resource fork!
      if (sendResourceFork)
      {
        nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID));
        if (fileUrl)
        {
          nsresult rv = fileUrl->SetSpec(url_string);
          if (NS_SUCCEEDED(rv))
          {
            nsCAutoString ext;
            rv = fileUrl->GetFileExtension(ext);
            if (NS_SUCCEEDED(rv) && !ext.IsEmpty())
            {
              sendResourceFork =
                 PL_strcasecmp(ext.get(), "TXT") &&
                 PL_strcasecmp(ext.get(), "JPG") &&
                 PL_strcasecmp(ext.get(), "GIF") &&
                 PL_strcasecmp(ext.get(), "TIF") &&
                 PL_strcasecmp(ext.get(), "HTM") &&
                 PL_strcasecmp(ext.get(), "HTML") &&
                 PL_strcasecmp(ext.get(), "ART") &&
                 PL_strcasecmp(ext.get(), "XUL") &&
                 PL_strcasecmp(ext.get(), "XML") &&
                 PL_strcasecmp(ext.get(), "CSS") &&
                 PL_strcasecmp(ext.get(), "JS");
            }
          }
        }
      }
    }

    // Only use appledouble if we aren't uuencoding.
    if( sendResourceFork && (! UseUUEncode_p()) )
    {
      char                *separator;
      nsInputFileStream   *myInputFile = new nsInputFileStream(scr_fileSpec);

      if ((!myInputFile) || (!myInputFile->is_open()))
        return NS_ERROR_OUT_OF_MEMORY;

      separator = mime_make_separator("ad");
      if (!separator)
      {
        delete myInputFile;
        PR_FREEIF(src_filename);
        return NS_ERROR_OUT_OF_MEMORY;
      }
            
      mAppleFileSpec = nsMsgCreateTempFileSpec("appledouble");
      if (!mAppleFileSpec) 
      {
        delete myInputFile;
        PR_FREEIF(separator);
        PR_FREEIF(src_filename);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      //
      // RICHIE_MAC - ok, here's the deal, we have a file that we need
      // to encode in appledouble encoding for the resource fork and put that
      // into the mAppleFileSpec location. Then, we need to patch the new file 
      // spec into the array and send this as part of the 2 part appledouble/mime
      // encoded mime part. 
      // 
      AppleDoubleEncodeObject     *obj = new (AppleDoubleEncodeObject);
      if (obj == NULL) 
      {
        delete mAppleFileSpec;
        PR_FREEIF(src_filename);
        PR_FREEIF(separator);
        return NS_ERROR_OUT_OF_MEMORY;
      }
   
      obj->fileStream = new nsIOFileStream(*mAppleFileSpec, (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE));
      if ( (!obj->fileStream) || (!obj->fileStream->is_open()) )
      {
        delete myInputFile;
        PR_FREEIF(src_filename);
        PR_FREEIF(separator);
        delete obj;
        return NS_ERROR_OUT_OF_MEMORY;
      }

      PRInt32     bSize = AD_WORKING_BUFF_SIZE;

      char  *working_buff = nsnull;
      while (!working_buff && (bSize >= 512))
      {
        working_buff = (char *)PR_CALLOC(bSize);
        if (!working_buff)
          bSize /= 2;
      }

      if (!working_buff)
      {
        PR_FREEIF(src_filename);
        PR_FREEIF(separator);
        delete obj;
        return NS_ERROR_OUT_OF_MEMORY;
      }

      obj->buff = working_buff;
      obj->s_buff = bSize;  

      //
      //  Setup all the need information on the apple double encoder.
      //
      ap_encode_init(&(obj->ap_encode_obj), escapedFilename.get(), separator);

      PRInt32 count;

      status = noErr;
      m_size = 0;
      while (status == noErr)
      {      
        status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, bSize, &count);
        if (status == noErr || status == errDone)
        {
          //
          // we got the encode data, so call the next stream to write it to the disk.
          //
          if (obj->fileStream->write(obj->buff, count) != count)
            status = NS_MSG_ERROR_WRITING_FILE;
        }
      } 
      
      delete myInputFile;  
      ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort
      if (obj->fileStream)
        obj->fileStream->close();

      PR_FREEIF(obj->buff);               /* free the working buff.   */
      PR_FREEIF(obj);

      char *newURLSpec = nsMsgPlatformFileToURL(*mAppleFileSpec);

      if (!newURLSpec) 
      {
        PR_FREEIF(src_filename);
        PR_FREEIF(separator);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec)))
      {
        PR_FREEIF(src_filename);
        PR_FREEIF(separator);
        PR_FREEIF(newURLSpec);
        return NS_ERROR_OUT_OF_MEMORY;
      }
  
      PR_FREEIF(newURLSpec);
      
      // Now after conversion, also patch the types.
      char        tmp[128];
      PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator);
      PR_FREEIF(separator);
      PR_FREEIF (m_type);
      m_type = PL_strdup(tmp);
    }
    else
    {
      if ( sendResourceFork )
      {
        // The only time we want to send just the data fork of a two-fork
        // Mac file is if uuencoding has been requested.
        NS_ASSERTION(UseUUEncode_p(), "not UseUUEncode_p");

        // For now, just do the encoding, but in the old world we would ask the
        // user about doing this conversion
        printf("...we could ask the user about this conversion, but for now, nahh..\n");
      }

      PRBool    useDefault;
      char      *macType, *macEncoding;
      if (m_type == NULL || !PL_strcasecmp (m_type, TEXT_PLAIN))
      {
# define TEXT_TYPE  0x54455854  /* the characters 'T' 'E' 'X' 'T' */
# define text_TYPE  0x74657874  /* the characters 't' 'e' 'x' 't' */

        if (info.fdType != TEXT_TYPE && info.fdType != text_TYPE)
        {
          MacGetFileType(&scr_fileSpec, &useDefault, &macType, &macEncoding);
          PR_FREEIF(m_type);
          m_type = macType;
        }
      }
      // don't bother to set the types if we failed in getting the file info.
    }

    PR_FREEIF(src_filename);
  }
#endif /* XP_MAC */

  //
  // Ok, here we are, we need to fire the URL off and get the data
  // in the temp file
  //
  // Create a fetcher for the URL attachment...

  nsresult rv;
  nsCOMPtr<nsIURLFetcher> fetcher = do_CreateInstance(NS_URLFETCHER_CONTRACTID, &rv);
  if (NS_FAILED(rv) || !fetcher)
  {
    if (NS_SUCCEEDED(rv))
      return NS_ERROR_UNEXPECTED;
    else
      return rv;
  }

  return fetcher->FireURLRequest(mURL, localFile, mOutFile, FetcherURLDoneCallback, this);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 532 of file nsMsgAttachmentHandler.cpp.

{
  nsresult rv = NS_ERROR_INVALID_ARG;
  nsCOMPtr <nsIMsgMessageService> messageService;

  if (PL_strcasestr(m_uri, "-message:"))
  {
    mFileSpec = nsMsgCreateTempFileSpec("nsmail.tmp");
    mDeleteFile = PR_TRUE;
    mCompFields = compFields;
    PR_FREEIF(m_type);
    m_type = PL_strdup(MESSAGE_RFC822);
    PR_FREEIF(m_override_type);
    m_override_type = PL_strdup(MESSAGE_RFC822);
    if (!mFileSpec) 
    {
      rv = NS_ERROR_FAILURE;
      goto done;
    }

    nsCOMPtr<nsILocalFile> localFile;
    nsCOMPtr<nsIOutputStream> outputStream;
    NS_FileSpecToIFile(mFileSpec, getter_AddRefs(localFile));
    rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), localFile, -1, 00600);
    if (NS_FAILED(rv) || !outputStream || CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_3))
    {
      if (m_mime_delivery_state)
      {
        nsCOMPtr<nsIMsgSendReport> sendReport;
        m_mime_delivery_state->GetSendReport(getter_AddRefs(sendReport));
        if (sendReport)
        {
          nsAutoString error_msg;
          nsAutoString path;
          NS_CopyNativeToUnicode(
            nsDependentCString(mFileSpec->GetNativePathCString()), path);
          nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull);
          sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE);
        }
      }
      rv =  NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
      goto done;
    }
    mOutFile = do_QueryInterface(outputStream);
    
    nsCOMPtr<nsIURLFetcher> fetcher = do_CreateInstance(NS_URLFETCHER_CONTRACTID, &rv);
    if (NS_FAILED(rv) || !fetcher)
    {
      if (NS_SUCCEEDED(rv))
        rv =  NS_ERROR_UNEXPECTED;
      goto done;
    }

    rv = fetcher->Initialize(localFile, mOutFile, FetcherURLDoneCallback, this);
    rv = GetMessageServiceFromURI(m_uri, getter_AddRefs(messageService));
    if (NS_SUCCEEDED(rv) && messageService)
    {
      nsCAutoString uri(m_uri);
      uri += (uri.FindChar('?') == kNotFound) ? "?" : "&";
      uri.Append("fetchCompleteMessage=true");
      nsCOMPtr<nsIStreamListener> strListener;
      fetcher->QueryInterface(NS_GET_IID(nsIStreamListener), getter_AddRefs(strListener));

      // initialize a new stream converter, that uses the strListener as its input
      // obtain the input stream listener from the new converter,
      // and pass the converter's input stream listener to DisplayMessage

      m_mime_parser = do_CreateInstance(NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID, &rv);
      if (NS_FAILED(rv))
        goto done;

      // Set us as the output stream for HTML data from libmime...
      nsCOMPtr<nsIMimeStreamConverter> mimeConverter = do_QueryInterface(m_mime_parser);
      if (mimeConverter)
      {
        mimeConverter->SetMimeOutputType(nsMimeOutput::nsMimeMessageDecrypt);
        mimeConverter->SetForwardInline(PR_FALSE);
        mimeConverter->SetIdentity(nsnull);
        mimeConverter->SetOriginalMsgURI(nsnull);
      }

      nsCOMPtr<nsIStreamListener> convertedListener = do_QueryInterface(m_mime_parser, &rv);
      if (NS_FAILED(rv))
        goto done;

      nsCOMPtr<nsIURI> aURL;
      rv = messageService->GetUrlForUri(uri.get(), getter_AddRefs(aURL), nsnull);
      if (aURL)
        aURL->SetSpec(nsDependentCString(uri.get()));

      rv = NS_NewInputStreamChannel(getter_AddRefs(m_converter_channel), aURL, nsnull);
      if (NS_FAILED(rv))
        goto done;

      rv = m_mime_parser->AsyncConvertData(
                  "message/rfc822",
                  "message/rfc822",
                  strListener, m_converter_channel);
      if (NS_FAILED(rv))
        goto done;

      rv = messageService->DisplayMessage(uri.get(), convertedListener, nsnull, nsnull, nsnull, nsnull);
    }
  }
done:
  if (NS_FAILED(rv))
  {
      if (mOutFile)
      {
        mOutFile->Close();
        mOutFile = nsnull;
      }

      if (mFileSpec)
      {
        mFileSpec->Delete(PR_FALSE);
        delete mFileSpec;
        mFileSpec = nsnull;
      }
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1051 of file nsMsgAttachmentHandler.cpp.

{
  NS_ASSERTION(m_mime_delivery_state != nsnull, "not-null m_mime_delivery_state");

  // Close the file, but don't delete the disk file (or the file spec.) 
  if (mOutFile)
  {
    mOutFile->Close();
    mOutFile = nsnull;
  }
  
  mRequest = nsnull;

  // First things first, we are now going to see if this is an HTML
  // Doc and if it is, we need to see if we can determine the charset 
  // for this part by sniffing the HTML file.
  // This is needed only when the charset is not set already.
  // (e.g. a charset may be specified in HTTP header)
  //
  if ( (m_type) &&  (*m_type) &&
       (!m_charset || !(*m_charset)) ) 
  {
    if (PL_strcasecmp(m_type, TEXT_HTML) == 0)
    {
      char *tmpCharset = (char *)nsMsgI18NParseMetaCharset(mFileSpec);
      if (tmpCharset[0] != '\0')
      {
        PR_FREEIF(m_charset);
        m_charset = PL_strdup(tmpCharset);
      }
    }
  }

  nsresult mimeDeliveryStatus;
  m_mime_delivery_state->GetStatus(&mimeDeliveryStatus);
  
  if (mimeDeliveryStatus == NS_ERROR_ABORT)
    status = NS_ERROR_ABORT;
 
  if (NS_FAILED(status) && status != NS_ERROR_ABORT && NS_SUCCEEDED(mimeDeliveryStatus))
  {
    // At this point, we should probably ask a question to the user 
    // if we should continue without this attachment.
    //
    PRBool            keepOnGoing = PR_TRUE;
    nsXPIDLCString    turl;
    nsXPIDLString     msg;
    PRUnichar         *printfString = nsnull;
    nsCOMPtr<nsIMsgStringService> composebundle (do_GetService(NS_MSG_COMPOSESTRINGSERVICE_CONTRACTID));

    nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow;
    m_mime_delivery_state->GetDeliveryMode(&mode);
    if (mode == nsIMsgSend::nsMsgSaveAsDraft || mode == nsIMsgSend::nsMsgSaveAsTemplate)
      composebundle->GetStringByID(NS_MSG_FAILURE_ON_OBJ_EMBED_WHILE_SAVING, getter_Copies(msg));
    else
      composebundle->GetStringByID(NS_MSG_FAILURE_ON_OBJ_EMBED_WHILE_SENDING, getter_Copies(msg));
 
    if (m_real_name && *m_real_name)
      printfString = nsTextFormatter::smprintf(msg, m_real_name);
    else
    if (NS_SUCCEEDED(mURL->GetSpec(turl)) && (turl))
      {
        nsCAutoString unescapeUrl(turl);
        nsUnescape(unescapeUrl.BeginWriting());
        if (unescapeUrl.IsEmpty())
          printfString = nsTextFormatter::smprintf(msg, turl.get());
        else
          printfString = nsTextFormatter::smprintf(msg, unescapeUrl.get());
      }
    else
      printfString = nsTextFormatter::smprintf(msg, "?");

    nsCOMPtr<nsIPrompt> aPrompt;
    if (m_mime_delivery_state)
      m_mime_delivery_state->GetDefaultPrompt(getter_AddRefs(aPrompt));
    nsMsgAskBooleanQuestionByString(aPrompt, printfString, &keepOnGoing);
    PR_FREEIF(printfString);

    if (keepOnGoing)
    {
      status = 0;
      m_bogus_attachment = PR_TRUE; //That will cause this attachment to be ignored.
    }
    else
    {
      status = NS_ERROR_ABORT;
      m_mime_delivery_state->SetStatus(status);
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, nsnull, &ignoreMe);
      m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, 0, nsnull);
      SetMimeDeliveryState(nsnull);
      return status;
    }
  }

  m_done = PR_TRUE;

  //
  // Ok, now that we have the file here on disk, we need to see if there was 
  // a need to do conversion to plain text...if so, the magic happens here,
  // otherwise, just move on to other attachments...
  //
  if (NS_SUCCEEDED(status) && m_type && PL_strcasecmp(m_type, TEXT_PLAIN) ) 
  {
    if (m_desired_type && !PL_strcasecmp(m_desired_type, TEXT_PLAIN) )
    {
      //
      // Conversion to plain text desired.
      //
      PRInt32       width = 72;
      nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
      if (pPrefBranch)
        pPrefBranch->GetIntPref("mailnews.wraplength", &width);
      // Let sanity reign!
      if (width == 0) 
        width = 72;
      else if (width < 10) 
        width = 10;
      else if (width > 30000) 
        width = 30000;

      //
      // Now use the converter service here to do the right 
      // thing and convert this data to plain text for us!
      //
      nsAutoString      conData;

      if (NS_SUCCEEDED(LoadDataFromFile(*mFileSpec, conData, PR_TRUE)))
      {
        if (NS_SUCCEEDED(ConvertBufToPlainText(conData, UseFormatFlowed(m_charset))))
        {
          if (mDeleteFile)
          mFileSpec->Delete(PR_FALSE);

          nsOutputFileStream tempfile(*mFileSpec, PR_WRONLY | PR_CREATE_FILE, 00600);
          if (tempfile.is_open()) 
          {
            nsCAutoString tData;
            if (NS_FAILED(ConvertFromUnicode(m_charset, conData, tData)))
              LossyCopyUTF16toASCII(conData, tData);
            if (!tData.IsEmpty())
            {
              (void) tempfile.write(tData.get(), tData.Length());
            }
            tempfile.close();
          }
        }
      }

      PR_FREEIF(m_type);
      m_type = m_desired_type;
      m_desired_type = nsnull;
      PR_FREEIF(m_encoding);
      m_encoding = nsnull;
    }
  }

  PRUint32 pendingAttachmentCount = 0;
  m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
  NS_ASSERTION (pendingAttachmentCount > 0, "no more pending attachment");
  
  m_mime_delivery_state->SetPendingAttachmentCount(pendingAttachmentCount - 1);

  PRBool processAttachmentsSynchronously = PR_FALSE;
  m_mime_delivery_state->GetProcessAttachmentsSynchronously(&processAttachmentsSynchronously);
  if (NS_SUCCEEDED(status) && processAttachmentsSynchronously)
  {
    /* Find the next attachment which has not yet been loaded,
     if any, and start it going.
     */
    PRUint32 i;
    nsMsgAttachmentHandler *next = 0;
    nsMsgAttachmentHandler *attachments = nsnull;
    PRUint32 attachmentCount = 0;
    
    m_mime_delivery_state->GetAttachmentCount(&attachmentCount);
    if (attachmentCount)
      m_mime_delivery_state->GetAttachmentHandlers(&attachments);
      
    for (i = 0; i < attachmentCount; i++)
    {
      if (!attachments[i].m_done)
      {
        next = &attachments[i];
        //
        // rhp: We need to get a little more understanding to failed URL 
        // requests. So, at this point if most of next is NULL, then we
        // should just mark it fetched and move on! We probably ignored
        // this earlier on in the send process.
        //
        if ( (!next->mURL) && (!next->m_uri) )
        {
          attachments[i].m_done = PR_TRUE;
          m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
          m_mime_delivery_state->SetPendingAttachmentCount(pendingAttachmentCount - 1);
          next->mPartUserOmissionOverride = PR_TRUE;
          next = nsnull;
          continue;
        }

        break;
      }
    }

    if (next)
    {
      int status = next->SnarfAttachment(mCompFields);
      if (NS_FAILED(status))
      {
        nsresult ignoreMe;
        m_mime_delivery_state->Fail(status, nsnull, &ignoreMe);
        m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, 0, nsnull);
        SetMimeDeliveryState(nsnull);
        return NS_ERROR_UNEXPECTED;
      }
    }
  }

  m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
  if (pendingAttachmentCount == 0)
  {
    // If this is the last attachment, then either complete the
    // delivery (if successful) or report the error by calling
    // the exit routine and terminating the delivery.
    if (NS_FAILED(status))
    {
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
      m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, aMsg, nsnull);
      SetMimeDeliveryState(nsnull);
      return NS_ERROR_UNEXPECTED;
    }
    else
    {
      status = m_mime_delivery_state->GatherMimeAttachments ();
      if (NS_FAILED(status))
      {
        nsresult ignoreMe;
        m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
        m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, aMsg, nsnull);
        SetMimeDeliveryState(nsnull);
        return NS_ERROR_UNEXPECTED;
      }
    }
  }
  else
  {
    // If this is not the last attachment, but it got an error,
    // then report that error and continue 
    if (NS_FAILED(status))
    {
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
    }
  }

  SetMimeDeliveryState(nsnull);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1312 of file nsMsgAttachmentHandler.cpp.

{
  if (mCompFields)
    return mCompFields->GetUuEncodeAttachments();
  else
    return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 131 of file nsMsgAttachmentHandler.h.

Definition at line 107 of file nsMsgAttachmentHandler.h.

Definition at line 117 of file nsMsgAttachmentHandler.h.

Definition at line 118 of file nsMsgAttachmentHandler.h.

Definition at line 174 of file nsMsgAttachmentHandler.h.

Definition at line 157 of file nsMsgAttachmentHandler.h.

Definition at line 161 of file nsMsgAttachmentHandler.h.

Definition at line 134 of file nsMsgAttachmentHandler.h.

Definition at line 127 of file nsMsgAttachmentHandler.h.

Definition at line 126 of file nsMsgAttachmentHandler.h.

Definition at line 116 of file nsMsgAttachmentHandler.h.

Definition at line 166 of file nsMsgAttachmentHandler.h.

Definition at line 130 of file nsMsgAttachmentHandler.h.

Definition at line 164 of file nsMsgAttachmentHandler.h.

Definition at line 159 of file nsMsgAttachmentHandler.h.

Definition at line 159 of file nsMsgAttachmentHandler.h.

Definition at line 159 of file nsMsgAttachmentHandler.h.

Definition at line 156 of file nsMsgAttachmentHandler.h.

Definition at line 163 of file nsMsgAttachmentHandler.h.

Definition at line 162 of file nsMsgAttachmentHandler.h.

Definition at line 172 of file nsMsgAttachmentHandler.h.

Definition at line 173 of file nsMsgAttachmentHandler.h.

Definition at line 158 of file nsMsgAttachmentHandler.h.

Definition at line 124 of file nsMsgAttachmentHandler.h.

Definition at line 121 of file nsMsgAttachmentHandler.h.

Definition at line 160 of file nsMsgAttachmentHandler.h.

Definition at line 128 of file nsMsgAttachmentHandler.h.

Definition at line 154 of file nsMsgAttachmentHandler.h.

Definition at line 119 of file nsMsgAttachmentHandler.h.

Definition at line 120 of file nsMsgAttachmentHandler.h.

Definition at line 155 of file nsMsgAttachmentHandler.h.

Definition at line 167 of file nsMsgAttachmentHandler.h.

Definition at line 114 of file nsMsgAttachmentHandler.h.

Definition at line 113 of file nsMsgAttachmentHandler.h.

Definition at line 106 of file nsMsgAttachmentHandler.h.

Definition at line 144 of file nsMsgAttachmentHandler.h.

Definition at line 103 of file nsMsgAttachmentHandler.h.

Definition at line 149 of file nsMsgAttachmentHandler.h.

Definition at line 147 of file nsMsgAttachmentHandler.h.

Definition at line 104 of file nsMsgAttachmentHandler.h.

Definition at line 148 of file nsMsgAttachmentHandler.h.

Definition at line 105 of file nsMsgAttachmentHandler.h.

Definition at line 102 of file nsMsgAttachmentHandler.h.


The documentation for this class was generated from the following files: