summaryrefslogtreecommitdiffstats
path: root/mailnews/imap/src/nsImapUrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/imap/src/nsImapUrl.cpp')
-rw-r--r--mailnews/imap/src/nsImapUrl.cpp1561
1 files changed, 1561 insertions, 0 deletions
diff --git a/mailnews/imap/src/nsImapUrl.cpp b/mailnews/imap/src/nsImapUrl.cpp
new file mode 100644
index 000000000..8fd9f2f65
--- /dev/null
+++ b/mailnews/imap/src/nsImapUrl.cpp
@@ -0,0 +1,1561 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "msgCore.h" // precompiled header...
+#include "nsMsgImapCID.h"
+
+#include "nsIURL.h"
+#include "nsImapUrl.h"
+#include "nsIIMAPHostSessionList.h"
+#include "nsThreadUtils.h"
+#include "nsStringGlue.h"
+#include "prmem.h"
+#include "plstr.h"
+#include "prprf.h"
+#include "nsMemory.h"
+#include "nsCOMPtr.h"
+#include "nsIImapIncomingServer.h"
+#include "nsMsgBaseCID.h"
+#include "nsImapUtils.h"
+#include "nsIMAPNamespace.h"
+#include "nsICacheEntry.h"
+#include "nsIMsgFolder.h"
+#include "nsIDocShell.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsMsgUtils.h"
+#include "nsIMsgHdr.h"
+#include "nsIProgressEventSink.h"
+#include "nsServiceManagerUtils.h"
+
+using namespace mozilla;
+
+static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
+
+nsImapUrl::nsImapUrl() : mLock("nsImapUrl.mLock")
+{
+ m_listOfMessageIds = nullptr;
+ m_sourceCanonicalFolderPathSubString = nullptr;
+ m_destinationCanonicalFolderPathSubString = nullptr;
+ m_listOfMessageIds = nullptr;
+ m_tokenPlaceHolder = nullptr;
+ m_searchCriteriaString = nullptr;
+ m_idsAreUids = false;
+ m_mimePartSelectorDetected = false;
+ m_allowContentChange = true; // assume we can do MPOD.
+ m_fetchPartsOnDemand = false; // but assume we're not doing it :-)
+ m_msgLoadingFromCache = false;
+ m_storeResultsOffline = false;
+ m_storeOfflineOnFallback = false;
+ m_localFetchOnly = false;
+ m_rerunningUrl = false;
+ m_moreHeadersToDownload = false;
+ m_externalLinkUrl = true; // we'll start this at true, and set it false in nsImapService::CreateStartOfImapUrl
+ m_contentModified = IMAP_CONTENT_NOT_MODIFIED;
+ m_validUrl = true; // assume the best.
+ m_flags = 0;
+ m_extraStatus = ImapStatusNone;
+ m_onlineSubDirSeparator = '/';
+
+ // ** jt - the following are not ref counted
+ m_copyState = nullptr;
+ m_file = nullptr;
+ m_imapMailFolderSink = nullptr;
+ m_imapMessageSink = nullptr;
+ m_addDummyEnvelope = false;
+ m_canonicalLineEnding = false;
+}
+
+nsImapUrl::~nsImapUrl()
+{
+ PR_FREEIF(m_listOfMessageIds);
+ PR_FREEIF(m_destinationCanonicalFolderPathSubString);
+ PR_FREEIF(m_sourceCanonicalFolderPathSubString);
+ PR_FREEIF(m_searchCriteriaString);
+}
+
+NS_IMPL_ADDREF_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
+
+NS_IMPL_RELEASE_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
+
+NS_INTERFACE_MAP_BEGIN(nsImapUrl)
+ NS_INTERFACE_MAP_ENTRY(nsIImapUrl)
+ NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
+ NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
+NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
+
+////////////////////////////////////////////////////////////////////////////////////
+// Begin nsIImapUrl specific support
+////////////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP nsImapUrl::GetRequiredImapState(nsImapState * aImapUrlState)
+{
+ if (aImapUrlState)
+ {
+ // the imap action determines the state we must be in...check the
+ // the imap action.
+
+ if (m_imapAction & 0x10000000)
+ *aImapUrlState = nsImapSelectedState;
+ else
+ *aImapUrlState = nsImapAuthenticatedState;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetImapAction(nsImapAction * aImapAction)
+{
+ *aImapAction = m_imapAction;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetImapAction(nsImapAction aImapAction)
+{
+ m_imapAction = aImapAction;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetFolder(nsIMsgFolder **aMsgFolder)
+{
+ NS_ENSURE_ARG_POINTER(aMsgFolder);
+ NS_ENSURE_ARG_POINTER(m_imapFolder);
+
+ nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(m_imapFolder);
+ NS_IF_ADDREF(*aMsgFolder = folder);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetFolder(nsIMsgFolder * aMsgFolder)
+{
+ nsresult rv;
+ m_imapFolder = do_GetWeakReference(aMsgFolder, &rv);
+ if (aMsgFolder)
+ {
+ nsCOMPtr <nsIMsgIncomingServer> incomingServer;
+ aMsgFolder->GetServer(getter_AddRefs(incomingServer));
+ if (incomingServer)
+ incomingServer->GetKey(m_serverKey);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::GetImapMailFolderSink(nsIImapMailFolderSink **
+ aImapMailFolderSink)
+{
+ NS_ENSURE_ARG_POINTER(aImapMailFolderSink);
+ if (!m_imapMailFolderSink)
+ return NS_ERROR_NULL_POINTER; // no assert, so don't use NS_ENSURE_POINTER.
+
+ nsCOMPtr<nsIImapMailFolderSink> folderSink = do_QueryReferent(m_imapMailFolderSink);
+ *aImapMailFolderSink = folderSink;
+ NS_IF_ADDREF(*aImapMailFolderSink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetImapMailFolderSink(nsIImapMailFolderSink * aImapMailFolderSink)
+{
+ nsresult rv;
+ m_imapMailFolderSink = do_GetWeakReference(aImapMailFolderSink, &rv);
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::GetImapMessageSink(nsIImapMessageSink ** aImapMessageSink)
+{
+ NS_ENSURE_ARG_POINTER(aImapMessageSink);
+ NS_ENSURE_ARG_POINTER(m_imapMessageSink);
+
+ nsCOMPtr<nsIImapMessageSink> messageSink = do_QueryReferent(m_imapMessageSink);
+ *aImapMessageSink = messageSink;
+ NS_IF_ADDREF(*aImapMessageSink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetImapMessageSink(nsIImapMessageSink * aImapMessageSink)
+{
+ nsresult rv;
+ m_imapMessageSink = do_GetWeakReference(aImapMessageSink, &rv);
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::GetImapServerSink(nsIImapServerSink ** aImapServerSink)
+{
+ NS_ENSURE_ARG_POINTER(aImapServerSink);
+ NS_ENSURE_ARG_POINTER(m_imapServerSink);
+
+ nsCOMPtr<nsIImapServerSink> serverSink = do_QueryReferent(m_imapServerSink);
+ *aImapServerSink = serverSink;
+ NS_IF_ADDREF(*aImapServerSink);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetImapServerSink(nsIImapServerSink * aImapServerSink)
+{
+ nsresult rv;
+ m_imapServerSink = do_GetWeakReference(aImapServerSink, &rv);
+ return rv;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// End nsIImapUrl specific support
+////////////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP nsImapUrl::SetSpec(const nsACString &aSpec)
+{
+ nsresult rv = nsMsgMailNewsUrl::SetSpec(aSpec);
+ if (NS_SUCCEEDED(rv))
+ {
+ m_validUrl = true; // assume the best.
+ rv = ParseUrl();
+ }
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::SetQuery(const nsACString &aQuery)
+{
+ nsresult rv = nsMsgMailNewsUrl::SetQuery(aQuery);
+ if (NS_SUCCEEDED(rv))
+ rv = ParseUrl();
+ return rv;
+}
+
+nsresult nsImapUrl::ParseUrl()
+{
+ nsresult rv = NS_OK;
+ // extract the user name
+ GetUserPass(m_userName);
+
+ nsAutoCString imapPartOfUrl;
+ rv = GetPath(imapPartOfUrl);
+ nsAutoCString unescapedImapPartOfUrl;
+ MsgUnescapeString(imapPartOfUrl, 0, unescapedImapPartOfUrl);
+ if (NS_SUCCEEDED(rv) && !unescapedImapPartOfUrl.IsEmpty())
+ {
+ ParseImapPart(unescapedImapPartOfUrl.BeginWriting()+1); // GetPath leaves leading '/' in the path!!!
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::CreateSearchCriteriaString(char ** aResult)
+{
+ // this method should only be called from the imap thread...
+ // o.t. add lock protection..
+ if (nullptr == aResult || !m_searchCriteriaString)
+ return NS_ERROR_NULL_POINTER;
+ *aResult = strdup(m_searchCriteriaString);
+ return NS_OK;
+}
+
+// this method gets called from the UI thread and the imap thread
+NS_IMETHODIMP nsImapUrl::GetListOfMessageIds(nsACString &aResult)
+{
+ MutexAutoLock mon(mLock);
+ if (!m_listOfMessageIds)
+ return NS_ERROR_NULL_POINTER;
+
+ int32_t bytesToCopy = strlen(m_listOfMessageIds);
+
+ // mime may have glommed a "&part=" for a part download
+ // we return the entire message and let mime extract
+ // the part. Pop and news work this way also.
+ // this algorithm truncates the "&part" string.
+ char *currentChar = m_listOfMessageIds;
+ while (*currentChar && (*currentChar != '?'))
+ currentChar++;
+ if (*currentChar == '?')
+ bytesToCopy = currentChar - m_listOfMessageIds;
+
+ // we should also strip off anything after "/;section="
+ // since that can specify an IMAP MIME part
+ char *wherePart = PL_strstr(m_listOfMessageIds, "/;section=");
+ if (wherePart)
+ bytesToCopy = std::min(bytesToCopy, int32_t(wherePart - m_listOfMessageIds));
+
+ aResult.Assign(m_listOfMessageIds, bytesToCopy);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCommand(nsACString &result)
+{
+ result = m_command;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImapUrl::GetCustomAttributeToFetch(nsACString &result)
+{
+ result = m_msgFetchAttribute;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCustomAttributeResult(nsACString &result)
+{
+ result = m_customAttributeResult;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetCustomAttributeResult(const nsACString &result)
+{
+ m_customAttributeResult = result;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCustomCommandResult(nsACString &result)
+{
+ result = m_customCommandResult;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetCustomCommandResult(const nsACString &result)
+{
+ m_customCommandResult = result;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCustomAddFlags(nsACString &aResult)
+{
+ aResult = m_customAddFlags;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCustomSubtractFlags(nsACString &aResult)
+{
+ aResult = m_customSubtractFlags;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImapUrl::GetImapPartToFetch(char **result)
+{
+ // here's the old code....
+
+ // unforunately an imap part can have the form: /;section= OR
+ // it can have the form ?section=. We need to look for both.
+ if (m_listOfMessageIds)
+ {
+ char *wherepart = PL_strstr(m_listOfMessageIds, ";section=");
+ if (!wherepart) // look for ?section too....
+ wherepart = PL_strstr(m_listOfMessageIds, "?section=");
+ if (wherepart)
+ {
+ wherepart += 9; // strlen("/;section=")
+ char *wherelibmimepart = PL_strstr(wherepart, "&part=");
+ if (!wherelibmimepart)
+ wherelibmimepart = PL_strstr(wherepart, "?part=");
+ int numCharsToCopy = (wherelibmimepart) ? wherelibmimepart - wherepart :
+ PL_strlen(m_listOfMessageIds) - (wherepart - m_listOfMessageIds);
+ if (numCharsToCopy)
+ {
+ *result = (char *) PR_Malloc(sizeof(char) * (numCharsToCopy + 1));
+ if (*result)
+ {
+ PL_strncpy(*result, wherepart, numCharsToCopy + 1); // appends a \0
+ (*result)[numCharsToCopy] = '\0';
+ }
+ }
+ } // if we got a wherepart
+ } // if we got a m_listOfMessageIds
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetOnlineSubDirSeparator(char* separator)
+{
+ if (separator)
+ {
+ *separator = m_onlineSubDirSeparator;
+ return NS_OK;
+ }
+ else
+ {
+ return NS_ERROR_NULL_POINTER;
+ }
+}
+
+NS_IMETHODIMP nsImapUrl::GetNumBytesToFetch(int32_t *aNumBytesToFetch)
+{
+ NS_ENSURE_ARG_POINTER(aNumBytesToFetch);
+ *aNumBytesToFetch = m_numBytesToFetch;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsImapUrl::SetOnlineSubDirSeparator(char onlineDirSeparator)
+{
+ m_onlineSubDirSeparator = onlineDirSeparator;
+ return NS_OK;
+}
+
+// this method is only called from the imap thread
+NS_IMETHODIMP nsImapUrl::MessageIdsAreUids(bool *result)
+{
+ *result = m_idsAreUids;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsImapUrl::SetExtraStatus(int32_t aExtraStatus)
+{
+ m_extraStatus = aExtraStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetExtraStatus(int32_t *aResult)
+{
+ NS_ENSURE_ARG_POINTER(aResult);
+ *aResult = m_extraStatus;
+ return NS_OK;
+}
+
+// this method is only called from the imap thread
+NS_IMETHODIMP nsImapUrl::GetMsgFlags(imapMessageFlagsType *result) // kAddMsgFlags or kSubtractMsgFlags only
+{
+ *result = m_flags;
+ return NS_OK;
+}
+
+void nsImapUrl::ParseImapPart(char *imapPartOfUrl)
+{
+ m_tokenPlaceHolder = imapPartOfUrl;
+ m_urlidSubString = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
+
+ if (!m_urlidSubString)
+ {
+ m_validUrl = false;
+ return;
+ }
+
+ if (!PL_strcasecmp(m_urlidSubString, "fetch"))
+ {
+ m_imapAction = nsImapMsgFetch;
+ ParseUidChoice();
+ PR_FREEIF(m_sourceCanonicalFolderPathSubString);
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ // if fetched by spam filter, the action will be changed to nsImapMsgFetchPeek
+ }
+ else
+ {
+ if (!PL_strcasecmp(m_urlidSubString, "header"))
+ {
+ m_imapAction = nsImapMsgHeader;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "customFetch"))
+ {
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseCustomMsgFetchAttribute();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "previewBody"))
+ {
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseNumBytes();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "deletemsg"))
+ {
+ m_imapAction = nsImapDeleteMsg;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "uidexpunge"))
+ {
+ m_imapAction = nsImapUidExpunge;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "deleteallmsgs"))
+ {
+ m_imapAction = nsImapDeleteAllMsgs;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "addmsgflags"))
+ {
+ m_imapAction = nsImapAddMsgFlags;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseMsgFlags();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "subtractmsgflags"))
+ {
+ m_imapAction = nsImapSubtractMsgFlags;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseMsgFlags();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "setmsgflags"))
+ {
+ m_imapAction = nsImapSetMsgFlags;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseMsgFlags();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "onlinecopy"))
+ {
+ m_imapAction = nsImapOnlineCopy;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "onlinemove"))
+ {
+ m_imapAction = nsImapOnlineMove;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "onlinetoofflinecopy"))
+ {
+ m_imapAction = nsImapOnlineToOfflineCopy;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "onlinetoofflinemove"))
+ {
+ m_imapAction = nsImapOnlineToOfflineMove;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "offlinetoonlinecopy"))
+ {
+ m_imapAction = nsImapOfflineToOnlineMove;
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "search"))
+ {
+ m_imapAction = nsImapSearch;
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseSearchCriteriaString();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "test"))
+ {
+ m_imapAction = nsImapTest;
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "select"))
+ {
+ m_imapAction = nsImapSelectFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
+ ParseListOfMessageIds();
+ else
+ m_listOfMessageIds = PL_strdup("");
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "liteselect"))
+ {
+ m_imapAction = nsImapLiteSelectFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "selectnoop"))
+ {
+ m_imapAction = nsImapSelectNoopFolder;
+ m_listOfMessageIds = PL_strdup("");
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "expunge"))
+ {
+ m_imapAction = nsImapExpungeFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ m_listOfMessageIds = PL_strdup(""); // no ids to UNDO
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "create"))
+ {
+ m_imapAction = nsImapCreateFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "ensureExists"))
+ {
+ m_imapAction = nsImapEnsureExistsFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "discoverchildren"))
+ {
+ m_imapAction = nsImapDiscoverChildrenUrl;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "discoverallboxes"))
+ {
+ m_imapAction = nsImapDiscoverAllBoxesUrl;
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "discoverallandsubscribedboxes"))
+ {
+ m_imapAction = nsImapDiscoverAllAndSubscribedBoxesUrl;
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "delete"))
+ {
+ m_imapAction = nsImapDeleteFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "deletefolder"))
+ {
+ m_imapAction = nsImapDeleteFolderAndMsgs;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "rename"))
+ {
+ m_imapAction = nsImapRenameFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "movefolderhierarchy"))
+ {
+ m_imapAction = nsImapMoveFolderHierarchy;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ if (m_tokenPlaceHolder && *m_tokenPlaceHolder) // handle promote to root
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "list"))
+ {
+ m_imapAction = nsImapLsubFolders;
+ ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "biff"))
+ {
+ m_imapAction = nsImapBiff;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "netscape"))
+ {
+ m_imapAction = nsImapGetMailAccountUrl;
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "appendmsgfromfile"))
+ {
+ m_imapAction = nsImapAppendMsgFromFile;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "appenddraftfromfile"))
+ {
+ m_imapAction = nsImapAppendDraftFromFile;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseUidChoice();
+ if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
+ ParseListOfMessageIds();
+ else
+ m_listOfMessageIds = strdup("");
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "subscribe"))
+ {
+ m_imapAction = nsImapSubscribe;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "unsubscribe"))
+ {
+ m_imapAction = nsImapUnsubscribe;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "refreshacl"))
+ {
+ m_imapAction = nsImapRefreshACL;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "refreshfolderurls"))
+ {
+ m_imapAction = nsImapRefreshFolderUrls;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "refreshallacls"))
+ {
+ m_imapAction = nsImapRefreshAllACLs;
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "listfolder"))
+ {
+ m_imapAction = nsImapListFolder;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "upgradetosubscription"))
+ {
+ m_imapAction = nsImapUpgradeToSubscription;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "folderstatus"))
+ {
+ m_imapAction = nsImapFolderStatus;
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ }
+ else if (!PL_strcasecmp(m_urlidSubString, "verifyLogon"))
+ {
+ m_imapAction = nsImapVerifylogon;
+ }
+ else if (m_imapAction == nsIImapUrl::nsImapUserDefinedMsgCommand)
+ {
+ m_command = m_urlidSubString; // save this
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ }
+ else if (m_imapAction == nsIImapUrl::nsImapMsgStoreCustomKeywords)
+ {
+ ParseUidChoice();
+ ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
+ ParseListOfMessageIds();
+ bool addKeyword = (m_tokenPlaceHolder && *m_tokenPlaceHolder != '>');
+ // if we're not adding a keyword, m_tokenPlaceHolder will now look like >keywordToSubtract>
+ // and strtok will leave flagsPtr pointing to keywordToSubtract. So detect this
+ // case and only set the customSubtractFlags.
+ char *flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nullptr;
+ if (addKeyword)
+ {
+ m_customAddFlags.Assign(flagsPtr);
+ flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nullptr;
+ }
+ m_customSubtractFlags.Assign(flagsPtr);
+ }
+ else
+ {
+ m_validUrl = false;
+ }
+ }
+}
+
+
+// Returns NULL if nothing was done.
+// Otherwise, returns a newly allocated name.
+NS_IMETHODIMP nsImapUrl::AddOnlineDirectoryIfNecessary(const char *onlineMailboxName, char ** directory)
+{
+ nsresult rv;
+ nsString onlineDirString;
+ char *newOnlineName = nullptr;
+
+ nsCOMPtr<nsIImapHostSessionList> hostSessionList =
+ do_GetService(kCImapHostSessionListCID, &rv);
+ if (NS_FAILED(rv)) return rv;
+ rv = hostSessionList->GetOnlineDirForHost(m_serverKey.get(), onlineDirString);
+ nsAutoCString onlineDir;
+ LossyCopyUTF16toASCII(onlineDirString, onlineDir);
+
+ nsIMAPNamespace *ns = nullptr;
+ rv = hostSessionList->GetNamespaceForMailboxForHost(m_serverKey.get(),
+ onlineMailboxName, ns);
+ if (!ns)
+ hostSessionList->GetDefaultNamespaceOfTypeForHost(m_serverKey.get(),
+ kPersonalNamespace, ns);
+
+ if (onlineDir.IsEmpty() && ns)
+ onlineDir = ns->GetPrefix();
+
+ // If this host has an online server directory configured
+ if (onlineMailboxName && !onlineDir.IsEmpty())
+ {
+ if (PL_strcasecmp(onlineMailboxName, "INBOX"))
+ {
+ NS_ASSERTION(ns, "couldn't find namespace for host");
+ nsAutoCString onlineDirWithDelimiter(onlineDir);
+ // make sure the onlineDir ends with the hierarchy delimiter
+ if (ns)
+ {
+ char delimiter = ns->GetDelimiter();
+ if ( delimiter && delimiter != kOnlineHierarchySeparatorUnknown )
+ {
+ // try to change the canonical online dir name to real dir name first
+ MsgReplaceChar(onlineDirWithDelimiter, '/', delimiter);
+ // make sure the last character is the delimiter
+ if ( onlineDirWithDelimiter.Last() != delimiter )
+ onlineDirWithDelimiter += delimiter;
+ if ( !*onlineMailboxName )
+ onlineDirWithDelimiter.SetLength(onlineDirWithDelimiter.Length()-1);
+ }
+ }
+ if (ns && (PL_strlen(ns->GetPrefix()) != 0) && !onlineDirWithDelimiter.Equals(ns->GetPrefix()))
+ {
+ // check that onlineMailboxName doesn't start with the namespace. If that's the case,
+ // we don't want to prepend the online dir.
+ if (PL_strncmp(onlineMailboxName, ns->GetPrefix(), PL_strlen(ns->GetPrefix())))
+ {
+ // The namespace for this mailbox is the root ("").
+ // Prepend the online server directory
+ int finalLen = onlineDirWithDelimiter.Length() +
+ strlen(onlineMailboxName) + 1;
+ newOnlineName = (char *)PR_Malloc(finalLen);
+ if (newOnlineName)
+ {
+ PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
+ PL_strcat(newOnlineName, onlineMailboxName);
+ }
+ }
+ }
+ // just prepend the online server directory if it doesn't start with it already
+ else if (strncmp(onlineMailboxName, onlineDirWithDelimiter.get(), onlineDirWithDelimiter.Length()))
+ {
+ newOnlineName = (char *)PR_Malloc(strlen(onlineMailboxName) + onlineDirWithDelimiter.Length() + 1);
+ if (newOnlineName)
+ {
+ PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
+ PL_strcat(newOnlineName, onlineMailboxName);
+ }
+ }
+ }
+ }
+ if (directory)
+ *directory = newOnlineName;
+ else if (newOnlineName)
+ NS_Free(newOnlineName);
+ return rv;
+}
+
+// Converts from canonical format (hierarchy is indicated by '/' and all real slashes ('/') are escaped)
+// to the real online name on the server.
+NS_IMETHODIMP nsImapUrl::AllocateServerPath(const char * canonicalPath, char onlineDelimiter, char ** aAllocatedPath)
+{
+ nsresult retVal = NS_OK;
+ char *rv = NULL;
+ char delimiterToUse = onlineDelimiter;
+ if (onlineDelimiter == kOnlineHierarchySeparatorUnknown)
+ GetOnlineSubDirSeparator(&delimiterToUse);
+ NS_ASSERTION(delimiterToUse != kOnlineHierarchySeparatorUnknown, "hierarchy separator unknown");
+ if (canonicalPath)
+ rv = ReplaceCharsInCopiedString(canonicalPath, '/', delimiterToUse);
+ else
+ rv = strdup("");
+
+ if (delimiterToUse != '/')
+ UnescapeSlashes(rv);
+ char *onlineNameAdded = nullptr;
+ AddOnlineDirectoryIfNecessary(rv, &onlineNameAdded);
+ if (onlineNameAdded)
+ {
+ NS_Free(rv);
+ rv = onlineNameAdded;
+ }
+
+ if (aAllocatedPath)
+ *aAllocatedPath = rv;
+ else
+ NS_Free(rv);
+
+ return retVal;
+}
+
+// escape '/' as ^, ^ -> ^^ - use UnescapeSlashes to revert
+/* static */ nsresult nsImapUrl::EscapeSlashes(const char *sourcePath, char **resultPath)
+{
+ NS_ENSURE_ARG(sourcePath);
+ NS_ENSURE_ARG(resultPath);
+ int32_t extra = 0;
+ int32_t len = strlen(sourcePath);
+ const char *src = sourcePath;
+ int32_t i;
+ for ( i = 0; i < len; i++)
+ {
+ if (*src == '^')
+ extra += 1; /* ^ -> ^^ */
+ src++;
+ }
+ char* result = (char *)moz_xmalloc(len + extra + 1);
+ if (!result)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ unsigned char* dst = (unsigned char *) result;
+ src = sourcePath;
+ for (i = 0; i < len; i++)
+ {
+ unsigned char c = *src++;
+ if (c == '/')
+ *dst++ = '^';
+ else if (c == '^')
+ {
+ *dst++ = '^';
+ *dst++ = '^';
+ }
+ else
+ *dst++ = c;
+ }
+ *dst = '\0'; /* tack on eos */
+ *resultPath = result;
+ return NS_OK;
+}
+
+/* static */ nsresult nsImapUrl::UnescapeSlashes(char *sourcePath)
+{
+ char *src = sourcePath;
+ char *dst = sourcePath;
+
+ while (*src)
+ {
+ if (*src == '^')
+ {
+ if (*(src + 1) == '^')
+ {
+ *dst++ = '^';
+ src++; // skip over second '^'
+ }
+ else
+ *dst++ = '/';
+ src++;
+ }
+ else
+ *dst++ = *src++;
+ }
+
+ *dst = 0;
+ return NS_OK;
+}
+
+/* static */ nsresult nsImapUrl::ConvertToCanonicalFormat(const char *folderName, char onlineDelimiter, char **resultingCanonicalPath)
+{
+ // Now, start the conversion to canonical form.
+
+ char *canonicalPath;
+ if (onlineDelimiter != '/')
+ {
+ nsCString escapedPath;
+
+ EscapeSlashes(folderName, getter_Copies(escapedPath));
+ canonicalPath = ReplaceCharsInCopiedString(escapedPath.get(), onlineDelimiter , '/');
+ }
+ else
+ {
+ canonicalPath = strdup(folderName);
+ }
+ if (canonicalPath)
+ *resultingCanonicalPath = canonicalPath;
+
+ return (canonicalPath) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+// Converts the real online name on the server to canonical format:
+// result is hierarchy is indicated by '/' and all real slashes ('/') are escaped.
+// The caller has already converted m-utf-7 to 8 bit ascii, which is a problem.
+// this method is only called from the imap thread
+NS_IMETHODIMP nsImapUrl::AllocateCanonicalPath(const char *serverPath, char onlineDelimiter, char **allocatedPath )
+{
+ nsresult rv = NS_ERROR_NULL_POINTER;
+ char delimiterToUse = onlineDelimiter;
+ char *serverKey = nullptr;
+ nsString aString;
+ char *currentPath = (char *) serverPath;
+ nsAutoCString onlineDir;
+ nsCOMPtr<nsIMsgIncomingServer> server;
+
+ nsCOMPtr<nsIImapHostSessionList> hostSessionList =
+ do_GetService(kCImapHostSessionListCID, &rv);
+
+ *allocatedPath = nullptr;
+
+ if (onlineDelimiter == kOnlineHierarchySeparatorUnknown ||
+ onlineDelimiter == 0)
+ GetOnlineSubDirSeparator(&delimiterToUse);
+
+ NS_ASSERTION (serverPath, "Oops... null serverPath");
+
+ if (!serverPath || NS_FAILED(rv))
+ goto done;
+
+ hostSessionList->GetOnlineDirForHost(m_serverKey.get(), aString);
+ // First we have to check to see if we should strip off an online server
+ // subdirectory
+ // If this host has an online server directory configured
+ LossyCopyUTF16toASCII(aString, onlineDir);
+
+ if (currentPath && !onlineDir.IsEmpty())
+ {
+ // By definition, the online dir must be at the root.
+ if (delimiterToUse && delimiterToUse != kOnlineHierarchySeparatorUnknown)
+ {
+ // try to change the canonical online dir name to real dir name first
+ MsgReplaceChar(onlineDir, '/', delimiterToUse);
+ // Add the delimiter
+ if (onlineDir.Last() != delimiterToUse)
+ onlineDir += delimiterToUse;
+ }
+ int len = onlineDir.Length();
+ if (!PL_strncmp(onlineDir.get(), currentPath, len))
+ {
+ // This online path begins with the server sub directory
+ currentPath += len;
+
+ // This might occur, but it's most likely something not good.
+ // Basically, it means we're doing something on the online sub directory itself.
+ NS_ASSERTION (*currentPath, "Oops ... null currentPath");
+ // Also make sure that the first character in the mailbox name is not '/'.
+ NS_ASSERTION (*currentPath != '/',
+ "Oops ... currentPath starts with a slash");
+ }
+ }
+
+
+ if (!currentPath)
+ goto done;
+
+ rv = ConvertToCanonicalFormat(currentPath, delimiterToUse, allocatedPath);
+
+done:
+ PR_Free(serverKey);
+ return rv;
+}
+
+// this method is only called from the imap thread
+NS_IMETHODIMP nsImapUrl::CreateServerSourceFolderPathString(char **result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ AllocateServerPath(m_sourceCanonicalFolderPathSubString, kOnlineHierarchySeparatorUnknown, result);
+ return NS_OK;
+}
+
+// this method is called from the imap thread AND the UI thread...
+NS_IMETHODIMP nsImapUrl::CreateCanonicalSourceFolderPathString(char **result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ MutexAutoLock mon(mLock);
+ *result = strdup(m_sourceCanonicalFolderPathSubString ? m_sourceCanonicalFolderPathSubString : "");
+ return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+// this method is called from the imap thread AND the UI thread...
+NS_IMETHODIMP nsImapUrl::CreateServerDestinationFolderPathString(char **result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ MutexAutoLock mon(mLock);
+ nsresult rv = AllocateServerPath(m_destinationCanonicalFolderPathSubString,
+ kOnlineHierarchySeparatorUnknown,
+ result);
+ return (*result) ? rv : NS_ERROR_OUT_OF_MEMORY;
+}
+
+// for enabling or disabling mime parts on demand. Setting this to true says we
+// can use mime parts on demand, if we chose.
+NS_IMETHODIMP nsImapUrl::SetAllowContentChange(bool allowContentChange)
+{
+ m_allowContentChange = allowContentChange;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetContentModified(nsImapContentModifiedType contentModified)
+{
+ m_contentModified = contentModified;
+ nsCOMPtr<nsICacheEntry> cacheEntry;
+ nsresult res = GetMemCacheEntry(getter_AddRefs(cacheEntry));
+ if (NS_SUCCEEDED(res) && cacheEntry)
+ {
+ const char *contentModifiedAnnotation = "";
+ switch (m_contentModified)
+ {
+ case IMAP_CONTENT_NOT_MODIFIED:
+ contentModifiedAnnotation = "Not Modified";
+ break;
+ case IMAP_CONTENT_MODIFIED_VIEW_INLINE:
+ contentModifiedAnnotation = "Modified View Inline";
+ break;
+ case IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS:
+ contentModifiedAnnotation = "Modified View As Link";
+ break;
+ case IMAP_CONTENT_FORCE_CONTENT_NOT_MODIFIED:
+ contentModifiedAnnotation = "Force Content Not Modified";
+ break;
+ }
+ cacheEntry->SetMetaDataElement("ContentModified", contentModifiedAnnotation);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetContentModified(nsImapContentModifiedType *contentModified)
+{
+ if (!contentModified) return NS_ERROR_NULL_POINTER;
+
+ *contentModified = m_contentModified;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetFetchPartsOnDemand(bool fetchPartsOnDemand)
+{
+ m_fetchPartsOnDemand = fetchPartsOnDemand;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetFetchPartsOnDemand(bool *fetchPartsOnDemand)
+{
+ if (!fetchPartsOnDemand) return NS_ERROR_NULL_POINTER;
+
+ *fetchPartsOnDemand = m_fetchPartsOnDemand;
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsImapUrl::SetMimePartSelectorDetected(bool mimePartSelectorDetected)
+{
+ m_mimePartSelectorDetected = mimePartSelectorDetected;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetMimePartSelectorDetected(bool *mimePartSelectorDetected)
+{
+ if (!mimePartSelectorDetected) return NS_ERROR_NULL_POINTER;
+
+ *mimePartSelectorDetected = m_mimePartSelectorDetected;
+ return NS_OK;
+}
+
+
+// this method is only called from the UI thread.
+NS_IMETHODIMP nsImapUrl::SetCopyState(nsISupports* copyState)
+{
+ MutexAutoLock mon(mLock);
+ m_copyState = copyState;
+ return NS_OK;
+}
+
+//this method is only called from the imap thread..but we still
+// need a monitor 'cause the setter is called from the UI thread.
+NS_IMETHODIMP nsImapUrl::GetCopyState(nsISupports** copyState)
+{
+ NS_ENSURE_ARG_POINTER(copyState);
+ MutexAutoLock mon(mLock);
+ *copyState = m_copyState;
+ NS_IF_ADDREF(*copyState);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsImapUrl::SetMsgFile(nsIFile* aFile)
+{
+ nsresult rv = NS_OK;
+ MutexAutoLock mon(mLock);
+ m_file = aFile;
+ return rv;
+}
+
+NS_IMETHODIMP
+nsImapUrl::GetMsgFile(nsIFile** aFile)
+{
+ NS_ENSURE_ARG_POINTER(aFile);
+
+ MutexAutoLock mon(mLock);
+ NS_IF_ADDREF(*aFile = m_file);
+ return NS_OK;
+}
+
+// this method is called from the UI thread..
+NS_IMETHODIMP nsImapUrl::GetMockChannel(nsIImapMockChannel ** aChannel)
+{
+ NS_ENSURE_ARG_POINTER(aChannel);
+ NS_WARNING_ASSERTION(NS_IsMainThread(), "should only access mock channel on ui thread");
+ *aChannel = nullptr;
+ nsCOMPtr<nsIImapMockChannel> channel(do_QueryReferent(m_channelWeakPtr));
+ channel.swap(*aChannel);
+ return *aChannel ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP nsImapUrl::SetMockChannel(nsIImapMockChannel * aChannel)
+{
+ NS_WARNING_ASSERTION(NS_IsMainThread(), "should only access mock channel on ui thread");
+ m_channelWeakPtr = do_GetWeakReference(aChannel);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetAllowContentChange(bool *result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ *result = m_allowContentChange;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::CloneInternal(uint32_t aRefHandlingMode,
+ const nsACString& newRef,
+ nsIURI** _retval)
+{
+ nsresult rv =
+ nsMsgMailNewsUrl::CloneInternal(aRefHandlingMode, newRef, _retval);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // also clone the mURI member, because GetUri below won't work if
+ // mURI isn't set due to escaping issues.
+ nsCOMPtr <nsIMsgMessageUrl> clonedUrl = do_QueryInterface(*_retval);
+ if (clonedUrl)
+ clonedUrl->SetUri(mURI.get());
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::GetPrincipalSpec(nsACString& aPrincipalSpec)
+{
+ // URLs look like this:
+ // imap://user@domain@server:port/fetch>UID>folder>nn
+ // We simply strip any query part beginning with ? & or /;
+ // Normalised spec: imap://user@domain@server:port/fetch>UID>folder>nn
+ nsCOMPtr<nsIMsgMailNewsUrl> mailnewsURL;
+ QueryInterface(NS_GET_IID(nsIMsgMailNewsUrl), getter_AddRefs(mailnewsURL));
+
+ nsAutoCString spec;
+ mailnewsURL->GetSpecIgnoringRef(spec);
+
+ // Strip any query part beginning with ? or /;
+ int32_t ind = spec.Find("/;");
+ if (ind != kNotFound)
+ spec.SetLength(ind);
+
+ ind = spec.FindChar('?');
+ if (ind != kNotFound)
+ spec.SetLength(ind);
+
+ aPrincipalSpec.Assign(spec);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetUri(const char * aURI)
+{
+ mURI= aURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetUri(char** aURI)
+{
+ nsresult rv = NS_OK;
+ if (!mURI.IsEmpty())
+ *aURI = ToNewCString(mURI);
+ else
+ {
+ *aURI = nullptr;
+ uint32_t key = m_listOfMessageIds ? strtoul(m_listOfMessageIds, nullptr, 10) : 0;
+ nsCString canonicalPath;
+ AllocateCanonicalPath(m_sourceCanonicalFolderPathSubString, m_onlineSubDirSeparator, (getter_Copies(canonicalPath)));
+ nsCString fullFolderPath("/");
+ fullFolderPath.Append(m_userName);
+ nsAutoCString hostName;
+ rv = GetHost(hostName);
+ fullFolderPath.Append('@');
+ fullFolderPath.Append(hostName);
+ fullFolderPath.Append('/');
+ fullFolderPath.Append(canonicalPath);
+
+ nsCString baseMessageURI;
+ nsCreateImapBaseMessageURI(fullFolderPath, baseMessageURI);
+ nsAutoCString uriStr;
+ rv = nsBuildImapMessageURI(baseMessageURI.get(), key, uriStr);
+ *aURI = ToNewCString(uriStr);
+ }
+ return rv;
+}
+
+NS_IMPL_GETSET(nsImapUrl, AddDummyEnvelope, bool, m_addDummyEnvelope)
+NS_IMPL_GETSET(nsImapUrl, CanonicalLineEnding, bool, m_canonicalLineEnding)
+NS_IMETHODIMP nsImapUrl::GetMsgLoadingFromCache(bool *result)
+{
+ NS_ENSURE_ARG_POINTER(result);
+ *result = m_msgLoadingFromCache;
+ return NS_OK;
+}
+NS_IMPL_GETSET(nsImapUrl, LocalFetchOnly, bool, m_localFetchOnly)
+NS_IMPL_GETSET(nsImapUrl, ExternalLinkUrl, bool, m_externalLinkUrl)
+NS_IMPL_GETSET(nsImapUrl, RerunningUrl, bool, m_rerunningUrl)
+NS_IMPL_GETSET(nsImapUrl, ValidUrl, bool, m_validUrl)
+NS_IMPL_GETSET(nsImapUrl, MoreHeadersToDownload, bool, m_moreHeadersToDownload)
+
+NS_IMETHODIMP nsImapUrl::SetMsgLoadingFromCache(bool loadingFromCache)
+{
+ nsresult rv = NS_OK;
+ m_msgLoadingFromCache = loadingFromCache;
+ return rv;
+}
+
+NS_IMETHODIMP nsImapUrl::SetMessageFile(nsIFile * aFile)
+{
+ m_messageFile = aFile;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetMessageFile(nsIFile ** aFile)
+{
+ if (aFile)
+ NS_IF_ADDREF(*aFile = m_messageFile);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::IsUrlType(uint32_t type, bool *isType)
+{
+ NS_ENSURE_ARG(isType);
+
+ switch(type)
+ {
+ case nsIMsgMailNewsUrl::eCopy:
+ *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineCopy) ||
+ (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineCopy) ||
+ (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineCopy));
+ break;
+ case nsIMsgMailNewsUrl::eMove:
+ *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineMove) ||
+ (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineMove) ||
+ (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineMove));
+ break;
+ case nsIMsgMailNewsUrl::eDisplay:
+ *isType = (m_imapAction == nsIImapUrl::nsImapMsgFetch ||
+ m_imapAction == nsIImapUrl::nsImapMsgFetchPeek);
+ break;
+ default:
+ *isType = false;
+ };
+
+ return NS_OK;
+
+}
+
+NS_IMETHODIMP
+nsImapUrl::GetOriginalSpec(char ** aSpec)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsImapUrl::SetOriginalSpec(const char *aSpec)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+char *nsImapUrl::ReplaceCharsInCopiedString(const char *stringToCopy, char oldChar, char newChar)
+{
+ char oldCharString[2];
+ *oldCharString = oldChar;
+ *(oldCharString+1) = 0;
+
+ char *translatedString = PL_strdup(stringToCopy);
+ char *currentSeparator = PL_strstr(translatedString, oldCharString);
+
+ while(currentSeparator)
+ {
+ *currentSeparator = newChar;
+ currentSeparator = PL_strstr(currentSeparator+1, oldCharString);
+ }
+
+ return translatedString;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// End of functions which should be made obsolete after modifying nsIURI
+////////////////////////////////////////////////////////////////////////////////////
+
+void nsImapUrl::ParseFolderPath(char **resultingCanonicalPath)
+{
+ char *resultPath = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
+
+ if (!resultPath)
+ {
+ m_validUrl = false;
+ return;
+ }
+ NS_ASSERTION(*resultingCanonicalPath == nullptr, "whoops, mem leak");
+
+ char dirSeparator = *resultPath;
+
+ nsCString unescapedResultingCanonicalPath;
+ MsgUnescapeString(nsDependentCString(resultPath + 1), 0, unescapedResultingCanonicalPath);
+ *resultingCanonicalPath = ToNewCString(unescapedResultingCanonicalPath);
+ // The delimiter will be set for a given URL, but will not be statically available
+ // from an arbitrary URL. It is the creator's responsibility to fill in the correct
+ // delimiter from the folder's namespace when creating the URL.
+ if (dirSeparator != kOnlineHierarchySeparatorUnknown)
+ SetOnlineSubDirSeparator( dirSeparator);
+
+ // if dirSeparator == kOnlineHierarchySeparatorUnknown, then this must be a create
+ // of a top level imap box. If there is an online subdir, we will automatically
+ // use its separator. If there is not an online subdir, we don't need a separator.
+}
+
+void nsImapUrl::ParseSearchCriteriaString()
+{
+ if (m_tokenPlaceHolder)
+ {
+ int quotedFlag = false;
+
+ //skip initial separator
+ while (*m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR)
+ m_tokenPlaceHolder++;
+
+ char *saveTokenPlaceHolder = m_tokenPlaceHolder;
+
+// m_searchCriteriaString = m_tokenPlaceHolder;
+
+ //looking for another separator outside quoted string
+ while (*m_tokenPlaceHolder)
+ {
+ if (*m_tokenPlaceHolder == '\\' && *(m_tokenPlaceHolder+1) == '"')
+ m_tokenPlaceHolder++;
+ else if (*m_tokenPlaceHolder == '"')
+ quotedFlag = !quotedFlag;
+ else if (!quotedFlag && *m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR)
+ {
+ *m_tokenPlaceHolder = '\0';
+ m_tokenPlaceHolder++;
+ break;
+ }
+ m_tokenPlaceHolder++;
+ }
+ m_searchCriteriaString = PL_strdup(saveTokenPlaceHolder);
+ if (*m_tokenPlaceHolder == '\0')
+ m_tokenPlaceHolder = NULL;
+
+ if (*m_searchCriteriaString == '\0')
+ m_searchCriteriaString = (char *)NULL;
+ }
+ else
+ m_searchCriteriaString = (char *)NULL;
+ if (!m_searchCriteriaString)
+ m_validUrl = false;
+}
+
+
+void nsImapUrl::ParseUidChoice()
+{
+ char *uidChoiceString = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
+ if (!uidChoiceString)
+ m_validUrl = false;
+ else
+ m_idsAreUids = strcmp(uidChoiceString, "UID") == 0;
+}
+
+void nsImapUrl::ParseMsgFlags()
+{
+ char *flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
+ if (flagsPtr)
+ {
+ // the url is encodes the flags byte as ascii
+ int intFlags = atoi(flagsPtr);
+ m_flags = (imapMessageFlagsType) intFlags; // cast here
+ }
+ else
+ m_flags = 0;
+}
+
+void nsImapUrl::ParseListOfMessageIds()
+{
+ m_listOfMessageIds = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)NULL;
+ if (!m_listOfMessageIds)
+ m_validUrl = false;
+ else
+ {
+ m_listOfMessageIds = strdup(m_listOfMessageIds);
+ m_mimePartSelectorDetected = PL_strstr(m_listOfMessageIds, "&part=") != 0 || PL_strstr(m_listOfMessageIds, "?part=") != 0;
+
+ // if we're asking for just the body, don't download the whole message. see
+ // nsMsgQuote::QuoteMessage() for the "header=" settings when replying to msgs.
+ if (!m_fetchPartsOnDemand)
+ m_fetchPartsOnDemand = (PL_strstr(m_listOfMessageIds, "?header=quotebody") != 0 ||
+ PL_strstr(m_listOfMessageIds, "?header=only") != 0);
+ // if it's a spam filter trying to fetch the msg, don't let it get marked read.
+ if (PL_strstr(m_listOfMessageIds,"?header=filter") != 0)
+ m_imapAction = nsImapMsgFetchPeek;
+ }
+}
+
+void nsImapUrl::ParseCustomMsgFetchAttribute()
+{
+ m_msgFetchAttribute = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : (char *)nullptr;
+}
+
+void nsImapUrl::ParseNumBytes()
+{
+ const char *numBytes = (m_tokenPlaceHolder) ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder) : 0;
+ m_numBytesToFetch = numBytes ? atoi(numBytes) : 0;
+}
+
+// nsIMsgI18NUrl support
+
+nsresult nsImapUrl::GetMsgFolder(nsIMsgFolder **msgFolder)
+{
+ // if we have a RDF URI, then try to get the folder for that URI and then ask the folder
+ // for it's charset....
+
+ nsCString uri;
+ GetUri(getter_Copies(uri));
+ NS_ENSURE_TRUE(!uri.IsEmpty(), NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIMsgDBHdr> msg;
+ GetMsgDBHdrFromURI(uri.get(), getter_AddRefs(msg));
+ NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
+ nsresult rv = msg->GetFolder(msgFolder);
+ NS_ENSURE_SUCCESS(rv,rv);
+ NS_ENSURE_TRUE(msgFolder, NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetFolderCharset(char ** aCharacterSet)
+{
+ nsCOMPtr<nsIMsgFolder> folder;
+ nsresult rv = GetMsgFolder(getter_AddRefs(folder));
+ NS_ENSURE_SUCCESS(rv,rv);
+ nsCString tmpStr;
+ folder->GetCharset(tmpStr);
+ *aCharacterSet = ToNewCString(tmpStr);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetFolderCharsetOverride(bool * aCharacterSetOverride)
+{
+ nsCOMPtr<nsIMsgFolder> folder;
+ nsresult rv = GetMsgFolder(getter_AddRefs(folder));
+ NS_ENSURE_SUCCESS(rv,rv);
+ NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
+ folder->GetCharsetOverride(aCharacterSetOverride);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetCharsetOverRide(char ** aCharacterSet)
+{
+ if (!mCharsetOverride.IsEmpty())
+ *aCharacterSet = ToNewCString(mCharsetOverride);
+ else
+ *aCharacterSet = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetCharsetOverRide(const char * aCharacterSet)
+{
+ mCharsetOverride = aCharacterSet;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetStoreResultsOffline(bool *aStoreResultsOffline)
+{
+ NS_ENSURE_ARG_POINTER(aStoreResultsOffline);
+ *aStoreResultsOffline = m_storeResultsOffline;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetStoreResultsOffline(bool aStoreResultsOffline)
+{
+ m_storeResultsOffline = aStoreResultsOffline;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetStoreOfflineOnFallback(bool *aStoreOfflineOnFallback)
+{
+ NS_ENSURE_ARG_POINTER(aStoreOfflineOnFallback);
+ *aStoreOfflineOnFallback = m_storeOfflineOnFallback;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::SetStoreOfflineOnFallback(bool aStoreOfflineOnFallback)
+{
+ m_storeOfflineOnFallback = aStoreOfflineOnFallback;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImapUrl::GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)
+{
+ nsCString uri;
+ nsresult rv = GetUri(getter_Copies(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+ return GetMsgDBHdrFromURI(uri.get(), aMsgHdr);
+}
+
+NS_IMETHODIMP nsImapUrl::SetMessageHeader(nsIMsgDBHdr *aMsgHdr)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}