1998-06-22 22:39:40 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1998-06-22 22:39:40 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1998-06-22 22:39:40 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1998-06-22 22:39:40 +00:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 03:43:54 +00:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
1998-06-22 22:39:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|