Back to index

lightning-sunbird  0.9+nobinonly
nsMsgBodyHandler.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) 1999
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 "msgCore.h"
00039 #include "nsMsgSearchCore.h"
00040 #include "nsMsgUtils.h"
00041 #include "nsMsgBodyHandler.h"
00042 #include "nsMsgSearchTerm.h"
00043 #include "nsFileStream.h"
00044 #include "nsIFileStream.h"
00045 #include "nsIFileSpec.h"
00046 
00047 nsMsgBodyHandler::nsMsgBodyHandler (nsIMsgSearchScopeTerm * scope, PRUint32 offset, PRUint32 numLines, nsIMsgDBHdr* msg, nsIMsgDatabase * db)
00048 {
00049   m_scope = scope;
00050   m_localFileOffset = offset;
00051   m_numLocalLines = numLines;
00052   m_msgHdr = msg;
00053   m_db = db;
00054   
00055   // the following are variables used when the body handler is handling stuff from filters....through this constructor, that is not the
00056   // case so we set them to NULL.
00057   m_headers = NULL;
00058   m_headersSize = 0;
00059   m_Filtering = PR_FALSE; // make sure we set this before we call initialize...
00060   
00061   Initialize();  // common initialization stuff
00062   OpenLocalFolder();     
00063 }
00064 
00065 nsMsgBodyHandler::nsMsgBodyHandler(nsIMsgSearchScopeTerm * scope,
00066                                    PRUint32 offset, PRUint32 numLines,
00067                                    nsIMsgDBHdr* msg, nsIMsgDatabase* db,
00068                                    const char * headers, PRUint32 headersSize,
00069                                    PRBool Filtering)
00070 {
00071   m_scope = scope;
00072   m_localFileOffset = offset;
00073   m_numLocalLines = numLines;
00074   m_msgHdr = msg;
00075   m_db = db;
00076   m_headersSize = headersSize;
00077   m_Filtering = Filtering;
00078   
00079   Initialize();
00080   
00081   if (m_Filtering)
00082     m_headers = headers;
00083   else
00084     OpenLocalFolder();  // if nothing else applies, then we must be a POP folder file
00085 }
00086 
00087 void nsMsgBodyHandler::Initialize()
00088 // common initialization code regardless of what body type we are handling...
00089 {
00090   // Default transformations for local message search and MAPI access
00091   m_stripHeaders = PR_TRUE;
00092   m_stripHtml = PR_TRUE;
00093   m_messageIsHtml = PR_FALSE;
00094   m_passedHeaders = PR_FALSE;
00095   m_headerBytesRead = 0;
00096   
00097 }
00098 
00099 nsMsgBodyHandler::~nsMsgBodyHandler()
00100 {
00101 }
00102 
00103 PRInt32 nsMsgBodyHandler::GetNextLine (nsCString &buf)
00104 {
00105   PRInt32 length = 0;
00106   PRBool eatThisLine = PR_FALSE;
00107   
00108   do {
00109     // first, handle the filtering case...this is easy....
00110     if (m_Filtering)
00111       length = GetNextFilterLine(buf);
00112     else
00113     {
00114       // 3 cases: Offline IMAP, POP, or we are dealing with a news message....
00115       // Offline cases should be same as local mail cases, since we're going
00116       // to store offline messages in berkeley format folders.
00117       if (m_db)
00118       {
00119          length = GetNextLocalLine (buf); // (2) POP
00120       }
00121     }
00122     
00123     if (length >= 0)
00124       length = ApplyTransformations (buf, length, eatThisLine);
00125   } while (eatThisLine && length >= 0);  // if we hit eof, make sure we break out of this loop. Bug #:
00126   return length;  
00127 }
00128 
00129 void nsMsgBodyHandler::OpenLocalFolder()
00130 {
00131   nsCOMPtr <nsIInputStream> inputStream;
00132   nsresult rv = m_scope->GetInputStream(getter_AddRefs(inputStream));
00133   if (NS_SUCCEEDED(rv))
00134   {
00135     nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream);
00136     seekableStream->Seek(PR_SEEK_SET, m_localFileOffset);
00137   }
00138   m_fileLineStream = do_QueryInterface(inputStream);
00139 }
00140 
00141 PRInt32 nsMsgBodyHandler::GetNextFilterLine(nsCString &buf)
00142 {
00143   // m_nextHdr always points to the next header in the list....the list is NULL terminated...
00144   PRUint32 numBytesCopied = 0;
00145   if (m_headersSize > 0)
00146   {
00147     // #mscott. Ugly hack! filter headers list have CRs & LFs inside the NULL delimited list of header
00148     // strings. It is possible to have: To NULL CR LF From. We want to skip over these CR/LFs if they start
00149     // at the beginning of what we think is another header.
00150     
00151     while (m_headersSize > 0 && (m_headers[0] == nsCRT::CR || m_headers[0] == nsCRT::LF || m_headers[0] == ' ' || m_headers[0] == '\0'))
00152     {
00153       m_headers++;  // skip over these chars...
00154       m_headersSize--;
00155     }
00156     
00157     if (m_headersSize > 0)
00158     {
00159       numBytesCopied = strlen(m_headers) + 1 ;
00160       buf.Assign(m_headers);
00161       m_headers += numBytesCopied;  
00162       // be careful...m_headersSize is unsigned. Don't let it go negative or we overflow to 2^32....*yikes*     
00163       if (m_headersSize < numBytesCopied)
00164         m_headersSize = 0;
00165       else
00166         m_headersSize -= numBytesCopied;  // update # bytes we have read from the headers list
00167       
00168       return (PRInt32) numBytesCopied;
00169     }
00170   }
00171   else if (m_headersSize == 0) {
00172     buf.Truncate();
00173   }
00174   return -1;
00175 }
00176 
00177 // return -1 if no more local lines, length of next line otherwise.
00178 
00179 PRInt32 nsMsgBodyHandler::GetNextLocalLine(nsCString &buf)
00180 // returns number of bytes copied
00181 {
00182   if (m_numLocalLines)
00183   {
00184     if (m_passedHeaders)
00185       m_numLocalLines--; // the line count is only for body lines
00186     // do we need to check the return value here?
00187     if (m_fileLineStream)
00188     {
00189       PRBool more = PR_FALSE;
00190       nsresult rv = m_fileLineStream->ReadLine(buf, &more);
00191       if (NS_SUCCEEDED(rv))
00192         return buf.Length();
00193     }
00194   }
00195   
00196   return -1;
00197 }
00198 
00199 PRInt32 nsMsgBodyHandler::ApplyTransformations (nsCString &buf, PRInt32 length, PRBool &eatThisLine)
00200 {
00201   PRInt32 newLength = length;
00202   eatThisLine = PR_FALSE;
00203   
00204   if (!m_passedHeaders)     // buf is a line from the message headers
00205   {
00206     if (m_stripHeaders)
00207       eatThisLine = PR_TRUE;
00208     
00209     if (StringBeginsWith(buf, NS_LITERAL_CSTRING("Content-Type:")) && FindInReadable(buf, NS_LITERAL_CSTRING("text/html")))
00210       m_messageIsHtml = PR_TRUE;
00211     
00212     m_passedHeaders = buf.IsEmpty() || buf.First() == nsCRT::CR || buf.First() == nsCRT::LF;
00213   }
00214   else // buf is a line from the message body
00215   {
00216     if (m_stripHtml && m_messageIsHtml)
00217     {
00218       StripHtml (buf);
00219       newLength = buf.Length();
00220     }
00221   }
00222   
00223   return newLength;
00224 }
00225 
00226 void nsMsgBodyHandler::StripHtml (nsCString &pBufInOut)
00227 {
00228   char *pBuf = (char*) PR_Malloc (pBufInOut.Length() + 1);
00229   if (pBuf)
00230   {
00231     char *pWalk = pBuf;
00232     
00233     char *pWalkInOut = (char *) pBufInOut.get();
00234     PRBool inTag = PR_FALSE;
00235     while (*pWalkInOut) // throw away everything inside < >
00236     {
00237       if (!inTag)
00238         if (*pWalkInOut == '<')
00239           inTag = PR_TRUE;
00240         else
00241           *pWalk++ = *pWalkInOut;
00242         else
00243           if (*pWalkInOut == '>')
00244             inTag = PR_FALSE;
00245           pWalkInOut++;
00246     }
00247     *pWalk = 0; // null terminator
00248     
00249     pBufInOut.Adopt(pBuf);
00250   }
00251 }
00252