/* -*- 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.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/ * * 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. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "msg.h" #include "errcode.h" #include "rosetta.h" #include "msgprefs.h" #include "msgprnot.h" #include "imap.h" #include "prefapi.h" #include "msgmast.h" #include "msgfinfo.h" #include "proto.h" // for XP_FindSomeContext #include "pmsgfilt.h" #include "msgimap.h" #include "imaphost.h" extern "C" { #include "mkreg.h" } #include "ptrarray.h" #ifdef XP_MAC #include "Memory.h" #include "Files.h" #include "ufilemgr.h" #include "uprefd.h" #else extern "C" { const char *FE_GetFolderDirectory(MWContext *c); void NET_SetMailRelayHost(char *); void NET_SetNewsHost(const char *); } #endif extern "C" { extern int MK_MSG_MAIL_DIRECTORY_CHANGED; extern int MK_MSG_SENT_L10N_NAME; extern void MIME_ConformToStandard(XP_Bool conform_p); extern int MK_MSG_UNABLE_TO_SAVE_DRAFT; extern int MK_MSG_UNABLE_TO_SAVE_TEMPLATE; } // Notify listeners that something got changed. updateCode is an int16 instead of // a MSG_PrefsNotify::NotifyCode because it was deemed a Bad Thing to include all of // msgprnot.h just to pick up that definition. void MSG_Prefs::Notify(int16 updateCode) { int i; // if we are changing mail servers, trash cached path to imap databases // m_IMAPdirectory will be reset by next reload call if ((updateCode == MSG_PrefsNotify::MailServerType) || (updateCode == MSG_PrefsNotify::PopHost)) FREEIF(m_IMAPdirectory); // Do the notification in such a way that deleted listeners don't // foul up the notification for everyone else. (m_notifying affects // the behavior of RemoveNotify so that it only NULLs deleted listeners.) m_notifying = TRUE; for (i = 0; i < m_numnotify ; i++) { if (m_notify[i]) m_notify[i]->NotifyPrefsChange((MSG_PrefsNotify::NotifyCode) updateCode); } m_notifying = FALSE; // Clean up after nulled pointers. for(i=(m_numnotify-1);i >= 0; i--) { if (! m_notify[i]) { if (i == (m_numnotify-1)) // last element is null, keep decrementing the count m_numnotify--; else // replace this null element with the last in the list m_notify[i] = m_notify[--m_numnotify]; } } } char *headerPrefNames[] = { "mail.identity.reply_to", "mail.default_cc", "mail.default_fcc", "mail.imap_sentmail_path", "news.default_cc", "news.default_fcc", "news.imap_sentmail_path", }; enum headerPrefIndices { mail_identity_reply_to=0, mail_default_cc, mail_default_fcc, // this is a mess don't change order mail_imap_sentmail_path, news_default_cc, news_default_fcc, // this is a mess don't change order news_imap_sentmail_path, num_of_header_prefs }; void MSG_Prefs::PlatformFileToURLPath(const char *platformFile, char **result) { *result = NULL; char *tmp = XP_PlatformFileToURL(platformFile); XP_ASSERT(tmp && !strncmp(tmp, "file://", 7)); if (tmp && !strncmp(tmp, "file://", 7)) *result = XP_STRDUP(&(tmp[7])); #ifdef XP_UNIX if ( *result && **result == '~' ) { char buf[1024]; char* home_dir = getenv("HOME"); char* tmp = (*result) + 1; while ( *tmp == '/' ) tmp++; /* trim trailing slashes in home_dir */ while ( (tmp = strrchr(home_dir, '/')) && tmp[1] == '\0' ) *tmp = '\0'; PR_snprintf(buf, sizeof(buf), "%s/%s", home_dir ? home_dir : "", tmp); XP_FREE(*result); *result = XP_STRDUP(buf); } #endif FREEIF(tmp); } static XP_Bool ShouldSavePrefAsBinaryAlias(const char* prefname) { #ifdef XP_MAC // Return TRUE if path names are saved as binary alias prefs (the default). // Return FALSE for the URL cases, now saved as a string (new in Nova). These are IMAP // fccs, and all drafts and all templates. if (XP_STRCMP(prefname, "mail.imap_sentmail_path") == 0) return FALSE; // URL else if (XP_STRCMP(prefname, "news.imap_sentmail_path") == 0) return FALSE; // URL else if (XP_STRCMP(prefname, "mail.default_drafts") == 0) return FALSE; // URL else if (XP_STRCMP(prefname, "mail.default_templates") == 0) return FALSE; // URL return TRUE; #else return FALSE; #endif // XP_MAC } int MSG_Prefs::GetXPDirPathPref(const char *prefName, XP_Bool /*expectFile*/, char **result) { int returnVal = PREF_NOERROR; char *tmp = NULL; *result = NULL; // in case we fail if (ShouldSavePrefAsBinaryAlias(prefName)) { returnVal = PREF_CopyPathPref(prefName, &tmp); if (returnVal == PREF_NOERROR) *result = tmp; return returnVal; } returnVal = PREF_CopyCharPref(prefName, &tmp); // paths are strings elsewhere if (returnVal == PREF_NOERROR) { // Convert pathname to an xp path. if (XP_STRLEN(tmp) > 0 && NET_URL_Type(tmp) != IMAP_TYPE_URL && NET_URL_Type(tmp) != MAILBOX_TYPE_URL) { PlatformFileToURLPath(tmp,result); XP_FREEIF(tmp); } else *result = tmp; } return returnVal; } int MSG_Prefs::SetXPMailFilePref(const char* /*prefName*/, char *xpPath) { int returnVal = PREF_NOERROR; if (NET_URL_Type(xpPath) != IMAP_TYPE_URL) { // ## mwelch 4.0b2 hack! Create the mail file if it doesn't already exist. // Mail parent folder was created at app startup, so it is // safe to assume that the parent directory exists. char *platformPath = WH_FileName(xpPath, xpMailFolder); XP_File fp = XP_FileOpen(xpPath, xpMailFolder, XP_FILE_APPEND_BIN); if (fp) XP_FileClose(fp); XP_FREEIF(platformPath); } return returnVal; } // MSG_Prefs::SetXPMailFilePref void MSG_Prefs::SetMailNewsProfileAgeFlag(int32 flag, XP_Bool set /* = TRUE */) { // each 'trick' uses this function to register that it is done, but we do not // want one trick to erase the completion of another. int32 currentAge = 0; PREF_GetIntPref("mailnews.profile_age",¤tAge); if (set) { if (!(currentAge & flag)) PREF_SetIntPref("mailnews.profile_age",(currentAge | flag)); } else { if (currentAge & flag) PREF_SetIntPref("mailnews.profile_age",(currentAge | ~flag)); } m_dirty = TRUE; } int32 MSG_Prefs::GetStartingMailNewsProfileAge() { Reload(); return m_startingMailNewsProfileAge; } void MSG_Prefs::Reload() { if (m_dirty) { // Temp vars we need to convey pref values. int32 intPref; char *strPref; int prefError = PREF_NOERROR; // Load in boolean prefs. PREF_GetBoolPref("mail.fixed_width_messages", &m_plainText); PREF_GetBoolPref("mail.auto_quote", &m_autoQuote); PREF_GetBoolPref("news.show_pretty_names", &m_showPrettyNames); PREF_GetBoolPref("news.notify.on", &m_newsNotifyOn); PREF_GetBoolPref("mail.cc_self", &m_mailBccSelf); PREF_GetBoolPref("news.cc_self", &m_newsBccSelf); PREF_GetBoolPref("mail.wrap_long_lines", &m_wraplonglines); HG63256 PREF_GetBoolPref("mail.inline_attachments", &m_noinline); PREF_GetBoolPref("mail.prompt_purge_threshhold", &m_purgeThreshholdEnabled); //Ask about compacting folders m_noinline = !m_noinline; // Load in int/enum prefs. intPref = (int) MSG_ItalicFont; // make italic if pref call fails PREF_GetIntPref("mail.quoted_style", &intPref); m_citationFont = (MSG_FONT) intPref; intPref = (int) MSG_NormalSize; // make normal size if pref call fails PREF_GetIntPref("mail.quoted_size", &intPref); m_citationFontSize = (MSG_CITATION_SIZE) intPref; intPref = 1; PREF_GetIntPref("mailnews.nav_crosses_folders", &intPref); m_navCrossesFolders = intPref; PREF_GetIntPref("mailnews.profile_age",&m_startingMailNewsProfileAge); intPref = 1; // default in case we fail prefError = PREF_GetIntPref("mail.show_headers", &intPref); switch (intPref) { case 0: m_headerstyle = MSG_ShowMicroHeaders; break; case 1: m_headerstyle = MSG_ShowSomeHeaders; break; case 2: m_headerstyle = MSG_ShowAllHeaders; break; default: XP_ASSERT(FALSE); break; } intPref = 0; // if no pref is set, return 0 - let the backend set the default port HG87635 // Server preference. // ### mwelch This used to use mail.use_imap, but we're switching // to mail.server_type as of 4.0b2. intPref = 0; // pop by default prefError = PREF_GetIntPref("mail.server_type", &intPref); m_mailInputType = intPref; m_mailServerIsIMAP = (m_mailInputType == 1); PREF_GetIntPref("mail.purge_threshhold", &m_purgeThreshhold); // Get string prefs. if (!m_freezeMailDirectory) { // m_localMailDirectory strPref = m_localMailDirectory; m_localMailDirectory = NULL; // Get the m_localMailDirectory pref. Passing in TRUE (expectFile) since the flag // tells the Mac-specific code to make use of the name (usually "\pMail") in the FSSpec // as well as the parent directory ID. GetXPDirPathPref("mail.directory", TRUE, &m_localMailDirectory); #if defined (XP_MAC) if (!m_localMailDirectory || !*m_localMailDirectory) { Assert_(FALSE); // can this happen? If not, remove this. char *newDirURL = NULL; // ### mwelch This is a hack, because the MacFE // doesn't set the mail root directory by default. FSSpec mailFolder = CPrefs::GetFolderSpec(CPrefs::MailFolder); newDirURL = CFileMgr::EncodedPathNameFromFSSpec(mailFolder, true); m_localMailDirectory = newDirURL; } #endif // It is still possible to have a NULL directory at this // point in the code. This is because the WinFE sets the default // mail directory preference after creating the prefs object. if (m_localMailDirectory) { // by arbitrary convention, the directory shouldn't have // a trailing slash int len = XP_STRLEN(m_localMailDirectory); if (len && m_localMailDirectory[len-1] == '/') m_localMailDirectory[len-1] = '\0'; #if !defined(XP_MAC) && !defined(XP_WIN) && !defined(XP_OS2) if (!strPref || strcmp(m_localMailDirectory, strPref)) { // Create the directory if it doesn't exist (Unix only) XP_StatStruct dirStat; if (-1 == XP_Stat(m_localMailDirectory, &dirStat, xpMailFolder)) XP_MakeDirectory (m_localMailDirectory, xpMailFolder); } #endif } if (strPref) XP_FREE(strPref); } HG93653 char onlineDir[256]; onlineDir[0] = '\0'; int stringSize = 256; PREF_GetCharPref("mail.imap.server_sub_directory", onlineDir, &stringSize); if ( *onlineDir && (*(onlineDir + XP_STRLEN(onlineDir) - 1) != '/') ) XP_STRCAT(onlineDir, "/"); if ((!m_OnlineImapSubDir) || ((m_OnlineImapSubDir) && XP_STRCMP(onlineDir, m_OnlineImapSubDir))) { FREEIF(m_OnlineImapSubDir); m_OnlineImapSubDir = XP_STRDUP(onlineDir); //if (XP_STRCMP(m_OnlineImapSubDir,"")) // only set it if it is not empty // IMAP_SetNamespacesFromPrefs(GetPopHost(), m_OnlineImapSubDir, "", ""); } PREF_GetBoolPref("mailnews.searchServer", &m_searchServer); PREF_GetBoolPref("mailnews.searchSubFolders", &m_searchSubFolders); PREF_GetBoolPref("mailnews.confirm.moveFoldersToTrash", &m_confirmMoveFoldersToTrash); FREEIF(m_customHeaders); PREF_CopyCharPref("mailnews.customHeaders",&m_customHeaders); FREEIF(m_citationColor); PREF_CopyCharPref("mail.citation_color", &m_citationColor); FREEIF(m_popHost); PREF_CopyCharPref("network.hosts.pop_server", &m_popHost); PREF_GetBoolPref("mail.imap.delete_is_move_to_trash", &m_ImapDeleteMoveToTrash); // Set the smtp and news (nntp) hosts. strPref = NULL; prefError = PREF_CopyCharPref("network.hosts.smtp_server", &strPref); if (prefError == PREF_NOERROR) NET_SetMailRelayHost(strPref); XP_FREEIF(strPref); // Refresh the username. strPref = NULL; prefError = PREF_CopyCharPref("mail.pop_name", &strPref); if (strPref) { NET_SetPopUsername(strPref); XP_FREE(strPref); } MSG_FolderInfo *folderInfo = NULL; for(int i=0;i<(int) num_of_header_prefs ;i++) { strPref = NULL; // Only look at the path if the "use it" bool flag is set! // Bug #45449 jrm XP_Bool doingFccPath = TRUE, wantsFccPath = FALSE; if (i == mail_default_fcc || i == mail_imap_sentmail_path) #ifdef XP_MAC PREF_GetBoolPref("mail.use_fcc", &wantsFccPath); #else wantsFccPath = TRUE; #endif else if (i == news_default_fcc || i == news_imap_sentmail_path) #ifdef XP_MAC PREF_GetBoolPref("news.use_fcc", &wantsFccPath); #else wantsFccPath = TRUE; #endif else doingFccPath = FALSE; if (doingFccPath && wantsFccPath) { prefError = GetXPDirPathPref(headerPrefNames[i], TRUE, &strPref); if ((prefError != PREF_NOERROR) || (!strPref) || (!*strPref) || (m_localMailDirectory && !XP_STRCMP(strPref, m_localMailDirectory))) { // Take the directory preference and add "Sent" to it. char *sent = XP_GetString(MK_MSG_SENT_L10N_NAME); XP_FREEIF(strPref); if (m_localMailDirectory && *m_localMailDirectory) strPref = PR_smprintf("%s/%s", m_localMailDirectory, sent); #ifdef XP_MAC // Still may need to ensure the file exists. SetXPMailFilePref(headerPrefNames[i], strPref); #endif } } else if (!doingFccPath) PREF_CopyCharPref(headerPrefNames[i], &strPref); FREEIF(m_defaultHeaders[i]); m_defaultHeaders[i] = strPref; } // Collect all the email addresses which specify the user. We'll need to know them // when checking the Reply recipients, or doing MDN receipts if (PREF_NOERROR == PREF_CopyCharPref ("mail.identity.useremail.aliases", &strPref)) { if (*strPref) // default is empty string. don't create an array for that { if (!m_emailAliases) m_emailAliases = new msg_StringArray (TRUE /*ownsMemory*/); if (m_emailAliases) { m_emailAliases->RemoveAll(); m_emailAliases->ImportTokenList (strPref); } } XP_FREE (strPref); } // Collect the email addresses which can't be considered aliases for this user. // This is intended to keep the email aliases feature from defeating the reply-to // header in messages char *replyTo = m_defaultHeaders[mail_identity_reply_to]; if (replyTo && *replyTo) { if (!m_emailAliasesNot) m_emailAliasesNot = new msg_StringArray (TRUE); if (m_emailAliasesNot) { char *addresses = NULL; int num = 0; if (0 != (num = MSG_ParseRFC822Addresses (replyTo, NULL, &addresses))) { // We're ignoring the name of the reply-to header, since the // actual address is all we care about for the alias calculation m_emailAliasesNot->RemoveAll(); for (int i = 0; i < num; i++) { m_emailAliasesNot->Add (addresses); addresses += XP_STRLEN (addresses) + 1; } } } } } m_dirty = FALSE; } int PR_CALLBACK MSG_PrefsChangeCallback(const char * prefName, void *data) { MSG_Prefs *prefs = (MSG_Prefs *) data; XP_Bool boolPref; char *strPref = NULL; int prefError = PREF_NOERROR; if (prefs) prefs->m_dirty = TRUE; // Depending on the preference being changed, // notify listeners as to the change. // Default headers first, since we have easy access to them. for (int i=0;i<(int) num_of_header_prefs;i++) { if (!XP_STRCMP(prefName, headerPrefNames[i])) { prefs->Notify(MSG_PrefsNotify::DefaultHeader); return PREF_NOERROR; } } if (!XP_STRNCMP(prefName, "netw", 4)) { if (!XP_STRCMP(prefName, "network.hosts.pop_server")) { NET_SetPopPassword(NULL); // invalidate pop3 password #54109 IMAP_SetPassword(NULL); PREF_SetCharPref("mail.pop_password", ""); prefs->Notify(MSG_PrefsNotify::PopHost); } else { // cause smtp and news host to be set to new values immediately if (prefs) prefs->Reload(); } } else if (!XP_STRNCMP(prefName, "mail", 4)) { if (!XP_STRCMP(prefName,"mail.fixed_width_messages")) prefs->Notify(MSG_PrefsNotify::PlaintextFont); else if (!XP_STRCMP(prefName,"mail.auto_quote")) prefs->Notify(MSG_PrefsNotify::AutoQuote); else if (!XP_STRCMP(prefName,"mail.strictly_mime")) { XP_Bool useQP = FALSE; prefError = PREF_GetBoolPref(prefName, &useQP); if (prefError == PREF_NOERROR) MIME_ConformToStandard(useQP); } else if (!XP_STRCMP(prefName,"mail.server_type")) { NET_SetPopPassword(NULL); // invalidate pop3 password #54109 IMAP_SetPassword(NULL); PREF_SetCharPref("mail.pop_password", ""); prefs->Notify(MSG_PrefsNotify::MailServerType); } HG32428 else if (!XP_STRNCMP(prefName, "mail.imap.server.", 17)) if (prefs->m_masterForBiff && prefs->m_masterForBiff->GetIMAPHostTable()) prefs->m_masterForBiff->GetIMAPHostTable()->UpdatePrefs(prefName); else if (!XP_STRCMP(prefName,"mail.cc_self")) prefs->Notify(MSG_PrefsNotify::DefaultBCC); else if (!XP_STRCMP(prefName,"mail.quoted_style")) prefs->Notify(MSG_PrefsNotify::CitationStyle); else if (!XP_STRCMP(prefName,"mail.quoted_size")) prefs->Notify(MSG_PrefsNotify::CitationStyle); else if (!XP_STRCMP(prefName,"mail.citation_color")) prefs->Notify(MSG_PrefsNotify::CitationStyle); else if (!XP_STRCMP(prefName,"mail.directory")) { char *dirTemp = NULL; // The WinFE has the habit of // setting the default mail.directory preference // after initializing the mail master. So, we test // the pref we get from GetXPDirPathPref (which follows // the logic of PREF_GetCharPref) against what we have, // if we have a preference at all. // Get the new directory preference. MSG_Prefs::GetXPDirPathPref("mail.directory", FALSE, &dirTemp); // Only put up an alert if we have a previous mail // directory specified, and if the new directory // doesn't match the one we already have. if (prefs && (prefs->m_localMailDirectory) && *(prefs->m_localMailDirectory) && dirTemp && strcmp(dirTemp, prefs->m_localMailDirectory)) { // ### mwelch Find any context we can // in order to display the alert. ugh. #ifndef XP_UNIX // X weirdness is such that their alert has to appear elsewhere MWContext *ctxt = XP_FindSomeContext(); FE_Alert(ctxt, XP_GetString(MK_MSG_MAIL_DIRECTORY_CHANGED)); #endif // don't reload directory pref prefs->m_freezeMailDirectory = TRUE; } else if ((prefs) && !(prefs->m_localMailDirectory && *prefs->m_localMailDirectory)) { // We are a new prefs object and couldn't find a user // pref when we first loaded. Reload immediately. prefs->Reload(); } // Clear out the FCC paths when the mail directory changes // so we don't keep FCCing into the old directory. We'll // create new system folders on restart. PREF_SetCharPref ("mail.default_fcc", ""); PREF_SetCharPref ("news.default_fcc", ""); // Free what got allocated when we got the dir pref. XP_FREEIF(dirTemp); } else if (!XP_STRCMP(prefName,"mail.imap.server_sub_directory")) prefs->Notify(MSG_PrefsNotify::ImapOnlineDir); else if (!XP_STRCMP(prefName,"mail.wrap_long_lines")) prefs->Notify(MSG_PrefsNotify::WrapLongLines); // Other prefs not covered in original MSG_Prefs object else if (!XP_STRCMP(prefName,"mail.leave_on_server")) { PREF_GetBoolPref(prefName, &boolPref); NET_LeavePopMailOnServer(boolPref); } else if (!XP_STRCMP(prefName, "mail.pop_name")) { // Refresh the username. prefError = PREF_CopyCharPref("mail.pop_name", &strPref); if (strPref) { HG82454 NET_SetPopUsername(strPref); XP_FREE(strPref); } // Act as if the server has changed. prefs->Notify(MSG_PrefsNotify::PopHost); } else if (!XP_STRCMP(prefName, "mail.remember_password")) { PREF_GetBoolPref(prefName, &boolPref); if (!boolPref) PREF_SetCharPref("mail.pop_password", ""); } else if (!XP_STRCMP(prefName,"mail.imap.delete_is_move_to_trash")) prefs->Notify(MSG_PrefsNotify::ChangeIMAPDeleteModel); } else // if (!XP_STRNCMP(prefName, "news", 4)) { if (!XP_STRCMP(prefName, "news.server_change_xaction")) { // Now we know that all news server prefs have been tweaked. // If the default news server isn't in the host table, add it. // (Thankfully, we just need to add it, and let the MSG_Master // do the searching.) MSG_Master *master = prefs->m_masterForBiff; if (master) { char *newsHost = NULL; int32 port = -1; XP_Bool xxx = FALSE; PREF_CopyCharPref("network.hosts.nntp_server", &newsHost); PREF_GetIntPref("news.server_port", &port); HG43788 if ((newsHost != NULL) && (port >= 0)) master->AddNewsHost(newsHost, xxx, port); } } else if (!XP_STRCMP(prefName,"news.cc_self")) prefs->Notify(MSG_PrefsNotify::DefaultBCC); } return PREF_NOERROR; } MSG_Prefs::MSG_Prefs() { m_citationFont = MSG_PlainFont; m_citationFontSize = MSG_Bigger; m_plainText = TRUE; m_mailServerIsIMAP = FALSE; HG98298 m_ImapDeleteMoveToTrash = TRUE; m_IMAPdirectory = NULL; m_headerstyle = MSG_ShowSomeHeaders; m_masterForBiff = NULL; m_notifying = FALSE; // Set up dirty flag. m_dirty = TRUE; m_freezeMailDirectory = FALSE; m_emailAliases = NULL; m_emailAliasesNot = NULL; // Set up prefs callback. PREF_RegisterCallback("mail.", &MSG_PrefsChangeCallback, this); PREF_RegisterCallback("news.", &MSG_PrefsChangeCallback, this); PREF_RegisterCallback("mailnews.", &MSG_PrefsChangeCallback, this); PREF_RegisterCallback("network.hosts.", &MSG_PrefsChangeCallback, this); // Load pref values from the prefs api. // (We can rely on the string members being NULL initially // since we derive from MSG_Zap.) Reload(); PREF_RegisterCallback ("mail.use_imap_sentmail", &MSG_UseImapSentmailPrefChanged, this); PREF_RegisterCallback ("mail.default_fcc", &MSG_FccPrefChanged, this); PREF_RegisterCallback ("mail.imap_sentmail_path", &MSG_FccPrefChanged, this); PREF_RegisterCallback ("news.use_imap_sentmail", &MSG_UseImapSentmailPrefChanged, this); PREF_RegisterCallback ("news.default_fcc", &MSG_FccPrefChanged, this); PREF_RegisterCallback ("news.imap_sentmail_path", &MSG_FccPrefChanged, this); PREF_RegisterCallback ("mail.server_type", &MSG_MailServerTypeChanged, this); PREF_RegisterCallback ("mail.default_drafts", &MSG_DraftsPrefChanged, this); PREF_RegisterCallback ("mail.default_templates", &MSG_TemplatesPrefChanged, this); // we are only interested in what this prefs value was at startup so initialize it // here rather than in Reload() m_startingMailNewsProfileAge = 0; PREF_GetIntPref("mailnews.profile_age",&m_startingMailNewsProfileAge); HG92734 } MSG_Prefs::~MSG_Prefs() { XP_ASSERT(m_numnotify == 0); FREEIF(m_localMailDirectory); FREEIF(m_citationColor); FREEIF(m_popHost); for (int i=0 ; iGetFolderInfo(tmp, FALSE); if (folderInfo && folderInfo->GetDepth() == 1) { if (NET_URL_Type(tmp) == IMAP_TYPE_URL && folderInfo->GetIMAPHost()) tmp = PR_smprintf("IMAP://%s@%s/%s", folderInfo->GetIMAPHost()->GetUserName(), folderInfo->GetName(), SENT_FOLDER_NAME); else if (folderInfo->GetMailFolderInfo()) tmp = PR_smprintf("%s/%s", folderInfo->GetMailFolderInfo()->GetPathname(), SENT_FOLDER_NAME); } } if (tmp) m_sentName = XP_STRDUP(tmp); return (tmp != NULL) ? XP_STRDUP(tmp) : 0; } else if (flag == MSG_FOLDER_FLAG_DRAFTS) { if (m_draftsName) return XP_STRDUP(m_draftsName); char *draftsName = NULL; PREF_CopyCharPref("mail.default_drafts", &draftsName); if (draftsName && *draftsName) { #ifdef XP_MAC #pragma warn_possunwant off #endif // XP_MAC if (m_masterForBiff && (folderInfo = m_masterForBiff->GetFolderInfo(draftsName, FALSE)) && folderInfo->GetDepth() == 1) { if (NET_URL_Type(draftsName) == IMAP_TYPE_URL && folderInfo->GetIMAPHost()) { char *newDraftsName = PR_smprintf("IMAP://%s@%s", folderInfo->GetIMAPHost()->GetUserName(), folderInfo->GetName()); if (newDraftsName) { XP_FREE(draftsName); draftsName = newDraftsName; } } StrAllocCat(draftsName, "/"); StrAllocCat(draftsName, DRAFTS_FOLDER_NAME); } #ifdef XP_MAC #pragma warn_possunwant reset #endif // XP_MAC m_draftsName = XP_STRDUP(draftsName); return draftsName; } // else fall through } else if (flag == MSG_FOLDER_FLAG_TEMPLATES) { if (m_templatesName) return XP_STRDUP(m_templatesName); char *templatesName = NULL; PREF_CopyCharPref("mail.default_templates", &templatesName); if (templatesName && *templatesName) { #ifdef XP_MAC #pragma warn_possunwant off #endif // XP_MAC if (m_masterForBiff && (folderInfo = m_masterForBiff->GetFolderInfo(templatesName, FALSE)) && folderInfo->GetDepth() == 1) { if (NET_URL_Type(templatesName) == IMAP_TYPE_URL && folderInfo->GetIMAPHost()) { char *newTemplatesName = PR_smprintf("IMAP://%s@%s", folderInfo->GetIMAPHost()->GetUserName(), folderInfo->GetName()); if (newTemplatesName) { XP_FREE(templatesName); templatesName = newTemplatesName; } } StrAllocCat(templatesName, "/"); StrAllocCat(templatesName, TEMPLATES_FOLDER_NAME); } #ifdef XP_MAC #pragma warn_possunwant reset #endif // XP_MAC m_templatesName = XP_STRDUP(templatesName); return templatesName; } // else fall through } const char *dir = GetFolderDirectory(); char *name; char *ptr; XP_ASSERT(dir); if (!dir) return 0; name = (char *) XP_ALLOC(XP_STRLEN(dir) + 30); if (!name) return 0; XP_STRCPY(name, dir); ptr = name + XP_STRLEN(name); if (ptr[-1] != '/') *ptr++ = '/'; #ifdef XP_MAC char* escapedName = NET_Escape( (flag == MSG_FOLDER_FLAG_INBOX ? INBOX_FOLDER_NAME : flag == MSG_FOLDER_FLAG_TRASH ? TRASH_FOLDER_NAME : flag == MSG_FOLDER_FLAG_QUEUE ? MSG_GetQueueFolderName() : flag == MSG_FOLDER_FLAG_DRAFTS ? DRAFTS_FOLDER_NAME : flag == MSG_FOLDER_FLAG_TEMPLATES ? TEMPLATES_FOLDER_NAME : "###"), URL_PATH); if (!escapedName) return NULL; XP_STRCPY(ptr, escapedName); XP_FREE(escapedName); #else XP_STRCPY(ptr, (flag == MSG_FOLDER_FLAG_INBOX ? INBOX_FOLDER_NAME : flag == MSG_FOLDER_FLAG_TRASH ? TRASH_FOLDER_NAME : flag == MSG_FOLDER_FLAG_QUEUE ? MSG_GetQueueFolderName() : flag == MSG_FOLDER_FLAG_DRAFTS ? DRAFTS_FOLDER_NAME : flag == MSG_FOLDER_FLAG_TEMPLATES ? TEMPLATES_FOLDER_NAME : "###")); #endif // Better have really found one. XP_ASSERT(XP_STRCMP(ptr, "###")); return name; } XP_Bool MSG_Prefs::CopyStringIfChanged(char** str, const char* value) { if (*str == NULL && value == NULL) return FALSE; if (*str && value && XP_STRCMP(*str, value) == 0) return FALSE; if (*str) delete [] *str; if (value) { *str = new char[XP_STRLEN(value) + 1]; if (*str) XP_STRCPY(*str, value); } else *str = NULL; return TRUE; } int MSG_Prefs::ConvertHeaderSetToSubscript(MSG_HEADER_SET header) { switch (header) { case MSG_REPLY_TO_HEADER_MASK: return 0; case MSG_BCC_HEADER_MASK: return 1; case MSG_FCC_HEADER_MASK: { XP_Bool use_imap_sentmail = FALSE; PREF_GetBoolPref("mail.use_imap_sentmail", &use_imap_sentmail); if (use_imap_sentmail) return 3; else return 2; } case MSG_NEWS_BCC_HEADER_MASK: return 4; case MSG_NEWS_FCC_HEADER_MASK: { XP_Bool use_imap_sentmail = FALSE; PREF_GetBoolPref("news.use_imap_sentmail", &use_imap_sentmail); if (use_imap_sentmail) return 6; else return 5; } default: XP_ASSERT (0); return -1; } } const char * msg_DefaultFolderName(uint32 flag) { switch (flag) { case MSG_FOLDER_FLAG_DRAFTS: return DRAFTS_FOLDER_NAME; case MSG_FOLDER_FLAG_SENTMAIL: return SENT_FOLDER_NAME; case MSG_FOLDER_FLAG_TEMPLATES: return TEMPLATES_FOLDER_NAME; default: XP_ASSERT(0); return ""; } } int msg_FolderPrefChanged(const char *prefName, void *msgPrefsVoid, uint32 flag) { char *folderPath = NULL; MSG_Prefs *msgPrefs = (MSG_Prefs*) msgPrefsVoid; MSG_Prefs::GetXPDirPathPref(prefName, TRUE, &folderPath); if (folderPath) { MSG_Master *master = msgPrefs->m_masterForBiff; // clear out calculated drafts,sent, and templates names XP_FREEIF(msgPrefs->m_draftsName); XP_FREEIF(msgPrefs->m_sentName); XP_FREEIF(msgPrefs->m_templatesName); if (master) { // Find all old magic folders and the new magic folder. For sent mail, // there can be 1 or 2 such folders. MSG_FolderInfoMail *newFolder = NULL; typedef MSG_FolderInfo* FInfoPtr; MSG_FolderInfo *folderList[3]; uint32 numFoldersToCheck = master->GetFolderTree()->GetFoldersWithFlag( flag, folderList, sizeof(folderList)/sizeof(FInfoPtr)); if (NET_URL_Type(folderPath) == IMAP_TYPE_URL) { char *host = NET_ParseURL(folderPath, GET_HOST_PART); char *name = NET_ParseURL(folderPath, GET_PATH_PART); char *owner = NET_ParseURL(folderPath, GET_USERNAME_PART); if (!name || !*name) { StrAllocCopy(name, "/"); StrAllocCat(name, msg_DefaultFolderName(flag)); } if ((!owner || !*owner) && master->GetIMAPHost(host)) { StrAllocCopy(owner, master->GetIMAPHost(host)->GetUserName()); } // name+1 skips the root "/" character newFolder = master->FindImapMailFolder(host, name+1, owner, FALSE); XP_FREEIF(host); XP_FREEIF(name); XP_FREEIF(owner); } else { const char *folderDir = msgPrefs->GetFolderDirectory(); if (!*folderPath) StrAllocCopy (folderPath, folderDir); const char *name = NET_URL_Type(folderPath) == MAILBOX_TYPE_URL ? folderPath + 8 : folderPath; if (XP_STRCMP(name, folderDir) == 0) { // Hmmm no folder name. Use default name. StrAllocCat(folderPath, "/"); StrAllocCat(folderPath, msg_DefaultFolderName(flag)); } newFolder = master->FindMailFolder(folderPath, FALSE /*createIfMissing*/); } if (newFolder) { XP_Bool newFolderIsSame = FALSE; MSG_FolderInfo** current = &folderList[0]; for (int i = 0; i < numFoldersToCheck; i++, current++) { if (*current == newFolder) { newFolderIsSame = TRUE; break; } } if (!newFolderIsSame) folderList[numFoldersToCheck++] = newFolder; } MSG_FolderInfo** current = &folderList[0]; for (int i = 0; i < numFoldersToCheck; i++, current++) { MSG_FolderInfoMail* f = (*current)->GetMailFolderInfo(); f->SetPrefFolderFlag(); // After changing the flag of a folder that's already in the tree, // you have to call QuickSort to maintain the sort order. // Possible improvement: sort only once per parent (even if // the folders are different, they may have the same parent). MSG_FolderInfo* parent = master->GetFolderTree()->FindParentOf(f); parent->GetSubFolders()->QuickSort(MSG_FolderInfoMail::CompareFolders); // Let the front end know that the flags have changed. The icon will // change. master->BroadcastFolderChanged(f); } } XP_FREE(folderPath); } return 0; } int PR_CALLBACK MSG_UseImapSentmailPrefChanged (const char *prefName, void *msgPrefsVoid) { XP_Bool bUseImap = FALSE; if ( XP_STRCMP(prefName, "mail.use_imap_sentmail") == 0 && PREF_NOERROR == PREF_GetBoolPref("mail.use_imap_sentmail", &bUseImap) ) { if (bUseImap) return MSG_FccPrefChanged ("mail.imap_sentmail_path", msgPrefsVoid); else return MSG_FccPrefChanged ("mail.default_fcc", msgPrefsVoid); } else if ( XP_STRCMP(prefName, "news.use_imap_sentmail") == 0 && PREF_NOERROR == PREF_GetBoolPref("news.use_imap_sentmail", &bUseImap) ) { if (bUseImap) return MSG_FccPrefChanged ("news.imap_sentmail_path", msgPrefsVoid); else return MSG_FccPrefChanged ("news.default_fcc", msgPrefsVoid); } return 0; } int PR_CALLBACK MSG_FccPrefChanged (const char *prefName, void *msgPrefsVoid) { return msg_FolderPrefChanged(prefName, msgPrefsVoid, MSG_FOLDER_FLAG_SENTMAIL); } int PR_CALLBACK MSG_DraftsPrefChanged (const char *prefName, void *msgPrefsVoid) { return msg_FolderPrefChanged(prefName, msgPrefsVoid, MSG_FOLDER_FLAG_DRAFTS); } int PR_CALLBACK MSG_TemplatesPrefChanged (const char *prefName, void *msgPrefsVoid) { return msg_FolderPrefChanged(prefName, msgPrefsVoid, MSG_FOLDER_FLAG_TEMPLATES); } int PR_CALLBACK MSG_MailServerTypeChanged (const char * /*prefName*/, void *msgPrefsVoid) { // Since we can't deal with Body filters in IMAP (in 4.0) we're going // to loop over all the filters and redirect them to the Subject header // // It would be nice to do this with the user's permission. // Don't do anything if we switched from POP to IMAP, only for IMAP to POP MSG_Master *master = ((MSG_Prefs*)msgPrefsVoid)->GetMasterForBiff(); int32 intPref = 0; // pop by default int prefError = PREF_GetIntPref("mail.server_type", &intPref); if (prefError == PREF_NOERROR && master) { int32 profileAge = master->GetPrefs()->GetStartingMailNewsProfileAge(); // Upgrade default IMAP host prefs if (!(profileAge & MSG_IMAP_DEFAULT_HOST_UPGRADE_FLAG) && intPref == 1) // we haven't upgraded the default host yet { // make the pop host look like an imap host. MSG_IMAPHost::UpgradeDefaultServerPrefs(master); return 0; } } else return 0; HG62437 if (master) master->CloseCachedImapConnections(); // Don't do anything if someone else is looking at the filter list if (!master || !master->AcquireRulesSemaphore(msgPrefsVoid)) return 0; // Don't do anything if we can't open the filter list MSG_FilterList *filterList = NULL; if (MSG_FilterList::Open (master, filterInbox, &filterList) != FilterError_Success || !filterList) { master->ReleaseRulesSemaphore (msgPrefsVoid); return 0; } XP_Bool filterListIsDirty = FALSE; int32 filterCount = 0; filterList->GetFilterCount(&filterCount); for (MSG_FilterIndex filterIndex = 0; filterIndex < filterCount; filterIndex++) { MSG_Filter *filter = NULL; if (filterList->GetFilterAt(filterIndex, &filter) == FilterError_Success && filter != NULL) { if (filter->GetType() == filterInboxRule) { MSG_Rule *rule = NULL; if (filter->GetRule(&rule) == FilterError_Success && rule != NULL) { MSG_SearchTermArray &terms = rule->GetTermList(); for (int i = 0; i < terms.GetSize(); i++) { MSG_SearchTerm *term = terms.GetAt(i); if (term && term->m_attribute == attribBody) { term->m_attribute = attribSubject; filterListIsDirty = TRUE; // Body searching can't do begins/ends with. Maybe it should... if (term->m_operator == opBeginsWith || term->m_operator == opEndsWith) term->m_operator = opContains; } } } } } } master->ReleaseRulesSemaphore (msgPrefsVoid); if (filterListIsDirty) MSG_CloseFilterList (filterList); else MSG_CancelFilterList (filterList); return 0; } msg_StringArray *MSG_Prefs::m_emailAliases = NULL; msg_StringArray *MSG_Prefs::m_emailAliasesNot = NULL; /*static*/ XP_Bool MSG_Prefs::IsEmailAddressAnAliasForMe (const char *addr) { // Does the address match one of the user's alias expressions (e.g. foo@*.netscape.com) if (m_emailAliasesNot) { // Some addresses can't be considered aliases. Right now, this is just used // for the Reply-To address, so that if you Reply All, your Reply-To address // will be included, or if you send yourself an MDN request, you'll get one back // // NB: this list is guaranteed to hold only addresses, not names, so we can strcmp // it without parsing it (here) for (int i = 0; i < m_emailAliasesNot->GetSize(); i++) if (!strcasecomp (addr, m_emailAliasesNot->GetAt(i))) return FALSE; } if (m_emailAliases) // master/prefs may not have been initialized yet { for (int i = 0; i < m_emailAliases->GetSize(); i++) { char *alias = (char*) m_emailAliases->GetAt(i); //Hacky cast: regexp API isn't const if (VALID_SXP == NET_RegExpValid (alias)) { // The alias is a regular expression, so send it into the regexp evaluator if (!NET_RegExpMatch ((char*) addr, alias, FALSE /*case sensitive*/)) return TRUE; } else { // The alias is not a regular expression, so just use a string compare if (!strcasecomp (addr, alias)) return TRUE; } } } return FALSE; }