Back to index

lightning-sunbird  0.9+nobinonly
nsMailboxUrl.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  *   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 "msgCore.h"    // precompiled header...
00040 
00041 #include "nsIURI.h"
00042 #include "nsIMailboxUrl.h"
00043 #include "nsMailboxUrl.h"
00044 
00045 #include "nsString.h"
00046 #include "nsReadableUtils.h"
00047 #include "nsEscape.h"
00048 #include "nsCRT.h"
00049 #include "nsLocalUtils.h"
00050 #include "nsIMsgDatabase.h"
00051 #include "nsMsgDBCID.h"
00052 #include "nsMsgBaseCID.h"
00053 #include "nsIMsgHdr.h"
00054 
00055 #include "nsXPIDLString.h"
00056 #include "nsIRDFService.h"
00057 #include "rdf.h"
00058 #include "nsIMsgFolder.h"
00059 #include "prprf.h"
00060 #include "nsISupportsObsolete.h"
00061 #include "nsIMsgMailSession.h"
00062 
00063 // we need this because of an egcs 1.0 (and possibly gcc) compiler bug
00064 // that doesn't allow you to call ::nsISupports::GetIID() inside of a class
00065 // that multiply inherits from nsISupports
00066 static NS_DEFINE_CID(kCMailDB, NS_MAILDB_CID);
00067 
00068 // this is totally lame and MUST be removed by M6
00069 // the real fix is to attach the URI to the URL as it runs through netlib
00070 // then grab it and use it on the other side
00071 #include "nsCOMPtr.h"
00072 #include "nsMsgBaseCID.h"
00073 #include "nsIMsgAccountManager.h"
00074 #include "nsMsgUtils.h"
00075 
00076 
00077 // helper function for parsing the search field of a url
00078 char * extractAttributeValue(const char * searchString, const char * attributeName);
00079 
00080 nsMailboxUrl::nsMailboxUrl()
00081 {
00082   m_mailboxAction = nsIMailboxUrl::ActionParseMailbox;
00083   m_filePath = nsnull;
00084   m_messageID = nsnull;
00085   m_messageKey = nsMsgKey_None;
00086   m_messageSize = 0;
00087   m_messageFileSpec = nsnull;
00088   m_addDummyEnvelope = PR_FALSE;
00089   m_canonicalLineEnding = PR_FALSE;
00090   m_curMsgIndex = 0;
00091 }
00092  
00093 nsMailboxUrl::~nsMailboxUrl()
00094 {
00095     delete m_filePath;
00096     PR_Free(m_messageID);
00097 }
00098 
00099 NS_IMPL_ADDREF_INHERITED(nsMailboxUrl, nsMsgMailNewsUrl)
00100 NS_IMPL_RELEASE_INHERITED(nsMailboxUrl, nsMsgMailNewsUrl)
00101 
00102 NS_INTERFACE_MAP_BEGIN(nsMailboxUrl)
00103    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMailboxUrl)
00104    NS_INTERFACE_MAP_ENTRY(nsIMailboxUrl)
00105    NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
00106    NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
00107 NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
00108 
00110 // Begin nsIMailboxUrl specific support
00112 nsresult nsMailboxUrl::SetMailboxParser(nsIStreamListener * aMailboxParser)
00113 {
00114   if (aMailboxParser)
00115     m_mailboxParser = aMailboxParser;
00116   return NS_OK;
00117 }
00118 
00119 nsresult nsMailboxUrl::GetMailboxParser(nsIStreamListener ** aConsumer)
00120 {
00121   NS_ENSURE_ARG_POINTER(aConsumer);
00122   
00123   NS_IF_ADDREF(*aConsumer = m_mailboxParser);
00124   return  NS_OK;
00125 }
00126 
00127 nsresult nsMailboxUrl::SetMailboxCopyHandler(nsIStreamListener * aMailboxCopyHandler)
00128 {
00129   if (aMailboxCopyHandler)
00130     m_mailboxCopyHandler = aMailboxCopyHandler;
00131   return NS_OK;
00132 }
00133 
00134 nsresult nsMailboxUrl::GetMailboxCopyHandler(nsIStreamListener ** aMailboxCopyHandler)
00135 {
00136   NS_ENSURE_ARG_POINTER(aMailboxCopyHandler);
00137   
00138   if (aMailboxCopyHandler)
00139   {
00140     *aMailboxCopyHandler = m_mailboxCopyHandler;
00141     NS_IF_ADDREF(*aMailboxCopyHandler);
00142   }
00143   
00144   return  NS_OK;
00145 }
00146 
00147 nsresult nsMailboxUrl::GetFileSpec(nsFileSpec ** aFilePath)
00148 {
00149   if (aFilePath)
00150     *aFilePath = m_filePath;
00151   return NS_OK;
00152 }
00153 
00154 nsresult nsMailboxUrl::GetMessageKey(nsMsgKey* aMessageKey)
00155 {
00156   *aMessageKey = m_messageKey;
00157   return NS_OK;
00158 }
00159 
00160 NS_IMETHODIMP nsMailboxUrl::GetMessageSize(PRUint32 * aMessageSize)
00161 {
00162   if (aMessageSize)
00163   {
00164     *aMessageSize = m_messageSize;
00165     return NS_OK;
00166   }
00167   else
00168     return NS_ERROR_NULL_POINTER;
00169 }
00170 
00171 nsresult nsMailboxUrl::SetMessageSize(PRUint32 aMessageSize)
00172 {
00173   m_messageSize = aMessageSize;
00174   return NS_OK;
00175 }
00176 
00177 NS_IMETHODIMP nsMailboxUrl::SetUri(const char * aURI)
00178 {
00179   mURI= aURI;
00180   return NS_OK;
00181 }
00182 
00183 NS_IMETHODIMP nsMailboxUrl::GetUri(char ** aURI)
00184 {
00185   // if we have been given a uri to associate with this url, then use it
00186   // otherwise try to reconstruct a URI on the fly....
00187   
00188   if (!mURI.IsEmpty())
00189     *aURI = ToNewCString(mURI);
00190   else
00191   {
00192     nsFileSpec * filePath = nsnull;
00193     GetFileSpec(&filePath);
00194     if (filePath)
00195     {
00196       nsCAutoString baseUri;
00197       // we blow off errors here so that we can open attachments
00198       // in .eml files.
00199       (void) MsgMailboxGetURI(m_file, baseUri);
00200       char * baseMessageURI;
00201       nsCreateLocalBaseMessageURI(baseUri.get(), &baseMessageURI);
00202       char * uri = nsnull;
00203       nsCAutoString uriStr;
00204       nsFileSpec folder = *filePath;
00205       nsBuildLocalMessageURI(baseMessageURI, m_messageKey, uriStr);
00206       nsCRT::free(baseMessageURI);
00207       uri = ToNewCString(uriStr);
00208       *aURI = uri;
00209     }
00210     else
00211       *aURI = nsnull;
00212   }
00213   
00214   return NS_OK;
00215 }
00216 
00217 nsresult nsMailboxUrl::GetMsgHdrForKey(nsMsgKey  msgKey, nsIMsgDBHdr ** aMsgHdr)
00218 {
00219   nsresult rv = NS_OK;
00220   if (aMsgHdr && m_filePath)
00221   {
00222     nsCOMPtr<nsIMsgDatabase> mailDBFactory;
00223     nsCOMPtr<nsIMsgDatabase> mailDB;
00224     
00225     nsCOMPtr<nsIMsgDBService> msgDBService = do_GetService(NS_MSGDB_SERVICE_CONTRACTID, &rv);
00226     nsCOMPtr <nsIFileSpec> dbFileSpec;
00227     NS_NewFileSpecWithSpec(*m_filePath, getter_AddRefs(dbFileSpec));
00228     
00229     if (msgDBService)
00230       rv = msgDBService->OpenMailDBFromFileSpec(dbFileSpec, PR_FALSE, PR_FALSE, (nsIMsgDatabase **) getter_AddRefs(mailDB));
00231     if (NS_SUCCEEDED(rv) && mailDB) // did we get a db back?
00232       rv = mailDB->GetMsgHdrForKey(msgKey, aMsgHdr);
00233     else
00234     {
00235       if (!m_msgWindow)
00236       {
00237         nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
00238         NS_ENSURE_SUCCESS(rv, rv);
00239         mailSession->GetTopmostMsgWindow(getter_AddRefs(m_msgWindow));
00240       }
00241       // maybe this is .eml file we're trying to read. See if we can get a header from the header sink.
00242       if (m_msgWindow)
00243       {
00244         nsCOMPtr <nsIMsgHeaderSink> headerSink;
00245         m_msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
00246         if (headerSink)
00247           return headerSink->GetDummyMsgHeader(aMsgHdr);
00248       }
00249     }
00250   }
00251   else
00252     rv = NS_ERROR_NULL_POINTER;
00253   
00254   return rv;
00255 }
00256 
00257 NS_IMETHODIMP nsMailboxUrl::GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)
00258 {
00259   return GetMsgHdrForKey(m_messageKey, aMsgHdr);
00260 }
00261 
00262 NS_IMPL_GETSET(nsMailboxUrl, AddDummyEnvelope, PRBool, m_addDummyEnvelope)
00263 NS_IMPL_GETSET(nsMailboxUrl, CanonicalLineEnding, PRBool, m_canonicalLineEnding)
00264 
00265 NS_IMETHODIMP
00266 nsMailboxUrl::GetOriginalSpec(char **aSpec)
00267 {
00268     if (!aSpec || !m_originalSpec) return NS_ERROR_NULL_POINTER;
00269     *aSpec = nsCRT::strdup(m_originalSpec);
00270     return NS_OK;
00271 }
00272 
00273 NS_IMETHODIMP
00274 nsMailboxUrl::SetOriginalSpec(const char *aSpec)
00275 {
00276     m_originalSpec.Adopt(aSpec ? nsCRT::strdup(aSpec) : 0);
00277     return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP nsMailboxUrl::SetMessageFile(nsIFileSpec * aFileSpec)
00281 {
00282   m_messageFileSpec = aFileSpec;
00283   return NS_OK;
00284 }
00285 
00286 NS_IMETHODIMP nsMailboxUrl::GetMessageFile(nsIFileSpec ** aFileSpec)
00287 {
00288   if (aFileSpec)
00289   {
00290     *aFileSpec = m_messageFileSpec;
00291     NS_IF_ADDREF(*aFileSpec);
00292   }
00293   return NS_OK;
00294 }
00295 
00296 NS_IMETHODIMP nsMailboxUrl::IsUrlType(PRUint32 type, PRBool *isType)
00297 {
00298   NS_ENSURE_ARG(isType);
00299   
00300   switch(type)
00301   {
00302     case nsIMsgMailNewsUrl::eCopy:
00303       *isType = (m_mailboxAction == nsIMailboxUrl::ActionCopyMessage);
00304       break;
00305     case nsIMsgMailNewsUrl::eMove:
00306       *isType = (m_mailboxAction == nsIMailboxUrl::ActionMoveMessage);
00307       break;
00308     case nsIMsgMailNewsUrl::eDisplay:
00309       *isType = (m_mailboxAction == nsIMailboxUrl::ActionFetchMessage);
00310       break;
00311     default:
00312       *isType = PR_FALSE;
00313   };                        
00314   
00315   return NS_OK;
00316   
00317 }
00318 
00320 // End nsIMailboxUrl specific support
00322 
00324 // possible search part phrases include: MessageID=id&number=MessageKey
00325 
00326 nsresult nsMailboxUrl::ParseSearchPart()
00327 {
00328   nsCAutoString searchPart;
00329   nsresult rv = GetQuery(searchPart);
00330   // add code to this function to decompose everything past the '?'.....
00331   if (NS_SUCCEEDED(rv) && !searchPart.IsEmpty())
00332   {
00333     // the action for this mailbox must be a display message...
00334     char * msgPart = extractAttributeValue(searchPart.get(), "part=");
00335     if (msgPart)  // if we have a part in the url then we must be fetching just the part.
00336       m_mailboxAction = nsIMailboxUrl::ActionFetchPart;
00337     else
00338       m_mailboxAction = nsIMailboxUrl::ActionFetchMessage;
00339     
00340     char * messageKey = extractAttributeValue(searchPart.get(), "number=");
00341     m_messageID = extractAttributeValue(searchPart.get(),"messageid=");
00342     if (messageKey)
00343       m_messageKey = atol(messageKey); // convert to a long...
00344     
00345     PR_Free(msgPart);
00346     PR_Free(messageKey);
00347   }
00348   else
00349     m_mailboxAction = nsIMailboxUrl::ActionParseMailbox;
00350   
00351   return rv;
00352 }
00353 
00354 // warning: don't assume when parsing the url that the protocol part is "news"...
00355 nsresult nsMailboxUrl::ParseUrl()
00356 {
00357   delete m_filePath;
00358   GetFilePath(m_file);
00359   ParseSearchPart();
00360   // ### fix me.
00361   // this hack is to avoid asserting on every local message loaded because the security manager
00362   // is creating an empty "mailbox://" uri for every message.
00363   if (strlen(m_file) < 2)
00364     m_filePath = nsnull;
00365   else
00366     m_filePath = new nsFileSpec(nsFilePath(nsUnescape((char *) (const char *)m_file)));
00367   return NS_OK;
00368 }
00369 
00370 NS_IMETHODIMP nsMailboxUrl::SetSpec(const nsACString &aSpec)
00371 {
00372   nsresult rv = nsMsgMailNewsUrl::SetSpec(aSpec);
00373   if (NS_SUCCEEDED(rv))
00374     rv = ParseUrl();
00375   return rv;
00376 }
00377 
00378 NS_IMETHODIMP nsMailboxUrl::SetQuery(const nsACString &aQuery)
00379 {
00380   nsresult rv = nsMsgMailNewsUrl::SetQuery(aQuery);
00381   if (NS_SUCCEEDED(rv))
00382     rv = ParseUrl();
00383   return rv;
00384 }
00385 
00386 // takes a string like ?messageID=fooo&number=MsgKey and returns a new string 
00387 // containing just the attribute value. i.e you could pass in this string with
00388 // an attribute name of messageID and I'll return fooo. Use PR_Free to delete
00389 // this string...
00390 
00391 // Assumption: attribute pairs in the string are separated by '&'.
00392 char * extractAttributeValue(const char * searchString, const char * attributeName)
00393 {
00394   char * attributeValue = nsnull;
00395   
00396   if (searchString && attributeName)
00397   {
00398     // search the string for attributeName
00399     PRUint32 attributeNameSize = PL_strlen(attributeName);
00400     char * startOfAttribute = PL_strcasestr(searchString, attributeName);
00401     if (startOfAttribute)
00402     {
00403       startOfAttribute += attributeNameSize; // skip over the attributeName
00404       if (startOfAttribute) // is there something after the attribute name
00405       {
00406         char * endofAttribute = startOfAttribute ? PL_strchr(startOfAttribute, '&') : nsnull;
00407         if (startOfAttribute && endofAttribute) // is there text after attribute value
00408           attributeValue = PL_strndup(startOfAttribute, endofAttribute - startOfAttribute);
00409         else // there is nothing left so eat up rest of line.
00410           attributeValue = PL_strdup(startOfAttribute);
00411         
00412         // now unescape the string...
00413         if (attributeValue)
00414           attributeValue = nsUnescape(attributeValue); // unescape the string...
00415       } // if we have a attribute value
00416       
00417     } // if we have a attribute name
00418   } // if we got non-null search string and attribute name values
00419   
00420   return attributeValue;
00421 }
00422 
00423 // nsIMsgI18NUrl support
00424 
00425 nsresult nsMailboxUrl::GetFolder(nsIMsgFolder **msgFolder)
00426 {
00427   // if we have a RDF URI, then try to get the folder for that URI and then ask the folder
00428   // for it's charset....
00429 
00430   nsXPIDLCString uri;
00431   GetUri(getter_Copies(uri));
00432   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
00433   nsCOMPtr<nsIMsgDBHdr> msg; 
00434   GetMsgDBHdrFromURI(uri, getter_AddRefs(msg));
00435   NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
00436   nsresult rv = msg->GetFolder(msgFolder);
00437   NS_ENSURE_SUCCESS(rv,rv);
00438   NS_ENSURE_TRUE(msgFolder, NS_ERROR_FAILURE);
00439 
00440   return NS_OK;
00441 }
00442 
00443 NS_IMETHODIMP nsMailboxUrl::GetFolderCharset(char ** aCharacterSet)
00444 {
00445   nsCOMPtr<nsIMsgFolder> folder;
00446   nsresult rv = GetFolder(getter_AddRefs(folder));
00447 #if 0
00448   if (NS_FAILED(rv))
00449   {
00450     nsCOMPtr<nsIPrefLocalizedString> pls;
00451     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
00452     NS_ENSURE_SUCCESS(rv,rv);
00453     rv = prefBranch->GetComplexValue("mailnews.view_default_charset",
00454       NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls));
00455     if (NS_SUCCEEDED(rv)) 
00456     {
00457       nsXPIDLString ucsval;
00458       pls->ToString(getter_Copies(ucsval));
00459       if (ucsval)
00460         *aCharacterSet = ToNewCString(ucsval);
00461       return rv;
00462     }
00463   }
00464 #endif
00465   NS_ENSURE_SUCCESS(rv,rv);
00466   NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
00467   folder->GetCharset(aCharacterSet);
00468   return NS_OK;
00469 }
00470 
00471 NS_IMETHODIMP nsMailboxUrl::GetFolderCharsetOverride(PRBool * aCharacterSetOverride)
00472 {
00473   nsCOMPtr<nsIMsgFolder> folder;
00474   nsresult rv = GetFolder(getter_AddRefs(folder));
00475   NS_ENSURE_SUCCESS(rv,rv);
00476   NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
00477   folder->GetCharsetOverride(aCharacterSetOverride);
00478 
00479   return NS_OK;
00480 }
00481 
00482 NS_IMETHODIMP nsMailboxUrl::GetCharsetOverRide(char ** aCharacterSet)
00483 {
00484   if (!mCharsetOverride.IsEmpty())
00485     *aCharacterSet = ToNewCString(mCharsetOverride); 
00486   else
00487     *aCharacterSet = nsnull;
00488   return NS_OK;
00489 }
00490 
00491 NS_IMETHODIMP nsMailboxUrl::SetCharsetOverRide(const char * aCharacterSet)
00492 {
00493   mCharsetOverride = aCharacterSet;
00494   return NS_OK;
00495 }
00496 
00497 /* void setMoveCopyMsgKeys (out nsMsgKey keysToFlag, in long numKeys); */
00498 NS_IMETHODIMP nsMailboxUrl::SetMoveCopyMsgKeys(nsMsgKey *keysToFlag, PRInt32 numKeys)
00499 {
00500   m_keys.RemoveAll();
00501   m_keys.Add(keysToFlag, numKeys);
00502   if (m_keys.GetSize() > 0 && m_messageKey == nsMsgKey_None)
00503     m_messageKey = m_keys.GetAt(0);
00504   return NS_OK;
00505 }
00506 
00507 NS_IMETHODIMP nsMailboxUrl::GetMoveCopyMsgHdrForIndex(PRUint32 msgIndex, nsIMsgDBHdr **msgHdr)
00508 {
00509   NS_ENSURE_ARG(msgHdr);
00510   if (msgIndex < m_keys.GetSize())
00511   {
00512     nsMsgKey nextKey = m_keys.GetAt(msgIndex);
00513     return GetMsgHdrForKey(nextKey, msgHdr);
00514   }
00515   return NS_MSG_MESSAGE_NOT_FOUND;
00516 }
00517 
00518 NS_IMETHODIMP nsMailboxUrl::GetNumMoveCopyMsgs(PRUint32 *numMsgs)
00519 {
00520   NS_ENSURE_ARG(numMsgs);
00521   *numMsgs = m_keys.GetSize();
00522   return NS_OK;
00523 }
00524 
00525