/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "msgCore.h" // precompiled header... #include "nsMsgImapCID.h" #include "netCore.h" #include "nsIServiceManager.h" #include "nsIComponentManager.h" #include "nsIIMAPHostSessionList.h" #include "nsImapService.h" #include "nsImapUrl.h" #include "nsCOMPtr.h" #include "nsIMsgFolder.h" #include "nsIMsgImapMailFolder.h" #include "nsIImapIncomingServer.h" #include "nsIImapServerSink.h" #include "nsIImapMockChannel.h" #include "nsImapUtils.h" #include "nsIDocShell.h" #include "nsIDocShellLoadInfo.h" #include "nsIRDFService.h" #include "nsIEventQueueService.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsRDFCID.h" #include "nsEscape.h" #include "nsIMsgStatusFeedback.h" #include "nsIPrefBranch.h" #include "nsIPrefService.h" #include "nsILoadGroup.h" #include "nsIMsgAccountManager.h" #include "nsMsgBaseCID.h" #include "nsMsgFolderFlags.h" #include "nsISubscribableServer.h" #include "nsIDirectoryService.h" #include "nsAppDirectoryServiceDefs.h" #include "nsIWebNavigation.h" #include "nsImapStringBundle.h" #include "plbase64.h" #include "nsImapOfflineSync.h" #include "nsIMsgHdr.h" #include "nsMsgUtils.h" #include "nsICacheService.h" #include "nsIStreamListenerTee.h" #include "nsNetCID.h" #include "nsMsgI18N.h" #include "nsIOutputStream.h" #include "nsIInputStream.h" #include "nsICopyMsgStreamListener.h" #include "nsIFileStream.h" #include "nsIMsgParseMailMsgState.h" #include "nsMsgLocalCID.h" #include "nsIOutputStream.h" #include "nsIDocShell.h" #include "nsIDocShellLoadInfo.h" #include "nsIDOMWindowInternal.h" #include "nsIMessengerWindowService.h" #include "nsIWindowMediator.h" #include "nsIPrompt.h" #include "nsIWindowWatcher.h" #include "nsImapProtocol.h" #include "nsIMsgMailSession.h" #include "nsIStreamConverterService.h" #include "nsNetUtil.h" #include "nsInt64.h" #define PREF_MAIL_ROOT_IMAP "mail.root.imap" // old - for backward compatibility only #define PREF_MAIL_ROOT_IMAP_REL "mail.root.imap-rel" static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kImapUrlCID, NS_IMAPURL_CID); static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID); static const char sequenceString[] = "SEQUENCE"; static const char uidString[] = "UID"; static PRBool gInitialized = PR_FALSE; static PRInt32 gMIMEOnDemandThreshold = 15000; static PRBool gMIMEOnDemand = PR_FALSE; NS_IMPL_THREADSAFE_ADDREF(nsImapService) NS_IMPL_THREADSAFE_RELEASE(nsImapService) NS_IMPL_QUERY_INTERFACE6(nsImapService, nsIImapService, nsIMsgMessageService, nsIProtocolHandler, nsIMsgProtocolInfo, nsIMsgMessageFetchPartService, nsIContentHandler) nsImapService::nsImapService() { mPrintingOperation = PR_FALSE; if (!gInitialized) { nsresult rv; nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv) && prefBranch) { prefBranch->GetBoolPref("mail.imap.mime_parts_on_demand", &gMIMEOnDemand); prefBranch->GetIntPref("mail.imap.mime_parts_on_demand_threshold", &gMIMEOnDemandThreshold); } gInitialized = PR_TRUE; } } nsImapService::~nsImapService() { } PRUnichar nsImapService::GetHierarchyDelimiter(nsIMsgFolder* aMsgFolder) { PRUnichar delimiter = '/'; if (aMsgFolder) { nsCOMPtr imapFolder = do_QueryInterface(aMsgFolder); if (imapFolder) imapFolder->GetHierarchyDelimiter(&delimiter); } return delimiter; } // N.B., this returns an escaped folder name, appropriate for putting in a url. nsresult nsImapService::GetFolderName(nsIMsgFolder* aImapFolder, char **folderName) { nsresult rv; nsCOMPtr aFolder(do_QueryInterface(aImapFolder, &rv)); if (NS_FAILED(rv)) return rv; nsXPIDLCString onlineName; // online name is in imap utf-7 - leave it that way rv = aFolder->GetOnlineName(getter_Copies(onlineName)); if (NS_FAILED(rv)) return rv; if (onlineName.IsEmpty()) { char *uri = nsnull; rv = aImapFolder->GetURI(&uri); if (NS_FAILED(rv)) return rv; char * hostname = nsnull; rv = aImapFolder->GetHostname(&hostname); if (NS_FAILED(rv)) return rv; rv = nsImapURI2FullName(kImapRootURI, hostname, uri, getter_Copies(onlineName)); PR_Free(uri); PR_Free(hostname); } // if the hierarchy delimiter is not '/', then we want to escape slashes; // otherwise, we do want to escape slashes. // we want to escape slashes and '^' first, otherwise, nsEscape will lose them PRBool escapeSlashes = (GetHierarchyDelimiter(aImapFolder) != (PRUnichar) '/'); if (escapeSlashes && (const char *) onlineName) { char* escapedOnlineName; rv = nsImapUrl::EscapeSlashes((const char *) onlineName, &escapedOnlineName); if (NS_SUCCEEDED(rv)) onlineName.Adopt(escapedOnlineName); } // need to escape everything else *folderName = nsEscape((const char *) onlineName, url_Path); return rv; } NS_IMETHODIMP nsImapService::SelectFolder(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI ** aURL) { NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; if (WeAreOffline()) return NS_MSG_ERROR_OFFLINE; PRBool canOpenThisFolder = PR_TRUE; nsCOMPtr imapFolder = do_QueryInterface(aImapMailFolder); if (imapFolder) imapFolder->GetCanIOpenThisFolder(&canOpenThisFolder); if (!canOpenThisFolder) return NS_OK; nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { // nsImapUrl::SetSpec() will set the imap action properly rv = imapUrl->SetImapAction(nsIImapUrl::nsImapSelectFolder); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); // if no msg window, we won't put up error messages (this is almost certainly a biff-inspired get new msgs) if (!aMsgWindow) mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE); mailNewsUrl->SetMsgWindow(aMsgWindow); mailNewsUrl->SetUpdatingFolder(PR_TRUE); imapUrl->AddChannelToLoadGroup(); rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append("/select>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); rv = mailNewsUrl->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } // if we have a url to run.... return rv; } // lite select, used to verify UIDVALIDITY while going on/offline NS_IMETHODIMP nsImapService::LiteSelectFolder(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/liteselect>", nsIImapUrl::nsImapLiteSelectFolder, aURL); } NS_IMETHODIMP nsImapService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL, nsIMsgWindow *aMsgWindow) { nsresult rv = NS_OK; if (PL_strstr(aMessageURI, "&type=application/x-message-display")) return NS_NewURI(aURL, aMessageURI); nsCOMPtr folder; nsXPIDLCString msgKey; rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, nsnull, urlSpec, hierarchySeparator); NS_ENSURE_SUCCESS(rv, rv); rv = SetImapUrlSink(folder, imapUrl); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr mailnewsUrl = do_QueryInterface(imapUrl); PRBool useLocalCache = PR_FALSE; folder->HasMsgOffline(atoi(msgKey), &useLocalCache); mailnewsUrl->SetMsgIsInLocalCache(useLocalCache); nsCOMPtr url = do_QueryInterface(imapUrl); url->GetSpec(urlSpec); urlSpec.Append("fetch>UID>"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(folder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(msgKey); rv = url->SetSpec(urlSpec); imapUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) aURL); } return rv; } NS_IMETHODIMP nsImapService::OpenAttachment(const char *aContentType, const char *aFileName, const char *aUrl, const char *aMessageUri, nsISupports *aDisplayConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener) { nsresult rv = NS_OK; // okay this is a little tricky....we may have to fetch the mime part // or it may already be downloaded for us....the only way i can tell to // distinguish the two events is to search for ?section or ?part nsCAutoString uri(aMessageUri); nsCAutoString urlString(aUrl); urlString.ReplaceSubstring("/;section", "?section"); // more stuff i don't understand PRInt32 sectionPos = urlString.Find("?section"); // if we have a section field then we must be dealing with a mime part we need to fetchf if (sectionPos > 0) { nsCAutoString mimePart; urlString.Right(mimePart, urlString.Length() - sectionPos); uri.Append(mimePart); uri += "&type="; uri += aContentType; uri += "&filename="; uri += aFileName; } else { // try to extract the specific part number out from the url string uri += "?"; const char *part = PL_strstr(aUrl, "part="); uri += part; uri += "&type="; uri += aContentType; uri += "&filename="; uri += aFileName; } nsCOMPtr folder; nsXPIDLCString msgKey; nsXPIDLCString uriMimePart; nsCAutoString folderURI; nsMsgKey key; rv = DecomposeImapURI(uri.get(), getter_AddRefs(folder), getter_Copies(msgKey)); rv = nsParseImapMessageURI(uri.get(), folderURI, &key, getter_Copies(uriMimePart)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(uri.get(), getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); if (NS_FAILED(rv)) return rv; urlSpec.Append("/fetch>UID>"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(folder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(msgKey.get()); urlSpec.Append(uriMimePart.get()); if (uriMimePart) { nsCOMPtr mailUrl (do_QueryInterface(imapUrl)); if (mailUrl) { mailUrl->SetSpec(urlSpec); mailUrl->SetFileName(nsDependentCString(aFileName)); } rv = FetchMimePart(imapUrl, nsIImapUrl::nsImapOpenMimePart, folder, imapMessageSink, nsnull, aDisplayConsumer, msgKey, uriMimePart); } } // if we got a message sink } // if we parsed the message uri return rv; } NS_IMETHODIMP nsImapService::FetchMimePart(nsIURI *aURI, const char *aMessageURI, nsISupports *aDisplayConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIURI **aURL) { nsresult rv = NS_OK; nsCOMPtr folder; nsXPIDLCString msgKey; nsXPIDLCString mimePart; nsCAutoString folderURI; nsMsgKey key; rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey)); rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl = do_QueryInterface(aURI); nsCOMPtr msgurl (do_QueryInterface(aURI)); msgurl->SetMsgWindow(aMsgWindow); msgurl->RegisterListener(aUrlListener); if (mimePart) { return FetchMimePart(imapUrl, nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink, aURL, aDisplayConsumer, msgKey, mimePart); } } } return rv; } NS_IMETHODIMP nsImapService::DisplayMessage(const char* aMessageURI, nsISupports * aDisplayConsumer, nsIMsgWindow * aMsgWindow, nsIUrlListener * aUrlListener, const char * aCharsetOverride, nsIURI ** aURL) { nsresult rv = NS_OK; nsCOMPtr folder; nsXPIDLCString msgKey; nsXPIDLCString mimePart; nsCAutoString folderURI; nsMsgKey key; nsCAutoString messageURI(aMessageURI); PRInt32 typeIndex = messageURI.Find("&type=application/x-message-display"); if (typeIndex != kNotFound) { // This happens with forward inline of a message/rfc822 attachment opened in // a standalone msg window. // So, just cut to the chase and call AsyncOpen on a channel. nsCOMPtr uri; messageURI.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1); rv = NS_NewURI(getter_AddRefs(uri), messageURI.get()); NS_ENSURE_SUCCESS(rv, rv); if (aURL) NS_IF_ADDREF(*aURL = uri); nsCOMPtr aStreamListener = do_QueryInterface(aDisplayConsumer, &rv); if (NS_SUCCEEDED(rv) && aStreamListener) { nsCOMPtr aChannel; nsCOMPtr aLoadGroup; nsCOMPtr mailnewsUrl = do_QueryInterface(uri, &rv); if (NS_SUCCEEDED(rv) && mailnewsUrl) mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup)); rv = NewChannel(uri, getter_AddRefs(aChannel)); if (NS_FAILED(rv)) return rv; nsCOMPtr aCtxt = do_QueryInterface(uri); // now try to open the channel passing in our display consumer as the listener return aChannel->AsyncOpen(aStreamListener, aCtxt); } } rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey)); if (msgKey.IsEmpty()) return NS_MSG_MESSAGE_NOT_FOUND; rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); if (NS_FAILED(rv)) return rv; if (mimePart) { return FetchMimePart(imapUrl, nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink, aURL, aDisplayConsumer, msgKey, mimePart); } nsCOMPtr msgurl (do_QueryInterface(imapUrl)); nsCOMPtr i18nurl (do_QueryInterface(imapUrl)); i18nurl->SetCharsetOverRide(aCharsetOverride); PRUint32 messageSize; PRBool useMimePartsOnDemand = gMIMEOnDemand; PRBool shouldStoreMsgOffline = PR_FALSE; PRBool hasMsgOffline = PR_FALSE; nsCOMPtr aMsgIncomingServer; if (imapMessageSink) imapMessageSink->GetMessageSizeFromDB(msgKey, PR_TRUE, &messageSize); msgurl->SetMsgWindow(aMsgWindow); rv = msgurl->GetServer(getter_AddRefs(aMsgIncomingServer)); if (NS_SUCCEEDED(rv) && aMsgIncomingServer) { nsCOMPtr aImapServer(do_QueryInterface(aMsgIncomingServer, &rv)); if (NS_SUCCEEDED(rv) && aImapServer) aImapServer->GetMimePartsOnDemand(&useMimePartsOnDemand); } nsCAutoString uriStr(aMessageURI); PRInt32 keySeparator = uriStr.RFindChar('#'); if(keySeparator != -1) { PRInt32 keyEndSeparator = uriStr.FindCharInSet("/?&", keySeparator); PRInt32 mpodFetchPos = uriStr.Find("fetchCompleteMessage=true", PR_FALSE, keyEndSeparator); if (mpodFetchPos != -1) useMimePartsOnDemand = PR_FALSE; } if (folder) { folder->ShouldStoreMsgOffline(key, &shouldStoreMsgOffline); folder->HasMsgOffline(key, &hasMsgOffline); } if (!useMimePartsOnDemand || (messageSize < (uint32) gMIMEOnDemandThreshold)) // allowedToBreakApart && // !GetShouldFetchAllParts() && // GetServerStateParser().ServerHasIMAP4Rev1Capability() && { imapUrl->SetFetchPartsOnDemand(PR_FALSE); // for now, lets try not adding these msgurl->SetAddToMemoryCache(PR_TRUE); } else { // whenever we are displaying a message, we want to add it to the memory cache.. imapUrl->SetFetchPartsOnDemand(PR_TRUE); // if we happen to fetch the whole message, note in the url // whether we want to store this message offline. imapUrl->SetShouldStoreMsgOffline(shouldStoreMsgOffline); shouldStoreMsgOffline = PR_FALSE; // if we're fetching by parts, don't store offline msgurl->SetAddToMemoryCache(PR_FALSE); } if (imapMessageSink && !hasMsgOffline) imapMessageSink->SetNotifyDownloadedLines(shouldStoreMsgOffline); if (hasMsgOffline) msgurl->SetMsgIsInLocalCache(PR_TRUE); nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); PRBool forcePeek = PR_FALSE; // should the message fetch force a peak or a traditional fetch? if (NS_SUCCEEDED(rv) && prefBranch) prefBranch->GetBoolPref("mailnews.mark_message_read.delay", &forcePeek); rv = FetchMessage(imapUrl, forcePeek ? nsIImapUrl::nsImapMsgFetchPeek : nsIImapUrl::nsImapMsgFetch, folder, imapMessageSink, aMsgWindow, aDisplayConsumer, msgKey, PR_FALSE, (mPrintingOperation) ? "print" : nsnull, aURL); } } return rv; } nsresult nsImapService::FetchMimePart(nsIImapUrl * aImapUrl, nsImapAction aImapAction, nsIMsgFolder * aImapMailFolder, nsIImapMessageSink * aImapMessage, nsIURI ** aURL, nsISupports * aDisplayConsumer, const char *messageIdentifierList, const char *mimePart) { nsresult rv = NS_OK; // create a protocol instance to handle the request. // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now // just create a connection and process the request. NS_ASSERTION (aImapUrl && aImapMailFolder && aImapMessage,"Oops ... null pointer"); if (!aImapUrl || !aImapMailFolder || !aImapMessage) return NS_ERROR_NULL_POINTER; nsCAutoString urlSpec; rv = SetImapUrlSink(aImapMailFolder, aImapUrl); nsImapAction actionToUse = aImapAction; if (actionToUse == nsImapUrl::nsImapOpenMimePart) actionToUse = nsIImapUrl::nsImapMsgFetch; nsCOMPtr msgurl (do_QueryInterface(aImapUrl)); if (aImapMailFolder && msgurl && messageIdentifierList) { PRBool useLocalCache = PR_FALSE; aImapMailFolder->HasMsgOffline(atoi(messageIdentifierList), &useLocalCache); msgurl->SetMsgIsInLocalCache(useLocalCache); } rv = aImapUrl->SetImapMessageSink(aImapMessage); if (NS_SUCCEEDED(rv)) { nsCOMPtr url = do_QueryInterface(aImapUrl); url->GetSpec(urlSpec); // rhp: If we are displaying this message for the purpose of printing, we // need to append the header=print option. // if (mPrintingOperation) urlSpec.Append("?header=print"); // mscott - this cast to a char * is okay...there's a bug in the XPIDL // compiler that is preventing in string parameters from showing up as // const char *. hopefully they will fix it soon. rv = url->SetSpec(urlSpec); rv = aImapUrl->SetImapAction(actionToUse /* nsIImapUrl::nsImapMsgFetch */); if (aImapMailFolder && aDisplayConsumer) { nsCOMPtr aMsgIncomingServer; rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer)); if (NS_SUCCEEDED(rv) && aMsgIncomingServer) { PRBool interrupted; nsCOMPtr aImapServer(do_QueryInterface(aMsgIncomingServer, &rv)); if (NS_SUCCEEDED(rv) && aImapServer) aImapServer->PseudoInterruptMsgLoad(aImapMailFolder, nsnull, &interrupted); } } // if the display consumer is a docshell, then we should run the url in the docshell. // otherwise, it should be a stream listener....so open a channel using AsyncRead // and the provided stream listener.... nsCOMPtr docShell(do_QueryInterface(aDisplayConsumer, &rv)); if (NS_SUCCEEDED(rv) && docShell) { nsCOMPtr loadInfo; // DIRTY LITTLE HACK --> if we are opening an attachment we want the docshell to // treat this load as if it were a user click event. Then the dispatching stuff will be much // happier. if (aImapAction == nsImapUrl::nsImapOpenMimePart) { docShell->CreateLoadInfo(getter_AddRefs(loadInfo)); loadInfo->SetLoadType(nsIDocShellLoadInfo::loadLink); } rv = docShell->LoadURI(url, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE); } else { nsCOMPtr aStreamListener = do_QueryInterface(aDisplayConsumer, &rv); if (NS_SUCCEEDED(rv) && aStreamListener) { nsCOMPtr aChannel; nsCOMPtr aLoadGroup; nsCOMPtr mailnewsUrl = do_QueryInterface(aImapUrl, &rv); if (NS_SUCCEEDED(rv) && mailnewsUrl) mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup)); rv = NewChannel(url, getter_AddRefs(aChannel)); if (NS_FAILED(rv)) return rv; nsCOMPtr aCtxt = do_QueryInterface(url); // now try to open the channel passing in our display consumer as the listener rv = aChannel->AsyncOpen(aStreamListener, aCtxt); } else // do what we used to do before { // I'd like to get rid of this code as I believe that we always get a docshell // or stream listener passed into us in this method but i'm not sure yet... // I'm going to use an assert for now to figure out if this is ever getting called #if defined(DEBUG_mscott) || defined(DEBUG_bienvenu) NS_ASSERTION(0, "oops...someone still is reaching this part of the code"); #endif nsCOMPtr queue; // get the Event Queue for this thread... nsCOMPtr pEventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue)); if (NS_FAILED(rv)) return rv; rv = GetImapConnectionAndLoadUrl(queue, aImapUrl, aDisplayConsumer, aURL); } } } return rv; } // // rhp: Right now, this is the same as simple DisplayMessage, but it will change // to support print rendering. // NS_IMETHODIMP nsImapService::DisplayMessageForPrinting(const char* aMessageURI, nsISupports * aDisplayConsumer, nsIMsgWindow * aMsgWindow, nsIUrlListener * aUrlListener, nsIURI ** aURL) { mPrintingOperation = PR_TRUE; nsresult rv = DisplayMessage(aMessageURI, aDisplayConsumer, aMsgWindow, aUrlListener, nsnull, aURL); mPrintingOperation = PR_FALSE; return rv; } NS_IMETHODIMP nsImapService::CopyMessage(const char * aSrcMailboxURI, nsIStreamListener * aMailboxCopy, PRBool moveMessage, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL) { nsresult rv = NS_ERROR_NULL_POINTER; nsCOMPtr streamSupport; if (!aSrcMailboxURI || !aMailboxCopy) return rv; streamSupport = do_QueryInterface(aMailboxCopy, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr folder; nsXPIDLCString msgKey; rv = DecomposeImapURI(aSrcMailboxURI, getter_AddRefs(folder), getter_Copies(msgKey)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); PRBool hasMsgOffline = PR_FALSE; nsMsgKey key = atoi(msgKey); rv = CreateStartOfImapUrl(aSrcMailboxURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); if (folder) { nsCOMPtr msgurl (do_QueryInterface(imapUrl)); folder->HasMsgOffline(key, &hasMsgOffline); if (msgurl) msgurl->SetMsgIsInLocalCache(hasMsgOffline); } // now try to download the message nsImapAction imapAction = nsIImapUrl::nsImapOnlineToOfflineCopy; if (moveMessage) imapAction = nsIImapUrl::nsImapOnlineToOfflineMove; rv = FetchMessage(imapUrl,imapAction, folder, imapMessageSink,aMsgWindow, streamSupport, msgKey, PR_FALSE, nsnull, aURL); } // if we got an imap message sink } // if we decomposed the imap message return rv; } NS_IMETHODIMP nsImapService::CopyMessages(nsMsgKeyArray *keys, nsIMsgFolder *srcFolder, nsIStreamListener *aMailboxCopy, PRBool moveMessage, nsIUrlListener * aUrlListener, nsIMsgWindow *aMsgWindow, nsIURI **aURL) { nsresult rv = NS_OK; nsCOMPtr streamSupport; if (!keys || !aMailboxCopy) return NS_ERROR_NULL_POINTER; streamSupport = do_QueryInterface(aMailboxCopy, &rv); if (!streamSupport || NS_FAILED(rv)) return rv; nsCOMPtr folder = srcFolder; nsXPIDLCString msgKey; if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { // we generate the uri for the first message so that way on down the line, // GetMessage in nsCopyMessageStreamListener will get an unescaped username // and be able to find the msg hdr. See bug 259656 for details nsXPIDLCString uri; srcFolder->GenerateMessageURI(keys->GetAt(0), getter_Copies(uri)); nsCString messageIds; PRUint32 numKeys = keys->GetSize(); AllocateImapUidString(keys->GetArray(), numKeys, nsnull, messageIds); nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(uri, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); nsImapAction action; if (moveMessage) action = nsIImapUrl::nsImapOnlineToOfflineMove; else action = nsIImapUrl::nsImapOnlineToOfflineCopy; imapUrl->SetCopyState(aMailboxCopy); // now try to display the message rv = FetchMessage(imapUrl, action, folder, imapMessageSink, aMsgWindow, streamSupport, messageIds.get(), PR_FALSE, nsnull, aURL); // ### end of copy operation should know how to do the delete.if this is a move } // if we got an imap message sink } // if we decomposed the imap message return rv; } NS_IMETHODIMP nsImapService::Search(nsIMsgSearchSession *aSearchSession, nsIMsgWindow *aMsgWindow, nsIMsgFolder *aMsgFolder, const char *aSearchUri) { nsresult rv = NS_OK; nsCAutoString folderURI; nsCOMPtr imapUrl; nsCOMPtr urlListener = do_QueryInterface(aSearchSession); nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aMsgFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aMsgFolder, urlListener, urlSpec, hierarchySeparator); if (NS_FAILED(rv)) return rv; nsCOMPtr msgurl (do_QueryInterface(imapUrl)); msgurl->SetMsgWindow(aMsgWindow); msgurl->SetSearchSession(aSearchSession); imapUrl->AddChannelToLoadGroup(); rv = SetImapUrlSink(aMsgFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsXPIDLCString folderName; GetFolderName(aMsgFolder, getter_Copies(folderName)); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); if (!aMsgWindow) mailNewsUrl->SetSuppressErrorMsgs(PR_TRUE); urlSpec.Append("/search>UID>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); urlSpec.Append('>'); // escape aSearchUri so that IMAP special characters (i.e. '\') // won't be replaced with '/' in NECKO. // it will be unescaped in nsImapUrl::ParseUrl(). char *search_cmd = nsEscape((char *)aSearchUri, url_XAlphas); urlSpec.Append(search_cmd); nsCRT::free(search_cmd); rv = mailNewsUrl->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) { nsCOMPtr queue; // get the Event Queue for this thread... nsCOMPtr pEventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue)); if (NS_FAILED(rv)) return rv; rv = GetImapConnectionAndLoadUrl(queue, imapUrl, nsnull, nsnull); } } return rv; } // just a helper method to break down imap message URIs.... nsresult nsImapService::DecomposeImapURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey) { NS_ENSURE_ARG_POINTER(aMessageURI); NS_ENSURE_ARG_POINTER(aFolder); NS_ENSURE_ARG_POINTER(aMsgKey); nsresult rv = NS_OK; nsCAutoString folderURI; rv = nsParseImapMessageURI(aMessageURI, folderURI, aMsgKey, nsnull); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr rdf = do_GetService("@mozilla.org/rdf/rdf-service;1",&rv); NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr res; rv = rdf->GetResource(folderURI, getter_AddRefs(res)); NS_ENSURE_SUCCESS(rv,rv); rv = res->QueryInterface(NS_GET_IID(nsIMsgFolder), (void **) aFolder); NS_ENSURE_SUCCESS(rv,rv); return NS_OK; } // just a helper method to break down imap message URIs.... nsresult nsImapService::DecomposeImapURI(const char * aMessageURI, nsIMsgFolder ** aFolder, char ** aMsgKey) { nsMsgKey msgKey; nsresult rv; rv = DecomposeImapURI(aMessageURI, aFolder, &msgKey); NS_ENSURE_SUCCESS(rv,rv); if (msgKey) { nsCAutoString messageIdString; messageIdString.AppendInt(msgKey); *aMsgKey = ToNewCString(messageIdString); } return rv; } NS_IMETHODIMP nsImapService::SaveMessageToDisk(const char *aMessageURI, nsIFileSpec *aFile, PRBool aAddDummyEnvelope, nsIUrlListener *aUrlListener, nsIURI **aURL, PRBool canonicalLineEnding, nsIMsgWindow *aMsgWindow) { nsresult rv = NS_OK; nsCOMPtr folder; nsCOMPtr imapUrl; nsXPIDLCString msgKey; rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey)); if (NS_FAILED(rv)) return rv; PRBool hasMsgOffline = PR_FALSE; if (folder) folder->HasMsgOffline(atoi(msgKey), &hasMsgOffline); nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_FAILED(rv)) return rv; nsCOMPtr msgUrl = do_QueryInterface(imapUrl, &rv); if (NS_FAILED(rv)) return rv; msgUrl->SetMessageFile(aFile); msgUrl->SetAddDummyEnvelope(aAddDummyEnvelope); msgUrl->SetCanonicalLineEnding(canonicalLineEnding); nsCOMPtr mailnewsUrl = do_QueryInterface(msgUrl); if (mailnewsUrl) mailnewsUrl->SetMsgIsInLocalCache(hasMsgOffline); nsCOMPtr saveAsListener; mailnewsUrl->GetSaveAsListener(aAddDummyEnvelope, aFile, getter_AddRefs(saveAsListener)); return FetchMessage(imapUrl, nsIImapUrl::nsImapSaveMessageToDisk, folder, imapMessageSink, aMsgWindow, saveAsListener, msgKey, PR_FALSE, nsnull, aURL); } return rv; } /* fetching RFC822 messages */ /* imap4://HOST>fetch>>MAILBOXPATH>x */ /* 'x' is the message UID */ /* will set the 'SEEN' flag */ NS_IMETHODIMP nsImapService::FetchMessage(nsIImapUrl * aImapUrl, nsImapAction aImapAction, nsIMsgFolder * aImapMailFolder, nsIImapMessageSink * aImapMessage, nsIMsgWindow *aMsgWindow, nsISupports * aDisplayConsumer, const char *messageIdentifierList, PRBool aConvertDataToText, const char *aAdditionalHeader, nsIURI ** aURL) { // create a protocol instance to handle the request. NS_ASSERTION (aImapUrl && aImapMailFolder && aImapMessage,"Oops ... null pointer"); if (!aImapUrl || !aImapMailFolder || !aImapMessage) return NS_ERROR_NULL_POINTER; nsresult rv = NS_OK; nsCOMPtr url = do_QueryInterface(aImapUrl); if (WeAreOffline()) { nsCOMPtr msgurl (do_QueryInterface(aImapUrl)); if (msgurl) { PRBool msgIsInLocalCache = PR_FALSE; msgurl->GetMsgIsInLocalCache(&msgIsInLocalCache); if (!msgIsInLocalCache) { nsCOMPtr server; rv = aImapMailFolder->GetServer(getter_AddRefs(server)); if (server && aDisplayConsumer) rv = server->DisplayOfflineMsg(aMsgWindow); return rv; } } } if (aURL) { *aURL = url; NS_IF_ADDREF(*aURL); } nsCAutoString urlSpec; rv = SetImapUrlSink(aImapMailFolder, aImapUrl); rv = aImapUrl->SetImapMessageSink(aImapMessage); url->GetSpec(urlSpec); PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); urlSpec.Append("fetch>UID>"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(messageIdentifierList); if (aAdditionalHeader) { urlSpec.Append("?header="); urlSpec.Append(aAdditionalHeader); } rv = url->SetSpec(urlSpec); rv = aImapUrl->SetImapAction(aImapAction); // if the display consumer is a docshell, then we should run the url in the docshell. // otherwise, it should be a stream listener....so open a channel using AsyncRead // and the provided stream listener.... nsCOMPtr docShell(do_QueryInterface(aDisplayConsumer, &rv)); if (aImapMailFolder && docShell) { nsCOMPtr aMsgIncomingServer; rv = aImapMailFolder->GetServer(getter_AddRefs(aMsgIncomingServer)); if (NS_SUCCEEDED(rv) && aMsgIncomingServer) { PRBool interrupted; nsCOMPtr aImapServer(do_QueryInterface(aMsgIncomingServer, &rv)); if (NS_SUCCEEDED(rv) && aImapServer) aImapServer->PseudoInterruptMsgLoad(aImapMailFolder, aMsgWindow, &interrupted); } } if (NS_SUCCEEDED(rv) && docShell) { NS_ASSERTION(!aConvertDataToText, "can't convert to text when using docshell"); rv = docShell->LoadURI(url, nsnull, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE); } else { nsCOMPtr streamListener = do_QueryInterface(aDisplayConsumer, &rv); nsCOMPtr mailnewsUrl = do_QueryInterface(aImapUrl, &rv); if (aMsgWindow && mailnewsUrl) mailnewsUrl->SetMsgWindow(aMsgWindow); if (NS_SUCCEEDED(rv) && streamListener) { nsCOMPtr channel; nsCOMPtr loadGroup; if (NS_SUCCEEDED(rv) && mailnewsUrl) mailnewsUrl->GetLoadGroup(getter_AddRefs(loadGroup)); rv = NewChannel(url, getter_AddRefs(channel)); if (NS_FAILED(rv)) return rv; rv = channel->SetLoadGroup(loadGroup); if (NS_FAILED(rv)) return rv; if (aConvertDataToText) { nsCOMPtr conversionListener; nsCOMPtr streamConverter = do_GetService("@mozilla.org/streamConverters;1", &rv); NS_ENSURE_SUCCESS(rv, rv); rv = streamConverter->AsyncConvertData("message/rfc822", "*/*", streamListener, channel, getter_AddRefs(conversionListener)); NS_ENSURE_SUCCESS(rv, rv); streamListener = conversionListener; // this is our new listener. } nsCOMPtr aCtxt = do_QueryInterface(url); // now try to open the channel passing in our display consumer as the listener rv = channel->AsyncOpen(streamListener, aCtxt); } else // do what we used to do before { // I'd like to get rid of this code as I believe that we always get a docshell // or stream listener passed into us in this method but i'm not sure yet... // I'm going to use an assert for now to figure out if this is ever getting called #if defined(DEBUG_mscott) || defined(DEBUG_bienvenu) NS_ASSERTION(0, "oops...someone still is reaching this part of the code"); #endif nsCOMPtr queue; // get the Event Queue for this thread... nsCOMPtr pEventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue)); if (NS_FAILED(rv)) return rv; rv = GetImapConnectionAndLoadUrl(queue, aImapUrl, aDisplayConsumer, aURL); } } return rv; } // this method streams a message to the passed in consumer, with an optional stream converter // and additional header (e.g., "header=filter") NS_IMETHODIMP nsImapService::StreamMessage(const char *aMessageURI, nsISupports *aConsumer, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, PRBool aConvertData, const char *aAdditionalHeader, nsIURI **aURL) { nsCOMPtr folder; nsXPIDLCString msgKey; nsXPIDLCString mimePart; nsCAutoString folderURI; nsMsgKey key; nsresult rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey)); if (msgKey.IsEmpty()) return NS_MSG_MESSAGE_NOT_FOUND; rv = nsParseImapMessageURI(aMessageURI, folderURI, &key, getter_Copies(mimePart)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapMessageSink(do_QueryInterface(folder, &rv)); if (NS_SUCCEEDED(rv)) { nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(aMessageURI, getter_AddRefs(imapUrl), folder, aUrlListener, urlSpec, hierarchySeparator); if (NS_FAILED(rv)) return rv; nsCOMPtr msgurl (do_QueryInterface(imapUrl)); PRBool shouldStoreMsgOffline = PR_FALSE; PRBool hasMsgOffline = PR_FALSE; nsCOMPtr aMsgIncomingServer; msgurl->SetMsgWindow(aMsgWindow); rv = msgurl->GetServer(getter_AddRefs(aMsgIncomingServer)); if (folder) { folder->ShouldStoreMsgOffline(key, &shouldStoreMsgOffline); folder->HasMsgOffline(key, &hasMsgOffline); } imapUrl->SetFetchPartsOnDemand(PR_FALSE); msgurl->SetAddToMemoryCache(PR_TRUE); if (imapMessageSink) imapMessageSink->SetNotifyDownloadedLines(shouldStoreMsgOffline); if (hasMsgOffline) msgurl->SetMsgIsInLocalCache(PR_TRUE); rv = FetchMessage(imapUrl, nsIImapUrl::nsImapMsgFetchPeek, folder, imapMessageSink, aMsgWindow, aConsumer, msgKey, aConvertData, aAdditionalHeader, aURL); } } return rv; } nsresult nsImapService::CreateStartOfImapUrl(const char * aImapURI, nsIImapUrl ** imapUrl, nsIMsgFolder* aImapMailFolder, nsIUrlListener * aUrlListener, nsCString & urlSpec, PRUnichar &hierarchyDelimiter) { nsresult rv = NS_OK; char *hostname = nsnull; nsXPIDLCString username; nsXPIDLCString escapedUsername; rv = aImapMailFolder->GetHostname(&hostname); if (NS_FAILED(rv)) return rv; rv = aImapMailFolder->GetUsername(getter_Copies(username)); if (NS_FAILED(rv)) { PR_Free(hostname); return rv; } if (((const char*)username) && username[0]) *((char **)getter_Copies(escapedUsername)) = nsEscape(username, url_XAlphas); PRInt32 port = IMAP_PORT; nsCOMPtr server; rv = aImapMailFolder->GetServer(getter_AddRefs(server)); if (NS_SUCCEEDED(rv)) { server->GetPort(&port); if (port == -1 || port == 0) port = IMAP_PORT; } // now we need to create an imap url to load into the connection. The url // needs to represent a select folder action. rv = CallCreateInstance(kImapUrlCID, imapUrl); if (NS_SUCCEEDED(rv) && *imapUrl) { nsCOMPtr mailnewsUrl = do_QueryInterface(*imapUrl, &rv); if (NS_SUCCEEDED(rv) && mailnewsUrl && aUrlListener) mailnewsUrl->RegisterListener(aUrlListener); nsCOMPtr msgurl(do_QueryInterface(*imapUrl)); (*imapUrl)->SetExternalLinkUrl(PR_FALSE); msgurl->SetUri(aImapURI); urlSpec = "imap://"; urlSpec.Append((const char *) escapedUsername); urlSpec.Append('@'); urlSpec.Append(hostname); urlSpec.Append(':'); urlSpec.AppendInt(port); // *** jefft - force to parse the urlSpec in order to search for // the correct incoming server // mscott - this cast to a char * is okay...there's a bug in the XPIDL // compiler that is preventing in string parameters from showing up as // const char *. hopefully they will fix it soon. rv = mailnewsUrl->SetSpec(urlSpec); hierarchyDelimiter = kOnlineHierarchySeparatorUnknown; nsCOMPtr imapFolder = do_QueryInterface(aImapMailFolder); if (imapFolder) imapFolder->GetHierarchyDelimiter(&hierarchyDelimiter); } PR_Free(hostname); return rv; } /* fetching the headers of RFC822 messages */ /* imap4://HOST>header>>MAILBOXPATH>x */ /* 'x' is the message UID or sequence number list */ /* will not affect the 'SEEN' flag */ NS_IMETHODIMP nsImapService::GetHeaders(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, PRBool messageIdsAreUID) { // create a protocol instance to handle the request. // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now // just create a connection and process the request. NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl),aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { nsCOMPtr uri = do_QueryInterface(imapUrl); rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch); rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { urlSpec.Append("/header>"); urlSpec.Append(messageIdsAreUID ? uidString : sequenceString); urlSpec.Append(">"); urlSpec.Append(char (hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(messageIdentifierList); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } /* peeking at the start of msg bodies */ /* imap4://HOST>header>>MAILBOXPATH>x>n */ /* 'x' is the message UID */ /* 'n' is the number of bytes to fetch */ /* will not affect the 'SEEN' flag */ NS_IMETHODIMP nsImapService::GetBodyStart(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, const char *messageIdentifierList, PRInt32 numBytes, nsIURI ** aURL) { nsresult rv; NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgPreview); rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); urlSpec.Append("/previewBody>"); urlSpec.Append(uidString); urlSpec.Append(">"); urlSpec.Append(char (hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(messageIdentifierList); urlSpec.Append(">"); urlSpec.AppendInt(numBytes); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } nsresult nsImapService::FolderCommand(nsIEventQueue * clientEventQueue, nsIMsgFolder * imapMailFolder, nsIUrlListener * urlListener, const char *command, nsImapAction imapAction, nsIURI ** url) { NS_ASSERTION (imapMailFolder && clientEventQueue, "Oops ... null pointer"); if (!imapMailFolder || !clientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(imapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), imapMailFolder, urlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = imapUrl->SetImapAction(imapAction); rv = SetImapUrlSink(imapMailFolder, imapUrl); nsCOMPtr uri = do_QueryInterface(imapUrl); if (NS_SUCCEEDED(rv)) { urlSpec.Append(command); urlSpec.Append(char (hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(imapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(clientEventQueue, imapUrl, nsnull, url); } } return rv; } // Noop, used to update a folder (causes server to send changes). NS_IMETHODIMP nsImapService::Noop(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/selectnoop>", nsIImapUrl::nsImapSelectNoopFolder, aURL); } // FolderStatus, used to update message counts NS_IMETHODIMP nsImapService::UpdateFolderStatus(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/folderstatus>", nsIImapUrl::nsImapFolderStatus, aURL); } // Expunge, used to "compress" an imap folder,removes deleted messages. NS_IMETHODIMP nsImapService::Expunge(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/Expunge>", nsIImapUrl::nsImapExpungeFolder, aURL); } /* old-stle biff that doesn't download headers */ NS_IMETHODIMP nsImapService::Biff(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, PRUint32 uidHighWater) { // static const char *formatString = "biff>%c%s>%ld"; NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = imapUrl->SetImapAction(nsIImapUrl::nsImapExpungeFolder); rv = SetImapUrlSink(aImapMailFolder, imapUrl); nsCOMPtr uri = do_QueryInterface(imapUrl); if (NS_SUCCEEDED(rv)) { urlSpec.Append("/Biff>"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.AppendInt(uidHighWater); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } NS_IMETHODIMP nsImapService::DeleteFolder(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aImapMailFolder, nsIUrlListener* aUrlListener, nsIURI** aURL) { // If it's an aol server then use 'deletefolder' url to // remove all msgs first and then remove the folder itself. PRBool removeFolderAndMsgs = PR_FALSE; nsCOMPtr server; if (NS_SUCCEEDED(aImapMailFolder->GetServer(getter_AddRefs(server))) && server) { nsCOMPtr imapServer = do_QueryInterface(server); if (imapServer) imapServer->GetIsAOLServer(&removeFolderAndMsgs); } return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, removeFolderAndMsgs ? "/deletefolder>": "/delete>", nsIImapUrl::nsImapDeleteFolder, aURL); } NS_IMETHODIMP nsImapService::DeleteMessages(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, PRBool messageIdsAreUID) { nsresult rv; // create a protocol instance to handle the request. // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now // just create a connection and process the request. NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch); rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); urlSpec.Append("/deletemsg>"); urlSpec.Append(messageIdsAreUID ? uidString : sequenceString); urlSpec.Append(">"); urlSpec.Append(char (hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(messageIdentifierList); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } // Delete all messages in a folder, used to empty trash NS_IMETHODIMP nsImapService::DeleteAllMessages(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/deleteallmsgs>", nsIImapUrl::nsImapSelectNoopFolder, aURL); } NS_IMETHODIMP nsImapService::AddMessageFlags(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, imapMessageFlagsType flags, PRBool messageIdsAreUID) { return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList, "addmsgflags", flags, messageIdsAreUID); } NS_IMETHODIMP nsImapService::SubtractMessageFlags(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, imapMessageFlagsType flags, PRBool messageIdsAreUID) { return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList, "subtractmsgflags", flags, messageIdsAreUID); } NS_IMETHODIMP nsImapService::SetMessageFlags(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, imapMessageFlagsType flags, PRBool messageIdsAreUID) { return DiddleFlags(aClientEventQueue, aImapMailFolder, aUrlListener, aURL, messageIdentifierList, "setmsgflags", flags, messageIdsAreUID); } nsresult nsImapService::DiddleFlags(nsIEventQueue * aClientEventQueue, nsIMsgFolder * aImapMailFolder, nsIUrlListener * aUrlListener, nsIURI ** aURL, const char *messageIdentifierList, const char *howToDiddle, imapMessageFlagsType flags, PRBool messageIdsAreUID) { // create a protocol instance to handle the request. // NOTE: once we start working with multiple connections, this step will be much more complicated...but for now // just create a connection and process the request. NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null pointer"); if (!aImapMailFolder || !aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgFetch); rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); urlSpec.Append('/'); urlSpec.Append(howToDiddle); urlSpec.Append('>'); urlSpec.Append(messageIdsAreUID ? uidString : sequenceString); urlSpec.Append(">"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aImapMailFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(messageIdentifierList); urlSpec.Append('>'); urlSpec.AppendInt(flags); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } nsresult nsImapService::SetImapUrlSink(nsIMsgFolder* aMsgFolder, nsIImapUrl* aImapUrl) { nsresult rv = NS_ERROR_NULL_POINTER; nsISupports* aInst = nsnull; nsCOMPtr incomingServer; nsCOMPtr imapServerSink; NS_ASSERTION (aMsgFolder && aImapUrl, "Oops ... null pointers"); if (!aMsgFolder || !aImapUrl) return rv; rv = aMsgFolder->GetServer(getter_AddRefs(incomingServer)); if (NS_SUCCEEDED(rv) && incomingServer) { imapServerSink = do_QueryInterface(incomingServer); if (imapServerSink) aImapUrl->SetImapServerSink(imapServerSink); } rv = aMsgFolder->QueryInterface(NS_GET_IID(nsIImapMailFolderSink), (void**)&aInst); if (NS_SUCCEEDED(rv) && aInst) aImapUrl->SetImapMailFolderSink((nsIImapMailFolderSink*) aInst); NS_IF_RELEASE (aInst); aInst = nsnull; rv = aMsgFolder->QueryInterface(NS_GET_IID(nsIImapMessageSink), (void**)&aInst); if (NS_SUCCEEDED(rv) && aInst) aImapUrl->SetImapMessageSink((nsIImapMessageSink*) aInst); NS_IF_RELEASE (aInst); aInst = nsnull; nsCOMPtr mailnewsUrl = do_QueryInterface(aImapUrl); mailnewsUrl->SetFolder(aMsgFolder); return NS_OK; } NS_IMETHODIMP nsImapService::DiscoverAllFolders(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aImapMailFolder, nsIUrlListener* aUrlListener, nsIMsgWindow * aMsgWindow, nsIURI** aURL) { NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null aClientEventQueue or aImapMailFolder"); if (!aImapMailFolder || ! aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED (rv)) { rv = SetImapUrlSink(aImapMailFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); nsCOMPtr mailnewsurl = do_QueryInterface(imapUrl); if (mailnewsurl) mailnewsurl->SetMsgWindow(aMsgWindow); urlSpec.Append("/discoverallboxes"); nsCOMPtr url = do_QueryInterface(imapUrl, &rv); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } return rv; } NS_IMETHODIMP nsImapService::DiscoverAllAndSubscribedFolders(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aImapMailFolder, nsIUrlListener* aUrlListener, nsIURI** aURL) { NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null aClientEventQueue or aImapMailFolder"); if (!aImapMailFolder || ! aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr aImapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(aImapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED (rv) && aImapUrl) { rv = SetImapUrlSink(aImapMailFolder, aImapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(aImapUrl); urlSpec.Append("/discoverallandsubscribedboxes"); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, aImapUrl, nsnull, aURL); } } return rv; } NS_IMETHODIMP nsImapService::DiscoverChildren(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aImapMailFolder, nsIUrlListener* aUrlListener, const char *folderPath, nsIURI** aURL) { NS_ASSERTION (aImapMailFolder && aClientEventQueue, "Oops ... null aClientEventQueue or aImapMailFolder"); if (!aImapMailFolder || ! aClientEventQueue) return NS_ERROR_NULL_POINTER; nsCOMPtr aImapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aImapMailFolder); nsresult rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(aImapUrl), aImapMailFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED (rv)) { rv = SetImapUrlSink(aImapMailFolder, aImapUrl); if (NS_SUCCEEDED(rv)) { if (folderPath && *folderPath) { nsCOMPtr uri = do_QueryInterface(aImapUrl); urlSpec.Append("/discoverchildren>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append(folderPath); // mscott - this cast to a char * is okay...there's a bug in the XPIDL // compiler that is preventing in string parameters from showing up as // const char *. hopefully they will fix it soon. rv = uri->SetSpec(urlSpec); // Make sure the uri has the same hierarchy separator as the one in msg folder // obj if it's not kOnlineHierarchySeparatorUnknown (ie, '^'). char uriDelimiter; nsresult rv1 = aImapUrl->GetOnlineSubDirSeparator(&uriDelimiter); if (NS_SUCCEEDED (rv1) && hierarchySeparator != kOnlineHierarchySeparatorUnknown && uriDelimiter != hierarchySeparator) aImapUrl->SetOnlineSubDirSeparator((char)hierarchySeparator); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, aImapUrl, nsnull, aURL); } else { rv = NS_ERROR_NULL_POINTER; } } } return rv; } NS_IMETHODIMP nsImapService::OnlineMessageCopy(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aSrcFolder, const char* messageIds, nsIMsgFolder* aDstFolder, PRBool idsAreUids, PRBool isMove, nsIUrlListener* aUrlListener, nsIURI** aURL, nsISupports* copyState, nsIMsgWindow *aMsgWindow) { NS_ASSERTION(aSrcFolder && aDstFolder && messageIds && aClientEventQueue, "Fatal ... missing key parameters"); if (!aClientEventQueue || !aSrcFolder || !aDstFolder || !messageIds || *messageIds == 0) return NS_ERROR_NULL_POINTER; nsresult rv = NS_ERROR_FAILURE; nsCOMPtr srcServer; nsCOMPtr dstServer; rv = aSrcFolder->GetServer(getter_AddRefs(srcServer)); if(NS_FAILED(rv)) return rv; rv = aDstFolder->GetServer(getter_AddRefs(dstServer)); if(NS_FAILED(rv)) return rv; PRBool sameServer; rv = dstServer->Equals(srcServer, &sameServer); if(NS_FAILED(rv)) return rv; if (!sameServer) { NS_ASSERTION(PR_FALSE, "can't use this method to copy across servers"); // *** can only take message from the same imap host and user accnt return NS_ERROR_FAILURE; } nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aSrcFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aSrcFolder, aUrlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv)) { SetImapUrlSink(aSrcFolder, imapUrl); imapUrl->SetCopyState(copyState); nsCOMPtr msgurl (do_QueryInterface(imapUrl)); msgurl->SetMsgWindow(aMsgWindow); imapUrl->AddChannelToLoadGroup(); //we get the loadGroup from msgWindow nsCOMPtr uri = do_QueryInterface(imapUrl); if (isMove) urlSpec.Append("/onlinemove>"); else urlSpec.Append("/onlinecopy>"); if (idsAreUids) urlSpec.Append(uidString); else urlSpec.Append(sequenceString); urlSpec.Append('>'); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aSrcFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); urlSpec.Append('>'); urlSpec.Append(messageIds); urlSpec.Append('>'); urlSpec.Append(char(hierarchySeparator)); folderName.Adopt(strdup("")); GetFolderName(aDstFolder, getter_Copies(folderName)); urlSpec.Append((const char *) folderName); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } return rv; } nsresult nsImapService::OfflineAppendFromFile(nsIFileSpec* aFileSpec, nsIURI *aUrl, nsIMsgFolder* aDstFolder, const char* messageId, // te be replaced PRBool inSelectedState, // needs to be in nsIUrlListener* aListener, nsIURI** aURL, nsISupports* aCopyState) { nsCOMPtr destDB; nsresult rv = aDstFolder->GetMsgDatabase(nsnull, getter_AddRefs(destDB)); // ### might need to send some notifications instead of just returning if (NS_SUCCEEDED(rv) && destDB) { nsMsgKey fakeKey; destDB->GetNextFakeOfflineMsgKey(&fakeKey); nsCOMPtr op; rv = destDB->GetOfflineOpForKey(fakeKey, PR_TRUE, getter_AddRefs(op)); if (NS_SUCCEEDED(rv) && op) { nsXPIDLCString destFolderUri; aDstFolder->GetURI(getter_Copies(destFolderUri)); op->SetOperation(nsIMsgOfflineImapOperation::kAppendDraft); // ### do we care if it's a template? op->SetDestinationFolderURI(destFolderUri); nsCOMPtr offlineStore; rv = aDstFolder->GetOfflineStoreOutputStream(getter_AddRefs(offlineStore)); if (NS_SUCCEEDED(rv) && offlineStore) { PRInt64 curOfflineStorePos = 0; nsCOMPtr seekable = do_QueryInterface(offlineStore); if (seekable) seekable->Tell(&curOfflineStorePos); else { NS_ASSERTION(PR_FALSE, "needs to be a random store!"); return NS_ERROR_FAILURE; } nsCOMPtr inputStream; nsCOMPtr msgParser = do_CreateInstance(NS_PARSEMAILMSGSTATE_CONTRACTID, &rv); msgParser->SetMailDB(destDB); if (NS_SUCCEEDED(rv)) rv = aFileSpec->GetInputStream(getter_AddRefs(inputStream)); if (NS_SUCCEEDED(rv) && inputStream) { // now, copy the temp file to the offline store for the dest folder. PRInt32 inputBufferSize = 10240; nsMsgLineStreamBuffer *inputStreamBuffer = new nsMsgLineStreamBuffer(inputBufferSize, PR_TRUE /* allocate new lines */, PR_FALSE /* leave CRLFs on the returned string */); PRUint32 fileSize; aFileSpec->GetFileSize(&fileSize); PRUint32 bytesWritten; rv = NS_OK; // rv = inputStream->Read(inputBuffer, inputBufferSize, &bytesRead); // if (NS_SUCCEEDED(rv) && bytesRead > 0) msgParser->SetState(nsIMsgParseMailMsgState::ParseHeadersState); // set the env pos to fake key so the msg hdr will have that for a key msgParser->SetEnvelopePos(fakeKey); PRBool needMoreData = PR_FALSE; char * newLine = nsnull; PRUint32 numBytesInLine = 0; do { newLine = inputStreamBuffer->ReadNextLine(inputStream, numBytesInLine, needMoreData); if (newLine) { msgParser->ParseAFolderLine(newLine, numBytesInLine); rv = offlineStore->Write(newLine, numBytesInLine, &bytesWritten); nsCRT::free(newLine); } } while (newLine); nsCOMPtr fakeHdr; msgParser->FinishHeader(); msgParser->GetNewMsgHdr(getter_AddRefs(fakeHdr)); if (fakeHdr) { if (NS_SUCCEEDED(rv) && fakeHdr) { PRUint32 resultFlags; nsInt64 tellPos = curOfflineStorePos; fakeHdr->SetMessageOffset((PRUint32) tellPos); fakeHdr->OrFlags(MSG_FLAG_OFFLINE | MSG_FLAG_READ, &resultFlags); fakeHdr->SetOfflineMessageSize(fileSize); destDB->AddNewHdrToDB(fakeHdr, PR_TRUE /* notify */); aDstFolder->SetFlag(MSG_FOLDER_FLAG_OFFLINEEVENTS); } } // tell the listener we're done. inputStream = nsnull; aFileSpec->CloseStream(); aListener->OnStopRunningUrl(aUrl, NS_OK); delete inputStreamBuffer; } } } } if (destDB) destDB->Close(PR_TRUE); return rv; } /* append message from file url */ /* imap://HOST>appendmsgfromfile>DESTINATIONMAILBOXPATH */ /* imap://HOST>appenddraftfromfile>DESTINATIONMAILBOXPATH>UID>messageId */ NS_IMETHODIMP nsImapService::AppendMessageFromFile(nsIEventQueue* aClientEventQueue, nsIFileSpec* aFileSpec, nsIMsgFolder* aDstFolder, const char* messageId, // te be replaced PRBool idsAreUids, PRBool inSelectedState, // needs to be in nsIUrlListener* aListener, nsIURI** aURL, nsISupports* aCopyState, nsIMsgWindow *aMsgWindow) { nsresult rv = NS_ERROR_NULL_POINTER; if (!aClientEventQueue || !aFileSpec || !aDstFolder) return rv; nsCOMPtr imapUrl; nsCAutoString urlSpec; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aDstFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aDstFolder, aListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv)) { nsCOMPtr msgUrl = do_QueryInterface(imapUrl); if (msgUrl && aMsgWindow) { //we get the loadGroup from msgWindow msgUrl->SetMsgWindow(aMsgWindow); imapUrl->AddChannelToLoadGroup(); } SetImapUrlSink(aDstFolder, imapUrl); imapUrl->SetMsgFileSpec(aFileSpec); imapUrl->SetCopyState(aCopyState); nsCOMPtr uri = do_QueryInterface(imapUrl); if (inSelectedState) urlSpec.Append("/appenddraftfromfile>"); else urlSpec.Append("/appendmsgfromfile>"); urlSpec.Append(char(hierarchySeparator)); nsXPIDLCString folderName; GetFolderName(aDstFolder, getter_Copies(folderName)); urlSpec.Append(folderName); if (inSelectedState) { urlSpec.Append('>'); if (idsAreUids) urlSpec.Append(uidString); else urlSpec.Append(sequenceString); urlSpec.Append('>'); if (messageId) urlSpec.Append(messageId); } rv = uri->SetSpec(urlSpec); if (WeAreOffline()) { return OfflineAppendFromFile(aFileSpec, uri, aDstFolder, messageId, inSelectedState, aListener, aURL, aCopyState); // handle offline append to drafts or templates folder here. } if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } return rv; } nsresult nsImapService::GetImapConnectionAndLoadUrl(nsIEventQueue* aClientEventQueue, nsIImapUrl* aImapUrl, nsISupports* aConsumer, nsIURI** aURL) { NS_ENSURE_ARG(aImapUrl); if (WeAreOffline()) { nsImapAction imapAction; // the only thing we can do offline is fetch messages. // ### TODO - need to look at msg copy, save attachment, etc. when we // have offline message bodies. aImapUrl->GetImapAction(&imapAction); if (imapAction != nsIImapUrl::nsImapMsgFetch && imapAction != nsIImapUrl::nsImapSaveMessageToDisk) return NS_MSG_ERROR_OFFLINE; } nsresult rv = NS_OK; nsCOMPtr aMsgIncomingServer; nsCOMPtr msgUrl = do_QueryInterface(aImapUrl); rv = msgUrl->GetServer(getter_AddRefs(aMsgIncomingServer)); if (aURL) NS_IF_ADDREF(*aURL = msgUrl); if (NS_SUCCEEDED(rv) && aMsgIncomingServer) { nsCOMPtr aImapServer(do_QueryInterface(aMsgIncomingServer, &rv)); if (NS_SUCCEEDED(rv) && aImapServer) rv = aImapServer->GetImapConnectionAndLoadUrl(aClientEventQueue, aImapUrl, aConsumer); } return rv; } NS_IMETHODIMP nsImapService::MoveFolder(nsIEventQueue* eventQueue, nsIMsgFolder* srcFolder, nsIMsgFolder* dstFolder, nsIUrlListener* urlListener, nsIMsgWindow *msgWindow, nsIURI** url) { NS_ASSERTION(eventQueue && srcFolder && dstFolder, "Oops ... null pointer"); if (!eventQueue || !srcFolder || !dstFolder) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar default_hierarchySeparator = GetHierarchyDelimiter(dstFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), dstFolder, urlListener, urlSpec, default_hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = SetImapUrlSink(dstFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); if (mailNewsUrl) mailNewsUrl->SetMsgWindow(msgWindow); char hierarchySeparator = kOnlineHierarchySeparatorUnknown; nsXPIDLCString folderName; nsCOMPtr uri = do_QueryInterface(imapUrl); GetFolderName(srcFolder, getter_Copies(folderName)); urlSpec.Append("/movefolderhierarchy>"); urlSpec.Append(hierarchySeparator); urlSpec.Append((const char *) folderName); urlSpec.Append('>'); folderName.Adopt(strdup("")); GetFolderName(dstFolder, getter_Copies(folderName)); if ( folderName && folderName[0]) { urlSpec.Append(hierarchySeparator); urlSpec.Append((const char *) folderName); } rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) { GetFolderName(srcFolder, getter_Copies(folderName)); rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl, nsnull, url); } } } return rv; } NS_IMETHODIMP nsImapService::RenameLeaf(nsIEventQueue* eventQueue, nsIMsgFolder* srcFolder, const PRUnichar* newLeafName, nsIUrlListener* urlListener, nsIMsgWindow *msgWindow, nsIURI** url) { NS_ASSERTION(eventQueue && srcFolder && newLeafName && *newLeafName, "Oops ... [RenameLeaf] null pointers"); if (!eventQueue || !srcFolder || !newLeafName || !*newLeafName) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(srcFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), srcFolder, urlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv)) { rv = SetImapUrlSink(srcFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); if (mailNewsUrl) mailNewsUrl->SetMsgWindow(msgWindow); nsXPIDLCString folderName; GetFolderName(srcFolder, getter_Copies(folderName)); urlSpec.Append("/rename>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); urlSpec.Append('>'); urlSpec.Append(char(hierarchySeparator)); nsCAutoString cStrFolderName(NS_STATIC_CAST(const char *, folderName)); // Unescape the name before looking for parent path nsUnescape(cStrFolderName.BeginWriting()); PRInt32 leafNameStart = cStrFolderName.RFindChar(hierarchySeparator); if (leafNameStart != -1) { cStrFolderName.SetLength(leafNameStart+1); urlSpec.Append(cStrFolderName); } nsCAutoString utfNewName; CopyUTF16toMUTF7(nsDependentString(newLeafName), utfNewName); char* escapedNewName = nsEscape(utfNewName.get(), url_Path); if (!escapedNewName) return NS_ERROR_OUT_OF_MEMORY; nsXPIDLCString escapedSlashName; rv = nsImapUrl::EscapeSlashes(escapedNewName, getter_Copies(escapedSlashName)); NS_ENSURE_SUCCESS(rv, rv); nsCRT::free(escapedNewName); urlSpec.Append(escapedSlashName.get()); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) { rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl, nsnull, url); } } // if (NS_SUCCEEDED(rv)) } // if (NS_SUCCEEDED(rv) && imapUrl) return rv; } NS_IMETHODIMP nsImapService::CreateFolder(nsIEventQueue* eventQueue, nsIMsgFolder* parent, const PRUnichar* newFolderName, nsIUrlListener* urlListener, nsIURI** url) { NS_ASSERTION(eventQueue && parent && newFolderName && *newFolderName, "Oops ... [CreateFolder] null pointers"); if (!eventQueue || !parent || !newFolderName || !*newFolderName) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(parent); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), parent, urlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = SetImapUrlSink(parent, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); nsXPIDLCString folderName; GetFolderName(parent, getter_Copies(folderName)); urlSpec.Append("/create>"); urlSpec.Append(char(hierarchySeparator)); if (!folderName.IsEmpty()) { nsXPIDLCString canonicalName; nsImapUrl::ConvertToCanonicalFormat(folderName, (char) hierarchySeparator, getter_Copies(canonicalName)); urlSpec.Append((const char *) canonicalName); urlSpec.Append(char(hierarchySeparator)); } nsCAutoString utfNewName; rv = CopyUTF16toMUTF7(nsDependentString(newFolderName), utfNewName); NS_ENSURE_SUCCESS(rv, rv); char* escapedFolderName = nsEscape(utfNewName.get(), url_Path); urlSpec.Append(escapedFolderName); nsCRT::free(escapedFolderName); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl, nsnull, url); } // if (NS_SUCCEEDED(rv)) } // if (NS_SUCCEEDED(rv) && imapUrl) return rv; } NS_IMETHODIMP nsImapService::EnsureFolderExists(nsIEventQueue* eventQueue, nsIMsgFolder* parent, const PRUnichar* newFolderName, nsIUrlListener* urlListener, nsIURI** url) { NS_ASSERTION(eventQueue && parent && newFolderName && *newFolderName, "Oops ... [EnsureExists] null pointers"); if (!eventQueue || !parent || !newFolderName || !*newFolderName) return NS_ERROR_NULL_POINTER; nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(parent); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), parent, urlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = SetImapUrlSink(parent, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); nsXPIDLCString folderName; GetFolderName(parent, getter_Copies(folderName)); urlSpec.Append("/ensureExists>"); urlSpec.Append(char(hierarchySeparator)); if (!folderName.IsEmpty()) { urlSpec.Append((const char *) folderName); urlSpec.Append(char(hierarchySeparator)); } nsCAutoString utfNewName; CopyUTF16toMUTF7(nsDependentString(newFolderName), utfNewName); char* escapedFolderName = nsEscape(utfNewName.get(), url_Path); urlSpec.Append(escapedFolderName); nsCRT::free(escapedFolderName); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl, nsnull, url); } // if (NS_SUCCEEDED(rv)) } // if (NS_SUCCEEDED(rv) && imapUrl) return rv; } NS_IMETHODIMP nsImapService::ListFolder(nsIEventQueue* aClientEventQueue, nsIMsgFolder* aImapMailFolder, nsIUrlListener* aUrlListener, nsIURI** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/listfolder>", nsIImapUrl::nsImapListFolder, aURL); } NS_IMETHODIMP nsImapService::GetScheme(nsACString &aScheme) { aScheme = "imap"; return NS_OK; } NS_IMETHODIMP nsImapService::GetDefaultPort(PRInt32 *aDefaultPort) { NS_ENSURE_ARG_POINTER(aDefaultPort); *aDefaultPort = IMAP_PORT; return NS_OK; } NS_IMETHODIMP nsImapService::GetProtocolFlags(PRUint32 *result) { *result = URI_STD | ALLOWS_PROXY; return NS_OK; } NS_IMETHODIMP nsImapService::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval) { // allow imap to run on any port *_retval = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetDefaultDoBiff(PRBool *aDoBiff) { NS_ENSURE_ARG_POINTER(aDoBiff); // by default, do biff for IMAP servers *aDoBiff = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetDefaultServerPort(PRBool isSecure, PRInt32 *aDefaultPort) { nsresult rv = NS_OK; // Return Secure IMAP Port if secure option chosen i.e., if isSecure is TRUE if (isSecure) *aDefaultPort = SECURE_IMAP_PORT; else rv = GetDefaultPort(aDefaultPort); return rv; } // this method first tries to find an exact username and hostname match with the given url // then, tries to find any account on the passed in imap host in case this is a url to // a shared imap folder. nsresult nsImapService::GetServerFromUrl(nsIImapUrl *aImapUrl, nsIMsgIncomingServer **aServer) { nsCAutoString userPass; nsCAutoString hostName; nsCOMPtr mailnewsUrl = do_QueryInterface(aImapUrl); nsresult rv; nsXPIDLCString folderName; // if we can't get a folder name out of the url then I think this is an error aImapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName)); if (folderName.IsEmpty()) { rv = mailnewsUrl->GetFileName(folderName); if (NS_FAILED(rv)) return rv; } nsCOMPtr accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; rv = accountManager->FindServerByURI(mailnewsUrl, PR_FALSE, aServer); // look for server with any user name, in case we're trying to subscribe // to a folder with some one else's user name like the following // "IMAP://userSharingFolder@server1/SharedFolderName" if (NS_FAILED(rv) || !aServer) { nsCAutoString turl; nsCOMPtr url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; mailnewsUrl->GetSpec(turl); rv = url->SetSpec(turl); if (NS_FAILED(rv)) return rv; url->SetUserPass(EmptyCString()); rv = accountManager->FindServerByURI(url, PR_FALSE, aServer); if (*aServer) aImapUrl->SetExternalLinkUrl(PR_TRUE); } // if we can't extract the imap server from this url then give up!!! if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(*aServer, NS_ERROR_FAILURE); return rv; } NS_IMETHODIMP nsImapService::NewURI(const nsACString &aSpec, const char *aOriginCharset, // ignored nsIURI *aBaseURI, nsIURI **_retval) { nsresult rv; nsCOMPtr aImapUrl = do_CreateInstance(kImapUrlCID, &rv); if (NS_SUCCEEDED(rv)) { // now extract lots of fun information... nsCOMPtr mailnewsUrl = do_QueryInterface(aImapUrl); //nsCAutoString unescapedSpec(aSpec); // nsUnescape(unescapedSpec.BeginWriting()); // set the spec if (aBaseURI) { nsCAutoString newSpec; aBaseURI->Resolve(aSpec, newSpec); mailnewsUrl->SetSpec(newSpec); } else { mailnewsUrl->SetSpec(aSpec); } nsXPIDLCString folderName; // if we can't get a folder name out of the url then I think this is an error aImapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName)); if (folderName.IsEmpty()) { rv = mailnewsUrl->GetFileName(folderName); if (NS_FAILED(rv)) return rv; } nsCOMPtr server; rv = GetServerFromUrl(aImapUrl, getter_AddRefs(server)); // if we can't extract the imap server from this url then give up!!! if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(server, NS_ERROR_FAILURE); // now try to get the folder in question... nsCOMPtr rootFolder; server->GetRootFolder(getter_AddRefs(rootFolder)); if (rootFolder && !folderName.IsEmpty()) { nsCOMPtr folder; nsCOMPtr imapRoot = do_QueryInterface(rootFolder, &rv); nsCOMPtr subFolder; if (imapRoot) { imapRoot->FindOnlineSubFolder(folderName, getter_AddRefs(subFolder)); folder = do_QueryInterface(subFolder, &rv); } if (NS_SUCCEEDED(rv)) { nsCOMPtr msgSink = do_QueryInterface(folder); rv = aImapUrl->SetImapMessageSink(msgSink); nsCOMPtr msgFolder = do_QueryInterface(folder); rv = SetImapUrlSink(msgFolder, aImapUrl); nsXPIDLCString msgKey; nsXPIDLCString messageIdString; aImapUrl->CreateListOfMessageIdsString(getter_Copies(messageIdString)); if (messageIdString.get()) { PRBool useLocalCache = PR_FALSE; msgFolder->HasMsgOffline(atoi(messageIdString), &useLocalCache); mailnewsUrl->SetMsgIsInLocalCache(useLocalCache); } } } // if we are fetching a part, be sure to enable fetch parts on demand PRBool mimePartSelectorDetected = PR_FALSE; aImapUrl->GetMimePartSelectorDetected(&mimePartSelectorDetected); if (mimePartSelectorDetected) aImapUrl->SetFetchPartsOnDemand(PR_TRUE); // we got an imap url, so be sure to return it... aImapUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) _retval); } return rv; } NS_IMETHODIMP nsImapService::NewChannel(nsIURI *aURI, nsIChannel **_retval) { // imap can't open and return a channel right away...the url needs to go in the imap url queue // until we find a connection which can run the url..in order to satisfy necko, we're going to return // a mock imap channel.... nsresult rv = NS_OK; nsCOMPtr mockChannel; nsCOMPtr imapUrl = do_QueryInterface(aURI, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr mailnewsUrl = do_QueryInterface(imapUrl); // XXX this mock channel stuff is wrong -- the channel really should be owning the URL // and the originalURL, not the other way around rv = imapUrl->InitializeURIforMockChannel(); rv = imapUrl->GetMockChannel(getter_AddRefs(mockChannel)); if (NS_FAILED(rv) || !mockChannel) { // this is a funky condition...it means we've already run the url once // and someone is trying to get us to run it again... imapUrl->Initialize(); // force a new mock channel to get created. rv = imapUrl->InitializeURIforMockChannel(); rv = imapUrl->GetMockChannel(getter_AddRefs(mockChannel)); if (!mockChannel) return NS_ERROR_FAILURE; } PRBool externalLinkUrl; imapUrl->GetExternalLinkUrl(&externalLinkUrl); if (externalLinkUrl) { // everything after here is to handle clicking on an external link. We only want // to do this if we didn't run the url through the various nsImapService methods, // which we can tell by seeing if the sinks have been setup on the url or not. nsCOMPtr server; rv = GetServerFromUrl(imapUrl, getter_AddRefs(server)); NS_ENSURE_SUCCESS(rv, rv); nsXPIDLCString folderName; imapUrl->CreateCanonicalSourceFolderPathString(getter_Copies(folderName)); if (folderName.IsEmpty()) { rv = mailnewsUrl->GetFileName(folderName); if (!folderName.IsEmpty()) NS_UnescapeURL(folderName); } // if the parent is null, then the folder doesn't really exist, so see if the user // wants to subscribe to it./ nsCOMPtr aFolder; // now try to get the folder in question... nsCOMPtr rootFolder; server->GetRootFolder(getter_AddRefs(rootFolder)); nsCOMPtr imapRoot = do_QueryInterface(rootFolder); nsCOMPtr subFolder; if (imapRoot) { imapRoot->FindOnlineSubFolder(folderName, getter_AddRefs(subFolder)); aFolder = do_QueryInterface(subFolder); } nsCOMPtr parent; if (aFolder) aFolder->GetParent(getter_AddRefs(parent)); nsXPIDLCString serverKey; nsCAutoString userPass; rv = mailnewsUrl->GetUserPass(userPass); server->GetKey(getter_Copies(serverKey)); char *fullFolderName = nsnull; if (parent) fullFolderName = ToNewCString(folderName); if (!parent && !folderName.IsEmpty())// check if this folder is another user's folder { fullFolderName = nsIMAPNamespaceList::GenerateFullFolderNameWithDefaultNamespace(serverKey.get(), folderName.get(), userPass.get(), kOtherUsersNamespace, nsnull); // if this is another user's folder, let's see if we're already subscribed to it. rv = imapRoot->FindOnlineSubFolder(fullFolderName, getter_AddRefs(subFolder)); aFolder = do_QueryInterface(subFolder); if (aFolder) aFolder->GetParent(getter_AddRefs(parent)); } // if we couldn't get the fullFolderName, then we probably couldn't find // the other user's namespace, in which case, we shouldn't try to subscribe to it. if (!parent && !folderName.IsEmpty() && fullFolderName) { // this folder doesn't exist - check if the user wants to subscribe to this folder. nsCOMPtr dialog; nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); wwatch->GetNewPrompter(nsnull, getter_AddRefs(dialog)); nsXPIDLString statusString, confirmText; nsCOMPtr bundle; rv = IMAPGetStringBundle(getter_AddRefs(bundle)); NS_ENSURE_SUCCESS(rv, rv); // need to convert folder name from mod-utf7 to unicode nsAutoString unescapedName; if (NS_FAILED(CopyMUTF7toUTF16(nsDependentCString(fullFolderName), unescapedName))) CopyASCIItoUTF16(nsDependentCString(fullFolderName), unescapedName); const PRUnichar *formatStrings[1] = { unescapedName.get() }; rv = bundle->FormatStringFromID(IMAP_SUBSCRIBE_PROMPT, formatStrings, 1, getter_Copies(confirmText)); NS_ENSURE_SUCCESS(rv,rv); PRBool confirmResult = PR_FALSE; rv = dialog->Confirm(nsnull, confirmText, &confirmResult); NS_ENSURE_SUCCESS(rv, rv); if (confirmResult) { nsCOMPtr imapServer = do_QueryInterface(server); if (imapServer) { nsCOMPtr subscribeURI; // now we have the real folder name to try to subscribe to. Let's try running // a subscribe url and returning that as the uri we've created. // We need to convert this to unicode because that's what subscribe wants :-( // It's already in mod-utf7. nsAutoString unicodeName; unicodeName.AssignWithConversion(fullFolderName); rv = imapServer->SubscribeToFolder(unicodeName.get(), PR_TRUE, getter_AddRefs(subscribeURI)); if (NS_SUCCEEDED(rv) && subscribeURI) { nsCOMPtr imapSubscribeUrl = do_QueryInterface(subscribeURI); if (imapSubscribeUrl) imapSubscribeUrl->SetExternalLinkUrl(PR_TRUE); nsCOMPtr mailnewsUrl = do_QueryInterface(subscribeURI); if (mailnewsUrl) { nsCOMPtr mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr msgWindow; rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow)); if (NS_SUCCEEDED(rv) && msgWindow) { mailnewsUrl->SetMsgWindow(msgWindow); nsCOMPtr listener = do_QueryInterface(rootFolder); if (listener) mailnewsUrl->RegisterListener(listener); } } } } } // error out this channel, so it'll stop trying to run the url. rv = NS_ERROR_FAILURE; *_retval = nsnull; PR_Free(fullFolderName); } else if (fullFolderName)// this folder exists - check if this is a click on a link to the folder { // in which case, we'll select it. nsCOMPtr imapFolder; nsCOMPtr serverSink; mailnewsUrl->GetFolder(getter_AddRefs(imapFolder)); imapUrl->GetImapServerSink(getter_AddRefs(serverSink)); // need to see if this is a link click - one way is to check if the url is set up correctly // if not, it's probably a url click. We need a better way of doing this. if (!imapFolder) { nsCOMPtr mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr msgWindow; rv = mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow)); if (NS_SUCCEEDED(rv) && msgWindow) { nsXPIDLCString uri; rootFolder->GetURI(getter_Copies(uri)); uri.Append('/'); uri.Append(fullFolderName); msgWindow->SelectFolder(uri.get()); // error out this channel, so it'll stop trying to run the url. *_retval = nsnull; rv = NS_ERROR_FAILURE; } else { // make sure the imap action is selectFolder, so the content type // will be x-application-imapfolder, so ::HandleContent will // know to open a new 3 pane window. imapUrl->SetImapAction(nsIImapUrl::nsImapSelectFolder); } } } } if (NS_SUCCEEDED(rv)) NS_IF_ADDREF(*_retval = mockChannel); return rv; } NS_IMETHODIMP nsImapService::SetDefaultLocalPath(nsIFileSpec *aPath) { NS_ENSURE_ARG(aPath); nsFileSpec spec; nsresult rv = aPath->GetFileSpec(&spec); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr localFile; NS_FileSpecToIFile(&spec, getter_AddRefs(localFile)); if (!localFile) return NS_ERROR_FAILURE; return NS_SetPersistentFile(PREF_MAIL_ROOT_IMAP_REL, PREF_MAIL_ROOT_IMAP, localFile); } NS_IMETHODIMP nsImapService::GetDefaultLocalPath(nsIFileSpec ** aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = nsnull; nsresult rv; nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) return rv; PRBool havePref; nsCOMPtr localFile; rv = NS_GetPersistentFile(PREF_MAIL_ROOT_IMAP_REL, PREF_MAIL_ROOT_IMAP, NS_APP_IMAP_MAIL_50_DIR, havePref, getter_AddRefs(localFile)); PRBool exists; rv = localFile->Exists(&exists); if (NS_SUCCEEDED(rv) && !exists) rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0775); NS_ENSURE_SUCCESS(rv, rv); // Make the resulting nsIFileSpec // TODO: Convert arg to nsILocalFile and avoid this nsCOMPtr outSpec; rv = NS_NewFileSpecFromIFile(localFile, getter_AddRefs(outSpec)); NS_ENSURE_SUCCESS(rv, rv); if (!havePref || !exists) { rv = NS_SetPersistentFile(PREF_MAIL_ROOT_IMAP_REL, PREF_MAIL_ROOT_IMAP, localFile); NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to set root dir pref."); } NS_IF_ADDREF(*aResult = outSpec); return NS_OK; } NS_IMETHODIMP nsImapService::GetServerIID(nsIID* *aServerIID) { *aServerIID = new nsIID(NS_GET_IID(nsIImapIncomingServer)); return NS_OK; } NS_IMETHODIMP nsImapService::GetRequiresUsername(PRBool *aRequiresUsername) { NS_ENSURE_ARG_POINTER(aRequiresUsername); *aRequiresUsername = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetPreflightPrettyNameWithEmailAddress(PRBool *aPreflightPrettyNameWithEmailAddress) { NS_ENSURE_ARG_POINTER(aPreflightPrettyNameWithEmailAddress); *aPreflightPrettyNameWithEmailAddress = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetCanLoginAtStartUp(PRBool *aCanLoginAtStartUp) { NS_ENSURE_ARG_POINTER(aCanLoginAtStartUp); *aCanLoginAtStartUp = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetCanDelete(PRBool *aCanDelete) { NS_ENSURE_ARG_POINTER(aCanDelete); *aCanDelete = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetCanDuplicate(PRBool *aCanDuplicate) { NS_ENSURE_ARG_POINTER(aCanDuplicate); *aCanDuplicate = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetCanGetMessages(PRBool *aCanGetMessages) { NS_ENSURE_ARG_POINTER(aCanGetMessages); *aCanGetMessages = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetCanGetIncomingMessages(PRBool *aCanGetIncomingMessages) { NS_ENSURE_ARG_POINTER(aCanGetIncomingMessages); *aCanGetIncomingMessages = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetShowComposeMsgLink(PRBool *showComposeMsgLink) { NS_ENSURE_ARG_POINTER(showComposeMsgLink); *showComposeMsgLink = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetNeedToBuildSpecialFolderURIs(PRBool *needToBuildSpecialFolderURIs) { NS_ENSURE_ARG_POINTER(needToBuildSpecialFolderURIs); *needToBuildSpecialFolderURIs = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsImapService::GetSpecialFoldersDeletionAllowed(PRBool *specialFoldersDeletionAllowed) { NS_ENSURE_ARG_POINTER(specialFoldersDeletionAllowed); *specialFoldersDeletionAllowed = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsImapService::GetListOfFoldersWithPath(nsIImapIncomingServer *aServer, nsIMsgWindow *aMsgWindow, const char *folderPath) { nsresult rv; #ifdef DEBUG_sspitzer printf("GetListOfFoldersWithPath(%s)\n",folderPath); #endif nsCOMPtr server = do_QueryInterface(aServer); if (!server) return NS_ERROR_FAILURE; nsCOMPtr rootMsgFolder; rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder)); if (NS_FAILED(rv)) return rv; if (!rootMsgFolder) return NS_ERROR_FAILURE; nsCOMPtr listener = do_QueryInterface(aServer, &rv); if (NS_FAILED(rv)) return rv; if (!listener) return NS_ERROR_FAILURE; nsCOMPtr queue; // get the Event Queue for this thread... nsCOMPtr pEventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue)); if (NS_FAILED(rv)) return rv; // Locate the folder so that the correct hierarchical delimiter is used in the folder // pathnames, otherwise root's (ie, '^') is used and this is wrong. nsCOMPtr msgFolder; if (rootMsgFolder && folderPath && (*folderPath)) { // If the folder path contains 'INBOX' of any forms, we need to convert it to uppercase // before finding it under the root folder. We do the same in PossibleImapMailbox(). nsCAutoString tempFolderName(folderPath); nsCAutoString tokenStr, remStr, changedStr; PRInt32 slashPos = tempFolderName.FindChar('/'); if (slashPos > 0) { tempFolderName.Left(tokenStr,slashPos); tempFolderName.Right(remStr, tempFolderName.Length()-slashPos); } else tokenStr.Assign(tempFolderName); if ((nsCRT::strcasecmp(tokenStr.get(), "INBOX")==0) && (nsCRT::strcmp(tokenStr.get(), "INBOX") != 0)) changedStr.Append("INBOX"); else changedStr.Append(tokenStr); if (slashPos > 0 ) changedStr.Append(remStr); rv = rootMsgFolder->FindSubFolder(changedStr, getter_AddRefs(msgFolder)); } rv = DiscoverChildren(queue, msgFolder, listener, folderPath, nsnull); if (NS_FAILED(rv)) return rv; return NS_OK; } NS_IMETHODIMP nsImapService::GetListOfFoldersOnServer(nsIImapIncomingServer *aServer, nsIMsgWindow *aMsgWindow) { nsresult rv; nsCOMPtr server = do_QueryInterface(aServer); if (!server) return NS_ERROR_FAILURE; nsCOMPtr rootMsgFolder; rv = server->GetRootMsgFolder(getter_AddRefs(rootMsgFolder)); if (NS_FAILED(rv)) return rv; if (!rootMsgFolder) return NS_ERROR_FAILURE; nsCOMPtr listener = do_QueryInterface(aServer, &rv); if (NS_FAILED(rv)) return rv; if (!listener) return NS_ERROR_FAILURE; nsCOMPtr queue; // get the Event Queue for this thread... nsCOMPtr pEventQService = do_GetService(kEventQueueServiceCID, &rv); if (NS_FAILED(rv)) return rv; rv = pEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(queue)); if (NS_FAILED(rv)) return rv; rv = DiscoverAllAndSubscribedFolders(queue, rootMsgFolder, listener, nsnull); if (NS_FAILED(rv)) return rv; return NS_OK; } NS_IMETHODIMP nsImapService::SubscribeFolder(nsIEventQueue* eventQueue, nsIMsgFolder* aFolder, const PRUnichar* aFolderName, nsIUrlListener* urlListener, nsIURI** url) { return ChangeFolderSubscription(eventQueue, aFolder, aFolderName, "/subscribe>", urlListener, url); } nsresult nsImapService::ChangeFolderSubscription(nsIEventQueue* eventQueue, nsIMsgFolder* folder, const PRUnichar* folderName, const char *command, nsIUrlListener* urlListener, nsIURI** url) { NS_ENSURE_ARG_POINTER(eventQueue); NS_ENSURE_ARG_POINTER(folder); NS_ENSURE_ARG_POINTER(folderName); nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(folder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), folder, urlListener, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { rv = SetImapUrlSink(folder, imapUrl); if (NS_SUCCEEDED(rv)) { nsCOMPtr uri = do_QueryInterface(imapUrl); urlSpec.Append(command); urlSpec.Append(char(hierarchySeparator)); nsCAutoString utfFolderName; rv = CopyUTF16toMUTF7(nsDependentString(folderName), utfFolderName); NS_ENSURE_SUCCESS(rv, rv); char* escapedFolderName = nsEscape(utfFolderName.get(), url_Path); urlSpec.Append(escapedFolderName); nsCRT::free(escapedFolderName); rv = uri->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(eventQueue, imapUrl, nsnull, url); } } return rv; } NS_IMETHODIMP nsImapService::UnsubscribeFolder(nsIEventQueue* aEventQueue, nsIMsgFolder* aFolder, const PRUnichar* aFolderName, nsIUrlListener* aUrlListener, nsIURI** aUrl) { return ChangeFolderSubscription(aEventQueue, aFolder, aFolderName, "/unsubscribe>", aUrlListener, aUrl); } NS_IMETHODIMP nsImapService::GetFolderAdminUrl(nsIEventQueue *aClientEventQueue, nsIMsgFolder *aImapMailFolder, nsIMsgWindow *aMsgWindow, nsIUrlListener *aUrlListener, nsIURI** aURL) { return FolderCommand(aClientEventQueue, aImapMailFolder, aUrlListener, "/refreshfolderurls>", nsIImapUrl::nsImapRefreshFolderUrls, aURL); } NS_IMETHODIMP nsImapService::IssueCommandOnMsgs(nsIEventQueue *aClientEventQueue, nsIMsgFolder *anImapFolder, nsIMsgWindow *aMsgWindow, const char *aCommand, const char *uids, nsIURI** aURL) { NS_ENSURE_ARG_POINTER(aClientEventQueue); NS_ENSURE_ARG_POINTER(anImapFolder); NS_ENSURE_ARG_POINTER(aMsgWindow); nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { // nsImapUrl::SetSpec() will set the imap action properly rv = imapUrl->SetImapAction(nsIImapUrl::nsImapUserDefinedMsgCommand); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); mailNewsUrl->SetMsgWindow(aMsgWindow); mailNewsUrl->SetUpdatingFolder(PR_TRUE); imapUrl->AddChannelToLoadGroup(); rv = SetImapUrlSink(anImapFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsXPIDLCString folderName; GetFolderName(anImapFolder, getter_Copies(folderName)); urlSpec.Append("/"); urlSpec.Append(aCommand); urlSpec.Append(">"); urlSpec.Append(uidString); urlSpec.Append(">"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(uids); rv = mailNewsUrl->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } // if we have a url to run.... return rv; } NS_IMETHODIMP nsImapService::FetchCustomMsgAttribute(nsIEventQueue *aClientEventQueue, nsIMsgFolder *anImapFolder, nsIMsgWindow *aMsgWindow, const char *aAttribute, const char *uids, nsIURI** aURL) { NS_ENSURE_ARG_POINTER(aClientEventQueue); NS_ENSURE_ARG_POINTER(anImapFolder); NS_ENSURE_ARG_POINTER(aMsgWindow); nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { // nsImapUrl::SetSpec() will set the imap action properly rv = imapUrl->SetImapAction(nsIImapUrl::nsImapUserDefinedFetchAttribute); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); mailNewsUrl->SetMsgWindow(aMsgWindow); mailNewsUrl->SetUpdatingFolder(PR_TRUE); imapUrl->AddChannelToLoadGroup(); rv = SetImapUrlSink(anImapFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsXPIDLCString folderName; GetFolderName(anImapFolder, getter_Copies(folderName)); urlSpec.Append("/customFetch>UID>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(uids); urlSpec.Append(">"); urlSpec.Append(aAttribute); rv = mailNewsUrl->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } // if we have a url to run.... return rv; } NS_IMETHODIMP nsImapService::StoreCustomKeywords(nsIEventQueue *aClientEventQueue, nsIMsgFolder *anImapFolder, nsIMsgWindow *aMsgWindow, const char *flagsToAdd, const char *flagsToSubtract, const char *uids, nsIURI** aURL) { NS_ENSURE_ARG_POINTER(aClientEventQueue); NS_ENSURE_ARG_POINTER(anImapFolder); nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(anImapFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), anImapFolder, nsnull, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { // nsImapUrl::SetSpec() will set the imap action properly rv = imapUrl->SetImapAction(nsIImapUrl::nsImapMsgStoreCustomKeywords); nsCOMPtr mailNewsUrl = do_QueryInterface(imapUrl); mailNewsUrl->SetMsgWindow(aMsgWindow); mailNewsUrl->SetUpdatingFolder(PR_TRUE); imapUrl->AddChannelToLoadGroup(); rv = SetImapUrlSink(anImapFolder, imapUrl); if (NS_SUCCEEDED(rv)) { nsXPIDLCString folderName; GetFolderName(anImapFolder, getter_Copies(folderName)); urlSpec.Append("/customKeywords>UID>"); urlSpec.Append(char(hierarchySeparator)); urlSpec.Append((const char *) folderName); urlSpec.Append(">"); urlSpec.Append(uids); urlSpec.Append(">"); urlSpec.Append(flagsToAdd); urlSpec.Append(">"); urlSpec.Append(flagsToSubtract); rv = mailNewsUrl->SetSpec(urlSpec); if (NS_SUCCEEDED(rv)) rv = GetImapConnectionAndLoadUrl(aClientEventQueue, imapUrl, nsnull, aURL); } } // if we have a url to run.... return rv; } NS_IMETHODIMP nsImapService::DownloadMessagesForOffline(const char *messageIds, nsIMsgFolder *aFolder, nsIUrlListener *aUrlListener, nsIMsgWindow *aMsgWindow) { NS_ENSURE_ARG_POINTER(aFolder); NS_ENSURE_ARG_POINTER(messageIds); nsCOMPtr imapUrl; nsCAutoString urlSpec; nsresult rv; PRUnichar hierarchySeparator = GetHierarchyDelimiter(aFolder); rv = CreateStartOfImapUrl(nsnull, getter_AddRefs(imapUrl), aFolder, nsnull, urlSpec, hierarchySeparator); if (NS_SUCCEEDED(rv) && imapUrl) { nsCOMPtr runningURI; // need to pass in stream listener in order to get the channel created correctly nsCOMPtr imapMessageSink(do_QueryInterface(aFolder, &rv)); rv = FetchMessage(imapUrl, nsImapUrl::nsImapMsgDownloadForOffline,aFolder, imapMessageSink, aMsgWindow, nsnull, messageIds, PR_FALSE, nsnull, getter_AddRefs(runningURI)); if (runningURI && aUrlListener) { nsCOMPtr msgurl (do_QueryInterface(runningURI)); if (msgurl) msgurl->RegisterListener(aUrlListener); } } return rv; } NS_IMETHODIMP nsImapService::MessageURIToMsgHdr(const char *uri, nsIMsgDBHdr **_retval) { NS_ENSURE_ARG_POINTER(uri); NS_ENSURE_ARG_POINTER(_retval); nsresult rv = NS_OK; nsCOMPtr folder; nsMsgKey msgKey; rv = DecomposeImapURI(uri, getter_AddRefs(folder), &msgKey); NS_ENSURE_SUCCESS(rv,rv); rv = folder->GetMessageHeader(msgKey, _retval); NS_ENSURE_SUCCESS(rv,rv); return NS_OK; } NS_IMETHODIMP nsImapService::PlaybackAllOfflineOperations(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener, nsISupports **aResult) { NS_ENSURE_ARG_POINTER(aResult); nsresult rv; nsImapOfflineSync *goOnline = new nsImapOfflineSync(aMsgWindow, aListener, nsnull); if (goOnline) { rv = goOnline->QueryInterface(NS_GET_IID(nsISupports), (void **) aResult); NS_ENSURE_SUCCESS(rv, rv); if (NS_SUCCEEDED(rv) && *aResult) return goOnline->ProcessNextOperation(); } return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsImapService::DownloadAllOffineImapFolders(nsIMsgWindow *aMsgWindow, nsIUrlListener *aListener) { nsImapOfflineDownloader *downloadForOffline = new nsImapOfflineDownloader(aMsgWindow, aListener); if (downloadForOffline) { // hold reference to this so it won't get deleted out from under itself. NS_ADDREF(downloadForOffline); nsresult rv = downloadForOffline->ProcessNextOperation(); NS_RELEASE(downloadForOffline); return rv; } return NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP nsImapService::GetCacheSession(nsICacheSession **result) { nsresult rv = NS_OK; if (!mCacheSession) { nsCOMPtr serv = do_GetService(kCacheServiceCID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = serv->CreateSession("IMAP-memory-only", nsICache::STORE_IN_MEMORY, nsICache::STREAM_BASED, getter_AddRefs(mCacheSession)); NS_ENSURE_SUCCESS(rv, rv); rv = mCacheSession->SetDoomEntriesIfExpired(PR_FALSE); } *result = mCacheSession; NS_IF_ADDREF(*result); return rv; } NS_IMETHODIMP nsImapService::HandleContent(const char * aContentType, nsIInterfaceRequestor* aWindowContext, nsIRequest *request) { nsresult rv; NS_ENSURE_ARG_POINTER(request); nsCOMPtr aChannel = do_QueryInterface(request, &rv); NS_ENSURE_SUCCESS(rv, rv); if (nsCRT::strcasecmp(aContentType, "x-application-imapfolder") == 0) { nsCOMPtr uri; rv = aChannel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); if (uri) { request->Cancel(NS_BINDING_ABORTED); nsCOMPtr mediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCAutoString uriStr; uri->GetSpec(uriStr); // imap uri's are unescaped, so unescape the url. NS_UnescapeURL(uriStr); nsCOMPtr messengerWindowService = do_GetService(NS_MESSENGERWINDOWSERVICE_CONTRACTID,&rv); NS_ENSURE_SUCCESS(rv, rv); rv = messengerWindowService->OpenMessengerWindowWithUri("mail:3pane", uriStr.get(), nsMsgKey_None); NS_ENSURE_SUCCESS(rv, rv); } } else { // The content-type was not x-application-imapfolder return NS_ERROR_WONT_HANDLE_CONTENT; } return rv; }