Back to index

lightning-sunbird  0.9+nobinonly
nsImapUrl.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  *   David Bienvenu <bienvenu@nventure.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 #include "nsMsgImapCID.h"
00041 
00042 #include "nsIEventQueueService.h"
00043 
00044 #include "nsIURL.h"
00045 #include "nsImapUrl.h"
00046 #include "nsIMsgMailSession.h"
00047 #include "nsIIMAPHostSessionList.h"
00048 #include "nsIMAPGenericParser.h"
00049 #include "nsString.h"
00050 #include "prmem.h"
00051 #include "plstr.h"
00052 #include "prprf.h"
00053 #include "nsCRT.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsIImapIncomingServer.h"
00056 #include "nsMsgBaseCID.h"
00057 #include "nsImapUtils.h"
00058 #include "nsXPIDLString.h"
00059 #include "nsReadableUtils.h"
00060 #include "nsAutoLock.h"
00061 #include "nsIMAPNamespace.h"
00062 #include "nsICacheEntryDescriptor.h"
00063 #include "nsISupportsObsolete.h"
00064 // rdf stuff is needed to get the charset from the imap folder associated with the url.
00065 #include "nsIRDFService.h"
00066 #include "rdf.h"
00067 #include "nsIMsgFolder.h"
00068 #include "nsIDocShell.h"
00069 #include "nsIInterfaceRequestor.h"
00070 #include "nsIInterfaceRequestorUtils.h"
00071 #include "nsMsgUtils.h"
00072 #include "nsIMsgHdr.h"
00073 #include "nsIProgressEventSink.h"
00074 #include "nsEscape.h"
00075 
00076 static NS_DEFINE_CID(kCImapMockChannel, NS_IMAPMOCKCHANNEL_CID);
00077 static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
00078 
00079 nsImapUrl::nsImapUrl()
00080 {
00081   m_listOfMessageIds = nsnull;
00082   m_sourceCanonicalFolderPathSubString = nsnull;
00083   m_destinationCanonicalFolderPathSubString = nsnull;
00084   m_listOfMessageIds = nsnull;
00085   m_tokenPlaceHolder = nsnull;
00086   m_searchCriteriaString = nsnull;
00087   m_idsAreUids = PR_FALSE;
00088   m_mimePartSelectorDetected = PR_FALSE;
00089   m_allowContentChange = PR_TRUE;  // assume we can do MPOD.
00090   m_fetchPartsOnDemand = PR_FALSE; // but assume we're not doing it :-)
00091   m_msgLoadingFromCache = PR_FALSE;
00092   m_shouldStoreMsgOffline = PR_FALSE;
00093   m_rerunningUrl = PR_FALSE;
00094   m_externalLinkUrl = PR_TRUE; // we'll start this at true, and set it false in nsImapService::CreateStartOfImapUrl
00095   m_contentModified = IMAP_CONTENT_NOT_MODIFIED;
00096   m_validUrl = PR_TRUE;     // assume the best.
00097   m_flags = 0;
00098   m_onlineSubDirSeparator = '/'; 
00099   
00100   // ** jt - the following are not ref counted
00101   m_copyState = nsnull;
00102   m_fileSpec = nsnull;
00103   m_imapMailFolderSink = nsnull;
00104   m_imapMessageSink = nsnull;
00105   m_addDummyEnvelope = PR_FALSE;
00106   m_canonicalLineEnding = PR_FALSE;
00107 }
00108 
00109 nsresult nsImapUrl::Initialize()
00110 {
00111   nsresult rv;
00112   m_mockChannel = do_CreateInstance(kCImapMockChannel, &rv);
00113   return rv;
00114 }
00115 
00116 
00117 NS_IMETHODIMP nsImapUrl::InitializeURIforMockChannel()
00118 {
00119   if (m_mockChannel)
00120     m_mockChannel->SetURI(this);
00121   return NS_OK;
00122 }
00123  
00124 NS_IMETHODIMP nsImapUrl::SetMsgWindow(nsIMsgWindow *aMsgWindow)
00125 {
00126   if (aMsgWindow)
00127   {
00128     m_msgWindow = do_QueryInterface(aMsgWindow);
00129     if (m_mockChannel) {
00130       m_mockChannel->SetURI(this);
00131       nsCOMPtr<nsIDocShell> msgDocShell;
00132       m_msgWindow->GetRootDocShell(getter_AddRefs(msgDocShell));
00133       if (msgDocShell) {
00134         nsCOMPtr <nsIProgressEventSink> prevEventSink;
00135         m_mockChannel->GetProgressEventSink(getter_AddRefs(prevEventSink));
00136         nsCOMPtr<nsIInterfaceRequestor> docIR(do_QueryInterface(msgDocShell));
00137         m_mockChannel->SetNotificationCallbacks(docIR);
00138         // we want to use our existing event sink.
00139         if (prevEventSink)
00140           m_mockChannel->SetProgressEventSink(prevEventSink);
00141       }
00142     }
00143   }
00144   return NS_OK;
00145 }
00146 
00147 
00148 nsImapUrl::~nsImapUrl()
00149 {
00150   PR_FREEIF(m_listOfMessageIds);
00151   PR_FREEIF(m_destinationCanonicalFolderPathSubString);
00152   PR_FREEIF(m_sourceCanonicalFolderPathSubString);
00153   PR_FREEIF(m_searchCriteriaString);
00154 }
00155   
00156 NS_IMPL_ADDREF_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
00157 
00158 NS_IMPL_RELEASE_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
00159 
00160 NS_INTERFACE_MAP_BEGIN(nsImapUrl)
00161    NS_INTERFACE_MAP_ENTRY(nsIImapUrl)
00162    NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
00163    NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
00164 NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
00165 
00167 // Begin nsIImapUrl specific support
00169 
00170 NS_IMETHODIMP nsImapUrl::GetRequiredImapState(nsImapState * aImapUrlState)
00171 {
00172   if (aImapUrlState)
00173   {
00174     // the imap action determines the state we must be in...check the 
00175     // the imap action.
00176     
00177     if (m_imapAction & 0x10000000)
00178       *aImapUrlState = nsImapSelectedState;
00179     else
00180       *aImapUrlState = nsImapAuthenticatedState;
00181   }
00182   
00183   return NS_OK;
00184 }
00185 
00186 NS_IMETHODIMP nsImapUrl::GetImapAction(nsImapAction * aImapAction)
00187 {
00188   *aImapAction = m_imapAction;
00189   return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP nsImapUrl::SetImapAction(nsImapAction aImapAction)
00193 {
00194   m_imapAction = aImapAction;
00195   return NS_OK;
00196 }
00197 
00198 NS_IMETHODIMP nsImapUrl::GetFolder(nsIMsgFolder **aMsgFolder)
00199 {
00200   NS_ENSURE_ARG_POINTER(aMsgFolder);
00201   NS_ENSURE_ARG_POINTER(m_imapFolder);
00202 
00203   nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(m_imapFolder);
00204   NS_IF_ADDREF(*aMsgFolder = folder);
00205   return NS_OK;
00206 }
00207 
00208 NS_IMETHODIMP nsImapUrl::SetFolder(nsIMsgFolder  * aMsgFolder)
00209 {
00210   nsresult rv;
00211   m_imapFolder = do_GetWeakReference(aMsgFolder, &rv);
00212   if (aMsgFolder)
00213   {
00214     nsCOMPtr <nsIMsgIncomingServer> incomingServer;
00215     aMsgFolder->GetServer(getter_AddRefs(incomingServer));
00216     if (incomingServer)
00217       incomingServer->GetKey(getter_Copies(m_serverKey));
00218   }
00219   return rv;
00220 }
00221 
00222 NS_IMETHODIMP nsImapUrl::GetImapMailFolderSink(nsIImapMailFolderSink **
00223                                            aImapMailFolderSink)
00224 {
00225     NS_ENSURE_ARG_POINTER(aImapMailFolderSink);
00226     if (!m_imapMailFolderSink)
00227       return NS_ERROR_NULL_POINTER; // no assert, so don't use NS_ENSURE_POINTER.
00228 
00229     nsCOMPtr<nsIImapMailFolderSink> folderSink = do_QueryReferent(m_imapMailFolderSink);
00230     *aImapMailFolderSink = folderSink;
00231     NS_IF_ADDREF(*aImapMailFolderSink);
00232     return NS_OK;
00233 }
00234 
00235 NS_IMETHODIMP nsImapUrl::SetImapMailFolderSink(nsIImapMailFolderSink  * aImapMailFolderSink)
00236 {
00237     nsresult rv;
00238     m_imapMailFolderSink = do_GetWeakReference(aImapMailFolderSink, &rv);
00239     return rv;
00240 }
00241  
00242 NS_IMETHODIMP nsImapUrl::GetImapMessageSink(nsIImapMessageSink ** aImapMessageSink)
00243 {
00244     NS_ENSURE_ARG_POINTER(aImapMessageSink);
00245     NS_ENSURE_ARG_POINTER(m_imapMessageSink);
00246 
00247     nsCOMPtr<nsIImapMessageSink> messageSink = do_QueryReferent(m_imapMessageSink);
00248     *aImapMessageSink = messageSink;
00249     NS_IF_ADDREF(*aImapMessageSink);
00250     return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP nsImapUrl::SetImapMessageSink(nsIImapMessageSink  * aImapMessageSink)
00254 {
00255   nsresult rv;
00256   m_imapMessageSink = do_GetWeakReference(aImapMessageSink, &rv);
00257   return rv;
00258 }
00259 
00260 NS_IMETHODIMP nsImapUrl::GetImapServerSink(nsIImapServerSink ** aImapServerSink)
00261 {
00262     NS_ENSURE_ARG_POINTER(aImapServerSink);
00263     NS_ENSURE_ARG_POINTER(m_imapServerSink);
00264 
00265     nsCOMPtr<nsIImapServerSink> serverSink = do_QueryReferent(m_imapServerSink);
00266     *aImapServerSink = serverSink;
00267     NS_IF_ADDREF(*aImapServerSink);
00268     return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP nsImapUrl::SetImapServerSink(nsIImapServerSink  * aImapServerSink)
00272 {
00273   nsresult rv;
00274   m_imapServerSink = do_GetWeakReference(aImapServerSink, &rv);
00275   return rv;
00276 }
00277 
00278         
00280 // End nsIImapUrl specific support
00282 
00283 NS_IMETHODIMP nsImapUrl::SetSpec(const nsACString &aSpec)
00284 {
00285   nsresult rv = nsMsgMailNewsUrl::SetSpec(aSpec);
00286   if (NS_SUCCEEDED(rv))
00287   {
00288     m_validUrl = PR_TRUE;   // assume the best.
00289     rv = ParseUrl();
00290   }
00291   return rv;
00292 }
00293 
00294 NS_IMETHODIMP nsImapUrl::SetQuery(const nsACString &aQuery)
00295 {
00296   nsresult rv = nsMsgMailNewsUrl::SetQuery(aQuery);
00297   if (NS_SUCCEEDED(rv))
00298     rv = ParseUrl();
00299   return rv;
00300 }
00301 
00302 nsresult nsImapUrl::ParseUrl()
00303 {
00304   nsresult rv = NS_OK;
00305   // extract the user name
00306   GetUserPass(m_userName);
00307   
00308   nsCAutoString imapPartOfUrl;
00309   rv = GetPath(imapPartOfUrl);
00310   NS_UnescapeURL(imapPartOfUrl);
00311   if (NS_SUCCEEDED(rv) && !imapPartOfUrl.IsEmpty())
00312   {
00313     ParseImapPart(imapPartOfUrl.BeginWriting()+1);  // GetPath leaves leading '/' in the path!!!
00314   }
00315   
00316   return NS_OK;
00317 }
00318 
00319 NS_IMETHODIMP nsImapUrl::CreateSearchCriteriaString(char ** aResult)
00320 {
00321   // this method should only be called from the imap thread...
00322   // o.t. add lock protection..
00323   if (nsnull == aResult || !m_searchCriteriaString) 
00324     return  NS_ERROR_NULL_POINTER;
00325   *aResult = strdup(m_searchCriteriaString);
00326   return NS_OK;
00327 }
00328 
00329 // this method gets called from the UI thread and the imap thread
00330 NS_IMETHODIMP nsImapUrl::CreateListOfMessageIdsString(char ** aResult) 
00331 {
00332   nsAutoCMonitor mon(this);
00333   nsCAutoString newStr;
00334   if (nsnull == aResult || !m_listOfMessageIds) 
00335     return  NS_ERROR_NULL_POINTER;
00336   
00337   PRInt32 bytesToCopy = strlen(m_listOfMessageIds);
00338   
00339   // mime may have glommed a "&part=" for a part download
00340   // we return the entire message and let mime extract
00341   // the part. Pop and news work this way also.
00342   // this algorithm truncates the "&part" string.
00343   char *currentChar = m_listOfMessageIds;
00344   while (*currentChar && (*currentChar != '?'))
00345     currentChar++;
00346   if (*currentChar == '?')
00347     bytesToCopy = currentChar - m_listOfMessageIds;
00348   
00349   // we should also strip off anything after "/;section="
00350   // since that can specify an IMAP MIME part
00351   char *wherePart = PL_strstr(m_listOfMessageIds, "/;section=");
00352   if (wherePart)
00353     bytesToCopy = PR_MIN(bytesToCopy, wherePart - m_listOfMessageIds);
00354   
00355   newStr.Assign(m_listOfMessageIds, bytesToCopy);
00356   *aResult = ToNewCString(newStr);
00357   return NS_OK;
00358 }
00359 
00360 NS_IMETHODIMP nsImapUrl::GetCommand(char **result)
00361 {
00362   NS_ENSURE_ARG_POINTER(result);
00363   *result = strdup(m_command.get());
00364   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00365 }
00366 
00367 
00368 NS_IMETHODIMP nsImapUrl::GetCustomAttributeToFetch(char **result)
00369 {
00370   NS_ENSURE_ARG_POINTER(result);
00371   *result = ToNewCString(m_msgFetchAttribute);
00372   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00373 }
00374 
00375 NS_IMETHODIMP nsImapUrl::GetCustomAttributeResult(char **result)
00376 {
00377   NS_ENSURE_ARG_POINTER(result);
00378   *result = ToNewCString(m_customAttributeResult);
00379   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00380 }
00381 
00382 NS_IMETHODIMP nsImapUrl::SetCustomAttributeResult(const char *result)
00383 {
00384   m_customAttributeResult = result;
00385   return NS_OK;
00386 }
00387 
00388 NS_IMETHODIMP nsImapUrl::GetCustomCommandResult(char **result)
00389 {
00390   NS_ENSURE_ARG_POINTER(result);
00391   *result = strdup(m_customCommandResult.get());
00392   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00393 }
00394 
00395 NS_IMETHODIMP nsImapUrl::SetCustomCommandResult(const char *result)
00396 {
00397   m_customCommandResult = result;
00398   return NS_OK;
00399 }
00400 
00401 NS_IMETHODIMP nsImapUrl::GetCustomAddFlags(char **aResult)
00402 {
00403   NS_ENSURE_ARG_POINTER(aResult);
00404   *aResult = ToNewCString(m_customAddFlags);
00405   return (*aResult) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00406 }
00407 
00408 NS_IMETHODIMP nsImapUrl::GetCustomSubtractFlags(char **aResult)
00409 {
00410   NS_ENSURE_ARG_POINTER(aResult);
00411   *aResult = ToNewCString(m_customSubtractFlags);
00412   return (*aResult) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00413 }
00414 
00415 
00416 NS_IMETHODIMP nsImapUrl::GetImapPartToFetch(char **result) 
00417 {
00418   //  here's the old code....
00419 
00420   // unforunately an imap part can have the form: /;section= OR
00421   // it can have the form ?section=. We need to look for both.
00422   if (m_listOfMessageIds)
00423   {
00424     char *wherepart = PL_strstr(m_listOfMessageIds, ";section=");
00425     if (!wherepart) // look for ?section too....
00426       wherepart = PL_strstr(m_listOfMessageIds, "?section=");
00427               if (wherepart)
00428               {
00429       wherepart += 9;  // nsCRT::strlen("/;section=")
00430                      char *wherelibmimepart = PL_strstr(wherepart, "&part=");
00431                      if (!wherelibmimepart)
00432         wherelibmimepart = PL_strstr(wherepart, "?part=");
00433       int numCharsToCopy = (wherelibmimepart) ? wherelibmimepart - wherepart :
00434                    PL_strlen(m_listOfMessageIds) - (wherepart - m_listOfMessageIds);
00435                      if (numCharsToCopy)
00436                      {
00437                             *result = (char *) PR_Malloc(sizeof(char) * (numCharsToCopy + 1));
00438                             if (*result)
00439                             {
00440                                    PL_strncpy(*result, wherepart, numCharsToCopy + 1);     // appends a \0
00441           (*result)[numCharsToCopy] = '\0';
00442                             }
00443                      }
00444     } // if we got a wherepart
00445   } // if we got a m_listOfMessageIds
00446   return NS_OK;
00447 }
00448 
00449 NS_IMETHODIMP nsImapUrl::GetOnlineSubDirSeparator(char* separator)
00450 {
00451   if (separator)
00452   {
00453       *separator = m_onlineSubDirSeparator;
00454       return NS_OK;
00455   }
00456   else
00457   {
00458       return NS_ERROR_NULL_POINTER;
00459   }
00460 }
00461 
00462 NS_IMETHODIMP nsImapUrl::GetNumBytesToFetch(PRInt32 *aNumBytesToFetch)
00463 {
00464   NS_ENSURE_ARG_POINTER(aNumBytesToFetch);
00465   *aNumBytesToFetch = m_numBytesToFetch;
00466   return NS_OK;
00467 }
00468 
00469 NS_IMETHODIMP
00470 nsImapUrl::SetOnlineSubDirSeparator(char onlineDirSeparator)
00471 {
00472   m_onlineSubDirSeparator = onlineDirSeparator;
00473   return NS_OK;
00474 }
00475 
00476 // this method is only called from the imap thread
00477 NS_IMETHODIMP nsImapUrl::MessageIdsAreUids(PRBool *result)
00478 {
00479   *result = m_idsAreUids;
00480   return NS_OK;
00481 }
00482 
00483 // this method is only called from the imap thread
00484 NS_IMETHODIMP nsImapUrl::GetMsgFlags(imapMessageFlagsType *result)    // kAddMsgFlags or kSubtractMsgFlags only
00485 {
00486   *result = m_flags;
00487   return NS_OK;
00488 }
00489 
00490 void nsImapUrl::ParseImapPart(char *imapPartOfUrl)
00491 {
00492   m_tokenPlaceHolder = imapPartOfUrl;
00493   m_urlidSubString = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
00494   
00495   if (!m_urlidSubString)
00496   {
00497     m_validUrl = PR_FALSE;
00498     return;
00499   }
00500   
00501   if (!nsCRT::strcasecmp(m_urlidSubString, "fetch"))
00502   {
00503     m_imapAction  = nsImapMsgFetch;
00504     ParseUidChoice();
00505     PR_FREEIF(m_sourceCanonicalFolderPathSubString);
00506     ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00507     ParseListOfMessageIds(); 
00508     // if fetched by spam filter, the action will be changed to nsImapMsgFetchPeek
00509   }
00510   else /* if (fInternal) no concept of internal - not sure there will be one */
00511   {
00512     if (!nsCRT::strcasecmp(m_urlidSubString, "header"))
00513     {
00514       m_imapAction = nsImapMsgHeader;
00515       ParseUidChoice();
00516       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00517       ParseListOfMessageIds();
00518     }
00519     else if (!nsCRT::strcasecmp(m_urlidSubString, "customFetch"))
00520     {
00521       ParseUidChoice();
00522       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00523       ParseListOfMessageIds();
00524       ParseCustomMsgFetchAttribute();
00525     }
00526     else if (!nsCRT::strcasecmp(m_urlidSubString, "previewBody"))
00527     {
00528       ParseUidChoice();
00529       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00530       ParseListOfMessageIds();
00531       ParseNumBytes();
00532     }
00533     else if (!nsCRT::strcasecmp(m_urlidSubString, "deletemsg"))
00534     {
00535       m_imapAction = nsImapDeleteMsg;
00536       ParseUidChoice();
00537       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00538       ParseListOfMessageIds();
00539     }
00540     else if (!nsCRT::strcasecmp(m_urlidSubString, "uidexpunge"))
00541     {
00542       m_imapAction = nsImapUidExpunge;
00543       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00544       ParseListOfMessageIds();
00545     }
00546     else if (!nsCRT::strcasecmp(m_urlidSubString, "deleteallmsgs"))
00547     {
00548       m_imapAction = nsImapDeleteAllMsgs;
00549       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00550     }
00551     else if (!nsCRT::strcasecmp(m_urlidSubString, "addmsgflags"))
00552     {
00553       m_imapAction = nsImapAddMsgFlags;
00554       ParseUidChoice();
00555       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00556       ParseListOfMessageIds();
00557       ParseMsgFlags();
00558     }
00559     else if (!nsCRT::strcasecmp(m_urlidSubString, "subtractmsgflags"))
00560     {
00561       m_imapAction = nsImapSubtractMsgFlags;
00562       ParseUidChoice();
00563       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00564       ParseListOfMessageIds();
00565       ParseMsgFlags();
00566     }
00567     else if (!nsCRT::strcasecmp(m_urlidSubString, "setmsgflags"))
00568     {
00569       m_imapAction = nsImapSetMsgFlags;
00570       ParseUidChoice();
00571       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00572       ParseListOfMessageIds();
00573       ParseMsgFlags();
00574     }
00575     else if (!nsCRT::strcasecmp(m_urlidSubString, "onlinecopy"))
00576     {
00577       m_imapAction = nsImapOnlineCopy;
00578       ParseUidChoice();
00579       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00580       ParseListOfMessageIds();
00581       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00582     }
00583     else if (!nsCRT::strcasecmp(m_urlidSubString, "onlinemove"))
00584     {
00585       m_imapAction = nsImapOnlineMove;
00586       ParseUidChoice();
00587       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00588       ParseListOfMessageIds();
00589       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00590     }
00591     else if (!nsCRT::strcasecmp(m_urlidSubString, "onlinetoofflinecopy"))
00592     {
00593       m_imapAction = nsImapOnlineToOfflineCopy;
00594       ParseUidChoice();
00595       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00596       ParseListOfMessageIds();
00597       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00598     }
00599     else if (!nsCRT::strcasecmp(m_urlidSubString, "onlinetoofflinemove"))
00600     {
00601       m_imapAction = nsImapOnlineToOfflineMove;
00602       ParseUidChoice();
00603       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00604       ParseListOfMessageIds();
00605       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00606     }
00607     else if (!nsCRT::strcasecmp(m_urlidSubString, "offlinetoonlinecopy"))
00608     {
00609       m_imapAction = nsImapOfflineToOnlineMove;
00610       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00611     }
00612     else if (!nsCRT::strcasecmp(m_urlidSubString, "search"))
00613     {
00614       m_imapAction = nsImapSearch;
00615       ParseUidChoice();
00616       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00617       ParseSearchCriteriaString();
00618     }
00619     else if (!nsCRT::strcasecmp(m_urlidSubString, "test"))
00620     {
00621       m_imapAction = nsImapTest;
00622     }
00623     else if (!nsCRT::strcasecmp(m_urlidSubString, "select"))
00624     {
00625       m_imapAction = nsImapSelectFolder;
00626       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00627       if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
00628         ParseListOfMessageIds();
00629       else
00630         m_listOfMessageIds = PL_strdup("");
00631     }
00632     else if (!nsCRT::strcasecmp(m_urlidSubString, "liteselect"))
00633     {
00634       m_imapAction = nsImapLiteSelectFolder;
00635       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00636     }
00637     else if (!nsCRT::strcasecmp(m_urlidSubString, "selectnoop"))
00638     {
00639       m_imapAction = nsImapSelectNoopFolder;
00640       m_listOfMessageIds = PL_strdup("");
00641       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00642     }
00643     else if (!nsCRT::strcasecmp(m_urlidSubString, "expunge"))
00644     {
00645       m_imapAction = nsImapExpungeFolder;
00646       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00647       m_listOfMessageIds = PL_strdup("");        // no ids to UNDO
00648     }
00649     else if (!nsCRT::strcasecmp(m_urlidSubString, "create"))
00650     {
00651       m_imapAction = nsImapCreateFolder;
00652       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00653     }
00654     else if (!nsCRT::strcasecmp(m_urlidSubString, "ensureExists"))
00655     {
00656       m_imapAction = nsImapEnsureExistsFolder;
00657       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00658     }
00659     else if (!nsCRT::strcasecmp(m_urlidSubString, "discoverchildren"))
00660     {
00661       m_imapAction = nsImapDiscoverChildrenUrl;
00662       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00663     }
00664     else if (!nsCRT::strcasecmp(m_urlidSubString, "discoverallboxes"))
00665     {
00666       m_imapAction = nsImapDiscoverAllBoxesUrl;
00667     }
00668     else if (!nsCRT::strcasecmp(m_urlidSubString, "discoverallandsubscribedboxes"))
00669     {
00670       m_imapAction = nsImapDiscoverAllAndSubscribedBoxesUrl;
00671     }
00672     else if (!nsCRT::strcasecmp(m_urlidSubString, "delete"))
00673     {
00674       m_imapAction = nsImapDeleteFolder;
00675       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00676     }
00677     else if (!nsCRT::strcasecmp(m_urlidSubString, "deletefolder"))
00678     {
00679       m_imapAction = nsImapDeleteFolderAndMsgs;
00680       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00681     }
00682     else if (!nsCRT::strcasecmp(m_urlidSubString, "rename"))
00683     {
00684       m_imapAction = nsImapRenameFolder;
00685       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00686       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00687     }
00688     else if (!nsCRT::strcasecmp(m_urlidSubString, "movefolderhierarchy"))
00689     {
00690       m_imapAction = nsImapMoveFolderHierarchy;
00691       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00692       if (m_tokenPlaceHolder && *m_tokenPlaceHolder)    // handle promote to root
00693         ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00694     }
00695     else if (!nsCRT::strcasecmp(m_urlidSubString, "list"))
00696     {
00697       m_imapAction = nsImapLsubFolders;
00698       ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
00699     }
00700     else if (!nsCRT::strcasecmp(m_urlidSubString, "biff"))
00701     {
00702       m_imapAction = nsImapBiff;
00703       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00704       ParseListOfMessageIds();
00705     }
00706     else if (!nsCRT::strcasecmp(m_urlidSubString, "netscape"))
00707     {
00708       m_imapAction = nsImapGetMailAccountUrl;
00709     }
00710     else if (!nsCRT::strcasecmp(m_urlidSubString, "appendmsgfromfile"))
00711     {
00712       m_imapAction = nsImapAppendMsgFromFile;
00713       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00714     }
00715     else if (!nsCRT::strcasecmp(m_urlidSubString, "appenddraftfromfile"))
00716     {
00717       m_imapAction = nsImapAppendDraftFromFile;
00718       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00719       ParseUidChoice();
00720       if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
00721         ParseListOfMessageIds();
00722       else
00723         m_listOfMessageIds = strdup("");
00724     }
00725     else if (!nsCRT::strcasecmp(m_urlidSubString, "subscribe"))
00726     {
00727       m_imapAction = nsImapSubscribe;
00728       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00729     }
00730     else if (!nsCRT::strcasecmp(m_urlidSubString, "unsubscribe"))
00731     {
00732       m_imapAction = nsImapUnsubscribe;
00733       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00734     }
00735     else if (!nsCRT::strcasecmp(m_urlidSubString, "refreshacl"))
00736     {
00737       m_imapAction = nsImapRefreshACL;
00738       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00739     }
00740     else if (!nsCRT::strcasecmp(m_urlidSubString, "refreshfolderurls"))
00741     {
00742       m_imapAction = nsImapRefreshFolderUrls;
00743       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00744     }
00745     else if (!nsCRT::strcasecmp(m_urlidSubString, "refreshallacls"))
00746     {
00747       m_imapAction = nsImapRefreshAllACLs;
00748     }
00749     else if (!nsCRT::strcasecmp(m_urlidSubString, "listfolder"))
00750     {
00751       m_imapAction = nsImapListFolder;
00752       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00753     }
00754     else if (!nsCRT::strcasecmp(m_urlidSubString, "upgradetosubscription"))
00755     {
00756       m_imapAction = nsImapUpgradeToSubscription;
00757       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00758     }
00759     else if (!nsCRT::strcasecmp(m_urlidSubString, "folderstatus"))
00760     {
00761       m_imapAction = nsImapFolderStatus;
00762       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00763     }
00764     else if (m_imapAction == nsIImapUrl::nsImapUserDefinedMsgCommand)
00765     {
00766       m_command = m_urlidSubString; // save this
00767       ParseUidChoice();
00768       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00769       ParseListOfMessageIds();
00770     }
00771     else if (m_imapAction == nsIImapUrl::nsImapMsgStoreCustomKeywords)
00772     {
00773       ParseUidChoice();
00774       ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
00775       ParseListOfMessageIds();
00776       PRBool addKeyword = (m_tokenPlaceHolder && *m_tokenPlaceHolder != '>');
00777       // if we're not adding a keyword, m_tokenPlaceHolder will now look like >keywordToSubtract>
00778       // and strtok will leave flagsPtr pointing to keywordToSubtract. So detect this
00779       // case and only set the customSubtractFlags.
00780       char *flagsPtr = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nsnull;
00781       if (addKeyword)
00782       {
00783         m_customAddFlags.Assign(flagsPtr);
00784         flagsPtr = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nsnull;
00785       }
00786       m_customSubtractFlags.Assign(flagsPtr);
00787     }
00788     else
00789     {
00790       m_validUrl = PR_FALSE;       
00791     }
00792   }
00793 }
00794 
00795 
00796 // Returns NULL if nothing was done.
00797 // Otherwise, returns a newly allocated name.
00798 NS_IMETHODIMP nsImapUrl::AddOnlineDirectoryIfNecessary(const char *onlineMailboxName, char ** directory)
00799 {
00800   nsresult rv;
00801   nsString aString;
00802   char *newOnlineName = nsnull;
00803   
00804   nsCOMPtr<nsIImapHostSessionList> hostSessionList = 
00805     do_GetService(kCImapHostSessionListCID, &rv);
00806   if (NS_FAILED(rv)) return rv;
00807   rv = hostSessionList->GetOnlineDirForHost(m_serverKey, aString);
00808   nsCAutoString onlineDir;
00809   onlineDir.AssignWithConversion(aString);
00810   
00811   // If this host has an online server directory configured
00812   if (onlineMailboxName && !onlineDir.IsEmpty())
00813   {
00814     nsIMAPNamespace *ns = nsnull;
00815     rv = hostSessionList->GetNamespaceForMailboxForHost(m_serverKey,
00816       onlineMailboxName, ns); 
00817     if (!ns)
00818        hostSessionList->GetDefaultNamespaceOfTypeForHost(m_serverKey, kPersonalNamespace, ns);
00819     
00820     if (PL_strcasecmp(onlineMailboxName, "INBOX"))
00821     {
00822       NS_ASSERTION(ns, "couldn't find namespace for host");
00823       nsCAutoString onlineDirWithDelimiter(onlineDir);
00824       // make sure the onlineDir ends with the hierarchy delimiter
00825       if (ns)
00826       {
00827         char delimiter = ns->GetDelimiter();
00828         if ( delimiter && delimiter != kOnlineHierarchySeparatorUnknown )
00829         {
00830           // try to change the canonical online dir name to real dir name first
00831           onlineDirWithDelimiter.ReplaceChar('/', delimiter);
00832           // make sure the last character is the delimiter
00833           if ( onlineDirWithDelimiter.Last() != delimiter )
00834             onlineDirWithDelimiter += delimiter;
00835           if ( !*onlineMailboxName )
00836             onlineDirWithDelimiter.SetLength(onlineDirWithDelimiter.Length()-1);
00837         }
00838       }
00839       if (ns && (PL_strlen(ns->GetPrefix()) != 0) && !onlineDirWithDelimiter.Equals(ns->GetPrefix()))
00840       {
00841         // check that onlineMailboxName doesn't start with the namespace. If that's the case,
00842         // we don't want to prepend the online dir.
00843         if (PL_strncmp(onlineMailboxName, ns->GetPrefix(), PL_strlen(ns->GetPrefix())))
00844         {
00845           // The namespace for this mailbox is the root ("").
00846           // Prepend the online server directory
00847           int finalLen = onlineDirWithDelimiter.Length() +
00848             strlen(onlineMailboxName) + 1;
00849           newOnlineName = (char *)PR_Malloc(finalLen);
00850           if (newOnlineName)
00851           {
00852             PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
00853             PL_strcat(newOnlineName, onlineMailboxName);
00854           }
00855         }
00856      }
00857       // just prepend the online server directory if it doesn't start with it already
00858       else if (strncmp(onlineMailboxName, onlineDirWithDelimiter.get(), onlineDirWithDelimiter.Length()))
00859       {
00860         newOnlineName = (char *)PR_Malloc(strlen(onlineMailboxName) + onlineDirWithDelimiter.Length() + 1);
00861         if (newOnlineName)
00862         {
00863           PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
00864           PL_strcat(newOnlineName, onlineMailboxName);
00865         }
00866       }
00867     }
00868   }
00869   if (directory)
00870     *directory = newOnlineName;
00871   else if (newOnlineName)
00872     nsCRT::free(newOnlineName);
00873   return rv;
00874 }
00875 
00876 // Converts from canonical format (hierarchy is indicated by '/' and all real slashes ('/') are escaped)
00877 // to the real online name on the server.
00878 NS_IMETHODIMP nsImapUrl::AllocateServerPath(const char * canonicalPath, char onlineDelimiter, char ** aAllocatedPath)
00879 {
00880   nsresult retVal = NS_OK;
00881   char *rv = NULL;
00882   char delimiterToUse = onlineDelimiter;
00883   if (onlineDelimiter == kOnlineHierarchySeparatorUnknown)
00884     GetOnlineSubDirSeparator(&delimiterToUse);
00885   NS_ASSERTION(delimiterToUse != kOnlineHierarchySeparatorUnknown, "hierarchy separator unknown");
00886   if (canonicalPath)
00887     rv = ReplaceCharsInCopiedString(canonicalPath, '/', delimiterToUse);
00888   else
00889     rv = strdup("");
00890   
00891   if (delimiterToUse != '/')
00892     UnescapeSlashes(rv);
00893   char *onlineNameAdded = nsnull;
00894   AddOnlineDirectoryIfNecessary(rv, &onlineNameAdded);
00895   if (onlineNameAdded)
00896   {
00897     nsCRT::free(rv);
00898     rv = onlineNameAdded;
00899   }
00900   
00901   if (aAllocatedPath)
00902     *aAllocatedPath = rv;
00903   else
00904     nsCRT::free(rv);
00905   
00906   return retVal;
00907 }
00908 
00909 // escape '/' as ^, ^ -> ^^ - use UnescapeSlashes to revert
00910 /* static */ nsresult nsImapUrl::EscapeSlashes(const char *sourcePath, char **resultPath)
00911 {
00912   NS_ENSURE_ARG(sourcePath);
00913   NS_ENSURE_ARG(resultPath);
00914   PRInt32 extra = 0;
00915   PRInt32 len = strlen(sourcePath);
00916   const char *src = sourcePath;
00917   PRInt32 i;
00918   for ( i = 0; i < len; i++)
00919   {
00920     if (*src == '^')
00921       extra += 1; /* ^ -> ^^ */
00922     src++;
00923   }
00924   char* result = (char *)nsMemory::Alloc(len + extra + 1);
00925   if (!result)
00926     return NS_ERROR_OUT_OF_MEMORY;
00927 
00928   register unsigned char* dst = (unsigned char *) result;
00929   src = sourcePath;
00930   for (i = 0; i < len; i++)
00931   {
00932     unsigned char c = *src++;
00933     if (c == '/') 
00934       *dst++ = '^';
00935     else if (c == '^')
00936     {
00937       *dst++ = '^';
00938       *dst++ = '^';
00939     }
00940     else
00941       *dst++ = c;
00942   }
00943   *dst = '\0';     /* tack on eos */
00944   *resultPath = result;
00945   return NS_OK;
00946 }
00947 
00948 /* static */ nsresult nsImapUrl::UnescapeSlashes(char *sourcePath)
00949 {
00950     register char *src = sourcePath;
00951     register char *dst = sourcePath;
00952 
00953     while (*src)
00954     {
00955       if (*src == '^')
00956       {
00957         if (*(src + 1) == '^')
00958         {
00959           *dst++ = '^';
00960           src++;   // skip over second '^'
00961         }
00962         else
00963           *dst++ = '/';
00964         src++;
00965       }
00966       else
00967         *dst++ = *src++;
00968     }
00969 
00970     *dst = 0;
00971     return NS_OK;
00972 }
00973 
00974 /*  static */ nsresult nsImapUrl::ConvertToCanonicalFormat(const char *folderName, char onlineDelimiter, char **resultingCanonicalPath)
00975 {
00976   // Now, start the conversion to canonical form.
00977 
00978   char *canonicalPath;
00979   if (onlineDelimiter != '/')
00980   {
00981     nsXPIDLCString escapedPath;
00982 
00983     EscapeSlashes(folderName, getter_Copies(escapedPath));
00984     canonicalPath = ReplaceCharsInCopiedString(escapedPath, onlineDelimiter , '/');
00985   }
00986   else
00987   {
00988     canonicalPath = strdup(folderName);
00989   }
00990   if (canonicalPath)
00991     *resultingCanonicalPath = canonicalPath;
00992 
00993   return (canonicalPath) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00994 }
00995 
00996 // Converts the real online name on the server to canonical format:
00997 // result is hierarchy is indicated by '/' and all real slashes ('/') are escaped.
00998 // The caller has already converted m-utf-7 to 8 bit ascii, which is a problem.
00999 // this method is only called from the imap thread
01000 NS_IMETHODIMP nsImapUrl::AllocateCanonicalPath(const char *serverPath, char onlineDelimiter, char **allocatedPath ) 
01001 {
01002   nsresult rv = NS_ERROR_NULL_POINTER;
01003   char delimiterToUse = onlineDelimiter;
01004   char *serverKey = nsnull;
01005   nsString aString;
01006   char *currentPath = (char *) serverPath;
01007   nsCAutoString onlineDir;
01008   nsCOMPtr<nsIMsgIncomingServer> server;
01009   
01010   nsCOMPtr<nsIImapHostSessionList> hostSessionList = 
01011     do_GetService(kCImapHostSessionListCID, &rv);
01012   
01013   *allocatedPath = nsnull;
01014   
01015   if (onlineDelimiter == kOnlineHierarchySeparatorUnknown ||
01016     onlineDelimiter == 0)
01017     GetOnlineSubDirSeparator(&delimiterToUse);
01018   
01019   NS_ASSERTION (serverPath, "Oops... null serverPath");
01020   
01021   if (!serverPath || NS_FAILED(rv))
01022     goto done;
01023   
01024   hostSessionList->GetOnlineDirForHost(m_serverKey, aString); 
01025   // First we have to check to see if we should strip off an online server
01026   // subdirectory 
01027   // If this host has an online server directory configured
01028   onlineDir = (char *)(!aString.IsEmpty() ? ToNewCString(aString) : nsnull);
01029   
01030   if (currentPath && !onlineDir.IsEmpty())
01031   {
01032     // By definition, the online dir must be at the root.
01033     if (delimiterToUse && delimiterToUse != kOnlineHierarchySeparatorUnknown)
01034     {
01035       // try to change the canonical online dir name to real dir name first
01036       onlineDir.ReplaceChar('/', delimiterToUse);
01037       // Add the delimiter
01038       if (onlineDir.Last() != delimiterToUse)
01039         onlineDir += delimiterToUse;
01040     }
01041     int len = onlineDir.Length();
01042     if (!PL_strncmp(onlineDir.get(), currentPath, len))
01043     {
01044       // This online path begins with the server sub directory
01045       currentPath += len;
01046       
01047       // This might occur, but it's most likely something not good.
01048       // Basically, it means we're doing something on the online sub directory itself.
01049       NS_ASSERTION (*currentPath, "Oops ... null currentPath");
01050       // Also make sure that the first character in the mailbox name is not '/'.
01051       NS_ASSERTION (*currentPath != '/', 
01052         "Oops ... currentPath starts with a slash");
01053     }
01054   }
01055   
01056   
01057   if (!currentPath)
01058     goto done;
01059   
01060   rv = ConvertToCanonicalFormat(currentPath, delimiterToUse, allocatedPath);
01061   
01062 done:
01063   PR_Free(serverKey);
01064   return rv;
01065 }
01066 
01067 // this method is only called from the imap thread
01068 NS_IMETHODIMP  nsImapUrl::CreateServerSourceFolderPathString(char **result)
01069 {
01070   NS_ENSURE_ARG_POINTER(result);
01071   AllocateServerPath(m_sourceCanonicalFolderPathSubString, kOnlineHierarchySeparatorUnknown, result);
01072   return NS_OK;
01073 }
01074 
01075 // this method is called from the imap thread AND the UI thread...
01076 NS_IMETHODIMP nsImapUrl::CreateCanonicalSourceFolderPathString(char **result)
01077 {
01078   NS_ENSURE_ARG_POINTER(result);
01079   nsAutoCMonitor mon(this);
01080   *result = strdup(m_sourceCanonicalFolderPathSubString ? m_sourceCanonicalFolderPathSubString : "");
01081   return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
01082 }
01083 
01084 // this method is called from the imap thread AND the UI thread...
01085 NS_IMETHODIMP nsImapUrl::CreateServerDestinationFolderPathString(char **result)
01086 {
01087   NS_ENSURE_ARG_POINTER(result);
01088   nsAutoCMonitor mon(this);
01089   nsresult rv = AllocateServerPath(m_destinationCanonicalFolderPathSubString,
01090                                    kOnlineHierarchySeparatorUnknown,
01091                                    result);
01092   return (*result) ? rv : NS_ERROR_OUT_OF_MEMORY;
01093 }
01094 
01095 // for enabling or disabling mime parts on demand. Setting this to PR_TRUE says we
01096 // can use mime parts on demand, if we chose.
01097 NS_IMETHODIMP nsImapUrl::SetAllowContentChange(PRBool allowContentChange)
01098 {
01099        m_allowContentChange = allowContentChange;
01100        return NS_OK;
01101 }
01102 
01103 NS_IMETHODIMP nsImapUrl::SetContentModified(nsImapContentModifiedType contentModified)
01104 {
01105   m_contentModified = contentModified;
01106   nsCOMPtr<nsICacheEntryDescriptor>  cacheEntry;
01107   nsresult res = GetMemCacheEntry(getter_AddRefs(cacheEntry));
01108   if (NS_SUCCEEDED(res) && cacheEntry)
01109   {
01110     const char *contentModifiedAnnotation = "";
01111     switch (m_contentModified)
01112     {
01113     case IMAP_CONTENT_NOT_MODIFIED:
01114       contentModifiedAnnotation = "Not Modified";
01115       break;
01116     case IMAP_CONTENT_MODIFIED_VIEW_INLINE:
01117       contentModifiedAnnotation = "Modified View Inline";
01118       break;
01119     case IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS:
01120       contentModifiedAnnotation = "Modified View As Link";
01121       break;
01122     case IMAP_CONTENT_FORCE_CONTENT_NOT_MODIFIED:
01123       contentModifiedAnnotation = "Force Content Not Modified";
01124       break;
01125     }
01126     cacheEntry->SetMetaDataElement("ContentModified", contentModifiedAnnotation);
01127   }
01128        return NS_OK;
01129 }
01130 
01131 NS_IMETHODIMP nsImapUrl::GetContentModified(nsImapContentModifiedType *contentModified)
01132 {
01133        if (!contentModified) return NS_ERROR_NULL_POINTER;
01134 
01135        *contentModified = m_contentModified;
01136        return NS_OK;
01137 }
01138 
01139 NS_IMETHODIMP nsImapUrl::SetFetchPartsOnDemand(PRBool fetchPartsOnDemand)
01140 {
01141        m_fetchPartsOnDemand = fetchPartsOnDemand;
01142        return NS_OK;
01143 }
01144 
01145 NS_IMETHODIMP nsImapUrl::GetFetchPartsOnDemand(PRBool *fetchPartsOnDemand)
01146 {
01147        if (!fetchPartsOnDemand) return NS_ERROR_NULL_POINTER;
01148 
01149        *fetchPartsOnDemand = m_fetchPartsOnDemand;
01150        return NS_OK;
01151 }
01152 
01153 
01154 NS_IMETHODIMP nsImapUrl::SetMimePartSelectorDetected(PRBool mimePartSelectorDetected)
01155 {
01156        m_mimePartSelectorDetected = mimePartSelectorDetected;
01157        return NS_OK;
01158 }
01159 
01160 NS_IMETHODIMP nsImapUrl::GetMimePartSelectorDetected(PRBool *mimePartSelectorDetected)
01161 {
01162        if (!mimePartSelectorDetected) return NS_ERROR_NULL_POINTER;
01163 
01164        *mimePartSelectorDetected = m_mimePartSelectorDetected;
01165        return NS_OK;
01166 }
01167 
01168 
01169 // this method is only called from the UI thread.
01170 NS_IMETHODIMP nsImapUrl::SetCopyState(nsISupports* copyState)
01171 {
01172   nsAutoCMonitor mon(this);
01173   m_copyState = copyState;
01174   return NS_OK;
01175 }
01176 
01177 //this method is only called from the imap thread..but we still
01178 // need a monitor 'cause the setter is called from the UI thread.
01179 NS_IMETHODIMP nsImapUrl::GetCopyState(nsISupports** copyState)
01180 {
01181   NS_ENSURE_ARG_POINTER(copyState);
01182   nsAutoCMonitor mon(this);
01183   *copyState = m_copyState;
01184   NS_IF_ADDREF(*copyState);
01185  
01186   return NS_OK;
01187 }
01188 
01189 NS_IMETHODIMP
01190 nsImapUrl::SetMsgFileSpec(nsIFileSpec* fileSpec)
01191 {
01192   nsresult rv = NS_OK;
01193   nsAutoCMonitor mon(this);
01194   m_fileSpec = fileSpec; // ** jt - not ref counted
01195   return rv;
01196 }
01197 
01198 NS_IMETHODIMP
01199 nsImapUrl::GetMsgFileSpec(nsIFileSpec** fileSpec)
01200 {
01201   NS_ENSURE_ARG_POINTER(fileSpec);
01202 
01203   nsAutoCMonitor mon(this);
01204   *fileSpec = m_fileSpec;
01205   NS_IF_ADDREF(*fileSpec);
01206   return NS_OK;
01207 }
01208 
01209 // this method is called from the UI thread..
01210 NS_IMETHODIMP nsImapUrl::GetMockChannel(nsIImapMockChannel ** aChannel)
01211 {    
01212   NS_ENSURE_ARG_POINTER(aChannel);
01213 
01214   *aChannel = m_mockChannel;
01215   NS_IF_ADDREF(*aChannel);
01216   
01217   return NS_OK;
01218 }
01219 
01220 NS_IMETHODIMP nsImapUrl::SetMockChannel(nsIImapMockChannel * aChannel)
01221 {
01222   nsresult rv = NS_OK;
01223   m_mockChannel = aChannel;
01224   return rv;
01225 }
01226 
01227 NS_IMETHODIMP nsImapUrl::AddChannelToLoadGroup()
01228 {
01229        nsCOMPtr <nsILoadGroup> loadGroup;
01230        if (m_mockChannel)
01231        {
01232               m_mockChannel->GetLoadGroup(getter_AddRefs(loadGroup));
01233     // if the mock channel wasn't initialized with a load group then 
01234     // use our load group (they may differ)
01235     if (!loadGroup)
01236       GetLoadGroup(getter_AddRefs(loadGroup));
01237               
01238     if (loadGroup)
01239               {
01240             nsCOMPtr<nsIRequest> request = do_QueryInterface(m_mockChannel);
01241                      loadGroup->AddRequest(request, nsnull /* context isupports */);
01242               }
01243        }
01244        return NS_OK;
01245 }
01246 
01247 NS_IMETHODIMP nsImapUrl::RemoveChannel(nsresult status)
01248 {
01249   nsCOMPtr <nsILoadGroup> loadGroup;
01250   if (m_mockChannel)
01251   {
01252     m_mockChannel->GetLoadGroup(getter_AddRefs(loadGroup));
01253     // if the mock channel wasn't initialized with a load group then 
01254     // use our load group (they may differ)
01255     if (!loadGroup)
01256       GetLoadGroup(getter_AddRefs(loadGroup));
01257     if (loadGroup)
01258     {
01259       nsCOMPtr<nsIRequest> request = do_QueryInterface(m_mockChannel);
01260       loadGroup->RemoveRequest(request, nsnull, status);
01261     }
01262     // break deadly embrace between mock channel and url
01263     SetMockChannel(nsnull);
01264   }
01265   return NS_OK;
01266 }
01267 
01268 NS_IMETHODIMP nsImapUrl::GetAllowContentChange(PRBool *result)
01269 {
01270   NS_ENSURE_ARG_POINTER(result);
01271        *result = m_allowContentChange;
01272        return NS_OK;
01273 }
01274 
01275 NS_IMETHODIMP nsImapUrl::SetUri(const char * aURI)
01276 {
01277   mURI= aURI;
01278   return NS_OK;
01279 }
01280 
01281 NS_IMETHODIMP nsImapUrl::GetUri(char** aURI)
01282 {
01283   nsresult rv = NS_OK;
01284   if (!mURI.IsEmpty())
01285     *aURI = ToNewCString(mURI);
01286   else
01287        {
01288     *aURI = nsnull;
01289     PRUint32 key = m_listOfMessageIds ? atoi(m_listOfMessageIds) : 0;
01290     nsXPIDLCString canonicalPath;
01291     AllocateCanonicalPath(m_sourceCanonicalFolderPathSubString, m_onlineSubDirSeparator, (getter_Copies(canonicalPath)));
01292     nsCString fullFolderPath("/");
01293     fullFolderPath += (const char *) m_userName;
01294     nsCAutoString hostName;
01295     rv = GetHost(hostName);
01296     fullFolderPath += '@';
01297     fullFolderPath += hostName;
01298     fullFolderPath += '/';
01299     fullFolderPath.Append(canonicalPath);
01300 
01301     char * baseMessageURI;
01302     nsCreateImapBaseMessageURI(fullFolderPath.get(), &baseMessageURI);
01303     nsCAutoString uriStr;
01304     rv = nsBuildImapMessageURI(baseMessageURI, key, uriStr);
01305     nsCRT::free(baseMessageURI);
01306     *aURI = ToNewCString(uriStr);
01307   }
01308   
01309   return rv;
01310 }
01311 
01312 NS_IMPL_GETSET(nsImapUrl, AddDummyEnvelope, PRBool, m_addDummyEnvelope)
01313 NS_IMPL_GETSET(nsImapUrl, CanonicalLineEnding, PRBool, m_canonicalLineEnding)
01314 NS_IMPL_GETTER(nsImapUrl::GetMsgLoadingFromCache, PRBool, m_msgLoadingFromCache)
01315 NS_IMPL_GETSET(nsImapUrl, ExternalLinkUrl, PRBool, m_externalLinkUrl)
01316 NS_IMPL_GETSET(nsImapUrl, RerunningUrl, PRBool, m_rerunningUrl)
01317 NS_IMPL_GETSET(nsImapUrl, ValidUrl, PRBool, m_validUrl)
01318 
01319 NS_IMETHODIMP nsImapUrl::SetMsgLoadingFromCache(PRBool loadingFromCache)
01320 {
01321   nsresult rv = NS_OK;
01322   m_msgLoadingFromCache = loadingFromCache;
01323   return rv;
01324 }
01325 
01326 NS_IMETHODIMP nsImapUrl::SetMessageFile(nsIFileSpec * aFileSpec)
01327 {
01328        m_messageFileSpec = aFileSpec;
01329        return NS_OK;
01330 }
01331 
01332 NS_IMETHODIMP nsImapUrl::GetMessageFile(nsIFileSpec ** aFileSpec)
01333 {
01334        if (aFileSpec)
01335        {
01336               *aFileSpec = m_messageFileSpec;
01337               NS_IF_ADDREF(*aFileSpec);
01338        }
01339        return NS_OK;
01340 }
01341 
01342 NS_IMETHODIMP nsImapUrl::IsUrlType(PRUint32 type, PRBool *isType)
01343 {
01344        NS_ENSURE_ARG(isType);
01345 
01346        switch(type)
01347        {
01348               case nsIMsgMailNewsUrl::eCopy:
01349                      *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineCopy) ||
01350                             (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineCopy) ||
01351                             (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineCopy));
01352                      break;
01353               case nsIMsgMailNewsUrl::eMove:
01354                      *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineMove) ||
01355                             (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineMove) ||
01356                             (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineMove));
01357                      break;
01358     case nsIMsgMailNewsUrl::eDisplay:
01359       *isType = (m_imapAction == nsIImapUrl::nsImapMsgFetch || 
01360         m_imapAction == nsIImapUrl::nsImapMsgFetchPeek);
01361       break;
01362               default:
01363                      *isType = PR_FALSE;
01364        };                          
01365 
01366        return NS_OK;
01367 
01368 }
01369 
01370 NS_IMETHODIMP
01371 nsImapUrl::GetOriginalSpec(char ** aSpec)
01372 {
01373     return NS_ERROR_NOT_IMPLEMENTED;
01374 }
01375 
01376 NS_IMETHODIMP
01377 nsImapUrl::SetOriginalSpec(const char *aSpec)
01378 {
01379     return NS_ERROR_NOT_IMPLEMENTED;
01380 }
01381 
01382 char *nsImapUrl::ReplaceCharsInCopiedString(const char *stringToCopy, char oldChar, char newChar)
01383 {      
01384        char oldCharString[2];
01385        *oldCharString = oldChar;
01386        *(oldCharString+1) = 0;
01387        
01388        char *translatedString = PL_strdup(stringToCopy);
01389        char *currentSeparator = PL_strstr(translatedString, oldCharString);
01390        
01391        while(currentSeparator)
01392        {
01393               *currentSeparator = newChar;
01394               currentSeparator = PL_strstr(currentSeparator+1, oldCharString);
01395        }
01396 
01397        return translatedString;
01398 }
01399 
01400 
01402 // End of functions which should be made obsolete after modifying nsIURI
01404 
01405 void nsImapUrl::ParseFolderPath(char **resultingCanonicalPath)
01406 {
01407        char *resultPath = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
01408        
01409        if (!resultPath)
01410        {
01411               m_validUrl = PR_FALSE;
01412               return;
01413        }
01414        NS_ASSERTION(*resultingCanonicalPath == nsnull, "whoops, mem leak");
01415 
01416        char dirSeparator = *resultPath;
01417 
01418        *resultingCanonicalPath = PL_strdup(resultPath + 1);
01419        nsUnescape(*resultingCanonicalPath);
01420        // The delimiter will be set for a given URL, but will not be statically available
01421        // from an arbitrary URL.  It is the creator's responsibility to fill in the correct
01422        // delimiter from the folder's namespace when creating the URL.
01423        if (dirSeparator != kOnlineHierarchySeparatorUnknown)
01424               SetOnlineSubDirSeparator( dirSeparator);
01425        
01426        // if dirSeparator == kOnlineHierarchySeparatorUnknown, then this must be a create
01427        // of a top level imap box.  If there is an online subdir, we will automatically
01428        // use its separator.  If there is not an online subdir, we don't need a separator.
01429        
01430 }
01431 
01432 
01433 void nsImapUrl::ParseSearchCriteriaString()
01434 {
01435        if (m_tokenPlaceHolder)
01436        {
01437               int quotedFlag = PR_FALSE;
01438 
01439               //skip initial separator
01440               while (*m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR)
01441                      m_tokenPlaceHolder++;
01442               
01443      char *saveTokenPlaceHolder = m_tokenPlaceHolder;
01444 
01445 //            m_searchCriteriaString = m_tokenPlaceHolder;
01446               
01447               //looking for another separator outside quoted string
01448               while (*m_tokenPlaceHolder)
01449               {
01450                      if (*m_tokenPlaceHolder == '\\' && *(m_tokenPlaceHolder+1) == '"')
01451                             m_tokenPlaceHolder++;
01452                      else if (*m_tokenPlaceHolder == '"')
01453                             quotedFlag = !quotedFlag;
01454                      else if (!quotedFlag && *m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR)
01455                      {
01456                             *m_tokenPlaceHolder = '\0';
01457                             m_tokenPlaceHolder++;
01458                             break;
01459                      }
01460                      m_tokenPlaceHolder++;
01461               }
01462     m_searchCriteriaString = PL_strdup(saveTokenPlaceHolder);
01463               if (*m_tokenPlaceHolder == '\0')
01464                      m_tokenPlaceHolder = NULL;
01465 
01466               if (*m_searchCriteriaString == '\0')
01467                      m_searchCriteriaString = (char *)NULL;
01468        }
01469        else
01470               m_searchCriteriaString = (char *)NULL;
01471   if (!m_searchCriteriaString)
01472               m_validUrl = PR_FALSE;
01473 }
01474 
01475 
01476 void nsImapUrl::ParseUidChoice()
01477 {
01478        char *uidChoiceString = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
01479        if (!uidChoiceString)
01480               m_validUrl = PR_FALSE;
01481        else
01482     m_idsAreUids = nsCRT::strcmp(uidChoiceString, "UID") == 0;
01483 }
01484 
01485 void nsImapUrl::ParseMsgFlags()
01486 {
01487        char *flagsPtr = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
01488        if (flagsPtr)
01489        {
01490               // the url is encodes the flags byte as ascii 
01491               int intFlags = atoi(flagsPtr);
01492               m_flags = (imapMessageFlagsType) intFlags;       // cast here 
01493        }
01494        else
01495               m_flags = 0;
01496 }
01497 
01498 void nsImapUrl::ParseListOfMessageIds()
01499 {
01500   m_listOfMessageIds = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
01501   if (!m_listOfMessageIds)
01502     m_validUrl = PR_FALSE;
01503   else
01504   {
01505     m_listOfMessageIds = strdup(m_listOfMessageIds);
01506     m_mimePartSelectorDetected = PL_strstr(m_listOfMessageIds, "&part=") != 0 || PL_strstr(m_listOfMessageIds, "?part=") != 0;
01507     
01508     // if we're asking for just the body, don't download the whole message. see
01509     // nsMsgQuote::QuoteMessage() for the "header=" settings when replying to msgs.
01510     if (!m_fetchPartsOnDemand)
01511       m_fetchPartsOnDemand = (PL_strstr(m_listOfMessageIds, "?header=quotebody") != 0 || 
01512       PL_strstr(m_listOfMessageIds, "?header=only") != 0);
01513     // if it's a spam filter trying to fetch the msg, don't let it get marked read.
01514     if (PL_strstr(m_listOfMessageIds,"?header=filter") != 0)
01515       m_imapAction = nsImapMsgFetchPeek;
01516   }
01517 }
01518 
01519 void nsImapUrl::ParseCustomMsgFetchAttribute()
01520 {
01521   m_msgFetchAttribute = m_tokenPlaceHolder ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nsnull;
01522 }
01523 
01524 void nsImapUrl::ParseNumBytes()
01525 {
01526   const char *numBytes = (m_tokenPlaceHolder) ? nsCRT::strtok(m_tokenPlaceHolder, IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : 0;
01527   m_numBytesToFetch = numBytes ? atoi(numBytes) : 0;
01528 }
01529 
01530 // nsIMsgI18NUrl support
01531 
01532 nsresult nsImapUrl::GetMsgFolder(nsIMsgFolder **msgFolder)
01533 {
01534   // if we have a RDF URI, then try to get the folder for that URI and then ask the folder
01535   // for it's charset....
01536 
01537   nsXPIDLCString uri;
01538   GetUri(getter_Copies(uri));
01539   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
01540 
01541   nsCOMPtr<nsIMsgDBHdr> msg; 
01542   GetMsgDBHdrFromURI(uri, getter_AddRefs(msg));
01543   NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
01544   nsresult rv = msg->GetFolder(msgFolder);
01545   NS_ENSURE_SUCCESS(rv,rv);
01546   NS_ENSURE_TRUE(msgFolder, NS_ERROR_FAILURE);
01547 
01548   return NS_OK;
01549 }
01550 
01551 NS_IMETHODIMP nsImapUrl::GetFolderCharset(char ** aCharacterSet)
01552 {
01553   nsCOMPtr<nsIMsgFolder> folder;
01554   nsresult rv = GetMsgFolder(getter_AddRefs(folder));
01555   NS_ENSURE_SUCCESS(rv,rv);
01556   NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
01557   folder->GetCharset(aCharacterSet);
01558   return NS_OK;
01559 }
01560 
01561 NS_IMETHODIMP nsImapUrl::GetFolderCharsetOverride(PRBool * aCharacterSetOverride)
01562 {
01563   nsCOMPtr<nsIMsgFolder> folder;
01564   nsresult rv = GetMsgFolder(getter_AddRefs(folder));
01565   NS_ENSURE_SUCCESS(rv,rv);
01566   NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
01567   folder->GetCharsetOverride(aCharacterSetOverride);
01568   return NS_OK;
01569 }
01570 
01571 NS_IMETHODIMP nsImapUrl::GetCharsetOverRide(char ** aCharacterSet)
01572 {
01573   if (!mCharsetOverride.IsEmpty())
01574     *aCharacterSet = ToNewCString(mCharsetOverride); 
01575   else
01576     *aCharacterSet = nsnull;
01577   return NS_OK;
01578 }
01579 
01580 NS_IMETHODIMP nsImapUrl::SetCharsetOverRide(const char * aCharacterSet)
01581 {
01582   mCharsetOverride = aCharacterSet;
01583   return NS_OK;
01584 }
01585 
01586 NS_IMETHODIMP nsImapUrl::GetShouldStoreMsgOffline(PRBool *aShouldStoreMsgOffline)
01587 {
01588   NS_ENSURE_ARG_POINTER(aShouldStoreMsgOffline);
01589   *aShouldStoreMsgOffline = m_shouldStoreMsgOffline;
01590   return NS_OK;
01591 }
01592 
01593 NS_IMETHODIMP nsImapUrl::SetShouldStoreMsgOffline(PRBool aShouldStoreMsgOffline)
01594 {
01595   m_shouldStoreMsgOffline = aShouldStoreMsgOffline;
01596   return NS_OK;
01597 }
01598 
01599 NS_IMETHODIMP nsImapUrl::GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)
01600 {
01601   nsXPIDLCString uri;
01602   nsresult rv = GetUri(getter_Copies(uri));
01603   NS_ENSURE_SUCCESS(rv, rv);
01604   return GetMsgDBHdrFromURI(uri.get(), aMsgHdr);
01605 }
01606