gecko-dev/lib/libmsg/msgmpane.cpp

1816 строки
47 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "rosetta.h"
#include "msg.h"
#include "errcode.h"
#include "xp_str.h"
#include "xpgetstr.h"
#include "msgmpane.h"
#include "msgtpane.h"
#include "msgfinfo.h"
#include "msgdb.h"
#include "msgdbvw.h"
#include "msgmast.h"
#include "msgprefs.h"
#include "msgsec.h"
#include "mailhdr.h"
#include "msgundmg.h"
#include "msgundac.h"
#include "mime.h"
#include "addrbook.h"
#include "libi18n.h"
#include "newshost.h"
#include "prefapi.h"
#include "maildb.h"
#include "prsembst.h"
#include "listngst.h"
#include "newsdb.h"
#include "intl_csi.h"
#include "msgimap.h"
#include "msgurlq.h"
#include "msgmdn.h"
#include "msgstrob.h"
extern "C"
{
extern int MK_MSG_DELETE_MESSAGE;
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_MARK_AS_READ;
extern int MK_MSG_MARK_AS_UNREAD;
extern int MK_MSG_NEW_NEWS_MESSAGE;
extern int MK_MSG_POST_REPLY;
extern int MK_MSG_POST_MAIL_REPLY;
extern int MK_MSG_NEW_MAIL_MESSAGE;
extern int MK_MSG_REPLY;
extern int MK_MSG_REPLY_TO_SENDER;
extern int MK_MSG_REPLY_TO_ALL;
extern int MK_MSG_FORWARD_QUOTED;
extern int MK_MSG_FORWARD;
extern int MK_MSG_PARTIAL_MSG_FMT_1;
extern int MK_MSG_PARTIAL_MSG_FMT_2;
extern int MK_MSG_PARTIAL_MSG_FMT_3;
extern int MK_MSG_ID_NOT_IN_FOLDER;
extern int MK_MSG_FOLDER_UNREADABLE;
extern int MK_MSG_OPEN_DRAFT;
extern int MK_MSG_ADD_SENDER_TO_ADDRESS_BOOK;
extern int MK_MSG_ADD_ALL_TO_ADDRESS_BOOK;
extern int MK_MSG_CANT_OPEN;
}
#ifdef DEBUG_terry
static void
StupidAttachmentCount(MSG_Pane* pane, void*, int32 num, XP_Bool finished)
{
XP_Trace("@@@ %d attachments (%s)\n", num, finished ? "Done" : "Not done");
if (finished && num > 0) {
MSG_AttachmentData* data;
finished = FALSE;
MSG_GetViewedAttachments(pane, &data, &finished);
XP_ASSERT(finished);
MSG_AttachmentData* tmp;
for (tmp = data ; tmp->url ; tmp++) {
XP_Trace("@@@ %s\n", tmp->url);
XP_Trace("@@@ %s\n", tmp->real_type);
XP_Trace("@@@ %s\n", tmp->real_name);
XP_Trace("@@@ %s\n", tmp->description);
}
MSG_FreeAttachmentList(pane, data);
}
}
#endif
MSG_MessagePane::MSG_MessagePane(MWContext* context, MSG_Master* master)
: m_PaneListener(this), MSG_Pane(context, master)
{
m_key = MSG_MESSAGEKEYNONE;
m_postDeleteLoadKey = MSG_MESSAGEKEYNONE;
#ifdef DEBUG_terry
static MSG_MessagePaneCallbacks call;
call.AttachmentCount = StupidAttachmentCount;
SetMessagePaneCallbacks(&call, NULL);
#endif
}
MSG_MessagePane::~MSG_MessagePane ()
{
ClearDerivedStrings();
InterruptContext(FALSE);
if (m_view) {
m_view->Remove(&m_PaneListener);
m_view->Close(); // drop reference count
m_view = NULL;
}
}
MSG_PaneType MSG_MessagePane::GetPaneType()
{
return MSG_MESSAGEPANE;
}
int MSG_MessagePane::SetMessagePaneCallbacks(MSG_MessagePaneCallbacks* c,
void* closure)
{
m_callbacks = c;
m_callbackclosure = closure;
return 0;
}
MSG_MessagePaneCallbacks*
MSG_MessagePane::GetMessagePaneCallbacks(void** closure)
{
if (closure) *closure = m_callbackclosure;
return m_callbacks;
}
void MSG_MessagePane::NotifyPrefsChange(NotifyCode code)
{
if (m_folder)
{
if (((code == MailServerType)||(code == PopHost)) &&
(GetFolder()->GetType() == FOLDER_IMAPMAIL))
{
FE_PaneChanged(this, TRUE, MSG_PaneNotifyFolderDeleted,
(uint32)GetFolder());
}
else if (code != Directory)
{
// We don't want to reload the message on a directory change
// because a directory notification can result from a prefs
// reload, which can in turn result from loading a message.
// (Holy recursion, Batman!)
LoadMessage(m_folder, m_key, NULL, TRUE);
}
else // code == Directory
{
// If the main mail directory changes, do we not close ourselves?
}
}
}
MSG_FolderInfo *MSG_MessagePane::GetFolder()
{
return m_folder;
}
void MSG_MessagePane::SetFolder(MSG_FolderInfo *info)
{
m_folder = info;
}
PaneListener *MSG_MessagePane::GetListener()
{
return &m_PaneListener;
}
MsgERR MSG_MessagePane::InitializeFolderAndView (const char *folderName)
{
MsgERR status = 0;
MSG_FolderInfo *folder = GetMaster()->FindMailFolder (folderName, FALSE);
if (m_folder != folder) // don't reinitialize folder and view unless it has changed
{
if (folder) // sometimes, folderName is NULL, so folder will be NULL, so re-use m_folder
m_folder = folder;
CloseView();
char* url = m_folder->BuildUrl(NULL, MSG_MESSAGEKEYNONE);
status = MessageDBView::OpenURL(url, GetMaster(),
ViewAny,
&m_view, TRUE /* open in foreground */);
if (status == eSUCCESS && m_view != NULL)
m_view->Add(&m_PaneListener); // add listener back to view
XP_FREE(url);
}
return status;
}
void MSG_MessagePane::StartingUpdate(MSG_NOTIFY_CODE code, MSG_ViewIndex where,
int32 num)
{
if (m_numstack == 0)
m_PaneListener.StartKeysChanging();
MSG_Pane::StartingUpdate(code, where, num);
}
void MSG_MessagePane::EndingUpdate(MSG_NOTIFY_CODE code, MSG_ViewIndex where,
int32 num)
{
MSG_Pane::EndingUpdate(code, where, num);
if (m_numstack == 0)
m_PaneListener.EndKeysChanging();
}
void MSG_MessagePane::SwitchView(MessageDBView *newView)
{
m_view->Remove(&m_PaneListener);
m_view->Close();
m_view = newView;
m_view->AddReference();
m_view->Add(&m_PaneListener); // add listener back to view
newView->EnsureListed(m_key);
}
// allow_content_change indicates whether we should maintain the
// integrity of the original message from the server. If set to TRUE,
// that means it is safe for us to fiddle with the content. For instance,
// we are allowed to download it by IMAP MIME parts and assemble a somewhat
// empty shell.
MsgERR
MSG_MessagePane::LoadMessage(MSG_FolderInfo* folder,
MessageKey key,
Net_GetUrlExitFunc *loadUrlExitFunction,
XP_Bool allow_content_change)
{
XP_Bool clearMessageArea = (m_key != key);
if (m_key != key)
MSG_SetBiffStateAndUpdateFE(MSG_BIFF_NoMail);
#ifdef XP_MAC
{
// Ask FE if it's OK to load another message (the window may be closing).
enum { MSG_PaneNotifyOKToLoadNewMessage = 999 }; // Can we make this official?
XP_Bool ok = TRUE;
FE_PaneChanged(this, FALSE, (MSG_PANE_CHANGED_NOTIFY_CODE)MSG_PaneNotifyOKToLoadNewMessage, (int32)&ok);
if (!ok)
return eSUCCESS;
}
#endif
if (clearMessageArea && folder && folder->GetType() == FOLDER_IMAPMAIL)
{
MSG_IMAPFolderInfoMail *imapFolder = folder->GetIMAPFolderInfoMail();
MSG_UrlQueue *queue = MSG_UrlQueue::FindQueueWithSameContext (this);
if (queue != NULL)
clearMessageArea = FALSE;
// pseudo interrupt any message load, if we're fetching by chunks
XP_Bool fetchByChunks = TRUE;
PREF_GetBoolPref("mail.imap.fetch_by_chunks", &fetchByChunks);
if (fetchByChunks && imapFolder && imapFolder->GetRunningIMAPUrl())
{
IMAP_PseudoInterruptFetch(GetContext());
clearMessageArea = FALSE;
}
}
// Clear message area, but only if we're loading
// a new message. This is all very unfortunate. Clearing message
// area causes libparse to interrupt the mail context, which happens
// to be reparsing a folder in some cases. This is because WinFE
// clears the message area if the view is empty (even if it was
// empty to start with) as a side effect of trying to select something.
if (clearMessageArea)
{
#ifndef XP_MAC
// macfe has its own clearing routine (CMessageView::ClearMessageArea)
msg_ClearMessageArea(GetContext());
#endif
m_key = key;
}
if (key == MSG_MESSAGEKEYNONE)
return eSUCCESS;
// don't reinitialize folder and view unless it has changed, or the view or DB seem invalid
if (m_folder != folder || !m_view || !m_view->GetDB())
{
m_folder = folder;
MsgERR status = InitializeFolderAndView (NULL);
if (status != eSUCCESS)
return status;
}
FE_PaneChanged(this, FALSE, MSG_PaneNotifyMessageLoaded, key);
if (m_callbacks && m_callbacks->AttachmentCount) {
m_callbacks->AttachmentCount(this, m_callbackclosure, 0, FALSE);
}
XP_ASSERT(m_view);
char *url = m_folder->BuildUrl(m_view->GetDB(), key);
if (NULL != url)
{
Net_GetUrlExitFunc *preExitFunc;
m_doneLoadingFunc = NULL;
m_doneLoading = FALSE;
if (m_justmakecompose)
{
preExitFunc = MSG_MessagePane::FinishComposeFor;
}
else
{
preExitFunc = MSG_MessagePane::FinishedLoading;
m_doneLoadingFunc = loadUrlExitFunction;
}
if (folder->GetType() == FOLDER_IMAPMAIL)
{
MSG_IMAPFolderInfoMail *imapFolder = (MSG_IMAPFolderInfoMail *) folder;
imapFolder->SetDownloadState(MSG_IMAPFolderInfoMail::kNoDownloadInProgress);
GetContext()->currentIMAPfolder = imapFolder;
}
if (m_callbacks && m_callbacks->AttachmentCount) {
m_callbacks->AttachmentCount(this, m_callbackclosure, 0, FALSE);
}
// if an imap folder is being loaded in this context, then this
// is the result of the user clicking on a message. We interrupt
// and load
XP_Bool shouldNotInterrupt = TRUE;
if (folder->GetType() == FOLDER_IMAPMAIL)
{
XP_Bool urlIsInMemoryCache = FALSE;
MSG_IMAPFolderInfoMail *imapFolder = folder->GetIMAPFolderInfoMail();
if (imapFolder->GetFolderLoadingContext() == GetContext())
shouldNotInterrupt = FALSE;
URL_Struct *url_s = NET_CreateURLStruct (url, NET_IsOffline() ? NET_SUPER_RELOAD : NET_DONT_RELOAD);
char extraFlag = 0; // figure out extra flag before we start loading offline messages, because that marks it read.
MSG_UrlQueue *q = NULL;
if (url_s)
{
if (!NET_IsOffline())
{
MSG_ViewIndex viewIndex = m_view->FindKey(key, FALSE);
if (viewIndex != MSG_VIEWINDEXNONE)
{
m_view->GetExtraFlag(viewIndex, &extraFlag);
}
}
url_s->allow_content_change = allow_content_change;
m_key = key;
q = MSG_UrlQueue::AddUrlToPane(url_s, preExitFunc, this, FALSE, NET_IsOffline() ? NET_SUPER_RELOAD : NET_DONT_RELOAD);
urlIsInMemoryCache = NET_IsURLInMemCache(url_s);
}
else
return eUNKNOWN;
XP_FREE(url);
// if this message was previously unread, and the message is offline or
// in memory cache, make sure the server knows it's read
if (!NET_IsOffline())
{
if (!(extraFlag & kIsRead))
{
if (urlIsInMemoryCache || (extraFlag & kOffline))
{
IDArray keysToFlag;
keysToFlag.Add(m_key);
imapFolder->StoreImapFlags(this, kImapMsgSeenFlag, TRUE, keysToFlag, q);
}
}
}
return eSUCCESS;
}
URL_Struct* ustruct = NET_CreateURLStruct(url, NET_IsOffline() ? NET_SUPER_RELOAD : NET_DONT_RELOAD);
ustruct->pre_exit_fn = preExitFunc;
GetURL(ustruct, TRUE); // TRUE will quietly work if any existing
// url is 'almost done'.
// clear any imap copy info so download will work
XP_FREE (url);
return eSUCCESS;
}
else
return eUNKNOWN; //PHP need better error code
}
void MSG_MessagePane::FinishedLoading(URL_Struct* ustruct, int status,
MWContext* context)
{
MSG_MessagePane* pane = (MSG_MessagePane*) ustruct->msg_pane;
XP_ASSERT(pane && pane->GetPaneType() == MSG_MESSAGEPANE);
if (!pane || pane->GetPaneType() != MSG_MESSAGEPANE) return;
if (pane->m_doneLoadingFunc) {
(*pane->m_doneLoadingFunc)(ustruct, status, context);
pane->m_doneLoadingFunc = NULL;
}
pane->m_doneLoading = TRUE;
if (pane->m_callbacks && pane->m_callbacks->AttachmentCount) {
pane->m_callbacks->AttachmentCount(pane, pane->m_callbackclosure,
MimeGetAttachmentCount(context),
TRUE);
if (context && MIME_HasAttachments(context))
(pane->m_view->GetDB())->MarkHasAttachments(pane->m_key, TRUE, (ChangeListener*) pane /* m_view ? */);
}
}
void MSG_MessagePane::DestroyPane(URL_Struct* ustruct, int /*status*/,
MWContext* /*context*/)
{
MSG_MessagePane* pane = (MSG_MessagePane*) ustruct->msg_pane;
XP_ASSERT(pane->GetPaneType() == MSG_MESSAGEPANE);
if (pane->GetPaneType() == MSG_MESSAGEPANE) {
delete pane;
}
}
void MSG_MessagePane::FinishComposeFor(URL_Struct* ustruct, int /*status*/,
MWContext* /*context*/)
{
MSG_MessagePane* pane = (MSG_MessagePane*) ustruct->msg_pane;
XP_ASSERT(pane->GetPaneType() == MSG_MESSAGEPANE);
if (pane->GetPaneType() == MSG_MESSAGEPANE) {
pane->UnregisterFromPaneList(); // Make sure that netlib won't decide
// to attach this pane to a URL,
// because this pane is about to go
// away.
if (pane->ComposeMessage(pane->m_composetype,
MSG_MessagePane::DestroyPane) != eSUCCESS) {
delete pane;
}
}
}
MsgERR
MSG_MessagePane::MakeComposeFor(MSG_FolderInfo* folder, MessageKey key,
MSG_CommandType type)
{
m_justmakecompose = TRUE;
m_composetype = type;
XP_Bool allow_content_change =
((type == MSG_ReplyToSender) ||
(type == MSG_ReplyToAll) ||
(type == MSG_ForwardMessageQuoted));
MsgERR status = LoadMessage(folder, key, NULL, allow_content_change); // forwarding requires message integrity
if (status != eSUCCESS) delete this;
return status;
}
void
MSG_MessagePane::ClearDerivedStrings()
{
FREEIF(m_mailToSenderUrl);
FREEIF(m_mailToAllUrl);
FREEIF(m_postReplyUrl);
FREEIF(m_postAndMailUrl);
FREEIF(m_displayedMessageSubject);
FREEIF(m_displayedMessageId);
}
static char*
msg_get_1522_header(MWContext *context, MimeHeaders *headers,
const char *name, XP_Bool all_p)
{
char *contents = MimeHeaders_get(headers, name, FALSE, all_p);
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
if (contents && *contents) {
char *converted = IntlDecodeMimePartIIStr(contents, INTL_GetCSIWinCSID(c),
FALSE);
if (converted) {
XP_FREE(contents);
contents = converted;
}
}
return contents;
}
void
MSG_MessagePane::ActivateReplyOptions(MimeHeaders* headers)
{
XP_Bool mdnNeeded = FALSE, isRead = FALSE;
// Since this gets called when the text appears in the pane, this is a
// great time to mark the message as read.
if (!m_justmakecompose) {
XP_Bool bMarkMessageRead = TRUE;
char *xref = MimeHeaders_get(headers, HEADER_XREF, FALSE, FALSE);
char *messageID = MimeHeaders_get(headers, HEADER_MESSAGE_ID, FALSE, FALSE);
if (messageID && m_view && m_view->GetDB())
{
MessageDB *db = m_view->GetDB();
// check if this is the same message-id as we think we should have for the
// current key.
DBMessageHdr *curHdr = db->GetDBHdrForKey(m_key);
db->IsMDNNeeded(m_key, &mdnNeeded);
db->IsRead(m_key, &isRead);
if (curHdr)
{
XPStringObj curKeyMessageID;
curHdr->GetMessageId(curKeyMessageID, db->GetDB());
char *strippedMsgID = (char *) XP_ALLOC(XP_STRLEN(messageID));
if (strippedMsgID)
{
MessageHdrStruct::StripMessageId(messageID, strippedMsgID, XP_STRLEN(messageID));
if (XP_STRCMP(strippedMsgID, curKeyMessageID))
{
char *newsgroups = MimeHeaders_get(headers, HEADER_NEWSGROUPS, FALSE, FALSE);
m_key = db->GetMessageKeyForID(messageID);
FE_PaneChanged(this, FALSE, MSG_PaneNotifyMessageLoaded, m_key);
// ### dmb should check if we've changed newsgroups!
FREEIF(newsgroups);
}
}
FREEIF(strippedMsgID);
delete curHdr;
}
if (m_folder && m_key == m_folder->GetLastMessageLoaded())
{
m_folder->SetLastMessageLoaded(MSG_MESSAGEKEYNONE);
bMarkMessageRead = FALSE;
}
}
if (bMarkMessageRead)
MarkMessageKeyRead(m_key, xref);
FREEIF(xref);
FREEIF(messageID);
}
char *host = 0;
char *to_and_cc = 0;
char *re_subject = 0;
char *new_refs = 0;
char *from = 0;
char *repl = 0;
char *subj = 0;
char *id = 0;
char *refs = 0;
char *to = 0;
char *cc = 0;
char *grps = 0;
char *foll = 0;
HG02087
ClearDerivedStrings();
if (headers) {
from = msg_get_1522_header(m_context, headers, HEADER_FROM, FALSE);
repl = msg_get_1522_header(m_context, headers, HEADER_REPLY_TO, FALSE);
subj = msg_get_1522_header(m_context, headers, HEADER_SUBJECT, FALSE);
to = msg_get_1522_header(m_context, headers, HEADER_TO, TRUE);
cc = msg_get_1522_header(m_context, headers, HEADER_CC, TRUE);
/* These headers should not be RFC-1522-decoded. */
grps = MimeHeaders_get(headers, HEADER_NEWSGROUPS, FALSE, TRUE);
foll = MimeHeaders_get(headers, HEADER_FOLLOWUP_TO, FALSE, TRUE);
id = MimeHeaders_get(headers, HEADER_MESSAGE_ID, FALSE, FALSE);
refs = MimeHeaders_get(headers, HEADER_REFERENCES, FALSE, TRUE);
if (repl) {
FREEIF(from);
from = repl;
repl = 0;
}
if (foll) {
FREEIF(grps);
grps = foll;
foll = 0;
}
HG82126
}
if (m_folder && m_folder->IsNews()) {
/* Decide whether cancelling this message should be allowed. */
m_cancellationAllowed = FALSE;
if (from) {
char *us = MSG_MakeFullAddress (NULL, FE_UsersMailAddress ());
char *them = MSG_ExtractRFC822AddressMailboxes(from);
m_cancellationAllowed = (us && them && !strcasecomp (us, them));
FREEIF(us);
FREEIF(them);
}
}
if (!headers) return;
if (subj) {
m_displayedMessageSubject = XP_STRDUP(subj);
}
if (id) {
m_displayedMessageId = XP_STRDUP(id);
}
host = ComputeNewshostArg();
if (to || cc) {
to_and_cc = (char *)
XP_ALLOC((to ? XP_STRLEN (to) : 0) +
(cc ? XP_STRLEN (cc) : 0) +
5);
if (!to_and_cc) goto FAIL;
*to_and_cc = 0;
if (to) XP_STRCPY(to_and_cc, to);
if (to && *to && cc && *cc) {
XP_STRCAT(to_and_cc, ", ");
}
if (cc) XP_STRCAT(to_and_cc, cc);
}
if (id || refs) {
int maxlen =
(id ? XP_STRLEN(id) : 0) +
(refs ? XP_STRLEN (refs) : 0) +
5;
new_refs = (char *) XP_ALLOC(maxlen);
if (!new_refs) goto FAIL;
*new_refs = 0;
if (refs) XP_STRCPY (new_refs, refs);
if (refs && id) {
XP_STRCAT (new_refs, " ");
}
if (id) XP_STRCAT (new_refs, id);
}
if (from || grps || to_and_cc) {
const char *s = subj;
if (s) msg_StripRE(&s, NULL);
re_subject = (char *) XP_ALLOC((s ? XP_STRLEN (s) : 0) + 10);
if (!re_subject) goto FAIL;
XP_STRCPY (re_subject, "Re: ");
if (s) XP_STRCAT (re_subject, s);
}
if (from) {
m_mailToSenderUrl = MakeMailto(from, 0, 0, re_subject, new_refs,
0, host, HG62212);
}
if (from || to_and_cc) {
m_mailToAllUrl = MakeMailto(from, to_and_cc, 0, re_subject,
new_refs, 0, host, HG91611);
}
if (grps) {
if (!strcasecomp(grps, "poster")) {
/* "Followup-to: poster" makes "post reply" act the same as
"reply to sender". */
if (m_mailToSenderUrl) {
m_postReplyUrl = XP_STRDUP(m_mailToSenderUrl);
}
} else {
m_postReplyUrl =
MakeMailto(0, 0, grps, re_subject, new_refs, 0, host, HG81762);
}
}
if (from || grps) {
if (grps && !strcasecomp(grps, "poster")) {
/* "Followup-to: poster" makes "post and mail reply" act the
same as "reply to sender". */
if (m_mailToSenderUrl) {
m_postAndMailUrl = XP_STRDUP(m_mailToSenderUrl);
}
} else {
m_postAndMailUrl = MakeMailto(from, 0, grps,
re_subject, new_refs, 0, host,
HG76255);
}
}
if (m_folder && !m_folder->IsNews() && mdnNeeded && !isRead)
{
// Constructor of MSG_ProcessMdnNeededState will send out
// an MDN report if needed.
MSG_ProcessMdnNeededState
processMdnNeeded(MSG_ProcessMdnNeededState::eDisplayed,
this,
m_folder,
m_key,
headers,
FALSE);
m_view->GetDB()->MarkMDNNeeded(m_key, FALSE);
m_view->GetDB()->MarkMDNSent(m_key, TRUE);
}
FAIL:
FREEIF(host);
FREEIF(to_and_cc);
FREEIF(re_subject);
FREEIF(new_refs);
FREEIF(from);
FREEIF(repl);
FREEIF(subj);
FREEIF(id);
FREEIF(refs);
FREEIF(to);
FREEIF(cc);
FREEIF(grps);
FREEIF(foll);
}
void
MSG_MessagePane::DoIncWithUIDL_s(URL_Struct *url, int status,
MWContext *context)
{
XP_ASSERT(url && url->msg_pane);
if (url && url->msg_pane) {
XP_ASSERT(url->msg_pane->GetPaneType() == MSG_MESSAGEPANE);
if (url->msg_pane->GetPaneType() == MSG_MESSAGEPANE) {
((MSG_MessagePane*)url->msg_pane)->DoIncWithUIDL(url, status,
context);
}
}
}
void
MSG_MessagePane::DoIncWithUIDL(URL_Struct * /*url*/, int /*status*/,
MWContext * /*context*/)
{
if (GetUIDL()) {
DoCommand(MSG_GetNewMail, NULL, 0);
}
}
void MSG_MessagePane::PrepareToIncUIDL(URL_Struct* url, const char* uidl)
{
XP_ASSERT(url && uidl);
if (!url || !uidl) return;
FREEIF(m_incUidl);
m_incUidl = XP_STRDUP(uidl);
if (url->msg_pane == NULL) url->msg_pane = this;
XP_ASSERT(url->msg_pane == this);
if (url && url->msg_pane == this && m_incUidl) {
url->pre_exit_fn = MSG_MessagePane::DoIncWithUIDL_s;
}
}
void
MSG_MessagePane::IncorporateShufflePartial(URL_Struct * /* url */, int status,
MWContext * /* context */)
{
FREEIF(m_incUidl);
if (status < 0)
return;
XP_ASSERT(m_view);
if (!m_view)
return;
MessageDB* db = m_view->GetDB();
XP_ASSERT(db);
if (!db)
return;
XP_ASSERT(m_folder);
if (!m_folder)
return;
MSG_FolderInfoMail* mailfolder = m_folder->GetMailFolderInfo();
XP_ASSERT(mailfolder);
if (!mailfolder)
return;
MessageKey oldkey = m_key;
MessageKey newkey = MSG_MESSAGEKEYNONE;
ListContext* list = NULL;
DBMessageHdr* hdr = NULL;
if (db->ListLast(&list, &hdr) == eSUCCESS) {
newkey = hdr->GetMessageKey();
db->ListDone(list);
}
if (newkey == MSG_MESSAGEKEYNONE)
return;
MSG_ThreadPane* threadpane = GetMaster()->FindThreadPaneNamed(mailfolder->GetPathname());
if (threadpane)
{
MessageDBView* threadview = threadpane->GetMsgView();
if (threadview)
{
MSG_ViewIndex index = threadview->FindViewIndex(oldkey);
if (index != MSG_VIEWINDEXNONE)
threadview->RemoveByIndex(index); // kill old msg line
//threadview->SetKeyByIndex(index, newkey);
}
}
hdr = db->GetDBHdrForKey(oldkey);
if (hdr) {
db->RemoveHeaderFromDB(hdr);
delete hdr;
}
LoadMessage(m_folder, newkey, NULL, TRUE);
// Ok, this is a little weird. The GetNewMail command rightly acquires
// the semaphore, and hopes that GetNewMailExit will be called to releaase
// the semaphore. But when incorporating the rest of a truncated message,
// the exit function is IncorporateShufflePartial, so release it here.
m_folder->ReleaseSemaphore (this);
mailfolder->SetGettingMail(FALSE);
}
char *
MSG_MessagePane::MakeForwardMessageUrl(XP_Bool quote_original)
{
char *url = 0;
char *host = ComputeNewshostArg();
MessageHdrStruct header;
char *fwd_subject = 0;
const char *id = 0;
char *attachment = 0;
HG22987
if (!m_view || m_key == MSG_MESSAGEKEYNONE ||
!m_folder || !m_view->GetDB()) {
return NULL;
}
if (m_view->GetDB()->GetMessageHdr(m_key, &header) != eSUCCESS) {
return NULL;
}
fwd_subject = CreateForwardSubject(&header);
id = header.m_messageId;
if (*id) {
attachment = m_folder->BuildUrl(m_view->GetDB(), m_key);
}
/* if we are quoting the original document, slip a cookie string in
at the beginning of the attachment field. This will be removed
before processing. */
if (quote_original && attachment) {
char * new_attachment = PR_smprintf(MSG_FORWARD_COOKIE "%s",
attachment);
FREEIF(attachment);
attachment = new_attachment;
}
url = MakeMailto(0, 0, 0, fwd_subject, 0, attachment, host, HG22296);
FREEIF(attachment);
FREEIF(host);
FREEIF(fwd_subject);
return url;
}
MsgERR
MSG_MessagePane::ComposeMessage(MSG_CommandType type, Net_GetUrlExitFunc* func)
{
char *host = 0;
char *url = 0;
XP_Bool free_url_p = FALSE;
URL_Struct *url_struct = 0;
MSG_FolderInfoNews *newsFolder;
MSG_PostDeliveryActionInfo *actionInfo = 0;
XP_Bool checkForHTML = FALSE;
HG22867
switch (type) {
case MSG_MailNew:
host = ComputeNewshostArg ();
HG32145
url = MakeMailto (0, 0, 0, 0, 0, 0, host, HG09990);
free_url_p = TRUE;
break;
case MSG_PostNew:
// ### tw - fix me - cast hack below
if (!m_folder->IsNews())
break;
newsFolder = (MSG_FolderInfoNews *) m_folder;
HG89520
host = ComputeNewshostArg ();
url = MakeMailto (0, 0, newsFolder->GetNewsgroupName(), 0, 0, 0,
host, HG02192);
free_url_p = TRUE;
break;
case MSG_ReplyToSender:
url = m_mailToSenderUrl;
checkForHTML = TRUE;
break;
case MSG_ReplyToAll:
url = m_mailToAllUrl;
checkForHTML = TRUE;
break;
case MSG_PostReply:
url = m_postReplyUrl;
checkForHTML = TRUE;
break;
case MSG_PostAndMailReply:
url = m_postAndMailUrl;
checkForHTML = TRUE;
break;
case MSG_ForwardMessageAttachment:
url = MakeForwardMessageUrl(FALSE);
free_url_p = TRUE;
break;
case MSG_ForwardMessageQuoted:
/* last flag indicates to quote the original message. */
url = MakeForwardMessageUrl(TRUE);
free_url_p = TRUE;
break;
default:
XP_ASSERT (0);
break;
}
FREEIF(host);
if (!url) {
url = "mailto:";
free_url_p = FALSE;
}
// This is the place to add a "&force-plain-text" to the URL, if we ever
// again wanted the feature of forcing a plaintext composition when you
// reply to a plaintext message.
if (checkForHTML) {
char* part = MimeGetHtmlPartURL(GetContext());
if (part) {
char* tmp = PR_smprintf("%s&html-part=%s", url, part);
if (tmp) {
if (free_url_p) XP_FREE(url);
url = tmp;
free_url_p = TRUE;
}
}
}
url_struct = NET_CreateURLStruct (url, NET_NORMAL_RELOAD);
if (free_url_p && url) {
XP_FREE(url);
}
if (!url_struct) return eOUT_OF_MEMORY;
/* Get a ride from url_struct->fe_data to attach
* post delivery action info */
if ( type == MSG_ReplyToSender ||
type == MSG_ReplyToAll ||
type == MSG_ForwardMessageAttachment ||
type == MSG_ForwardMessageQuoted ) {
actionInfo = new MSG_PostDeliveryActionInfo(m_folder);
if (actionInfo) {
actionInfo->m_msgKeyArray.Add(m_key);
XP_ASSERT( url_struct->fe_data == NULL );
switch (type) {
case MSG_ReplyToSender:
case MSG_ReplyToAll:
actionInfo->m_flags |= MSG_FLAG_REPLIED;
url_struct->fe_data = actionInfo;
/* actionInfo will be freed by CompositionPane
* when we close down the Composition Window.
*/
break;
case MSG_ForwardMessageAttachment:
case MSG_ForwardMessageQuoted:
actionInfo->m_flags |= MSG_FLAG_FORWARDED;
url_struct->fe_data = actionInfo;
/* actionInfo will be freed by CompositionPane
* when we close down the Composition Window.
*/
break;
default:
XP_FREE (actionInfo);
break;
}
}
}
url_struct->internal_url = TRUE;
url_struct->pre_exit_fn = func;
GetURL (url_struct, TRUE);
return 0;
}
MsgERR MSG_MessagePane::SetViewFromUrl (const char *url)
{
XP_ASSERT(!m_view);
XP_ASSERT(url);
return MessageDBView::OpenURL(url, GetMaster(),
ViewAny, &m_view, TRUE);
}
MsgERR MSG_MessagePane::DeleteMessage ()
{
MSG_ViewIndex index = m_view->FindViewIndex(m_key);
// if (index != MSG_VIEWINDEXNONE) // try using the base class method...see what happens.
// return TrashMessages(&index, 1);
MessageKey nextKey = MSG_MESSAGEKEYNONE;
IDArray *headerIds = new IDArray;
XP_Bool imapDeleteIsMoveToTrash = (m_folder) ? m_folder->DeleteIsMoveToTrash() : FALSE;
// allocate an array for the async machine
if (!headerIds)
{
XP_ASSERT(FALSE);
return eOUT_OF_MEMORY;
}
// fill in the header for the selected message
headerIds->Add(m_key);
// copy the messages into the trash folder
if (m_folder && (!(m_folder->GetFlags() & MSG_FOLDER_FLAG_TRASH) || !imapDeleteIsMoveToTrash))
{
XP_ASSERT (m_folder->IsMail());
MSG_FolderInfoMail *trashFolder = NULL;
const char *path = NULL;
if (m_folder->GetType() == FOLDER_MAIL)
{
path = m_master->GetPrefs()->MagicFolderName (MSG_FOLDER_FLAG_TRASH);
trashFolder = m_master->FindMailFolder (path, TRUE);
}
else
{
if (imapDeleteIsMoveToTrash)
{
MSG_IMAPFolderInfoMail *imapInfo = m_folder->GetIMAPFolderInfoMail();
if (imapInfo)
{
MSG_FolderInfo *foundTrash = MSG_GetTrashFolderForHost(imapInfo->GetIMAPHost());
trashFolder = foundTrash ? foundTrash->GetMailFolderInfo() : (MSG_FolderInfoMail *)NULL;
}
}
}
// Figure out what messate to load after this one is deleted
// MSG_FolderInfoMail::FinishCopyingMessages does the actual load.
if (index != MSG_VIEWINDEXNONE)
{
nextKey = m_view->GetAt(index + 1);
if (nextKey == MSG_MESSAGEKEYNONE) // if last msg, try getting previous
nextKey = m_view->GetAt(index - 1);
}
if (trashFolder)
m_folder->StartAsyncCopyMessagesInto (trashFolder,
this,
m_view->GetDB(),
headerIds,
1,
m_context,
NULL, // do not run in url queue
TRUE,
nextKey);
else if (!imapDeleteIsMoveToTrash && (m_folder->GetType() == FOLDER_IMAPMAIL) )
((MSG_IMAPFolderInfoMail *)m_folder)->DeleteSpecifiedMessages(this, *headerIds,nextKey);
//PHP impedance mismatch on error codes
}
return 0;
}
// static
void MSG_MessagePane::PostDeleteLoadExitFunction(URL_Struct *URL_s, int status, MWContext *)
{
if ((status == 0) && (URL_s->msg_pane->GetPaneType() == MSG_MESSAGEPANE))
{
MSG_MessagePane *msgPane = (MSG_MessagePane *) URL_s->msg_pane;
MessageKey loadKey = msgPane->GetPostDeleteLoadKey();
if (loadKey != MSG_MESSAGEKEYNONE)
{
msgPane->LoadMessage(msgPane->GetFolder(), loadKey, NULL, TRUE);
}
}
if (URL_s->msg_pane->GetPaneType() == MSG_MESSAGEPANE)
((MSG_MessagePane *) URL_s->msg_pane)->SetPostDeleteLoadKey(MSG_MESSAGEKEYNONE);
}
MsgERR MSG_MessagePane::DoCommand(MSG_CommandType command,
MSG_ViewIndex* indices, int32 numIndices)
{
// Note that nothing in here pays the slightest attention to indices or
// numIndices. On messagepanes, commands effect the displayed message
// and that's it.
// We'd better not be trying to do any commands at all if we don't even
// have a m_view.
XP_ASSERT(m_view);
if (!m_view) return eUNKNOWN;
if (command == MSG_ForwardMessage)
{
int32 forwardMsgMode = 0;
PREF_GetIntPref("mail.forward_message_mode", &forwardMsgMode);
if (forwardMsgMode == 1)
command = MSG_ForwardMessageQuoted;
else if (forwardMsgMode == 2)
command = MSG_ForwardMessageInline;
else
command = MSG_ForwardMessageAttachment;
}
MsgERR err = eSUCCESS;
switch (command)
{
case MSG_DeleteMessage:
{
// put this bug back in (deleting message from the trash) so that
// deleting a message from non-trash in stand-alone message will
// work for alpha.
// The real solution is to send a notification to the fe that
// a delete has finished.
err = DeleteMessage();
// MSG_ViewIndex idx = m_view->FindIndex(m_key);
// err = TrashMessages (&idx, 1);
}
break;
case MSG_PostNew:
case MSG_PostReply:
case MSG_PostAndMailReply:
case MSG_MailNew:
case MSG_ReplyToSender:
case MSG_ReplyToAll:
case MSG_ForwardMessageAttachment:
case MSG_ForwardMessageQuoted:
err = ComposeMessage(command, NULL);
break;
case MSG_AddSender:
AddURLToAddressBook(m_mailToSenderUrl);
break;
case MSG_AddAll:
AddURLToAddressBook(m_mailToAllUrl);
break;
case MSG_ShowAllHeaders:
case MSG_ShowSomeHeaders:
case MSG_ShowMicroHeaders:
// ### mwelch Changed from m/n prefs object accessor
// to prefs api (will tweak prefs object)
PREF_SetIntPref("mail.show_headers",
(int) (command - MSG_ShowMicroHeaders));
//GetMaster()->GetPrefs()->SetHeaderStyle (command);
err = LoadMessage (m_folder, m_key, NULL, TRUE); // is there an easier way to do this?
break;
case MSG_SaveMessagesAs:
case MSG_ForwardMessageInline:
case MSG_OpenMessageAsDraft:
{
MSG_ViewIndex index = m_view->FindViewIndex(m_key);
err = MSG_Pane::DoCommand(command, &index, 1);
}
break;
case MSG_AttachmentsInline:
case MSG_AttachmentsAsLinks:
{
MessageKey key = m_key;
PREF_SetBoolPref("mail.inline_attachments",
(command == MSG_AttachmentsInline));
LoadMessage (m_folder, MSG_MESSAGEKEYNONE, NULL, TRUE);
LoadMessage (m_folder, key, NULL, TRUE);
}
break;
case MSG_WrapLongLines:
{
MessageKey key = m_key;
XP_Bool newWrap = !GetPrefs()->GetWrapLongLines();
PREF_SetBoolPref("mail.wrap_long_lines", newWrap);
LoadMessage (m_folder, MSG_MESSAGEKEYNONE, NULL, TRUE);
LoadMessage (m_folder, key, NULL, TRUE);
}
break;
case MSG_Rot13Message:
{
m_rot13p = !m_rot13p;
MessageKey key = m_key;
LoadMessage (m_folder, MSG_MESSAGEKEYNONE, NULL, TRUE);
LoadMessage (m_folder, key, NULL, TRUE);
}
break;
case MSG_CompressFolder:
{
MSG_FolderInfoMail *mailFolder = GetFolder()->GetMailFolderInfo();
if (mailFolder)
err = CompressOneMailFolder(mailFolder);
else
XP_ASSERT(FALSE); // MSG_CommandStatus should have failed!
break;
}
default:
if (!indices)
{
MSG_ViewIndex index = m_view->FindViewIndex(m_key);
if (index != MSG_VIEWINDEXNONE )
{
indices = &index;
numIndices = 1;
}
}
err = MSG_Pane::DoCommand(command, indices, numIndices);
}
return err;
}
MsgERR MSG_MessagePane::AddToAddressBook(MSG_CommandType command, MSG_ViewIndex*indices, int32 numIndices, AB_ContainerInfo * destAB)
{
MsgERR status = 0;
MessageHdrStruct header;
status = m_view->GetDB()->GetMessageHdr(m_key, &header);
if (status != eSUCCESS)
return status;
switch(command)
{
case MSG_AddSender:
AB_AddSenderAB2(this, destAB, header.m_author, m_mailToSenderUrl);
break;
case MSG_AddAll:
AB_AddSenderAB2(this, destAB, header.m_author, m_mailToAllUrl);
break;
default:
XP_ASSERT(0);
}
return status;
}
MsgERR MSG_MessagePane::AddURLToAddressBook(char * url)
{
MessageHdrStruct header;
if (!url) return 0;
if (m_view->GetDB()->GetMessageHdr(m_key, &header) != eSUCCESS) {
return 0;
}
// assume add to personal address book
AB_AddSenderToAddBook(FE_GetAddressBook(this), GetContext(), header.m_author, url);
return 0;
}
MsgERR MSG_MessagePane::GetCommandStatus(MSG_CommandType command,
const MSG_ViewIndex* indices,
int32 numindices,
XP_Bool *selectable_pP,
MSG_COMMAND_CHECK_STATE *selected_p,
const char **display_stringP,
XP_Bool * plural_p)
{
MsgERR err = eSUCCESS;
const char *display_string = NULL;
XP_Bool selectable_p = TRUE;
XP_Bool showingMsg = (m_key != MSG_MESSAGEKEYNONE);
MSG_ViewIndex curIndex;
XP_Bool news_p = (m_folder && m_folder->IsNews() );
switch (command)
{
case MSG_CompressFolder:
{
selectable_p = m_folder && m_folder->IsMail();
break;
}
case MSG_DeleteMessageNoTrash:
case MSG_DeleteMessage:
{
MessageDB *db = (m_view) ? m_view->GetDB() : 0;
selectable_p = (db != NULL && NULL != db->GetMailDB() && showingMsg);
if (selectable_p)
selectable_p = (MSG_VIEWINDEXNONE != m_view->FindViewIndex(m_key));
// can't delete news msg
display_string = XP_GetString (MK_MSG_DELETE_MESSAGE);
if (selected_p)
*selected_p = MSG_NotUsed;
break;
}
case MSG_MarkMessagesRead:
{
MessageDB *db = (m_view) ? m_view->GetDB() : 0;
if (m_view && db)
{
XP_Bool isRead;
if (db->IsRead(m_view->GetAt(m_view->FindViewIndex(m_key)), &isRead) == eSUCCESS)
{
if (!isRead)
{
selectable_p = TRUE;
}
}
display_string = XP_GetString (MK_MSG_MARK_AS_READ);
if (selected_p)
*selected_p = MSG_NotUsed;
}
break;
}
case MSG_MarkMessagesUnread:
{
MessageDB *db = (m_view) ? m_view->GetDB() : 0;
if (m_view && db)
{
XP_Bool isRead;
if (db->IsRead(m_view->GetAt(m_view->FindViewIndex(m_key)), &isRead) == eSUCCESS)
{
if (isRead)
{
selectable_p = TRUE;
}
}
display_string = XP_GetString (MK_MSG_MARK_AS_UNREAD);
if (selected_p)
*selected_p = MSG_NotUsed;
}
break;
}
case MSG_AddSender:
display_string = XP_GetString(MK_MSG_ADD_SENDER_TO_ADDRESS_BOOK);
selectable_p = showingMsg;
break;
case MSG_AddAll:
display_string = XP_GetString(MK_MSG_ADD_ALL_TO_ADDRESS_BOOK);
selectable_p = showingMsg;
break;
case MSG_PostNew:
display_string = XP_GetString(MK_MSG_NEW_NEWS_MESSAGE);
selectable_p = news_p && m_folder->AllowsPosting();
break;
case MSG_PostReply:
display_string = XP_GetString(MK_MSG_POST_REPLY);
selectable_p = news_p && showingMsg && m_folder->AllowsPosting();
break;
case MSG_PostAndMailReply:
display_string = XP_GetString(MK_MSG_POST_MAIL_REPLY);
selectable_p = news_p && showingMsg && m_folder->AllowsPosting();
break;
case MSG_MailNew:
display_string = XP_GetString(MK_MSG_NEW_MAIL_MESSAGE);
break;
case MSG_ReplyToSender:
display_string = XP_GetString(MK_MSG_REPLY_TO_SENDER);
selectable_p = showingMsg;
break;
case MSG_ReplyToAll:
display_string = XP_GetString(MK_MSG_REPLY_TO_ALL);
selectable_p = showingMsg;
break;
case MSG_ForwardMessageQuoted:
display_string = XP_GetString(MK_MSG_FORWARD_QUOTED);
selectable_p = showingMsg;
break;
case MSG_ForwardMessage:
case MSG_ForwardMessageAttachment:
if (plural_p)
*plural_p = FALSE;
selectable_p = showingMsg;
display_string = XP_GetString(MK_MSG_FORWARD);
break;
case MSG_Rot13Message:
selectable_p = showingMsg;
if (selected_p)
*selected_p = (m_rot13p) ? MSG_Checked : MSG_Unchecked;
break;
case MSG_ShowAllHeaders:
case MSG_ShowSomeHeaders:
case MSG_ShowMicroHeaders:
if (selected_p)
*selected_p = (command == GetPrefs()->GetHeaderStyle() ?
MSG_Checked : MSG_Unchecked);
selectable_p = showingMsg;
break;
case MSG_AttachmentsInline:
if (selected_p)
*selected_p = (GetPrefs()->GetNoInlineAttachments() ?
MSG_Unchecked : MSG_Checked);
selectable_p = showingMsg;
break;
case MSG_AttachmentsAsLinks:
if (selected_p)
*selected_p = (GetPrefs()->GetNoInlineAttachments() ?
MSG_Checked : MSG_Unchecked);
selectable_p = showingMsg;
break;
case MSG_WrapLongLines:
if (selected_p)
*selected_p = (GetPrefs()->GetWrapLongLines() ?
MSG_Checked : MSG_Unchecked);
selectable_p = showingMsg;
break;
default:
if (indices == NULL && m_view)
{
curIndex = m_view->FindViewIndex(m_key);
indices = &curIndex;
numindices = 1;
}
return MSG_Pane::GetCommandStatus(command, indices, numindices,
selectable_pP, selected_p,
display_stringP, plural_p);
}
if (display_stringP)
*display_stringP = display_string;
if (selectable_pP)
*selectable_pP = selectable_p;
return err;
}
void
MSG_MessagePane::GetCurMessage(MSG_FolderInfo** folder, MessageKey* key,
MSG_ViewIndex *index)
{
MessageKey curKey = (m_folder) ? m_key : MSG_MESSAGEKEYNONE;
if (folder) *folder = m_folder;
if (key) *key = curKey;
if (index)
{
*index = (m_view && curKey != MSG_MESSAGEKEYNONE)
? m_view->FindViewIndex(curKey) : MSG_VIEWINDEXNONE;
}
}
int
MSG_MessagePane::GetViewedAttachments(MSG_AttachmentData** data,
XP_Bool* iscomplete)
{
if (iscomplete) *iscomplete = m_doneLoading;
return MimeGetAttachmentList(GetContext(), data);
}
void
MSG_MessagePane::FreeAttachmentList(MSG_AttachmentData* data)
{
MimeFreeAttachmentList(data);
}
HG82821
XP_Bool MSG_MessagePane::GetThreadLineByKey(MessageKey key, MSG_MessageLine* data)
{
XP_ASSERT(m_view);
if (!m_view)
return FALSE;
// XP_ASSERT(key == m_key); //When we load new msg ,this isn't be true
int numlisted = -1;
MsgERR status = m_view->ListThreadsShort(&key, 1, data, &numlisted);
return (status == 0 && numlisted == 1);
}
XP_Bool MSG_MessagePane::ShouldRot13Message()
{
return m_rot13p;
}
/* This function opens a message and returns a handle to that message in the
* msg_ptr pointer.
*
* The message handle will be passed to MSG_ReadMessage and MSG_CloseMessage
* to read data and to close the message
*
* Return values: return a negative return value listed in merrors.h to
* signify an error. return zero (0) on success.
*
* !Set message_ptr to NULL on error!
*/
int
MSG_MessagePane::OpenMessageSock(const char *folder_name,
const char *msg_id, int32 msgnum,
void *folder_ptr, void **message_ptr,
int32 *content_length)
{
if (!m_view)
InitializeFolderAndView (folder_name);
if (msgnum == MSG_MESSAGEKEYNONE && m_view)
{
MailMessageHdr *hdr = (MailMessageHdr*) m_view->GetDB()->GetDBMessageHdrForID(msg_id);
if (hdr)
msgnum = hdr->GetMessageKey();
}
if ( msgnum != MSG_MESSAGEKEYNONE ) {
m_key = msgnum;
InitializeFolderAndView (folder_name);
FE_PaneChanged(this, FALSE, MSG_PaneNotifyMessageLoaded, msgnum);
}
return MSG_Pane::OpenMessageSock ( folder_name, msg_id, msgnum,
folder_ptr, message_ptr,
content_length );
}
/* Partial messages
*/
char *
MSG_MessagePane::GeneratePartialMessageBlurb(URL_Struct *url,
void * /*closure*/,
MimeHeaders *headers)
{
char *stuff = 0;
char *new_url = 0, *quoted = 0;
unsigned long flags = 0;
char dummy = 0;
char *uidl = 0, *xmoz = 0;
/* The message is partial if it has an X-UIDL header field, and it has
an X-Mozilla-Status header field which contains the `partial' bit.
*/
uidl = MimeHeaders_get(headers, HEADER_X_UIDL, FALSE, FALSE);
if (!uidl) goto DONE;
xmoz = MimeHeaders_get(headers, HEADER_X_MOZILLA_STATUS, FALSE, FALSE);
if (!xmoz) goto DONE;
if (1 != sscanf (xmoz, " %lx %c", &flags, &dummy)) goto DONE;
if (! (flags & MSG_FLAG_PARTIAL)) goto DONE;
quoted = NET_Escape (uidl, URL_XALPHAS);
if (!quoted) goto DONE;
FREEIF(uidl);
new_url = (char *) XP_ALLOC (XP_STRLEN (url->address) +
XP_STRLEN (quoted) + 20);
if (!new_url) goto DONE;
XP_STRCPY (new_url, url->address);
XP_ASSERT (XP_STRCHR (new_url, '?'));
if (XP_STRCHR (new_url, '?')) {
XP_STRCAT (new_url, "&uidl=");
} else {
XP_STRCAT (new_url, "?uidl=");
}
XP_STRCAT (new_url, quoted);
FREEIF(quoted);
stuff = PR_smprintf ("%s%s%s%s",
XP_GetString(MK_MSG_PARTIAL_MSG_FMT_1),
XP_GetString(MK_MSG_PARTIAL_MSG_FMT_2),
new_url,
XP_GetString(MK_MSG_PARTIAL_MSG_FMT_3));
DONE:
FREEIF(new_url);
FREEIF(quoted);
FREEIF(uidl);
FREEIF(xmoz);
return stuff;
}
URL_Struct * MSG_MessagePane::ConstructUrlForMessage(MessageKey key)
{
if (key == MSG_MESSAGEKEYNONE)
key = m_key;
return MSG_Pane::ConstructUrlForMessage(key);
}
MsgERR
MSG_MessagePane::LoadFolder(MSG_FolderInfo* f)
{
char *url = NULL;
XP_Bool finishedLoadingFolder = FALSE; // are we finished loading folder?
XP_StatStruct folderst;
if (f == m_folder) return 0;
m_folder = f;
if (!f)
return CloseView();
XP_ASSERT(f->GetType() == FOLDER_MAIL ||
f->GetType() == FOLDER_NEWSGROUP ||
f->GetType() == FOLDER_IMAPMAIL ||
f->GetType() == FOLDER_CATEGORYCONTAINER);
// we need to abort any current background parsing.
if (m_folder != NULL)
msg_InterruptContext(GetContext(), TRUE);
if (m_folder && m_folder->UserNeedsToAuthenticateForFolder(FALSE) && m_master->PromptForHostPassword(GetContext(), m_folder) != 0)
return 0;
CloseView();
url = f->BuildUrl(NULL, MSG_MESSAGEKEYNONE);
ViewType typeOfView = ViewAny;
MsgERR status = MessageDBView::OpenURL(url, GetMaster(),
typeOfView, &m_view, FALSE);
// fire off the IMAP url to update this folder, if it is IMAP
if ((f->GetType() == FOLDER_IMAPMAIL) && (status == eSUCCESS))
{
MSG_IMAPFolderInfoMail *imapFolder = f->GetIMAPFolderInfoMail();
if (imapFolder)
{
imapFolder->StartUpdateOfNewlySelectedFolder(this,TRUE,NULL);
}
else
{
XP_ASSERT(FALSE);
}
}
if (f->GetType() == FOLDER_MAIL && status != eSUCCESS /*== eOldSummaryFile*/)
{
MailDB *mailDB;
XP_Trace("blowing away old summary file\n");
const char* pathname = ((MSG_FolderInfoMail*) f)->GetPathname();
if (!XP_Stat(pathname, &folderst, xpMailFolderSummary) && XP_FileRemove(pathname, xpMailFolderSummary) != 0)
{
status = MK_MSG_CANT_OPEN;
}
else
{
MSG_Master *mailMaster = GetMaster();
URL_Struct *url_struct;
url_struct = NET_CreateURLStruct(url, NET_DONT_RELOAD);
status = MailDB::Open(pathname, TRUE, &mailDB, TRUE);
if (mailDB != NULL && (status == eSUCCESS || status == eNoSummaryFile))
{
status = MessageDBView::OpenViewOnDB(mailDB,
ViewAny, &m_view);
mailDB->Close(); // decrement ref count.
}
if (m_view != NULL && m_view->GetDB() != NULL)
{
ParseMailboxState *parseMailboxState = new ParseMailboxState(pathname);
parseMailboxState->SetView(m_view);
parseMailboxState->SetPane(this);
parseMailboxState->SetIncrementalUpdate(FALSE);
parseMailboxState->SetMaster(mailMaster);
parseMailboxState->SetDB(m_view->GetDB()->GetMailDB());
parseMailboxState->SetContext(GetContext());
parseMailboxState->SetFolder(m_folder);
((MSG_FolderInfoMail*)f)->SetParseMailboxState(parseMailboxState);
// fire off url to create summary file from mailbox - will work in background
GetURL(url_struct, FALSE);
}
}
}
else if (f->IsNews())
{
MSG_FolderInfoNews *newsFolder = f->GetNewsFolderInfo();
XP_ASSERT(newsFolder);
const char* groupname = newsFolder->GetNewsgroupName();
if (status != eSUCCESS)
{
if (status == eErrorOpeningDB || status == eOldSummaryFile) // corrupt database or out of date
{
NewsGroupDB *newsDB;
const char *dbFileName = newsFolder->GetXPDBFileName();
if (dbFileName != NULL)
XP_FileRemove(dbFileName, xpXoverCache);
status = NewsGroupDB::Open(url, GetMaster(), &newsDB);
if (status == eSUCCESS)
{
status = MessageDBView::OpenViewOnDB(newsDB,
ViewAny, &m_view);
newsDB->Close();
}
}
}
if (status == eSUCCESS) // get new articles from server.
{
MSG_Master *master = GetMaster();
URL_Struct *url_struct;
url_struct = NET_CreateURLStruct(url, NET_DONT_RELOAD);
ListNewsGroupState * listState = new ListNewsGroupState(url, groupname, this);
listState->SetMaster(master);
listState->SetView(m_view);
newsFolder->SetListNewsGroupState(listState);
int status = GetURL(url_struct, FALSE);
if (status == MK_INTERRUPTED || status == MK_OFFLINE)
{
if (newsFolder->GetListNewsGroupState()) // FinishXOver not called...
{
delete listState;
newsFolder->SetListNewsGroupState(NULL);
}
StartingUpdate(MSG_NotifyAll, 0, 0);
EndingUpdate(MSG_NotifyAll, 0, 0);
finishedLoadingFolder = TRUE;
}
}
else if (status == eBuildViewInBackground)
{
status = ListThreads();
}
}
else if (f->GetType() == FOLDER_IMAPMAIL && status != eSUCCESS)
{
const char* pathname = ((MSG_FolderInfoMail*) f)->GetPathname();
XP_FileRemove(pathname, xpMailFolderSummary);
}
else if (status == eSUCCESS)
{
finishedLoadingFolder = TRUE;
}
if (status == eSUCCESS)
{
m_view->Add(GetListener());
}
// imap folders loads are asynchronous
// this notification will happen in
// MSG_IMAPFolderInfoMail::AllFolderHeadersAreDownloaded
if (finishedLoadingFolder && (f->GetType() != FOLDER_IMAPMAIL))
{
FE_PaneChanged(this, TRUE, MSG_PaneNotifyFolderLoaded, (uint32) f);
}
if (m_folder)
m_folder->SummaryChanged(); // for Will - so thread pane can display counts.
XP_FREE(url);
return status;
}