1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "msgCore.h" // precompiled header...
7 #include "nsMsgImapCID.h"
8
9 #include "nsImapUrl.h"
10 #include "nsIImapHostSessionList.h"
11 #include "nsThreadUtils.h"
12 #include "nsString.h"
13 #include "prmem.h"
14 #include "plstr.h"
15 #include "prprf.h"
16 #include "nsMemory.h"
17 #include "nsCOMPtr.h"
18 #include "nsMsgBaseCID.h"
19 #include "nsImapUtils.h"
20 #include "nsIImapMockChannel.h"
21 #include "nsIImapMailFolderSink.h"
22 #include "nsIImapMessageSink.h"
23 #include "nsIImapServerSink.h"
24 #include "nsImapNamespace.h"
25 #include "nsICacheEntry.h"
26 #include "nsIMsgFolder.h"
27 #include "nsMsgUtils.h"
28 #include "nsIMsgHdr.h"
29 #include "nsServiceManagerUtils.h"
30 #include "mozilla/Logging.h"
31
32 using namespace mozilla;
33 extern LazyLogModule IMAPCache; // defined in nsImapProtocol.cpp
34
35 static NS_DEFINE_CID(kCImapHostSessionListCID, NS_IIMAPHOSTSESSIONLIST_CID);
36
nsImapUrl()37 nsImapUrl::nsImapUrl() : mLock("nsImapUrl.mLock") {
38 m_listOfMessageIds = nullptr;
39 m_sourceCanonicalFolderPathSubString = nullptr;
40 m_destinationCanonicalFolderPathSubString = nullptr;
41 m_listOfMessageIds = nullptr;
42 m_tokenPlaceHolder = nullptr;
43 m_searchCriteriaString = nullptr;
44 m_idsAreUids = false;
45 m_mimePartSelectorDetected = false;
46 m_allowContentChange = true; // assume we can do MPOD.
47 m_fetchPartsOnDemand = false; // but assume we're not doing it :-)
48 m_msgLoadingFromCache = false;
49 m_storeResultsOffline = false;
50 m_storeOfflineOnFallback = false;
51 m_localFetchOnly = false;
52 m_rerunningUrl = false;
53 m_moreHeadersToDownload = false;
54 m_externalLinkUrl = true; // we'll start this at true, and set it false in
55 // nsImapService::CreateStartOfImapUrl
56 m_contentModified = IMAP_CONTENT_NOT_MODIFIED;
57 m_validUrl = true; // assume the best.
58 m_flags = 0;
59 m_extraStatus = ImapStatusNone;
60 m_onlineSubDirSeparator = '/';
61 m_imapAction = 0;
62 mOverrideCharset = false;
63
64 // ** jt - the following are not ref counted
65 m_copyState = nullptr;
66 m_file = nullptr;
67 m_imapMailFolderSink = nullptr;
68 m_imapMessageSink = nullptr;
69 m_addDummyEnvelope = false;
70 m_canonicalLineEnding = false;
71 }
72
~nsImapUrl()73 nsImapUrl::~nsImapUrl() {
74 PR_FREEIF(m_listOfMessageIds);
75 PR_FREEIF(m_destinationCanonicalFolderPathSubString);
76 PR_FREEIF(m_sourceCanonicalFolderPathSubString);
77 PR_FREEIF(m_searchCriteriaString);
78 }
79
NS_IMPL_ADDREF_INHERITED(nsImapUrl,nsMsgMailNewsUrl)80 NS_IMPL_ADDREF_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
81
82 NS_IMPL_RELEASE_INHERITED(nsImapUrl, nsMsgMailNewsUrl)
83
84 NS_INTERFACE_MAP_BEGIN(nsImapUrl)
85 NS_INTERFACE_MAP_ENTRY(nsIImapUrl)
86 NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
87 NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
88 NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
89
90 ////////////////////////////////////////////////////////////////////////////////////
91 // Begin nsIImapUrl specific support
92 ////////////////////////////////////////////////////////////////////////////////////
93
94 NS_IMETHODIMP nsImapUrl::GetRequiredImapState(nsImapState* aImapUrlState) {
95 if (aImapUrlState) {
96 // the imap action determines the state we must be in...check the
97 // the imap action.
98
99 if (m_imapAction & 0x10000000)
100 *aImapUrlState = nsImapSelectedState;
101 else
102 *aImapUrlState = nsImapAuthenticatedState;
103 }
104
105 return NS_OK;
106 }
107
GetImapAction(nsImapAction * aImapAction)108 NS_IMETHODIMP nsImapUrl::GetImapAction(nsImapAction* aImapAction) {
109 *aImapAction = m_imapAction;
110 return NS_OK;
111 }
112
SetImapAction(nsImapAction aImapAction)113 NS_IMETHODIMP nsImapUrl::SetImapAction(nsImapAction aImapAction) {
114 m_imapAction = aImapAction;
115 return NS_OK;
116 }
117
GetFolder(nsIMsgFolder ** aMsgFolder)118 NS_IMETHODIMP nsImapUrl::GetFolder(nsIMsgFolder** aMsgFolder) {
119 NS_ENSURE_ARG_POINTER(aMsgFolder);
120 NS_ENSURE_ARG_POINTER(m_imapFolder);
121
122 nsCOMPtr<nsIMsgFolder> folder = do_QueryReferent(m_imapFolder);
123 folder.forget(aMsgFolder);
124 return NS_OK;
125 }
126
SetFolder(nsIMsgFolder * aMsgFolder)127 NS_IMETHODIMP nsImapUrl::SetFolder(nsIMsgFolder* aMsgFolder) {
128 nsresult rv;
129 m_imapFolder = do_GetWeakReference(aMsgFolder, &rv);
130 if (aMsgFolder) {
131 nsCOMPtr<nsIMsgIncomingServer> incomingServer;
132 aMsgFolder->GetServer(getter_AddRefs(incomingServer));
133 if (incomingServer) incomingServer->GetKey(m_serverKey);
134 }
135 return rv;
136 }
137
GetImapMailFolderSink(nsIImapMailFolderSink ** aImapMailFolderSink)138 NS_IMETHODIMP nsImapUrl::GetImapMailFolderSink(
139 nsIImapMailFolderSink** aImapMailFolderSink) {
140 NS_ENSURE_ARG_POINTER(aImapMailFolderSink);
141 if (!m_imapMailFolderSink)
142 return NS_ERROR_NULL_POINTER; // no assert, so don't use NS_ENSURE_POINTER.
143
144 nsCOMPtr<nsIImapMailFolderSink> folderSink =
145 do_QueryReferent(m_imapMailFolderSink);
146 folderSink.forget(aImapMailFolderSink);
147 return NS_OK;
148 }
149
SetImapMailFolderSink(nsIImapMailFolderSink * aImapMailFolderSink)150 NS_IMETHODIMP nsImapUrl::SetImapMailFolderSink(
151 nsIImapMailFolderSink* aImapMailFolderSink) {
152 nsresult rv;
153 m_imapMailFolderSink = do_GetWeakReference(aImapMailFolderSink, &rv);
154 return rv;
155 }
156
GetImapMessageSink(nsIImapMessageSink ** aImapMessageSink)157 NS_IMETHODIMP nsImapUrl::GetImapMessageSink(
158 nsIImapMessageSink** aImapMessageSink) {
159 NS_ENSURE_ARG_POINTER(aImapMessageSink);
160 NS_ENSURE_ARG_POINTER(m_imapMessageSink);
161
162 nsCOMPtr<nsIImapMessageSink> messageSink =
163 do_QueryReferent(m_imapMessageSink);
164 messageSink.forget(aImapMessageSink);
165 return NS_OK;
166 }
167
SetImapMessageSink(nsIImapMessageSink * aImapMessageSink)168 NS_IMETHODIMP nsImapUrl::SetImapMessageSink(
169 nsIImapMessageSink* aImapMessageSink) {
170 nsresult rv;
171 m_imapMessageSink = do_GetWeakReference(aImapMessageSink, &rv);
172 return rv;
173 }
174
GetImapServerSink(nsIImapServerSink ** aImapServerSink)175 NS_IMETHODIMP nsImapUrl::GetImapServerSink(
176 nsIImapServerSink** aImapServerSink) {
177 NS_ENSURE_ARG_POINTER(aImapServerSink);
178 NS_ENSURE_ARG_POINTER(m_imapServerSink);
179
180 nsCOMPtr<nsIImapServerSink> serverSink = do_QueryReferent(m_imapServerSink);
181 serverSink.forget(aImapServerSink);
182 return NS_OK;
183 }
184
SetImapServerSink(nsIImapServerSink * aImapServerSink)185 NS_IMETHODIMP nsImapUrl::SetImapServerSink(nsIImapServerSink* aImapServerSink) {
186 nsresult rv;
187 m_imapServerSink = do_GetWeakReference(aImapServerSink, &rv);
188 return rv;
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////////
192 // End nsIImapUrl specific support
193 ////////////////////////////////////////////////////////////////////////////////////
194
SetSpecInternal(const nsACString & aSpec)195 nsresult nsImapUrl::SetSpecInternal(const nsACString& aSpec) {
196 nsresult rv = nsMsgMailNewsUrl::SetSpecInternal(aSpec);
197 if (NS_SUCCEEDED(rv)) {
198 m_validUrl = true; // assume the best.
199 rv = ParseUrl();
200 }
201 return rv;
202 }
203
SetQuery(const nsACString & aQuery)204 nsresult nsImapUrl::SetQuery(const nsACString& aQuery) {
205 nsresult rv = nsMsgMailNewsUrl::SetQuery(aQuery);
206 if (NS_SUCCEEDED(rv)) rv = ParseUrl();
207 return rv;
208 }
209
ParseUrl()210 nsresult nsImapUrl::ParseUrl() {
211 nsresult rv = NS_OK;
212 // extract the user name
213 GetUserPass(m_userName);
214
215 nsAutoCString imapPartOfUrl;
216 rv = GetPathQueryRef(imapPartOfUrl);
217 nsAutoCString unescapedImapPartOfUrl;
218 MsgUnescapeString(imapPartOfUrl, 0, unescapedImapPartOfUrl);
219 if (NS_SUCCEEDED(rv) && !unescapedImapPartOfUrl.IsEmpty()) {
220 ParseImapPart(unescapedImapPartOfUrl.BeginWriting() +
221 1); // GetPath leaves leading '/' in the path!!!
222 }
223
224 return NS_OK;
225 }
226
CreateSearchCriteriaString(char ** aResult)227 NS_IMETHODIMP nsImapUrl::CreateSearchCriteriaString(char** aResult) {
228 // this method should only be called from the imap thread...
229 // o.t. add lock protection..
230 if (nullptr == aResult || !m_searchCriteriaString)
231 return NS_ERROR_NULL_POINTER;
232 *aResult = strdup(m_searchCriteriaString);
233 return NS_OK;
234 }
235
236 // this method gets called from the UI thread and the imap thread
GetListOfMessageIds(nsACString & aResult)237 NS_IMETHODIMP nsImapUrl::GetListOfMessageIds(nsACString& aResult) {
238 MutexAutoLock mon(mLock);
239 if (!m_listOfMessageIds) return NS_ERROR_NULL_POINTER;
240
241 int32_t bytesToCopy = strlen(m_listOfMessageIds);
242
243 // mime may have glommed a "&part=" for a part download
244 // we return the entire message and let mime extract
245 // the part. Pop and news work this way also.
246 // this algorithm truncates the "&part" string.
247 char* currentChar = m_listOfMessageIds;
248 while (*currentChar && (*currentChar != '?')) currentChar++;
249 if (*currentChar == '?') bytesToCopy = currentChar - m_listOfMessageIds;
250
251 // we should also strip off anything after "/;section="
252 // since that can specify an IMAP MIME part
253 char* wherePart = PL_strstr(m_listOfMessageIds, "/;section=");
254 if (wherePart)
255 bytesToCopy =
256 std::min(bytesToCopy, int32_t(wherePart - m_listOfMessageIds));
257
258 aResult.Assign(m_listOfMessageIds, bytesToCopy);
259 return NS_OK;
260 }
261
GetCommand(nsACString & result)262 NS_IMETHODIMP nsImapUrl::GetCommand(nsACString& result) {
263 result = m_command;
264 return NS_OK;
265 }
266
GetCustomAttributeToFetch(nsACString & result)267 NS_IMETHODIMP nsImapUrl::GetCustomAttributeToFetch(nsACString& result) {
268 result = m_msgFetchAttribute;
269 return NS_OK;
270 }
271
GetCustomAttributeResult(nsACString & result)272 NS_IMETHODIMP nsImapUrl::GetCustomAttributeResult(nsACString& result) {
273 result = m_customAttributeResult;
274 return NS_OK;
275 }
276
SetCustomAttributeResult(const nsACString & result)277 NS_IMETHODIMP nsImapUrl::SetCustomAttributeResult(const nsACString& result) {
278 m_customAttributeResult = result;
279 return NS_OK;
280 }
281
GetCustomCommandResult(nsACString & result)282 NS_IMETHODIMP nsImapUrl::GetCustomCommandResult(nsACString& result) {
283 result = m_customCommandResult;
284 return NS_OK;
285 }
286
SetCustomCommandResult(const nsACString & result)287 NS_IMETHODIMP nsImapUrl::SetCustomCommandResult(const nsACString& result) {
288 m_customCommandResult = result;
289 return NS_OK;
290 }
291
GetCustomAddFlags(nsACString & aResult)292 NS_IMETHODIMP nsImapUrl::GetCustomAddFlags(nsACString& aResult) {
293 aResult = m_customAddFlags;
294 return NS_OK;
295 }
296
GetCustomSubtractFlags(nsACString & aResult)297 NS_IMETHODIMP nsImapUrl::GetCustomSubtractFlags(nsACString& aResult) {
298 aResult = m_customSubtractFlags;
299 return NS_OK;
300 }
301
GetImapPartToFetch(char ** result)302 NS_IMETHODIMP nsImapUrl::GetImapPartToFetch(char** result) {
303 // here's the old code....
304
305 // unfortunately an imap part can have the form: /;section= OR
306 // it can have the form ?section=. We need to look for both.
307 if (m_listOfMessageIds) {
308 char* wherepart = PL_strstr(m_listOfMessageIds, ";section=");
309 if (!wherepart) // look for ?section too....
310 wherepart = PL_strstr(m_listOfMessageIds, "?section=");
311 if (wherepart) {
312 wherepart += 9; // strlen("/;section=")
313 char* wherelibmimepart = PL_strstr(wherepart, "&part=");
314 if (!wherelibmimepart) wherelibmimepart = PL_strstr(wherepart, "?part=");
315 int numCharsToCopy = (wherelibmimepart)
316 ? wherelibmimepart - wherepart
317 : PL_strlen(m_listOfMessageIds) -
318 (wherepart - m_listOfMessageIds);
319 if (numCharsToCopy) {
320 *result = (char*)PR_Malloc(sizeof(char) * (numCharsToCopy + 1));
321 if (*result) {
322 PL_strncpy(*result, wherepart, numCharsToCopy + 1); // appends a \0
323 (*result)[numCharsToCopy] = '\0';
324 }
325 }
326 } // if we got a wherepart
327 } // if we got a m_listOfMessageIds
328 return NS_OK;
329 }
330
GetOnlineSubDirSeparator(char * separator)331 NS_IMETHODIMP nsImapUrl::GetOnlineSubDirSeparator(char* separator) {
332 if (separator) {
333 *separator = m_onlineSubDirSeparator;
334 return NS_OK;
335 }
336 return NS_ERROR_NULL_POINTER;
337 }
338
GetNumBytesToFetch(int32_t * aNumBytesToFetch)339 NS_IMETHODIMP nsImapUrl::GetNumBytesToFetch(int32_t* aNumBytesToFetch) {
340 NS_ENSURE_ARG_POINTER(aNumBytesToFetch);
341 *aNumBytesToFetch = m_numBytesToFetch;
342 return NS_OK;
343 }
344
345 NS_IMETHODIMP
SetOnlineSubDirSeparator(char onlineDirSeparator)346 nsImapUrl::SetOnlineSubDirSeparator(char onlineDirSeparator) {
347 m_onlineSubDirSeparator = onlineDirSeparator;
348 return NS_OK;
349 }
350
351 // this method is only called from the imap thread
MessageIdsAreUids(bool * result)352 NS_IMETHODIMP nsImapUrl::MessageIdsAreUids(bool* result) {
353 *result = m_idsAreUids;
354 return NS_OK;
355 }
356
357 NS_IMETHODIMP
SetExtraStatus(int32_t aExtraStatus)358 nsImapUrl::SetExtraStatus(int32_t aExtraStatus) {
359 m_extraStatus = aExtraStatus;
360 return NS_OK;
361 }
362
GetExtraStatus(int32_t * aResult)363 NS_IMETHODIMP nsImapUrl::GetExtraStatus(int32_t* aResult) {
364 NS_ENSURE_ARG_POINTER(aResult);
365 *aResult = m_extraStatus;
366 return NS_OK;
367 }
368
369 // this method is only called from the imap thread
GetMsgFlags(imapMessageFlagsType * result)370 NS_IMETHODIMP nsImapUrl::GetMsgFlags(
371 imapMessageFlagsType* result) // kAddMsgFlags or kSubtractMsgFlags only
372 {
373 *result = m_flags;
374 return NS_OK;
375 }
376
ParseImapPart(char * imapPartOfUrl)377 void nsImapUrl::ParseImapPart(char* imapPartOfUrl) {
378 m_tokenPlaceHolder = imapPartOfUrl;
379 m_urlidSubString = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
380 &m_tokenPlaceHolder)
381 : (char*)NULL;
382
383 if (!m_urlidSubString) {
384 m_validUrl = false;
385 return;
386 }
387
388 if (!PL_strcasecmp(m_urlidSubString, "fetch")) {
389 m_imapAction = nsImapMsgFetch;
390 ParseUidChoice();
391 PR_FREEIF(m_sourceCanonicalFolderPathSubString);
392 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
393 ParseListOfMessageIds();
394 // if fetched by spam filter, the action will be changed to
395 // nsImapMsgFetchPeek
396 } else {
397 if (!PL_strcasecmp(m_urlidSubString, "header")) {
398 m_imapAction = nsImapMsgHeader;
399 ParseUidChoice();
400 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
401 ParseListOfMessageIds();
402 } else if (!PL_strcasecmp(m_urlidSubString, "customFetch")) {
403 ParseUidChoice();
404 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
405 ParseListOfMessageIds();
406 ParseCustomMsgFetchAttribute();
407 } else if (!PL_strcasecmp(m_urlidSubString, "previewBody")) {
408 ParseUidChoice();
409 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
410 ParseListOfMessageIds();
411 ParseNumBytes();
412 } else if (!PL_strcasecmp(m_urlidSubString, "deletemsg")) {
413 m_imapAction = nsImapDeleteMsg;
414 ParseUidChoice();
415 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
416 ParseListOfMessageIds();
417 } else if (!PL_strcasecmp(m_urlidSubString, "uidexpunge")) {
418 m_imapAction = nsImapUidExpunge;
419 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
420 ParseListOfMessageIds();
421 } else if (!PL_strcasecmp(m_urlidSubString, "deleteallmsgs")) {
422 m_imapAction = nsImapDeleteAllMsgs;
423 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
424 } else if (!PL_strcasecmp(m_urlidSubString, "addmsgflags")) {
425 m_imapAction = nsImapAddMsgFlags;
426 ParseUidChoice();
427 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
428 ParseListOfMessageIds();
429 ParseMsgFlags();
430 } else if (!PL_strcasecmp(m_urlidSubString, "subtractmsgflags")) {
431 m_imapAction = nsImapSubtractMsgFlags;
432 ParseUidChoice();
433 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
434 ParseListOfMessageIds();
435 ParseMsgFlags();
436 } else if (!PL_strcasecmp(m_urlidSubString, "setmsgflags")) {
437 m_imapAction = nsImapSetMsgFlags;
438 ParseUidChoice();
439 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
440 ParseListOfMessageIds();
441 ParseMsgFlags();
442 } else if (!PL_strcasecmp(m_urlidSubString, "onlinecopy")) {
443 m_imapAction = nsImapOnlineCopy;
444 ParseUidChoice();
445 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
446 ParseListOfMessageIds();
447 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
448 } else if (!PL_strcasecmp(m_urlidSubString, "onlinemove")) {
449 m_imapAction = nsImapOnlineMove;
450 ParseUidChoice();
451 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
452 ParseListOfMessageIds();
453 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
454 } else if (!PL_strcasecmp(m_urlidSubString, "onlinetoofflinecopy")) {
455 m_imapAction = nsImapOnlineToOfflineCopy;
456 ParseUidChoice();
457 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
458 ParseListOfMessageIds();
459 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
460 } else if (!PL_strcasecmp(m_urlidSubString, "onlinetoofflinemove")) {
461 m_imapAction = nsImapOnlineToOfflineMove;
462 ParseUidChoice();
463 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
464 ParseListOfMessageIds();
465 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
466 } else if (!PL_strcasecmp(m_urlidSubString, "offlinetoonlinecopy")) {
467 m_imapAction = nsImapOfflineToOnlineMove;
468 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
469 } else if (!PL_strcasecmp(m_urlidSubString, "search")) {
470 m_imapAction = nsImapSearch;
471 ParseUidChoice();
472 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
473 ParseSearchCriteriaString();
474 } else if (!PL_strcasecmp(m_urlidSubString, "test")) {
475 m_imapAction = nsImapTest;
476 } else if (!PL_strcasecmp(m_urlidSubString, "select")) {
477 m_imapAction = nsImapSelectFolder;
478 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
479 if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
480 ParseListOfMessageIds();
481 else
482 m_listOfMessageIds = PL_strdup("");
483 } else if (!PL_strcasecmp(m_urlidSubString, "liteselect")) {
484 m_imapAction = nsImapLiteSelectFolder;
485 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
486 } else if (!PL_strcasecmp(m_urlidSubString, "selectnoop")) {
487 m_imapAction = nsImapSelectNoopFolder;
488 m_listOfMessageIds = PL_strdup("");
489 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
490 } else if (!PL_strcasecmp(m_urlidSubString, "expunge")) {
491 m_imapAction = nsImapExpungeFolder;
492 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
493 m_listOfMessageIds = PL_strdup(""); // no ids to UNDO
494 } else if (!PL_strcasecmp(m_urlidSubString, "create")) {
495 m_imapAction = nsImapCreateFolder;
496 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
497 } else if (!PL_strcasecmp(m_urlidSubString, "ensureExists")) {
498 m_imapAction = nsImapEnsureExistsFolder;
499 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
500 } else if (!PL_strcasecmp(m_urlidSubString, "discoverchildren")) {
501 m_imapAction = nsImapDiscoverChildrenUrl;
502 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
503 } else if (!PL_strcasecmp(m_urlidSubString, "discoverallboxes")) {
504 m_imapAction = nsImapDiscoverAllBoxesUrl;
505 } else if (!PL_strcasecmp(m_urlidSubString,
506 "discoverallandsubscribedboxes")) {
507 m_imapAction = nsImapDiscoverAllAndSubscribedBoxesUrl;
508 } else if (!PL_strcasecmp(m_urlidSubString, "delete")) {
509 m_imapAction = nsImapDeleteFolder;
510 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
511 } else if (!PL_strcasecmp(m_urlidSubString, "deletefolder")) {
512 m_imapAction = nsImapDeleteFolderAndMsgs;
513 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
514 } else if (!PL_strcasecmp(m_urlidSubString, "rename")) {
515 m_imapAction = nsImapRenameFolder;
516 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
517 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
518 } else if (!PL_strcasecmp(m_urlidSubString, "movefolderhierarchy")) {
519 m_imapAction = nsImapMoveFolderHierarchy;
520 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
521 if (m_tokenPlaceHolder && *m_tokenPlaceHolder) // handle promote to root
522 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
523 } else if (!PL_strcasecmp(m_urlidSubString, "list")) {
524 m_imapAction = nsImapLsubFolders;
525 ParseFolderPath(&m_destinationCanonicalFolderPathSubString);
526 } else if (!PL_strcasecmp(m_urlidSubString, "biff")) {
527 m_imapAction = nsImapBiff;
528 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
529 ParseListOfMessageIds();
530 } else if (!PL_strcasecmp(m_urlidSubString, "netscape")) {
531 m_imapAction = nsImapGetMailAccountUrl;
532 } else if (!PL_strcasecmp(m_urlidSubString, "appendmsgfromfile")) {
533 m_imapAction = nsImapAppendMsgFromFile;
534 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
535 } else if (!PL_strcasecmp(m_urlidSubString, "appenddraftfromfile")) {
536 m_imapAction = nsImapAppendDraftFromFile;
537 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
538 ParseUidChoice();
539 if (m_tokenPlaceHolder && *m_tokenPlaceHolder)
540 ParseListOfMessageIds();
541 else
542 m_listOfMessageIds = strdup("");
543 } else if (!PL_strcasecmp(m_urlidSubString, "subscribe")) {
544 m_imapAction = nsImapSubscribe;
545 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
546 } else if (!PL_strcasecmp(m_urlidSubString, "unsubscribe")) {
547 m_imapAction = nsImapUnsubscribe;
548 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
549 } else if (!PL_strcasecmp(m_urlidSubString, "refreshacl")) {
550 m_imapAction = nsImapRefreshACL;
551 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
552 } else if (!PL_strcasecmp(m_urlidSubString, "refreshfolderurls")) {
553 m_imapAction = nsImapRefreshFolderUrls;
554 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
555 } else if (!PL_strcasecmp(m_urlidSubString, "refreshallacls")) {
556 m_imapAction = nsImapRefreshAllACLs;
557 } else if (!PL_strcasecmp(m_urlidSubString, "listfolder")) {
558 m_imapAction = nsImapListFolder;
559 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
560 } else if (!PL_strcasecmp(m_urlidSubString, "upgradetosubscription")) {
561 m_imapAction = nsImapUpgradeToSubscription;
562 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
563 } else if (!PL_strcasecmp(m_urlidSubString, "folderstatus")) {
564 m_imapAction = nsImapFolderStatus;
565 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
566 } else if (!PL_strcasecmp(m_urlidSubString, "verifyLogon")) {
567 m_imapAction = nsImapVerifylogon;
568 } else if (m_imapAction == nsIImapUrl::nsImapUserDefinedMsgCommand) {
569 m_command = m_urlidSubString; // save this
570 ParseUidChoice();
571 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
572 ParseListOfMessageIds();
573 } else if (m_imapAction == nsIImapUrl::nsImapMsgStoreCustomKeywords) {
574 ParseUidChoice();
575 ParseFolderPath(&m_sourceCanonicalFolderPathSubString);
576 ParseListOfMessageIds();
577 bool addKeyword = (m_tokenPlaceHolder && *m_tokenPlaceHolder != '>');
578 // if we're not adding a keyword, m_tokenPlaceHolder will now look like
579 // >keywordToSubtract> and strtok will leave flagsPtr pointing to
580 // keywordToSubtract. So detect this case and only set the
581 // customSubtractFlags.
582 char* flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
583 &m_tokenPlaceHolder)
584 : (char*)nullptr;
585 if (addKeyword) {
586 m_customAddFlags.Assign(flagsPtr);
587 flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
588 &m_tokenPlaceHolder)
589 : (char*)nullptr;
590 }
591 m_customSubtractFlags.Assign(flagsPtr);
592 } else {
593 m_validUrl = false;
594 }
595 }
596 }
597
598 // Returns NULL if nothing was done.
599 // Otherwise, returns a newly allocated name.
AddOnlineDirectoryIfNecessary(const char * onlineMailboxName,char ** directory)600 NS_IMETHODIMP nsImapUrl::AddOnlineDirectoryIfNecessary(
601 const char* onlineMailboxName, char** directory) {
602 nsresult rv;
603 nsString onlineDirString;
604 char* newOnlineName = nullptr;
605
606 nsCOMPtr<nsIImapHostSessionList> hostSessionList =
607 do_GetService(kCImapHostSessionListCID, &rv);
608 if (NS_FAILED(rv)) return rv;
609 rv = hostSessionList->GetOnlineDirForHost(m_serverKey.get(), onlineDirString);
610 nsAutoCString onlineDir;
611 LossyCopyUTF16toASCII(onlineDirString, onlineDir);
612
613 nsImapNamespace* ns = nullptr;
614 rv = hostSessionList->GetNamespaceForMailboxForHost(m_serverKey.get(),
615 onlineMailboxName, ns);
616 if (!ns)
617 hostSessionList->GetDefaultNamespaceOfTypeForHost(m_serverKey.get(),
618 kPersonalNamespace, ns);
619
620 if (onlineDir.IsEmpty() && ns) onlineDir = ns->GetPrefix();
621
622 // If this host has an online server directory configured
623 if (onlineMailboxName && !onlineDir.IsEmpty()) {
624 if (PL_strcasecmp(onlineMailboxName, "INBOX")) {
625 NS_ASSERTION(ns, "couldn't find namespace for host");
626 nsAutoCString onlineDirWithDelimiter(onlineDir);
627 // make sure the onlineDir ends with the hierarchy delimiter
628 if (ns) {
629 char delimiter = ns->GetDelimiter();
630 if (delimiter && delimiter != kOnlineHierarchySeparatorUnknown) {
631 // try to change the canonical online dir name to real dir name first
632 onlineDirWithDelimiter.ReplaceChar('/', delimiter);
633 // make sure the last character is the delimiter
634 if (onlineDirWithDelimiter.Last() != delimiter)
635 onlineDirWithDelimiter += delimiter;
636 if (!*onlineMailboxName)
637 onlineDirWithDelimiter.SetLength(onlineDirWithDelimiter.Length() -
638 1);
639 }
640 }
641 if (ns && (PL_strlen(ns->GetPrefix()) != 0) &&
642 !onlineDirWithDelimiter.Equals(ns->GetPrefix())) {
643 // check that onlineMailboxName doesn't start with the namespace. If
644 // that's the case, we don't want to prepend the online dir.
645 if (PL_strncmp(onlineMailboxName, ns->GetPrefix(),
646 PL_strlen(ns->GetPrefix()))) {
647 // The namespace for this mailbox is the root ("").
648 // Prepend the online server directory
649 int finalLen =
650 onlineDirWithDelimiter.Length() + strlen(onlineMailboxName) + 1;
651 newOnlineName = (char*)PR_Malloc(finalLen);
652 if (newOnlineName) {
653 PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
654 PL_strcat(newOnlineName, onlineMailboxName);
655 }
656 }
657 }
658 // just prepend the online server directory if it doesn't start with it
659 // already
660 else if (strncmp(onlineMailboxName, onlineDirWithDelimiter.get(),
661 onlineDirWithDelimiter.Length())) {
662 newOnlineName = (char*)PR_Malloc(strlen(onlineMailboxName) +
663 onlineDirWithDelimiter.Length() + 1);
664 if (newOnlineName) {
665 PL_strcpy(newOnlineName, onlineDirWithDelimiter.get());
666 PL_strcat(newOnlineName, onlineMailboxName);
667 }
668 }
669 }
670 }
671 if (directory)
672 *directory = newOnlineName;
673 else if (newOnlineName)
674 free(newOnlineName);
675 return rv;
676 }
677
678 // Converts from canonical format (hierarchy is indicated by '/' and all real
679 // slashes ('/') are escaped) to the real online name on the server.
AllocateServerPath(const char * canonicalPath,char onlineDelimiter,char ** aAllocatedPath)680 NS_IMETHODIMP nsImapUrl::AllocateServerPath(const char* canonicalPath,
681 char onlineDelimiter,
682 char** aAllocatedPath) {
683 nsresult retVal = NS_OK;
684 char* rv = NULL;
685 char delimiterToUse = onlineDelimiter;
686 if (onlineDelimiter == kOnlineHierarchySeparatorUnknown)
687 GetOnlineSubDirSeparator(&delimiterToUse);
688 NS_ASSERTION(delimiterToUse != kOnlineHierarchySeparatorUnknown,
689 "hierarchy separator unknown");
690 if (canonicalPath)
691 rv = ReplaceCharsInCopiedString(canonicalPath, '/', delimiterToUse);
692 else
693 rv = strdup("");
694
695 if (delimiterToUse != '/') UnescapeSlashes(rv);
696 char* onlineNameAdded = nullptr;
697 AddOnlineDirectoryIfNecessary(rv, &onlineNameAdded);
698 if (onlineNameAdded) {
699 free(rv);
700 rv = onlineNameAdded;
701 }
702
703 if (aAllocatedPath)
704 *aAllocatedPath = rv;
705 else
706 free(rv);
707
708 return retVal;
709 }
710
711 // escape '/' as ^, ^ -> ^^ - use UnescapeSlashes to revert
EscapeSlashes(const char * sourcePath,char ** resultPath)712 /* static */ nsresult nsImapUrl::EscapeSlashes(const char* sourcePath,
713 char** resultPath) {
714 NS_ENSURE_ARG(sourcePath);
715 NS_ENSURE_ARG(resultPath);
716 int32_t extra = 0;
717 int32_t len = strlen(sourcePath);
718 const char* src = sourcePath;
719 int32_t i;
720 for (i = 0; i < len; i++) {
721 if (*src == '^') extra += 1; /* ^ -> ^^ */
722 src++;
723 }
724 char* result = (char*)moz_xmalloc(len + extra + 1);
725 if (!result) return NS_ERROR_OUT_OF_MEMORY;
726
727 unsigned char* dst = (unsigned char*)result;
728 src = sourcePath;
729 for (i = 0; i < len; i++) {
730 unsigned char c = *src++;
731 if (c == '/')
732 *dst++ = '^';
733 else if (c == '^') {
734 *dst++ = '^';
735 *dst++ = '^';
736 } else
737 *dst++ = c;
738 }
739 *dst = '\0'; /* tack on eos */
740 *resultPath = result;
741 return NS_OK;
742 }
743
unescapeSlashes(char * path,size_t * newLength)744 static void unescapeSlashes(char* path, size_t* newLength) {
745 char* src = path;
746 char* start = src;
747 char* dst = path;
748
749 while (*src) {
750 if (*src == '^') {
751 if (*(src + 1) == '^') {
752 *dst++ = '^';
753 src++; // skip over second '^'
754 } else
755 *dst++ = '/';
756 src++;
757 } else
758 *dst++ = *src++;
759 }
760
761 *newLength = dst - start;
762 }
763
UnescapeSlashes(char * path)764 /* static */ nsresult nsImapUrl::UnescapeSlashes(char* path) {
765 size_t newLength;
766 unescapeSlashes(path, &newLength);
767 path[newLength] = 0;
768 return NS_OK;
769 }
770
UnescapeSlashes(nsACString & path)771 /* static */ nsresult nsImapUrl::UnescapeSlashes(nsACString& path) {
772 size_t newLength;
773 unescapeSlashes(path.BeginWriting(), &newLength);
774 path.SetLength(newLength);
775 return NS_OK;
776 }
777
ConvertToCanonicalFormat(const char * folderName,char onlineDelimiter,char ** resultingCanonicalPath)778 /* static */ nsresult nsImapUrl::ConvertToCanonicalFormat(
779 const char* folderName, char onlineDelimiter,
780 char** resultingCanonicalPath) {
781 // Now, start the conversion to canonical form.
782
783 char* canonicalPath;
784 if (onlineDelimiter != '/') {
785 nsCString escapedPath;
786
787 EscapeSlashes(folderName, getter_Copies(escapedPath));
788 canonicalPath =
789 ReplaceCharsInCopiedString(escapedPath.get(), onlineDelimiter, '/');
790 } else {
791 canonicalPath = strdup(folderName);
792 }
793 if (canonicalPath) *resultingCanonicalPath = canonicalPath;
794
795 return (canonicalPath) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
796 }
797
798 // Converts the real online name on the server to canonical format:
799 // result is hierarchy is indicated by '/' and all real slashes ('/') are
800 // escaped. This method is only called from the IMAP thread.
AllocateCanonicalPath(const char * serverPath,char onlineDelimiter,char ** allocatedPath)801 NS_IMETHODIMP nsImapUrl::AllocateCanonicalPath(const char* serverPath,
802 char onlineDelimiter,
803 char** allocatedPath) {
804 nsresult rv = NS_ERROR_NULL_POINTER;
805 char delimiterToUse = onlineDelimiter;
806 char* serverKey = nullptr;
807 nsString aString;
808 char* currentPath = (char*)serverPath;
809 nsAutoCString onlineDir;
810 nsCOMPtr<nsIMsgIncomingServer> server;
811
812 nsCOMPtr<nsIImapHostSessionList> hostSessionList =
813 do_GetService(kCImapHostSessionListCID, &rv);
814
815 *allocatedPath = nullptr;
816
817 if (onlineDelimiter == kOnlineHierarchySeparatorUnknown ||
818 onlineDelimiter == 0)
819 GetOnlineSubDirSeparator(&delimiterToUse);
820
821 NS_ASSERTION(serverPath, "Oops... null serverPath");
822
823 if (!serverPath || NS_FAILED(rv)) goto done;
824
825 hostSessionList->GetOnlineDirForHost(m_serverKey.get(), aString);
826 // First we have to check to see if we should strip off an online server
827 // subdirectory
828 // If this host has an online server directory configured
829 LossyCopyUTF16toASCII(aString, onlineDir);
830
831 if (currentPath && !onlineDir.IsEmpty()) {
832 // By definition, the online dir must be at the root.
833 if (delimiterToUse && delimiterToUse != kOnlineHierarchySeparatorUnknown) {
834 // try to change the canonical online dir name to real dir name first
835 onlineDir.ReplaceChar('/', delimiterToUse);
836 // Add the delimiter
837 if (onlineDir.Last() != delimiterToUse) onlineDir += delimiterToUse;
838 }
839 int len = onlineDir.Length();
840 if (!PL_strncmp(onlineDir.get(), currentPath, len)) {
841 // This online path begins with the server sub directory
842 currentPath += len;
843
844 // This might occur, but it's most likely something not good.
845 // Basically, it means we're doing something on the online sub directory
846 // itself.
847 NS_ASSERTION(*currentPath, "Oops ... null currentPath");
848 // Also make sure that the first character in the mailbox name is not '/'.
849 NS_ASSERTION(*currentPath != '/',
850 "Oops ... currentPath starts with a slash");
851 }
852 }
853
854 if (!currentPath) goto done;
855
856 rv = ConvertToCanonicalFormat(currentPath, delimiterToUse, allocatedPath);
857
858 done:
859 PR_Free(serverKey);
860 return rv;
861 }
862
863 // this method is only called from the imap thread
CreateServerSourceFolderPathString(char ** result)864 NS_IMETHODIMP nsImapUrl::CreateServerSourceFolderPathString(char** result) {
865 NS_ENSURE_ARG_POINTER(result);
866 AllocateServerPath(m_sourceCanonicalFolderPathSubString,
867 kOnlineHierarchySeparatorUnknown, result);
868 return NS_OK;
869 }
870
871 // this method is called from the imap thread AND the UI thread...
CreateCanonicalSourceFolderPathString(char ** result)872 NS_IMETHODIMP nsImapUrl::CreateCanonicalSourceFolderPathString(char** result) {
873 NS_ENSURE_ARG_POINTER(result);
874 MutexAutoLock mon(mLock);
875 *result = strdup(m_sourceCanonicalFolderPathSubString
876 ? m_sourceCanonicalFolderPathSubString
877 : "");
878 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
879 }
880
881 // this method is called from the imap thread AND the UI thread...
CreateServerDestinationFolderPathString(char ** result)882 NS_IMETHODIMP nsImapUrl::CreateServerDestinationFolderPathString(
883 char** result) {
884 NS_ENSURE_ARG_POINTER(result);
885 MutexAutoLock mon(mLock);
886 nsresult rv = AllocateServerPath(m_destinationCanonicalFolderPathSubString,
887 kOnlineHierarchySeparatorUnknown, result);
888 return (*result) ? rv : NS_ERROR_OUT_OF_MEMORY;
889 }
890
891 // for enabling or disabling mime parts on demand. Setting this to true says we
892 // can use mime parts on demand, if we chose.
SetAllowContentChange(bool allowContentChange)893 NS_IMETHODIMP nsImapUrl::SetAllowContentChange(bool allowContentChange) {
894 m_allowContentChange = allowContentChange;
895 return NS_OK;
896 }
897
SetContentModified(nsImapContentModifiedType contentModified)898 NS_IMETHODIMP nsImapUrl::SetContentModified(
899 nsImapContentModifiedType contentModified) {
900 m_contentModified = contentModified;
901 nsCOMPtr<nsICacheEntry> cacheEntry;
902 nsresult res = GetMemCacheEntry(getter_AddRefs(cacheEntry));
903 if (NS_SUCCEEDED(res) && cacheEntry) {
904 const char* contentModifiedAnnotation = "";
905 switch (m_contentModified) {
906 case IMAP_CONTENT_NOT_MODIFIED:
907 contentModifiedAnnotation = "Not Modified";
908 break;
909 case IMAP_CONTENT_MODIFIED_VIEW_INLINE:
910 contentModifiedAnnotation = "Modified View Inline";
911 break;
912 case IMAP_CONTENT_MODIFIED_VIEW_AS_LINKS:
913 contentModifiedAnnotation = "Modified View As Link";
914 break;
915 case IMAP_CONTENT_FORCE_CONTENT_NOT_MODIFIED:
916 contentModifiedAnnotation = "Force Content Not Modified";
917 break;
918 }
919 MOZ_LOG(IMAPCache, LogLevel::Debug,
920 ("SetContentModified(): Set annotation to |%s|",
921 contentModifiedAnnotation));
922 cacheEntry->SetMetaDataElement("ContentModified",
923 contentModifiedAnnotation);
924 } else {
925 MOZ_LOG(IMAPCache, LogLevel::Debug,
926 ("SetContentModified(): Set annotation FAILED -- no cacheEntry"));
927 }
928 return NS_OK;
929 }
930
GetContentModified(nsImapContentModifiedType * contentModified)931 NS_IMETHODIMP nsImapUrl::GetContentModified(
932 nsImapContentModifiedType* contentModified) {
933 if (!contentModified) return NS_ERROR_NULL_POINTER;
934
935 *contentModified = m_contentModified;
936 return NS_OK;
937 }
938
SetFetchPartsOnDemand(bool fetchPartsOnDemand)939 NS_IMETHODIMP nsImapUrl::SetFetchPartsOnDemand(bool fetchPartsOnDemand) {
940 m_fetchPartsOnDemand = fetchPartsOnDemand;
941 return NS_OK;
942 }
943
GetFetchPartsOnDemand(bool * fetchPartsOnDemand)944 NS_IMETHODIMP nsImapUrl::GetFetchPartsOnDemand(bool* fetchPartsOnDemand) {
945 if (!fetchPartsOnDemand) return NS_ERROR_NULL_POINTER;
946
947 *fetchPartsOnDemand = m_fetchPartsOnDemand;
948 return NS_OK;
949 }
950
SetMimePartSelectorDetected(bool mimePartSelectorDetected)951 NS_IMETHODIMP nsImapUrl::SetMimePartSelectorDetected(
952 bool mimePartSelectorDetected) {
953 m_mimePartSelectorDetected = mimePartSelectorDetected;
954 return NS_OK;
955 }
956
GetMimePartSelectorDetected(bool * mimePartSelectorDetected)957 NS_IMETHODIMP nsImapUrl::GetMimePartSelectorDetected(
958 bool* mimePartSelectorDetected) {
959 if (!mimePartSelectorDetected) return NS_ERROR_NULL_POINTER;
960
961 *mimePartSelectorDetected = m_mimePartSelectorDetected;
962 return NS_OK;
963 }
964
965 // this method is only called from the UI thread.
SetCopyState(nsISupports * copyState)966 NS_IMETHODIMP nsImapUrl::SetCopyState(nsISupports* copyState) {
967 MutexAutoLock mon(mLock);
968 m_copyState = copyState;
969 return NS_OK;
970 }
971
972 // this method is only called from the imap thread..but we still
973 // need a monitor 'cause the setter is called from the UI thread.
GetCopyState(nsISupports ** copyState)974 NS_IMETHODIMP nsImapUrl::GetCopyState(nsISupports** copyState) {
975 NS_ENSURE_ARG_POINTER(copyState);
976 MutexAutoLock mon(mLock);
977 NS_IF_ADDREF(*copyState = m_copyState);
978
979 return NS_OK;
980 }
981
982 NS_IMETHODIMP
SetMsgFile(nsIFile * aFile)983 nsImapUrl::SetMsgFile(nsIFile* aFile) {
984 nsresult rv = NS_OK;
985 MutexAutoLock mon(mLock);
986 m_file = aFile;
987 return rv;
988 }
989
990 NS_IMETHODIMP
GetMsgFile(nsIFile ** aFile)991 nsImapUrl::GetMsgFile(nsIFile** aFile) {
992 NS_ENSURE_ARG_POINTER(aFile);
993
994 MutexAutoLock mon(mLock);
995 NS_IF_ADDREF(*aFile = m_file);
996 return NS_OK;
997 }
998
999 // this method is called from the UI thread..
GetMockChannel(nsIImapMockChannel ** aChannel)1000 NS_IMETHODIMP nsImapUrl::GetMockChannel(nsIImapMockChannel** aChannel) {
1001 NS_ENSURE_ARG_POINTER(aChannel);
1002 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
1003 "should only access mock channel on ui thread");
1004 *aChannel = nullptr;
1005 nsCOMPtr<nsIImapMockChannel> channel(do_QueryReferent(m_channelWeakPtr));
1006 channel.forget(aChannel);
1007 return *aChannel ? NS_OK : NS_ERROR_FAILURE;
1008 }
1009
SetMockChannel(nsIImapMockChannel * aChannel)1010 NS_IMETHODIMP nsImapUrl::SetMockChannel(nsIImapMockChannel* aChannel) {
1011 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
1012 "should only access mock channel on ui thread");
1013 m_channelWeakPtr = do_GetWeakReference(aChannel);
1014 return NS_OK;
1015 }
1016
GetAllowContentChange(bool * result)1017 NS_IMETHODIMP nsImapUrl::GetAllowContentChange(bool* result) {
1018 NS_ENSURE_ARG_POINTER(result);
1019 *result = m_allowContentChange;
1020 return NS_OK;
1021 }
1022
Clone(nsIURI ** _retval)1023 nsresult nsImapUrl::Clone(nsIURI** _retval) {
1024 nsresult rv = nsMsgMailNewsUrl::Clone(_retval);
1025 NS_ENSURE_SUCCESS(rv, rv);
1026 // also clone the mURI member, because GetUri below won't work if
1027 // mURI isn't set due to escaping issues.
1028 nsCOMPtr<nsIMsgMessageUrl> clonedUrl = do_QueryInterface(*_retval);
1029 if (clonedUrl) clonedUrl->SetUri(mURI);
1030 return rv;
1031 }
1032
GetNormalizedSpec(nsACString & aPrincipalSpec)1033 NS_IMETHODIMP nsImapUrl::GetNormalizedSpec(nsACString& aPrincipalSpec) {
1034 // URLs look like this:
1035 // imap://user@domain@server:port/fetch>UID>folder>nn
1036 // We simply strip any query part beginning with ? & or /;
1037 // Normalized spec: imap://user@domain@server:port/fetch>UID>folder>nn
1038 nsCOMPtr<nsIMsgMailNewsUrl> mailnewsURL;
1039 QueryInterface(NS_GET_IID(nsIMsgMailNewsUrl), getter_AddRefs(mailnewsURL));
1040
1041 nsAutoCString spec;
1042 mailnewsURL->GetSpecIgnoringRef(spec);
1043
1044 // Strip any query part beginning with ? or /;
1045 MsgRemoveQueryPart(spec);
1046
1047 aPrincipalSpec.Assign(spec);
1048 return NS_OK;
1049 }
1050
SetUri(const nsACString & aURI)1051 NS_IMETHODIMP nsImapUrl::SetUri(const nsACString& aURI) {
1052 mURI = aURI;
1053 return NS_OK;
1054 }
1055
GetUri(nsACString & aURI)1056 NS_IMETHODIMP nsImapUrl::GetUri(nsACString& aURI) {
1057 nsresult rv = NS_OK;
1058 if (!mURI.IsEmpty())
1059 aURI = mURI;
1060 else {
1061 uint32_t key =
1062 m_listOfMessageIds ? strtoul(m_listOfMessageIds, nullptr, 10) : 0;
1063 nsCString canonicalPath;
1064 AllocateCanonicalPath(m_sourceCanonicalFolderPathSubString,
1065 m_onlineSubDirSeparator,
1066 (getter_Copies(canonicalPath)));
1067 nsCString fullFolderPath("/");
1068 fullFolderPath.Append(m_userName);
1069 nsAutoCString hostName;
1070 rv = GetHost(hostName);
1071 fullFolderPath.Append('@');
1072 fullFolderPath.Append(hostName);
1073 fullFolderPath.Append('/');
1074 fullFolderPath.Append(canonicalPath);
1075
1076 nsCString baseMessageURI;
1077 nsCreateImapBaseMessageURI(fullFolderPath, baseMessageURI);
1078 rv = nsBuildImapMessageURI(baseMessageURI.get(), key, aURI);
1079 }
1080 return rv;
1081 }
1082
NS_IMPL_GETSET(nsImapUrl,AddDummyEnvelope,bool,m_addDummyEnvelope)1083 NS_IMPL_GETSET(nsImapUrl, AddDummyEnvelope, bool, m_addDummyEnvelope)
1084 NS_IMPL_GETSET(nsImapUrl, CanonicalLineEnding, bool, m_canonicalLineEnding)
1085 NS_IMETHODIMP nsImapUrl::GetMsgLoadingFromCache(bool* result) {
1086 NS_ENSURE_ARG_POINTER(result);
1087 *result = m_msgLoadingFromCache;
1088 return NS_OK;
1089 }
NS_IMPL_GETSET(nsImapUrl,LocalFetchOnly,bool,m_localFetchOnly)1090 NS_IMPL_GETSET(nsImapUrl, LocalFetchOnly, bool, m_localFetchOnly)
1091 NS_IMPL_GETSET(nsImapUrl, ExternalLinkUrl, bool, m_externalLinkUrl)
1092 NS_IMPL_GETSET(nsImapUrl, RerunningUrl, bool, m_rerunningUrl)
1093 NS_IMPL_GETSET(nsImapUrl, ValidUrl, bool, m_validUrl)
1094 NS_IMPL_GETSET(nsImapUrl, MoreHeadersToDownload, bool, m_moreHeadersToDownload)
1095
1096 NS_IMETHODIMP nsImapUrl::SetMsgLoadingFromCache(bool loadingFromCache) {
1097 nsresult rv = NS_OK;
1098 m_msgLoadingFromCache = loadingFromCache;
1099 return rv;
1100 }
1101
SetMessageFile(nsIFile * aFile)1102 NS_IMETHODIMP nsImapUrl::SetMessageFile(nsIFile* aFile) {
1103 m_messageFile = aFile;
1104 return NS_OK;
1105 }
1106
GetMessageFile(nsIFile ** aFile)1107 NS_IMETHODIMP nsImapUrl::GetMessageFile(nsIFile** aFile) {
1108 if (aFile) NS_IF_ADDREF(*aFile = m_messageFile);
1109 return NS_OK;
1110 }
1111
IsUrlType(uint32_t type,bool * isType)1112 NS_IMETHODIMP nsImapUrl::IsUrlType(uint32_t type, bool* isType) {
1113 NS_ENSURE_ARG(isType);
1114
1115 switch (type) {
1116 case nsIMsgMailNewsUrl::eCopy:
1117 *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineCopy) ||
1118 (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineCopy) ||
1119 (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineCopy));
1120 break;
1121 case nsIMsgMailNewsUrl::eMove:
1122 *isType = ((m_imapAction == nsIImapUrl::nsImapOnlineMove) ||
1123 (m_imapAction == nsIImapUrl::nsImapOnlineToOfflineMove) ||
1124 (m_imapAction == nsIImapUrl::nsImapOfflineToOnlineMove));
1125 break;
1126 case nsIMsgMailNewsUrl::eDisplay:
1127 *isType = (m_imapAction == nsIImapUrl::nsImapMsgFetch ||
1128 m_imapAction == nsIImapUrl::nsImapMsgFetchPeek);
1129 break;
1130 default:
1131 *isType = false;
1132 };
1133
1134 return NS_OK;
1135 }
1136
1137 NS_IMETHODIMP
GetOriginalSpec(nsACString & aSpec)1138 nsImapUrl::GetOriginalSpec(nsACString& aSpec) {
1139 return NS_ERROR_NOT_IMPLEMENTED;
1140 }
1141
1142 NS_IMETHODIMP
SetOriginalSpec(const nsACString & aSpec)1143 nsImapUrl::SetOriginalSpec(const nsACString& aSpec) {
1144 return NS_ERROR_NOT_IMPLEMENTED;
1145 }
1146
ReplaceCharsInCopiedString(const char * stringToCopy,char oldChar,char newChar)1147 char* nsImapUrl::ReplaceCharsInCopiedString(const char* stringToCopy,
1148 char oldChar, char newChar) {
1149 char oldCharString[2];
1150 *oldCharString = oldChar;
1151 *(oldCharString + 1) = 0;
1152
1153 char* translatedString = PL_strdup(stringToCopy);
1154 char* currentSeparator = PL_strstr(translatedString, oldCharString);
1155
1156 while (currentSeparator) {
1157 *currentSeparator = newChar;
1158 currentSeparator = PL_strstr(currentSeparator + 1, oldCharString);
1159 }
1160
1161 return translatedString;
1162 }
1163
1164 ////////////////////////////////////////////////////////////////////////////////////
1165 // End of functions which should be made obsolete after modifying nsIURI
1166 ////////////////////////////////////////////////////////////////////////////////////
1167
ParseFolderPath(char ** resultingCanonicalPath)1168 void nsImapUrl::ParseFolderPath(char** resultingCanonicalPath) {
1169 char* resultPath = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
1170 &m_tokenPlaceHolder)
1171 : (char*)NULL;
1172
1173 if (!resultPath) {
1174 m_validUrl = false;
1175 return;
1176 }
1177 NS_ASSERTION(*resultingCanonicalPath == nullptr, "whoops, mem leak");
1178
1179 char dirSeparator = *resultPath;
1180
1181 nsCString unescapedResultingCanonicalPath;
1182 MsgUnescapeString(nsDependentCString(resultPath + 1), 0,
1183 unescapedResultingCanonicalPath);
1184 *resultingCanonicalPath = ToNewCString(unescapedResultingCanonicalPath);
1185 // The delimiter will be set for a given URL, but will not be statically
1186 // available from an arbitrary URL. It is the creator's responsibility to
1187 // fill in the correct delimiter from the folder's namespace when creating the
1188 // URL.
1189 if (dirSeparator != kOnlineHierarchySeparatorUnknown)
1190 SetOnlineSubDirSeparator(dirSeparator);
1191
1192 // if dirSeparator == kOnlineHierarchySeparatorUnknown, then this must be a
1193 // create of a top level imap box. If there is an online subdir, we will
1194 // automatically use its separator. If there is not an online subdir, we
1195 // don't need a separator.
1196 }
1197
ParseSearchCriteriaString()1198 void nsImapUrl::ParseSearchCriteriaString() {
1199 if (m_tokenPlaceHolder) {
1200 int quotedFlag = false;
1201
1202 // skip initial separator
1203 while (*m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR)
1204 m_tokenPlaceHolder++;
1205
1206 char* saveTokenPlaceHolder = m_tokenPlaceHolder;
1207
1208 // m_searchCriteriaString = m_tokenPlaceHolder;
1209
1210 // looking for another separator outside quoted string
1211 while (*m_tokenPlaceHolder) {
1212 if (*m_tokenPlaceHolder == '\\' && *(m_tokenPlaceHolder + 1) == '"')
1213 m_tokenPlaceHolder++;
1214 else if (*m_tokenPlaceHolder == '"')
1215 quotedFlag = !quotedFlag;
1216 else if (!quotedFlag &&
1217 *m_tokenPlaceHolder == *IMAP_URL_TOKEN_SEPARATOR) {
1218 *m_tokenPlaceHolder = '\0';
1219 m_tokenPlaceHolder++;
1220 break;
1221 }
1222 m_tokenPlaceHolder++;
1223 }
1224 m_searchCriteriaString = PL_strdup(saveTokenPlaceHolder);
1225 if (*m_tokenPlaceHolder == '\0') m_tokenPlaceHolder = NULL;
1226
1227 if (*m_searchCriteriaString == '\0') m_searchCriteriaString = (char*)NULL;
1228 } else
1229 m_searchCriteriaString = (char*)NULL;
1230 if (!m_searchCriteriaString) m_validUrl = false;
1231 }
1232
ParseUidChoice()1233 void nsImapUrl::ParseUidChoice() {
1234 char* uidChoiceString =
1235 m_tokenPlaceHolder
1236 ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder)
1237 : (char*)NULL;
1238 if (!uidChoiceString)
1239 m_validUrl = false;
1240 else
1241 m_idsAreUids = strcmp(uidChoiceString, "UID") == 0;
1242 }
1243
ParseMsgFlags()1244 void nsImapUrl::ParseMsgFlags() {
1245 char* flagsPtr = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
1246 &m_tokenPlaceHolder)
1247 : (char*)NULL;
1248 if (flagsPtr) {
1249 // the url is encodes the flags byte as ascii
1250 int intFlags = atoi(flagsPtr);
1251 m_flags = (imapMessageFlagsType)intFlags; // cast here
1252 } else
1253 m_flags = 0;
1254 }
1255
ParseListOfMessageIds()1256 void nsImapUrl::ParseListOfMessageIds() {
1257 m_listOfMessageIds = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
1258 &m_tokenPlaceHolder)
1259 : (char*)NULL;
1260 if (!m_listOfMessageIds)
1261 m_validUrl = false;
1262 else {
1263 m_listOfMessageIds = strdup(m_listOfMessageIds);
1264 m_mimePartSelectorDetected = PL_strstr(m_listOfMessageIds, "&part=") != 0 ||
1265 PL_strstr(m_listOfMessageIds, "?part=") != 0;
1266
1267 // if we're asking for just the body, don't download the whole message. see
1268 // nsMsgQuote::QuoteMessage() for the "header=" settings when replying to
1269 // msgs.
1270 if (!m_fetchPartsOnDemand)
1271 m_fetchPartsOnDemand =
1272 (PL_strstr(m_listOfMessageIds, "?header=quotebody") != 0 ||
1273 PL_strstr(m_listOfMessageIds, "?header=only") != 0);
1274 // if it's a spam filter trying to fetch the msg, don't let it get marked
1275 // read.
1276 if (PL_strstr(m_listOfMessageIds, "?header=filter") != 0)
1277 m_imapAction = nsImapMsgFetchPeek;
1278 }
1279 }
1280
ParseCustomMsgFetchAttribute()1281 void nsImapUrl::ParseCustomMsgFetchAttribute() {
1282 m_msgFetchAttribute = m_tokenPlaceHolder ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR,
1283 &m_tokenPlaceHolder)
1284 : (char*)nullptr;
1285 }
1286
ParseNumBytes()1287 void nsImapUrl::ParseNumBytes() {
1288 const char* numBytes =
1289 (m_tokenPlaceHolder)
1290 ? NS_strtok(IMAP_URL_TOKEN_SEPARATOR, &m_tokenPlaceHolder)
1291 : 0;
1292 m_numBytesToFetch = numBytes ? atoi(numBytes) : 0;
1293 }
1294
1295 // nsIMsgI18NUrl support
1296
GetMsgFolder(nsIMsgFolder ** msgFolder)1297 nsresult nsImapUrl::GetMsgFolder(nsIMsgFolder** msgFolder) {
1298 // if we have a RDF URI, then try to get the folder for that URI and then ask
1299 // the folder for it's charset....
1300
1301 nsCString uri;
1302 GetUri(uri);
1303 NS_ENSURE_TRUE(!uri.IsEmpty(), NS_ERROR_FAILURE);
1304
1305 nsCOMPtr<nsIMsgDBHdr> msg;
1306 GetMsgDBHdrFromURI(uri, getter_AddRefs(msg));
1307 NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE);
1308 nsresult rv = msg->GetFolder(msgFolder);
1309 NS_ENSURE_SUCCESS(rv, rv);
1310 NS_ENSURE_TRUE(msgFolder, NS_ERROR_FAILURE);
1311
1312 return NS_OK;
1313 }
1314
GetOverRideCharset(bool * aOverride)1315 NS_IMETHODIMP nsImapUrl::GetOverRideCharset(bool* aOverride) {
1316 *aOverride = mOverrideCharset;
1317 return NS_OK;
1318 }
1319
SetOverRideCharset(bool aOverride)1320 NS_IMETHODIMP nsImapUrl::SetOverRideCharset(bool aOverride) {
1321 mOverrideCharset = aOverride;
1322 return NS_OK;
1323 }
1324
GetStoreResultsOffline(bool * aStoreResultsOffline)1325 NS_IMETHODIMP nsImapUrl::GetStoreResultsOffline(bool* aStoreResultsOffline) {
1326 NS_ENSURE_ARG_POINTER(aStoreResultsOffline);
1327 *aStoreResultsOffline = m_storeResultsOffline;
1328 return NS_OK;
1329 }
1330
SetStoreResultsOffline(bool aStoreResultsOffline)1331 NS_IMETHODIMP nsImapUrl::SetStoreResultsOffline(bool aStoreResultsOffline) {
1332 m_storeResultsOffline = aStoreResultsOffline;
1333 return NS_OK;
1334 }
1335
GetStoreOfflineOnFallback(bool * aStoreOfflineOnFallback)1336 NS_IMETHODIMP nsImapUrl::GetStoreOfflineOnFallback(
1337 bool* aStoreOfflineOnFallback) {
1338 NS_ENSURE_ARG_POINTER(aStoreOfflineOnFallback);
1339 *aStoreOfflineOnFallback = m_storeOfflineOnFallback;
1340 return NS_OK;
1341 }
1342
SetStoreOfflineOnFallback(bool aStoreOfflineOnFallback)1343 NS_IMETHODIMP nsImapUrl::SetStoreOfflineOnFallback(
1344 bool aStoreOfflineOnFallback) {
1345 m_storeOfflineOnFallback = aStoreOfflineOnFallback;
1346 return NS_OK;
1347 }
1348
GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)1349 NS_IMETHODIMP nsImapUrl::GetMessageHeader(nsIMsgDBHdr** aMsgHdr) {
1350 nsCString uri;
1351 nsresult rv = GetUri(uri);
1352 NS_ENSURE_SUCCESS(rv, rv);
1353 return GetMsgDBHdrFromURI(uri, aMsgHdr);
1354 }
1355
SetMessageHeader(nsIMsgDBHdr * aMsgHdr)1356 NS_IMETHODIMP nsImapUrl::SetMessageHeader(nsIMsgDBHdr* aMsgHdr) {
1357 return NS_ERROR_NOT_IMPLEMENTED;
1358 }
1359