pjs/lib/libmsg/msgmast.cpp

2402 строки
68 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.
*/
#define FORCE_PR_LOG /* Allow logging in the release build */
#include "rosetta.h"
#include "msg.h"
#include "errcode.h"
#include "msgmast.h"
#include "msgprefs.h"
#include "msgfinfo.h"
#include "msgfpane.h"
#include "msgtpane.h"
#include "hosttbl.h"
#include "newshost.h"
#include "prsembst.h"
#include "listngst.h"
#include "newsdb.h"
#include "maildb.h"
#include "prtime.h"
#include "msgbgcln.h"
#include "prefapi.h"
#include "rosetta.h"
#include HG99877
#include "msgdwnof.h"
#include "imapoff.h"
#include "msgurlq.h"
#include "xpgetstr.h"
#include "msgfcach.h"
#include "prlog.h"
#include "pmsgsrch.h"
#include "msgccach.h"
#include "imaphost.h"
#include "msgimap.h"
#include "nslocks.h"
#include "pw_public.h"
extern "C" {
extern int MK_OUT_OF_MEMORY;
extern int MK_MSG_SET_HTML_NEWSGROUP_HEIRARCHY_CONFIRM;
extern int MK_MSG_FOLDER_ALREADY_EXISTS;
extern int MK_MSG_INBOX_L10N_NAME;
extern int MK_IMAP_UPGRADE_WAIT_WHILE_UPGRADE;
extern int MK_IMAP_UPGRADE_PROMPT_QUESTION;
extern int MK_IMAP_UPGRADE_CUSTOM;
extern int MK_POP3_USERNAME_UNDEFINED;
extern int XP_PASSWORD_FOR_POP3_USER;
extern int XP_MSG_CACHED_PASSWORD_NOT_MATCHED;
extern int XP_MSG_PASSWORD_FAILED;
extern int MK_POP3_PASSWORD_UNDEFINED;
}
#ifndef NSPR20
PR_LOG_DEFINE(IMAP);
#else
PRLogModuleInfo *IMAP;
#endif
MSG_Master::MSG_Master(MSG_Prefs* prefs)
{
XP_Bool purgeBodiesByAge;
int32 purgeMethod;
int32 daysToKeepHdrs;
int32 headersToKeep;
int32 daysToKeepBodies;
PREF_GetBoolPref("news.enabled",&m_collabraEnabled);
m_prefs = prefs;
m_folderTree = NULL;
m_IMAPfoldersBuilt = FALSE;
m_upgradingToIMAPSubscription = FALSE;
if (m_collabraEnabled)
m_hosttable = msg_HostTable::Create(this);
else
m_hosttable = NULL;
m_rulesSemaphoreHolder = NULL;
m_editHeadersSemaphoreHolder = NULL;
m_mailfolders = NULL;
m_imapfolders = NULL;
m_parseMailboxState = NULL;
m_userAuthenticated = FALSE;
m_localFoldersAuthenticated = FALSE;
m_prefs->AddNotify(this);
m_purgeHdrPref = new MSG_PurgeInfo;
m_purgeArtPref = new MSG_PurgeInfo;
PREF_GetIntPref("mail.purge_threshhold", &m_purgeThreshhold);
PREF_GetIntPref("news.keep.method", &purgeMethod);
PREF_GetIntPref("news.keep.days", &daysToKeepHdrs); // days
PREF_GetIntPref("news.keep.count", &headersToKeep); //keep x newest messages
PREF_GetBoolPref("news.keep.only_unread", &m_purgeHdrPref->m_unreadOnly);
PREF_GetBoolPref("news.remove_bodies.by_age", &purgeBodiesByAge);
PREF_GetIntPref("news.remove_bodies.days", &daysToKeepBodies);
PREF_GetBoolPref("mail.password_protect_local_cache" , &m_passwordProtectCache);
m_purgeHdrPref->m_purgeBy = (MSG_PurgeByPreferences) purgeMethod;
m_purgeHdrPref->m_daysToKeep = daysToKeepHdrs;
m_purgeHdrPref->m_numHeadersToKeep = headersToKeep;
m_purgeArtPref->m_purgeBy = (purgeBodiesByAge) ? MSG_PurgeByAge : MSG_PurgeNone;
m_mailAccountUrl = NULL;
m_cachedConnectionList = NULL;
m_playingBackOfflineOps = FALSE;
m_progressWindow = NULL;
m_imapUpgradeBeginPane = NULL;
m_upgradingToIMAPSubscription = FALSE;
#ifndef NSPR20
PR_LogInit(&IMAPLog);
#else
IMAP = PR_NewLogModule("IMAP");
#endif
// on the mac, use this java script preference
// as an alternate to setenv
XP_Bool imapIOlogging;
PREF_GetBoolPref("imap.io.mac.logging", &imapIOlogging);
if (imapIOlogging)
IMAP->level = PR_LOG_ALWAYS;
}
MSG_Master::~MSG_Master()
{
m_prefs->RemoveNotify(this);
MSG_FolderCache cache;
cache.WriteToDisk (m_folderTree);
delete m_hosttable;
delete m_folderTree;
delete m_purgeHdrPref;
delete m_purgeArtPref;
XP_FREEIF(m_mailAccountUrl);
delete m_cachedConnectionList;
delete m_imapHostTable;
}
// See if there is a previous connection cached for us, if so, then return it.
// If there is no connection, allow them to make
// a connection since it will be the first one, somebody has got to start one.
TNavigatorImapConnection* MSG_Master::UnCacheImapConnection(const char *host, const char *folderName)
{
if (m_cachedConnectionList) // Someone has made a connection at least once
{
if (folderName)
{
MSG_IMAPFolderInfoMail *folder = (folderName) ? FindImapMailFolder(host, folderName, NULL, FALSE) : 0;
if (folder)
return (m_cachedConnectionList->RemoveConnection(folder, folder->GetIMAPHost()));
}
else
return m_cachedConnectionList->RemoveConnection(NULL, GetIMAPHost(host));
}
else
{
m_cachedConnectionList = new MSG_CachedConnectionList; // mark a connection has been created
}
return NULL; // No connections have been made, you are the first dude
}
XP_Bool MSG_Master::HasCachedConnection(MSG_IMAPFolderInfoMail *folder)
{
int cacheIndex;
if (m_cachedConnectionList) // Someone has made a connection at least once
return (m_cachedConnectionList->HasConnection(folder, folder->GetIMAPHost(), cacheIndex));
else
return FALSE;
}
void MSG_Master::CloseCachedImapConnections()
{
if (m_cachedConnectionList)
m_cachedConnectionList->CloseAllConnections();
}
XP_Bool MSG_Master::TryToCacheImapConnection(TNavigatorImapConnection *connection, const char *host, const char *folderName)
{
XP_Bool wasCached = FALSE;
if (!m_cachedConnectionList)
m_cachedConnectionList = new MSG_CachedConnectionList;
if (m_cachedConnectionList)
{
MSG_FolderInfo *folder = (folderName) ? FindImapMailFolder(host, folderName, NULL, FALSE) : 0;
wasCached = m_cachedConnectionList->AddConnection(connection, folder, GetIMAPHost(host));
}
#ifdef DEBUG_bienvenu
XP_Trace("trying to uncache %s result = %s\n", folderName, (wasCached) ? "TRUE" : "FALSE");
#endif
return wasCached;
}
void MSG_Master::ImapFolderClosed(MSG_FolderInfo *folder)
{
if (m_cachedConnectionList)
m_cachedConnectionList->FolderClosed(folder);
}
void
MSG_Master::SetFirstPane(MSG_Pane* pane)
{
m_firstpane = pane;
}
MSG_Pane*
MSG_Master::GetFirstPane()
{
return m_firstpane;
}
void MSG_Master::NotifyPrefsChange(NotifyCode code)
{
// km - There is no way to get a notification from anybody but the MSG_Prefs
// object. Therefore hacking NET_Setpopusername (name wrong) cannot work without
// also adding to MSG_Prefs
if (HG24326 (m_prefs->GetMailServerIsIMAP4()))
{
// if we're using IMAP
// then we should clear the connection cache and info here
IMAP_ResetAnyCachedConnectionInfo();
// if there is any existing cached imap connection, tell it to die
CloseCachedImapConnections();
}
else if (m_firstpane && ((code == MailServerType) || (code == PopHost)))
{
// biff state is unknown now
FE_UpdateBiff(MSG_BIFF_Unknown);
// if the new mail server is IMAP, then delete any previous
// imap thread and message panes
if (m_prefs->GetMailServerIsIMAP4())
{
// mwelch will add code here for pane deletion?
}
// remove any existing imap folders from the folders from the folder pane.
if (m_imapfolders)
BroadcastFolderDeleted (m_imapfolders);
// leak m_imapfolders. Until the closure of thread panes and
// message panes works, there will be dangling references
// in the front ends.
if (m_imapfolders && m_folderTree)
{
m_folderTree->RemoveSubFolder(m_imapfolders);
m_imapfolders = NULL;
}
// if the new server is imap, populate the folder pane.
if (m_prefs->GetMailServerIsIMAP4())
{
// BuildIMAPFolderTree will flag the IMAP inbox with
// MSG_FOLDER_FLAG_INBOX. Remove this flag from any pop
// mailbox that has it.
MSG_FolderInfo *offlineInbox = NULL;
if (GetLocalMailFolderTree()->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, &offlineInbox, 1))
{
XP_ASSERT(offlineInbox);
offlineInbox->ClearFlag(MSG_FOLDER_FLAG_INBOX);
BroadcastFolderChanged(offlineInbox);
}
// start fresh
IMAP_ResetAnyCachedConnectionInfo();
// build the imap folder tree
m_imapfolders =
MSG_IMAPFolderInfoMail::BuildIMAPFolderTree(
this, // master is used by libnet
1,
m_folderTree->GetSubFolders()); // parent of imap folders
// add them to the folder pane
if (m_imapfolders)
{
m_IMAPfoldersBuilt = TRUE;
BroadcastFolderAdded (m_imapfolders);
}
}
else
{
if (m_IMAPfoldersBuilt)
{
// this was a switch from imap to pop. Flag the pop inbox
MSG_FolderInfoMail *offlineInbox = FindMagicMailFolder(MSG_FOLDER_FLAG_INBOX, TRUE);
if (offlineInbox)
{
offlineInbox->SetFlag(MSG_FOLDER_FLAG_INBOX);
BroadcastFolderChanged (offlineInbox);
}
}
m_IMAPfoldersBuilt = FALSE;
m_imapfolders = NULL;
}
// if there is any existing cached imap connection, tell it to die
CloseCachedImapConnections();
}
else if (code == ChangeIMAPDeleteModel)
{
IMAP_ResetAnyCachedConnectionInfo();
CloseCachedImapConnections();
}
}
int32
MSG_Master::GetFolderChildren(MSG_FolderInfo* folder,
MSG_FolderInfo** result,
int32 resultsize)
{
if (folder == NULL)
folder = GetFolderTree();
int32 num = folder->GetNumSubFolders();
int32 numResults = 0;
if (result && resultsize > num)
resultsize = num;
for (int i=0 ; i<num ; i++)
{
MSG_FolderInfo *child = folder->GetSubFolder(i);
if (child->CanBeInFolderPane())
{
if (result)
result[numResults] = child;
numResults++;
}
}
return numResults;
}
int32
MSG_Master::GetFoldersWithFlag(uint32 flags, MSG_FolderInfo** result,
int32 resultsize)
{
return GetFolderTree()->GetFoldersWithFlag(flags, result, resultsize);
}
XP_Bool
MSG_Master::GetFolderLineById(MSG_FolderInfo* folder,
MSG_FolderLine* data) {
XP_BZERO (data, sizeof(*data));
XP_ASSERT(folder);
if (!folder) return FALSE;
data->level = folder->GetDepth();
data->name = folder->GetName();
data->prettyName = folder->GetPrettyName();
data->flags = folder->GetFlags();
data->prefFlags = folder->GetFolderPrefFlags();
data->unseen = folder->GetNumUnread() + folder->GetNumPendingUnread();
data->total = folder->GetTotalMessages() + folder->GetNumPendingTotalMessages();
data->deepUnseen = folder->GetNumUnread(TRUE /*deep?*/) +
folder->GetNumPendingUnread(TRUE /*deep?*/);
data->deepTotal = folder->GetTotalMessages(TRUE /*deep?*/) +
folder->GetNumPendingTotalMessages(TRUE /*deep?*/);
data->id = folder;
data->numChildren = folder->GetNumSubFoldersToDisplay();
data->deletedBytes = folder->GetExpungedBytesCount();
return TRUE;
}
void MSG_Master::BroadcastFolderChanged(MSG_FolderInfo *folderInfo)
{
MSG_Pane *pane;
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane())
{
if (pane->GetPaneType() == MSG_FOLDERPANE)
{
MSG_FolderPane* folderPane = (MSG_FolderPane*) pane;
MSG_FolderInfo *parent = folderInfo;
while (parent)
{
// since we're not rolling up container counts, don't invalidate, since it slows down the mac.
if (parent->GetType() != FOLDER_CONTAINERONLY)
folderPane->OnFolderChanged (parent);
parent = m_folderTree->FindParentOf(parent);
}
}
else if (pane->GetPaneType() == MSG_THREADPANE)
{
pane->OnFolderChanged (folderInfo);
}
}
}
void MSG_Master::BroadcastFolderDeleted (MSG_FolderInfo *folderInfo)
{
MSG_Pane *pane;
XP_ASSERT (folderInfo);
if (!folderInfo)
return;
MSG_IMAPFolderInfoMail *imapFolder = folderInfo->GetIMAPFolderInfoMail();
if (imapFolder && m_cachedConnectionList)
m_cachedConnectionList->FolderDeleted(folderInfo);
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane())
pane->OnFolderDeleted (folderInfo);
}
void MSG_Master::BroadcastFolderAdded (MSG_FolderInfo *folder, MSG_Pane *instigator)
{
MSG_Pane *pane;
XP_ASSERT(folder);
if (!folder)
return;
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane())
pane->OnFolderAdded (folder, instigator);
}
void MSG_Master::BroadcastFolderKeysAreInvalid (MSG_FolderInfo *folder)
{
MSG_Pane *pane;
XP_ASSERT(folder);
if (!folder)
return;
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane())
pane->OnFolderKeysAreInvalid (folder);
}
MSG_Pane *MSG_Master::FindFirstPaneOfType(MSG_PaneType type)
{
return FindNextPaneOfType(GetFirstPane(), type);
}
MSG_Pane *MSG_Master::FindNextPaneOfType(MSG_Pane *startHere, MSG_PaneType type)
{
MSG_Pane *pane;
for (pane = startHere; pane != NULL; pane = pane->GetNextPane())
{
if (pane->GetPaneType() == type)
return pane;
}
return NULL;
}
MSG_Pane *MSG_Master::FindPaneOfType(MSG_FolderInfo *id, MSG_PaneType type)
{
MSG_Pane *pane;
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane())
{
if (pane->GetPaneType() == type || type == MSG_ANYPANE)
{
MSG_FolderInfo *paneFolder = pane->GetFolder();
if (paneFolder == id)
return pane;
}
}
return NULL;
}
MSG_Pane *MSG_Master::FindPaneOfType (const char *url, MSG_PaneType type)
{
char *path = NET_ParseURL (url, GET_PATH_PART);
if (path)
{
MSG_FolderInfo *folder = FindMailFolder (path, FALSE /*createIfMissing*/);
FREEIF(path);
if (folder)
return FindPaneOfType (folder, type);
}
return NULL;
}
void MSG_Master::ClearParseMailboxState()
{
if (m_parseMailboxState != NULL)
{
delete m_parseMailboxState;
m_parseMailboxState = NULL;
}
}
void MSG_Master::ClearParseMailboxState(const char *folderName)
{
MSG_FolderInfoMail *mailFolder = FindMailFolder(folderName, FALSE);
ParseMailboxState *parser = (mailFolder) ? mailFolder->GetParseMailboxState() : 0;
if (parser != NULL)
{
delete parser;
mailFolder->SetParseMailboxState(NULL);
}
}
void MSG_Master::ClearListNewsGroupState(MSG_NewsHost* host,
const char *newsGroupName)
{
MSG_FolderInfoNews *newsFolder = FindNewsFolder(host, newsGroupName);
ListNewsGroupState *state = (newsFolder) ? newsFolder->GetListNewsGroupState() : 0;
if (state != NULL)
{
delete state;
newsFolder->SetListNewsGroupState(NULL);
}
}
XP_Bool MSG_Master::FolderTreeExists ()
{
return m_folderTree != NULL;
}
MSG_FolderInfo *MSG_Master::GetFolderTree()
{
if (!m_folderTree)
{
char* dir = XP_STRDUP(GetPrefs()->GetFolderDirectory());
m_folderTree = new MSG_FolderInfoContainer("Parent of mail and news", 0, NULL);
MSG_FolderArray *parentFolder = m_folderTree->GetSubFolders();
m_folderCache = new MSG_FolderCache ();
if (m_folderCache)
m_folderCache->ReadFromDisk ();
if (GetPrefs()->GetMailServerIsIMAP4() &&
!m_IMAPfoldersBuilt)
{
// ###tw This probably needs revisiting now that news folders are
// crammed in here too.
m_imapfolders =
MSG_IMAPFolderInfoMail::BuildIMAPFolderTree(
this, // master is used by libnet
1,
parentFolder);
m_IMAPfoldersBuilt = TRUE;
}
m_mailfolders = MSG_FolderInfoMail::BuildFolderTree(dir, 1, parentFolder, this);
// Create the magic folders on startup
///// DRAFTS //////
XP_Bool imapDrafts = FALSE;
char *draftsLocation = NULL;
PREF_CopyCharPref("mail.default_drafts", &draftsLocation);
imapDrafts = (draftsLocation ?
(NET_URL_Type(draftsLocation) == IMAP_TYPE_URL) :
FALSE);
if (imapDrafts)
FindMagicMailFolder(MSG_FOLDER_FLAG_DRAFTS, FALSE);
else
FindMagicMailFolder(MSG_FOLDER_FLAG_DRAFTS, TRUE);
///// TEMPLATES //////
XP_Bool imapTemplates = FALSE;
char *templatesLocation = NULL;
PREF_CopyCharPref("mail.default_templates", &templatesLocation);
imapTemplates = (templatesLocation ? (NET_URL_Type(templatesLocation) == IMAP_TYPE_URL) : FALSE);
if (imapTemplates)
FindMagicMailFolder(MSG_FOLDER_FLAG_TEMPLATES, FALSE);
else
FindMagicMailFolder(MSG_FOLDER_FLAG_TEMPLATES, TRUE);
///// TRASH //////
FindMagicMailFolder(MSG_FOLDER_FLAG_TRASH, TRUE);
///// SENT //////
FindMagicMailFolder(MSG_FOLDER_FLAG_SENTMAIL, TRUE);
///// UNSENT (OUTBOX) //////
MSG_SetQueueFolderName(QUEUE_FOLDER_NAME);
MSG_FolderInfo *q = FindMagicMailFolder(MSG_FOLDER_FLAG_QUEUE, FALSE); // see if we have "Unsent Messages"
if (!q) {
MSG_SetQueueFolderName(QUEUE_FOLDER_NAME_OLD);
q = FindMagicMailFolder(MSG_FOLDER_FLAG_QUEUE, FALSE); // if not, see if we have "Outbox"
if (!q)
{
MSG_SetQueueFolderName(QUEUE_FOLDER_NAME);
FindMagicMailFolder(MSG_FOLDER_FLAG_QUEUE,TRUE); // if not, fresh install: create "Unsent Messages"
}
else {
q->SetFlag(MSG_FOLDER_FLAG_QUEUE); // make sure we know this is the queue folder.
}
}
// It is kept sorted, but we must resort after promoting the magic folder.
// jrm asks: probably faster to remove q, set the flag, then add it back.
m_mailfolders->GetSubFolders()->QuickSort(m_mailfolders->CompareFolders);
// for POP create the inbox here. Imap does it after it
// discovers all of its mailboxes
if (GetPrefs()->GetMailServerIsIMAP4())
m_mailfolders->SetFlag(MSG_FOLDER_FLAG_ELIDED); // collapse offline mail
else
{
FindMagicMailFolder(MSG_FOLDER_FLAG_INBOX, TRUE);
m_mailfolders->ClearFlag(MSG_FOLDER_FLAG_ELIDED);
}
// m_hosttable can be NULL if we failed to build the hosts DB
int n = m_hosttable ? m_hosttable->getNumHosts() : 0;
for (int i=0 ; i<n ; i++) {
MSG_NewsHost* host = m_hosttable->getHost(i);
XP_ASSERT(host);
if (!host) continue;
MSG_NewsFolderInfoContainer* info =
new MSG_NewsFolderInfoContainer(host, 1);
info->SetFlag(MSG_FOLDER_FLAG_ELIDED);
info->SetFlag(MSG_FOLDER_FLAG_NEWS_HOST);
parentFolder->Add(info);
host->LoadNewsrc(info); // ###tw Sigh. This is expensive.
// Probably should at least put it off until
// the user opens the host...
}
delete m_folderCache;
m_folderCache = NULL;
XP_FREE(dir);
}
return m_folderTree;
}
MSG_FolderInfoMail*
MSG_Master::GetLocalMailFolderTree()
{
if (!m_mailfolders) {
(void) GetFolderTree(); // Has a side effect of creating folders.
}
return m_mailfolders;
}
MSG_IMAPFolderInfoContainer*
MSG_Master::GetImapMailFolderTree()
{
if (!m_imapfolders) {
(void) GetFolderTree(); // Has a side effect of creating folders.
}
return m_imapfolders;
}
// Find a folder, but do not create the folder trees
MSG_FolderInfoMail* MSG_Master::FindFolderForNikiBiff(const char *path, const char *host, const char *owner)
{
MSG_FolderInfoMail *folder = NULL;
if (m_mailfolders)
folder = m_mailfolders->FindPathname((const char*) path);
if (!folder && m_imapfolders)
folder = FindImapMailFolder(host, path, owner, FALSE);
return folder;
}
MSG_NewsHost *MSG_Master::AddNewsHost(const char* hostname,
XP_Bool isxxx, int32 port)
{
if (GetHostTable() == NULL) return NULL;
int32 defaultport = HG19826 NEWS_PORT;
if (port == 0) port = defaultport;
MSG_NewsHost* newsHost = FindHost(hostname, isxxx, port);
if (newsHost) return newsHost;
char* hostAndPort = NULL;
if (port != defaultport) {
hostAndPort = PR_smprintf("%s:%ld", hostname, long(port));
if (!hostAndPort) return NULL; // Out of memory.
}
newsHost =
GetHostTable()->AddNewsHost(hostname,
isxxx, port,
hostAndPort ? hostAndPort : hostname);
FREEIF(hostAndPort);
if (newsHost)
{
XPPtrArray *parentFolder =
(XPPtrArray *) GetFolderTree()->GetSubFolders();
MSG_NewsFolderInfoContainer* info =
new MSG_NewsFolderInfoContainer(newsHost, 1);
info->SetFlag(MSG_FOLDER_FLAG_ELIDED);
info->SetFlag(MSG_FOLDER_FLAG_NEWS_HOST);
parentFolder->Add(info);
// need to diddle the fat file, I guess - I'm lost.
newsHost->SetNewsrcFileName(newsHost->getNameAndPort());
newsHost->LoadNewsrc(info); // ###tw Sigh. This is expensive.
// Probably should at least put it off until
// the user opens the host...
newsHost->MarkDirty(); // Make sure the newsrc will get created if it
// isn't already out there. This makes sure
// that adding the newshost will stick to the
// next session, even if the user never
// subscribes to any groups in it. See bug
// 39791.
MSG_Pane* pane;
for (pane = GetFirstPane() ; pane ; pane = pane->GetNextPane()) {
if (pane->GetPaneType() == MSG_FOLDERPANE) {
((MSG_FolderPane*) pane)->RedisplayAll();
}
}
}
return newsHost;
}
MSG_IMAPHostTable *MSG_Master::GetIMAPHostTable()
{
if (!m_imapHostTable)
{
m_imapHostTable = new MSG_IMAPHostTable(this);
GetFolderTree(); // make sure we've loaded the hosts
}
return m_imapHostTable;
}
MSG_IMAPHost *MSG_Master::AddIMAPHost(const char* hostname,
XP_Bool isxxx,
const char *userName,
XP_Bool checkNewMail,
int biffInterval,
XP_Bool rememberPassword,
XP_Bool usingSubscription,
XP_Bool overrideNamespace,
const char *personalOnlineDir,
const char *publicOnlineDir,
const char *otherUsersOnlineDir,
XP_Bool writePrefs /* = TRUE */)
{
MSG_IMAPHost* imapHost = GetIMAPHostTable()->FindIMAPHost(hostname);
if (imapHost)
return imapHost;
imapHost =
GetIMAPHostTable()->AddIMAPHost(hostname, isxxx, userName, checkNewMail, biffInterval, rememberPassword,
usingSubscription, overrideNamespace, personalOnlineDir, publicOnlineDir, otherUsersOnlineDir, writePrefs);
return imapHost;
}
MSG_ThreadPane* MSG_Master::FindThreadPaneNamed(const char *pathname)
{
MSG_Pane *pane;
for (pane = GetFirstPane(); pane != NULL; pane = pane->GetNextPane()) {
if (pane->GetPaneType() == MSG_THREADPANE) {
MSG_ThreadPane* threadPane = (MSG_ThreadPane*) pane;
MSG_FolderInfo *folderInfo = threadPane->GetFolder();
MSG_FolderInfoMail *mailFolderInfo = (folderInfo) ? folderInfo->GetMailFolderInfo() : 0;
if (mailFolderInfo && !XP_FILENAMECMP(mailFolderInfo->GetPathname(), pathname)) {
return threadPane;
}
}
}
return NULL;
}
void MSG_Master::FindPanesReferringToFolder (MSG_FolderInfo *folder, XPPtrArray *outArray)
{
for (MSG_Pane *pane = GetFirstPane() ; pane != NULL; pane = pane->GetNextPane())
{
if (folder == pane->GetFolder())
outArray->Add (pane);
}
}
MSG_IMAPFolderInfoMail*
MSG_Master::FindImapMailFolder(const char *hostName, const char* onlineServerName, const char *owner, XP_Bool createIfMissing)
{
if (!hostName)
return FindImapMailFolder(onlineServerName);
MSG_IMAPHostTable *imapHostTable = GetIMAPHostTable();
if (imapHostTable)
{
MSG_IMAPHost *host = imapHostTable->FindIMAPHost (hostName);
if (host && host->GetHostFolderInfo())
return host->GetHostFolderInfo()->FindImapMailOnline(onlineServerName, owner, createIfMissing);
}
return NULL;
}
MSG_IMAPFolderInfoMail *
MSG_Master::FindImapMailFolderFromPath(const char *pathName)
{
if (!m_imapHostTable) return NULL;
for (int i = 0; i < m_imapHostTable->GetSize(); i++)
{
MSG_IMAPHost *host = (MSG_IMAPHost *) m_imapHostTable->GetAt(i);
if (host && host->GetHostFolderInfo())
{
MSG_FolderInfo *folderInfo = host->GetHostFolderInfo()->FindMailPathname(pathName);
if (folderInfo)
return folderInfo->GetIMAPFolderInfoMail();
}
}
return NULL;
}
// ### dmb - what about port????
MSG_FolderInfoContainer *MSG_Master::GetImapMailFolderTreeForHost(const char *hostName)
{
if (!m_imapHostTable) return NULL;
MSG_IMAPHost *host = m_imapHostTable->FindIMAPHost (hostName);
if (host && host->GetHostFolderInfo())
return host->GetHostFolderInfo();
return NULL;
}
MSG_IMAPHost *MSG_Master::GetIMAPHost(const char *hostName)
{
return (m_imapHostTable) ? m_imapHostTable->FindIMAPHost (hostName) : 0;
}
int32 MSG_Master::GetSubscribingIMAPHosts(MSG_IMAPHost** result, int32 resultsize)
{
if (result == NULL)
{
// just checking for size
int32 numSubscribingIMAPHosts = 0;
MSG_IMAPHostTable *imapHostTable = GetIMAPHostTable();
if (imapHostTable)
{
int32 numIMAPHostsToFillIn = imapHostTable->GetHostList(NULL, 0);
MSG_IMAPHost **imapHosts = new MSG_IMAPHost* [numIMAPHostsToFillIn];
int32 numIMAPHosts = GetIMAPHostTable()->GetHostList(imapHosts, numIMAPHostsToFillIn);
for (int i = 0; i < numIMAPHosts; i++)
{
if (imapHosts[i]->GetIsHostUsingSubscription())
numSubscribingIMAPHosts++;
}
delete imapHosts;
}
return numSubscribingIMAPHosts;
}
else
{
// actually filling in the list
int32 numIMAPHostsToFillIn = resultsize, numSubscribingIMAPHosts = 0;
if (numIMAPHostsToFillIn > 0 && (GetIMAPHostTable() != NULL))
{
// get the IMAP Host list
int32 numIMAPHosts = GetIMAPHostTable()->GetSize();
MSG_IMAPHost **imapHosts = new MSG_IMAPHost* [numIMAPHosts];
int32 numIMAPHostsListed = GetIMAPHostTable()->GetHostList(imapHosts, numIMAPHosts);
// copy them from the IMAP host list to the main result list
for (int i = 0; (i < numIMAPHostsToFillIn) && (i < numIMAPHosts); i++)
{
if (imapHosts[i]->GetIsHostUsingSubscription())
{
result[numSubscribingIMAPHosts] = imapHosts[i];
numSubscribingIMAPHosts++;
}
}
delete imapHosts;
}
return numSubscribingIMAPHosts;
}
}
// This is being changed to include all IMAP hosts, regardless of whether or not we are
// showing only subscribed folders.
// If later we want to change it back, just remove the two "TRUE"'s in the if statements.
int32 MSG_Master::GetSubscribingHosts(MSG_Host** result, int32 resultsize)
{
if (result == NULL)
{
// just checking for size
int32 numNewsHosts = GetHostTable()->GetHostList(NULL, resultsize);
int32 numSubscribingIMAPHosts = 0;
MSG_IMAPHostTable *imapHostTable = GetIMAPHostTable();
if (imapHostTable)
{
numSubscribingIMAPHosts = imapHostTable->GetSize();
}
int32 total = numNewsHosts + numSubscribingIMAPHosts;
return total;
}
else
{
// actually filling in the list
int32 numNewsHosts = GetHostTable()->GetHostList((MSG_NewsHost **)result,resultsize);
int32 total = numNewsHosts;
int32 numIMAPHostsToFillIn = resultsize - numNewsHosts;
XP_ASSERT(numIMAPHostsToFillIn >= 0);
if (numIMAPHostsToFillIn > 0 && GetIMAPHostTable() != NULL)
{
// get the IMAP Host list
int32 numIMAPHosts = GetIMAPHostTable()->GetSize();
MSG_Host **imapHosts = new MSG_Host* [numIMAPHosts];
int32 numIMAPHostsListed = GetIMAPHostTable()->GetHostList((MSG_IMAPHost **)imapHosts, numIMAPHosts);
int32 numSubscribingIMAPHosts = 0;
// copy them from the IMAP host list to the main result list
for (int i = 0; i < numIMAPHosts && numNewsHosts + numSubscribingIMAPHosts < resultsize; i++)
{
result[numNewsHosts + numSubscribingIMAPHosts] = imapHosts[i];
numSubscribingIMAPHosts++;
}
total += numSubscribingIMAPHosts;
delete imapHosts;
}
return total;
}
}
MSG_IMAPFolderInfoMail*
MSG_Master::FindImapMailFolder(const char* onlineServerName)
{
if (!m_imapfolders) return NULL;
return m_imapfolders->FindImapMailOnline(onlineServerName, NULL, FALSE);
}
MSG_FolderInfoMail*
MSG_Master::FindMagicMailFolder(int flag, XP_Bool createIfMissing)
{
MSG_FolderInfoMail *retFolder = NULL;
char *magicFolderName = m_prefs->MagicFolderName(flag);
if (magicFolderName)
{
retFolder = FindMailFolder(magicFolderName, createIfMissing);
#ifdef XP_OS2
if (retFolder)
{
if (flag & MSG_FOLDER_FLAG_INBOX)
retFolder->SetName(INBOX_FOLDER_PRETTY_NAME);
if (flag & MSG_FOLDER_FLAG_TRASH)
retFolder->SetName(TRASH_FOLDER_PRETTY_NAME);
if (flag & MSG_FOLDER_FLAG_QUEUE)
retFolder->SetName(QUEUE_FOLDER_PRETTY_NAME);
if (flag & MSG_FOLDER_FLAG_DRAFTS)
retFolder->SetName(DRAFTS_FOLDER_PRETTY_NAME);
if (flag & MSG_FOLDER_FLAG_TEMPLATES)
retFolder->SetName(TEMPLATES_FOLDER_PRETTY_NAME);
}
#endif
XP_FREE(magicFolderName);
}
return retFolder;
}
MSG_FolderInfoMail*
MSG_Master::FindMailFolder(const char* pathURL, XP_Bool createIfMissing)
{
if (!m_mailfolders)
GetFolderTree(); // at least try to build the folder tree before failing...
if (!m_mailfolders || !pathURL) return NULL;
if (NET_URL_Type(pathURL) == IMAP_TYPE_URL)
{
return GetFolderInfo(pathURL, createIfMissing) ?
GetFolderInfo(pathURL, createIfMissing)->GetMailFolderInfo():
0 ;
}
char* folderPath = NET_ParseURL(pathURL, GET_PATH_PART);
if (!*folderPath)
StrAllocCat(folderPath, pathURL); // it was already a path?
MSG_FolderInfo* result = m_mailfolders->FindPathname(folderPath);
if (!result)
{
if (createIfMissing)
{
XP_StatStruct stat;
/* removing orphaned summary file for nonexistent mail folder
* otherwise the creation of the missing mail folder will fail.
*/
if (0 == XP_Stat (folderPath, &stat, xpMailFolderSummary))
XP_FileRemove(folderPath, xpMailFolderSummary);
MSG_FolderInfoMail *mailRoot = GetLocalMailFolderTree();
// try to strip off the folder from the pathname, since
// that's what CreateSubfolder wants.
const char *folderDir = GetPrefs()->GetFolderDirectory();
const char *folderName = folderPath + strlen(folderDir);
if (strncmp(folderDir, folderPath, strlen(folderDir)))
goto Cleanup;
if (folderName[0] == '/')
folderName++;
int32 newFolderPos = 0;
if (mailRoot->CreateSubfolder(folderName, &result, &newFolderPos)!= eSUCCESS)
result = NULL;
else
{
MSG_FolderPane *folderPane = (MSG_FolderPane*) FindPaneOfType ((MSG_FolderInfo*)NULL, MSG_FOLDERPANE);
if (folderPane)
{
MSG_FolderInfo *parent = m_folderTree->FindParentOf (result);
if (parent)
folderPane->AddFolderToView (result, parent, newFolderPos);
}
}
}
}
Cleanup:
XP_FREEIF(folderPath);
return (MSG_FolderInfoMail *) result;
}
// createIfMissing is currently only used for IMAPFolderInfoMail's. Also note that this
// only creates the folder info, not the actual folder on the server. This is used
// for automatically adding folders to the list before we've discovered them, as in
// a URL click on a link to a folder.
MSG_FolderInfo* MSG_Master::GetFolderInfo(const char *url, XP_Bool createIfMissing)
{
int urlType = NET_URL_Type(url);
MSG_FolderInfo *folder = NULL;
char *folderName = NULL;
char *host_and_port = NULL;
char *owner = NULL;
switch (urlType)
{
case NEWS_TYPE_URL:
{
folderName = NewsGroupDB::GetGroupNameFromURL(url);
host_and_port = NET_ParseURL (url, GET_HOST_PART);
folder = FindNewsFolder(host_and_port, folderName, *url == 's');
}
break;
case MAILBOX_TYPE_URL:
{
folderName = NET_ParseURL(url, GET_PATH_PART);
if (folderName && folderName[0] != '/')
{
char *saveFolderName = folderName;
folderName = PR_smprintf("%s/%s", m_prefs->GetFolderDirectory(), saveFolderName);
FREEIF(saveFolderName);
}
folder = FindMailFolder(folderName, FALSE);
break;
}
case IMAP_TYPE_URL:
{
owner = NET_ParseURL (url, GET_USERNAME_PART);
host_and_port = NET_ParseURL (url, GET_HOST_PART);
folderName = NET_ParseURL(url, GET_PATH_PART); // folderName will have leading '/'
if (folderName && *folderName)
folder = FindImapMailFolder(host_and_port, folderName + 1, owner, createIfMissing);
else
folder = GetImapMailFolderTreeForHost(host_and_port);
}
default:
break;
}
FREEIF(folderName);
FREEIF(host_and_port);
FREEIF(owner);
return folder;
}
int MSG_Master::GetMessageLineForURL(const char *url, MSG_MessageLine *msgLine)
{
int urlType = NET_URL_Type(url);
MSG_FolderInfo *folder = NULL;
char *folderName = NULL;
char *hostName = NULL;
int ret = -1; // ### dmb what should error be?
MessageKey key = MSG_MESSAGEKEYNONE;
switch (urlType)
{
case NEWS_TYPE_URL:
{
// given a url of the form news://news/<message-id>, GetGroupNameFromURL
// will return the <message-id>, so go with it.
char *idPart = NewsGroupDB::GetGroupNameFromURL(url);
if (!idPart)
break;
char *msgId = XP_STRDUP (NET_UnEscape (idPart));
// need to iterate through open thread and message panes trying to
// find this messageid.
MSG_Pane *pane = FindFirstPaneOfType(MSG_MESSAGEPANE);
while (pane != NULL)
{
if (MSG_GetKeyFromMessageId(pane, msgId, &key) == 0)
break;
pane = FindNextPaneOfType(pane->GetNextPane(), MSG_MESSAGEPANE);
}
if (pane == NULL)
{
pane = FindFirstPaneOfType(MSG_THREADPANE);
while (pane != NULL)
{
if (MSG_GetKeyFromMessageId(pane, msgId, &key) == 0)
break;
pane = FindNextPaneOfType(pane->GetNextPane(), MSG_THREADPANE);
}
}
if (key != MSG_MESSAGEKEYNONE)
ret = MSG_GetThreadLineById(pane, key, msgLine);
}
break;
case MAILBOX_TYPE_URL:
{
folderName = NET_ParseURL(url, GET_PATH_PART);
if (folderName && folderName[0] != '/')
{
char *saveFolderName = folderName;
folderName = PR_smprintf("%s/%s", m_prefs->GetFolderDirectory(), saveFolderName);
FREEIF(saveFolderName);
}
folder = FindMailFolder(folderName, FALSE);
if (folder)
{
MSG_Pane *pane = FindPaneOfType(folder, MSG_ANYPANE);
if (!pane)
break;
char *path = NET_ParseURL(url, GET_SEARCH_PART); // is this right?
char *idPart = XP_STRSTR(path, "?id=");
char *msgId = NULL;
if (idPart)
{
char *amp = XP_STRCHR(idPart+1, '&');
if (amp)
*amp = '\0'; // get rid of next ? if any
msgId = XP_STRDUP (NET_UnEscape (idPart+4));
ret = MSG_GetKeyFromMessageId (pane, msgId, &key);
if (ret >= 0)
ret = MSG_GetThreadLineById(pane, key, msgLine);
}
FREEIF(path);
FREEIF(msgId);
}
break;
}
case IMAP_TYPE_URL:
{
}
default:
break;
}
FREEIF(folderName);
FREEIF(hostName);
return ret;
}
MSG_FolderInfoNews *MSG_Master::FindNewsFolder(const char *host_and_port,
const char *newsGroupName,
XP_Bool xxxP,
XP_Bool autoSubscribe /*= TRUE*/)
{
const char *atSign = XP_STRCHR(host_and_port, '@');
const char *hostName = atSign;
// if Collabra has been disabled through the prefs/mission control
if (!m_collabraEnabled)
return NULL;
// in case this is a x newsgroup and has username/password tagged along
if (hostName)
hostName++;
else
hostName = host_and_port;
int32 port = 0;
char* colon = XP_STRCHR(host_and_port, ':');
if (colon) {
*colon = '\0';
port = XP_ATOI(colon + 1);
}
MSG_NewsHost *host = FindHost(hostName, xxxP, port);
MSG_FolderInfoNews *info = NULL;
if (!host && strlen(hostName) == 0)
host = m_hosttable->GetDefaultHost(TRUE);
if (!host && autoSubscribe)
host = AddNewsHost(hostName, xxxP, port);
if (host)
{
GetFolderTree(); // this has the side effect of loading the
// news rc - it is great!
info = host->FindGroup(newsGroupName);
// maybe we should add the group but not subscribe to it - though this
// will grow newsrc file
if ((!info || !info->IsSubscribed()) && autoSubscribe && XP_STRLEN(newsGroupName) > 0) {
// let us try autosubscribe...
info = host->AddGroup(newsGroupName);
if (info)
info->SetAutoSubscribed(TRUE);
}
if (info && hostName != host_and_port) {
// we have a pair of username and password here
// parse it and save it along with the newsgroup
const char *usercolon = XP_STRCHR(host_and_port, ':');
if (usercolon) {
char *username = (char*)
XP_ALLOC(usercolon - host_and_port + 1);
if (username) {
XP_MEMSET(username, 0, usercolon - host_and_port + 1);
XP_MEMCPY(username, host_and_port,
usercolon - host_and_port);
char *munged = HG28265(username);
info->SetNewsgroupUsername(munged);
FREEIF(munged);
HG24239
}
usercolon++;
if (usercolon < atSign) {
char *password = (char*) XP_ALLOC(atSign - usercolon + 1);
if (password) {
XP_MEMSET(password, 0, atSign - usercolon + 1);
XP_MEMCPY(password, usercolon, atSign - usercolon);
char *munged = HG23258(password);
info->SetNewsgroupPassword(munged);
FREEIF(munged);
HG56307
}
}
}
// else we do not have a legitimate username/password
// forget about the whole thing
}
// if (info && !info->IsSubscribed())
// info->Subscribe(TRUE, this);
}
if (colon) *colon = ':';
return info;
}
MSG_FolderInfoNews*
MSG_Master::FindNewsFolder(MSG_NewsHost* host,
const char *newsGroupName,
XP_Bool autoSubscribe /*= TRUE*/)
{
MSG_FolderInfoNews *info = NULL;
// if Collabra has been disabled through the prefs/mission control
if (!m_collabraEnabled)
return NULL;
XP_ASSERT(host);
if (!host) return NULL;
GetFolderTree(); // this has the side effect of loading the
// news rc - it is great!
info = host->FindGroup(newsGroupName);
// maybe we should add the group but not subscribe to it - though this
// will grow newsrc file
if (!info && autoSubscribe && XP_STRLEN(newsGroupName) > 0) {
// let us try autosubscribe...
info = host->AddGroup(newsGroupName);
}
return info;
}
MSG_FolderInfo *MSG_Master::FindNextFolder(MSG_FolderInfo *startFolder)
{
MSG_FolderIterator folderIterator(GetFolderTree());
MSG_FolderInfo *curFolder;
curFolder = folderIterator.AdvanceToFolder(startFolder);
curFolder = folderIterator.Next();
while (curFolder != NULL && (curFolder->GetType() == FOLDER_CONTAINERONLY || curFolder->GetType() == FOLDER_IMAPSERVERCONTAINER))
curFolder = folderIterator.Next();
return curFolder;
}
MSG_FolderInfo *MSG_Master::FindNextFolderWithUnread(MSG_FolderInfo *startFolder)
{
MSG_FolderIterator folderIterator(GetFolderTree());
MSG_FolderInfo *curFolder;
MSG_FolderInfo *retFolder = NULL;
curFolder = folderIterator.AdvanceToFolder(startFolder);
while (curFolder != NULL)
{
curFolder = folderIterator.Next();
// ignore trash folder while looking for next folder with unread
// This will still hit child folders of trash with unread.
if (curFolder && (curFolder->GetNumUnread() + curFolder->GetNumPendingUnread()) > 0 && !(curFolder->GetFlags() & MSG_FOLDER_FLAG_TRASH))
{
retFolder = curFolder;
break;
}
}
return retFolder;
}
ParseMailboxState *
MSG_Master::GetParseMailboxState(const char *folderName)
{
MSG_FolderInfoMail *mailFolder = FindMailFolder(folderName, FALSE);
return (mailFolder) ? mailFolder->GetParseMailboxState() : 0;
}
ListNewsGroupState *
MSG_Master::GetListNewsGroupState(MSG_NewsHost* host,
const char *newsGroupName)
{
MSG_FolderInfoNews *newsFolder = FindNewsFolder(host, newsGroupName);
return (newsFolder) ? newsFolder->GetListNewsGroupState() : 0;
}
MSG_NewsHost*
MSG_Master::FindHost(const char* name, XP_Bool isxxx, int32 port)
{
if (!name) return NULL; // Can happen, especially if we do not have a
// default newshost set.
const char* atSign = XP_STRCHR(name, '@');
if (atSign) {
name = atSign + 1; // In case there is a username/password tagged
// along with this host.
}
char* dupname = NULL;
MSG_NewsHost* result = NULL;
if (port < 0) {
port = 0;
if (XP_STRCHR(name, ':')) {
dupname = XP_STRDUP(name);
if (!dupname) return NULL;
char* ptr = XP_STRCHR(dupname, ':');
XP_ASSERT(ptr);
if (ptr) {
*ptr++ = '\0';
port = XP_ATOI(ptr);
}
name = dupname;
}
}
if (port == 0) port = HG82266 NEWS_PORT;
XP_ASSERT(XP_STRCHR(name, ':') == NULL);
// m_hosttable can be NULL if we failed to build the hosts DB
int n = m_hosttable ? m_hosttable->getNumHosts() : 0;
for (int i=0 ; i<n ; i++) {
MSG_NewsHost* host = m_hosttable->getHost(i);
if (XP_STRCMP(host->getStr(), name) == 0 &&
HG18262
host->getPort() == port) {
result = host;
break;
}
}
FREEIF(dupname);
return result;
}
MSG_NewsHost*
MSG_Master::GetDefaultNewsHost()
{
if (m_hosttable) return m_hosttable->GetDefaultHost(TRUE);
return NULL;
}
// The intent is to allow the user to type in a group name
// or a group url (including news server) and we would add the
// group to the newsrc file.
MSG_FolderInfoNews *MSG_Master::AddNewsGroup(const char *groupURL)
{
char *hostName = NET_ParseURL (groupURL, GET_HOST_PART);
char *groupName = NET_ParseURL(groupURL, GET_PATH_PART);
char *origGroupName = groupName;
char *origHostName = hostName;
MSG_FolderInfoNews *newsInfo = NULL;
HG12765
if (groupName[0] == '/')
groupName++;
else if (groupName[0] == '\0')
groupName = (char *) groupURL;
if (hostName[0] == '\0')
{
FREEIF(origHostName);
PREF_CopyCharPref("network.hosts.nntp_server", &origHostName);
if (origHostName && *origHostName == '\0') {
XP_FREE(origHostName);
origHostName = NULL;
}
if (!origHostName) return NULL;
hostName = origHostName;
int32 defport = 0;
PREF_GetIntPref("news.server_port", &defport);
if (defport && defport != (HG16236 NEWS_PORT)) {
char* tmp = PR_smprintf("%s:%ld", origHostName, long(defport));
XP_FREE(origHostName);
origHostName = tmp;
if (!origHostName) return NULL;
}
hostName = origHostName;
}
MSG_NewsHost *newsHost = FindHost(hostName, *groupURL == 's', -1);
if (newsHost)
newsInfo = newsHost->AddGroup(groupName);
if (newsInfo) // if group already exists, AddGroup will return NULL.
{
XP_File newsrcFile = XP_FileOpen(hostName,
HG16215 xpNewsRC,
XP_FILE_APPEND_BIN);
if (newsrcFile != NULL)
{
XP_FileWrite(groupName, strlen(groupName), newsrcFile);
XP_FileWrite(":\n", 2, newsrcFile);
XP_FileClose(newsrcFile);
}
}
FREEIF(origHostName);
FREEIF(origGroupName);
return newsInfo;
}
MSG_FolderInfoNews *MSG_Master::AddProfileNewsgroup (MSG_NewsHost* host,
const char *groupName)
{
char *groupUrl = PR_smprintf ("%s/%s", host->GetURLBase(), groupName);
if (groupUrl)
{
MSG_FolderInfoNews *newsFolder = AddNewsGroup (groupUrl);
host->SetIsProfile (groupName, TRUE);
XP_FREE(groupUrl);
if (newsFolder)
{
newsFolder->SetFlag (MSG_FOLDER_FLAG_PROFILE_GROUP);
BroadcastFolderChanged (newsFolder);
}
return newsFolder;
}
return NULL;
}
XP_Bool MSG_Master::AcquireRulesSemaphore (void *semRequester)
{
if (m_rulesSemaphoreHolder)
return FALSE;
m_rulesSemaphoreHolder = semRequester;
return TRUE;
}
XP_Bool MSG_Master::ReleaseRulesSemaphore (void *semHolder)
{
if (m_rulesSemaphoreHolder == semHolder)
{
m_rulesSemaphoreHolder = NULL;
return TRUE;
}
return FALSE;
}
XP_Bool MSG_Master::AcquireEditHeadersSemaphore (void * semRequester)
{
if (m_editHeadersSemaphoreHolder)
return FALSE;
m_editHeadersSemaphoreHolder = semRequester;
return TRUE;
}
XP_Bool MSG_Master::ReleaseEditHeadersSemaphore (void *semHolder)
{
if (m_editHeadersSemaphoreHolder == semHolder)
{
m_editHeadersSemaphoreHolder = NULL;
return TRUE;
}
return FALSE;
}
void MSG_Master::PostCreateImapFolderUrlExitFunc (URL_Struct *URL_s, int status, MWContext * /* window_id */)
{
// Not sure why this happens (pane is deleted), but it's a guaranteed crash.
if (!MSG_Pane::PaneInMasterList(URL_s->msg_pane))
URL_s->msg_pane = NULL;
if (URL_s->msg_pane && (0 == status))
{
MSG_Master *master = URL_s->msg_pane->GetMaster();
char *host_and_port = NET_ParseURL (URL_s->address, GET_HOST_PART);
// find the folder we created
char *folderName = IMAP_CreateOnlineSourceFolderNameFromUrl(URL_s->address);
MSG_IMAPFolderInfoMail *newImapFolder = master->FindImapMailFolder(host_and_port, folderName, NULL, FALSE);
FREEIF(host_and_port);
if (MSG_FOLDERPANE == URL_s->msg_pane->GetPaneType())
((MSG_FolderPane*) URL_s->msg_pane)->PostProcessRemoteCopyAction();
master->BroadcastFolderAdded (newImapFolder, URL_s->msg_pane);
FREEIF(folderName);
}
else if (URL_s->msg_pane) // this may be wrong - the url could have been interrupted after the folder was created.
{
MSG_Master *master = URL_s->msg_pane->GetMaster();
for (MSG_Pane *pane = master->GetFirstPane(); pane; pane = pane->GetNextPane())
{
MSG_PaneType type = pane->GetPaneType();
if (type == MSG_PANE || type == MSG_FOLDERPANE)
FE_PaneChanged (pane, FALSE, MSG_PaneNotifyNewFolderFailed, 0);
}
}
}
// This function is in the Master because we want to be able to create mail
// folders without having any panes, and certainly without a folder pane.
//
MsgERR MSG_Master::CreateMailFolder (MSG_Pane *invokingPane, MSG_FolderInfo *parent, const char *childName)
{
MsgERR status = 0;
MSG_FolderPane *folderPane = (MSG_FolderPane*) FindFirstPaneOfType (MSG_FOLDERPANE);
XP_Bool folderIsIMAPContainer = parent && (parent->GetType() == FOLDER_IMAPSERVERCONTAINER);
if (parent && !folderIsIMAPContainer && (parent->GetDepth() == 1)) {
// trying to create a folder in the root
parent = GetLocalMailFolderTree();
}
if (parent && parent->ContainsChildNamed(childName))
{
status = MK_MSG_FOLDER_ALREADY_EXISTS;
if (invokingPane)
{
FE_Alert(invokingPane->GetContext(),XP_GetString(status));
FE_PaneChanged (folderPane, FALSE, MSG_PaneNotifyNewFolderFailed, status); // let the FE know creation failed,
}
return status;
}
if ((parent->GetType() == FOLDER_IMAPMAIL) || folderIsIMAPContainer)
{
// this code will only allow creation of subfolders for existing
// online folders.
const char *parentOnlineName;
const char *hostName;
MSG_IMAPHost *host = NULL;
char newFolderOnlineHierarchySeparator = kOnlineHierarchySeparatorUnknown;
if (folderIsIMAPContainer)
{
// creating a new IMAP folder, and the parent is the IMAP container.
// This means that we might actually need to use the personal namespace
// as the parent folder, since we will sometimes strip it off.
hostName = ((MSG_IMAPFolderInfoContainer *) parent)->GetName();
host = ((MSG_IMAPFolderInfoContainer *) parent)->GetIMAPHost();
parentOnlineName = host->GetRootNamespacePrefix();
}
else
{
parentOnlineName = ((MSG_IMAPFolderInfoMail *) parent)->GetOnlineName();
host = ((MSG_IMAPFolderInfoMail *) parent)->GetIMAPHost();
newFolderOnlineHierarchySeparator = ((MSG_IMAPFolderInfoMail *) parent)->GetOnlineHierarchySeparator();
}
char *newFolderOnlineName = (char *) XP_ALLOC(XP_STRLEN(childName) + XP_STRLEN(parentOnlineName) + 2); // 2 == '/' and '\0'
XP_STRCPY(newFolderOnlineName, parentOnlineName);
const char *namespacePrefix = host->GetNamespacePrefixForFolder(parentOnlineName);
XP_Bool parentIsNamespace = FALSE;
if (namespacePrefix &&
!XP_STRCMP(namespacePrefix, parentOnlineName))
{
parentIsNamespace = TRUE; // the folder we are discovering is actually a namespace prefix.
}
// If the parent is a namespace itself, we shouldn't append any delimiters between the namespace
// and the top-level folder
if (!parentIsNamespace)
{
if (*newFolderOnlineName && *(newFolderOnlineName + XP_STRLEN(newFolderOnlineName) - 1) != '/')
XP_STRCAT(newFolderOnlineName, "/");
}
XP_STRCAT(newFolderOnlineName, childName);
if (NET_IsOffline())
{
MSG_IMAPFolderInfoMail *newFolder = MSG_IMAPFolderInfoMail::CreateNewIMAPFolder(parent->GetIMAPFolderInfoMail(), invokingPane->GetContext(),
newFolderOnlineName, childName, kPersonalMailbox, host);
if (newFolder)
newFolder->SetFolderPrefFlags(MSG_FOLDER_PREF_OFFLINEEVENTS | MSG_FOLDER_PREF_CREATED_OFFLINE | newFolder->GetFolderPrefFlags());
// tell FE about new folder, but don't make it select it - I hate that.
FE_PaneChanged (invokingPane, FALSE, MSG_PaneNotifySelectNewFolder, MSG_VIEWINDEXNONE);
// what about name validation? What about other folder types besides kPersonalMailbox?
return 0;
}
char *createMailboxURL = CreateImapMailboxCreateUrl(host->GetHostName(), newFolderOnlineName,newFolderOnlineHierarchySeparator);
if (createMailboxURL)
{
URL_Struct *url_struct = NET_CreateURLStruct(createMailboxURL, NET_SUPER_RELOAD);
if (url_struct && (invokingPane || folderPane))
{
if (invokingPane)
{
MSG_UrlQueue::AddUrlToPane(url_struct, MSG_Master::PostCreateImapFolderUrlExitFunc, invokingPane);
}
else
{
// should not get here, but just for backward compatibility until XFE and MacFE call the right glue function
if (folderPane)
MSG_UrlQueue::AddUrlToPane(url_struct, MSG_Master::PostCreateImapFolderUrlExitFunc, folderPane);
}
}
XP_FREE(createMailboxURL);
}
FREEIF(newFolderOnlineName);
}
else
{
MSG_FolderInfo *newFolder = NULL;
int32 newFolderPos = 0;
status = parent->CreateSubfolder (childName, &newFolder, &newFolderPos);
if (status == 0)
{
BroadcastFolderAdded (newFolder, invokingPane);
}
else { // status != 0; folder creation failed
if (folderPane) {
FE_Alert (folderPane->GetContext(), XP_GetString (status)); // put up the message to the user
FE_PaneChanged (folderPane, FALSE, MSG_PaneNotifyNewFolderFailed, status); // let the FE know creation failed,
}
// in case it wants to do anything
}
}
return status;
}
XP_Bool MSG_Master::CleanupNeeded()
{
MSG_FolderIterator folderIterator(GetFolderTree());
MSG_FolderInfo *curFolder;
curFolder = folderIterator.First();
while(curFolder)
{
if (curFolder->RequiresCleanup())
return TRUE;
curFolder = folderIterator.Next();
}
return FALSE;
}
void MSG_Master::CleanupFolders(MSG_Pane *pane)
{
MSG_FolderIterator folderIterator(GetFolderTree());
MSG_FolderInfo *curFolder;
XPPtrArray foldersToCleanup;
curFolder = folderIterator.First();
// build up list of folders that need compaction
while(curFolder)
{
if (curFolder->RequiresCleanup())
foldersToCleanup.Add(curFolder);
curFolder = folderIterator.Next();
}
if (foldersToCleanup.GetSize() > 0)
{
MSG_BackgroundCleanup *bgCleanupHandler = new MSG_BackgroundCleanup(foldersToCleanup);
if (bgCleanupHandler)
bgCleanupHandler->Begin(pane);
}
}
int MSG_Master::DownloadForOffline(MSG_Pane *pane, MSG_FolderInfo *folder /*=NULL*/)
{
int returnValue = 0;
if (folder && !folder->IsNews())
{
FE_AllConnectionsComplete(pane->GetContext());
return -1;
}
MSG_DownloadOfflineFoldersState *downloadOfflineFoldersState = new MSG_DownloadOfflineFoldersState(pane);
if (downloadOfflineFoldersState)
{
if (folder)
returnValue = downloadOfflineFoldersState->DownloadOneFolder(folder);
else
returnValue = downloadOfflineFoldersState->DoIt();
}
return returnValue;
}
class MSG_GoOfflineState : public MSG_PaneURLChain
{
public:
MSG_GoOfflineState(MSG_Pane *pane, XP_Bool goOffline);
virtual int GetNextURL();
XP_Bool m_bReplicateDirectories;
XP_Bool m_bDownloadDiscussions;
XP_Bool m_bGetNewMail;
XP_Bool m_bSendOutbox;
XP_Bool m_bOnline;
XP_Bool m_bDownloadRet;
XP_Bool m_bLaunchedURL;
XP_Bool m_bGoOffline;
};
MSG_GoOfflineState::MSG_GoOfflineState(MSG_Pane *pane, XP_Bool goOffline) : MSG_PaneURLChain(pane)
{
m_bDownloadDiscussions = FALSE;
m_bGetNewMail = FALSE;
m_bSendOutbox = FALSE;
m_bDownloadRet = 0;
m_bLaunchedURL = FALSE;
m_bGoOffline = goOffline;
PREF_GetBoolPref("network.online", &m_bOnline);
if (!m_bOnline)
PREF_SetBoolPref("network.online", TRUE);
}
int MSG_GoOfflineState::GetNextURL()
{
int ret = 0;
if (m_bDownloadDiscussions)
{
m_bDownloadDiscussions = FALSE;
m_bDownloadRet = m_pane->GetMaster()->DownloadForOffline(m_pane);
m_bLaunchedURL = (m_bLaunchedURL) ? TRUE : (ret >= 0);
if (m_bLaunchedURL)
return 0;
}
if (m_bSendOutbox)
{
m_bSendOutbox = FALSE;
m_bLaunchedURL = TRUE;
m_pane->DeliverQueuedMessages();
return 0;
}
if (m_bGetNewMail)
{
m_bGetNewMail = FALSE;
m_bLaunchedURL = TRUE;
if (m_pane->GetMaster()->GetPrefs()->GetMailServerIsIMAP4())
{
m_pane->GetMaster()->ImapGoOnline(m_pane); // uses MSG_UrlQueue chaining
}
else
return m_pane->GetNewMail(m_pane, NULL);
}
if (m_bReplicateDirectories)
{
m_bReplicateDirectories = FALSE;
if (NET_ReplicateDirectory(m_pane, NULL))
m_bLaunchedURL = TRUE;
}
else
{
if (m_bOnline && m_bGoOffline)
{
// this will need to terminate all imap connections, not just the cached one,
m_pane->GetMaster()->CloseCachedImapConnections();
PREF_SetBoolPref("network.online", FALSE);
}
if (!m_bLaunchedURL)
FE_PaneChanged(m_pane, TRUE, MSG_PaneProgressDone, 0);
else
m_pane->ClearURLChain(); // will delete this, so don't do anything after this with this!!!
}
return 0;
}
int MSG_Master::SynchronizeOffline(MSG_Pane *pane, XP_Bool bDownloadDiscussions, XP_Bool bGetNewMail, XP_Bool bSendOutbox, XP_Bool bReplicateDirectories, XP_Bool goOffline)
{
MSG_GoOfflineState *queue = new MSG_GoOfflineState (pane, goOffline);
if (queue)
{
queue->m_bReplicateDirectories = bReplicateDirectories;
queue->m_bDownloadDiscussions = bDownloadDiscussions;
queue->m_bGetNewMail = bGetNewMail;
queue->m_bSendOutbox = bSendOutbox;
pane->SetURLChain(queue);
queue->GetNextURL();
}
return 0;
}
MSG_PurgeInfo *MSG_Master::GetPurgeHdrInfo()
{
return m_purgeHdrPref;
}
MSG_PurgeInfo *MSG_Master::GetPurgeArtInfo()
{
return m_purgeArtPref;
}
void MSG_Master::ImapGoOnline(MSG_Pane *paneForUrls)
{
if (GetPrefs()->GetMailServerIsIMAP4())
{
XP_ASSERT(paneForUrls);
OfflineImapGoOnlineState *goState = new OfflineImapGoOnlineState(paneForUrls);
if (goState)
goState->ProcessNextOperation();
}
}
XP_Bool MSG_Master::IsCachePasswordProtected()
{
return m_passwordProtectCache;
}
XP_Bool
MSG_Master::IsHTMLOK(MSG_FolderInfo* info)
{
MSG_FolderInfoNews* group = info->GetNewsFolderInfo();
XP_ASSERT(group && group->GetHost() && group->GetNewsgroupName());
if (!group || !group->GetHost() || !group->GetNewsgroupName()) return -1;
return group->GetHost()->IsHTMLOk(group->GetNewsgroupName());
}
int
MSG_Master::SetIsHTMLOK(MSG_FolderInfo* info, MWContext* context,
XP_Bool value)
{
MSG_FolderInfoNews* group = info->GetNewsFolderInfo();
XP_ASSERT(group && group->GetHost() && group->GetNewsgroupName());
if (!group || !group->GetHost() || !group->GetNewsgroupName()) return -1;
MSG_NewsHost* host = group->GetHost();
const char* name = group->GetNewsgroupName();
if (value == host->IsHTMLOk(name)) return 0;
if (value) {
return host->SetIsHTMLOKGroup(name, value);
}
char* tmp = XP_STRDUP(name);
if (!tmp) return MK_OUT_OF_MEMORY;
char* ancestor = NULL;
while (*tmp) {
if (host->IsHTMLOKTree(tmp)) {
FREEIF(ancestor);
ancestor = XP_STRDUP(tmp);
if (!ancestor) return MK_OUT_OF_MEMORY;
}
char* ptr = XP_STRRCHR(tmp, '.');
if (ptr) *ptr = '\0';
else break;
}
XP_FREE(tmp);
tmp = NULL;
if (!ancestor) {
return host->SetIsHTMLOKGroup(name, value);
}
XP_ASSERT(!value); // If value is TRUE, and we found an ancestor,
// then host->IsHTMLOk() should have returned
// TRUE as well.
if (value) return -1;
tmp =
PR_smprintf(XP_GetString(MK_MSG_SET_HTML_NEWSGROUP_HEIRARCHY_CONFIRM),
name, ancestor, ancestor);
XP_FREE(ancestor);
ancestor = NULL;
if (!tmp) return MK_OUT_OF_MEMORY;
XP_Bool doit = FE_Confirm(context, tmp);
XP_FREE(tmp);
tmp = NULL;
if (!doit) return -1; // ### Need a better return value.
tmp = XP_STRDUP(name);
if (!tmp) return MK_OUT_OF_MEMORY;
while (*tmp) {
host->SetIsHTMLOKTree(tmp, value);
char* ptr = XP_STRRCHR(tmp, '.');
if (ptr) *ptr = '\0';
else break;
}
return host->SetIsHTMLOKGroup(name, value);
}
void MSG_Master::ClearFolderGotNewBit()
{
MSG_FolderIterator folderIterator(GetFolderTree());
MSG_FolderInfo *curFolder = folderIterator.First();
// clear new bit on all folders - should stop at mail...
while(curFolder)
{
curFolder->ClearFlag(MSG_FOLDER_FLAG_GOT_NEW);
curFolder = folderIterator.Next();
}
}
void MSG_Master::SetMailAccountURL(const char* urlString)
{
if (!urlString)
{
FREEIF(m_mailAccountUrl);
}
else
{
if (urlString && XP_STRLEN(urlString))
StrAllocCopy(m_mailAccountUrl, urlString);
}
}
XP_Bool MSG_Master::InitFolderFromCache (MSG_FolderInfo *folder)
{
if (m_folderCache)
return m_folderCache->InitializeFolder (folder);
return FALSE;
}
// Returns TRUE if we are running the auto-upgrade process now, FALSE otherwise
XP_Bool MSG_Master::TryUpgradeToIMAPSubscription(MWContext *context, XP_Bool forceBringUpSubscribeUI,
MSG_Pane *paneToAssociate, MSG_IMAPHost *hostBeingOpened)
{
if (forceBringUpSubscribeUI ||
(!NET_IsOffline() && ShouldUpgradeToIMAPSubscription()))
{
XP_Bool usingIMAP = FALSE;
char *oldHostName = NULL;
MSG_IMAPHost *upgradeHost = NULL;
PREF_CopyCharPref("network.hosts.pop_server", &oldHostName);
if (oldHostName)
{
upgradeHost = GetIMAPHost(oldHostName);
usingIMAP = (upgradeHost != NULL);
}
if (paneToAssociate->GetPaneType() == MSG_THREADPANE)
m_imapUpgradeBeginPane = (MSG_ThreadPane *)paneToAssociate;
if (hostBeingOpened && (upgradeHost != hostBeingOpened))
{
// This case should be extremely rare, and there is no really good way to handle it.
// But we will try our best...
// It occurs when the user has added a second IMAP server before running
// the upgrade, and has made that second server their default host.
// If that's the case, we should run the upgrade on the host for
// the folder being opened (hostBeingOpened), but ONLY IF the
// host's using_subscription bit is set to false. If it is set to
// true, then we should mark the upgrade as done.
upgradeHost = hostBeingOpened;
XP_Bool alreadyUsingSubscription = FALSE;
char *prefString = PR_smprintf("mail.imap.server.%s.using_subscription", hostBeingOpened->GetHostName());
if (prefString)
{
PREF_GetBoolPref(prefString, &alreadyUsingSubscription);
XP_FREE(prefString);
}
if (alreadyUsingSubscription)
{
m_prefs->SetMailNewsProfileAgeFlag(MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG);
m_imapUpgradeBeginPane = 0;
return FALSE;
}
}
if (usingIMAP)
{
XP_Bool leaveSubscriptionAlone = FALSE;
PREF_GetBoolPref("mail.imap.upgrade.leave_subscriptions_alone", &leaveSubscriptionAlone);
if (leaveSubscriptionAlone && !forceBringUpSubscribeUI)
{
// set the upgraded flag, and don't turn on using_subscription
m_prefs->SetMailNewsProfileAgeFlag(MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG);
m_imapUpgradeBeginPane = 0;
return FALSE;
}
else
{
// ok, it's time to upgrade
XP_Bool subscribeToAll = FALSE;
MSG_IMAPUpgradeType upgradePath = MSG_IMAPUpgradeAutomatic;
PREF_GetBoolPref("mail.imap.upgrade.auto_subscribe_to_all", &subscribeToAll);
if (subscribeToAll && !forceBringUpSubscribeUI)
{
FE_Alert(context, XP_GetString(MK_IMAP_UPGRADE_WAIT_WHILE_UPGRADE));
}
else if (!forceBringUpSubscribeUI)
{
#ifdef FE_IMPLEMENTS_IMAP_SUBSCRIBE_UPGRADE
upgradePath = FE_PromptIMAPSubscriptionUpgrade (context, oldHostName);
if (upgradePath == MSG_IMAPUpgradeDont)
{
m_imapUpgradeBeginPane = 0;
return TRUE; // don't let them continue
}
#else // FE_IMPLEMENTS_IMAP_SUBSCRIBE_UPGRADE
XP_Bool upgradePathBool = FE_Confirm(context, XP_GetString(MK_IMAP_UPGRADE_PROMPT_QUESTION));
if (upgradePathBool)
upgradePath = MSG_IMAPUpgradeAutomatic;
else
upgradePath = MSG_IMAPUpgradeCustom;
#endif
}
else if (forceBringUpSubscribeUI)
{
// forceBringUpSubscribeUI
upgradePath = MSG_IMAPUpgradeCustom;
}
if (upgradePath == MSG_IMAPUpgradeCustom)
{
// the user said "Manual", so bring up the subscribe UI.
//if (!forceBringUpSubscribeUI) // don't alert them if we're forcing it - we already alterted them
// FE_Alert(context, XP_GetString(MK_IMAP_UPGRADE_CUSTOM));
// Set some flags so we know the callback should write out
// the upgrade state if successful.
SetUpgradingToIMAPSubscription(TRUE); // It is the subscribe pane's responsibility
// to clear this flag; it is not critical if it
// is not immediately cleared, however, since its only
// purpose is to instruct the subscribe pane to write
// out the fact that we've upgraded.
FE_CreateSubscribePaneOnHost(this, context, upgradeHost);
// return TRUE, since we want to stop the current folder load URL
return TRUE;
}
else
{
// either "subscribe to all" or "automatic," so switch to the new URL
char *upgradeUrl = CreateIMAPUpgradeToSubscriptionURL(oldHostName, subscribeToAll);
URL_Struct *URL_s = NET_CreateURLStruct(upgradeUrl, NET_DONT_RELOAD);
if(!URL_s) // out of memory?
{
FE_Alert(context, XP_GetString(MK_OUT_OF_MEMORY));
m_imapUpgradeBeginPane = 0;
return FALSE;
}
URL_s->internal_url = TRUE;
/*pw_ptr */ m_progressWindow = PW_Create(context, pwApplicationModal);
if (m_progressWindow)
{
MWContext *progressContext = PW_CreateProgressContext();
if (progressContext)
{
PW_SetCancelCallback(m_progressWindow, CancelIMAPProgressCallback, progressContext);
progressContext->mailMaster = this;
PW_AssociateWindowWithContext(progressContext, m_progressWindow);
PW_SetWindowTitle(m_progressWindow, "IMAP Folder Upgrade");
PW_SetLine1(m_progressWindow, "Upgrading to IMAP Subscription...");
PW_SetLine2(m_progressWindow, NULL);
//PW_Show(m_progressWindow);
paneToAssociate->AdoptProgressContext(progressContext);
m_upgradingToIMAPSubscription = TRUE;
NET_GetURL(URL_s, FO_PRESENT, progressContext, MSG_Master::PostImapSubscriptionUpgradeExitFunc);
}
else
{
FE_Alert(context, XP_GetString(MK_OUT_OF_MEMORY));
m_imapUpgradeBeginPane = 0;
return FALSE;
}
}
else
{
FE_Alert(context, XP_GetString(MK_OUT_OF_MEMORY));
m_imapUpgradeBeginPane = 0;
return FALSE;
}
return TRUE;
}
}
}
else
{
// Not Using IMAP - set the pref flag, and don't try again
m_prefs->SetMailNewsProfileAgeFlag(MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG);
m_imapUpgradeBeginPane = 0;
return FALSE;
}
}
else
{
// Offline, or shouldn't upgrade
return FALSE;
}
}
void MSG_Master::PostIMAPUpgradeFolderLoad(int status)
{
if (m_imapUpgradeBeginPane)
{
m_imapUpgradeBeginPane->FinishLoadingIMAPUpgradeFolder(status != MK_INTERRUPTED);
m_imapUpgradeBeginPane = 0;
}
}
XP_Bool MSG_Master::ShouldUpgradeToIMAPSubscription()
{
int32 profileAge = m_prefs->GetStartingMailNewsProfileAge();
if (profileAge & MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG) // we've upgraded to subscription already
return FALSE;
else
return TRUE;
}
void MSG_Master::SetIMAPSubscriptionUpgradedPrefs()
{
char *oldHostName = NULL;
PREF_CopyCharPref("network.hosts.pop_server", &oldHostName);
if (oldHostName)
{
MSG_IMAPHost *upgradedHost = GetIMAPHost(oldHostName);
XP_ASSERT(upgradedHost);
if (upgradedHost)
{
upgradedHost->SetIsHostUsingSubscription(TRUE);
}
XP_FREE(oldHostName);
}
m_prefs->SetMailNewsProfileAgeFlag(MSG_IMAP_SUBSCRIBE_UPGRADE_FLAG);
}
XP_Bool MSG_Master::ShowIMAPProgressWindow()
{
if (m_progressWindow)
{
PW_Show(m_progressWindow);
PW_SetProgressRange(m_progressWindow, 1, 0);
return TRUE;
}
else
return FALSE;
}
/* static */ void MSG_Master::PostImapSubscriptionUpgradeExitFunc (URL_Struct *, int status, MWContext *context)
{
MSG_Master *master = context->mailMaster;
if (context->type == MWContextProgressModule)
PW_AssociateWindowWithContext(context, NULL);
XP_ASSERT(master);
if (master)
{
if (master->m_progressWindow)
{
PW_Hide(master->m_progressWindow);
PW_Destroy(master->m_progressWindow);
master->m_progressWindow = NULL;
}
master->m_upgradingToIMAPSubscription = FALSE;
master->PostIMAPUpgradeFolderLoad(status);
}
}
/* static */ void MSG_Master::CancelIMAPProgressCallback(void *closure)
{
MWContext *context = (MWContext *)closure;
if (context)
{
XP_InterruptContext(context);
}
}
// Returns a newly-allocated space-delimited list of the arbitrary headers needed to be downloaded for filters
// for a given host, when using IMAP. Returns NULL if there are none, or the host could not be found.
// This list should not include standard filter headers, such as "To" or "CC"
char *MSG_Master::GetArbitraryHeadersForHostFromFilters(const char* /*hostName*/)
{
// eventually we'll want to provide just the ones used in filters...
// short term fix for now to test the system where we return a space delimited list of
// all registered custom headers from the prefs. Return string is null terminated.
int numHeaders = 0;
int headerBufSize = 0;
MSG_Prefs * prefs = GetPrefs();
if (prefs)
{
numHeaders = prefs->GetNumCustomHeaders();
if (numHeaders > 0)
{
char ** arrayOfHeaders = (char **) XP_ALLOC(sizeof(char *) * numHeaders);
if (arrayOfHeaders)
{
for (int index = 0; index < numHeaders; index++)
{
arrayOfHeaders[index] = prefs->GetNthCustomHeader(index);
if (arrayOfHeaders[index])
headerBufSize += XP_STRLEN(arrayOfHeaders[index])+1; // + 1 for space delimter or null terminator
}
char * headerBuffer = (char *) XP_ALLOC(sizeof(char) * headerBufSize);
if (headerBuffer)
{
XP_STRCPY(headerBuffer, "");
int i = 0;
for (i = 0; i < numHeaders; i++)
if (arrayOfHeaders[i])
{
XP_STRCAT(headerBuffer, arrayOfHeaders[i]);
XP_FREE(arrayOfHeaders[i]); // free memory for the arbitrary header string
// However, on this day NJ wins...
if (i < numHeaders-1) // only add the space if it is the last character...
XP_STRCAT(headerBuffer, " "); // space delimited
}
}
XP_FREE(arrayOfHeaders);
return headerBuffer;
}
} // NJ > TX
} // TX >>> nj
return NULL;
}
// Returns a newly-allocated space-delimited list of the arbitrary headers needed to be downloaded for MDN
// for a given host, when using IMAP. Returns NULL if there are none, or the host could not be found.
// For instance, if MDN is not enabled, it should return NULL.
// An example of something it might return would look like: "From To CC Resent-From"
char *MSG_Master::GetArbitraryHeadersForHostFromMDN(const char* /*hostName*/)
{
XP_Bool bMdnEnabled = FALSE;
int32 intPref = 0;
char *hdrString = NULL;
PREF_GetIntPref("mail.incorporate.return_receipt", &intPref);
if (intPref == 1)
StrAllocCopy(hdrString, "Content-Type");
PREF_GetBoolPref("mail.mdn.report.enabled", &bMdnEnabled);
if (bMdnEnabled)
if (hdrString)
StrAllocCat(hdrString, " Return-Receipt-To Disposition-Notification-To");
else
StrAllocCopy(hdrString, "Return-Receipt-To Disposition-Notification-To");
return hdrString;
}
int MSG_Master::PromptForHostPassword(MWContext *context, MSG_FolderInfo *folder)
// prompt for the password and match against saved password until user gets it
// right or cancels. Returns 0 if passed, non-zero for failure.
// For local folders, we want to use the default imap host password if there's an imap host,
// otherwise, we want to use the pop password, which we'll store in the local Inbox summary file.
// This routine also needs to set the appropriate internal state so the user won't be challenged
// again for the password when they make a real network connection.
{
const char *userName = folder->GetUserName();
int ret = -1;
const int kNumPasswordTries = 3;
char *userNameDup = NULL;
if (userName)
userNameDup = XP_STRDUP(userName);
else
return MK_POP3_USERNAME_UNDEFINED;
const char *host = folder->GetHostName();
char *alert;
const char *savedPassword = folder->GetRememberedPassword();
// well, if we don't have a remembered password, just let them in.
if (!savedPassword || !XP_STRLEN(savedPassword))
{
FREEIF(userNameDup);
return 0;
}
const char *fmt1 = XP_GetString( XP_PASSWORD_FOR_POP3_USER );
if (fmt1) /* We need to read a password. */
{
char *password;
size_t len = (XP_STRLEN(fmt1) + (host ? XP_STRLEN(host) : 0) + 300) * sizeof(char);
char *prompt = (char *) XP_ALLOC (len);
if (!prompt)
return MK_OUT_OF_MEMORY;
PR_snprintf (prompt, len, fmt1, userNameDup, host);
FREEIF(userNameDup);
char *unmungedPassword = NULL;
if (savedPassword)
unmungedPassword = HG32686(savedPassword);
if (unmungedPassword == NULL || !XP_STRLEN(unmungedPassword))
return MK_POP3_PASSWORD_UNDEFINED;
int i;
for (i = 0; i < kNumPasswordTries; i++)
{
password = FE_PromptPassword(context, prompt);
if (!password || !XP_STRLEN(password))
{
ret = -1;
break;
}
if (!XP_STRCMP(password, unmungedPassword))
{
ret = 0;
if (GetPrefs()->GetMailServerIsIMAP4())
{
MSG_IMAPHost *defaultIMAPHost = GetIMAPHostTable()->GetDefaultHost();
if (defaultIMAPHost)
IMAP_SetPasswordForHost(defaultIMAPHost->GetHostName(), password);
}
else
{
HG53961
NET_SetPopPassword(savedPassword);
}
SetLocalFoldersAuthenticated();
break;
}
else
{
char *alert = XP_GetString(XP_MSG_CACHED_PASSWORD_NOT_MATCHED);
if (alert)
FE_Alert(context, alert);
}
FREEIF(password);
}
if (ret != 0)
{
alert = XP_GetString(XP_MSG_PASSWORD_FAILED);
FE_Alert(context, alert);
}
XP_FREE(prompt);
FREEIF(unmungedPassword);
}
return ret;
}