From 0367cfdae3ab31b4b2dc6d57b02190268ac9f437 Mon Sep 17 00:00:00 2001 From: "bienvenu%nventure.com" Date: Thu, 10 Jun 2004 15:58:10 +0000 Subject: [PATCH] fix for 185184, patch by hyc@symas.com, r=bienvenu, sr=mscott add option to only download pop3 headers initially, and download body on demand --- .../prefs/resources/content/am-server.xul | 6 ++ .../resources/locale/en-US/am-server-top.dtd | 2 + .../resources/content/mailWindowOverlay.xul | 12 ++- .../base/search/public/nsMsgFilterCore.idl | 3 +- .../search/resources/content/FilterEditor.js | 11 +++ .../search/resources/content/FilterEditor.xul | 6 ++ .../resources/locale/en-US/FilterEditor.dtd | 1 + mailnews/base/search/src/nsMsgFilter.cpp | 1 + mailnews/base/src/nsMsgDBView.cpp | 13 ++- .../local/public/nsIMsgLocalMailFolder.idl | 12 ++- .../local/public/nsIPop3IncomingServer.idl | 9 +- mailnews/local/public/nsIPop3Protocol.idl | 10 +- mailnews/local/public/nsIPop3Sink.idl | 2 +- mailnews/local/src/nsLocalMailFolder.cpp | 56 ++++++++--- mailnews/local/src/nsLocalMailFolder.h | 4 + mailnews/local/src/nsLocalUndoTxn.cpp | 4 +- mailnews/local/src/nsParseMailbox.cpp | 24 ++++- mailnews/local/src/nsPop3IncomingServer.cpp | 42 ++++++-- mailnews/local/src/nsPop3IncomingServer.h | 2 +- mailnews/local/src/nsPop3Protocol.cpp | 95 +++++++++++++------ mailnews/local/src/nsPop3Protocol.h | 14 +-- mailnews/local/src/nsPop3Sink.cpp | 9 +- mailnews/mime/resources/mime.properties | 21 ++++ mailnews/mime/src/mimemsg.cpp | 15 ++- mailnews/mime/src/mimemsg.h | 1 + mailnews/mime/src/nsMimeStringResources.h | 3 + 26 files changed, 301 insertions(+), 77 deletions(-) diff --git a/mailnews/base/prefs/resources/content/am-server.xul b/mailnews/base/prefs/resources/content/am-server.xul index b7cccc0fe229..25bf1d0ea379 100644 --- a/mailnews/base/prefs/resources/content/am-server.xul +++ b/mailnews/base/prefs/resources/content/am-server.xul @@ -150,6 +150,12 @@ accesskey="&downloadOnBiff.accesskey;" prefstring="mail.server.%serverkey%.download_on_biff"/> + + + + diff --git a/mailnews/base/resources/content/mailWindowOverlay.xul b/mailnews/base/resources/content/mailWindowOverlay.xul index 77f0fdb7e58e..51cfed5e2adf 100644 --- a/mailnews/base/resources/content/mailWindowOverlay.xul +++ b/mailnews/base/resources/content/mailWindowOverlay.xul @@ -90,6 +90,11 @@ + + + + + - - + @@ -229,6 +233,7 @@ + @@ -635,6 +640,9 @@ + + + + + + + + + diff --git a/mailnews/base/search/resources/locale/en-US/FilterEditor.dtd b/mailnews/base/search/resources/locale/en-US/FilterEditor.dtd index 58eb2cee6017..20f69a31e6cd 100644 --- a/mailnews/base/search/resources/locale/en-US/FilterEditor.dtd +++ b/mailnews/base/search/resources/locale/en-US/FilterEditor.dtd @@ -24,6 +24,7 @@ + diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index 7d952e828473..12f9c151a162 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -745,6 +745,7 @@ static struct RuleActionsTableEntry ruleActionsTable[] = { nsMsgFilterAction::DeleteFromPop3Server, nsMsgFilterType::All, 0, "Delete from Pop3 server"}, { nsMsgFilterAction::LeaveOnPop3Server, nsMsgFilterType::All, 0, "Leave on Pop3 server"}, { nsMsgFilterAction::JunkScore, nsMsgFilterType::All, 0, "JunkScore"}, + { nsMsgFilterAction::FetchBodyFromPop3Server, nsMsgFilterType::All, 0, "Fetch body from Pop3Server"}, }; const char *nsMsgFilter::GetActionStr(nsMsgRuleActionType action) diff --git a/mailnews/base/src/nsMsgDBView.cpp b/mailnews/base/src/nsMsgDBView.cpp index a7eea26734fe..68ebd85a9c2a 100644 --- a/mailnews/base/src/nsMsgDBView.cpp +++ b/mailnews/base/src/nsMsgDBView.cpp @@ -717,7 +717,14 @@ nsresult nsMsgDBView::FetchSize(nsIMsgHdr * aHdr, PRUnichar ** aSizeString) } else { - aHdr->GetMessageSize(&msgSize); + PRUint32 flags = 0; + + aHdr->GetFlags(&flags); + if (flags & MSG_FLAG_PARTIAL) + aHdr->GetUint32Property("onlineSize", &msgSize); + + if (msgSize == 0) + aHdr->GetMessageSize(&msgSize); if(msgSize < 1024) msgSize = 1024; @@ -1229,7 +1236,9 @@ NS_IMETHODIMP nsMsgDBView::GetCellProperties(PRInt32 aRow, nsITreeColumn *col, n if (flags & MSG_FLAG_NEW) properties->AppendElement(kNewMsgAtom); - if (flags & MSG_FLAG_OFFLINE) + nsCOMPtr localFolder = do_QueryInterface(m_folder); + + if ((flags & MSG_FLAG_OFFLINE) || (localFolder && !(flags & MSG_FLAG_PARTIAL))) properties->AppendElement(kOfflineMsgAtom); if (flags & MSG_FLAG_ATTACHMENT) diff --git a/mailnews/local/public/nsIMsgLocalMailFolder.idl b/mailnews/local/public/nsIMsgLocalMailFolder.idl index 0d43f2846b05..17c2ac943e38 100644 --- a/mailnews/local/public/nsIMsgLocalMailFolder.idl +++ b/mailnews/local/public/nsIMsgLocalMailFolder.idl @@ -43,7 +43,15 @@ interface nsIMsgDatabase; interface nsIMsgFolder; interface nsIMsgCopyServiceListener; -[scriptable, uuid(27D2DE40-BAF1-11d2-9578-00805F8AC615)] +%{C++ +/* flags for markMsgsOnPop3Server */ +#define POP3_NONE 0 +#define POP3_DELETE 1 +#define POP3_FETCH_BODY 2 +#define POP3_FORCE_DEL 3 +%} + +[scriptable, uuid(b8e26003-f2bb-4239-ba47-d597ab6e3671)] interface nsIMsgLocalMailFolder : nsISupports { /** * set the default flags on the subfolders of this folder, such as @@ -59,6 +67,6 @@ interface nsIMsgLocalMailFolder : nsISupports { void copyAllSubFolders(in nsIMsgFolder srcFolder, in nsIMsgWindow msgWindow, in nsIMsgCopyServiceListener listener ); void onCopyCompleted(in nsISupports aSrcSupport, in boolean aMoveCopySucceeded); attribute boolean checkForNewMessagesAfterParsing; - [noscript] void markMsgsOnPop3Server(in nsISupportsArray aMessages, in boolean aDeleteMsgs); + [noscript] void markMsgsOnPop3Server(in nsISupportsArray aMessages, in PRInt32 aMark); void refreshSizeOnDisk(); // file size on disk has possibly changed - update and notify }; diff --git a/mailnews/local/public/nsIPop3IncomingServer.idl b/mailnews/local/public/nsIPop3IncomingServer.idl index 7b9c6b36517e..4ef286bc53f5 100644 --- a/mailnews/local/public/nsIPop3IncomingServer.idl +++ b/mailnews/local/public/nsIPop3IncomingServer.idl @@ -43,9 +43,10 @@ interface nsIMsgFolder; interface nsIUrlListener; interface nsIMsgWindow; -[scriptable, uuid(758a8970-e628-11d2-b7fc-00805f05ffa5)] +[scriptable, uuid(dcae2877-b7e7-47e1-80ca-5a67de03ec4c)] interface nsIPop3IncomingServer : nsISupports { attribute boolean leaveMessagesOnServer; + attribute boolean headersOnly; attribute boolean deleteMailLeftOnServer; attribute boolean authLogin; attribute boolean dotFix; @@ -53,9 +54,9 @@ interface nsIPop3IncomingServer : nsISupports { attribute boolean deleteByAgeFromServer; attribute long numDaysToLeaveOnServer; attribute nsIPop3Protocol runningProtocol; - // client adds uidls to mark one by one, then calls markMessagesDeleted - void addUidlToMarkDeleted(in string aUidl); - void markMessagesDeleted(in boolean aDeleteMsgs); + // client adds uidls to mark one by one, then calls markMessages + void addUidlToMark(in string aUidl, in PRInt32 newStatus); + void markMessages(); attribute boolean authenticated; /* account to which this server defers storage, for global inbox */ attribute string deferredToAccount; diff --git a/mailnews/local/public/nsIPop3Protocol.idl b/mailnews/local/public/nsIPop3Protocol.idl index b16cbf7fbad0..3c3ae6faed41 100644 --- a/mailnews/local/public/nsIPop3Protocol.idl +++ b/mailnews/local/public/nsIPop3Protocol.idl @@ -38,15 +38,19 @@ #include "nsISupports.idl" -[ptr] native nsCStringArray(nsCStringArray); +[ptr] native nsVoidArray(nsVoidArray); %{C++ #include "nsVoidArray.h" %} -[scriptable, uuid(853daefb-411a-41f5-97e0-2f93e79b7302)] +[scriptable, uuid(aebda729-c423-4113-ae36-2229fdc3b699)] interface nsIPop3Protocol : nsISupports { - [noscript] void markMessagesDeleted(in nsCStringArray aUidlArray, in boolean aDeleteMsgs); + /* aUidl is an array of pointers to Pop3UidlEntry's. That structure is + * currently defined in nsPop3Protocol.h, perhaps it should be here + * instead... + */ + [noscript] void markMessages(in nsVoidArray aUidl); }; diff --git a/mailnews/local/public/nsIPop3Sink.idl b/mailnews/local/public/nsIPop3Sink.idl index 8b7802492bcc..77207dac35a0 100644 --- a/mailnews/local/public/nsIPop3Sink.idl +++ b/mailnews/local/public/nsIPop3Sink.idl @@ -61,7 +61,7 @@ interface nsIPop3Sink : nsISupports { [noscript] void IncorporateWrite(in string block, in long length); - [noscript] void IncorporateComplete(in nsIMsgWindow aMsgWindow); + [noscript] void IncorporateComplete(in nsIMsgWindow aMsgWindow, in PRInt32 aSize); [noscript] void IncorporateAbort(in boolean uidlDownload); void BiffGetNewMail(); diff --git a/mailnews/local/src/nsLocalMailFolder.cpp b/mailnews/local/src/nsLocalMailFolder.cpp index 1d25bbaf96f0..a5a6e4b9e623 100644 --- a/mailnews/local/src/nsLocalMailFolder.cpp +++ b/mailnews/local/src/nsLocalMailFolder.cpp @@ -1601,7 +1601,7 @@ nsMsgLocalMailFolder::DeleteMessages(nsISupportsArray *messages, if(NS_SUCCEEDED(rv)) { nsCOMPtr msgSupport; - MarkMsgsOnPop3Server(messages, PR_TRUE); + MarkMsgsOnPop3Server(messages, POP3_DELETE); rv = EnableNotifications(allMessageCountNotifications, PR_FALSE, PR_TRUE /*dbBatching*/); if (NS_SUCCEEDED(rv)) @@ -2938,12 +2938,11 @@ nsresult nsMsgLocalMailFolder::CopyMessageTo(nsISupports *message, // The next time we look at mail the message will be deleted from the server. NS_IMETHODIMP -nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool aDeleteMsgs) +nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRInt32 aMark) { const char *uidl, *accountKey; char *header = nsnull; PRUint32 size = 0, len = 0; - nsCOMPtr hdr; nsCOMPtr curFolderPop3MailServer; nsCOMPtr mailboxSpec; nsCOMArray pop3Servers; // servers with msgs deleted... @@ -2982,6 +2981,11 @@ nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool a PRUint32 srcCount; aMessages->Count(&srcCount); + // Filter delete requests are always honored, others are subject + // to the deleteMailLeftOnServer preference. + PRInt32 mark; + mark = (aMark == POP3_FORCE_DEL) ? POP3_DELETE : aMark; + for (PRInt32 i = 0; i < srcCount; i++) { /* get uidl for this message */ @@ -2992,7 +2996,7 @@ nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool a PRUint32 flags = 0; - if (msgDBHdr /* maybe check for partial flag || some server has leave on server */) + if (msgDBHdr) { msgDBHdr->GetFlags(&flags); len = 0; @@ -3007,8 +3011,6 @@ nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool a curFolderPop3MailServer->GetLeaveMessagesOnServer(&leaveOnServer); } - if (!deleteMailLeftOnServer) - continue; msgDBHdr->GetMessageOffset(&messageOffset); rv = seekableStream->Seek(PR_SEEK_SET, messageOffset); NS_ENSURE_SUCCESS(rv,rv); @@ -3048,20 +3050,22 @@ nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool a msgPop3Server = curMsgPop3MailServer; msgPop3Server->GetDeleteMailLeftOnServer(&deleteMailLeftOnServer); msgPop3Server->GetLeaveMessagesOnServer(&leaveOnServer); - // stop looking at headers if leaveOnServer not set... - if (! (flags & MSG_FLAG_PARTIAL) && !leaveOnServer) - continue; } } } + // ignore this header if not partial and leaveOnServer not set... + if (! (flags & MSG_FLAG_PARTIAL) && !leaveOnServer) + continue; + // if marking deleted, ignore header if we're not deleting from + // server when deleting locally. + if (aMark == POP3_DELETE && leaveOnServer && !deleteMailLeftOnServer) + continue; uidl = strstr(header.get(), X_UIDL); if (uidl) { - if (! (flags & MSG_FLAG_PARTIAL) && !leaveOnServer) - continue; uidl += X_UIDL_LEN + 2; // skip UIDL: header len = strlen(uidl); - msgPop3Server->AddUidlToMarkDeleted(uidl); + msgPop3Server->AddUidlToMark(uidl, mark); // remember this pop server in list of servers with msgs deleted if (pop3Servers.IndexOfObject(msgPop3Server) == kNotFound) pop3Servers.AppendObject(msgPop3Server); @@ -3079,13 +3083,39 @@ nsMsgLocalMailFolder::MarkMsgsOnPop3Server(nsISupportsArray *aMessages, PRBool a // need to do this for all pop3 mail servers that had messages deleted. PRInt32 serverCount = pop3Servers.Count(); for (PRUint32 index = 0; index < serverCount; index++) - pop3Servers[index]->MarkMessagesDeleted(aDeleteMsgs); + pop3Servers[index]->MarkMessages(); mailboxSpec->CloseStream(); return rv; } +NS_IMETHODIMP nsMsgLocalMailFolder::DownloadMessagesForOffline( + nsISupportsArray *aMessages, nsIMsgWindow *aWindow) +{ + nsresult rv; + MarkMsgsOnPop3Server(aMessages, POP3_FETCH_BODY); + rv = GetNewMessages(aWindow, nsnull); + + if (NS_SUCCEEDED(rv)) + { + PRUint32 srcCount; + aMessages->Count(&srcCount); + + for (PRInt32 i = 0; i < srcCount; i++) + { + nsCOMPtr msgDBHdr (do_QueryElementAt(aMessages, i, &rv)); + if (msgDBHdr) + { + PRUint32 flags = 0; + msgDBHdr->GetFlags(&flags); + if (flags & MSG_FLAG_PARTIAL) + mDatabase->DeleteHeader(msgDBHdr, nsnull, PR_FALSE, PR_TRUE); + } + } + } + return rv; +} // TODO: once we move certain code into the IncomingServer (search for TODO) // this method will go away. diff --git a/mailnews/local/src/nsLocalMailFolder.h b/mailnews/local/src/nsLocalMailFolder.h index f2ba28a56c55..55c189ca6002 100644 --- a/mailnews/local/src/nsLocalMailFolder.h +++ b/mailnews/local/src/nsLocalMailFolder.h @@ -174,6 +174,10 @@ public: NS_IMETHOD GetName(PRUnichar **aName); + // Used when headers_only is TRUE + NS_IMETHOD DownloadMessagesForOffline(nsISupportsArray *aMessages, nsIMsgWindow *aWindow); + + protected: nsresult CopyFolderAcrossServer(nsIMsgFolder *srcFolder, nsIMsgWindow *msgWindow,nsIMsgCopyServiceListener* listener); diff --git a/mailnews/local/src/nsLocalUndoTxn.cpp b/mailnews/local/src/nsLocalUndoTxn.cpp index 39e1efbce9c3..5f45ca2145de 100644 --- a/mailnews/local/src/nsLocalUndoTxn.cpp +++ b/mailnews/local/src/nsLocalUndoTxn.cpp @@ -346,7 +346,7 @@ nsLocalMoveCopyMsgTxn::UndoTransactionInternal() } nsCOMPtr localFolder = do_QueryInterface(srcFolder); if (localFolder) - localFolder->MarkMsgsOnPop3Server(srcMessages, PR_FALSE /*deleteMsgs*/); + localFolder->MarkMsgsOnPop3Server(srcMessages, POP3_NONE /*deleteMsgs*/); } srcDB->SetSummaryValid(PR_TRUE); srcDB->Commit(nsMsgDBCommitType::kLargeCommit); @@ -430,7 +430,7 @@ nsLocalMoveCopyMsgTxn::RedoTransaction() { nsCOMPtr localFolder = do_QueryInterface(srcFolder); if (localFolder) - localFolder->MarkMsgsOnPop3Server(srcMessages, PR_TRUE /*deleteMsgs*/); + localFolder->MarkMsgsOnPop3Server(srcMessages, POP3_DELETE /*deleteMsgs*/); rv = srcDB->DeleteMessages(&m_srcKeyArray, nsnull); srcDB->SetSummaryValid(PR_TRUE); diff --git a/mailnews/local/src/nsParseMailbox.cpp b/mailnews/local/src/nsParseMailbox.cpp index 60eed8e94806..24c72c2d2b08 100644 --- a/mailnews/local/src/nsParseMailbox.cpp +++ b/mailnews/local/src/nsParseMailbox.cpp @@ -1722,7 +1722,29 @@ NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, nsIMsgWi NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr iSupports = do_QueryInterface(msgHdr); messages->AppendElement(iSupports); - localFolder->MarkMsgsOnPop3Server(messages, PR_TRUE); + // This action ignores the deleteMailLeftOnServer preference + localFolder->MarkMsgsOnPop3Server(messages, POP3_FORCE_DEL); + } + } + break; + case nsMsgFilterAction::FetchBodyFromPop3Server: + { + PRUint32 flags = 0; + nsCOMPtr downloadFolder; + msgHdr->GetFolder(getter_AddRefs(downloadFolder)); + nsCOMPtr localFolder = do_QueryInterface(downloadFolder); + msgHdr->GetFlags(&flags); + if (localFolder && (flags & MSG_FLAG_PARTIAL)) + { + nsCOMPtr messages; + rv = NS_NewISupportsArray(getter_AddRefs(messages)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr iSupports = do_QueryInterface(msgHdr); + messages->AppendElement(iSupports); + localFolder->MarkMsgsOnPop3Server(messages, POP3_FETCH_BODY); + // Don't add this header to the DB, we're going to replace it + // with the full message. + m_msgMovedByFilter = PR_TRUE; } } break; diff --git a/mailnews/local/src/nsPop3IncomingServer.cpp b/mailnews/local/src/nsPop3IncomingServer.cpp index 52f8fcc3c672..79b9d8d7009d 100644 --- a/mailnews/local/src/nsPop3IncomingServer.cpp +++ b/mailnews/local/src/nsPop3IncomingServer.cpp @@ -109,6 +109,10 @@ NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, LeaveMessagesOnServer, "leave_on_server") +NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, + HeadersOnly, + "headers_only") + NS_IMPL_SERVERPREF_BOOL(nsPop3IncomingServer, DeleteMailLeftOnServer, "delete_mail_left_on_server") @@ -547,17 +551,36 @@ NS_IMETHODIMP nsPop3IncomingServer::GetRunningProtocol(nsIPop3Protocol **aProtoc return NS_OK; } -NS_IMETHODIMP nsPop3IncomingServer::AddUidlToMarkDeleted(const char *aUidl) +NS_IMETHODIMP nsPop3IncomingServer::AddUidlToMark(const char *aUidl, + PRInt32 aMark) { - return m_uidlsToMarkDeleted.AppendCString(nsDependentCString(aUidl)); + Pop3UidlEntry *uidlEntry; + nsresult rv = NS_ERROR_OUT_OF_MEMORY; + + uidlEntry = PR_NEWZAP(Pop3UidlEntry); + if (uidlEntry) + { + uidlEntry->uidl = strdup(aUidl); + if (uidlEntry->uidl) + { + uidlEntry->status = (aMark == POP3_DELETE) ? DELETE_CHAR : + (aMark == POP3_FETCH_BODY) ? FETCH_BODY : KEEP; + m_uidlsToMark.AppendElement(uidlEntry); + rv = NS_OK; + } else + { + PR_Free(uidlEntry); + } + } + return rv; } -NS_IMETHODIMP nsPop3IncomingServer::MarkMessagesDeleted(PRBool aDeleteMsgs) +NS_IMETHODIMP nsPop3IncomingServer::MarkMessages() { nsresult rv; if (m_runningProtocol) { - rv = m_runningProtocol->MarkMessagesDeleted(&m_uidlsToMarkDeleted, aDeleteMsgs); + rv = m_runningProtocol->MarkMessages(&m_uidlsToMark); } else { @@ -570,9 +593,16 @@ NS_IMETHODIMP nsPop3IncomingServer::MarkMessagesDeleted(PRBool aDeleteMsgs) GetHostName(getter_Copies(hostName)); GetUsername(getter_Copies(userName)); // do it all in one fell swoop - rv = nsPop3Protocol::MarkMsgDeletedForHost(hostName, userName, localPath, m_uidlsToMarkDeleted, aDeleteMsgs); + rv = nsPop3Protocol::MarkMsgForHost(hostName, userName, localPath, m_uidlsToMark); } - m_uidlsToMarkDeleted.Clear(); + PRUint32 count = m_uidlsToMark.Count(); + for (PRUint32 i = 0; i < count; i++) + { + Pop3UidlEntry *ue = NS_STATIC_CAST(Pop3UidlEntry*,m_uidlsToMark[i]); + PR_Free(ue->uidl); + PR_Free(ue); + } + m_uidlsToMark.Clear(); return rv; } diff --git a/mailnews/local/src/nsPop3IncomingServer.h b/mailnews/local/src/nsPop3IncomingServer.h index 502ed6e5a379..b854719ab1be 100644 --- a/mailnews/local/src/nsPop3IncomingServer.h +++ b/mailnews/local/src/nsPop3IncomingServer.h @@ -79,7 +79,7 @@ private: PRBool m_authenticated; nsCOMPtr m_runningProtocol; nsCOMPtr m_rootMsgFolder; - nsCStringArray m_uidlsToMarkDeleted; + nsVoidArray m_uidlsToMark; }; #endif diff --git a/mailnews/local/src/nsPop3Protocol.cpp b/mailnews/local/src/nsPop3Protocol.cpp index 06645d18a576..3226a8684a8c 100644 --- a/mailnews/local/src/nsPop3Protocol.cpp +++ b/mailnews/local/src/nsPop3Protocol.cpp @@ -158,10 +158,10 @@ put_hash(PLHashTable* table, const char* key, char value, PRTime dateReceived) if (tmp) { tmp->uidl = PL_strdup(key); - tmp->dateReceived = dateReceived; - tmp->status = value; if (tmp->uidl) { + tmp->dateReceived = dateReceived; + tmp->status = value; PL_HashTableAdd(table, (const void *)tmp->uidl, (void*) tmp); } else @@ -313,7 +313,7 @@ net_pop3_load_state(const char* searchhost, if (flags && uidl) { if ((flags[0] == KEEP) || (flags[0] == DELETE_CHAR) || - (flags[0] == TOO_BIG)) + (flags[0] == TOO_BIG) || (flags[0] == FETCH_BODY)) { put_hash(current->hash, uidl, flags[0], dateReceived); } @@ -368,6 +368,7 @@ net_pop3_write_mapper(PLHashEntry* he, PRIntn msgindex, void* arg) Pop3UidlEntry *uidlEntry = (Pop3UidlEntry *) he->value; NS_ASSERTION((uidlEntry->status == KEEP) || (uidlEntry->status == DELETE_CHAR) || + (uidlEntry->status == FETCH_BODY) || (uidlEntry->status == TOO_BIG), "invalid status"); char* tmpBuffer = PR_smprintf("%c %s %d" MSG_LINEBREAK, uidlEntry->status, (char*) uidlEntry->uidl, uidlEntry->dateReceived); @@ -446,15 +447,14 @@ message is not found, then the message was downloaded completly and already dele from the server. So this only applies to messages kept on the server or too big for download. */ /* static */ -void nsPop3Protocol::MarkMsgDeletedInHashTable(PLHashTable *hashTable, const char *uidl, PRBool deleteChar, PRBool *changed) +void nsPop3Protocol::MarkMsgInHashTable(PLHashTable *hashTable, const Pop3UidlEntry *uidlE, PRBool *changed) { - Pop3UidlEntry *uidlEntry = (Pop3UidlEntry *) PL_HashTableLookup(hashTable, uidl); + Pop3UidlEntry *uidlEntry = (Pop3UidlEntry *) PL_HashTableLookup(hashTable, uidlE->uidl); if (uidlEntry) { - char newStatus = (deleteChar) ? DELETE_CHAR : KEEP; - if (uidlEntry->status != newStatus) + if (uidlEntry->status != uidlE->status) { - uidlEntry->status = newStatus; + uidlEntry->status = uidlE->status; *changed = PR_TRUE; } } @@ -462,10 +462,9 @@ void nsPop3Protocol::MarkMsgDeletedInHashTable(PLHashTable *hashTable, const cha /* static */ nsresult -nsPop3Protocol::MarkMsgDeletedForHost(const char *hostName, const char *userName, +nsPop3Protocol::MarkMsgForHost(const char *hostName, const char *userName, nsIFileSpec *mailDirectory, - nsCStringArray &UIDLArray, - PRBool deleteMsgs) + nsVoidArray &UIDLArray) { if (!hostName || !userName || !mailDirectory) return NS_ERROR_NULL_POINTER; @@ -478,7 +477,10 @@ nsPop3Protocol::MarkMsgDeletedForHost(const char *hostName, const char *userName PRUint32 count = UIDLArray.Count(); for (PRUint32 i = 0; i < count; i++) - MarkMsgDeletedInHashTable(uidlHost->hash, UIDLArray[i]->get(), deleteMsgs, &changed); + { + MarkMsgInHashTable(uidlHost->hash, + NS_STATIC_CAST(Pop3UidlEntry*,UIDLArray[i]), &changed); + } if (changed) net_pop3_write_state(uidlHost, mailDirectory); @@ -798,6 +800,7 @@ nsresult nsPop3Protocol::LoadUrl(nsIURI* aURL, nsISupports * /* aConsumer */) // size limit m_pop3Server->GetLeaveMessagesOnServer(&m_pop3ConData->leave_on_server); + m_pop3Server->GetHeadersOnly(&m_pop3ConData->headers_only); PRBool limitMessageSize = PR_FALSE; nsCOMPtr server = do_QueryInterface(m_pop3Server); @@ -2396,7 +2399,7 @@ PRInt32 nsPop3Protocol::GetUidlList(nsIInputStream* inputStream, PRInt32 nsPop3Protocol::GetMsg() { - char c; + char c = 0; int i; PRBool prefBool = PR_FALSE; PRInt32 popstateTimestamp = TimeInSecondsFromPRTime(PR_Now()); @@ -2636,10 +2639,18 @@ nsPop3Protocol::GetMsg() { m_pop3ConData->next_state = POP3_GET_MSG; } - else if ((c != TOO_BIG) && (m_pop3ConData->size_limit > 0) && - (info->size > m_pop3ConData->size_limit) && + else if (c == FETCH_BODY) + { + m_pop3ConData->next_state = POP3_SEND_RETR; + PL_HashTableRemove (m_pop3ConData->uidlinfo->hash, (void*) + info->uidl); + } + else if ((c != TOO_BIG) && (TestCapFlag(POP3_TOP_UNDEFINED | POP3_HAS_TOP)) && - !m_pop3ConData->only_uidl) + (m_pop3ConData->headers_only || + ((m_pop3ConData->size_limit > 0) && + (info->size > m_pop3ConData->size_limit) && + !m_pop3ConData->only_uidl))) { /* message is too big */ m_pop3ConData->truncating_cur_msg = PR_TRUE; @@ -2678,7 +2689,7 @@ nsPop3Protocol::GetMsg() // if this is a message we already know about (i.e., it was in popstate.dat already), // we need to maintain the original date the message was downloaded. - if (info->uidl && !m_pop3ConData->only_uidl && !m_pop3ConData->truncating_cur_msg) + if (info->uidl && !m_pop3ConData->only_uidl && !m_pop3ConData->truncating_cur_msg) /* message already marked as too_big */ put_hash(m_pop3ConData->newuidl, info->uidl, KEEP, popstateTimestamp); } @@ -2694,8 +2705,9 @@ nsPop3Protocol::GetMsg() */ PRInt32 nsPop3Protocol::SendTop() { - char * cmd = PR_smprintf( "TOP %ld 20" CRLF, - m_pop3ConData->msg_info[m_pop3ConData->last_accessed_msg].msgnum); + char * cmd = PR_smprintf( "TOP %ld %d" CRLF, + m_pop3ConData->msg_info[m_pop3ConData->last_accessed_msg].msgnum, + m_pop3ConData->headers_only ? 0 : 20); PRInt32 status = -1; if (cmd) { @@ -2841,7 +2853,6 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream, */ if (m_pop3ConData->truncating_cur_msg) { /* TOP, truncated message */ - m_pop3ConData->cur_msg_size = m_pop3ConData->size_limit; flags |= MSG_FLAG_PARTIAL; } else @@ -2910,8 +2921,8 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream, nsCOMPtr msgWindow; if (NS_SUCCEEDED(rv)) rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow)); - - rv = m_nsIPop3Sink->IncorporateComplete(msgWindow); + rv = m_nsIPop3Sink->IncorporateComplete(msgWindow, + m_pop3ConData->truncating_cur_msg ? m_pop3ConData->cur_msg_size : 0); // The following was added to prevent the loss of Data when we try // and write to somewhere we dont have write access error to (See // bug 62480) @@ -2980,7 +2991,8 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream, if (NS_SUCCEEDED(rv)) rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow)); rv = - m_nsIPop3Sink->IncorporateComplete(msgWindow); + m_nsIPop3Sink->IncorporateComplete(msgWindow, + m_pop3ConData->truncating_cur_msg ? m_pop3ConData->cur_msg_size : 0); // The following was added to prevent the loss of Data when we try // and write to somewhere we dont have write access error to (See @@ -3001,10 +3013,34 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream, if (m_pop3ConData->truncating_cur_msg || m_pop3ConData->leave_on_server ) { + Pop3UidlEntry *uidlEntry = NULL; + + // A filter might have decided to retrieve this full msg + if (m_pop3ConData->truncating_cur_msg) + { + Pop3MsgInfo* info = m_pop3ConData->msg_info + m_pop3ConData->last_accessed_msg; + uidlEntry = (Pop3UidlEntry *)PL_HashTableLookup(m_pop3ConData->newuidl, info->uidl); + } + if (uidlEntry && uidlEntry->status == FETCH_BODY) + { + // A filter decided to retrieve this full msg + m_pop3ConData->next_state = POP3_SEND_RETR; + m_pop3ConData->truncating_cur_msg = PR_FALSE; + } else + { /* We've retrieved all or part of this message, but we want to keep it on the server. Go on to the next message. */ - m_pop3ConData->last_accessed_msg++; - m_pop3ConData->next_state = POP3_GET_MSG; + m_pop3ConData->last_accessed_msg++; + m_pop3ConData->next_state = POP3_GET_MSG; + } + if (m_pop3ConData->only_uidl) + { + /* GetMsg didn't update this field. Do it now. */ + uidlEntry = (Pop3UidlEntry *)PL_HashTableLookup(m_pop3ConData->uidlinfo->hash, m_pop3ConData->only_uidl); + NS_ASSERTION(uidlEntry, "uidl not found in uidlinfo"); + if (uidlEntry) + put_hash(m_pop3ConData->uidlinfo->hash, m_pop3ConData->only_uidl, KEEP, uidlEntry->dateReceived); + } } else { m_pop3ConData->next_state = POP3_SEND_DELE; @@ -3122,7 +3158,8 @@ nsPop3Protocol::HandleLine(char *line, PRUint32 line_length) nsCOMPtr msgWindow; if (NS_SUCCEEDED(rv)) rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow)); - rv = m_nsIPop3Sink->IncorporateComplete(msgWindow); + rv = m_nsIPop3Sink->IncorporateComplete(msgWindow, + m_pop3ConData->truncating_cur_msg ? m_pop3ConData->cur_msg_size : 0); // The following was added to prevent the loss of Data when we try // and write to somewhere we dont have write access error to (See @@ -3711,7 +3748,7 @@ nsresult nsPop3Protocol::CloseSocket() return rv; } -NS_IMETHODIMP nsPop3Protocol::MarkMessagesDeleted(nsCStringArray *aUIDLArray, PRBool aDeleteMsgs) +NS_IMETHODIMP nsPop3Protocol::MarkMessages(nsVoidArray *aUIDLArray) { NS_ENSURE_ARG_POINTER(aUIDLArray); PRUint32 count = aUIDLArray->Count(); @@ -3720,9 +3757,9 @@ NS_IMETHODIMP nsPop3Protocol::MarkMessagesDeleted(nsCStringArray *aUIDLArray, PR { PRBool changed; if (m_pop3ConData->newuidl) - MarkMsgDeletedInHashTable(m_pop3ConData->newuidl, aUIDLArray->CStringAt(i)->get(), aDeleteMsgs, &changed); + MarkMsgInHashTable(m_pop3ConData->newuidl, NS_STATIC_CAST(Pop3UidlEntry*,aUIDLArray->ElementAt(i)), &changed); if (m_pop3ConData->uidlinfo) - MarkMsgDeletedInHashTable(m_pop3ConData->uidlinfo->hash, aUIDLArray->CStringAt(i)->get(), aDeleteMsgs, &changed); + MarkMsgInHashTable(m_pop3ConData->uidlinfo->hash, NS_STATIC_CAST(Pop3UidlEntry*,aUIDLArray->ElementAt(i)), &changed); } return NS_OK; } diff --git a/mailnews/local/src/nsPop3Protocol.h b/mailnews/local/src/nsPop3Protocol.h index e3ecd1adc3df..6bb174e02c59 100644 --- a/mailnews/local/src/nsPop3Protocol.h +++ b/mailnews/local/src/nsPop3Protocol.h @@ -175,10 +175,11 @@ enum Pop3StatesEnum { #define KEEP 'k' /* If we want to keep this item on server. */ #define DELETE_CHAR 'd' /* If we want to delete this item. */ #define TOO_BIG 'b' /* item left on server because it was too big */ +#define FETCH_BODY 'f' /* Fetch full body of a partial msg */ typedef struct Pop3UidlEntry { /* information about this message */ char* uidl; - char status; // KEEP=='k', DELETE='d' TOO_BIG='b' + char status; // KEEP=='k', DELETE='d' TOO_BIG='b' FETCH_BODY='f' PRInt32 dateReceived; // time message received, used for aging } Pop3UidlEntry; @@ -199,6 +200,8 @@ typedef struct Pop3MsgInfo { typedef struct _Pop3ConData { PRBool leave_on_server; /* Whether we're supposed to leave messages on server. */ + PRBool headers_only; /* Whether to just fetch headers on initial + downloads. */ PRInt32 size_limit; /* Leave messages bigger than this on the server and only download a partial message. */ @@ -299,13 +302,12 @@ public: // for nsMsgLineBuffer virtual PRInt32 HandleLine(char *line, PRUint32 line_length); - static void MarkMsgDeletedInHashTable(PLHashTable *hashTable, const char *uidl, - PRBool deleteChar, PRBool *changed); + static void MarkMsgInHashTable(PLHashTable *hashTable, const Pop3UidlEntry *uidl, + PRBool *changed); - static nsresult MarkMsgDeletedForHost(const char *hostName, const char *userName, + static nsresult MarkMsgForHost(const char *hostName, const char *userName, nsIFileSpec *mailDirectory, - nsCStringArray &UIDLArray, - PRBool deleteMsgs); + nsVoidArray &UIDLArray); private: nsCString m_ApopTimestamp; nsCOMPtr mStringService; diff --git a/mailnews/local/src/nsPop3Sink.cpp b/mailnews/local/src/nsPop3Sink.cpp index 92c95264fb4a..8923a2c8a420 100644 --- a/mailnews/local/src/nsPop3Sink.cpp +++ b/mailnews/local/src/nsPop3Sink.cpp @@ -533,7 +533,7 @@ nsresult nsPop3Sink::WriteLineToMailbox(const char *buffer) } NS_IMETHODIMP -nsPop3Sink::IncorporateComplete(nsIMsgWindow *aMsgWindow) +nsPop3Sink::IncorporateComplete(nsIMsgWindow *aMsgWindow, PRInt32 aSize) { if (m_buildMessageUri && m_baseMessageUri) { @@ -549,7 +549,14 @@ nsPop3Sink::IncorporateComplete(nsIMsgWindow *aMsgWindow) if (NS_FAILED(rv)) return rv; NS_ASSERTION(m_newMailParser, "could not get m_newMailParser"); if (m_newMailParser) + { + // PublishMsgHdr clears m_newMsgHdr, so we need a comptr to + // hold onto it. + nsCOMPtr hdr = m_newMailParser->m_newMsgHdr; m_newMailParser->PublishMsgHeader(aMsgWindow); + if (aSize) + hdr->SetUint32Property("onlineSize", aSize); + } #ifdef DEBUG printf("Incorporate message complete.\n"); diff --git a/mailnews/mime/resources/mime.properties b/mailnews/mime/resources/mime.properties index e251d299e182..3d7e85027971 100644 --- a/mailnews/mime/resources/mime.properties +++ b/mailnews/mime/resources/mime.properties @@ -284,3 +284,24 @@ ## @name MIME_FORWARDED_MESSAGE_USER_WROTE ## @loc 1041=-------- Original Message -------- + +# Partial Message Format2 1 +## @name MIME_MSG_PARTIAL_FMT2_1 +## @loc +# LOCALIZATION NOTE (1037): In the following line, translate only the words, "Not Downloaded". +1042=

Not Downloaded
+ +# Partial Message Format2 2 +## @name MIME_MSG_PARTIAL_FMT2_2 +## @loc +# LOCALIZATION NOTE (1038): Translate the following two lines as a single sentence. In the middle of the two sections +# there will be a URL. You may translate the text in any order you wish, but the html tags must stay in the same locations. +# In particular, the "" tag must begin the first section, which must end with the "" +1043=Only the headers for this message were downloaded from the mail server.

Click " sign and end with the tags,"

" +# Do not translate "" tag. +1044=">here to download the rest of the message. diff --git a/mailnews/mime/src/mimemsg.cpp b/mailnews/mime/src/mimemsg.cpp index 61f5f329e9ec..b4318b82c5ee 100644 --- a/mailnews/mime/src/mimemsg.cpp +++ b/mailnews/mime/src/mimemsg.cpp @@ -111,6 +111,7 @@ MimeMessage_initialize (MimeObject *object) { MimeMessage *msg = (MimeMessage *)object; msg->grabSubject = PR_FALSE; + msg->bodyLength = 0; return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(object); } @@ -193,6 +194,8 @@ MimeMessage_parse_line (char *aLine, PRInt32 aLength, MimeObject *obj) PR_ASSERT(kid); if (!kid) return -1; + msg->bodyLength += length; + /* Don't allow MimeMessage objects to not end in a newline, since it would be inappropriate for any following part to appear on the same line as the last line of the message. @@ -521,8 +524,11 @@ MimeMessage_close_headers (MimeObject *obj) char dummy = 0; if (sscanf(xmoz, " %lx %c", &flags, &dummy) == 1 && flags & MSG_FLAG_PARTIAL) + { + obj->options->html_closure = obj; obj->options->generate_footer_html_fn = MimeMessage_partial_message_html; + } PR_FREEIF(xmoz); } } @@ -816,12 +822,14 @@ static char * MimeMessage_partial_message_html(const char *data, void *closure, MimeHeaders *headers) { + MimeMessage *msg = (MimeMessage *)closure; nsCAutoString orig_url(data); char *partialMsgHtml = nsnull; char *uidl = MimeHeaders_get(headers, HEADER_X_UIDL, PR_FALSE, PR_FALSE); char *msgId = MimeHeaders_get(headers, HEADER_MESSAGE_ID, PR_FALSE, PR_FALSE); char *msgIdPtr = PL_strstr(msgId, "<"); + int msgBase; orig_url.ReplaceSubstring("mailbox-message", "mailbox"); orig_url.ReplaceSubstring("#", "?number="); @@ -834,11 +842,12 @@ MimeMessage_partial_message_html(const char *data, void *closure, if (gtPtr) *gtPtr = 0; + msgBase = (msg->bodyLength > MSG_LINEBREAK_LEN) ? MIME_MSG_PARTIAL_FMT_1 : MIME_MSG_PARTIAL_FMT2_1; char *escapedUidl = uidl ? nsEscape(uidl, url_XAlphas) : nsnull; char *escapedMsgId = msgIdPtr ? nsEscape(msgIdPtr, url_Path) : nsnull; - char *fmt1 = MimeGetStringByID(1037); - char *fmt2 = MimeGetStringByID(1038); - char *fmt3 = MimeGetStringByID(1039); + char *fmt1 = MimeGetStringByID(msgBase); + char *fmt2 = MimeGetStringByID(msgBase+1); + char *fmt3 = MimeGetStringByID(msgBase+2); char *msgUrl = PR_smprintf("%s&messageid=%s&uidl=%s", orig_url.get(), escapedMsgId, escapedUidl); partialMsgHtml = PR_smprintf("%s%s%s%s", fmt1,fmt2, msgUrl, fmt3); diff --git a/mailnews/mime/src/mimemsg.h b/mailnews/mime/src/mimemsg.h index 38ce0ddfce57..2d4ee85f0601 100644 --- a/mailnews/mime/src/mimemsg.h +++ b/mailnews/mime/src/mimemsg.h @@ -64,6 +64,7 @@ struct MimeMessage { PRBool crypto_msg_signed_p; /* What the emitted xlation-stamp *says*. */ PRBool crypto_msg_encrypted_p; PRBool grabSubject; /* Should we try to grab the subject of this message */ + PRInt32 bodyLength; }; #endif /* _MIMEMSG_H_ */ diff --git a/mailnews/mime/src/nsMimeStringResources.h b/mailnews/mime/src/nsMimeStringResources.h index 91d7b678c937..bb61474fd5b6 100644 --- a/mailnews/mime/src/nsMimeStringResources.h +++ b/mailnews/mime/src/nsMimeStringResources.h @@ -82,5 +82,8 @@ #define MIME_MSG_PARTIAL_FMT_3 1039 #define MIME_MSG_DEFAULT_ATTACHMENT_NAME 1040 #define MIME_FORWARDED_MESSAGE_HTML_USER_WROTE 1041 +#define MIME_MSG_PARTIAL_FMT2_1 1042 +#define MIME_MSG_PARTIAL_FMT2_2 1043 +#define MIME_MSG_PARTIAL_FMT2_3 1044 #endif /* _NAME_OF_THIS_HEADER_FILE__ */