Back to index

lightning-sunbird  0.9+nobinonly
nsImapService.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) 1998
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 #include "nsMsgImapCID.h"
00041 
00042 #include "netCore.h"
00043 
00044 #include "nsIServiceManager.h"
00045 #include "nsIComponentManager.h"
00046 
00047 #include "nsIIMAPHostSessionList.h"
00048 #include "nsImapService.h"
00049 #include "nsImapUrl.h"
00050 #include "nsCOMPtr.h"
00051 #include "nsIMsgFolder.h"
00052 #include "nsIMsgImapMailFolder.h"
00053 #include "nsIImapIncomingServer.h"
00054 #include "nsIImapServerSink.h"
00055 #include "nsIImapMockChannel.h"
00056 #include "nsImapUtils.h"
00057 #include "nsIDocShell.h"
00058 #include "nsIDocShellLoadInfo.h"
00059 #include "nsIRDFService.h"
00060 #include "nsIEventQueueService.h"
00061 #include "nsXPIDLString.h"
00062 #include "nsReadableUtils.h"
00063 #include "nsRDFCID.h"
00064 #include "nsEscape.h"
00065 #include "nsIMsgStatusFeedback.h"
00066 #include "nsIPrefBranch.h"
00067 #include "nsIPrefService.h"
00068 #include "nsILoadGroup.h"
00069 #include "nsIMsgAccountManager.h"
00070 #include "nsMsgBaseCID.h"
00071 #include "nsMsgFolderFlags.h"
00072 #include "nsISubscribableServer.h"
00073 #include "nsIDirectoryService.h"
00074 #include "nsAppDirectoryServiceDefs.h"
00075 #include "nsIWebNavigation.h"
00076 #include "nsImapStringBundle.h"
00077 #include "plbase64.h"
00078 #include "nsImapOfflineSync.h"
00079 #include "nsIMsgHdr.h"
00080 #include "nsMsgUtils.h"
00081 #include "nsICacheService.h"
00082 #include "nsIStreamListenerTee.h"
00083 #include "nsNetCID.h"
00084 #include "nsMsgI18N.h"
00085 #include "nsIOutputStream.h"
00086 #include "nsIInputStream.h"
00087 #include "nsICopyMsgStreamListener.h"
00088 #include "nsIFileStream.h"
00089 #include "nsIMsgParseMailMsgState.h"
00090 #include "nsMsgLocalCID.h"
00091 #include "nsIOutputStream.h"
00092 #include "nsIDocShell.h"
00093 #include "nsIDocShellLoadInfo.h"
00094 #include "nsIDOMWindowInternal.h"
00095 #include "nsIMessengerWindowService.h"
00096 #include "nsIWindowMediator.h"
00097 #include "nsIPrompt.h"
00098 #include "nsIWindowWatcher.h"
00099 #include "nsImapProtocol.h"
00100 #include "nsIMsgMailSession.h"
00101 #include "nsIStreamConverterService.h"
00102 #include "nsNetUtil.h"
00103 #include "nsInt64.h"
00104 
00105 #define PREF_MAIL_ROOT_IMAP "mail.root.imap"            // old - for backward compatibility only
00106 #define PREF_MAIL_ROOT_IMAP_REL "mail.root.imap-rel"
00107 
00108 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00109 static NS_DEFINE_CID(kImapUrlCID, NS_IMAPURL_CID);
00110 static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
00111 
00112 
00113 static const char sequenceString[] = "SEQUENCE";
00114 static const char uidString[] = "UID";
00115 
00116 static PRBool gInitialized = PR_FALSE;
00117 static PRInt32 gMIMEOnDemandThreshold = 15000;
00118 static PRBool gMIMEOnDemand = PR_FALSE;
00119 
00120 NS_IMPL_THREADSAFE_ADDREF(nsImapService)
00121 NS_IMPL_THREADSAFE_RELEASE(nsImapService)
00122 NS_IMPL_QUERY_INTERFACE6(nsImapService,
00123                          nsIImapService,
00124                          nsIMsgMessageService,
00125                          nsIProtocolHandler,
00126                          nsIMsgProtocolInfo,
00127                          nsIMsgMessageFetchPartService,
00128                          nsIContentHandler)
00129 
00130 nsImapService::nsImapService()
00131 {
00132   mPrintingOperation = PR_FALSE;
00133   if (!gInitialized)
00134   {
00135     nsresult rv;
00136     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); 
00137     if (NS_SUCCEEDED(rv) && prefBranch) 
00138     {
00139       prefBranch->GetBoolPref("mail.imap.mime_parts_on_demand", &gMIMEOnDemand);
00140       prefBranch->GetIntPref("mail.imap.mime_parts_on_demand_threshold", &gMIMEOnDemandThreshold);
00141     }
00142     gInitialized = PR_TRUE;
00143   }
00144 }
00145 
00146 nsImapService::~nsImapService()
00147 {
00148 }
00149 
00150 PRUnichar nsImapService::GetHierarchyDelimiter(nsIMsgFolder* aMsgFolder)
00151 {
00152   PRUnichar delimiter = '/';
00153   if (aMsgFolder)
00154   {
00155     nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aMsgFolder);
00156     if (imapFolder)
00157       imapFolder->GetHierarchyDelimiter(&delimiter);
00158   }
00159   return delimiter;
00160 }
00161 
00162 // N.B., this returns an escaped folder name, appropriate for putting in a url.
00163 nsresult
00164 nsImapService::GetFolderName(nsIMsgFolder* aImapFolder,
00165                              char **folderName)
00166 {
00167   nsresult rv;
00168   nsCOMPtr<nsIMsgImapMailFolder> aFolder(do_QueryInterface(aImapFolder, &rv));
00169   if (NS_FAILED(rv)) return rv;
00170   nsXPIDLCString onlineName;
00171   // online name is in imap utf-7 - leave it that way
00172   rv = aFolder->GetOnlineName(getter_Copies(onlineName));
00173   
00174   if (NS_FAILED(rv)) return rv;
00175   if (onlineName.IsEmpty())
00176   {
00177     char *uri = nsnull;
00178     rv = aImapFolder->GetURI(&uri);
00179     if (NS_FAILED(rv)) return rv;
00180     char * hostname = nsnull;
00181     rv = aImapFolder->GetHostname(&hostname);
00182     if (NS_FAILED(rv)) return rv;
00183     rv = nsImapURI2FullName(kImapRootURI, hostname, uri, getter_Copies(onlineName));
00184     PR_Free(uri);
00185     PR_Free(hostname);
00186   }
00187   // if the hierarchy delimiter is not '/', then we want to escape slashes;
00188   // otherwise, we do want to escape slashes.
00189   // we want to escape slashes and '^' first, otherwise, nsEscape will lose them
00190   PRBool escapeSlashes = (GetHierarchyDelimiter(aImapFolder) != (PRUnichar) '/');
00191   if (escapeSlashes && (const char *) onlineName)
00192   {
00193     char* escapedOnlineName;
00194     rv = nsImapUrl::EscapeSlashes((const char *) onlineName, &escapedOnlineName);
00195     if (NS_SUCCEEDED(rv))
00196       onlineName.Adopt(escapedOnlineName);
00197   }
00198   // need to escape everything else
00199   *folderName = nsEscape((const char *) onlineName, url_Path);
00200   return rv;
00201 }
00202 
00203 NS_IMETHODIMP
00204 nsImapService::SelectFolder(nsIEventQueue * aClientEventQueue, 
00205                             nsIMsgFolder * aImapMailFolder, 
00206                             nsIUrlListener * aUrlListener, 
00207                             nsIMsgWindow *aMsgWindow,
00208                             nsIURI ** aURL)
00209 {
00210   NS_ASSERTION (aImapMailFolder && aClientEventQueue,
00211     "Oops ... null pointer");
00212   if (!aImapMailFolder || !aClientEventQueue)
00213     return NS_ERROR_NULL_POINTER;
00214   
00215   if (WeAreOffline())
00216     return NS_MSG_ERROR_OFFLINE;
00217   
00218   PRBool canOpenThisFolder = PR_TRUE;
00219   nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aImapMailFolder);
00220   if (imapFolder)
00221     imapFolder->GetCanIOpenThisFolder(&canOpenThisFolder);
00222   
00223   if (!canOpenThisFolder) 
00224     return NS_OK;
00225   
00226   nsCOMPtr<nsIImapUrl> imapUrl;
00227   nsCAutoString urlSpec;
00228   nsresult rv;
00229   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
00230   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator);
00231   
00232   if (NS_SUCCEEDED(rv) && imapUrl)
00233   {
00234     // nsImapUrl::SetSpec() will set the imap action properly
00235     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapSelectFolder);
00236     
00237     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
00238     // if no msg window, we won't put up error messages (this is almost certainly a biff-inspired get new msgs)
00239     if (!aMsgWindow)
00240       mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE);
00241     mailNewsUrl->SetMsgWindow(aMsgWindow);
00242     mailNewsUrl->SetUpdatingFolder(PR_TRUE);
00243     imapUrl->AddChannelToLoadGroup();
00244     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
00245     
00246     if (NS_SUCCEEDED(rv))
00247     {
00248       nsXPIDLCString folderName;
00249       GetFolderName(aImapMailFolder, getter_Copies(folderName));
00250       urlSpec.Append("/select>");
00251       urlSpec.Append(char(hierarchySeparator));
00252       urlSpec.Append((const char *) folderName);
00253       rv = mailNewsUrl->SetSpec(urlSpec);
00254       if (NS_SUCCEEDED(rv))
00255         rv = GetImapConnectionAndLoadUrl(aClientEventQueue,
00256         imapUrl,
00257         nsnull,
00258         aURL);
00259     }
00260   } // if we have a url to run....
00261   
00262   return rv;
00263 }
00264 
00265 // lite select, used to verify UIDVALIDITY while going on/offline
00266 NS_IMETHODIMP
00267 nsImapService::LiteSelectFolder(nsIEventQueue * aClientEventQueue, 
00268                                 nsIMsgFolder * aImapMailFolder, 
00269                                 nsIUrlListener * aUrlListener, 
00270                                 nsIURI ** aURL)
00271 {
00272     return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
00273                       "/liteselect>", nsIImapUrl::nsImapLiteSelectFolder, aURL);
00274 
00275 }
00276 
00277 NS_IMETHODIMP nsImapService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL, nsIMsgWindow *aMsgWindow) 
00278 {
00279   nsresult rv = NS_OK;
00280 
00281   if (PL_strstr(aMessageURI, "&type=application/x-message-display"))
00282     return NS_NewURI(aURL, aMessageURI);
00283 
00284 
00285   nsCOMPtr<nsIMsgFolder> folder;
00286   nsXPIDLCString msgKey;
00287   rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
00288   if (NS_SUCCEEDED(rv))
00289   {
00290     nsCOMPtr<nsIImapUrl> imapUrl;
00291     nsCAutoString urlSpec;
00292     PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00293     rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, nsnull, urlSpec, hierarchySeparator);
00294     NS_ENSURE_SUCCESS(rv, rv);
00295     rv = SetImapUrlSink(folder, imapUrl);
00296     NS_ENSURE_SUCCESS(rv, rv);
00297     nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(imapUrl);
00298     PRBool useLocalCache = PR_FALSE;
00299     folder->HasMsgOffline(atoi(msgKey), &useLocalCache);
00300     mailnewsUrl->SetMsgIsInLocalCache(useLocalCache);
00301 
00302     nsCOMPtr<nsIURI> url = do_QueryInterface(imapUrl);
00303     url->GetSpec(urlSpec);
00304     urlSpec.Append("fetch>UID>");
00305     urlSpec.Append(char(hierarchySeparator));
00306 
00307     nsXPIDLCString folderName;
00308     GetFolderName(folder, getter_Copies(folderName));
00309     urlSpec.Append((const char *) folderName);
00310     urlSpec.Append(">");
00311     urlSpec.Append(msgKey);
00312     rv = url->SetSpec(urlSpec);
00313     imapUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) aURL);
00314   }
00315 
00316   return rv;
00317 }
00318 
00319 NS_IMETHODIMP nsImapService::OpenAttachment(const char *aContentType, 
00320                                             const char *aFileName,
00321                                             const char *aUrl, 
00322                                             const char *aMessageUri, 
00323                                             nsISupports *aDisplayConsumer, 
00324                                             nsIMsgWindow *aMsgWindow, 
00325                                             nsIUrlListener *aUrlListener)
00326 {
00327   nsresult rv = NS_OK;
00328   // okay this is a little tricky....we may have to fetch the mime part
00329   // or it may already be downloaded for us....the only way i can tell to 
00330   // distinguish the two events is to search for ?section or ?part
00331   
00332   nsCAutoString uri(aMessageUri);
00333   nsCAutoString urlString(aUrl);
00334   urlString.ReplaceSubstring("/;section", "?section");
00335   
00336   // more stuff i don't understand
00337   PRInt32 sectionPos = urlString.Find("?section");
00338   // if we have a section field then we must be dealing with a mime part we need to fetchf
00339   if (sectionPos > 0)
00340   {
00341     nsCAutoString mimePart;
00342     
00343     urlString.Right(mimePart, urlString.Length() - sectionPos); 
00344     uri.Append(mimePart);
00345     uri += "&type=";
00346     uri += aContentType;
00347     uri += "&filename=";
00348     uri += aFileName;
00349   }
00350   else
00351   {
00352     // try to extract the specific part number out from the url string
00353     uri += "?";
00354     const char *part = PL_strstr(aUrl, "part=");
00355     uri += part;
00356     uri += "&type=";
00357     uri += aContentType;
00358     uri += "&filename=";
00359     uri += aFileName;
00360   }
00361   
00362   nsCOMPtr<nsIMsgFolder> folder;
00363   nsXPIDLCString msgKey;
00364   nsXPIDLCString uriMimePart;
00365   nsCAutoString      folderURI;
00366   nsMsgKey key;
00367   
00368   rv = DecomposeImapURI(uri.get(), getter_AddRefs(folder), getter_Copies(msgKey));
00369   rv = nsParseImapMessageURI(uri.get(), folderURI, &key, getter_Copies(uriMimePart));
00370   if (NS_SUCCEEDED(rv))
00371   {
00372     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00373     if (NS_SUCCEEDED(rv))
00374     {
00375       nsCOMPtr<nsIImapUrl> imapUrl;
00376       nsCAutoString urlSpec;
00377       PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00378       rv = CreateStartOfImapUrl(uri.get(), getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
00379       if (NS_FAILED(rv)) 
00380         return rv;
00381     
00382       urlSpec.Append("/fetch>UID>");
00383       urlSpec.Append(char(hierarchySeparator));
00384     
00385       nsXPIDLCString folderName;
00386       GetFolderName(folder, getter_Copies(folderName));
00387       urlSpec.Append((const char *) folderName);
00388       urlSpec.Append(">");
00389       urlSpec.Append(msgKey.get());
00390       urlSpec.Append(uriMimePart.get());
00391       
00392       if (uriMimePart)
00393       {
00394         nsCOMPtr<nsIMsgMailNewsUrl> mailUrl (do_QueryInterface(imapUrl));
00395         if (mailUrl)
00396         {
00397           mailUrl->SetSpec(urlSpec);
00398           mailUrl->SetFileName(nsDependentCString(aFileName));
00399         }
00400         rv =  FetchMimePart(imapUrl, nsIImapUrl::nsImapOpenMimePart, folder, imapMessageSink,
00401           nsnull, aDisplayConsumer, msgKey, uriMimePart);
00402       }
00403     } // if we got a message sink
00404   } // if we parsed the message uri
00405   
00406   return rv;
00407 }
00408 
00409 NS_IMETHODIMP nsImapService::FetchMimePart(nsIURI *aURI, const char *aMessageURI, nsISupports *aDisplayConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIURI **aURL)
00410 {
00411   nsresult rv = NS_OK;
00412   nsCOMPtr<nsIMsgFolder> folder;
00413   nsXPIDLCString msgKey;
00414   nsXPIDLCString mimePart;
00415   nsCAutoString      folderURI;
00416   nsMsgKey key;
00417   
00418   rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
00419   rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart));
00420   if (NS_SUCCEEDED(rv))
00421   {
00422     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00423     if (NS_SUCCEEDED(rv))
00424     {
00425       nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aURI);
00426       nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(aURI));
00427       
00428       msgurl->SetMsgWindow(aMsgWindow);
00429       msgurl->RegisterListener(aUrlListener);
00430       
00431       if (mimePart)
00432       {
00433         return FetchMimePart(imapUrl, nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink,
00434           aURL, aDisplayConsumer, msgKey, mimePart);
00435       }
00436     }
00437   }
00438   return rv;
00439 }
00440 
00441 NS_IMETHODIMP nsImapService::DisplayMessage(const char* aMessageURI,
00442                                             nsISupports * aDisplayConsumer,  
00443                                             nsIMsgWindow * aMsgWindow,
00444                                             nsIUrlListener * aUrlListener,
00445                                             const char * aCharsetOverride,
00446                                             nsIURI ** aURL)
00447 {
00448   nsresult rv = NS_OK;
00449   nsCOMPtr<nsIMsgFolder> folder;
00450   nsXPIDLCString msgKey;
00451   nsXPIDLCString mimePart;
00452   nsCAutoString      folderURI;
00453   nsMsgKey key;
00454   nsCAutoString messageURI(aMessageURI);
00455 
00456   PRInt32 typeIndex = messageURI.Find("&type=application/x-message-display");
00457   if (typeIndex != kNotFound)
00458   {
00459     // This happens with forward inline of a message/rfc822 attachment opened in
00460     // a standalone msg window.
00461     // So, just cut to the chase and call AsyncOpen on a channel.
00462     nsCOMPtr <nsIURI> uri;
00463     messageURI.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
00464     rv = NS_NewURI(getter_AddRefs(uri), messageURI.get());
00465     NS_ENSURE_SUCCESS(rv, rv);
00466     if (aURL)
00467       NS_IF_ADDREF(*aURL = uri);
00468     nsCOMPtr<nsIStreamListener> aStreamListener = do_QueryInterface(aDisplayConsumer, &rv);
00469     if (NS_SUCCEEDED(rv) && aStreamListener)
00470     {
00471       nsCOMPtr<nsIChannel> aChannel;
00472       nsCOMPtr<nsILoadGroup> aLoadGroup;
00473       nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(uri, &rv);
00474       if (NS_SUCCEEDED(rv) && mailnewsUrl)
00475         mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup));
00476       
00477       rv = NewChannel(uri, getter_AddRefs(aChannel));
00478       if (NS_FAILED(rv)) return rv;
00479       
00480       nsCOMPtr<nsISupports> aCtxt = do_QueryInterface(uri);
00481       //  now try to open the channel passing in our display consumer as the listener
00482       return aChannel->AsyncOpen(aStreamListener, aCtxt);
00483     }
00484   }
00485   rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
00486   if (msgKey.IsEmpty())
00487     return NS_MSG_MESSAGE_NOT_FOUND;
00488   rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart));
00489   if (NS_SUCCEEDED(rv))
00490   {
00491     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00492     if (NS_SUCCEEDED(rv))
00493     {
00494       nsCOMPtr<nsIImapUrl> imapUrl;
00495       nsCAutoString urlSpec;
00496       PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00497       rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
00498       if (NS_FAILED(rv)) 
00499         return rv;
00500       if (mimePart)
00501       {
00502         return FetchMimePart(imapUrl, nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink,
00503           aURL, aDisplayConsumer, msgKey, mimePart);
00504       }
00505       
00506       nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(imapUrl));
00507       nsCOMPtr<nsIMsgI18NUrl> i18nurl (do_QueryInterface(imapUrl));
00508       i18nurl->SetCharsetOverRide(aCharsetOverride);
00509       
00510       PRUint32 messageSize;
00511       PRBool useMimePartsOnDemand = gMIMEOnDemand;
00512       PRBool shouldStoreMsgOffline = PR_FALSE;
00513       PRBool hasMsgOffline = PR_FALSE;
00514       
00515       nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
00516       
00517       if (imapMessageSink)
00518         imapMessageSink->GetMessageSizeFromDB(msgKey, PR_TRUE, &messageSize);
00519       
00520       msgurl->SetMsgWindow(aMsgWindow);
00521       
00522       rv = msgurl->GetServer(getter_AddRefs(aMsgIncomingServer));
00523       
00524       if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
00525       {
00526         nsCOMPtr<nsIImapIncomingServer>
00527           aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
00528         if (NS_SUCCEEDED(rv) && aImapServer)
00529           aImapServer->GetMimePartsOnDemand(&useMimePartsOnDemand);
00530       }
00531       
00532       nsCAutoString uriStr(aMessageURI);
00533       PRInt32 keySeparator = uriStr.RFindChar('#');
00534       if(keySeparator != -1)
00535       {
00536         PRInt32 keyEndSeparator = uriStr.FindCharInSet("/?&", 
00537           keySeparator); 
00538         PRInt32 mpodFetchPos = uriStr.Find("fetchCompleteMessage=true", PR_FALSE, keyEndSeparator);
00539         if (mpodFetchPos != -1)
00540           useMimePartsOnDemand = PR_FALSE;
00541       }
00542       
00543       if (folder)
00544       {
00545         folder->ShouldStoreMsgOffline(key, &shouldStoreMsgOffline);
00546         folder->HasMsgOffline(key, &hasMsgOffline);
00547       }
00548       
00549       if (!useMimePartsOnDemand || (messageSize < (uint32) gMIMEOnDemandThreshold))
00550         //                allowedToBreakApart && 
00551         //              !GetShouldFetchAllParts() &&
00552         //            GetServerStateParser().ServerHasIMAP4Rev1Capability() &&
00553       {
00554         imapUrl->SetFetchPartsOnDemand(PR_FALSE);
00555         // for now, lets try not adding these 
00556         msgurl->SetAddToMemoryCache(PR_TRUE);
00557       }
00558       else
00559       {
00560         // whenever we are displaying a message, we want to add it to the memory cache..
00561         imapUrl->SetFetchPartsOnDemand(PR_TRUE);
00562         // if we happen to fetch the whole message, note in the url
00563         // whether we want to store this message offline.
00564         imapUrl->SetShouldStoreMsgOffline(shouldStoreMsgOffline);
00565         shouldStoreMsgOffline = PR_FALSE; // if we're fetching by parts, don't store offline
00566         msgurl->SetAddToMemoryCache(PR_FALSE);
00567       }
00568       if (imapMessageSink && !hasMsgOffline)
00569         imapMessageSink->SetNotifyDownloadedLines(shouldStoreMsgOffline);
00570       
00571       if (hasMsgOffline)
00572         msgurl->SetMsgIsInLocalCache(PR_TRUE);
00573       
00574       nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); 
00575       PRBool forcePeek = PR_FALSE; // should the message fetch force a peak or a traditional fetch? 
00576 
00577       if (NS_SUCCEEDED(rv) && prefBranch) 
00578          prefBranch->GetBoolPref("mailnews.mark_message_read.delay", &forcePeek);
00579       
00580       rv = FetchMessage(imapUrl, forcePeek ? nsIImapUrl::nsImapMsgFetchPeek : nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink,
00581         aMsgWindow, aDisplayConsumer, msgKey, PR_FALSE, (mPrintingOperation) ? "print" : nsnull, aURL);
00582     }
00583   }
00584   return rv;
00585 }
00586 
00587 
00588 nsresult nsImapService::FetchMimePart(nsIImapUrl * aImapUrl,
00589                                       nsImapAction aImapAction,
00590                                       nsIMsgFolder * aImapMailFolder, 
00591                                       nsIImapMessageSink * aImapMessage,
00592                                       nsIURI ** aURL,
00593                                       nsISupports * aDisplayConsumer, 
00594                                       const char *messageIdentifierList,
00595                                       const char *mimePart) 
00596 {
00597   nsresult rv = NS_OK;
00598   
00599   // create a protocol instance to handle the request.
00600   // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now
00601   // just create a connection and process the request.
00602   NS_ASSERTION (aImapUrl && aImapMailFolder &&  aImapMessage,"Oops ... null pointer");
00603   if (!aImapUrl || !aImapMailFolder || !aImapMessage)
00604     return NS_ERROR_NULL_POINTER;
00605   
00606   nsCAutoString urlSpec;
00607   rv = SetImapUrlSink(aImapMailFolder, aImapUrl);
00608   nsImapAction actionToUse = aImapAction;
00609   if (actionToUse == nsImapUrl::nsImapOpenMimePart)
00610     actionToUse = nsIImapUrl::nsImapMsgFetch;
00611   
00612   nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(aImapUrl));
00613   if (aImapMailFolder && msgurl && messageIdentifierList)
00614   {
00615     PRBool useLocalCache = PR_FALSE;
00616     aImapMailFolder->HasMsgOffline(atoi(messageIdentifierList), &useLocalCache);  
00617     msgurl->SetMsgIsInLocalCache(useLocalCache);
00618   }
00619   rv = aImapUrl->SetImapMessageSink(aImapMessage);
00620   if (NS_SUCCEEDED(rv))
00621   {
00622     nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl);
00623     url->GetSpec(urlSpec);
00624     
00625     // rhp: If we are displaying this message for the purpose of printing, we
00626     // need to append the header=print option.
00627     //
00628     if (mPrintingOperation)
00629       urlSpec.Append("?header=print");
00630     
00631     // mscott - this cast to a char * is okay...there's a bug in the XPIDL
00632     // compiler that is preventing in string parameters from showing up as
00633     // const char *. hopefully they will fix it soon.
00634     rv = url->SetSpec(urlSpec);
00635     
00636     rv = aImapUrl->SetImapAction(actionToUse /* nsIImapUrl::nsImapMsgFetch */);
00637     if (aImapMailFolder && aDisplayConsumer)
00638     {
00639       nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
00640       rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer));
00641       if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
00642       {
00643         PRBool interrupted;
00644         nsCOMPtr<nsIImapIncomingServer>
00645           aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
00646         if (NS_SUCCEEDED(rv) && aImapServer)
00647           aImapServer->PseudoInterruptMsgLoad(aImapMailFolder, nsnull, &interrupted);
00648       }
00649     }
00650     // if the display consumer is a docshell, then we should run the url in the docshell.
00651     // otherwise, it should be a stream listener....so open a channel using AsyncRead
00652     // and the provided stream listener....
00653     
00654     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
00655     if (NS_SUCCEEDED(rv) && docShell)
00656     {
00657       nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
00658       // DIRTY LITTLE HACK --> if we are opening an attachment we want the docshell to
00659       // treat this load as if it were a user click event. Then the dispatching stuff will be much
00660       // happier.
00661       if (aImapAction == nsImapUrl::nsImapOpenMimePart)
00662       {
00663         docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
00664         loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink);
00665       }
00666       
00667       rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
00668     }
00669     else
00670     {
00671       nsCOMPtr<nsIStreamListener> aStreamListener = do_QueryInterface(aDisplayConsumer, &rv);
00672       if (NS_SUCCEEDED(rv) && aStreamListener)
00673       {
00674         nsCOMPtr<nsIChannel> aChannel;
00675        nsCOMPtr<nsILoadGroup> aLoadGroup;
00676         nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl, &rv);
00677         if (NS_SUCCEEDED(rv) && mailnewsUrl)
00678           mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup));
00679         
00680         rv = NewChannel(url, getter_AddRefs(aChannel));
00681         if (NS_FAILED(rv)) return rv;
00682         
00683         nsCOMPtr<nsISupports> aCtxt = do_QueryInterface(url);
00684         //  now try to open the channel passing in our display consumer as the listener
00685         rv = aChannel->AsyncOpen(aStreamListener, aCtxt);
00686       }
00687       else // do what we used to do before
00688       {
00689         // I'd like to get rid of this code as I believe that we always get a docshell
00690         // or stream listener passed into us in this method but i'm not sure yet...
00691         // I'm going to use an assert for now to figure out if this is ever getting called
00692 #if defined(DEBUG_mscott) || defined(DEBUG_bienvenu)
00693         NS_ASSERTION(0, "oops...someone still is reaching this part of the code");
00694 #endif
00695         nsCOMPtr<nsIEventQueue> queue;    
00696         // get the Event Queue for this thread...
00697         nsCOMPtr<nsIEventQueueService> pEventQService = 
00698           do_GetService(kEventQueueServiceCID, &rv);
00699         
00700         if (NS_FAILED(rv)) return rv;
00701         
00702         rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
00703         if (NS_FAILED(rv)) return rv;
00704         rv = GetImapConnectionAndLoadUrl(queue, aImapUrl, aDisplayConsumer, aURL);
00705       }
00706     }
00707   }
00708   return rv;
00709 }
00710 
00711 //
00712 // rhp: Right now, this is the same as simple DisplayMessage, but it will change
00713 // to support print rendering.
00714 //
00715 NS_IMETHODIMP nsImapService::DisplayMessageForPrinting(const char* aMessageURI,
00716                                                         nsISupports * aDisplayConsumer,  
00717                                                         nsIMsgWindow * aMsgWindow,
00718                                                         nsIUrlListener * aUrlListener,
00719                                                         nsIURI ** aURL) 
00720 {
00721   mPrintingOperation = PR_TRUE;
00722   nsresult rv = DisplayMessage(aMessageURI, aDisplayConsumer, aMsgWindow, aUrlListener, nsnull, aURL);
00723   mPrintingOperation = PR_FALSE;
00724   return rv;
00725 }
00726 
00727 NS_IMETHODIMP
00728 nsImapService::CopyMessage(const char * aSrcMailboxURI, nsIStreamListener *
00729                            aMailboxCopy, PRBool moveMessage,
00730                            nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL)
00731 {
00732   nsresult rv = NS_ERROR_NULL_POINTER;
00733   nsCOMPtr<nsISupports> streamSupport;
00734   if (!aSrcMailboxURI || !aMailboxCopy) return rv;
00735   streamSupport = do_QueryInterface(aMailboxCopy, &rv);
00736   if (NS_FAILED(rv)) return rv;
00737   
00738   nsCOMPtr<nsIMsgFolder> folder;
00739   nsXPIDLCString msgKey;
00740   rv = DecomposeImapURI(aSrcMailboxURI, getter_AddRefs(folder), getter_Copies(msgKey));
00741   if (NS_SUCCEEDED(rv))
00742   {
00743     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00744     if (NS_SUCCEEDED(rv))
00745     {
00746       nsCOMPtr<nsIImapUrl> imapUrl;
00747       nsCAutoString urlSpec;
00748       PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00749       PRBool hasMsgOffline = PR_FALSE;
00750       nsMsgKey key = atoi(msgKey);
00751       
00752       rv = CreateStartOfImapUrl(aSrcMailboxURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
00753       
00754       if (folder)
00755       {
00756         nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(imapUrl));
00757         folder->HasMsgOffline(key, &hasMsgOffline);
00758         if (msgurl)
00759           msgurl->SetMsgIsInLocalCache(hasMsgOffline);
00760       }
00761       // now try to download the message
00762       nsImapAction imapAction = nsIImapUrl::nsImapOnlineToOfflineCopy;
00763       if (moveMessage)
00764         imapAction = nsIImapUrl::nsImapOnlineToOfflineMove; 
00765       rv = FetchMessage(imapUrl,imapAction, folder, imapMessageSink,aMsgWindow, streamSupport, msgKey, PR_FALSE, nsnull, aURL);
00766     } // if we got an imap message sink
00767   } // if we decomposed the imap message 
00768   return rv;
00769 }
00770 
00771 NS_IMETHODIMP
00772 nsImapService::CopyMessages(nsMsgKeyArray *keys, nsIMsgFolder *srcFolder, nsIStreamListener *aMailboxCopy, PRBool moveMessage,
00773                             nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL)
00774 {
00775   nsresult rv = NS_OK;
00776   nsCOMPtr<nsISupports> streamSupport;
00777   if (!keys || !aMailboxCopy) 
00778     return NS_ERROR_NULL_POINTER;
00779   streamSupport = do_QueryInterface(aMailboxCopy, &rv);
00780   if (!streamSupport || NS_FAILED(rv)) return rv;
00781   
00782   nsCOMPtr<nsIMsgFolder> folder = srcFolder;
00783   nsXPIDLCString msgKey;
00784   if (NS_SUCCEEDED(rv))
00785   {
00786     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00787     if (NS_SUCCEEDED(rv))
00788     {
00789       // we generate the uri for the first message so that way on down the line,
00790       // GetMessage in nsCopyMessageStreamListener will get an unescaped username
00791       // and be able to find the msg hdr. See bug 259656 for details
00792       nsXPIDLCString uri;
00793       srcFolder->GenerateMessageURI(keys->GetAt(0), getter_Copies(uri));
00794 
00795       nsCString messageIds;
00796       PRUint32 numKeys = keys->GetSize();
00797       AllocateImapUidString(keys->GetArray(), numKeys, nsnull, messageIds);
00798       nsCOMPtr<nsIImapUrl> imapUrl;
00799       nsCAutoString urlSpec;
00800       PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00801       rv = CreateStartOfImapUrl(uri, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
00802       nsImapAction action;
00803       if (moveMessage)
00804         action = nsIImapUrl::nsImapOnlineToOfflineMove;
00805       else
00806         action = nsIImapUrl::nsImapOnlineToOfflineCopy;
00807       imapUrl->SetCopyState(aMailboxCopy);
00808       // now try to display the message
00809       rv = FetchMessage(imapUrl, action, folder, imapMessageSink,
00810         aMsgWindow, streamSupport, messageIds.get(), PR_FALSE, nsnull, aURL);
00811       // ### end of copy operation should know how to do the delete.if this is a move
00812       
00813     } // if we got an imap message sink
00814   } // if we decomposed the imap message 
00815   return rv;
00816 }
00817 
00818 NS_IMETHODIMP nsImapService::Search(nsIMsgSearchSession *aSearchSession, nsIMsgWindow *aMsgWindow, nsIMsgFolder *aMsgFolder, const char *aSearchUri)
00819 {
00820   nsresult rv = NS_OK;
00821   nsCAutoString      folderURI;
00822 
00823   nsCOMPtr<nsIImapUrl> imapUrl;
00824   nsCOMPtr <nsIUrlListener> urlListener = do_QueryInterface(aSearchSession);
00825 
00826   nsCAutoString urlSpec;
00827   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aMsgFolder);
00828   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aMsgFolder, urlListener, urlSpec, hierarchySeparator);
00829   if (NS_FAILED(rv)) 
00830         return rv;
00831   nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(imapUrl));
00832 
00833   msgurl->SetMsgWindow(aMsgWindow);
00834   msgurl->SetSearchSession(aSearchSession);
00835   imapUrl->AddChannelToLoadGroup();
00836   rv = SetImapUrlSink(aMsgFolder, imapUrl);
00837 
00838   if (NS_SUCCEEDED(rv))
00839   {
00840     nsXPIDLCString folderName;
00841     GetFolderName(aMsgFolder, getter_Copies(folderName));
00842 
00843     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
00844     if (!aMsgWindow)
00845       mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE);
00846 
00847     urlSpec.Append("/search>UID>");
00848     urlSpec.Append(char(hierarchySeparator));
00849     urlSpec.Append((const char *) folderName);
00850     urlSpec.Append('>');
00851     // escape aSearchUri so that IMAP special characters (i.e. '\')
00852     // won't be replaced with '/' in NECKO.
00853     // it will be unescaped in nsImapUrl::ParseUrl().
00854     char *search_cmd = nsEscape((char *)aSearchUri, url_XAlphas);
00855     urlSpec.Append(search_cmd);
00856     nsCRT::free(search_cmd);
00857     rv = mailNewsUrl->SetSpec(urlSpec);
00858     if (NS_SUCCEEDED(rv))
00859     {
00860       nsCOMPtr<nsIEventQueue> queue;      
00861       // get the Event Queue for this thread...
00862       nsCOMPtr<nsIEventQueueService> pEventQService = 
00863           do_GetService(kEventQueueServiceCID, &rv);
00864 
00865       if (NS_FAILED(rv)) return rv;
00866 
00867       rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
00868       if (NS_FAILED(rv)) return rv;
00869         rv = GetImapConnectionAndLoadUrl(queue, imapUrl, nsnull, nsnull);
00870     }
00871   }
00872   return rv;
00873 }
00874 
00875 // just a helper method to break down imap message URIs....
00876 nsresult nsImapService::DecomposeImapURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey)
00877 {
00878     NS_ENSURE_ARG_POINTER(aMessageURI);
00879     NS_ENSURE_ARG_POINTER(aFolder);
00880     NS_ENSURE_ARG_POINTER(aMsgKey);
00881 
00882     nsresult rv = NS_OK;
00883     nsCAutoString folderURI;
00884     rv = nsParseImapMessageURI(aMessageURI, folderURI, aMsgKey, nsnull);
00885     NS_ENSURE_SUCCESS(rv,rv);
00886 
00887     nsCOMPtr <nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1",&rv);
00888     NS_ENSURE_SUCCESS(rv,rv);
00889 
00890     nsCOMPtr<nsIRDFResource> res;
00891     rv = rdf->GetResource(folderURI, getter_AddRefs(res));
00892     NS_ENSURE_SUCCESS(rv,rv);
00893 
00894     rv = res->QueryInterface(NS_GET_IID(nsIMsgFolder), (void **) aFolder);
00895     NS_ENSURE_SUCCESS(rv,rv);
00896 
00897     return NS_OK;
00898 }
00899 
00900 // just a helper method to break down imap message URIs....
00901 nsresult nsImapService::DecomposeImapURI(const char * aMessageURI, nsIMsgFolder ** aFolder, char ** aMsgKey)
00902 {
00903     nsMsgKey msgKey;
00904     nsresult rv;
00905     rv = DecomposeImapURI(aMessageURI, aFolder, &msgKey);
00906     NS_ENSURE_SUCCESS(rv,rv);
00907 
00908     if (msgKey) {
00909       nsCAutoString messageIdString;
00910       messageIdString.AppendInt(msgKey);
00911       *aMsgKey = ToNewCString(messageIdString);
00912     }
00913 
00914     return rv;
00915 }
00916 
00917 NS_IMETHODIMP nsImapService::SaveMessageToDisk(const char *aMessageURI, 
00918                                                nsIFileSpec *aFile, 
00919                                                PRBool aAddDummyEnvelope, 
00920                                                nsIUrlListener *aUrlListener, 
00921                                                nsIURI **aURL,
00922                                                PRBool canonicalLineEnding,
00923                                                                                 nsIMsgWindow *aMsgWindow)
00924 {
00925     nsresult rv = NS_OK;
00926     nsCOMPtr<nsIMsgFolder> folder;
00927     nsCOMPtr<nsIImapUrl> imapUrl;
00928     nsXPIDLCString msgKey;
00929 
00930     rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
00931     if (NS_FAILED(rv)) return rv;
00932     
00933     PRBool hasMsgOffline = PR_FALSE;
00934 
00935     if (folder)
00936       folder->HasMsgOffline(atoi(msgKey), &hasMsgOffline);
00937 
00938     nsCAutoString urlSpec;
00939     PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
00940     rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
00941     if (NS_SUCCEEDED(rv)) 
00942     {
00943         nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
00944         if (NS_FAILED(rv)) return rv;
00945         nsCOMPtr<nsIMsgMessageUrl> msgUrl = do_QueryInterface(imapUrl, &rv);
00946         if (NS_FAILED(rv)) return rv;
00947         msgUrl->SetMessageFile(aFile);
00948         msgUrl->SetAddDummyEnvelope(aAddDummyEnvelope);
00949         msgUrl->SetCanonicalLineEnding(canonicalLineEnding);
00950 
00951         nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(msgUrl);
00952         if (mailnewsUrl)
00953           mailnewsUrl->SetMsgIsInLocalCache(hasMsgOffline);
00954 
00955         nsCOMPtr <nsIStreamListener> saveAsListener;
00956         mailnewsUrl->GetSaveAsListener(aAddDummyEnvelope, aFile, getter_AddRefs(saveAsListener));
00957         
00958         return FetchMessage(imapUrl, nsIImapUrl::nsImapSaveMessageToDisk, folder, imapMessageSink, aMsgWindow, saveAsListener, msgKey, PR_FALSE, nsnull, aURL);
00959     }
00960 
00961   return rv;
00962 }
00963 
00964 /* fetching RFC822 messages */
00965 /* imap4://HOST>fetch><UID>>MAILBOXPATH>x */
00966 /*   'x' is the message UID */
00967 /* will set the 'SEEN' flag */
00968 
00969 NS_IMETHODIMP
00970 nsImapService::FetchMessage(nsIImapUrl * aImapUrl,
00971                             nsImapAction aImapAction,
00972                             nsIMsgFolder * aImapMailFolder, 
00973                             nsIImapMessageSink * aImapMessage,
00974                             nsIMsgWindow *aMsgWindow,
00975                             nsISupports * aDisplayConsumer, 
00976                             const char *messageIdentifierList,
00977                             PRBool aConvertDataToText,
00978                             const char *aAdditionalHeader,
00979                             nsIURI ** aURL)
00980 {
00981   // create a protocol instance to handle the request.
00982   NS_ASSERTION (aImapUrl && aImapMailFolder &&  aImapMessage,"Oops ... null pointer");
00983   if (!aImapUrl || !aImapMailFolder || !aImapMessage)
00984       return NS_ERROR_NULL_POINTER;
00985 
00986   nsresult rv = NS_OK;
00987   nsCOMPtr<nsIURI> url = do_QueryInterface(aImapUrl);
00988   if (WeAreOffline())
00989   {
00990     nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(aImapUrl));
00991     if (msgurl)
00992     {
00993       PRBool msgIsInLocalCache = PR_FALSE;
00994       msgurl->GetMsgIsInLocalCache(&msgIsInLocalCache);
00995       if (!msgIsInLocalCache)
00996       {
00997         nsCOMPtr<nsIMsgIncomingServer> server;
00998 
00999         rv = aImapMailFolder->GetServer(getter_AddRefs(server));
01000         if (server && aDisplayConsumer)
01001           rv = server->DisplayOfflineMsg(aMsgWindow);
01002         return rv;
01003       }
01004     }
01005   }
01006 
01007   if (aURL)
01008   {
01009     *aURL = url;
01010     NS_IF_ADDREF(*aURL);
01011   }
01012   nsCAutoString urlSpec;
01013   rv = SetImapUrlSink(aImapMailFolder, aImapUrl);
01014 
01015   rv = aImapUrl->SetImapMessageSink(aImapMessage);
01016   url->GetSpec(urlSpec);
01017 
01018   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); 
01019 
01020   urlSpec.Append("fetch>UID>");
01021   urlSpec.Append(char(hierarchySeparator));
01022 
01023   nsXPIDLCString folderName;
01024   GetFolderName(aImapMailFolder, getter_Copies(folderName));
01025   urlSpec.Append((const char *) folderName);
01026   urlSpec.Append(">");
01027   urlSpec.Append(messageIdentifierList);
01028 
01029   if (aAdditionalHeader)
01030   {
01031     urlSpec.Append("?header=");
01032     urlSpec.Append(aAdditionalHeader);
01033   }
01034 
01035   rv = url->SetSpec(urlSpec);
01036 
01037   rv = aImapUrl->SetImapAction(aImapAction);
01038   // if the display consumer is a docshell, then we should run the url in the docshell.
01039   // otherwise, it should be a stream listener....so open a channel using AsyncRead
01040   // and the provided stream listener....
01041 
01042   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aDisplayConsumer, &rv));
01043   if (aImapMailFolder && docShell)
01044   {
01045     nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
01046     rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer));
01047     if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
01048     {
01049       PRBool interrupted;
01050       nsCOMPtr<nsIImapIncomingServer>
01051         aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
01052       if (NS_SUCCEEDED(rv) && aImapServer)
01053         aImapServer->PseudoInterruptMsgLoad(aImapMailFolder, aMsgWindow, &interrupted);
01054     }
01055   }
01056   if (NS_SUCCEEDED(rv) && docShell)
01057   {
01058     NS_ASSERTION(!aConvertDataToText, "can't convert to text when using docshell");
01059     rv = docShell->LoadURI(url, nsnull, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
01060   }
01061   else
01062   {
01063     nsCOMPtr<nsIStreamListener> streamListener = do_QueryInterface(aDisplayConsumer, &rv);
01064     nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl, &rv);
01065     if (aMsgWindow && mailnewsUrl)
01066       mailnewsUrl->SetMsgWindow(aMsgWindow);
01067     if (NS_SUCCEEDED(rv) && streamListener)
01068     {
01069       nsCOMPtr<nsIChannel> channel;
01070       nsCOMPtr<nsILoadGroup> loadGroup;
01071       if (NS_SUCCEEDED(rv) && mailnewsUrl)
01072         mailnewsUrl->GetLoadGroup(getter_AddRefs(loadGroup));
01073 
01074       rv = NewChannel(url, getter_AddRefs(channel));
01075       if (NS_FAILED(rv)) return rv;
01076 
01077       rv = channel->SetLoadGroup(loadGroup);
01078       if (NS_FAILED(rv)) return rv;
01079 
01080       if (aConvertDataToText)
01081       {
01082         nsCOMPtr<nsIStreamListener> conversionListener;
01083         nsCOMPtr<nsIStreamConverterService> streamConverter = do_GetService("@mozilla.org/streamConverters;1", &rv);
01084         NS_ENSURE_SUCCESS(rv, rv);
01085         rv = streamConverter->AsyncConvertData("message/rfc822",
01086                                                "*/*",
01087                                                streamListener, channel, getter_AddRefs(conversionListener));
01088         NS_ENSURE_SUCCESS(rv, rv);
01089         streamListener = conversionListener; // this is our new listener.
01090       }
01091       nsCOMPtr<nsISupports> aCtxt = do_QueryInterface(url);
01092       //  now try to open the channel passing in our display consumer as the listener 
01093       rv = channel->AsyncOpen(streamListener, aCtxt);
01094     }
01095     else // do what we used to do before
01096     {
01097       // I'd like to get rid of this code as I believe that we always get a docshell
01098       // or stream listener passed into us in this method but i'm not sure yet...
01099       // I'm going to use an assert for now to figure out if this is ever getting called
01100 #if defined(DEBUG_mscott) || defined(DEBUG_bienvenu)
01101       NS_ASSERTION(0, "oops...someone still is reaching this part of the code");
01102 #endif
01103       nsCOMPtr<nsIEventQueue> queue;      
01104       // get the Event Queue for this thread...
01105            nsCOMPtr<nsIEventQueueService> pEventQService = 
01106                     do_GetService(kEventQueueServiceCID, &rv);
01107 
01108       if (NS_FAILED(rv)) return rv;
01109 
01110       rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
01111       if (NS_FAILED(rv)) return rv;
01112       rv = GetImapConnectionAndLoadUrl(queue, aImapUrl, aDisplayConsumer, aURL);
01113     }
01114   }
01115   return rv;
01116 }
01117 
01118 // this method streams a message to the passed in consumer, with an optional stream converter
01119 // and additional header (e.g., "header=filter")
01120 NS_IMETHODIMP
01121 nsImapService::StreamMessage(const char *aMessageURI, nsISupports *aConsumer, 
01122                                    nsIMsgWindow *aMsgWindow,
01123                                    nsIUrlListener *aUrlListener, 
01124                                         PRBool aConvertData,
01125                                         const char *aAdditionalHeader,
01126                                    nsIURI **aURL)
01127 {
01128   nsCOMPtr<nsIMsgFolder> folder;
01129   nsXPIDLCString msgKey;
01130   nsXPIDLCString mimePart;
01131   nsCAutoString      folderURI;
01132   nsMsgKey key;
01133   
01134   nsresult rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
01135   if (msgKey.IsEmpty())
01136     return NS_MSG_MESSAGE_NOT_FOUND;
01137   rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart));
01138   if (NS_SUCCEEDED(rv))
01139   {
01140     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(folder, &rv));
01141     if (NS_SUCCEEDED(rv))
01142     {
01143       nsCOMPtr<nsIImapUrl> imapUrl;
01144       nsCAutoString urlSpec;
01145       PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
01146       rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator);
01147       if (NS_FAILED(rv)) 
01148         return rv;
01149       nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(imapUrl));
01150       
01151       PRBool shouldStoreMsgOffline = PR_FALSE;
01152       PRBool hasMsgOffline = PR_FALSE;
01153       
01154       nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
01155       
01156       msgurl->SetMsgWindow(aMsgWindow);
01157       
01158       rv = msgurl->GetServer(getter_AddRefs(aMsgIncomingServer));
01159       
01160       if (folder)
01161       {
01162         folder->ShouldStoreMsgOffline(key, &shouldStoreMsgOffline);
01163         folder->HasMsgOffline(key, &hasMsgOffline);
01164       }
01165       
01166       imapUrl->SetFetchPartsOnDemand(PR_FALSE);
01167       msgurl->SetAddToMemoryCache(PR_TRUE);
01168       if (imapMessageSink)
01169         imapMessageSink->SetNotifyDownloadedLines(shouldStoreMsgOffline);
01170       
01171       if (hasMsgOffline)
01172         msgurl->SetMsgIsInLocalCache(PR_TRUE);
01173       
01174       rv = FetchMessage(imapUrl, nsIImapUrl::nsImapMsgFetchPeek, folder, imapMessageSink,
01175         aMsgWindow, aConsumer, msgKey, aConvertData, aAdditionalHeader, aURL);
01176     }
01177   }
01178   return rv;
01179 }
01180 
01181 nsresult 
01182 nsImapService::CreateStartOfImapUrl(const char * aImapURI, nsIImapUrl ** imapUrl,
01183                                     nsIMsgFolder* aImapMailFolder,
01184                                     nsIUrlListener * aUrlListener,
01185                                     nsCString & urlSpec, 
01186                                     PRUnichar &hierarchyDelimiter)
01187 {
01188   nsresult rv = NS_OK;
01189   char *hostname = nsnull;
01190   nsXPIDLCString username;
01191   nsXPIDLCString escapedUsername;
01192   
01193   rv = aImapMailFolder->GetHostname(&hostname);
01194   if (NS_FAILED(rv)) return rv;
01195   rv = aImapMailFolder->GetUsername(getter_Copies(username));
01196   if (NS_FAILED(rv))
01197   {
01198     PR_Free(hostname);
01199     return rv;
01200   }
01201   
01202   if (((const char*)username) && username[0])
01203     *((char **)getter_Copies(escapedUsername)) = nsEscape(username, url_XAlphas);
01204   
01205   PRInt32 port = IMAP_PORT;
01206   nsCOMPtr<nsIMsgIncomingServer> server;
01207   rv = aImapMailFolder->GetServer(getter_AddRefs(server));
01208   if (NS_SUCCEEDED(rv)) 
01209   {
01210     server->GetPort(&port);
01211     if (port == -1 || port == 0) port = IMAP_PORT;
01212   }
01213   
01214   // now we need to create an imap url to load into the connection. The url
01215   // needs to represent a select folder action. 
01216   rv = CallCreateInstance(kImapUrlCID, imapUrl);
01217   if (NS_SUCCEEDED(rv) && *imapUrl)
01218   {
01219     nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(*imapUrl, &rv);
01220     if (NS_SUCCEEDED(rv) && mailnewsUrl && aUrlListener)
01221       mailnewsUrl->RegisterListener(aUrlListener);
01222     nsCOMPtr<nsIMsgMessageUrl> msgurl(do_QueryInterface(*imapUrl));
01223     (*imapUrl)->SetExternalLinkUrl(PR_FALSE);
01224     msgurl->SetUri(aImapURI);
01225     
01226     urlSpec = "imap://";
01227     urlSpec.Append((const char *) escapedUsername);
01228     urlSpec.Append('@');
01229     urlSpec.Append(hostname);
01230     urlSpec.Append(':');
01231     
01232     urlSpec.AppendInt(port);
01233     
01234     // *** jefft - force to parse the urlSpec in order to search for
01235     // the correct incoming server
01236     // mscott - this cast to a char * is okay...there's a bug in the XPIDL
01237     // compiler that is preventing in string parameters from showing up as
01238     // const char *. hopefully they will fix it soon.
01239     rv = mailnewsUrl->SetSpec(urlSpec);
01240     
01241     hierarchyDelimiter = kOnlineHierarchySeparatorUnknown;
01242     nsCOMPtr <nsIMsgImapMailFolder> imapFolder = do_QueryInterface(aImapMailFolder);
01243     if (imapFolder)
01244       imapFolder->GetHierarchyDelimiter(&hierarchyDelimiter);
01245   }
01246   
01247   PR_Free(hostname);
01248   return rv;
01249 }
01250 
01251 /* fetching the headers of RFC822 messages */
01252 /* imap4://HOST>header><UID/SEQUENCE>>MAILBOXPATH>x */
01253 /*   'x' is the message UID or sequence number list */
01254 /* will not affect the 'SEEN' flag */
01255 NS_IMETHODIMP
01256 nsImapService::GetHeaders(nsIEventQueue * aClientEventQueue, 
01257                           nsIMsgFolder * aImapMailFolder, 
01258                           nsIUrlListener * aUrlListener, 
01259                           nsIURI ** aURL,
01260                           const char *messageIdentifierList,
01261                           PRBool messageIdsAreUID)
01262 {
01263   // create a protocol instance to handle the request.
01264   // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now
01265   // just create a connection and process the request.
01266   NS_ASSERTION (aImapMailFolder && aClientEventQueue,
01267     "Oops ... null pointer");
01268   if (!aImapMailFolder || !aClientEventQueue)
01269     return NS_ERROR_NULL_POINTER;
01270   
01271   nsCOMPtr<nsIImapUrl> imapUrl;
01272   nsCAutoString urlSpec;
01273   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01274   
01275   nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator);
01276   if (NS_SUCCEEDED(rv) && imapUrl)
01277   {
01278     nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01279     
01280     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch);
01281     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01282     
01283     if (NS_SUCCEEDED(rv))
01284     {
01285       
01286       urlSpec.Append("/header>");
01287       urlSpec.Append(messageIdsAreUID ? uidString : sequenceString);
01288       urlSpec.Append(">");
01289       urlSpec.Append(char (hierarchySeparator));
01290       
01291       nsXPIDLCString folderName;
01292       
01293       GetFolderName(aImapMailFolder, getter_Copies(folderName));
01294       urlSpec.Append((const char *) folderName);
01295       urlSpec.Append(">");
01296       urlSpec.Append(messageIdentifierList);
01297       rv = uri->SetSpec(urlSpec);
01298       
01299       if (NS_SUCCEEDED(rv))
01300         rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01301         nsnull, aURL);
01302       
01303     }
01304   }
01305   return rv;
01306 }
01307 
01308 
01309 /* peeking at the start of msg bodies */
01310 /* imap4://HOST>header><UID>>MAILBOXPATH>x>n */
01311 /*   'x' is the message UID */
01312 /*   'n' is the number of bytes to fetch */
01313 /* will not affect the 'SEEN' flag */
01314 NS_IMETHODIMP
01315 nsImapService::GetBodyStart(nsIEventQueue * aClientEventQueue, 
01316                           nsIMsgFolder * aImapMailFolder, 
01317                           nsIUrlListener * aUrlListener, 
01318                           const char *messageIdentifierList,
01319                           PRInt32 numBytes,
01320                           nsIURI ** aURL)
01321 {
01322   nsresult rv;
01323   NS_ASSERTION (aImapMailFolder && aClientEventQueue,
01324     "Oops ... null pointer");
01325   if (!aImapMailFolder || !aClientEventQueue)
01326     return NS_ERROR_NULL_POINTER;
01327   
01328   nsCOMPtr<nsIImapUrl> imapUrl;
01329   nsCAutoString urlSpec;
01330 
01331   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01332   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01333     aImapMailFolder,
01334     aUrlListener, urlSpec, hierarchySeparator);
01335   if (NS_SUCCEEDED(rv) && imapUrl)
01336   {
01337     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgPreview);
01338     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01339     
01340     if (NS_SUCCEEDED(rv))
01341     {
01342       nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01343       
01344       urlSpec.Append("/previewBody>");
01345       urlSpec.Append(uidString);
01346       urlSpec.Append(">");
01347       urlSpec.Append(char (hierarchySeparator));
01348       
01349       nsXPIDLCString folderName;
01350       
01351       GetFolderName(aImapMailFolder, getter_Copies(folderName));
01352       urlSpec.Append((const char *) folderName);
01353       urlSpec.Append(">");
01354       urlSpec.Append(messageIdentifierList);
01355       urlSpec.Append(">");
01356       urlSpec.AppendInt(numBytes);
01357       rv = uri->SetSpec(urlSpec);
01358       if (NS_SUCCEEDED(rv))
01359         rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01360         nsnull, aURL);
01361     }
01362   }
01363   return rv;
01364 }
01365 
01366 nsresult nsImapService::FolderCommand(nsIEventQueue * clientEventQueue, 
01367                                       nsIMsgFolder * imapMailFolder,
01368                                       nsIUrlListener * urlListener,
01369                                       const char *command,
01370                                       nsImapAction imapAction,
01371                                       nsIURI ** url)
01372 {
01373   NS_ASSERTION (imapMailFolder && clientEventQueue,
01374     "Oops ... null pointer");
01375   if (!imapMailFolder || !clientEventQueue)
01376     return NS_ERROR_NULL_POINTER;
01377   
01378   nsCOMPtr<nsIImapUrl> imapUrl;
01379   nsCAutoString urlSpec;
01380   
01381   PRUnichar hierarchySeparator = GetHierarchyDelimiter(imapMailFolder);
01382   nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01383     imapMailFolder,
01384     urlListener, urlSpec, hierarchySeparator);
01385   if (NS_SUCCEEDED(rv) && imapUrl)
01386   {
01387     
01388     rv = imapUrl->SetImapAction(imapAction);
01389     rv = SetImapUrlSink(imapMailFolder, imapUrl);
01390     nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01391     
01392     if (NS_SUCCEEDED(rv))
01393     {
01394       urlSpec.Append(command);
01395       urlSpec.Append(char (hierarchySeparator));
01396       
01397       nsXPIDLCString folderName;
01398       
01399       GetFolderName(imapMailFolder, getter_Copies(folderName));
01400       urlSpec.Append((const char *) folderName);
01401       rv = uri->SetSpec(urlSpec);
01402       if (NS_SUCCEEDED(rv))
01403         rv = GetImapConnectionAndLoadUrl(clientEventQueue, imapUrl,
01404         nsnull, url);
01405     }
01406   }
01407   return rv;
01408 }
01409 
01410 // Noop, used to update a folder (causes server to send changes).
01411 NS_IMETHODIMP
01412 nsImapService::Noop(nsIEventQueue * aClientEventQueue, 
01413                                   nsIMsgFolder * aImapMailFolder,
01414                                   nsIUrlListener * aUrlListener, 
01415                                   nsIURI ** aURL)
01416 {
01417   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
01418                       "/selectnoop>", nsIImapUrl::nsImapSelectNoopFolder, aURL);
01419 }
01420     
01421 // FolderStatus, used to update message counts
01422 NS_IMETHODIMP
01423 nsImapService::UpdateFolderStatus(nsIEventQueue * aClientEventQueue, 
01424                                   nsIMsgFolder * aImapMailFolder,
01425                                   nsIUrlListener * aUrlListener, 
01426                                   nsIURI ** aURL)
01427 {
01428   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
01429                       "/folderstatus>", nsIImapUrl::nsImapFolderStatus, aURL);
01430 }
01431 
01432 // Expunge, used to "compress" an imap folder,removes deleted messages.
01433 NS_IMETHODIMP
01434 nsImapService::Expunge(nsIEventQueue * aClientEventQueue, 
01435                        nsIMsgFolder * aImapMailFolder,
01436                        nsIUrlListener * aUrlListener, 
01437                        nsIURI ** aURL)
01438 {
01439   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
01440                       "/Expunge>", nsIImapUrl::nsImapExpungeFolder, aURL);
01441 }
01442 
01443 /* old-stle biff that doesn't download headers */
01444 NS_IMETHODIMP
01445 nsImapService::Biff(nsIEventQueue * aClientEventQueue, 
01446                     nsIMsgFolder * aImapMailFolder,
01447                     nsIUrlListener * aUrlListener, 
01448                     nsIURI ** aURL,
01449                     PRUint32 uidHighWater)
01450 {
01451   // static const char *formatString = "biff>%c%s>%ld";
01452        
01453     NS_ASSERTION (aImapMailFolder && aClientEventQueue,
01454                   "Oops ... null pointer");
01455     if (!aImapMailFolder || !aClientEventQueue)
01456         return NS_ERROR_NULL_POINTER;
01457 
01458        nsCOMPtr<nsIImapUrl> imapUrl;
01459        nsCAutoString urlSpec;
01460 
01461        PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01462        nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01463                                           aImapMailFolder,
01464                                           aUrlListener, urlSpec, hierarchySeparator);
01465        if (NS_SUCCEEDED(rv) && imapUrl)
01466        {
01467 
01468               rv = imapUrl->SetImapAction(nsIImapUrl::nsImapExpungeFolder);
01469         rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01470         
01471         nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01472 
01473               if (NS_SUCCEEDED(rv))
01474               {
01475                      urlSpec.Append("/Biff>");
01476                      urlSpec.Append(char(hierarchySeparator));
01477 
01478             nsXPIDLCString folderName;
01479             GetFolderName(aImapMailFolder, getter_Copies(folderName));
01480             urlSpec.Append((const char *) folderName);
01481                      urlSpec.Append(">");
01482                      urlSpec.AppendInt(uidHighWater);
01483                      rv = uri->SetSpec(urlSpec);
01484             if (NS_SUCCEEDED(rv))
01485                 rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01486                                                  nsnull, aURL);
01487               }
01488        }
01489        return rv;
01490 }
01491 
01492 NS_IMETHODIMP
01493 nsImapService::DeleteFolder(nsIEventQueue* aClientEventQueue,
01494                             nsIMsgFolder* aImapMailFolder,
01495                             nsIUrlListener* aUrlListener,
01496                             nsIURI** aURL)
01497 {
01498 
01499     // If it's an aol server then use 'deletefolder' url to 
01500     // remove all msgs first and then remove the folder itself.
01501     PRBool removeFolderAndMsgs = PR_FALSE;
01502     nsCOMPtr<nsIMsgIncomingServer> server;
01503     if (NS_SUCCEEDED(aImapMailFolder->GetServer(getter_AddRefs(server))) && server)
01504     {
01505       nsCOMPtr <nsIImapIncomingServer> imapServer = do_QueryInterface(server);
01506       if (imapServer) 
01507         imapServer->GetIsAOLServer(&removeFolderAndMsgs);
01508     }
01509 
01510     return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
01511                           removeFolderAndMsgs ? "/deletefolder>": "/delete>", 
01512                           nsIImapUrl::nsImapDeleteFolder, aURL);
01513 
01514 }
01515 
01516 NS_IMETHODIMP
01517 nsImapService::DeleteMessages(nsIEventQueue * aClientEventQueue, 
01518                               nsIMsgFolder * aImapMailFolder, 
01519                               nsIUrlListener * aUrlListener, 
01520                               nsIURI ** aURL,
01521                               const char *messageIdentifierList,
01522                               PRBool messageIdsAreUID)
01523 {
01524   nsresult rv;
01525   // create a protocol instance to handle the request.
01526   // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now
01527   // just create a connection and process the request.
01528   NS_ASSERTION (aImapMailFolder && aClientEventQueue,
01529     "Oops ... null pointer");
01530   if (!aImapMailFolder || !aClientEventQueue)
01531     return NS_ERROR_NULL_POINTER;
01532   
01533   nsCOMPtr<nsIImapUrl> imapUrl;
01534   nsCAutoString urlSpec;
01535 
01536   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01537   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01538     aImapMailFolder,
01539     aUrlListener, urlSpec, hierarchySeparator);
01540   if (NS_SUCCEEDED(rv) && imapUrl)
01541   {
01542     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch);
01543     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01544     
01545     if (NS_SUCCEEDED(rv))
01546     {
01547       nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01548       
01549       urlSpec.Append("/deletemsg>");
01550       urlSpec.Append(messageIdsAreUID ? uidString : sequenceString);
01551       urlSpec.Append(">");
01552       urlSpec.Append(char (hierarchySeparator));
01553       
01554       nsXPIDLCString folderName;
01555       
01556       GetFolderName(aImapMailFolder, getter_Copies(folderName));
01557       urlSpec.Append((const char *) folderName);
01558       urlSpec.Append(">");
01559       urlSpec.Append(messageIdentifierList);
01560       rv = uri->SetSpec(urlSpec);
01561       if (NS_SUCCEEDED(rv))
01562         rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01563         nsnull, aURL);
01564       
01565     }
01566   }
01567   return rv;
01568 }
01569 
01570 // Delete all messages in a folder, used to empty trash
01571 NS_IMETHODIMP
01572 nsImapService::DeleteAllMessages(nsIEventQueue * aClientEventQueue, 
01573                                  nsIMsgFolder * aImapMailFolder,
01574                                  nsIUrlListener * aUrlListener, 
01575                                  nsIURI ** aURL)
01576 {
01577   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
01578                       "/deleteallmsgs>", nsIImapUrl::nsImapSelectNoopFolder, aURL);
01579 }
01580 
01581 NS_IMETHODIMP
01582 nsImapService::AddMessageFlags(nsIEventQueue * aClientEventQueue,
01583                                nsIMsgFolder * aImapMailFolder, 
01584                                nsIUrlListener * aUrlListener, 
01585                                nsIURI ** aURL,
01586                                const char *messageIdentifierList,
01587                                imapMessageFlagsType flags,
01588                                PRBool messageIdsAreUID)
01589 {
01590   return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
01591                     "addmsgflags", flags, messageIdsAreUID);
01592 }
01593 
01594 NS_IMETHODIMP
01595 nsImapService::SubtractMessageFlags(nsIEventQueue * aClientEventQueue,
01596                                     nsIMsgFolder * aImapMailFolder, 
01597                                     nsIUrlListener * aUrlListener, 
01598                                     nsIURI ** aURL,
01599                                     const char *messageIdentifierList,
01600                                     imapMessageFlagsType flags,
01601                                     PRBool messageIdsAreUID)
01602 {
01603   return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
01604                     "subtractmsgflags", flags, messageIdsAreUID);
01605 }
01606 
01607 NS_IMETHODIMP
01608 nsImapService::SetMessageFlags(nsIEventQueue * aClientEventQueue,
01609                                nsIMsgFolder * aImapMailFolder, 
01610                                nsIUrlListener * aUrlListener, 
01611                                nsIURI ** aURL,
01612                                const char *messageIdentifierList,
01613                                imapMessageFlagsType flags,
01614                                PRBool messageIdsAreUID)
01615 {
01616   return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList,
01617                     "setmsgflags", flags, messageIdsAreUID);
01618 }
01619 
01620 nsresult nsImapService::DiddleFlags(nsIEventQueue * aClientEventQueue, 
01621                                     nsIMsgFolder * aImapMailFolder, 
01622                                     nsIUrlListener * aUrlListener,
01623                                     nsIURI ** aURL,
01624                                     const char *messageIdentifierList,
01625                                     const char *howToDiddle,
01626                                     imapMessageFlagsType flags,
01627                                     PRBool messageIdsAreUID)
01628 {
01629   // create a protocol instance to handle the request.
01630   // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now
01631   // just create a connection and process the request.
01632   NS_ASSERTION (aImapMailFolder && aClientEventQueue,
01633     "Oops ... null pointer");
01634   if (!aImapMailFolder || !aClientEventQueue)
01635     return NS_ERROR_NULL_POINTER;
01636   
01637   nsCOMPtr<nsIImapUrl> imapUrl;
01638   nsCAutoString urlSpec;
01639   
01640   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01641   nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01642     aImapMailFolder,
01643     aUrlListener, urlSpec, hierarchySeparator); 
01644   if (NS_SUCCEEDED(rv) && imapUrl)
01645   {
01646     
01647     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch);
01648     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01649     
01650     if (NS_SUCCEEDED(rv))
01651     {
01652       nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01653       
01654       urlSpec.Append('/');
01655       urlSpec.Append(howToDiddle);
01656       urlSpec.Append('>');
01657       urlSpec.Append(messageIdsAreUID ? uidString : sequenceString);
01658       urlSpec.Append(">");
01659       urlSpec.Append(char(hierarchySeparator));
01660       nsXPIDLCString folderName;
01661       GetFolderName(aImapMailFolder, getter_Copies(folderName));
01662       urlSpec.Append((const char *) folderName);
01663       urlSpec.Append(">");
01664       urlSpec.Append(messageIdentifierList);
01665       urlSpec.Append('>');
01666       urlSpec.AppendInt(flags);
01667       rv = uri->SetSpec(urlSpec);
01668       if (NS_SUCCEEDED(rv))
01669         rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01670         nsnull, aURL);
01671     }
01672   }
01673   return rv;
01674 }
01675 
01676 nsresult
01677 nsImapService::SetImapUrlSink(nsIMsgFolder* aMsgFolder,
01678                                 nsIImapUrl* aImapUrl)
01679 {
01680   nsresult rv = NS_ERROR_NULL_POINTER;
01681   nsISupports* aInst = nsnull;
01682   nsCOMPtr <nsIMsgIncomingServer> incomingServer;
01683   nsCOMPtr <nsIImapServerSink> imapServerSink;
01684 
01685   NS_ASSERTION (aMsgFolder && aImapUrl, "Oops ... null pointers");
01686   if (!aMsgFolder || !aImapUrl)
01687       return rv;
01688     
01689   rv = aMsgFolder->GetServer(getter_AddRefs(incomingServer));
01690   if (NS_SUCCEEDED(rv) && incomingServer)
01691   {
01692     imapServerSink = do_QueryInterface(incomingServer);
01693     if (imapServerSink)
01694       aImapUrl->SetImapServerSink(imapServerSink);
01695   }
01696    
01697   rv = aMsgFolder->QueryInterface(NS_GET_IID(nsIImapMailFolderSink), 
01698                                  (void**)&aInst);
01699   if (NS_SUCCEEDED(rv) && aInst)
01700       aImapUrl->SetImapMailFolderSink((nsIImapMailFolderSink*) aInst);
01701   NS_IF_RELEASE (aInst);
01702   aInst = nsnull;
01703   
01704   rv = aMsgFolder->QueryInterface(NS_GET_IID(nsIImapMessageSink), 
01705                                  (void**)&aInst);
01706   if (NS_SUCCEEDED(rv) && aInst)
01707       aImapUrl->SetImapMessageSink((nsIImapMessageSink*) aInst);
01708   NS_IF_RELEASE (aInst);
01709   aInst = nsnull;
01710   
01711   nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl);
01712   mailnewsUrl->SetFolder(aMsgFolder);
01713 
01714   return NS_OK;
01715 }
01716 
01717 NS_IMETHODIMP
01718 nsImapService::DiscoverAllFolders(nsIEventQueue* aClientEventQueue,
01719                                   nsIMsgFolder* aImapMailFolder,
01720                                   nsIUrlListener* aUrlListener,
01721                                   nsIMsgWindow *  aMsgWindow,
01722                                   nsIURI** aURL)
01723 {
01724   NS_ASSERTION (aImapMailFolder && aClientEventQueue, 
01725                 "Oops ... null aClientEventQueue or aImapMailFolder");
01726   if (!aImapMailFolder || ! aClientEventQueue)
01727       return NS_ERROR_NULL_POINTER;
01728   
01729   nsCOMPtr<nsIImapUrl> imapUrl;
01730   nsCAutoString urlSpec;
01731 
01732   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01733   nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),
01734                                      aImapMailFolder,
01735                                      aUrlListener, urlSpec, hierarchySeparator);
01736   if (NS_SUCCEEDED (rv))
01737   {
01738     rv = SetImapUrlSink(aImapMailFolder, imapUrl);
01739 
01740     if (NS_SUCCEEDED(rv))
01741     {
01742       nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01743       nsCOMPtr<nsIMsgMailNewsUrl> mailnewsurl = do_QueryInterface(imapUrl);
01744       if (mailnewsurl)
01745         mailnewsurl->SetMsgWindow(aMsgWindow);
01746       urlSpec.Append("/discoverallboxes");
01747       nsCOMPtr <nsIURI> url = do_QueryInterface(imapUrl, &rv);
01748                 rv = uri->SetSpec(urlSpec);
01749       if (NS_SUCCEEDED(rv))
01750          rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01751                                           nsnull, aURL);
01752     }
01753   }
01754   return rv;
01755 }
01756 
01757 NS_IMETHODIMP
01758 nsImapService::DiscoverAllAndSubscribedFolders(nsIEventQueue* aClientEventQueue,
01759                                               nsIMsgFolder* aImapMailFolder,
01760                                               nsIUrlListener* aUrlListener,
01761                                               nsIURI** aURL)
01762 {
01763     NS_ASSERTION (aImapMailFolder && aClientEventQueue, 
01764                   "Oops ... null aClientEventQueue or aImapMailFolder");
01765     if (!aImapMailFolder || ! aClientEventQueue)
01766         return NS_ERROR_NULL_POINTER;
01767     
01768     nsCOMPtr<nsIImapUrl> aImapUrl;
01769     nsCAutoString urlSpec;
01770 
01771     PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01772     nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(aImapUrl),
01773                                           aImapMailFolder,
01774                                           aUrlListener, urlSpec, hierarchySeparator);
01775     if (NS_SUCCEEDED (rv) && aImapUrl)
01776     {
01777         rv = SetImapUrlSink(aImapMailFolder, aImapUrl);
01778 
01779         if (NS_SUCCEEDED(rv))
01780         {
01781             nsCOMPtr<nsIURI> uri = do_QueryInterface(aImapUrl);
01782 
01783             urlSpec.Append("/discoverallandsubscribedboxes");
01784                      rv = uri->SetSpec(urlSpec);
01785             if (NS_SUCCEEDED(rv))
01786                 rv = GetImapConnectionAndLoadUrl(aClientEventQueue, aImapUrl,
01787                                                  nsnull, aURL);
01788         }
01789     }
01790     return rv;
01791 }
01792 
01793 NS_IMETHODIMP
01794 nsImapService::DiscoverChildren(nsIEventQueue* aClientEventQueue,
01795                                 nsIMsgFolder* aImapMailFolder,
01796                                 nsIUrlListener* aUrlListener,
01797                                                         const char *folderPath,
01798                                 nsIURI** aURL)
01799 {
01800     NS_ASSERTION (aImapMailFolder && aClientEventQueue, 
01801                   "Oops ... null aClientEventQueue or aImapMailFolder");
01802     if (!aImapMailFolder || ! aClientEventQueue)
01803         return NS_ERROR_NULL_POINTER;
01804     
01805     nsCOMPtr<nsIImapUrl> aImapUrl;
01806     nsCAutoString urlSpec;
01807 
01808     PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder);
01809     nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(aImapUrl),
01810                                           aImapMailFolder,
01811                                           aUrlListener, urlSpec, hierarchySeparator);
01812     if (NS_SUCCEEDED (rv))
01813     {
01814         rv = SetImapUrlSink(aImapMailFolder, aImapUrl);
01815 
01816         if (NS_SUCCEEDED(rv))
01817         {
01818             if (folderPath && *folderPath)
01819             {
01820                 nsCOMPtr<nsIURI> uri = do_QueryInterface(aImapUrl);
01821 
01822                 urlSpec.Append("/discoverchildren>");
01823                             urlSpec.Append(char(hierarchySeparator));
01824                 urlSpec.Append(folderPath);
01825                      // mscott - this cast to a char * is okay...there's a bug in the XPIDL
01826                             // compiler that is preventing in string parameters from showing up as
01827                             // const char *. hopefully they will fix it soon.
01828                             rv = uri->SetSpec(urlSpec);
01829 
01830         // Make sure the uri has the same hierarchy separator as the one in msg folder 
01831         // obj if it's not kOnlineHierarchySeparatorUnknown (ie, '^').
01832         char uriDelimiter;
01833         nsresult rv1 = aImapUrl->GetOnlineSubDirSeparator(&uriDelimiter);
01834         if (NS_SUCCEEDED (rv1) && hierarchySeparator != kOnlineHierarchySeparatorUnknown &&
01835             uriDelimiter != hierarchySeparator)
01836           aImapUrl->SetOnlineSubDirSeparator((char)hierarchySeparator);
01837 
01838 
01839                 if (NS_SUCCEEDED(rv))
01840                     rv = GetImapConnectionAndLoadUrl(aClientEventQueue,
01841                                                      aImapUrl,
01842                                                      nsnull, aURL);
01843             }
01844             else
01845             {
01846                 rv = NS_ERROR_NULL_POINTER;
01847             }
01848         }
01849     }
01850     return rv;
01851 }
01852 
01853 
01854 NS_IMETHODIMP
01855 nsImapService::OnlineMessageCopy(nsIEventQueue* aClientEventQueue,
01856                                  nsIMsgFolder* aSrcFolder,
01857                                  const char* messageIds,
01858                                  nsIMsgFolder* aDstFolder,
01859                                  PRBool idsAreUids,
01860                                  PRBool isMove,
01861                                  nsIUrlListener* aUrlListener,
01862                                  nsIURI** aURL,
01863                                  nsISupports* copyState,
01864                                  nsIMsgWindow *aMsgWindow)
01865 {
01866     NS_ASSERTION(aSrcFolder && aDstFolder && messageIds && aClientEventQueue,
01867                  "Fatal ... missing key parameters");
01868     if (!aClientEventQueue || !aSrcFolder || !aDstFolder || !messageIds ||
01869         *messageIds == 0)
01870         return NS_ERROR_NULL_POINTER;
01871 
01872     nsresult rv = NS_ERROR_FAILURE;
01873 
01874     nsCOMPtr <nsIMsgIncomingServer> srcServer;
01875     nsCOMPtr <nsIMsgIncomingServer> dstServer;
01876 
01877     rv = aSrcFolder->GetServer(getter_AddRefs(srcServer));
01878     if(NS_FAILED(rv)) return rv;
01879 
01880     rv = aDstFolder->GetServer(getter_AddRefs(dstServer));
01881     if(NS_FAILED(rv)) return rv;
01882 
01883     PRBool sameServer;
01884     rv = dstServer->Equals(srcServer, &sameServer);
01885     if(NS_FAILED(rv)) return rv;
01886 
01887     if (!sameServer) 
01888     {
01889       NS_ASSERTION(PR_FALSE, "can't use this method to copy across servers");
01890         // *** can only take message from the same imap host and user accnt
01891       return NS_ERROR_FAILURE;
01892     }
01893 
01894     nsCOMPtr<nsIImapUrl> imapUrl;
01895     nsCAutoString urlSpec;
01896 
01897     PRUnichar hierarchySeparator = GetHierarchyDelimiter(aSrcFolder);
01898     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aSrcFolder, aUrlListener, urlSpec, hierarchySeparator);
01899     if (NS_SUCCEEDED(rv))
01900     {
01901         SetImapUrlSink(aSrcFolder, imapUrl);
01902         imapUrl->SetCopyState(copyState);
01903 
01904         nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(imapUrl));
01905 
01906         msgurl->SetMsgWindow(aMsgWindow);
01907         imapUrl->AddChannelToLoadGroup();  //we get the loadGroup from msgWindow
01908         nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
01909 
01910         if (isMove)
01911             urlSpec.Append("/onlinemove>");
01912         else
01913             urlSpec.Append("/onlinecopy>");
01914         if (idsAreUids)
01915             urlSpec.Append(uidString);
01916         else
01917             urlSpec.Append(sequenceString);
01918         urlSpec.Append('>');
01919         urlSpec.Append(char(hierarchySeparator));
01920 
01921         nsXPIDLCString folderName;
01922         GetFolderName(aSrcFolder, getter_Copies(folderName));
01923         urlSpec.Append((const char *) folderName);
01924         urlSpec.Append('>');
01925         urlSpec.Append(messageIds);
01926         urlSpec.Append('>');
01927         urlSpec.Append(char(hierarchySeparator));
01928         folderName.Adopt(strdup(""));
01929         GetFolderName(aDstFolder, getter_Copies(folderName));
01930         urlSpec.Append((const char *) folderName);
01931 
01932               rv = uri->SetSpec(urlSpec);
01933         if (NS_SUCCEEDED(rv))
01934             rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
01935                                              nsnull, aURL);
01936     }
01937     return rv;
01938 }
01939 
01940 nsresult nsImapService::OfflineAppendFromFile(nsIFileSpec* aFileSpec,
01941                                               nsIURI *aUrl,
01942                                      nsIMsgFolder* aDstFolder,
01943                                      const char* messageId, // te be replaced
01944                                      PRBool inSelectedState, // needs to be in
01945                                      nsIUrlListener* aListener,
01946                                      nsIURI** aURL,
01947                                      nsISupports* aCopyState)
01948 {
01949   nsCOMPtr <nsIMsgDatabase> destDB;
01950   nsresult rv = aDstFolder->GetMsgDatabase(nsnull, getter_AddRefs(destDB));
01951   // ### might need to send some notifications instead of just returning
01952 
01953   if (NS_SUCCEEDED(rv) && destDB)
01954   {
01955     nsMsgKey fakeKey;
01956     destDB->GetNextFakeOfflineMsgKey(&fakeKey);
01957     
01958     nsCOMPtr <nsIMsgOfflineImapOperation> op;
01959     rv = destDB->GetOfflineOpForKey(fakeKey, PR_TRUE, getter_AddRefs(op));
01960     if (NS_SUCCEEDED(rv) && op)
01961     {
01962       nsXPIDLCString destFolderUri;
01963 
01964       aDstFolder->GetURI(getter_Copies(destFolderUri));
01965       op->SetOperation(nsIMsgOfflineImapOperation::kAppendDraft); // ### do we care if it's a template?
01966       op->SetDestinationFolderURI(destFolderUri);
01967       nsCOMPtr <nsIOutputStream> offlineStore;
01968       rv = aDstFolder->GetOfflineStoreOutputStream(getter_AddRefs(offlineStore));
01969 
01970       if (NS_SUCCEEDED(rv) && offlineStore)
01971       {
01972         PRInt64 curOfflineStorePos = 0;
01973         nsCOMPtr <nsISeekableStream> seekable = do_QueryInterface(offlineStore);
01974         if (seekable)
01975           seekable->Tell(&curOfflineStorePos);
01976         else
01977         {
01978           NS_ASSERTION(PR_FALSE, "needs to be a random store!");
01979           return NS_ERROR_FAILURE;
01980         }
01981 
01982 
01983         nsCOMPtr <nsIInputStream> inputStream;
01984         nsCOMPtr <nsIMsgParseMailMsgState> msgParser = do_CreateInstance(NS_PARSEMAILMSGSTATE_CONTRACTID, &rv);
01985         msgParser->SetMailDB(destDB);
01986 
01987         if (NS_SUCCEEDED(rv))
01988           rv = aFileSpec->GetInputStream(getter_AddRefs(inputStream));
01989         if (NS_SUCCEEDED(rv) && inputStream)
01990         {
01991           // now, copy the temp file to the offline store for the dest folder.
01992           PRInt32 inputBufferSize = 10240;
01993           nsMsgLineStreamBuffer *inputStreamBuffer = new nsMsgLineStreamBuffer(inputBufferSize, PR_TRUE /* allocate new lines */, PR_FALSE /* leave CRLFs on the returned string */);
01994           PRUint32 fileSize;
01995           aFileSpec->GetFileSize(&fileSize);
01996           PRUint32 bytesWritten;
01997           rv = NS_OK;
01998 //            rv = inputStream->Read(inputBuffer, inputBufferSize, &bytesRead);
01999 //            if (NS_SUCCEEDED(rv) && bytesRead > 0)
02000           msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState);
02001           // set the env pos to fake key so the msg hdr will have that for a key
02002           msgParser->SetEnvelopePos(fakeKey);
02003           PRBool needMoreData = PR_FALSE;
02004           char * newLine = nsnull;
02005           PRUint32 numBytesInLine = 0;
02006           do
02007           {
02008             newLine = inputStreamBuffer->ReadNextLine(inputStream, numBytesInLine, needMoreData); 
02009             if (newLine)
02010             {
02011               msgParser->ParseAFolderLine(newLine, numBytesInLine);
02012               rv = offlineStore->Write(newLine, numBytesInLine, &bytesWritten);
02013               nsCRT::free(newLine);
02014             }
02015           }
02016           while (newLine);
02017           nsCOMPtr <nsIMsgDBHdr> fakeHdr;
02018 
02019           msgParser->FinishHeader();
02020           msgParser->GetNewMsgHdr(getter_AddRefs(fakeHdr));
02021           if (fakeHdr)
02022           {
02023             if (NS_SUCCEEDED(rv) && fakeHdr)
02024             {
02025               PRUint32 resultFlags;
02026               nsInt64 tellPos = curOfflineStorePos;
02027               fakeHdr->SetMessageOffset((PRUint32) tellPos);
02028               fakeHdr->OrFlags(MSG_FLAG_OFFLINE | MSG_FLAG_READ, &resultFlags);
02029               fakeHdr->SetOfflineMessageSize(fileSize);
02030               destDB->AddNewHdrToDB(fakeHdr, PR_TRUE /* notify */);
02031               aDstFolder->SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS);
02032             }
02033           }
02034           // tell the listener we're done.
02035           inputStream = nsnull;
02036           aFileSpec->CloseStream();
02037           aListener->OnStopRunningUrl(aUrl, NS_OK);
02038           delete inputStreamBuffer;
02039         }
02040       }
02041     }
02042   }
02043           
02044          
02045   if (destDB)
02046     destDB->Close(PR_TRUE);
02047   return rv;
02048 }
02049 
02050 /* append message from file url */
02051 /* imap://HOST>appendmsgfromfile>DESTINATIONMAILBOXPATH */
02052 /* imap://HOST>appenddraftfromfile>DESTINATIONMAILBOXPATH>UID>messageId */
02053 NS_IMETHODIMP
02054 nsImapService::AppendMessageFromFile(nsIEventQueue* aClientEventQueue,
02055                                      nsIFileSpec* aFileSpec,
02056                                      nsIMsgFolder* aDstFolder,
02057                                      const char* messageId, // te be replaced
02058                                      PRBool idsAreUids,
02059                                      PRBool inSelectedState, // needs to be in
02060                                      nsIUrlListener* aListener,
02061                                      nsIURI** aURL,
02062                                      nsISupports* aCopyState,
02063                                      nsIMsgWindow *aMsgWindow)
02064 {
02065     nsresult rv = NS_ERROR_NULL_POINTER;
02066     if (!aClientEventQueue || !aFileSpec || !aDstFolder)
02067         return rv;
02068     
02069     nsCOMPtr<nsIImapUrl> imapUrl;
02070     nsCAutoString urlSpec;
02071 
02072     PRUnichar hierarchySeparator = GetHierarchyDelimiter(aDstFolder);
02073     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aDstFolder, aListener, urlSpec, hierarchySeparator);
02074     if (NS_SUCCEEDED(rv))
02075     {
02076         nsCOMPtr <nsIMsgMailNewsUrl> msgUrl = do_QueryInterface(imapUrl);
02077         if (msgUrl && aMsgWindow)
02078         {
02079           //we get the loadGroup from msgWindow
02080           msgUrl->SetMsgWindow(aMsgWindow);
02081           imapUrl->AddChannelToLoadGroup();
02082         }
02083 
02084         SetImapUrlSink(aDstFolder, imapUrl);
02085         imapUrl->SetMsgFileSpec(aFileSpec);
02086         imapUrl->SetCopyState(aCopyState);
02087 
02088         nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
02089 
02090         if (inSelectedState)
02091             urlSpec.Append("/appenddraftfromfile>");
02092         else
02093             urlSpec.Append("/appendmsgfromfile>");
02094 
02095         urlSpec.Append(char(hierarchySeparator));
02096         
02097         nsXPIDLCString folderName;
02098         GetFolderName(aDstFolder, getter_Copies(folderName));
02099         urlSpec.Append(folderName);
02100 
02101         if (inSelectedState)
02102         {
02103             urlSpec.Append('>');
02104             if (idsAreUids)
02105                 urlSpec.Append(uidString);
02106             else
02107                 urlSpec.Append(sequenceString);
02108             urlSpec.Append('>');
02109             if (messageId)
02110                 urlSpec.Append(messageId);
02111         }
02112 
02113         rv = uri->SetSpec(urlSpec);
02114         if (WeAreOffline())
02115         {
02116           return OfflineAppendFromFile(aFileSpec, uri, aDstFolder, messageId, inSelectedState, aListener, aURL, aCopyState);
02117           // handle offline append to drafts or templates folder here.
02118         }
02119         if (NS_SUCCEEDED(rv))
02120             rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl,
02121                                              nsnull, aURL);
02122     }
02123     return rv;
02124 }
02125 
02126 nsresult
02127 nsImapService::GetImapConnectionAndLoadUrl(nsIEventQueue* aClientEventQueue,
02128                                            nsIImapUrl* aImapUrl,
02129                                            nsISupports* aConsumer,
02130                                            nsIURI** aURL)
02131 {
02132   NS_ENSURE_ARG(aImapUrl);
02133 
02134   if (WeAreOffline())
02135   {
02136     nsImapAction imapAction;
02137 
02138     // the only thing we can do offline is fetch messages.
02139     // ### TODO - need to look at msg copy, save attachment, etc. when we
02140     // have offline message bodies.
02141     aImapUrl->GetImapAction(&imapAction);
02142     if (imapAction != nsIImapUrl::nsImapMsgFetch && imapAction != nsIImapUrl::nsImapSaveMessageToDisk)
02143       return NS_MSG_ERROR_OFFLINE;
02144   }
02145 
02146   nsresult rv = NS_OK;
02147   nsCOMPtr<nsIMsgIncomingServer> aMsgIncomingServer;
02148   nsCOMPtr<nsIMsgMailNewsUrl> msgUrl = do_QueryInterface(aImapUrl);
02149   rv = msgUrl->GetServer(getter_AddRefs(aMsgIncomingServer));
02150     
02151   if (aURL)
02152       NS_IF_ADDREF(*aURL = msgUrl);
02153 
02154   if (NS_SUCCEEDED(rv) && aMsgIncomingServer)
02155   {
02156     nsCOMPtr<nsIImapIncomingServer> aImapServer(do_QueryInterface(aMsgIncomingServer, &rv));
02157     if (NS_SUCCEEDED(rv) && aImapServer)
02158       rv = aImapServer->GetImapConnectionAndLoadUrl(aClientEventQueue,
02159                                                     aImapUrl, aConsumer);
02160   }
02161   return rv;
02162 }
02163 
02164 NS_IMETHODIMP
02165 nsImapService::MoveFolder(nsIEventQueue* eventQueue, nsIMsgFolder* srcFolder,
02166                           nsIMsgFolder* dstFolder, nsIUrlListener* urlListener, 
02167                           nsIMsgWindow *msgWindow, nsIURI** url)
02168 {
02169     NS_ASSERTION(eventQueue && srcFolder && dstFolder, 
02170                  "Oops ... null pointer");
02171     if (!eventQueue || !srcFolder || !dstFolder)
02172         return NS_ERROR_NULL_POINTER;
02173 
02174     nsCOMPtr<nsIImapUrl> imapUrl;
02175     nsCAutoString urlSpec;
02176     nsresult rv;
02177 
02178     PRUnichar default_hierarchySeparator = GetHierarchyDelimiter(dstFolder);
02179     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), dstFolder, urlListener, urlSpec, default_hierarchySeparator);
02180     if (NS_SUCCEEDED(rv) && imapUrl)
02181     {
02182         rv = SetImapUrlSink(dstFolder, imapUrl);
02183         if (NS_SUCCEEDED(rv))
02184         {
02185             nsCOMPtr<nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
02186             if (mailNewsUrl)
02187               mailNewsUrl->SetMsgWindow(msgWindow);
02188             char hierarchySeparator = kOnlineHierarchySeparatorUnknown;
02189             nsXPIDLCString folderName;
02190             
02191             nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
02192             GetFolderName(srcFolder, getter_Copies(folderName));
02193             urlSpec.Append("/movefolderhierarchy>");
02194             urlSpec.Append(hierarchySeparator);
02195             urlSpec.Append((const char *) folderName);
02196             urlSpec.Append('>');
02197             folderName.Adopt(strdup(""));
02198             GetFolderName(dstFolder, getter_Copies(folderName));
02199             if ( folderName && folderName[0])
02200             {
02201                urlSpec.Append(hierarchySeparator);
02202                urlSpec.Append((const char *) folderName);
02203             }
02204             rv = uri->SetSpec(urlSpec);
02205             if (NS_SUCCEEDED(rv))
02206             {
02207                 GetFolderName(srcFolder, getter_Copies(folderName));
02208                 rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl,
02209                                                  nsnull,
02210                                                  url);
02211             }
02212         }
02213     }
02214     return rv;
02215 }
02216 
02217 NS_IMETHODIMP
02218 nsImapService::RenameLeaf(nsIEventQueue* eventQueue, nsIMsgFolder* srcFolder,
02219                           const PRUnichar* newLeafName, nsIUrlListener* urlListener,
02220                           nsIMsgWindow *msgWindow, nsIURI** url)
02221 {
02222     NS_ASSERTION(eventQueue && srcFolder && newLeafName && *newLeafName,
02223                  "Oops ... [RenameLeaf] null pointers");
02224     if (!eventQueue || !srcFolder || !newLeafName || !*newLeafName)
02225         return NS_ERROR_NULL_POINTER;
02226     
02227     nsCOMPtr<nsIImapUrl> imapUrl;
02228     nsCAutoString urlSpec;
02229     nsresult rv;
02230 
02231        PRUnichar hierarchySeparator = GetHierarchyDelimiter(srcFolder);
02232     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), srcFolder, urlListener, urlSpec, hierarchySeparator);
02233     if (NS_SUCCEEDED(rv))
02234     {
02235         rv = SetImapUrlSink(srcFolder, imapUrl);
02236         if (NS_SUCCEEDED(rv))
02237         {
02238             nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
02239             nsCOMPtr<nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
02240             if (mailNewsUrl)
02241               mailNewsUrl->SetMsgWindow(msgWindow);
02242             nsXPIDLCString folderName;
02243             GetFolderName(srcFolder, getter_Copies(folderName));
02244             urlSpec.Append("/rename>");
02245             urlSpec.Append(char(hierarchySeparator));
02246             urlSpec.Append((const char *) folderName);
02247             urlSpec.Append('>');
02248             urlSpec.Append(char(hierarchySeparator));
02249 
02250 
02251             nsCAutoString cStrFolderName(NS_STATIC_CAST(const char *, folderName));
02252             // Unescape the name before looking for parent path
02253             nsUnescape(cStrFolderName.BeginWriting());
02254             PRInt32 leafNameStart = 
02255             cStrFolderName.RFindChar(hierarchySeparator);
02256             if (leafNameStart != -1)
02257             {
02258                 cStrFolderName.SetLength(leafNameStart+1);
02259                 urlSpec.Append(cStrFolderName);
02260             }
02261 
02262             nsCAutoString utfNewName;
02263             CopyUTF16toMUTF7(nsDependentString(newLeafName), utfNewName);
02264             char* escapedNewName = nsEscape(utfNewName.get(), url_Path);
02265             if (!escapedNewName) return NS_ERROR_OUT_OF_MEMORY;
02266             nsXPIDLCString escapedSlashName;
02267             rv = nsImapUrl::EscapeSlashes(escapedNewName, getter_Copies(escapedSlashName));
02268             NS_ENSURE_SUCCESS(rv, rv);
02269             nsCRT::free(escapedNewName);
02270             urlSpec.Append(escapedSlashName.get());
02271 
02272             rv = uri->SetSpec(urlSpec);
02273             if (NS_SUCCEEDED(rv))
02274             {
02275                 rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl,
02276                                                  nsnull, url);
02277             }
02278         } // if (NS_SUCCEEDED(rv))
02279     } // if (NS_SUCCEEDED(rv) && imapUrl)
02280     return rv;
02281 }
02282 
02283 NS_IMETHODIMP
02284 nsImapService::CreateFolder(nsIEventQueue* eventQueue, nsIMsgFolder* parent,
02285                             const PRUnichar* newFolderName, 
02286                             nsIUrlListener* urlListener, nsIURI** url)
02287 {
02288     NS_ASSERTION(eventQueue && parent && newFolderName && *newFolderName,
02289                  "Oops ... [CreateFolder] null pointers");
02290     if (!eventQueue || !parent || !newFolderName || !*newFolderName)
02291         return NS_ERROR_NULL_POINTER;
02292     
02293     nsCOMPtr<nsIImapUrl> imapUrl;
02294     nsCAutoString urlSpec;
02295     nsresult rv;
02296 
02297     PRUnichar hierarchySeparator = GetHierarchyDelimiter(parent);
02298     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), parent, urlListener, urlSpec, hierarchySeparator);
02299     if (NS_SUCCEEDED(rv) && imapUrl)
02300     {
02301         rv = SetImapUrlSink(parent, imapUrl);
02302         if (NS_SUCCEEDED(rv))
02303         {
02304             nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
02305 
02306             nsXPIDLCString folderName;
02307             GetFolderName(parent, getter_Copies(folderName));
02308             urlSpec.Append("/create>");
02309             urlSpec.Append(char(hierarchySeparator));
02310             if (!folderName.IsEmpty())
02311             {
02312               nsXPIDLCString canonicalName;
02313 
02314               nsImapUrl::ConvertToCanonicalFormat(folderName, (char) hierarchySeparator, getter_Copies(canonicalName));
02315               urlSpec.Append((const char *) canonicalName);
02316               urlSpec.Append(char(hierarchySeparator));
02317             }
02318 
02319             nsCAutoString utfNewName;
02320             rv = CopyUTF16toMUTF7(nsDependentString(newFolderName), utfNewName);
02321             NS_ENSURE_SUCCESS(rv, rv);
02322             char* escapedFolderName = nsEscape(utfNewName.get(), url_Path);
02323             urlSpec.Append(escapedFolderName);
02324             nsCRT::free(escapedFolderName);
02325     
02326             rv = uri->SetSpec(urlSpec);
02327             if (NS_SUCCEEDED(rv))
02328                 rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl,
02329                                                      nsnull,
02330                                                      url);
02331         } // if (NS_SUCCEEDED(rv))
02332     } // if (NS_SUCCEEDED(rv) && imapUrl)
02333     return rv;
02334 }
02335 
02336 NS_IMETHODIMP
02337 nsImapService::EnsureFolderExists(nsIEventQueue* eventQueue, nsIMsgFolder* parent,
02338                             const PRUnichar* newFolderName, 
02339                             nsIUrlListener* urlListener, nsIURI** url)
02340 {
02341     NS_ASSERTION(eventQueue && parent && newFolderName && *newFolderName,
02342                  "Oops ... [EnsureExists] null pointers");
02343     if (!eventQueue || !parent || !newFolderName || !*newFolderName)
02344         return NS_ERROR_NULL_POINTER;
02345     
02346     nsCOMPtr<nsIImapUrl> imapUrl;
02347     nsCAutoString urlSpec;
02348     nsresult rv;
02349 
02350   PRUnichar hierarchySeparator = GetHierarchyDelimiter(parent);
02351     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), parent, urlListener, urlSpec, hierarchySeparator);
02352     if (NS_SUCCEEDED(rv) && imapUrl)
02353     {
02354         rv = SetImapUrlSink(parent, imapUrl);
02355         if (NS_SUCCEEDED(rv))
02356         {
02357             nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
02358 
02359             nsXPIDLCString folderName;
02360             GetFolderName(parent, getter_Copies(folderName));
02361             urlSpec.Append("/ensureExists>");
02362             urlSpec.Append(char(hierarchySeparator));
02363             if (!folderName.IsEmpty())
02364             {
02365                 urlSpec.Append((const char *) folderName);
02366                 urlSpec.Append(char(hierarchySeparator));
02367             }
02368             nsCAutoString utfNewName; 
02369             CopyUTF16toMUTF7(nsDependentString(newFolderName), utfNewName);
02370             char* escapedFolderName = nsEscape(utfNewName.get(), url_Path);
02371             urlSpec.Append(escapedFolderName);
02372             nsCRT::free(escapedFolderName);
02373     
02374             rv = uri->SetSpec(urlSpec);
02375             if (NS_SUCCEEDED(rv))
02376                 rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl,
02377                                                      nsnull,
02378                                                      url);
02379         } // if (NS_SUCCEEDED(rv))
02380     } // if (NS_SUCCEEDED(rv) && imapUrl)
02381     return rv;
02382 }
02383 
02384 
02385 NS_IMETHODIMP
02386 nsImapService::ListFolder(nsIEventQueue* aClientEventQueue,
02387                                 nsIMsgFolder* aImapMailFolder,
02388                                 nsIUrlListener* aUrlListener,
02389                                 nsIURI** aURL)
02390 {
02391   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
02392                       "/listfolder>", nsIImapUrl::nsImapListFolder, aURL);
02393 }
02394 
02395 
02396 
02397 
02398 NS_IMETHODIMP nsImapService::GetScheme(nsACString &aScheme)
02399 {
02400   aScheme = "imap";
02401   return NS_OK; 
02402 }
02403 
02404 NS_IMETHODIMP nsImapService::GetDefaultPort(PRInt32 *aDefaultPort)
02405 {
02406     NS_ENSURE_ARG_POINTER(aDefaultPort);
02407     *aDefaultPort = IMAP_PORT;
02408 
02409     return NS_OK;
02410 }
02411 
02412 NS_IMETHODIMP nsImapService::GetProtocolFlags(PRUint32 *result)
02413 {
02414     *result = URI_STD | ALLOWS_PROXY;
02415     return NS_OK;
02416 }
02417 
02418 NS_IMETHODIMP nsImapService::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
02419 {
02420     // allow imap to run on any port
02421     *_retval = PR_TRUE;
02422     return NS_OK;
02423 }
02424 
02425 NS_IMETHODIMP nsImapService::GetDefaultDoBiff(PRBool *aDoBiff)
02426 {
02427     NS_ENSURE_ARG_POINTER(aDoBiff);
02428     // by default, do biff for IMAP servers
02429     *aDoBiff = PR_TRUE;    
02430     return NS_OK;
02431 }
02432 
02433 NS_IMETHODIMP
02434 nsImapService::GetDefaultServerPort(PRBool isSecure, PRInt32 *aDefaultPort)
02435 {
02436     nsresult rv = NS_OK;
02437 
02438     // Return Secure IMAP Port if secure option chosen i.e., if isSecure is TRUE
02439     if (isSecure)
02440        *aDefaultPort = SECURE_IMAP_PORT;
02441     else    
02442         rv = GetDefaultPort(aDefaultPort);
02443 
02444     return rv;
02445 }
02446 
02447 // this method first tries to find an exact username and hostname match with the given url
02448 // then, tries to find any account on the passed in imap host in case this is a url to 
02449 // a shared imap folder.
02450 nsresult nsImapService::GetServerFromUrl(nsIImapUrl *aImapUrl, nsIMsgIncomingServer **aServer)
02451 {
02452     nsCAutoString userPass;
02453     nsCAutoString hostName;
02454     nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl);
02455     nsresult rv;
02456     
02457     nsXPIDLCString folderName;
02458 
02459     // if we can't get a folder name out of the url then I think this is an error
02460     aImapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName));
02461     if (folderName.IsEmpty())
02462     {
02463       rv = mailnewsUrl->GetFileName(folderName);
02464       if (NS_FAILED(rv)) 
02465         return rv;
02466     }
02467     
02468     nsCOMPtr<nsIMsgAccountManager> accountManager = 
02469              do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
02470     if (NS_FAILED(rv)) 
02471       return rv;
02472     
02473     rv = accountManager->FindServerByURI(mailnewsUrl, PR_FALSE, aServer);
02474 
02475     // look for server with any user name, in case we're trying to subscribe
02476     // to a folder with some one else's user name like the following
02477     // "IMAP://userSharingFolder@server1/SharedFolderName"
02478 
02479     if (NS_FAILED(rv) || !aServer)
02480     {
02481       nsCAutoString turl;
02482       nsCOMPtr<nsIURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv);
02483       if (NS_FAILED(rv)) return rv;
02484 
02485       mailnewsUrl->GetSpec(turl);
02486       rv = url->SetSpec(turl);
02487       if (NS_FAILED(rv)) return rv;
02488 
02489       url->SetUserPass(EmptyCString());
02490       rv = accountManager->FindServerByURI(url, PR_FALSE, aServer);
02491       if (*aServer)
02492         aImapUrl->SetExternalLinkUrl(PR_TRUE);
02493     }
02494     // if we can't extract the imap server from this url then give up!!!
02495     if (NS_FAILED(rv))
02496       return rv;
02497     NS_ENSURE_TRUE(*aServer, NS_ERROR_FAILURE);
02498     return rv;
02499 }
02500 
02501 NS_IMETHODIMP nsImapService::NewURI(const nsACString &aSpec,
02502                                     const char *aOriginCharset, // ignored 
02503                                     nsIURI *aBaseURI,
02504                                     nsIURI **_retval)
02505 {
02506   nsresult rv;
02507   nsCOMPtr<nsIImapUrl> aImapUrl = do_CreateInstance(kImapUrlCID, &rv);
02508   if (NS_SUCCEEDED(rv))
02509   {
02510     // now extract lots of fun information...
02511     nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(aImapUrl);
02512     //nsCAutoString unescapedSpec(aSpec);
02513     // nsUnescape(unescapedSpec.BeginWriting());
02514 
02515     // set the spec
02516     if (aBaseURI) 
02517     {
02518       nsCAutoString newSpec;
02519       aBaseURI->Resolve(aSpec, newSpec);
02520       mailnewsUrl->SetSpec(newSpec);
02521     } 
02522     else 
02523     {
02524       mailnewsUrl->SetSpec(aSpec);
02525     }
02526 
02527     nsXPIDLCString folderName;
02528 
02529     // if we can't get a folder name out of the url then I think this is an error
02530     aImapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName));
02531     if (folderName.IsEmpty())
02532     {
02533       rv = mailnewsUrl->GetFileName(folderName);
02534       if (NS_FAILED(rv)) 
02535         return rv;
02536     }
02537 
02538     nsCOMPtr <nsIMsgIncomingServer> server;
02539     rv = GetServerFromUrl(aImapUrl, getter_AddRefs(server));
02540     // if we can't extract the imap server from this url then give up!!!
02541     if (NS_FAILED(rv)) 
02542       return rv;
02543     NS_ENSURE_TRUE(server, NS_ERROR_FAILURE);
02544 
02545     // now try to get the folder in question...
02546     nsCOMPtr<nsIMsgFolder> rootFolder;
02547     server->GetRootFolder(getter_AddRefs(rootFolder));
02548 
02549     if (rootFolder && !folderName.IsEmpty())
02550     {
02551       nsCOMPtr<nsIMsgFolder> folder;
02552       nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder, &rv);
02553       nsCOMPtr <nsIMsgImapMailFolder> subFolder;
02554       if (imapRoot)
02555       {
02556         imapRoot->FindOnlineSubFolder(folderName, getter_AddRefs(subFolder));
02557         folder = do_QueryInterface(subFolder, &rv);
02558       }
02559       if (NS_SUCCEEDED(rv))
02560       {
02561         nsCOMPtr<nsIImapMessageSink> msgSink = do_QueryInterface(folder);
02562         rv = aImapUrl->SetImapMessageSink(msgSink);
02563 
02564         nsCOMPtr<nsIMsgFolder> msgFolder = do_QueryInterface(folder);
02565         rv = SetImapUrlSink(msgFolder, aImapUrl);       
02566         nsXPIDLCString msgKey;
02567 
02568          nsXPIDLCString messageIdString;
02569          aImapUrl->CreateListOfMessageIdsString(getter_Copies(messageIdString));
02570          if (messageIdString.get())
02571         {
02572           PRBool useLocalCache = PR_FALSE;
02573           msgFolder->HasMsgOffline(atoi(messageIdString), &useLocalCache);  
02574           mailnewsUrl->SetMsgIsInLocalCache(useLocalCache);
02575         }
02576       }
02577     }
02578 
02579     // if we are fetching a part, be sure to enable fetch parts on demand
02580     PRBool mimePartSelectorDetected = PR_FALSE;
02581     aImapUrl->GetMimePartSelectorDetected(&mimePartSelectorDetected);
02582     if (mimePartSelectorDetected)
02583       aImapUrl->SetFetchPartsOnDemand(PR_TRUE);
02584 
02585     // we got an imap url, so be sure to return it...
02586     aImapUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) _retval);
02587   }
02588 
02589   return rv;
02590 }
02591 
02592 NS_IMETHODIMP nsImapService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
02593 {
02594     // imap can't open and return a channel right away...the url needs to go in the imap url queue 
02595     // until we find a connection which can run the url..in order to satisfy necko, we're going to return
02596     // a mock imap channel....
02597 
02598     nsresult rv = NS_OK;
02599     nsCOMPtr<nsIImapMockChannel> mockChannel;
02600     nsCOMPtr<nsIImapUrl> imapUrl = do_QueryInterface(aURI, &rv);
02601     if (NS_FAILED(rv)) return rv;
02602     nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(imapUrl);
02603 
02604     // XXX this mock channel stuff is wrong -- the channel really should be owning the URL
02605     // and the originalURL, not the other way around
02606     rv = imapUrl->InitializeURIforMockChannel();
02607     rv = imapUrl->GetMockChannel(getter_AddRefs(mockChannel));
02608     if (NS_FAILED(rv) || !mockChannel) 
02609     {
02610       // this is a funky condition...it means we've already run the url once
02611       // and someone is trying to get us to run it again...
02612       imapUrl->Initialize(); // force a new mock channel to get created.
02613       rv = imapUrl->InitializeURIforMockChannel();
02614       rv = imapUrl->GetMockChannel(getter_AddRefs(mockChannel));
02615       if (!mockChannel) return NS_ERROR_FAILURE;
02616     }
02617 
02618     PRBool externalLinkUrl;
02619     imapUrl->GetExternalLinkUrl(&externalLinkUrl);
02620     if (externalLinkUrl)
02621     {
02622       // everything after here is to handle clicking on an external link. We only want
02623       // to do this if we didn't run the url through the various nsImapService methods,
02624       // which we can tell by seeing if the sinks have been setup on the url or not.
02625       nsCOMPtr <nsIMsgIncomingServer> server;
02626       rv = GetServerFromUrl(imapUrl, getter_AddRefs(server));
02627       NS_ENSURE_SUCCESS(rv, rv);
02628       nsXPIDLCString folderName;
02629       imapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName));
02630       if (folderName.IsEmpty())
02631       {
02632         rv = mailnewsUrl->GetFileName(folderName);
02633         if (!folderName.IsEmpty())
02634           NS_UnescapeURL(folderName);
02635       }
02636       // if the parent is null, then the folder doesn't really exist, so see if the user
02637       // wants to subscribe to it./
02638       nsCOMPtr<nsIMsgFolder> aFolder;
02639       // now try to get the folder in question...
02640       nsCOMPtr<nsIMsgFolder> rootFolder;
02641       server->GetRootFolder(getter_AddRefs(rootFolder));
02642       nsCOMPtr <nsIMsgImapMailFolder> imapRoot = do_QueryInterface(rootFolder);
02643       nsCOMPtr <nsIMsgImapMailFolder> subFolder;
02644       if (imapRoot)
02645       {
02646         imapRoot->FindOnlineSubFolder(folderName, getter_AddRefs(subFolder));
02647         aFolder = do_QueryInterface(subFolder);
02648       }
02649       nsCOMPtr <nsIMsgFolder> parent;
02650       if (aFolder)
02651         aFolder->GetParent(getter_AddRefs(parent));
02652       nsXPIDLCString serverKey;
02653       nsCAutoString userPass;
02654       rv = mailnewsUrl->GetUserPass(userPass);
02655       server->GetKey(getter_Copies(serverKey));
02656       char *fullFolderName = nsnull;
02657       if (parent)
02658         fullFolderName = ToNewCString(folderName);
02659       if (!parent && !folderName.IsEmpty())// check if this folder is another user's folder
02660       {
02661         fullFolderName = nsIMAPNamespaceList::GenerateFullFolderNameWithDefaultNamespace(serverKey.get(), folderName.get(), userPass.get(), kOtherUsersNamespace, nsnull);
02662         // if this is another user's folder, let's see if we're already subscribed to it.
02663         rv = imapRoot->FindOnlineSubFolder(fullFolderName, getter_AddRefs(subFolder));
02664         aFolder = do_QueryInterface(subFolder);
02665         if (aFolder)
02666           aFolder->GetParent(getter_AddRefs(parent));
02667       }
02668       // if we couldn't get the fullFolderName, then we probably couldn't find
02669       // the other user's namespace, in which case, we shouldn't try to subscribe to it.
02670       if (!parent && !folderName.IsEmpty() && fullFolderName)
02671       {
02672         // this folder doesn't exist - check if the user wants to subscribe to this folder.
02673         nsCOMPtr<nsIPrompt> dialog;
02674         nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
02675         NS_ENSURE_SUCCESS(rv, rv);
02676         wwatch->GetNewPrompter(nsnull, getter_AddRefs(dialog));
02677 
02678         nsXPIDLString statusString, confirmText;
02679         nsCOMPtr<nsIStringBundle> bundle;
02680         rv = IMAPGetStringBundle(getter_AddRefs(bundle));
02681         NS_ENSURE_SUCCESS(rv, rv);
02682         // need to convert folder name from mod-utf7 to unicode
02683         nsAutoString unescapedName;
02684         if (NS_FAILED(CopyMUTF7toUTF16(nsDependentCString(fullFolderName), unescapedName)))
02685             CopyASCIItoUTF16(nsDependentCString(fullFolderName), unescapedName);
02686         const PRUnichar *formatStrings[1] = { unescapedName.get() };
02687 
02688         rv = bundle->FormatStringFromID(IMAP_SUBSCRIBE_PROMPT,
02689                                           formatStrings, 1,
02690                                           getter_Copies(confirmText));
02691         NS_ENSURE_SUCCESS(rv,rv);
02692 
02693         PRBool confirmResult = PR_FALSE;
02694         rv = dialog->Confirm(nsnull, confirmText, &confirmResult);
02695         NS_ENSURE_SUCCESS(rv, rv);
02696 
02697         if (confirmResult)
02698         {
02699           nsCOMPtr <nsIImapIncomingServer> imapServer = do_QueryInterface(server);
02700           if (imapServer)
02701           {
02702             nsCOMPtr <nsIURI> subscribeURI;
02703             // now we have the real folder name to try to subscribe to. Let's try running
02704             // a subscribe url and returning that as the uri we've created.
02705             // We need to convert this to unicode because that's what subscribe wants :-(
02706             // It's already in mod-utf7.
02707             nsAutoString unicodeName;
02708             unicodeName.AssignWithConversion(fullFolderName);
02709             rv = imapServer->SubscribeToFolder(unicodeName.get(), PR_TRUE, getter_AddRefs(subscribeURI));
02710             if (NS_SUCCEEDED(rv) && subscribeURI)
02711             {
02712               nsCOMPtr <nsIImapUrl> imapSubscribeUrl = do_QueryInterface(subscribeURI);
02713               if (imapSubscribeUrl)
02714                 imapSubscribeUrl->SetExternalLinkUrl(PR_TRUE);
02715               nsCOMPtr <nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(subscribeURI);
02716               if (mailnewsUrl)
02717               {
02718                 nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
02719                 NS_ENSURE_SUCCESS(rv, rv);
02720                 nsCOMPtr <nsIMsgWindow> msgWindow;
02721                 rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
02722                 if (NS_SUCCEEDED(rv) && msgWindow)
02723                 {
02724                   mailnewsUrl->SetMsgWindow(msgWindow);
02725                   nsCOMPtr <nsIUrlListener> listener = do_QueryInterface(rootFolder);
02726                   if (listener)
02727                     mailnewsUrl->RegisterListener(listener);
02728                 }
02729               }
02730             }
02731           }
02732         }
02733         // error out this channel, so it'll stop trying to run the url.
02734         rv = NS_ERROR_FAILURE;
02735         *_retval = nsnull;
02736         PR_Free(fullFolderName);
02737       }
02738       else if (fullFolderName)// this folder exists - check if this is a click on a link to the folder
02739       {     // in which case, we'll select it.
02740         nsCOMPtr <nsIMsgFolder> imapFolder;
02741         nsCOMPtr <nsIImapServerSink> serverSink;
02742 
02743         mailnewsUrl->GetFolder(getter_AddRefs(imapFolder));
02744         imapUrl->GetImapServerSink(getter_AddRefs(serverSink));
02745         // need to see if this is a link click - one way is to check if the url is set up correctly
02746         // if not, it's probably a url click. We need a better way of doing this. 
02747         if (!imapFolder)
02748         {
02749           nsCOMPtr<nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
02750           NS_ENSURE_SUCCESS(rv, rv);
02751           nsCOMPtr <nsIMsgWindow> msgWindow;
02752           rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
02753           if (NS_SUCCEEDED(rv) && msgWindow)
02754           {
02755             nsXPIDLCString uri;
02756             rootFolder->GetURI(getter_Copies(uri));
02757            uri.Append('/');
02758             uri.Append(fullFolderName);
02759             msgWindow->SelectFolder(uri.get());
02760             // error out this channel, so it'll stop trying to run the url.
02761             *_retval = nsnull;
02762             rv = NS_ERROR_FAILURE;
02763           }
02764           else
02765           {
02766             // make sure the imap action is selectFolder, so the content type
02767             // will be x-application-imapfolder, so ::HandleContent will
02768             // know to open a new 3 pane window.
02769             imapUrl->SetImapAction(nsIImapUrl::nsImapSelectFolder);
02770           }
02771         }
02772       }
02773     }
02774     if (NS_SUCCEEDED(rv))
02775       NS_IF_ADDREF(*_retval = mockChannel);
02776     return rv;
02777 }
02778 
02779 NS_IMETHODIMP
02780 nsImapService::SetDefaultLocalPath(nsIFileSpec *aPath)
02781 {
02782     NS_ENSURE_ARG(aPath);
02783     
02784     nsFileSpec spec;
02785     nsresult rv = aPath->GetFileSpec(&spec);
02786     NS_ENSURE_SUCCESS(rv, rv);
02787     nsCOMPtr<nsILocalFile> localFile;
02788     NS_FileSpecToIFile(&spec, getter_AddRefs(localFile));
02789     if (!localFile) return NS_ERROR_FAILURE;
02790     
02791     return NS_SetPersistentFile(PREF_MAIL_ROOT_IMAP_REL, PREF_MAIL_ROOT_IMAP, localFile);
02792 }       
02793 
02794 NS_IMETHODIMP
02795 nsImapService::GetDefaultLocalPath(nsIFileSpec ** aResult)
02796 {
02797     NS_ENSURE_ARG_POINTER(aResult);
02798     *aResult = nsnull;
02799     
02800     nsresult rv;
02801     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
02802     if (NS_FAILED(rv)) return rv;
02803     
02804     PRBool havePref;
02805     nsCOMPtr<nsILocalFile> localFile;    
02806     rv = NS_GetPersistentFile(PREF_MAIL_ROOT_IMAP_REL,
02807                               PREF_MAIL_ROOT_IMAP,
02808                               NS_APP_IMAP_MAIL_50_DIR,
02809                               havePref,
02810                               getter_AddRefs(localFile));
02811         
02812     PRBool exists;
02813     rv = localFile->Exists(&exists);
02814     if (NS_SUCCEEDED(rv) && !exists)
02815         rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775);
02816     NS_ENSURE_SUCCESS(rv, rv);
02817     
02818     // Make the resulting nsIFileSpec
02819     // TODO: Convert arg to nsILocalFile and avoid this
02820     nsCOMPtr<nsIFileSpec> outSpec;
02821     rv = NS_NewFileSpecFromIFile(localFile, getter_AddRefs(outSpec));
02822     NS_ENSURE_SUCCESS(rv, rv);
02823     
02824     if (!havePref || !exists) 
02825     {
02826         rv = NS_SetPersistentFile(PREF_MAIL_ROOT_IMAP_REL, PREF_MAIL_ROOT_IMAP, localFile);
02827         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref.");
02828     }
02829         
02830     NS_IF_ADDREF(*aResult = outSpec);
02831     return NS_OK;
02832 }
02833     
02834 NS_IMETHODIMP
02835 nsImapService::GetServerIID(nsIID* *aServerIID)
02836 {
02837     *aServerIID = new nsIID(NS_GET_IID(nsIImapIncomingServer));
02838     return NS_OK;
02839 }
02840 
02841 NS_IMETHODIMP
02842 nsImapService::GetRequiresUsername(PRBool *aRequiresUsername)
02843 {
02844        NS_ENSURE_ARG_POINTER(aRequiresUsername);
02845        *aRequiresUsername = PR_TRUE;
02846        return NS_OK;
02847 }
02848 
02849 NS_IMETHODIMP
02850 nsImapService::GetPreflightPrettyNameWithEmailAddress(PRBool *aPreflightPrettyNameWithEmailAddress)
02851 {
02852        NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress);
02853        *aPreflightPrettyNameWithEmailAddress = PR_TRUE;
02854        return NS_OK;
02855 }
02856 
02857 NS_IMETHODIMP
02858 nsImapService::GetCanLoginAtStartUp(PRBool *aCanLoginAtStartUp)
02859 {
02860         NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp);
02861         *aCanLoginAtStartUp = PR_TRUE;
02862         return NS_OK;
02863 }
02864 
02865 NS_IMETHODIMP
02866 nsImapService::GetCanDelete(PRBool *aCanDelete)
02867 {
02868   NS_ENSURE_ARG_POINTER(aCanDelete);
02869   *aCanDelete = PR_TRUE;
02870   return NS_OK;
02871 }
02872 
02873 NS_IMETHODIMP
02874 nsImapService::GetCanDuplicate(PRBool *aCanDuplicate)
02875 {
02876   NS_ENSURE_ARG_POINTER(aCanDuplicate);
02877   *aCanDuplicate = PR_TRUE;
02878   return NS_OK;
02879 }        
02880 
02881 NS_IMETHODIMP
02882 nsImapService::GetCanGetMessages(PRBool *aCanGetMessages)
02883 {
02884     NS_ENSURE_ARG_POINTER(aCanGetMessages);
02885     *aCanGetMessages = PR_TRUE;
02886     return NS_OK;
02887 }        
02888 
02889 NS_IMETHODIMP
02890 nsImapService::GetCanGetIncomingMessages(PRBool *aCanGetIncomingMessages)
02891 {
02892     NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages);
02893     *aCanGetIncomingMessages = PR_TRUE;
02894     return NS_OK;
02895 }    
02896 
02897 NS_IMETHODIMP
02898 nsImapService::GetShowComposeMsgLink(PRBool *showComposeMsgLink)
02899 {
02900     NS_ENSURE_ARG_POINTER(showComposeMsgLink);
02901     *showComposeMsgLink = PR_TRUE;
02902     return NS_OK;
02903 }        
02904 
02905 NS_IMETHODIMP
02906 nsImapService::GetNeedToBuildSpecialFolderURIs(PRBool *needToBuildSpecialFolderURIs)
02907 {
02908     NS_ENSURE_ARG_POINTER(needToBuildSpecialFolderURIs);
02909     *needToBuildSpecialFolderURIs = PR_TRUE;
02910     return NS_OK;
02911 }        
02912 
02913 NS_IMETHODIMP
02914 nsImapService::GetSpecialFoldersDeletionAllowed(PRBool *specialFoldersDeletionAllowed)
02915 {
02916     NS_ENSURE_ARG_POINTER(specialFoldersDeletionAllowed);
02917     *specialFoldersDeletionAllowed = PR_FALSE;
02918     return NS_OK;
02919 }
02920 
02921 NS_IMETHODIMP
02922 nsImapService::GetListOfFoldersWithPath(nsIImapIncomingServer *aServer, nsIMsgWindow *aMsgWindow, const char *folderPath)
02923 {
02924   nsresult rv;
02925 
02926 #ifdef DEBUG_sspitzer
02927   printf("GetListOfFoldersWithPath(%s)\n",folderPath);
02928 #endif
02929   nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(aServer);
02930   if (!server) return NS_ERROR_FAILURE;
02931 
02932   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
02933   rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
02934 
02935   if (NS_FAILED(rv)) return rv;
02936   if (!rootMsgFolder) return NS_ERROR_FAILURE;
02937 
02938   nsCOMPtr<nsIUrlListener> listener = do_QueryInterface(aServer, &rv);
02939   if (NS_FAILED(rv)) return rv;
02940   if (!listener) return NS_ERROR_FAILURE;
02941 
02942   nsCOMPtr<nsIEventQueue> queue;
02943   // get the Event Queue for this thread...
02944   nsCOMPtr<nsIEventQueueService> pEventQService = 
02945     do_GetService(kEventQueueServiceCID, &rv);
02946   if (NS_FAILED(rv)) return rv;
02947   
02948   rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
02949   if (NS_FAILED(rv)) return rv;
02950   
02951   // Locate the folder so that the correct hierarchical delimiter is used in the folder
02952   // pathnames, otherwise root's (ie, '^') is used and this is wrong.
02953   nsCOMPtr<nsIMsgFolder> msgFolder;
02954   if (rootMsgFolder && folderPath && (*folderPath))
02955   {
02956     // If the folder path contains 'INBOX' of any forms, we need to convert it to uppercase
02957     // before finding it under the root folder. We do the same in PossibleImapMailbox().
02958     nsCAutoString tempFolderName(folderPath);
02959     nsCAutoString tokenStr, remStr, changedStr;
02960     PRInt32 slashPos = tempFolderName.FindChar('/');
02961     if (slashPos > 0)
02962     {
02963       tempFolderName.Left(tokenStr,slashPos);
02964       tempFolderName.Right(remStr, tempFolderName.Length()-slashPos);
02965     }
02966     else
02967       tokenStr.Assign(tempFolderName);
02968     
02969     if ((nsCRT::strcasecmp(tokenStr.get(), "INBOX")==0) && (nsCRT::strcmp(tokenStr.get(), "INBOX") != 0))
02970       changedStr.Append("INBOX");
02971     else
02972       changedStr.Append(tokenStr);
02973     
02974     if (slashPos > 0 ) 
02975       changedStr.Append(remStr);
02976     
02977     
02978     rv = rootMsgFolder->FindSubFolder(changedStr, getter_AddRefs(msgFolder));
02979   }
02980   
02981   rv = DiscoverChildren(queue, msgFolder, listener, folderPath, nsnull);
02982   if (NS_FAILED(rv)) return rv;
02983   
02984   return NS_OK;
02985 }
02986 
02987 NS_IMETHODIMP
02988 nsImapService::GetListOfFoldersOnServer(nsIImapIncomingServer *aServer, nsIMsgWindow *aMsgWindow)
02989 {
02990   nsresult rv;
02991 
02992   nsCOMPtr<nsIMsgIncomingServer> server = do_QueryInterface(aServer);
02993   if (!server) return NS_ERROR_FAILURE;
02994 
02995   nsCOMPtr<nsIMsgFolder> rootMsgFolder;
02996   rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder));
02997 
02998   if (NS_FAILED(rv)) return rv;
02999   if (!rootMsgFolder) return NS_ERROR_FAILURE;
03000 
03001   nsCOMPtr<nsIUrlListener> listener = do_QueryInterface(aServer, &rv);
03002   if (NS_FAILED(rv)) return rv;
03003   if (!listener) return NS_ERROR_FAILURE;
03004 
03005   nsCOMPtr<nsIEventQueue> queue;
03006   // get the Event Queue for this thread...
03007   nsCOMPtr<nsIEventQueueService> pEventQService = 
03008            do_GetService(kEventQueueServiceCID, &rv);
03009   if (NS_FAILED(rv)) return rv;
03010 
03011   rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue));
03012   if (NS_FAILED(rv)) return rv;
03013 
03014   rv = DiscoverAllAndSubscribedFolders(queue, rootMsgFolder, listener, nsnull);
03015   if (NS_FAILED(rv)) return rv;
03016 
03017   return NS_OK;
03018 } 
03019 
03020 NS_IMETHODIMP
03021 nsImapService::SubscribeFolder(nsIEventQueue* eventQueue, 
03022                                nsIMsgFolder* aFolder,
03023                                const PRUnichar* aFolderName, 
03024                                nsIUrlListener* urlListener, nsIURI** url)
03025 {
03026   return ChangeFolderSubscription(eventQueue, aFolder, aFolderName, 
03027                                   "/subscribe>", urlListener, url);
03028 }
03029 
03030 nsresult nsImapService::ChangeFolderSubscription(nsIEventQueue* eventQueue, 
03031                                nsIMsgFolder* folder,
03032                                const PRUnichar* folderName, 
03033                                const char *command,
03034                                nsIUrlListener* urlListener, nsIURI** url)
03035 {
03036     NS_ENSURE_ARG_POINTER(eventQueue);
03037     NS_ENSURE_ARG_POINTER(folder);
03038     NS_ENSURE_ARG_POINTER(folderName);
03039     
03040     nsCOMPtr<nsIImapUrl> imapUrl;
03041     nsCAutoString urlSpec;
03042     nsresult rv;
03043     PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder);
03044     rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), folder, urlListener,
03045                               urlSpec, hierarchySeparator);
03046     if (NS_SUCCEEDED(rv) && imapUrl)
03047     {
03048         rv = SetImapUrlSink(folder, imapUrl);
03049         if (NS_SUCCEEDED(rv))
03050         {
03051             nsCOMPtr<nsIURI> uri = do_QueryInterface(imapUrl);
03052             urlSpec.Append(command);
03053             urlSpec.Append(char(hierarchySeparator));
03054             nsCAutoString utfFolderName;
03055             rv = CopyUTF16toMUTF7(nsDependentString(folderName), utfFolderName);
03056             NS_ENSURE_SUCCESS(rv, rv);
03057             char* escapedFolderName = nsEscape(utfFolderName.get(), url_Path);
03058             urlSpec.Append(escapedFolderName);
03059             nsCRT::free(escapedFolderName);
03060             rv = uri->SetSpec(urlSpec);
03061             if (NS_SUCCEEDED(rv))
03062                 rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl,
03063                                                  nsnull, url);
03064         }
03065     }
03066     return rv;
03067 }
03068 
03069 NS_IMETHODIMP
03070 nsImapService::UnsubscribeFolder(nsIEventQueue* aEventQueue, 
03071                                nsIMsgFolder* aFolder,
03072                                const PRUnichar* aFolderName, 
03073                                nsIUrlListener* aUrlListener, nsIURI** aUrl)
03074 {
03075   return ChangeFolderSubscription(aEventQueue, aFolder, aFolderName, 
03076                                   "/unsubscribe>", aUrlListener, aUrl);
03077 }
03078 
03079 NS_IMETHODIMP
03080 nsImapService::GetFolderAdminUrl(nsIEventQueue *aClientEventQueue,
03081                       nsIMsgFolder *aImapMailFolder,
03082                       nsIMsgWindow   *aMsgWindow,
03083                       nsIUrlListener *aUrlListener,
03084                       nsIURI** aURL)
03085 {
03086   return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener,
03087                       "/refreshfolderurls>", nsIImapUrl::nsImapRefreshFolderUrls, aURL);
03088 }
03089 
03090 NS_IMETHODIMP
03091 nsImapService::IssueCommandOnMsgs(nsIEventQueue *aClientEventQueue,
03092                       nsIMsgFolder *anImapFolder,
03093                       nsIMsgWindow   *aMsgWindow,
03094                       const char *aCommand,
03095                       const char *uids,
03096                       nsIURI** aURL)
03097 {
03098   NS_ENSURE_ARG_POINTER(aClientEventQueue);
03099   NS_ENSURE_ARG_POINTER(anImapFolder);
03100   NS_ENSURE_ARG_POINTER(aMsgWindow);
03101   nsCOMPtr<nsIImapUrl> imapUrl;
03102   nsCAutoString urlSpec;
03103   nsresult rv;
03104   PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder);
03105   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator);
03106   
03107   if (NS_SUCCEEDED(rv) && imapUrl)
03108   {
03109     // nsImapUrl::SetSpec() will set the imap action properly
03110     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapUserDefinedMsgCommand);
03111     
03112     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
03113     mailNewsUrl->SetMsgWindow(aMsgWindow);
03114     mailNewsUrl->SetUpdatingFolder(PR_TRUE);
03115     imapUrl->AddChannelToLoadGroup();
03116     rv = SetImapUrlSink(anImapFolder, imapUrl);
03117     
03118     if (NS_SUCCEEDED(rv))
03119     {
03120       nsXPIDLCString folderName;
03121       GetFolderName(anImapFolder, getter_Copies(folderName));
03122       urlSpec.Append("/");
03123       urlSpec.Append(aCommand);
03124       urlSpec.Append(">");
03125       urlSpec.Append(uidString);
03126       urlSpec.Append(">");
03127       urlSpec.Append(char(hierarchySeparator));
03128       urlSpec.Append((const char *) folderName);
03129       urlSpec.Append(">");
03130       urlSpec.Append(uids);
03131       rv = mailNewsUrl->SetSpec(urlSpec);
03132       if (NS_SUCCEEDED(rv))
03133         rv = GetImapConnectionAndLoadUrl(aClientEventQueue,
03134         imapUrl,
03135         nsnull,
03136         aURL);
03137     }
03138   } // if we have a url to run....
03139   
03140   return rv;
03141 }
03142 
03143 NS_IMETHODIMP
03144 nsImapService::FetchCustomMsgAttribute(nsIEventQueue *aClientEventQueue,
03145                       nsIMsgFolder *anImapFolder,
03146                       nsIMsgWindow   *aMsgWindow,
03147                       const char *aAttribute,
03148                       const char *uids,
03149                       nsIURI** aURL)
03150 {
03151   NS_ENSURE_ARG_POINTER(aClientEventQueue);
03152   NS_ENSURE_ARG_POINTER(anImapFolder);
03153   NS_ENSURE_ARG_POINTER(aMsgWindow);
03154   nsCOMPtr<nsIImapUrl> imapUrl;
03155   nsCAutoString urlSpec;
03156   nsresult rv;
03157   PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder);
03158   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator);
03159   
03160   if (NS_SUCCEEDED(rv) && imapUrl)
03161   {
03162     // nsImapUrl::SetSpec() will set the imap action properly
03163     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapUserDefinedFetchAttribute);
03164     
03165     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
03166     mailNewsUrl->SetMsgWindow(aMsgWindow);
03167     mailNewsUrl->SetUpdatingFolder(PR_TRUE);
03168     imapUrl->AddChannelToLoadGroup();
03169     rv = SetImapUrlSink(anImapFolder, imapUrl);
03170     
03171     if (NS_SUCCEEDED(rv))
03172     {
03173       nsXPIDLCString folderName;
03174       GetFolderName(anImapFolder, getter_Copies(folderName));
03175       urlSpec.Append("/customFetch>UID>");
03176       urlSpec.Append(char(hierarchySeparator));
03177       urlSpec.Append((const char *) folderName);
03178       urlSpec.Append(">");
03179       urlSpec.Append(uids);
03180       urlSpec.Append(">");
03181       urlSpec.Append(aAttribute);
03182       rv = mailNewsUrl->SetSpec(urlSpec);
03183       if (NS_SUCCEEDED(rv))
03184         rv = GetImapConnectionAndLoadUrl(aClientEventQueue,
03185         imapUrl,
03186         nsnull,
03187         aURL);
03188     }
03189   } // if we have a url to run....
03190   
03191   return rv;
03192 }
03193 
03194 NS_IMETHODIMP
03195 nsImapService::StoreCustomKeywords(nsIEventQueue *aClientEventQueue,
03196                       nsIMsgFolder *anImapFolder,
03197                       nsIMsgWindow   *aMsgWindow,
03198                       const char *flagsToAdd,
03199                       const char *flagsToSubtract,
03200                       const char *uids,
03201                       nsIURI** aURL)
03202 {
03203   NS_ENSURE_ARG_POINTER(aClientEventQueue);
03204   NS_ENSURE_ARG_POINTER(anImapFolder);
03205   nsCOMPtr<nsIImapUrl> imapUrl;
03206   nsCAutoString urlSpec;
03207   nsresult rv;
03208   PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder);
03209   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator);
03210   
03211   if (NS_SUCCEEDED(rv) && imapUrl)
03212   {
03213     // nsImapUrl::SetSpec() will set the imap action properly
03214     rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgStoreCustomKeywords);
03215     
03216     nsCOMPtr <nsIMsgMailNewsUrl> mailNewsUrl = do_QueryInterface(imapUrl);
03217     mailNewsUrl->SetMsgWindow(aMsgWindow);
03218     mailNewsUrl->SetUpdatingFolder(PR_TRUE);
03219     imapUrl->AddChannelToLoadGroup();
03220     rv = SetImapUrlSink(anImapFolder, imapUrl);
03221     
03222     if (NS_SUCCEEDED(rv))
03223     {
03224       nsXPIDLCString folderName;
03225       GetFolderName(anImapFolder, getter_Copies(folderName));
03226       urlSpec.Append("/customKeywords>UID>");
03227       urlSpec.Append(char(hierarchySeparator));
03228       urlSpec.Append((const char *) folderName);
03229       urlSpec.Append(">");
03230       urlSpec.Append(uids);
03231       urlSpec.Append(">");
03232       urlSpec.Append(flagsToAdd);
03233       urlSpec.Append(">");
03234       urlSpec.Append(flagsToSubtract);
03235       rv = mailNewsUrl->SetSpec(urlSpec);
03236       if (NS_SUCCEEDED(rv))
03237         rv = GetImapConnectionAndLoadUrl(aClientEventQueue,
03238         imapUrl,
03239         nsnull,
03240         aURL);
03241     }
03242   } // if we have a url to run....
03243   
03244   return rv;
03245 }
03246 
03247 
03248 NS_IMETHODIMP
03249 nsImapService::DownloadMessagesForOffline(const char *messageIds, nsIMsgFolder *aFolder, nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow)
03250 {
03251   NS_ENSURE_ARG_POINTER(aFolder);
03252   NS_ENSURE_ARG_POINTER(messageIds);
03253   
03254   nsCOMPtr<nsIImapUrl> imapUrl;
03255   nsCAutoString urlSpec;
03256   nsresult rv;
03257   PRUnichar hierarchySeparator = GetHierarchyDelimiter(aFolder);
03258   rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aFolder, nsnull,
03259                             urlSpec, hierarchySeparator);
03260   if (NS_SUCCEEDED(rv) && imapUrl)
03261   {
03262     nsCOMPtr <nsIURI> runningURI;
03263     // need to pass in stream listener in order to get the channel created correctly
03264     nsCOMPtr<nsIImapMessageSink> imapMessageSink(do_QueryInterface(aFolder, &rv));
03265     rv = FetchMessage(imapUrl, nsImapUrl::nsImapMsgDownloadForOffline,aFolder, imapMessageSink, 
03266                         aMsgWindow, nsnull, messageIds, PR_FALSE, nsnull, getter_AddRefs(runningURI));
03267     if (runningURI && aUrlListener)
03268     {
03269       nsCOMPtr<nsIMsgMailNewsUrl> msgurl (do_QueryInterface(runningURI));
03270       if (msgurl)
03271         msgurl->RegisterListener(aUrlListener);
03272     }
03273   }
03274   return rv;
03275 }
03276 
03277 NS_IMETHODIMP
03278 nsImapService::MessageURIToMsgHdr(const char *uri, nsIMsgDBHdr **_retval)
03279 {
03280   NS_ENSURE_ARG_POINTER(uri);
03281   NS_ENSURE_ARG_POINTER(_retval);
03282 
03283   nsresult rv = NS_OK;
03284 
03285   nsCOMPtr<nsIMsgFolder> folder;
03286   nsMsgKey msgKey;
03287 
03288   rv = DecomposeImapURI(uri, getter_AddRefs(folder), &msgKey);
03289   NS_ENSURE_SUCCESS(rv,rv);
03290 
03291   rv = folder->GetMessageHeader(msgKey, _retval);
03292   NS_ENSURE_SUCCESS(rv,rv);
03293   return NS_OK;
03294 }
03295 
03296 NS_IMETHODIMP
03297 nsImapService::PlaybackAllOfflineOperations(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener, nsISupports **aResult)
03298 {
03299   NS_ENSURE_ARG_POINTER(aResult);
03300   nsresult rv;
03301   nsImapOfflineSync *goOnline = new nsImapOfflineSync(aMsgWindow, aListener, nsnull);
03302   if (goOnline)
03303   {
03304     rv = goOnline->QueryInterface(NS_GET_IID(nsISupports), (void **) aResult); 
03305     NS_ENSURE_SUCCESS(rv, rv);
03306     if (NS_SUCCEEDED(rv) && *aResult)
03307       return goOnline->ProcessNextOperation();
03308   }
03309   return NS_ERROR_OUT_OF_MEMORY;
03310 }
03311 
03312 NS_IMETHODIMP
03313 nsImapService::DownloadAllOffineImapFolders(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener)
03314 {
03315   nsImapOfflineDownloader *downloadForOffline = new nsImapOfflineDownloader(aMsgWindow, aListener);
03316   if (downloadForOffline)
03317   {
03318     // hold reference to this so it won't get deleted out from under itself.
03319     NS_ADDREF(downloadForOffline); 
03320     nsresult rv = downloadForOffline->ProcessNextOperation();
03321     NS_RELEASE(downloadForOffline);
03322     return rv;
03323   }
03324   return NS_ERROR_OUT_OF_MEMORY;
03325 }
03326 
03327 
03328 NS_IMETHODIMP nsImapService::GetCacheSession(nsICacheSession **result)
03329 {
03330   nsresult rv = NS_OK;
03331   if (!mCacheSession)
03332   {
03333     nsCOMPtr<nsICacheService> serv = do_GetService(kCacheServiceCID, &rv);
03334     NS_ENSURE_SUCCESS(rv, rv);
03335     
03336     rv = serv->CreateSession("IMAP-memory-only", nsICache::STORE_IN_MEMORY, nsICache::STREAM_BASED, getter_AddRefs(mCacheSession));
03337     NS_ENSURE_SUCCESS(rv, rv);
03338     rv = mCacheSession->SetDoomEntriesIfExpired(PR_FALSE);
03339   }
03340 
03341   *result = mCacheSession;
03342   NS_IF_ADDREF(*result);
03343   return rv;
03344 }
03345 
03346 NS_IMETHODIMP 
03347 nsImapService::HandleContent(const char * aContentType, nsIInterfaceRequestor* aWindowContext, nsIRequest *request)
03348 {
03349   nsresult rv;
03350   NS_ENSURE_ARG_POINTER(request);
03351   
03352   nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request, &rv);
03353   NS_ENSURE_SUCCESS(rv, rv);
03354 
03355   if (nsCRT::strcasecmp(aContentType, "x-application-imapfolder") == 0)
03356   {
03357     nsCOMPtr<nsIURI> uri;
03358     rv = aChannel->GetURI(getter_AddRefs(uri));
03359     NS_ENSURE_SUCCESS(rv, rv);
03360 
03361     if (uri)
03362     {
03363       request->Cancel(NS_BINDING_ABORTED);
03364       nsCOMPtr<nsIWindowMediator> mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
03365       NS_ENSURE_SUCCESS(rv, rv);
03366       nsCAutoString uriStr;
03367 
03368       uri->GetSpec(uriStr);
03369 
03370       // imap uri's are unescaped, so unescape the url.
03371       NS_UnescapeURL(uriStr);
03372       nsCOMPtr <nsIMessengerWindowService> messengerWindowService = do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID,&rv);
03373       NS_ENSURE_SUCCESS(rv, rv);
03374 
03375       rv = messengerWindowService->OpenMessengerWindowWithUri("mail:3pane", uriStr.get(), nsMsgKey_None);
03376       NS_ENSURE_SUCCESS(rv, rv);
03377     }
03378   } else {
03379     // The content-type was not x-application-imapfolder
03380     return NS_ERROR_WONT_HANDLE_CONTENT;
03381   }
03382 
03383   return rv;
03384 }
03385