gecko-dev/lib/libmsg/filters.cpp

1574 строки
44 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.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 "msg_filt.h" /* public API */
#include "pmsgfilt.h" /* private API */
#include "pmsgsrch.h" /* private Search API */
#include "msgimap.h"
#include "msgprefs.h"
#include "xpgetstr.h"
#include "msgstrob.h"
#include "imaphost.h"
extern "C"
{
extern int XP_FILTER_MOVE_TO_FOLDER;
extern int XP_FILTER_CHANGE_PRIORITY;
extern int XP_FILTER_DELETE;
extern int XP_FILTER_MARK_READ;
extern int XP_FILTER_KILL_THREAD;
extern int XP_FILTER_WATCH_THREAD;
}
const int16 kFileVersion = 6;
const int16 kFileVersionOldMoveTarget = 5;
#if defined(XP_WIN) || defined(XP_OS2)
const int16 kFileVersionAbsPath = 3;
#endif
const int16 kFileVersionOldStream = 2;
// This will return a zero length string ("") instead of NULL on
// empty strings. If this is a problem, we will need a way to
// distinguish memory allocation failures from empty strings.
static int XP_FileReadAllocStr(char **str, XP_File fid)
{
int status;
int length;
if ((status = XP_FileRead(&length, sizeof(length), fid)) < 0)
return status;
*str = (char *) XP_ALLOC(length + 1);
if (*str != NULL)
{
if (length > 0)
status = XP_FileRead(*str, length, fid);
(*str)[length] = '\0';
}
return status;
}
// ------------ FilterList methods ------------------
MSG_FilterError MSG_OpenFilterList(MSG_Master *master, MSG_FilterType type, MSG_FilterList **filterList)
{
return MSG_FilterList::Open(master, type, NULL, NULL, filterList);
}
MSG_FilterError MSG_OpenFolderFilterList(MSG_Pane *pane, MSG_FolderInfo *folder, MSG_FilterType type, MSG_FilterList **filterList)
{
return MSG_FilterList::Open(pane->GetMaster(), type, pane, folder, filterList);
}
MSG_FilterError MSG_OpenFolderFilterListFromMaster(MSG_Master *master, MSG_FolderInfo *folder, MSG_FilterType type, MSG_FilterList **filterList)
{
return MSG_FilterList::Open(master, type, NULL, folder, filterList);
}
MSG_FilterError MSG_FilterList::Open(MSG_Master *master, MSG_FilterType type, MSG_FilterList **filterList)
{
return MSG_FilterList::Open(master, type, NULL, NULL, filterList);
}
// static method to open a filter list from persistent storage
MSG_FilterError MSG_FilterList::Open(MSG_Master *master, MSG_FilterType type, MSG_Pane *pane, MSG_FolderInfo *folderInfo, MSG_FilterList **filterList)
{
MSG_FilterError err = FilterError_Success;
XP_File fid;
XP_StatStruct outStat;
MSG_FilterList *newFilterList;
if (type != filterInbox
&& type != filterNews)
return FilterError_InvalidFilterType;
if (NULL == filterList)
return FilterError_NullPointer;
newFilterList = new MSG_FilterList;
if (newFilterList == NULL)
return FilterError_OutOfMemory;
newFilterList->m_master = master;
// hack up support for news filters by checking the current folder of the pane and massaging input params.
if (pane != NULL && folderInfo == NULL)
{
folderInfo = pane->GetFolder();
if (folderInfo)
{
if (folderInfo->IsNews())
type = filterNews;
}
}
newFilterList->m_folderInfo = folderInfo;
newFilterList->m_pane = pane;
*filterList = newFilterList;
const char *upgradeIMAPFiltersDestFileName = 0;
if (type == filterNews)
{
MSG_FolderInfoNews *newsFolder = folderInfo->GetNewsFolderInfo();
if (newsFolder)
newFilterList->m_filterFileName = newsFolder->GetXPRuleFileName();
newFilterList->m_fileType = xpNewsSort;
}
else
{
MSG_IMAPFolderInfoMail *imapMailFolder = (folderInfo) ? folderInfo->GetIMAPFolderInfoMail() : (MSG_IMAPFolderInfoMail *)NULL;
newFilterList->m_filterFileName = "";
newFilterList->m_fileType = xpMailSort;
if (imapMailFolder)
{
MSG_IMAPHost *defaultHost = imapMailFolder->GetMaster()->GetIMAPHostTable()->GetDefaultHost();
if (imapMailFolder->GetIMAPHost() == defaultHost)
{
XP_Bool defaultHostFiltersExist = !XP_Stat(imapMailFolder->GetIMAPHost()->GetHostName(), &outStat, newFilterList->m_fileType);
if (!defaultHostFiltersExist)
upgradeIMAPFiltersDestFileName = imapMailFolder->GetIMAPHost()->GetHostName();
}
if (!upgradeIMAPFiltersDestFileName)
newFilterList->m_filterFileName = imapMailFolder->GetIMAPHost()->GetHostName();
}
}
if (XP_Stat(newFilterList->m_filterFileName, &outStat, newFilterList->m_fileType))
{
// file must not exist - no rules, we're done.
return FilterError_Success;
}
fid = XP_FileOpen(newFilterList->m_filterFileName, newFilterList->m_fileType, XP_FILE_READ_BIN);
if (fid)
{
err = newFilterList->LoadTextFilters(fid);
XP_FileClose(fid);
// if the file version changed, save it out right away.
if (newFilterList->GetVersion() != kFileVersion || upgradeIMAPFiltersDestFileName)
{
if (upgradeIMAPFiltersDestFileName)
newFilterList->m_filterFileName = upgradeIMAPFiltersDestFileName;
newFilterList->Close();
}
}
else
{
err = FilterError_FileError;
}
return err;
}
extern "C" MSG_FolderInfo *MSG_GetFolderInfoForFilterList(MSG_FilterList *filterList)
{
return filterList ? filterList->GetFolderInfo() : (MSG_FolderInfo *)NULL;
}
typedef struct
{
FilterFileAttrib attrib;
const char *attribName;
} FilterFileAttribEntry;
FilterFileAttribEntry FilterFileAttribTable[] =
{
{filterAttribNone, ""},
{filterAttribVersion, "version"},
{filterAttribLogging, "logging"},
{filterAttribName, "name"},
{filterAttribEnabled, "enabled"},
{filterAttribDescription, "description"},
{filterAttribType, "type"},
{filterAttribScriptFile, "scriptName"},
{filterAttribAction, "action"},
{filterAttribActionValue, "actionValue"},
{filterAttribCondition, "condition"}
};
// If we want to buffer file IO, wrap it in here.
char MSG_FilterList::ReadChar(XP_File fid)
{
char newChar;
int status = XP_FileRead(&newChar, sizeof(newChar), fid);
return (status > 0) ? newChar : (char) -1;
}
XP_Bool MSG_FilterList::IsWhitespace(char ch)
{
return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
}
char MSG_FilterList::SkipWhitespace(XP_File fid)
{
char ch;
do
{
ch = ReadChar(fid);
} while (IsWhitespace(ch));
return ch;
}
XP_Bool MSG_FilterList::StrToBool(const char *str)
{
return !XP_STRCASECMP(str, "yes");
}
char MSG_FilterList::LoadAttrib(XP_File fid, FilterFileAttrib &attrib)
{
char attribStr[100];
char curChar;
curChar = SkipWhitespace(fid);
int i;
for (i = 0; i + 1 < sizeof(attribStr); )
{
if (curChar == (char) -1 || IsWhitespace(curChar) || curChar == '=')
break;
attribStr[i++] = curChar;
curChar = ReadChar(fid);
}
attribStr[i] = '\0';
for (int tableIndex = 0; tableIndex < sizeof(FilterFileAttribTable) / sizeof(FilterFileAttribTable[0]); tableIndex++)
{
if (!XP_STRCASECMP(attribStr, FilterFileAttribTable[tableIndex].attribName))
{
attrib = FilterFileAttribTable[tableIndex].attrib;
break;
}
}
return curChar;
}
const char *MSG_FilterList::GetStringForAttrib(FilterFileAttrib attrib)
{
for (int tableIndex = 0; tableIndex < sizeof(FilterFileAttribTable) / sizeof(FilterFileAttribTable[0]); tableIndex++)
{
if (attrib == FilterFileAttribTable[tableIndex].attrib)
return FilterFileAttribTable[tableIndex].attribName;
}
return NULL;
}
MSG_FilterError MSG_FilterList::LoadValue(XP_File fid, XPStringObj &value)
{
char valueStr[100];
char curChar;
value = "";
curChar = SkipWhitespace(fid);
if (curChar != '"')
{
XP_ASSERT(FALSE);
return FilterError_FileError;
}
curChar = ReadChar(fid);
for (int i = 0; i + 2 < sizeof(valueStr); )
{
if (curChar == '\\')
{
char nextChar = ReadChar(fid);
if (nextChar == '"')
curChar = '"';
else if (nextChar == '\\') // replace "\\" with "\"
{
curChar = ReadChar(fid);
}
else
{
valueStr[i++] = curChar;
curChar = nextChar;
}
}
else
{
if (curChar == (char) -1 || curChar == '"' || curChar == '\n' || curChar == '\r')
{
valueStr[i] = '\0';
if (XP_STRLEN(value))
value += (const char *)valueStr;
else
value = (const char *) valueStr;
break;
}
}
valueStr[i++] = curChar;
curChar = ReadChar(fid);
if (i + 2 >= sizeof(valueStr))
{
valueStr[i] = '\0';
if (XP_STRLEN(value))
value += (const char *)valueStr;
else
value = (const char *) valueStr;
i = 0;
}
}
return FilterError_Success;
}
MSG_FilterError MSG_FilterList::LoadTextFilters(XP_File fid)
{
MSG_FilterError err = FilterError_Success;
FilterFileAttrib attrib;
// We'd really like to move lot's of these into the objects that they refer to.
XP_FileSeek(fid, 0, SEEK_SET);
do
{
XPStringObj value;
char curChar = LoadAttrib(fid, attrib);
if (attrib == filterAttribNone)
break;
err = LoadValue(fid, value);
if (err != FilterError_Success)
break;
switch(attrib)
{
case filterAttribNone:
break;
case filterAttribVersion:
m_fileVersion = XP_ATOI(value);
break;
case filterAttribLogging:
m_loggingEnabled = StrToBool(value);
break;
case filterAttribName:
{
MSG_Filter *filter = new MSG_Filter;
if (filter == NULL)
{
err = FilterError_OutOfMemory;
break;
}
filter->SetFilterList(this);
filter->SetName(value);
m_curFilter = filter;
m_filters.Add(filter);
}
break;
case filterAttribEnabled:
if (m_curFilter)
m_curFilter->SetEnabled(StrToBool(value));
break;
case filterAttribDescription:
if (m_curFilter)
m_curFilter->SetDescription(value);
break;
case filterAttribType:
if (m_curFilter)
{
m_curFilter->SetType((MSG_FilterType) XP_ATOI(value));
if (!m_curFilter->IsScript())
{
m_curFilter->m_filter.m_rule = new MSG_Rule(m_curFilter);
if (m_curFilter->m_filter.m_rule == NULL)
err = FilterError_OutOfMemory;
}
}
break;
case filterAttribScriptFile:
if (m_curFilter)
m_curFilter->SetFilterScript(value);
break;
case filterAttribAction:
m_curFilter->m_filter.m_rule->m_action.m_type = MSG_Rule::GetActionForFilingStr(value);
break;
case filterAttribActionValue:
if (m_curFilter->m_filter.m_rule->m_action.m_type == acMoveToFolder)
err = m_curFilter->m_filter.m_rule->ConvertMoveToFolderValue((const char *) value);
else if (m_curFilter->m_filter.m_rule->m_action.m_type == acChangePriority)
m_curFilter->m_filter.m_rule->SetAction(m_curFilter->m_filter.m_rule->m_action.m_type, (void *) (int32) MSG_GetPriorityFromString(value));
break;
case filterAttribCondition:
err = ParseCondition(value);
break;
}
} while (attrib != filterAttribNone);
return err;
}
// parse condition like "(subject, contains, fred) AND (body, isn't, "foo)")"
// values with close parens will be quoted.
// what about values with close parens and quotes? e.g., (body, isn't, "foo")")
// I guess interior quotes will need to be escaped - ("foo\")")
// which will get written out as (\"foo\\")\") and read in as ("foo\")"
MSG_FilterError MSG_FilterList::ParseCondition(const char *value)
{
XP_Bool done = FALSE;
MSG_FilterError err = FilterError_Success;
const char *curPtr = value;
while (!done)
{
// insert code to save the boolean operator if there is one for this search term....
const char *openParen = XP_STRCHR(curPtr, '(');
const char *orTermPos = XP_STRCHR(curPtr, 'O'); // determine if an "OR" appears before the openParen...
XP_Bool ANDTerm = TRUE;
if (orTermPos && orTermPos < openParen) // make sure OR term falls before the '('
ANDTerm = FALSE;
char *termDup = NULL;
if (openParen)
{
XP_Bool foundEndTerm = FALSE;
XP_Bool inQuote = FALSE;
for (curPtr = openParen +1; *curPtr; curPtr++)
{
if (*curPtr == '\\' && *(curPtr + 1) == '"')
curPtr++;
else if (*curPtr == ')' && !inQuote)
{
foundEndTerm = TRUE;
break;
}
else if (*curPtr == '"')
inQuote = !inQuote;
}
if (foundEndTerm)
{
int termLen = curPtr - openParen - 1;
termDup = (char *) XP_ALLOC(termLen + 1);
if (termDup)
XP_STRNCPY_SAFE(termDup, openParen + 1, termLen + 1);
else
{
err = FilterError_OutOfMemory;
break;
}
}
}
else
break;
if (termDup)
{
MSG_SearchTerm *newTerm = new MSG_SearchTerm;
if (newTerm)
newTerm->m_booleanOp = ANDTerm ? MSG_SearchBooleanAND : MSG_SearchBooleanOR;
if (newTerm->DeStreamNew(termDup, XP_STRLEN(termDup)) == SearchError_Success)
m_curFilter->m_filter.m_rule->GetTermList().Add(newTerm);
FREEIF(termDup);
}
else
break;
}
return err;
}
MSG_FilterError MSG_FilterList::WriteIntAttr(XP_File fid, FilterFileAttrib attrib, int value)
{
const char *attribStr = GetStringForAttrib(attrib);
if (attribStr)
XP_FilePrintf(fid, "%s=\"%d\"%s", attribStr, value, LINEBREAK);
return FilterError_Success;
}
MSG_FilterError MSG_FilterList::WriteStrAttr(XP_File fid, FilterFileAttrib attrib, const char *str)
{
char *escapedStr = NULL;
if (XP_STRCHR(str, '"'))
escapedStr = MSG_SearchTerm::EscapeQuotesInStr(str);
const char *attribStr = GetStringForAttrib(attrib);
if (attribStr)
XP_FilePrintf(fid, "%s=\"%s\"%s", attribStr, (escapedStr) ? escapedStr : str, LINEBREAK);
FREEIF(escapedStr);
return FilterError_Success;
}
MSG_FilterError MSG_FilterList::WriteBoolAttr(XP_File fid, FilterFileAttrib attrib, XP_Bool boolVal)
{
return WriteStrAttr(fid, attrib, (boolVal) ? "yes" : "no");
}
MSG_FilterError MSG_FilterList::SaveTextFilters(XP_File fid)
{
MSG_FilterError err = FilterError_Success;
const char *attribStr;
int32 filterCount = m_filters.GetSize();
attribStr = GetStringForAttrib(filterAttribVersion);
err = WriteIntAttr(fid, filterAttribVersion, kFileVersion);
err = WriteBoolAttr(fid, filterAttribLogging, m_loggingEnabled);
for (int i = 0; i < filterCount; i ++)
{
MSG_Filter *filter;
if (GetFilterAt(i, &filter) == FilterError_Success && filter != NULL)
{
filter->SetFilterList(this);
if ((err = filter->SaveToTextFile(fid)) != FilterError_Success)
break;
}
else
break;
}
return err;
}
MSG_FilterList::MSG_FilterList() : msg_OpaqueObject (m_expectedMagic)
{
m_loggingEnabled = FALSE;
m_master = NULL;
m_curFilter = NULL;
}
MSG_FilterList::~MSG_FilterList()
{
for (int32 i = 0; i < m_filters.GetSize(); i++)
{
MSG_Filter *filter;
if (GetFilterAt(i, &filter) == FilterError_Success)
delete filter;
}
}
uint32 MSG_FilterList::GetExpectedMagic ()
{
return m_expectedMagic;
}
// What should we do about file errors here? If we blow away the
// filter list even when we have an error, we can't let the user
// correct the problem. But if we don't blow it away, we'll have
// memory leaks.
MSG_FilterError MSG_CloseFilterList(MSG_FilterList *filterList)
{
MSG_FilterError err;
if (filterList == NULL)
return FilterError_NullPointer;
err = filterList->Close();
if (err == FilterError_Success)
delete filterList;
return err;
}
MSG_FilterError MSG_CancelFilterList(MSG_FilterList *filterList)
{
if (filterList == NULL)
return FilterError_NullPointer;
delete filterList;
return FilterError_Success;
}
MSG_FilterError MSG_SaveFilterList(MSG_FilterList *filterList)
{
if (filterList == NULL)
return FilterError_NullPointer;
return filterList->Close();
}
MSG_FilterError MSG_FilterList::Close()
{
MSG_FilterError err = FilterError_FileError;
XP_File fid;
XP_FileType retType;
const char *finalName = m_filterFileName;
char *tmpName = (finalName) ? FE_GetTempFileFor(NULL, finalName, m_fileType, &retType) : (char *)NULL;
if (!tmpName || !finalName)
return FilterError_OutOfMemory;
fid = XP_FileOpen(tmpName, xpTemporary,
XP_FILE_TRUNCATE_BIN);
if (fid)
{
err = SaveTextFilters(fid);
XP_FileClose(fid);
if (err == FilterError_Success)
{
int status = XP_FileRename(tmpName, xpTemporary, finalName, m_fileType);
XP_ASSERT(status >= 0);
}
}
FREEIF(tmpName);
return err;
}
MSG_FilterError MSG_GetFilterCount(MSG_FilterList *filterList, int32 *pCount)
{
return filterList->GetFilterCount(pCount);
}
MSG_FilterError MSG_FilterList::GetFilterCount(int32 *pCount)
{
if (pCount == NULL)
return FilterError_NullPointer;
*pCount = m_filters.GetSize();
return FilterError_Success;
}
MSG_FilterError MSG_GetFilterAt(MSG_FilterList *filterList, MSG_FilterIndex filterIndex, MSG_Filter **filter)
{
return filterList->GetFilterAt(filterIndex, filter);
}
MSG_FilterError MSG_FilterList::GetFilterAt(MSG_FilterIndex filterIndex, MSG_Filter **filter)
{
if (!m_filters.IsValidIndex(filterIndex))
return FilterError_InvalidIndex;
if (filter == NULL)
return FilterError_NullPointer;
*filter = (MSG_Filter *) m_filters.GetAt(filterIndex);
return FilterError_Success;
}
MSG_FilterError MSG_SetFilterAt(MSG_FilterList *filterList, MSG_FilterIndex filterIndex,
MSG_Filter *filter)
{
return filterList->SetFilterAt(filterIndex, filter);
}
MSG_FilterError MSG_FilterList::SetFilterAt(MSG_FilterIndex filterIndex, MSG_Filter *filter)
{
m_filters.SetAtGrow(filterIndex, filter);
return FilterError_Success;
}
MSG_FilterError MSG_RemoveFilterAt(MSG_FilterList *filterList, MSG_FilterIndex filterIndex)
{
return filterList->RemoveFilterAt(filterIndex);
}
MSG_FilterError MSG_FilterList::RemoveFilterAt(MSG_FilterIndex filterIndex)
{
m_filters.RemoveAt(filterIndex, 1);
return FilterError_Success;
}
MSG_FilterError MSG_InsertFilterAt(MSG_FilterList *filterList,
MSG_FilterIndex filterIndex, MSG_Filter *filter)
{
return filterList->InsertFilterAt(filterIndex, filter);
}
MSG_FilterError MSG_FilterList::InsertFilterAt(MSG_FilterIndex filterIndex, MSG_Filter *filter)
{
m_filters.InsertAt(filterIndex, filter);
return FilterError_Success;
}
MSG_FilterError MSG_MoveFilterAt(MSG_FilterList *filterList,
MSG_FilterIndex filterIndex, MSG_FilterMotion motion)
{
return filterList->MoveFilterAt(filterIndex, motion);
}
// Attempt to move the filter at index filterIndex in the specified direction.
// If motion not possible in that direction, we still return success.
// We could return an error if the FE's want to beep or something.
MSG_FilterError MSG_FilterList::MoveFilterAt(MSG_FilterIndex filterIndex,
MSG_FilterMotion motion)
{
MSG_Filter *tempFilter;
if (!m_filters.IsValidIndex(filterIndex))
return FilterError_InvalidIndex;
tempFilter = (MSG_Filter *) m_filters.GetAt(filterIndex);
if (motion == filterUp)
{
if (filterIndex == 0)
return FilterError_Success;
m_filters.SetAt(filterIndex, m_filters.GetAt(filterIndex - 1));
m_filters.SetAt(filterIndex - 1, tempFilter);
}
else if (motion == filterDown)
{
if (filterIndex + 1 > (MSG_FilterIndex) (m_filters.GetSize() - 1))
return FilterError_Success;
m_filters.SetAt(filterIndex, m_filters.GetAt(filterIndex + 1));
m_filters.SetAt(filterIndex + 1, tempFilter);
}
else
{
return FilterError_InvalidMotion;
}
return FilterError_Success;
}
MSG_FilterError MSG_EnableLogging(MSG_FilterList *filterList, XP_Bool enable)
{
if (filterList == NULL)
return FilterError_NullPointer;
filterList->EnableLogging(enable);
return FilterError_Success;
}
XP_Bool MSG_IsLoggingEnabled(MSG_FilterList *filterList)
{
if (filterList == NULL)
return FALSE;
return filterList->IsLoggingEnabled();
}
#ifdef DEBUG
void MSG_FilterList::Dump()
{
XP_Trace("%d filters\n", m_filters.GetSize());
for (int32 i = 0; i < m_filters.GetSize(); i++)
{
MSG_Filter *filter;
if (GetFilterAt(i, &filter) == FilterError_Success)
filter->Dump();
}
}
#endif
// ------------ End FilterList methods ------------------
// ------------ MSG_Filter methods ----------------------
MSG_Filter::MSG_Filter (MSG_FilterType type, char *name) : msg_OpaqueObject (m_expectedMagic)
{
m_filterName = XP_STRDUP(name);
m_type = type;
m_description = NULL;
m_enabled = FALSE;
if (IsRule())
m_filter.m_rule = new MSG_Rule(this);
else
m_filter.m_rule = NULL;
m_dontFileMe = FALSE;
}
MSG_Filter::MSG_Filter() : msg_OpaqueObject (m_expectedMagic)
{
m_filterName = NULL;
m_description = NULL;
m_dontFileMe = FALSE;
}
MSG_Filter::~MSG_Filter ()
{
FREEIF(m_filterName);
FREEIF(m_description);
if (IsRule())
delete m_filter.m_rule;
}
MSG_FilterError MSG_CreateFilter (MSG_FilterType type, char *name, MSG_Filter **result)
{
if (NULL == result || NULL == name)
return FilterError_NullPointer;
*result = new MSG_Filter(type, name);
if (*result == NULL)
return FilterError_OutOfMemory;
return FilterError_Success;
}
MSG_FilterError MSG_DestroyFilter(MSG_Filter *filter)
{
if (NULL == filter)
return FilterError_NullPointer;
delete filter;
return FilterError_Success;
}
MSG_FilterError MSG_Filter::SaveToTextFile(XP_File fid)
{
MSG_FilterError err;
err = m_filterList->WriteStrAttr(fid, filterAttribName, m_filterName);
err = m_filterList->WriteBoolAttr(fid, filterAttribEnabled, m_enabled);
err = m_filterList->WriteStrAttr(fid, filterAttribDescription, m_description);
err = m_filterList->WriteIntAttr(fid, filterAttribType, m_type);
if (IsScript())
err = m_filterList->WriteStrAttr(fid, filterAttribScriptFile, m_filter.m_scriptFileName);
else
err = m_filter.m_rule->SaveToTextFile(fid);
return err;
}
MSG_FilterError MSG_GetFilterType(MSG_Filter *filter, MSG_FilterType *filterType)
{
if (NULL == filterType || NULL == filter)
return FilterError_NullPointer;
*filterType = filter->GetType();
return FilterError_Success;
}
MSG_FilterError MSG_EnableFilter(MSG_Filter *filter, XP_Bool enable)
{
if (NULL == filter)
return FilterError_NullPointer;
filter->SetEnabled(enable);
return FilterError_Success;
}
MSG_FilterError MSG_IsFilterEnabled(MSG_Filter *filter, XP_Bool *enabled)
{
if (NULL == filter || NULL == enabled)
return FilterError_NullPointer;
*enabled = filter->GetEnabled();
return FilterError_Success;
}
MSG_FilterError MSG_GetFilterRule(MSG_Filter *filter, MSG_Rule ** result)
{
if (NULL == filter || NULL == result)
return FilterError_NullPointer;
return filter->GetRule(result);
}
MSG_FilterError MSG_Filter::GetRule(MSG_Rule **result)
{
if (!(m_type & (filterInboxRule | filterNewsRule)))
return FilterError_NotRule;
*result = m_filter.m_rule;
return FilterError_Success;
}
MSG_FilterError MSG_GetFilterName(MSG_Filter *filter, char **name)
{
return filter->GetName(name);
}
MSG_FilterError MSG_Filter::GetName(char **name)
{
*name = m_filterName;
return FilterError_Success;
}
MSG_FilterError MSG_GetFilterScript(MSG_Filter *filter, char **name)
{
if (NULL == filter || NULL == name)
return FilterError_NullPointer;
return filter->GetFilterScript(name);
}
MSG_FilterError MSG_Filter::GetFilterScript(char **name)
{
if (!(m_type & (filterInboxJavaScript | filterNewsJavaScript)))
return FilterError_NotScript;
*name = m_filter.m_scriptFileName;
return FilterError_Success;
}
MSG_FilterError MSG_SetFilterScript(MSG_Filter *filter, const char *name)
{
if (NULL == filter || NULL == name)
return FilterError_NullPointer;
return filter->SetFilterScript(name);
}
MSG_FilterError MSG_Filter::SetFilterScript(const char *name)
{
m_filter.m_scriptFileName = XP_STRDUP(name);
return FilterError_Success;
}
MSG_FilterError MSG_SetFilterDesc(MSG_Filter *filter, const char *desc)
{
if (NULL == filter)
return FilterError_NullPointer;
return filter->SetDescription(desc);
}
MSG_FilterError MSG_SetFilterName(MSG_Filter *filter, const char *name)
{
if (NULL == filter)
return FilterError_NullPointer;
return filter->SetName(name);
}
MSG_FilterError MSG_Filter::SetDescription(const char *desc)
{
FREEIF(m_description);
m_description = XP_STRDUP(desc);
return FilterError_Success;
}
MSG_FilterError MSG_Filter::SetName(const char *name)
{
FREEIF(m_filterName);
m_filterName = XP_STRDUP(name);
return FilterError_Success;
}
MSG_FilterError MSG_GetFilterDesc(MSG_Filter *filter, char **desc)
{
return filter->GetDescription(desc);
}
MSG_FilterError MSG_Filter::GetDescription(char **desc)
{
*desc = m_description;
return FilterError_Success;
}
#ifdef DEBUG
void MSG_Filter::Dump()
{
XP_Trace("filter %s type %d enabled %s\n", m_filterName, m_type,
m_enabled ? "TRUE" : "FALSE");
XP_Trace("desc = %s\n", m_description);
if (IsRule())
{
m_filter.m_rule->Dump();
}
else
{
XP_Trace("script file = %s\n", m_filter.m_scriptFileName);
}
}
#endif
// ------------ End MSG_Filter methods ------------------
MSG_Rule::MSG_Rule(MSG_Filter *filter) : msg_OpaqueObject(m_expectedMagic)
{
m_scope = NULL;
m_action.m_type = acNone;
m_action.m_originalServerPath = NULL;
m_filter = filter;
}
const char *MSG_Rule::kImapPrefix = "//imap:";
MSG_Rule::~MSG_Rule()
{
for (int i = 0; i < m_termList.GetSize(); i++)
{
MSG_SearchTerm * term = (MSG_SearchTerm *) m_termList.GetAt(i);
if (term == NULL)
continue;
delete term;
}
if (m_scope != NULL)
delete m_scope;
if (acMoveToFolder == m_action.m_type)
{
FREEIF(m_action.m_value.m_folderName);
FREEIF(m_action.m_originalServerPath);
}
}
MSG_FilterError MSG_Rule::SaveToTextFile(XP_File fid)
{
MSG_FilterError err = FilterError_Success;
MSG_Master *master = GetFilter()->GetMaster();
char *relativePath = NULL;
const char *folderDirectory;
MSG_FilterList *filterList = m_filter->GetFilterList();
err = filterList->WriteStrAttr(fid, filterAttribAction, GetActionFilingStr(m_action.m_type));
if (err != FilterError_Success)
return err;
switch(m_action.m_type)
{
case acMoveToFolder:
folderDirectory = master->GetPrefs()->GetFolderDirectory();
// if path starts off with folder directory, strip it off.
if (!XP_STRNCASECMP(m_action.m_value.m_folderName, folderDirectory, XP_STRLEN(folderDirectory)))
{
relativePath = m_action.m_value.m_folderName + XP_STRLEN(folderDirectory);
if (*relativePath == '/')
relativePath++;
err = filterList->WriteStrAttr(fid, filterAttribActionValue, relativePath);
}
else
{
if (!m_action.m_originalServerPath && m_action.m_value.m_folderName)
{
// attempt to convert full path to server path
MSG_IMAPFolderInfoMail *imapMailFolder = (filterList->GetFolderInfo()) ? filterList->GetFolderInfo()->GetIMAPFolderInfoMail() : (MSG_IMAPFolderInfoMail *)NULL;
MSG_IMAPFolderInfoContainer *imapContainer = (imapMailFolder) ? imapMailFolder->GetIMAPContainer() : GetFilter()->GetMaster()->GetImapMailFolderTree();
if (imapContainer)
{
MSG_IMAPFolderInfoMail *imapFolder = (MSG_IMAPFolderInfoMail *) imapContainer->FindMailPathname(m_action.m_value.m_folderName);
if (imapFolder)
m_action.m_originalServerPath = XP_STRDUP(imapFolder->GetOnlineName());
}
if (!m_action.m_originalServerPath)
m_action.m_originalServerPath = XP_STRDUP(""); // emergency fallback
}
if (m_action.m_originalServerPath)
{
char *imapTargetString = (char *)XP_ALLOC(XP_STRLEN(kImapPrefix) + XP_STRLEN(m_action.m_originalServerPath) + 1);
if (imapTargetString)
{
XP_STRCPY(imapTargetString, kImapPrefix);
XP_STRCAT(imapTargetString, m_action.m_originalServerPath);
err = filterList->WriteStrAttr(fid, filterAttribActionValue, imapTargetString);
XP_FREE(imapTargetString);
}
}
}
break;
case acChangePriority:
{
char priority[50];
MSG_GetUntranslatedPriorityName (m_action.m_value.m_priority, priority, sizeof(priority));
err = filterList->WriteStrAttr(fid, filterAttribActionValue, priority);
}
break;
default:
break;
}
// and here we begin - file out term list...
int searchIndex;
XPStringObj condition = " "; // do not inser the open paren....
for (searchIndex = 0; searchIndex < m_termList.GetSize() && err == FilterError_Success;
searchIndex++)
{
char *stream;
int16 length;
MSG_SearchError searchError;
MSG_SearchTerm * term = (MSG_SearchTerm *) m_termList.GetAt(searchIndex);
if (term == NULL)
continue;
if (XP_STRLEN(condition) > 1)
condition += ' ';
if (term->m_booleanOp == MSG_SearchBooleanOR)
condition += "OR (";
else
condition += "AND (";
searchError = term->EnStreamNew(&stream, &length);
if (searchError != SearchError_Success)
{
err = FilterError_SearchError;
break;
}
condition += stream;
condition += ')';
XP_FREE(stream);
}
if (err == FilterError_Success)
err = filterList->WriteStrAttr(fid, filterAttribCondition, condition);
return err;
}
MSG_FilterError MSG_Rule::ConvertMoveToFolderValue(const char *relativePath)
{
MSG_Master *master = GetFilter()->GetMaster();
const char *folderDirectory;
MSG_FilterList *filterList = m_filter->GetFilterList();
if (relativePath)
{
folderDirectory = master->GetPrefs()->GetFolderDirectory();
// ### dmb - check to see if the start of the dest folder name is the
// mail directory. If not, add the directory name back on. In general,
// the mail directory won't be there, so this is upgrade code.
// km add check to make sure we don't prepend the mail dir to an imap path
const char *imapDirectory = master->GetPrefs()->GetIMAPFolderDirectory();
if (GetFilter()->GetVersion() <= kFileVersionOldMoveTarget)
{
if (XP_STRNCASECMP(relativePath, folderDirectory, XP_STRLEN(folderDirectory)) &&
XP_STRNCASECMP(relativePath, imapDirectory, XP_STRLEN(imapDirectory)) )
{
m_action.m_value.m_folderName = PR_smprintf("%s/%s", master->GetPrefs()->GetFolderDirectory(), relativePath);
}
else
{
m_action.m_originalServerPath = NULL;
m_action.m_value.m_folderName = XP_STRDUP(relativePath);
// upgrade: save m_originalServerPath
MSG_IMAPFolderInfoMail *imapMailFolder = (filterList->GetFolderInfo()) ? filterList->GetFolderInfo()->GetIMAPFolderInfoMail() : (MSG_IMAPFolderInfoMail *)NULL;
MSG_IMAPFolderInfoContainer *imapContainer = (imapMailFolder) ? imapMailFolder->GetIMAPContainer() : GetFilter()->GetMaster()->GetImapMailFolderTree();
if (imapContainer)
{
MSG_IMAPFolderInfoMail *imapFolder = (MSG_IMAPFolderInfoMail *) imapContainer->FindMailPathname(relativePath);
if (imapFolder)
m_action.m_originalServerPath = XP_STRDUP(imapFolder->GetOnlineName());
}
if (!m_action.m_originalServerPath)
{
// did the user switch servers??
FREEIF(m_action.m_value.m_folderName);
m_action.m_value.m_folderName = XP_STRDUP("");
}
}
}
else
{
if (XP_STRNCMP(MSG_Rule::kImapPrefix, relativePath, XP_STRLEN(MSG_Rule::kImapPrefix)))
m_action.m_value.m_folderName = PR_smprintf("%s/%s", master->GetPrefs()->GetFolderDirectory(), relativePath);
else
{
m_action.m_originalServerPath = XP_STRDUP(relativePath + XP_STRLEN(MSG_Rule::kImapPrefix));
// convert the server path to the local full path
MSG_IMAPFolderInfoMail *imapMailFolder = (filterList->GetFolderInfo()) ? filterList->GetFolderInfo()->GetIMAPFolderInfoMail() : (MSG_IMAPFolderInfoMail *)NULL;
MSG_IMAPFolderInfoContainer *imapContainer = (imapMailFolder) ? imapMailFolder->GetIMAPContainer() : GetFilter()->GetMaster()->GetImapMailFolderTree();
MSG_IMAPFolderInfoMail *imapFolder = NULL;
if (imapContainer)
imapFolder = GetFilter()->GetMaster()->FindImapMailFolder(imapContainer->GetHostName(), relativePath + XP_STRLEN(MSG_Rule::kImapPrefix), NULL, FALSE);
if (imapFolder)
m_action.m_value.m_folderName = XP_STRDUP(imapFolder->GetPathname());
else
{
// did the user switch servers??
// we'll still save this filter, the filter code in the mail parser will handle this case
m_action.m_value.m_folderName = XP_STRDUP("");
}
}
}
#if defined(XP_WIN) || defined(XP_OS2)
if (GetFilter()->GetVersion() <= kFileVersionAbsPath)
{
XP_File folderFile = XP_FileOpen(m_action.m_value.m_folderName, xpMailFolder, XP_FILE_READ_BIN);
char *mailPart = m_action.m_value.m_folderName;
char *newFolderName = NULL;
while (!folderFile) // dest got messed up - try to fix by finding "mail" part of path
{ // preprending mail directory, and seeing if the folder exists.
if (newFolderName)
XP_FREE(newFolderName);
mailPart = strcasestr(mailPart + 1, "mail");
if (mailPart)
{
newFolderName = PR_smprintf("%s/%s", folderDirectory, mailPart + 5);
folderFile = XP_FileOpen(newFolderName, xpMailFolder, XP_FILE_READ_BIN);
}
else
{
newFolderName = XP_STRDUP(INBOX_FOLDER_NAME);
#ifdef DEBUG_bienvenu
FE_Alert(NULL, "Couldn't find destination for move rule");
#endif
break;
}
}
if (newFolderName)
{
XP_FREE(m_action.m_value.m_folderName);
m_action.m_value.m_folderName = newFolderName;
}
if (folderFile)
XP_FileClose(folderFile);
}
#endif
}
return FilterError_Success;
}
MSG_FilterError MSG_RuleAddTerm(MSG_Rule *rule,
MSG_SearchAttribute attrib, /* attribute for this term */
MSG_SearchOperator op, /* operator e.g. opContains */
MSG_SearchValue *value, /* value e.g. "Fred" */
XP_Bool booleanAND, /* set to true of boolean operator is AND */
char * arbitraryHeader) /* the "Other..." header the user manually provided the FE.
ignored by BE unless attrib is attribOtherHeader */
{
if (NULL == rule)
return FilterError_NullPointer;
return rule->AddTerm(attrib, op, value, booleanAND, arbitraryHeader);
}
MSG_FilterError MSG_Rule::AddTerm(
MSG_SearchAttribute attrib, /* attribute for this term */
MSG_SearchOperator op, /* operator e.g. opContains */
MSG_SearchValue *value, /* value e.g. "Fred" */
XP_Bool booleanAND, /* set to TRUE if boolean operator is AND */
char * arbitraryHeader) /* arbitrary header provided by user. ignored unless attrib = attribOtherHeader */
{
MSG_SearchTerm *newSearchTerm = new MSG_SearchTerm(attrib, op, value, booleanAND, arbitraryHeader);
if (newSearchTerm == NULL)
return FilterError_OutOfMemory;
m_termList.Add(newSearchTerm);
return FilterError_Success;
}
MSG_FilterError MSG_RuleGetNumTerms(MSG_Rule *rule, int32 *numTerms)
{
if (NULL == rule || NULL == numTerms)
return FilterError_NullPointer;
return rule->GetNumTerms(numTerms);
}
MSG_FilterError MSG_Rule::GetNumTerms(int32 *numTerms)
{
*numTerms = m_termList.GetSize();
return FilterError_Success;
}
MSG_FilterError MSG_RuleGetTerm(MSG_Rule *rule, int32 termIndex,
MSG_SearchAttribute *attrib, /* attribute for this term */
MSG_SearchOperator *op, /* operator e.g. opContains */
MSG_SearchValue *value, /* value e.g. "Fred" */
XP_Bool * booleanAND, /* Boolean AND operator */
char ** arbitraryHeader)
{
if (NULL == rule || NULL == attrib || NULL == op)
return FilterError_NullPointer;
return rule->GetTerm(termIndex, attrib, op, value, booleanAND, arbitraryHeader);
}
MSG_FilterError MSG_Rule::GetTerm(int32 termIndex,
MSG_SearchAttribute *attrib, /* attribute for this term */
MSG_SearchOperator *op, /* operator e.g. opContains */
MSG_SearchValue *value, /* value e.g. "Fred" */
XP_Bool * BooleanAND,
char ** arbitraryHeader)
{
// we're going to leave the first element empty, like search does
MSG_SearchTerm *term = (MSG_SearchTerm *) m_termList.GetAt(termIndex);
if (term == NULL)
return FilterError_InvalidIndex;
*attrib = term->m_attribute;
*op = term->m_operator;
*value = term->m_value;
if (BooleanAND)
* BooleanAND = term->IsBooleanOpAND();
if (arbitraryHeader)
* arbitraryHeader = term->m_arbitraryHeader;
return FilterError_Success;
}
MSG_FilterError MSG_RuleSetScope(MSG_Rule *rule, MSG_ScopeTerm *scope)
{
if (NULL == rule || NULL == scope)
return FilterError_NullPointer;
return FilterError_NotImplemented;
}
MSG_FilterError MSG_RuleGetScope(MSG_Rule *rule, MSG_ScopeTerm **scope)
{
if (NULL == rule || NULL == scope)
return FilterError_NullPointer;
return FilterError_NotImplemented;
}
/* if type is acChangePriority, value is a pointer to priority.
If type is acMoveToFolder, value is pointer to folder name.
Otherwise, value is ignored.
*/
MSG_FilterError MSG_RuleSetAction(MSG_Rule *rule, MSG_RuleActionType type, void *value)
{
if (NULL == rule) // value is sometimes legally NULL here...
return FilterError_NullPointer;
return rule->SetAction(type, value);
}
MSG_FilterError MSG_Rule::SetAction(MSG_RuleActionType type, void *value)
{
m_action.m_type = type;
switch (type)
{
case acMoveToFolder:
if (value == NULL)
return FilterError_NullPointer;
m_action.m_value.m_folderName = XP_STRDUP((char *) value);
// reset m_action.m_originalServerPath to NULL, the SaveToTextFile
// function will convert m_action.m_value.m_folderName to the right
// m_action.m_originalServerPath and write it out.
FREEIF(m_action.m_originalServerPath);
m_action.m_originalServerPath = NULL; // FREEIF does this but prevent
// future changes from breaking this
break;
case acChangePriority:
if (value == NULL)
return FilterError_NullPointer;
m_action.m_value.m_priority = (MSG_PRIORITY ) (int32) value;
break;
default:
break;
}
return FilterError_Success;
}
MSG_FilterError MSG_RuleGetAction(MSG_Rule *rule, MSG_RuleActionType *type, void **value)
{
if (NULL == rule || NULL == value || NULL == type)
return FilterError_NullPointer;
return rule->GetAction(type, value);
}
MSG_FilterError MSG_Rule::GetAction(MSG_RuleActionType *type, void **value)
{
*type = m_action.m_type;
switch (*type)
{
case acMoveToFolder:
* (char **) value = (m_action.m_value.m_folderName);
break;
case acChangePriority:
* (MSG_PRIORITY *) value = m_action.m_value.m_priority;
break;
default:
break;
}
return FilterError_Success;
}
/* help FEs manage menu choices in Filter dialog box */
extern "C"
MSG_FilterError MSG_GetRuleActionMenuItems(
MSG_FilterType type, /* type of filter */
MSG_RuleMenuItem *items, /* array of caller-allocated structs */
uint16 *maxItems) /* in- max array size; out- num returned */
{
if (NULL == items || NULL == maxItems)
return FilterError_NullPointer;
return MSG_Rule::GetActionMenuItems(type, items, maxItems);
}
// for each action, this table encodes the filterTypes that support the action.
struct RuleActionsTableEntry
{
MSG_RuleActionType action;
MSG_FilterType supportedTypes;
int xp_strIndex;
const char *actionFilingStr; /* used for filing out filters, don't translate! */
};
// Because some native C++ compilers can't initialize static objects with ints,
// we can't initialize this structure directly, so we have to do it in two phases.
static struct RuleActionsTableEntry ruleActionsTable[] =
{
{ acMoveToFolder, filterInbox, 0, /*XP_FILTER_MOVE_TO_FOLDER*/ "Move to folder" },
{ acChangePriority, filterInbox, 0, /*XP_FILTER_CHANGE_PRIORITY*/ "Change priority"},
{ acDelete, filterAll, 0, /*XP_FILTER_DELETE */ "Delete"},
{ acMarkRead, filterAll, 0, /*XP_FILTER_MARK_READ */ "Mark read"},
{ acKillThread, filterAll, 0, /*XP_FILTER_KILL_THREAD */ "Ignore thread"},
{ acWatchThread, filterAll, 0, /*XP_FILTER_WATCH_THREAD */ "Watch thread"}
};
/*static*/ void MSG_Rule::InitActionsTable()
{
if (ruleActionsTable[0].xp_strIndex == 0)
{
ruleActionsTable[0].xp_strIndex = XP_FILTER_MOVE_TO_FOLDER;
ruleActionsTable[1].xp_strIndex = XP_FILTER_CHANGE_PRIORITY;
ruleActionsTable[2].xp_strIndex = XP_FILTER_DELETE;
ruleActionsTable[3].xp_strIndex = XP_FILTER_MARK_READ;
ruleActionsTable[4].xp_strIndex = XP_FILTER_KILL_THREAD;
ruleActionsTable[5].xp_strIndex = XP_FILTER_WATCH_THREAD;
}
}
/*static */char *MSG_Rule::GetActionStr(MSG_RuleActionType action)
{
int numActions = sizeof(ruleActionsTable) / sizeof(ruleActionsTable[0]);
InitActionsTable();
for (int i = 0; i < numActions; i++)
{
if (action == ruleActionsTable[i].action)
return XP_GetString(ruleActionsTable[i].xp_strIndex);
}
return "";
}
/*static */const char *MSG_Rule::GetActionFilingStr(MSG_RuleActionType action)
{
int numActions = sizeof(ruleActionsTable) / sizeof(ruleActionsTable[0]);
for (int i = 0; i < numActions; i++)
{
if (action == ruleActionsTable[i].action)
return ruleActionsTable[i].actionFilingStr;
}
return "";
}
MSG_RuleActionType MSG_Rule::GetActionForFilingStr(const char *actionStr)
{
int numActions = sizeof(ruleActionsTable) / sizeof(ruleActionsTable[0]);
for (int i = 0; i < numActions; i++)
{
if (!XP_STRCASECMP(ruleActionsTable[i].actionFilingStr, actionStr))
return ruleActionsTable[i].action;
}
return acNone;
}
MSG_FilterError MSG_Rule::GetActionMenuItems(
MSG_FilterType type,
MSG_RuleMenuItem *items, /* array of caller-allocated structs */
uint16 *maxItems) /* in- max array size; out- num returned */
{
int numActions = sizeof(ruleActionsTable) / sizeof(ruleActionsTable[0]);
int numReturned = 0;
InitActionsTable();
for (int i = 0; i < numActions; i++)
{
if (numReturned >= *maxItems)
break;
if (type & ruleActionsTable[i].supportedTypes)
{
items[numReturned].attrib = ruleActionsTable[i].action;
char *name = XP_GetString(ruleActionsTable[i].xp_strIndex);
XP_STRNCPY_SAFE (items[numReturned].name, name, sizeof(items[numReturned].name));
numReturned++;
}
}
*maxItems = numReturned;
return FilterError_Success;
}
extern "C" MSG_FilterError MSG_GetFilterWidgetForAction( MSG_RuleActionType action,
MSG_SearchValueWidget *widget )
{
switch (action) {
case acMoveToFolder:
case acChangePriority:
*widget = widgetMenu;
break;
case acNone:
case acDelete:
case acMarkRead:
case acKillThread:
case acWatchThread:
default:
*widget = widgetNone;
break;
}
return FilterError_Success;
}
extern "C" MSG_SearchError MSG_GetValuesForAction( MSG_RuleActionType action,
MSG_SearchMenuItem *items,
uint16 *maxItems)
{
const MSG_PRIORITY aiPriorityValues[] = { MSG_NoPriority,
MSG_LowestPriority,
MSG_LowPriority,
MSG_NormalPriority,
MSG_HighPriority,
MSG_HighestPriority };
uint16 nPriorities = sizeof(aiPriorityValues) / sizeof(MSG_PRIORITY);
uint16 i;
switch (action) {
case acChangePriority:
for ( i = 0; i < nPriorities && i < *maxItems; i++ ) {
items[i].attrib = (int16) aiPriorityValues[i];
MSG_GetUntranslatedPriorityName( (MSG_PRIORITY) items[i].attrib,
items[i].name,
sizeof( items[i].name ) / sizeof(char) );
items[i].isEnabled = TRUE;
}
*maxItems = i;
if ( i == nPriorities ) {
return SearchError_Success;
} else {
return SearchError_ListTooSmall;
}
default:
*maxItems = 0;
return SearchError_InvalidAttribute;
}
}
void MSG_ViewFilterLog(MSG_Pane *pane)
{
char *filterLogName = WH_FileName("", xpMailFilterLog);
char *platformFileName = XP_PlatformFileToURL(filterLogName);
URL_Struct *url_struct = NET_CreateURLStruct(platformFileName, NET_NORMAL_RELOAD);
pane->GetURL(url_struct, TRUE);
FREEIF(filterLogName);
FREEIF(platformFileName);
}
#ifdef DEBUG
void MSG_Rule::Dump()
{
XP_Trace("action type = %d, \n", m_action.m_type);
switch (m_action.m_type)
{
case acMoveToFolder:
XP_Trace("dest folder = %s\n", m_action.m_value.m_folderName);
break;
case acChangePriority:
XP_Trace("result priority = %d\n", m_action.m_value.m_priority);
break;
default:
break;
}
for (int i = 0; i < m_termList.GetSize(); i++)
{
MSG_SearchTerm * term = (MSG_SearchTerm *) m_termList.GetAt(i);
if (term == NULL)
continue;
XP_Trace("search term attr = %d op = %d\n", term->m_attribute,
term->m_operator);
switch (term->m_attribute)
{
case attribDate:
XP_Trace("date = %ld\n", (long) term->m_value.u.date);
break;
case attribPriority:
XP_Trace("priority = %d\n", term->m_value.u.priority);
break;
case attribMsgStatus:
XP_Trace("msg_status = %lx\n", (long) term->m_value.u.msgStatus);
break;
case attribSender :
case attribSubject:
case attribBody:
case attribTo:
case attribCC:
case attribToOrCC:
XP_Trace("value = %s\n", term->m_value.u.string);
break;
default:
break;
}
}
}
#endif
/* ---------- Private implementation ---------- */
uint32 MSG_Rule::m_expectedMagic = 0x44444444;
uint32 MSG_Filter::m_expectedMagic = 0x55555555;
uint32 MSG_FilterList::m_expectedMagic = 0x66666666;