Esempio n. 1
0
    void ReadInputStreamData(nsTArray<nsCString>& aProtocolString)
    {
        nsLineBuffer<char> lineBuffer;
        nsCString line;
        bool more = true;
        do {
            NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);

            if (line.Length() > 0) {
                aProtocolString.AppendElement(line);
            }
        } while (more && line.Length() > 0);
    }
void nsMsgLocalStoreUtils::ChangeKeywordsHelper(
    nsIMsgDBHdr *message, uint64_t desiredOffset,
    nsLineBuffer<char> *lineBuffer, nsTArray<nsCString> &keywordArray,
    bool aAdd, nsIOutputStream *outputStream, nsISeekableStream *seekableStream,
    nsIInputStream *inputStream) {
  uint32_t bytesWritten;

  for (uint32_t i = 0; i < keywordArray.Length(); i++) {
    nsAutoCString header;
    nsAutoCString keywords;
    bool done = false;
    uint32_t len = 0;
    nsAutoCString keywordToWrite(" ");

    keywordToWrite.Append(keywordArray[i]);
    seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, desiredOffset);
    // need to reset lineBuffer, which is cheaper than creating a new one.
    lineBuffer->start = lineBuffer->end = lineBuffer->buf;
    bool inKeywordHeader = false;
    bool foundKeyword = false;
    int64_t offsetToAddKeyword = 0;
    bool more;
    message->GetMessageSize(&len);
    // loop through
    while (!done) {
      int64_t lineStartPos;
      seekableStream->Tell(&lineStartPos);
      // we need to adjust the linestart pos by how much extra the line
      // buffer has read from the stream.
      lineStartPos -= (lineBuffer->end - lineBuffer->start);
      // NS_ReadLine doesn't return line termination chars.
      nsCString keywordHeaders;
      nsresult rv = NS_ReadLine(inputStream, lineBuffer, keywordHeaders, &more);
      if (NS_SUCCEEDED(rv)) {
        if (keywordHeaders.IsEmpty())
          break;  // passed headers; no x-mozilla-keywords header; give up.
        if (StringBeginsWith(keywordHeaders,
                             NS_LITERAL_CSTRING(HEADER_X_MOZILLA_KEYWORDS)))
          inKeywordHeader = true;
        else if (inKeywordHeader && (keywordHeaders.CharAt(0) == ' ' ||
                                     keywordHeaders.CharAt(0) == '\t'))
          ;  // continuation header line
        else if (inKeywordHeader)
          break;
        else
          continue;
        uint32_t keywordHdrLength = keywordHeaders.Length();
        int32_t startOffset, keywordLength;
        // check if we have the keyword
        if (MsgFindKeyword(keywordArray[i], keywordHeaders, &startOffset,
                           &keywordLength)) {
          foundKeyword = true;
          if (!aAdd)  // if we're removing, remove it, and break;
          {
            keywordHeaders.Cut(startOffset, keywordLength);
            for (int32_t j = keywordLength; j > 0; j--)
              keywordHeaders.Append(' ');
            seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, lineStartPos);
            outputStream->Write(keywordHeaders.get(), keywordHeaders.Length(),
                                &bytesWritten);
          }
          offsetToAddKeyword = 0;
          // if adding and we already have the keyword, done
          done = true;
          break;
        }
        // argh, we need to check all the lines to see if we already have the
        // keyword, but if we don't find it, we want to remember the line and
        // position where we have room to add the keyword.
        if (aAdd) {
          nsAutoCString curKeywordHdr(keywordHeaders);
          // strip off line ending spaces.
          curKeywordHdr.Trim(" ", false, true);
          if (!offsetToAddKeyword &&
              curKeywordHdr.Length() + keywordToWrite.Length() <
                  keywordHdrLength)
            offsetToAddKeyword = lineStartPos + curKeywordHdr.Length();
        }
      }
    }
    if (aAdd && !foundKeyword) {
      if (!offsetToAddKeyword)
        message->SetUint32Property("growKeywords", 1);
      else {
        seekableStream->Seek(nsISeekableStream::NS_SEEK_SET,
                             offsetToAddKeyword);
        outputStream->Write(keywordToWrite.get(), keywordToWrite.Length(),
                            &bytesWritten);
      }
    }
  }
}
Esempio n. 3
0
int 
nsMsgSendPart::Write()
{
  int     status = 0;
  char    *separator = nsnull;
  bool    needToWriteCRLFAfterEncodedBody  = false;

#define PUSHLEN(str, length)                  \
  do {                            \
    status = mime_write_message_body(m_state, str, length); \
    if (status < 0) goto FAIL;                \
  } while (0)                         \

#define PUSH(str) PUSHLEN(str, PL_strlen(str))

  // rhp: Suppress the output of parts that are empty!
  if ( (m_parent) &&
       (m_numchildren == 0) &&
       ( (!m_buffer) || (!*m_buffer) ) &&
       (!m_file) &&
       (!m_mainpart) )
    return SKIP_EMPTY_PART;

  if (m_mainpart && m_type && PL_strcmp(m_type, TEXT_HTML) == 0) 
  {     
    if (m_file) 
    {
      // The "insert HTML links" code requires a memory buffer,
      // so read the file into memory.
      NS_ASSERTION(m_buffer == nsnull, "not-null buffer");
      PRInt32           length = 0;
      PRInt64 fileSize;
      if (NS_SUCCEEDED(m_file->GetFileSize(&fileSize)))
          length = fileSize;
      
      m_buffer = (char *) PR_Malloc(sizeof(char) * (length + 1));
      if (m_buffer) 
      {
        nsCOMPtr<nsIInputStream> inputFile;
        nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputFile), m_file);
        if (NS_SUCCEEDED(rv)) 
        {
          PRUint32 bytesRead;
          rv = inputFile->Read(m_buffer, length, &bytesRead);
          inputFile->Close();
          m_buffer[length] = '\0';
        }
        else 
          PR_Free(m_buffer);
      }
    }
  }
  
  if (m_parent && m_parent->m_type &&
        !PL_strcasecmp(m_parent->m_type, MULTIPART_DIGEST) &&
        m_type &&
        (!PL_strcasecmp(m_type, MESSAGE_RFC822) ||
        !PL_strcasecmp(m_type, MESSAGE_NEWS))) 
  {
    // If we're in a multipart/digest, and this document is of type
    // message/rfc822, then it's appropriate to emit no headers.
    //
  }
  else 
  {
    char *message_headers = 0;
    char *content_headers = 0;
    char *content_type_header = 0;
    status = divide_content_headers(m_other,
                                    &message_headers,
                                    &content_headers,
                                    &content_type_header);
    if (status < 0)
      goto FAIL;
    
      /* First, write out all of the headers that refer to the message
      itself (From, Subject, MIME-Version, etc.)
    */
    if (message_headers) 
    {
      PUSH(message_headers);
      PR_Free(message_headers);
      message_headers = 0;
    }

    /* Now allow the crypto library to (potentially) insert some text
       (it may want to wrap the body in an envelope.)           */
    if (!m_parent) {
      status = m_state->BeginCryptoEncapsulation();
      if (status < 0) goto FAIL;
    }
          
    /* Now make sure there's a Content-Type header.
    */
    if (!content_type_header) 
    {
      NS_ASSERTION(m_type && *m_type, "null ptr");
      bool needsCharset = mime_type_needs_charset(m_type ? m_type : TEXT_PLAIN);
      if (needsCharset) 
      {
        content_type_header = PR_smprintf("Content-Type: %s; charset=%s" CRLF,
                                          (m_type ? m_type : TEXT_PLAIN), m_charset_name);
      }
      else
        content_type_header = PR_smprintf("Content-Type: %s" CRLF,
                                          (m_type ? m_type : TEXT_PLAIN));
      if (!content_type_header) 
      {
        if (content_headers)
          PR_Free(content_headers);
        status = NS_ERROR_OUT_OF_MEMORY;
        goto FAIL;
      }
    }
    
    /* If this is a compound object, tack a boundary string onto the
    Content-Type header. this
    */
    if (m_numchildren > 0)
    {
      int L;
      char *ct2;
      NS_ASSERTION(m_type, "null ptr");

      if (!separator)
      {
        separator = mime_make_separator("");
        if (!separator)
        {
          status = NS_ERROR_OUT_OF_MEMORY;
          goto FAIL;
        }
      }

      L = PL_strlen(content_type_header);
      
      if (content_type_header[L-1] == '\n')
        content_type_header[--L] = 0;
      if (content_type_header[L-1] == '\r')
        content_type_header[--L] = 0;
      
      ct2 = PR_smprintf("%s;\r\n boundary=\"%s\"" CRLF, content_type_header, separator);
      PR_Free(content_type_header);
      if (!ct2) 
      {
        if (content_headers)
          PR_Free(content_headers);
        status = NS_ERROR_OUT_OF_MEMORY;
        goto FAIL;
      }
      
      content_type_header = ct2;
    }
    
    // Now write out the Content-Type header...
    NS_ASSERTION(content_type_header && *content_type_header, "null ptr");
    PUSH(content_type_header);
    PR_Free(content_type_header);
    content_type_header = 0;
    
    /* ...followed by all of the other headers that refer to the body of
    the message (Content-Transfer-Encoding, Content-Dispositon, etc.)
    */
    if (content_headers) 
    {
      PUSH(content_headers);
      PR_Free(content_headers);
      content_headers = 0;
    }
  }

  PUSH(CRLF);         // A blank line, to mark the end of headers.

  m_firstBlock = true;
  /* only convert if we need to tag charset */
  m_needIntlConversion = mime_type_needs_charset(m_type);
  
  if (m_buffer) 
  {
    status = PushBody(m_buffer, PL_strlen(m_buffer));
    if (status < 0)
      goto FAIL;
  }
  else if (m_file) 
  {
    nsCOMPtr<nsIInputStream> inputStream;
    nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), m_file);
    if (NS_FAILED(rv))
    {
      // mysteriously disappearing?
      nsCOMPtr<nsIMsgSendReport> sendReport;
      m_state->GetSendReport(getter_AddRefs(sendReport));
      if (sendReport)
      {
        nsAutoString error_msg;
        nsMsgBuildMessageWithTmpFile(m_file, error_msg);
        sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
      }
      status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
      goto FAIL;
    }

    nsCString curLine;
    bool more = true;

    /* Kludge to avoid having to allocate memory on the toy computers... */
    if (!mime_mailto_stream_read_buffer) 
    {
      mime_mailto_stream_read_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
      if (!mime_mailto_stream_read_buffer) 
      {
        status = NS_ERROR_OUT_OF_MEMORY;
        goto FAIL;
      }
    }

    char    *buffer = mime_mailto_stream_read_buffer;
    if (m_strip_sensitive_headers) 
    {
      // We are attaching a message, so we should be careful to
      // strip out certain sensitive internal header fields.
      bool skipping = false;
      nsLineBuffer<char> *lineBuffer;
      
      rv = NS_InitLineBuffer(&lineBuffer);
      NS_ENSURE_SUCCESS(rv, rv);

      while (more) 
      {
        // NS_ReadLine doesn't return line termination chars.
        rv = NS_ReadLine(inputStream.get(), lineBuffer, curLine, &more);
      
        curLine.Append(CRLF);
        
        char *line = (char *) curLine.get();
        if (skipping) {
          if (*line == ' ' || *line == '\t')
            continue;
          else
            skipping = false;
        }
                
        if (!PL_strncasecmp(line, "From -", 6) ||
            !PL_strncasecmp(line, "BCC:", 4) ||
            !PL_strncasecmp(line, "FCC:", 4) ||
            !PL_strncasecmp(line, CONTENT_LENGTH ":", CONTENT_LENGTH_LEN+1) ||
            !PL_strncasecmp(line, "Lines:", 6) ||
            !PL_strncasecmp(line, "Status:", 7) ||
            !PL_strncasecmp(line, X_MOZILLA_STATUS ":", X_MOZILLA_STATUS_LEN+1) ||
            !PL_strncasecmp(line, X_MOZILLA_STATUS2 ":", X_MOZILLA_STATUS2_LEN+1) ||
            !PL_strncasecmp(line, X_MOZILLA_DRAFT_INFO ":", X_MOZILLA_DRAFT_INFO_LEN+1) ||
            !PL_strncasecmp(line, X_MOZILLA_NEWSHOST ":", X_MOZILLA_NEWSHOST_LEN+1) ||
            !PL_strncasecmp(line, X_UIDL ":", X_UIDL_LEN+1) ||
            !PL_strncasecmp(line, "X-VM-", 5)) /* hi Kyle */
        {
          skipping = true;
          continue;
        }
        
        PUSH(line);
        
        if (curLine.Length() == 2) {
          nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream);
          // seek back the amount of data left in the line buffer...
          seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, lineBuffer->start - lineBuffer->end);
          break;  // Now can do normal reads for the body.
        }
      }
      PR_Free(lineBuffer);
    }

    while (status >= 0) 
    {
      PRUint32 bytesRead;
      nsresult rv = inputStream->Read(buffer, MIME_BUFFER_SIZE, &bytesRead);
      if (NS_FAILED(rv))
      {  
        nsCOMPtr<nsIMsgSendReport> sendReport;
        m_state->GetSendReport(getter_AddRefs(sendReport));
        if (sendReport)
        {
          nsAutoString error_msg;
          nsMsgBuildMessageWithFile(m_file, error_msg);
          sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
          status = NS_MSG_UNABLE_TO_OPEN_FILE;
          goto FAIL;
        }
      }
      status = PushBody(buffer, bytesRead);
      if (status < 0)
        goto FAIL;
      if (bytesRead < MIME_BUFFER_SIZE)
        break;
    }
  }
  
  if (m_encoder_data) 
  {
    status = MIME_EncoderDestroy(m_encoder_data, false);
    m_encoder_data = nsnull;
    needToWriteCRLFAfterEncodedBody = !m_parent;
    if (status < 0)
      goto FAIL;
  }
  
  // 
  // Ok, from here we loop and drive the the output of all children 
  // for this message.
  //
  if (m_numchildren > 0) 
  {
    bool    writeSeparator = true;

    for (int i = 0 ; i < m_numchildren ; i ++) 
    {
      if (writeSeparator)
      {
        PUSH(CRLF);
        PUSH("--");

        PUSH(separator);
        PUSH(CRLF);
      }

      status = m_children[i]->Write();
      if (status < 0)
        goto FAIL;

      if (status == SKIP_EMPTY_PART)
        writeSeparator = false;
      else
        writeSeparator = true;
    }

    PUSH(CRLF);
    PUSH("--");
    PUSH(separator);
    PUSH("--");
    PUSH(CRLF);
  }
  else if (needToWriteCRLFAfterEncodedBody)
    PUSH(CRLF);
  
FAIL:
  PR_FREEIF(separator);
  return status;
}
static nsresult __AddNewMessageToFolder(nsIMsgFolder * dstFolder,
                                        ews_msg_item * msg_item,
                                        nsIMsgDBHdr* messageToReplace,
                                        nsIFile * pSrc,
                                        nsIMsgDBHdr ** _msgHdr) {
    nsCOMPtr<nsIOutputStream> outputStream;
    nsCOMPtr<nsIMsgPluggableStore> msgStore;
    nsresult rv;
    
    nsCOMPtr<nsIMsgDatabase> destDB;
    rv = dstFolder->GetMsgDatabase(getter_AddRefs(destDB));
    
    rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
    NS_ENSURE_SUCCESS(rv, rv);
    
    nsCOMPtr<nsIMsgDBHdr> msgHdr;
    bool reusable;

    rv = msgStore->GetNewMsgOutputStream(dstFolder,
                                         getter_AddRefs(msgHdr),
                                         &reusable,
                                         getter_AddRefs(outputStream));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr <nsIInputStream> pInputStream;
    rv = NS_NewLocalFileInputStream(getter_AddRefs(pInputStream), pSrc);
    NS_ENSURE_SUCCESS(rv, rv);

    nsAutoPtr<nsLineBuffer<char> > lineBuffer(new nsLineBuffer<char>);
    NS_ENSURE_TRUE(lineBuffer, NS_ERROR_OUT_OF_MEMORY);

    nsCOMPtr <nsIMsgParseMailMsgState> msgParser = do_CreateInstance(NS_PARSEMAILMSGSTATE_CONTRACTID, &rv);
    msgParser->SetMailDB(destDB);
    msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
    msgParser->SetNewMsgHdr(msgHdr);
    
    nsCString line;
    bool more = false;
    uint32_t write_count = 0;
    uint32_t msg_size = 0;

    //Need to write Local message header
    //From
    nsAutoCString result;
    time_t now = time ((time_t*) 0);
    char *ct = ctime(&now);
    ct[24] = 0;
    result = "From - ";
    result += ct;
    result += MSG_LINEBREAK;

    outputStream->Write(result.get(),
                        result.Length(),
                        &write_count);
    msg_size += write_count;
    
    //Status
    NS_NAMED_LITERAL_CSTRING(MozillaStatus,
                             "X-Mozilla-Status: 0001" MSG_LINEBREAK);
    outputStream->Write(MozillaStatus.get(),
                        MozillaStatus.Length(),
                        &write_count);
    msg_size += write_count;

    //Status2
    NS_NAMED_LITERAL_CSTRING(MozillaStatus2,
                             "X-Mozilla-Status2: 00000000" MSG_LINEBREAK);
    outputStream->Write(MozillaStatus2.get(),
                        MozillaStatus2.Length(),
                        &write_count);
    msg_size += write_count;

    do {
        rv = NS_ReadLine(pInputStream.get(),
                         lineBuffer.get(),
                         line,
                         &more);
        if (NS_FAILED(rv))
            break;

        nsCString newLine(line);
        newLine.AppendLiteral("\x0D\x0A");
        msgParser->ParseAFolderLine(newLine.get(), newLine.Length());

        //Need to replace Date: Header with received time
        if (!strncmp(line.get(), "Date:", strlen("Date:")) &&
            msg_item &&
            msg_item->item.received_time > 0) {
            char buf[256] = {0};
            size_t len = strftime(buf, 255, "%a, %d %b %Y %H:%M:%S %z", localtime(&msg_item->item.received_time));

            outputStream->Write("Date: ", strlen("Date: "), &write_count);
            msg_size += write_count;
            outputStream->Write(buf, len, &write_count);
            msg_size += write_count;
            outputStream->Write("\x0D\x0A", 2, &write_count);
            msg_size += write_count;
        } else if (!strncmp(line.get(), "Subject:", strlen("Subject:"))) {
            const char * key = line.get() + strlen("Subject:");
            uint32_t l = strlen(key);
            
            nsCString newSubject("Subject: ");

            /* strip "Re: " */
            nsCString modifiedSubject;
            if (mailews::NS_MsgStripRE((const char **) &key,
                              &l,
                              modifiedSubject)) {
                nsString utf16LocalizedRe;
                mailews::NS_GetLocalizedUnicharPreferenceWithDefault(nullptr,
                                                            "mailnews.localizedRe",
                                                            EmptyString(),
                                                            utf16LocalizedRe);
                NS_ConvertUTF16toUTF8 localizedRe(utf16LocalizedRe);

                if (localizedRe.IsEmpty()) {
                    newSubject.Append("Re");
                } else {
                    newSubject.Append(localizedRe);
                }
                newSubject.Append(": ");
            }

            if (!modifiedSubject.IsEmpty()) {
                newSubject.Append(modifiedSubject);
            } else {
                newSubject.AppendLiteral(key);
            }
            outputStream->Write(newSubject.get(), newSubject.Length(), &write_count);
            msg_size += write_count;
            outputStream->Write("\x0D\x0A", 2, &write_count);
            msg_size += write_count;
        } else {
            outputStream->Write(line.get(), line.Length(), &write_count);
            msg_size += write_count;
            outputStream->Write("\x0D\x0A", 2, &write_count);
            msg_size += write_count;
        }
    } while(more);

    pInputStream->Close();

    msgParser->FinishHeader();

    msgParser->GetNewMsgHdr(getter_AddRefs(msgHdr));
    
    if (NS_SUCCEEDED(rv)) {
        if (msg_item)
            UpdateMsgHdr(msg_item, msgHdr);
        else if (messageToReplace) {
            CopyPropertiesToMsgHdr(msgHdr, messageToReplace, true);
        }

        msgHdr->SetMessageSize(msg_size);
        
        destDB->AddNewHdrToDB(msgHdr, true /* notify */);
        msgStore->FinishNewMessage(outputStream, msgHdr);
        dstFolder->UpdateSummaryTotals(true);
    }
    else {
        msgStore->DiscardNewMessage(outputStream, msgHdr);
        IMPORT_LOG0( "*** Error importing message\n");
    }

    if (!reusable)
        outputStream->Close();

    destDB->Commit(nsMsgDBCommitType::kLargeCommit);

    if (_msgHdr)
        msgHdr.swap(*_msgHdr);
    return rv;
}