src/mui/MainMailList.c
/***************************************************************************
YAM - Yet Another Mailer
Copyright (C) 1995-2000 Marcel Beck
Copyright (C) 2000-2022 YAM Open Source Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
YAM Official Support Site : http://www.yam.ch
YAM OpenSource project : http://sourceforge.net/projects/yamos/
$Id$
Superclass: MUIC_NList
Description: NList class of the main mail list in the main window
***************************************************************************/
#include "MainMailList_cl.h"
#include <string.h>
#include <proto/dos.h>
#include <proto/muimaster.h>
#include <proto/timer.h>
#include <libraries/gadtools.h>
#include <mui/NList_mcc.h>
#include "SDI_hook.h"
#include "timeval.h"
#include "YAM.h"
#include "YAM_find.h"
#include "YAM_mainFolder.h"
#include "mui/ImageArea.h"
#include "AddressBook.h"
#include "BayesFilter.h"
#include "Busy.h"
#include "Config.h"
#include "Locale.h"
#include "MailList.h"
#include "MUIObjects.h"
#include "Themes.h"
#include "Debug.h"
/* CLASSDATA
struct Data
{
Object *context_menu;
Object *statusImage[SI_MAX];
char fromBuffer[SIZE_DEFAULT];
char replytoBuffer[SIZE_DEFAULT];
char date1Buffer[64]; // we don't use LEN_DATSTRING as OS3.1 anyway ignores it.
char date2Buffer[64]; // we don't use LEN_DATSTRING as OS3.1 anyway ignores it.
char statusBuffer[SIZE_DEFAULT];
char sizeBuffer[SIZE_SMALL];
char context_menu_title[SIZE_DEFAULT];
BOOL inSearchWindow;
LONG helpEntry;
};
*/
/* INCLUDE
#include "Themes.h"
*/
/* EXPORT
#define NUMBER_MAILLIST_COLUMNS 9
*/
/* Private Functions */
/// MailCompare
// Compares two messages
static int MailCompare(struct Mail *entry1, struct Mail *entry2, LONG column)
{
switch (column)
{
case 0:
{
// lets calculate each value
int status1 = 0;
int status2 = 0;
// We do not sort on other things than the real status and the Importance+Marked flag of
// the message because this would be confusing if you use "Status" as a sorting
// criteria within the folder config. Why should a MultiPart mail be sorted with
// other multipart messages? It`s more important to sort just for New/Unread/Read aso
// and then be able to sort as a second criteria for the date. Sorting the message
// depending on other stuff than importance will make it impossible to sort for
// status+date in the folder config. Perhaps we need to have a configuable way for
// sorting by status later, but this is future stuff..
status1 += hasStatusNew(entry1) ? 512 : 0;
status2 += hasStatusNew(entry2) ? 512 : 0;
status1 += !hasStatusRead(entry1) ? 256 : 0;
status2 += !hasStatusRead(entry2) ? 256 : 0;
status1 += !hasStatusError(entry1) ? 256 : 0;
status2 += !hasStatusError(entry2) ? 256 : 0;
status1 += hasStatusReplied(entry1) ? 64 : 0;
status2 += hasStatusReplied(entry2) ? 64 : 0;
status1 += hasStatusForwarded(entry1) ? 32 : 0;
status2 += hasStatusForwarded(entry2) ? 32 : 0;
status1 += hasStatusSent(entry1) ? 32 : 0;
status2 += hasStatusSent(entry2) ? 32 : 0;
status1 += hasStatusMarked(entry1) ? 8 : 0;
status2 += hasStatusMarked(entry2) ? 8 : 0;
status1 += (getImportanceLevel(entry1) == IMP_HIGH) ? 16 : 0;
status2 += (getImportanceLevel(entry2) == IMP_HIGH) ? 16 : 0;
return -(status1)+(status2);
}
break;
case 1:
{
struct Person *pe1;
struct Person *pe2;
char *addr1;
char *addr2;
if(isSentMailFolder(entry1->Folder))
{
pe1 = &entry1->To;
pe2 = &entry2->To;
}
else
{
pe1 = &entry1->From;
pe2 = &entry2->From;
}
// in case the user wants to take the additional pain
// of performing an addressbook lookup for every entry in the
// list we do it right here.
if(C->ABookLookup == TRUE)
{
struct ABookNode *abn1;
struct ABookNode *abn2;
if((abn1 = FindPersonInABook(&G->abook, pe1)) != NULL)
addr1 = abn1->RealName[0] != '\0' ? abn1->RealName : AddrName(*pe1);
else
addr1 = AddrName(*pe1);
if((abn2 = FindPersonInABook(&G->abook, pe2)) != NULL)
addr2 = abn2->RealName[0] != '\0' ? abn2->RealName : AddrName(*pe2);
else
addr2 = AddrName(*pe2);
}
else
{
addr1 = AddrName(*pe1);
addr2 = AddrName(*pe2);
}
return stricmp(addr1, addr2);
}
break;
case 2:
{
return stricmp(AddrName(entry1->ReplyTo), AddrName(entry2->ReplyTo));
}
break;
case 3:
{
return stricmp(MA_GetRealSubject(entry1->Subject), MA_GetRealSubject(entry2->Subject));
}
break;
case 4:
{
return CompareDates(&entry2->Date, &entry1->Date);
}
break;
case 5:
{
return entry1->Size-entry2->Size;
}
break;
case 6:
{
return strcmp(entry1->MailFile, entry2->MailFile);
}
break;
case 7:
{
return CmpTime(TIMEVAL(&entry2->transDate), TIMEVAL(&entry1->transDate));
}
break;
case 8:
{
return stricmp(entry1->MailAccount, entry2->MailAccount);
}
break;
case 9:
{
return stricmp(entry1->Folder->Name, entry2->Folder->Name);
}
break;
}
return 0;
}
///
/* Overloaded Methods */
/// OVERLOAD(OM_NEW)
OVERLOAD(OM_NEW)
{
ENTER();
if((obj = DoSuperNew(cl, obj,
MUIA_Font, C->FixedFontList ? MUIV_NList_Font_Fixed : MUIV_NList_Font,
MUIA_ShortHelp, TRUE,
MUIA_NList_MinColSortable, 0,
MUIA_NList_TitleClick, TRUE,
MUIA_NList_TitleClick2, TRUE,
MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
MUIA_NList_AutoVisible, TRUE,
MUIA_NList_Title, TRUE,
MUIA_NList_TitleSeparator, TRUE,
MUIA_NList_ActiveObjectOnClick, TRUE,
MUIA_NList_DefaultObjectOnClick, FALSE,
TAG_MORE, inittags(msg))) != NULL)
{
GETDATA;
BOOL handleDoubleClick;
ULONG i;
// determine whether double clicks are handled by ourself or by some external stuff
handleDoubleClick = GetTagData(ATTR(HandleDoubleClick), TRUE, inittags(msg));
data->inSearchWindow = GetTagData(ATTR(InSearchWindow), FALSE, inittags(msg));
// prepare the mail status images
data->statusImage[SI_ATTACH] = MakeImageObject("status_attach", G->theme.statusImages[SI_ATTACH]);
data->statusImage[SI_CRYPT] = MakeImageObject("status_crypt", G->theme.statusImages[SI_CRYPT]);
data->statusImage[SI_DELETE] = MakeImageObject("status_delete", G->theme.statusImages[SI_DELETE]);
data->statusImage[SI_DOWNLOAD] = MakeImageObject("status_download", G->theme.statusImages[SI_DOWNLOAD]);
data->statusImage[SI_ERROR] = MakeImageObject("status_error", G->theme.statusImages[SI_ERROR]);
data->statusImage[SI_FORWARD] = MakeImageObject("status_forward", G->theme.statusImages[SI_FORWARD]);
data->statusImage[SI_GROUP] = MakeImageObject("status_group", G->theme.statusImages[SI_GROUP]);
data->statusImage[SI_HOLD] = MakeImageObject("status_hold", G->theme.statusImages[SI_HOLD]);
data->statusImage[SI_MARK] = MakeImageObject("status_mark", G->theme.statusImages[SI_MARK]);
data->statusImage[SI_NEW] = MakeImageObject("status_new", G->theme.statusImages[SI_NEW]);
data->statusImage[SI_OLD] = MakeImageObject("status_old", G->theme.statusImages[SI_OLD]);
data->statusImage[SI_REPLY] = MakeImageObject("status_reply", G->theme.statusImages[SI_REPLY]);
data->statusImage[SI_REPORT] = MakeImageObject("status_report", G->theme.statusImages[SI_REPORT]);
data->statusImage[SI_SENT] = MakeImageObject("status_sent", G->theme.statusImages[SI_SENT]);
data->statusImage[SI_SIGNED] = MakeImageObject("status_signed", G->theme.statusImages[SI_SIGNED]);
data->statusImage[SI_SPAM] = MakeImageObject("status_spam", G->theme.statusImages[SI_SPAM]);
data->statusImage[SI_UNREAD] = MakeImageObject("status_unread", G->theme.statusImages[SI_UNREAD]);
data->statusImage[SI_URGENT] = MakeImageObject("status_urgent", G->theme.statusImages[SI_URGENT]);
data->statusImage[SI_WAITSEND] = MakeImageObject("status_waitsend", G->theme.statusImages[SI_WAITSEND]);
for(i = 0; i < SI_MAX; i++)
{
if(data->statusImage[i] != NULL)
DoMethod(obj, MUIM_NList_UseImage, data->statusImage[i], i, MUIF_NONE);
}
// only call MakeFormat if the user didn't specify NList_Format himself
if(GetTagData(MUIA_NList_Format, 0, inittags(msg)) == 0)
DoMethod(obj, METHOD(MakeFormat));
if(handleDoubleClick == TRUE)
DoMethod(obj, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, MUIV_Notify_Self, 2, METHOD(DoubleClicked), MUIV_TriggerValue);
DoMethod(obj, MUIM_Notify, MUIA_NList_SelectChange, TRUE, MUIV_Notify_Application, 2, MUIM_CallHook, &MA_ChangeSelectedHook);
// connect some notifies to the mainMailList group
DoMethod(obj, MUIM_Notify, MUIA_NList_TitleClick, MUIV_EveryTime, MUIV_Notify_Self, 4, MUIM_NList_Sort3, MUIV_TriggerValue, MUIV_NList_SortTypeAdd_2Values, MUIV_NList_Sort3_SortType_Both);
DoMethod(obj, MUIM_Notify, MUIA_NList_TitleClick2, MUIV_EveryTime, MUIV_Notify_Self, 4, MUIM_NList_Sort3, MUIV_TriggerValue, MUIV_NList_SortTypeAdd_2Values, MUIV_NList_Sort3_SortType_2);
DoMethod(obj, MUIM_Notify, MUIA_NList_SortType, MUIV_EveryTime, MUIV_Notify_Self, 3, MUIM_Set, MUIA_NList_TitleMark, MUIV_TriggerValue);
DoMethod(obj, MUIM_Notify, MUIA_NList_SortType2, MUIV_EveryTime, MUIV_Notify_Self, 3, MUIM_Set, MUIA_NList_TitleMark2, MUIV_TriggerValue);
}
RETURN((IPTR)obj);
return (IPTR)obj;
}
///
/// OVERLOAD(OM_DISPOSE)
OVERLOAD(OM_DISPOSE)
{
GETDATA;
int i;
// make sure that our context menus are also disposed
if(data->context_menu != NULL)
MUI_DisposeObject(data->context_menu);
for(i=0; i < SI_MAX; i++)
{
DoMethod(obj, MUIM_NList_UseImage, NULL, i, MUIF_NONE);
if(data->statusImage[i] != NULL)
{
MUI_DisposeObject(data->statusImage[i]);
data->statusImage[i] = NULL;
}
}
return DoSuperMethodA(cl,obj,msg);
}
///
/// OVERLOAD(OM_GET)
OVERLOAD(OM_GET)
{
IPTR *store = ((struct opGet *)msg)->opg_Storage;
switch(((struct opGet *)msg)->opg_AttrID)
{
case ATTR(SortOrderReversed):
{
LONG sortOrder[2];
sortOrder[0] = xget(obj, MUIA_NList_SortType);
sortOrder[1] = xget(obj, MUIA_NList_SortType2);
*store = (sortOrder[0] < 0 || sortOrder[1] < 0) ? TRUE : FALSE;
return TRUE;
}
}
return DoSuperMethodA(cl, obj, msg);
}
///
/// OVERLOAD(MUIM_NList_Construct)
OVERLOAD(MUIM_NList_Construct)
{
struct MUIP_NList_Construct *ncm = (struct MUIP_NList_Construct *)msg;
// Some words to why there are such empty constructor/destructor methods.
// Although NList's default method do basically the same and just return the
// supplied entry there is a big difference when it comes to large lists with
// more than 10000 entries. In this case every pointer comparison and every
// DoSuperMethod() call definitely has an impact on the overall performance.
// Hence we try to avoid as much overhead as possible. The difference is
// really noticable with large folders consisting of several ten thousand
// mails, which is not that uncommon if you keep old mails for more than a
// year and are subscribed to several quite active mailing lists.
// just return the supplied mail entry, no need to allocate or duplicate anything
return (IPTR)ncm->entry;
}
///
/// OVERLOAD(MUIM_NList_Destruct)
OVERLOAD(MUIM_NList_Destruct)
{
// nothing to free as we didn't allocate anything before
return (IPTR)0;
}
///
/// OVERLOAD(MUIM_NList_Compare)
// Message listview compare method
OVERLOAD(MUIM_NList_Compare)
{
struct MUIP_NList_Compare *ncm = (struct MUIP_NList_Compare *)msg;
struct Mail *entry1 = (struct Mail *)ncm->entry1;
struct Mail *entry2 = (struct Mail *)ncm->entry2;
LONG col1 = ncm->sort_type1 & MUIV_NList_TitleMark_ColMask;
LONG col2 = ncm->sort_type2 & MUIV_NList_TitleMark2_ColMask;
int cmp;
ENTER();
if(ncm->sort_type1 == (LONG)MUIV_NList_SortType_None)
{
RETURN(0);
return 0;
}
if(ncm->sort_type1 & MUIV_NList_TitleMark_TypeMask) cmp = MailCompare(entry2, entry1, col1);
else cmp = MailCompare(entry1, entry2, col1);
if(cmp != 0 || col1 == col2)
{
RETURN(cmp);
return cmp;
}
if(ncm->sort_type2 & MUIV_NList_TitleMark2_TypeMask) cmp = MailCompare(entry2, entry1, col2);
else cmp = MailCompare(entry1, entry2, col2);
RETURN(cmp);
return cmp;
}
///
/// OVERLOAD(MUIM_NList_Display)
OVERLOAD(MUIM_NList_Display)
{
GETDATA;
struct MUIP_NList_Display *ndm = (struct MUIP_NList_Display *)msg;
struct Mail *mail = (struct Mail *)ndm->entry;
ENTER();
if(mail != NULL)
{
if(mail->Folder != NULL)
{
// prepare the status char buffer
data->statusBuffer[0] = '\0';
ndm->strings[0] = data->statusBuffer;
// first we check which main status this mail has
// and put the leftmost mail icon accordingly.
if(hasStatusError(mail) || isPartialMail(mail)) strlcat(data->statusBuffer, SI_STR(SI_ERROR), sizeof(data->statusBuffer));
else if(isOutgoingFolder(mail->Folder)) strlcat(data->statusBuffer, SI_STR(SI_WAITSEND), sizeof(data->statusBuffer));
else if(isDraftsFolder(mail->Folder)) strlcat(data->statusBuffer, SI_STR(SI_HOLD), sizeof(data->statusBuffer));
else if(hasStatusSent(mail)) strlcat(data->statusBuffer, SI_STR(SI_SENT), sizeof(data->statusBuffer));
else if(hasStatusNew(mail)) strlcat(data->statusBuffer, SI_STR(SI_NEW), sizeof(data->statusBuffer));
else if(hasStatusRead(mail)) strlcat(data->statusBuffer, SI_STR(SI_OLD), sizeof(data->statusBuffer));
else strlcat(data->statusBuffer, SI_STR(SI_UNREAD), sizeof(data->statusBuffer));
// then we add the 2. level if icons with the additional mail information
// like importance, signed/crypted, report and attachment information
if(C->SpamFilterEnabled == TRUE && hasStatusSpam(mail)) strlcat(data->statusBuffer, SI_STR(SI_SPAM), sizeof(data->statusBuffer));
if(getImportanceLevel(mail) == IMP_HIGH) strlcat(data->statusBuffer, SI_STR(SI_URGENT), sizeof(data->statusBuffer));
if(isMP_CryptedMail(mail)) strlcat(data->statusBuffer, SI_STR(SI_CRYPT), sizeof(data->statusBuffer));
else if(isMP_SignedMail(mail)) strlcat(data->statusBuffer, SI_STR(SI_SIGNED), sizeof(data->statusBuffer));
if(isMP_ReportMail(mail)) strlcat(data->statusBuffer, SI_STR(SI_REPORT), sizeof(data->statusBuffer));
if(isMP_MixedMail(mail)) strlcat(data->statusBuffer, SI_STR(SI_ATTACH), sizeof(data->statusBuffer));
// and as the 3rd level of icons we put information on the secondary status
// like marked, replied, forwarded
if(hasStatusMarked(mail)) strlcat(data->statusBuffer, SI_STR(SI_MARK), sizeof(data->statusBuffer));
if(hasStatusReplied(mail)) strlcat(data->statusBuffer, SI_STR(SI_REPLY), sizeof(data->statusBuffer));
if(hasStatusForwarded(mail)) strlcat(data->statusBuffer, SI_STR(SI_FORWARD), sizeof(data->statusBuffer));
// now we generate the proper string for the mailaddress
if(hasMColSender(C->MessageCols) || data->inSearchWindow == TRUE)
{
BOOL toPrefix = FALSE;
struct Person *pe;
char *addr = NULL;
if(((isCustomMixedFolder(mail->Folder) || isTrashFolder(mail->Folder) || isSpamFolder(mail->Folder)) &&
(hasStatusSent(mail) || hasStatusError(mail))) || (data->inSearchWindow == TRUE && isSentMailFolder(mail->Folder)))
{
pe = &mail->To;
// put a To: prefix before our sender name
toPrefix = TRUE;
}
else
pe = isSentMailFolder(mail->Folder) ? &mail->To : &mail->From;
// in case the user wants to take the additional pain
// of performing an addressbook lookup for every mail in the
// list we do it right here.
if(C->ABookLookup == TRUE)
{
struct ABookNode *abn;
if((abn = FindPersonInABook(&G->abook, pe)) != NULL)
{
if(abn->RealName[0] != '\0')
addr = abn->RealName;
}
}
// if we didn't perform an address book lookup then we
// extract the address from the given information
if(addr == NULL)
addr = AddrName(*pe);
// lets put the string together
if(IsStrEmpty(addr) == FALSE)
{
snprintf(data->fromBuffer, sizeof(data->fromBuffer), "%s%s%s%s", isMultiRCPTMail(mail) ? SI_STR(SI_GROUP) : "",
toPrefix ? tr(MSG_MA_ToPrefix) : "",
addr,
isMultiSenderMail(mail) && toPrefix == FALSE ? ", ..." : "");
ndm->strings[1] = data->fromBuffer;
}
else
ndm->strings[1] = (char *)tr(MSG_MA_NO_RECIPIENTS);
}
// lets set all other fields now
if(data->inSearchWindow == FALSE && hasMColReplyTo(C->MessageCols))
{
if(isMultiReplyToMail(mail))
{
snprintf(data->replytoBuffer, sizeof(data->replytoBuffer), "%s, ...", AddrName(mail->ReplyTo));
ndm->strings[2] = data->replytoBuffer;
}
else
ndm->strings[2] = AddrName(mail->ReplyTo);
}
// then the Subject
if(IsStrEmpty(mail->Subject) == FALSE)
ndm->strings[3] = mail->Subject;
else
ndm->strings[3] = (char *)tr(MSG_MA_NO_SUBJECT);
if(hasMColDate(C->MessageCols) || data->inSearchWindow == TRUE)
{
DateStamp2String(data->date1Buffer, sizeof(data->date1Buffer), &mail->Date, C->DSListFormat, TZC_UTC2LOCAL);
ndm->strings[4] = data->date1Buffer;
}
if(hasMColSize(C->MessageCols) || data->inSearchWindow == TRUE)
{
ndm->strings[5] = data->sizeBuffer;
FormatSize(mail->Size, data->sizeBuffer, sizeof(data->sizeBuffer), SF_AUTO);
}
ndm->strings[6] = mail->MailFile;
// we first copy the Date Received/sent because this would probably be not
// set by all ppl and strcpy() is costy ;)
if((hasMColTransDate(C->MessageCols) && mail->transDate.Seconds > 0) || data->inSearchWindow == TRUE)
{
TimeVal2String(data->date2Buffer, sizeof(data->date2Buffer), &mail->transDate, C->DSListFormat, TZC_UTC2LOCAL);
ndm->strings[7] = data->date2Buffer;
}
ndm->strings[8] = mail->MailAccount;
// The Folder is just a dummy entry to serve the SearchMailWindow DisplayHook
ndm->strings[9] = mail->Folder->Name;
// depending on the mail status we set the font to bold or plain
if(hasStatusUnread(mail) || hasStatusNew(mail))
{
ndm->preparses[1] = C->StyleMailUnread;
ndm->preparses[2] = C->StyleMailUnread;
ndm->preparses[3] = C->StyleMailUnread;
ndm->preparses[4] = C->StyleMailUnread;
ndm->preparses[5] = C->StyleMailUnread;
ndm->preparses[6] = C->StyleMailUnread;
ndm->preparses[7] = C->StyleMailUnread;
ndm->preparses[8] = C->StyleMailUnread;
ndm->preparses[9] = C->StyleMailUnread;
}
else
{
ndm->preparses[1] = C->StyleMailRead;
ndm->preparses[2] = C->StyleMailRead;
ndm->preparses[3] = C->StyleMailRead;
ndm->preparses[4] = C->StyleMailRead;
ndm->preparses[5] = C->StyleMailRead;
ndm->preparses[6] = C->StyleMailRead;
ndm->preparses[7] = C->StyleMailRead;
ndm->preparses[8] = C->StyleMailRead;
ndm->preparses[9] = C->StyleMailRead;
}
}
else
{
// set some valid strings, even if there is no valid folder
ndm->strings[0] = (STRPTR)"";
ndm->strings[1] = (STRPTR)"";
ndm->strings[2] = (STRPTR)"";
ndm->strings[3] = (STRPTR)"";
ndm->strings[4] = (STRPTR)"";
ndm->strings[5] = (STRPTR)"";
ndm->strings[6] = (STRPTR)"";
ndm->strings[7] = (STRPTR)"";
ndm->strings[8] = (STRPTR)"";
}
}
else
{
struct Folder *folder = GetCurrentFolder();
// first we have to make sure that the mail window has a valid folder
if(data->inSearchWindow == TRUE || folder != NULL)
{
ndm->strings[0] = (STRPTR)tr(MSG_MA_TitleStatus);
// depending on the current folder and the parent object we
// display different titles for different columns
if(data->inSearchWindow == FALSE && isSentMailFolder(folder))
{
ndm->strings[1] = (STRPTR)tr(MSG_To);
ndm->strings[7] = (STRPTR)tr(MSG_DATE_SENT);
}
else if(data->inSearchWindow == TRUE || isCustomMixedFolder(folder) || isTrashFolder(folder) || isSpamFolder(folder))
{
ndm->strings[1] = (STRPTR)tr(MSG_FROMTO);
ndm->strings[7] = (STRPTR)tr(MSG_DATE_SNTRCVD);
}
else
{
ndm->strings[1] = (STRPTR)tr(MSG_From);
ndm->strings[7] = (STRPTR)tr(MSG_DATE_RECEIVED);
}
ndm->strings[2] = (STRPTR)tr(MSG_ReturnAddress);
ndm->strings[3] = (STRPTR)tr(MSG_Subject);
ndm->strings[4] = (STRPTR)tr(MSG_Date);
ndm->strings[5] = (STRPTR)tr(MSG_Size);
ndm->strings[6] = (STRPTR)tr(MSG_Filename);
ndm->strings[8] = (STRPTR)tr(MSG_MAILACCOUNT_TRANSFERRED);
// The Folder is just a dummy entry to serve the SearchMailWindow DisplayHook
ndm->strings[9] = (STRPTR)tr(MSG_Folder);
}
else
{
// set some valid strings, even if there is no valid folder
ndm->strings[0] = (STRPTR)tr(MSG_MA_TitleStatus);
ndm->strings[1] = (STRPTR)tr(MSG_From);
ndm->strings[2] = (STRPTR)tr(MSG_ReturnAddress);
ndm->strings[3] = (STRPTR)tr(MSG_Subject);
ndm->strings[4] = (STRPTR)tr(MSG_Date);
ndm->strings[5] = (STRPTR)tr(MSG_Size);
ndm->strings[6] = (STRPTR)tr(MSG_Filename);
ndm->strings[7] = (STRPTR)tr(MSG_DATE_RECEIVED);
ndm->strings[8] = (STRPTR)tr(MSG_MAILACCOUNT_TRANSFERRED);
}
}
RETURN(0);
return 0;
}
///
/// OVERLOAD(MUIM_NList_ContextMenuBuild)
OVERLOAD(MUIM_NList_ContextMenuBuild)
{
GETDATA;
struct MUIP_NList_ContextMenuBuild *m = (struct MUIP_NList_ContextMenuBuild *)msg;
struct Folder *fo;
// dispose the old context_menu if it still exists
if(data->context_menu != NULL)
{
MUI_DisposeObject(data->context_menu);
data->context_menu = NULL;
}
// if this was a RMB click on the titlebar we create our own special menu
if(m->ontop)
{
data->context_menu = MenustripObject,
MenuChild, MenuObjectT(tr(MSG_MA_CTX_MAILLIST)),
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Status), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 1, MUIA_Menuitem_Enabled, FALSE, MUIA_Menuitem_Checked, TRUE, MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_SenderRecpt), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 2, MUIA_Menuitem_Checked, hasMColSender(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_ReturnAddress), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 3, MUIA_Menuitem_Checked, hasMColReplyTo(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Subject), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 4, MUIA_Menuitem_Checked, hasMColSubject(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MessageDate), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 5, MUIA_Menuitem_Checked, hasMColDate(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Size), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 6, MUIA_Menuitem_Checked, hasMColSize(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Filename), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 7, MUIA_Menuitem_Checked, hasMColFilename(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_CO_DATE_SNTRCVD), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 8, MUIA_Menuitem_Checked, hasMColTransDate(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_CO_MAILACCOUNT_TRANSFERRED), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 9, MUIA_Menuitem_Checked, hasMColMailAccount(C->MessageCols),MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, NM_BARLABEL, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFWIDTH_THIS), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefWidth_This, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFWIDTH_ALL), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefWidth_All, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFORDER_THIS), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefOrder_This, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFORDER_ALL), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefOrder_All, End,
End,
End;
}
else if((fo = GetCurrentFolder()) != NULL)
{
struct MUI_NList_TestPos_Result res;
// Now lets find out which entry is under the mouse pointer
DoMethod(obj, MUIM_NList_TestPos, m->mx, m->my, &res);
if(res.entry >= 0)
{
struct Mail *mail = NULL;
DoMethod(obj, MUIM_NList_GetEntry, res.entry, &mail);
if(mail != NULL)
{
BOOL isSentMail = isSentMailFolder(fo);
BOOL isArchive = isArchiveFolder(fo);
BOOL hasattach = FALSE;
ULONG numSelected = 0;
struct Person *pers = isSentMail ? &mail->To : &mail->From;
char address[SIZE_LARGE];
Object *afterThis;
fo->LastActive = xget(obj, MUIA_NList_Active);
// Now we set this entry as active and make it visible
// in the center of our listview
if(fo->LastActive != res.entry)
DoMethod(obj, MUIM_NList_SetActive, res.entry, MUIV_NList_SetActive_Jump_Center);
if(isMultiPartMail(mail))
hasattach = TRUE;
DoMethod(obj, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Ask, &numSelected);
// now we create the menu title of the context menu
snprintf(data->context_menu_title, sizeof(data->context_menu_title), "%s: ", tr(isSentMail ? MSG_To : MSG_From));
strlcat(data->context_menu_title, BuildAddress(address, sizeof(address), pers->Address, pers->RealName), 20-strlen(data->context_menu_title) > 0 ? 20-strlen(data->context_menu_title) : 0);
strlcat(data->context_menu_title, "...", sizeof(data->context_menu_title));
data->context_menu = MenustripObject,
MenuChild, MenuObjectT(data->context_menu_title),
MenuChild, Menuitem(tr(MSG_MA_MREAD), NULL, TRUE, FALSE, MMEN_READ),
MenuChild, Menuitem(isDraftsFolder(fo) ? tr(MSG_MA_MEDIT) : tr(MSG_MA_MEDITASNEW), NULL, TRUE, FALSE, MMEN_EDIT),
MenuChild, Menuitem(tr(MSG_MA_MMOVE), NULL, TRUE, FALSE, MMEN_MOVE),
MenuChild, Menuitem(tr(MSG_MA_MCOPY), NULL, TRUE, FALSE, MMEN_COPY),
MenuChild, Menuitem(tr(MSG_MA_MARCHIVE), NULL, isArchive == FALSE, FALSE, MMEN_ARCHIVE),
MenuChild, Menuitem(tr(MSG_MA_MDelete), NULL, TRUE, FALSE, MMEN_DELETE),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_MPRINT), NULL, TRUE, FALSE, MMEN_PRINT),
MenuChild, Menuitem(tr(MSG_MA_MSAVE), NULL, TRUE, FALSE, MMEN_SAVE),
MenuChild, MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_Attachments),
MUIA_Menuitem_CopyStrings, FALSE,
MUIA_Menuitem_Enabled, hasattach,
MenuChild, Menuitem(tr(MSG_MA_MSAVEATT), NULL, hasattach, FALSE, MMEN_DETACH),
MenuChild, Menuitem(tr(MSG_MA_MDELETEATT), NULL, hasattach, FALSE, MMEN_DELETEATT),
End,
MenuChild, Menuitem(tr(MSG_MESSAGE_EXPORT), NULL, TRUE, FALSE, MMEN_EXPMSG),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_MNEW), NULL, TRUE, FALSE, MMEN_NEW),
MenuChild, Menuitem(tr(MSG_MA_MREPLY), NULL, TRUE, FALSE, MMEN_REPLY),
MenuChild, MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_MA_MFORWARD),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_MA_MFORWARD_ATTACH), NULL, TRUE, FALSE, MMEN_FORWARD_ATTACH),
MenuChild, Menuitem(tr(MSG_MA_MFORWARD_INLINE), NULL, TRUE, FALSE, MMEN_FORWARD_INLINE),
End,
MenuChild, Menuitem(tr(MSG_MA_MREDIRECT), NULL, !isSentMail, FALSE, MMEN_REDIRECT),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_MSAVEADDRESS), NULL, TRUE, FALSE, MMEN_SAVEADDR),
MenuChild, MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_MA_Select),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_MA_SELECTALL), NULL, TRUE, FALSE, MMEN_SELALL),
MenuChild, Menuitem(tr(MSG_MA_SELECTNONE), NULL, TRUE, FALSE, MMEN_SELNONE),
MenuChild, Menuitem(tr(MSG_MA_SELECTTOGGLE), NULL, TRUE, FALSE, MMEN_SELTOGG),
End,
MenuChild, MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_MA_SetStatus),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_MA_TOMARKED), NULL, numSelected >= 2 || !hasStatusMarked(mail), FALSE, MMEN_TOMARKED),
MenuChild, Menuitem(tr(MSG_MA_TOUNMARKED), NULL, numSelected >= 2 || hasStatusMarked(mail), FALSE, MMEN_TOUNMARKED),
MenuChild, Menuitem(tr(MSG_MA_TOREAD), NULL, !isSentMail && (numSelected >= 2 || hasStatusNew(mail) || hasStatusUnread(mail)), FALSE, MMEN_TOREAD),
MenuChild, afterThis = Menuitem(tr(MSG_MA_TOUNREAD), NULL, !isSentMail && (numSelected >= 2 || hasStatusRead(mail)), FALSE, MMEN_TOUNREAD),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_ALLTOREAD), NULL, !isSentMail, FALSE, MMEN_ALLTOREAD),
End,
MenuChild, Menuitem(tr(MSG_MA_ChangeSubj), NULL, TRUE, FALSE, MMEN_CHSUBJ),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_MSend), NULL, isOutgoingFolder(fo), FALSE, MMEN_SEND),
End,
End;
if(data->context_menu != NULL && C->SpamFilterEnabled == TRUE)
{
Object *spamItem;
Object *hamItem;
spamItem = Menuitem(tr(MSG_MA_TOSPAM), NULL, numSelected >= 2 || !hasStatusSpam(mail), FALSE, MMEN_TOSPAM);
hamItem = Menuitem(tr(MSG_MA_TONOTSPAM), NULL, numSelected >= 2 || hasStatusSpam(mail), FALSE, MMEN_TOHAM);
DoMethod(data->context_menu, MUIM_Family_Insert, hamItem, afterThis);
DoMethod(data->context_menu, MUIM_Family_Insert, spamItem, afterThis);
}
}
}
else
{
// for empty folders the same context menu as for the title bar is created
data->context_menu = MenustripObject,
MenuChild, MenuObjectT(tr(MSG_MA_CTX_MAILLIST)),
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Status), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 1, MUIA_Menuitem_Enabled, FALSE, MUIA_Menuitem_Checked, TRUE, MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_SenderRecpt), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 2, MUIA_Menuitem_Checked, hasMColSender(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_ReturnAddress), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 3, MUIA_Menuitem_Checked, hasMColReplyTo(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Subject), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 4, MUIA_Menuitem_Checked, hasMColSubject(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MessageDate), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 5, MUIA_Menuitem_Checked, hasMColDate(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Size), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 6, MUIA_Menuitem_Checked, hasMColSize(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_Filename), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 7, MUIA_Menuitem_Checked, hasMColFilename(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_CO_DATE_SNTRCVD), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 8, MUIA_Menuitem_Checked, hasMColTransDate(C->MessageCols), MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_CO_MAILACCOUNT_TRANSFERRED), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, 9, MUIA_Menuitem_Checked, hasMColMailAccount(C->MessageCols),MUIA_Menuitem_Checkit, TRUE, MUIA_Menuitem_Toggle, TRUE, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, NM_BARLABEL, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFWIDTH_THIS), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefWidth_This, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFWIDTH_ALL), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefWidth_All, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFORDER_THIS), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefOrder_This, End,
MenuChild, MenuitemObject, MUIA_Menuitem_Title, tr(MSG_MA_CTX_DEFORDER_ALL), MUIA_Menuitem_CopyStrings, FALSE, MUIA_UserData, MUIV_NList_Menu_DefOrder_All, End,
End,
End;
}
}
return (IPTR)data->context_menu;
}
///
/// OVERLOAD(MUIM_ContextMenuChoice)
OVERLOAD(MUIM_ContextMenuChoice)
{
struct MUIP_ContextMenuChoice *m = (struct MUIP_ContextMenuChoice *)msg;
ULONG result = 0;
ENTER();
switch(xget(m->item, MUIA_UserData))
{
// if the user selected a TitleContextMenu item
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
{
ULONG flag = (1 << (xget(m->item, MUIA_UserData)-1));
if(isFlagSet(C->MessageCols, flag))
clearFlag(C->MessageCols, flag);
else
setFlag(C->MessageCols, flag);
DoMethod(obj, METHOD(MakeFormat));
}
break;
// or other item out of the MailListContextMenu
case MMEN_READ: DoMethod(_app(obj), MUIM_CallHook, &MA_ReadMessageHook); break;
case MMEN_EDIT: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_EDIT, 0); break;
case MMEN_NEW: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_NEW, 0); break;
case MMEN_REPLY: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_REPLY, 0); break;
case MMEN_FORWARD_ATTACH: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_FORWARD_ATTACH, 0); break;
case MMEN_FORWARD_INLINE: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_FORWARD_INLINE, 0); break;
case MMEN_REDIRECT: DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_REDIRECT, 0); break;
case MMEN_SEND: DoMethod(_app(obj), MUIM_CallHook, &MA_SendHook, SENDMAIL_ACTIVE_USER); break;
case MMEN_CHSUBJ: DoMethod(_app(obj), MUIM_CallHook, &MA_ChangeSubjectHook); break;
case MMEN_TOUNREAD: DoMethod(_app(obj), MUIM_CallHook, &MA_SetStatusToHook, SFLAG_NONE, SFLAG_NEW|SFLAG_READ); break;
case MMEN_TOREAD: DoMethod(_app(obj), MUIM_CallHook, &MA_SetStatusToHook, SFLAG_READ, SFLAG_NEW); break;
case MMEN_TOMARKED: DoMethod(_app(obj), MUIM_CallHook, &MA_SetStatusToHook, SFLAG_MARKED, SFLAG_NONE); break;
case MMEN_TOUNMARKED: DoMethod(_app(obj), MUIM_CallHook, &MA_SetStatusToHook, SFLAG_NONE, SFLAG_MARKED); break;
case MMEN_ALLTOREAD: DoMethod(_app(obj), MUIM_CallHook, &MA_SetAllStatusToHook, SFLAG_READ, SFLAG_NEW); break;
case MMEN_TOSPAM: DoMethod(_app(obj), MUIM_CallHook, &MA_ClassifyMessageHook, BC_SPAM); break;
case MMEN_TOHAM: DoMethod(_app(obj), MUIM_CallHook, &MA_ClassifyMessageHook, BC_HAM); break;
case MMEN_SAVEADDR: DoMethod(_app(obj), MUIM_CallHook, &MA_GetAddressHook); break;
case MMEN_MOVE: DoMethod(_app(obj), MUIM_CallHook, &MA_MoveMessageHook); break;
case MMEN_COPY: DoMethod(_app(obj), MUIM_CallHook, &MA_CopyMessageHook); break;
case MMEN_ARCHIVE: DoMethod(_app(obj), MUIM_CallHook, &MA_ArchiveMessageHook); break;
case MMEN_DELETE: DoMethod(_app(obj), MUIM_CallHook, &MA_DeleteMessageHook, 0); break;
case MMEN_PRINT: DoMethod(_app(obj), MUIM_CallHook, &MA_SavePrintHook, TRUE); break;
case MMEN_SAVE: DoMethod(_app(obj), MUIM_CallHook, &MA_SavePrintHook, FALSE); break;
case MMEN_DETACH: DoMethod(_app(obj), MUIM_CallHook, &MA_SaveAttachHook); break;
case MMEN_DELETEATT: DoMethod(_app(obj), MUIM_CallHook, &MA_RemoveAttachHook); break;
case MMEN_EXPMSG: DoMethod(_app(obj), MUIM_CallHook, &MA_ExportMessagesHook, FALSE); break;
case MMEN_SELALL: DoMethod(obj, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_On, NULL); break;
case MMEN_SELNONE: DoMethod(obj, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL); break;
case MMEN_SELTOGG: DoMethod(obj, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Toggle, NULL); break;
default:
result = DoSuperMethodA(cl, obj, msg);
}
RETURN(result);
return result;
}
///
/// OVERLOAD(MUIM_CheckShortHelp)
// check whether the entry under the mouse pointer changed and a new bubble help is required
OVERLOAD(MUIM_CheckShortHelp)
{
GETDATA;
struct MUIP_CheckShortHelp *csh = (struct MUIP_CheckShortHelp *)msg;
struct MUI_NList_TestPos_Result res;
BOOL changeHelp;
ENTER();
DoMethod(obj, MUIM_NList_TestPos, csh->mx, csh->my, &res);
changeHelp = (res.entry == data->helpEntry) ? TRUE : FALSE;
RETURN(changeHelp);
return changeHelp;
}
///
/// OVERLOAD(MUIM_CreateShortHelp)
// set up a text for the bubble help
OVERLOAD(MUIM_CreateShortHelp)
{
GETDATA;
struct MUIP_CreateShortHelp *csh = (struct MUIP_CreateShortHelp *)msg;
char *shortHelp = NULL;
ENTER();
// don't create a help text in case we are disabled
if(xget(obj, MUIA_Disabled) == FALSE)
{
struct MUI_NList_TestPos_Result res;
DoMethod(obj, MUIM_NList_TestPos, csh->mx, csh->my, &res);
if(res.entry != -1)
{
struct Mail *mail;
DoMethod(obj, MUIM_NList_GetEntry, res.entry, &mail);
if(mail != NULL)
{
char datestr[64];
char sizestr[SIZE_DEFAULT];
// convert the datestamp of the mail to
// well defined string
DateStamp2String(datestr, sizeof(datestr), &mail->Date, (C->DSListFormat == DSS_DATEBEAT || C->DSListFormat == DSS_RELDATEBEAT) ? DSS_DATEBEAT : DSS_DATETIME, TZC_UTC2LOCAL);
// use FormatSize() to prettify the size display of the mail info
FormatSize(mail->Size, sizestr, sizeof(sizestr), SF_AUTO);
if(asprintf(&shortHelp, tr(MSG_MAILINFO_SHORTHELP), mail->From.RealName,
mail->From.Address,
IsStrEmpty(mail->To.Address) ? tr(MSG_MA_NO_RECIPIENTS) : mail->To.RealName,
mail->To.Address,
IsStrEmpty(mail->Subject) ? tr(MSG_MA_NO_SUBJECT) : mail->Subject,
datestr,
mail->MailFile,
sizestr) == -1)
{
// string formatting failed
shortHelp = NULL;
}
else
{
data->helpEntry = res.entry;
}
}
}
}
RETURN(shortHelp);
return (IPTR)shortHelp;
}
///
/// OVERLOAD(MUIM_DeleteShortHelp)
// free the bubble help text
OVERLOAD(MUIM_DeleteShortHelp)
{
struct MUIP_DeleteShortHelp *dsh = (struct MUIP_DeleteShortHelp *)msg;
ENTER();
free(dsh->help);
RETURN(0);
return 0;
}
///
/* Private Methods */
/// DECLARE(DoubleClicked)
// if the user double-clicked in the mail list we either
// have to open the message in a read window or if it is currently in
// the outgoing folder we open it for editing.
DECLARE(DoubleClicked) // LONG entryNum
{
ENTER();
if(msg->entryNum >= 0)
{
struct Folder *folder = GetCurrentFolder();
// A double click in the drafts folder should popup a write
// window instead.
if(folder != NULL && isDraftsFolder(folder))
{
// in case the folder is the "drafts" folder
// we edit the mail instead.
DoMethod(_app(obj), MUIM_CallHook, &MA_NewMessageHook, NMM_EDIT, 0);
}
else
{
// if not, then we open a read window instead
DoMethod(_app(obj), MUIM_CallHook, &MA_ReadMessageHook);
}
}
RETURN(0);
return 0;
}
///
/* Public Methods */
/// DECLARE(MakeFormat)
// Creates format definition for message listview
DECLARE(MakeFormat)
{
static const int defwidth[NUMBER_MAILLIST_COLUMNS] = { -1,-1,-1,-1,-1,-1,-1,-1,-1 };
char format[SIZE_LARGE];
BOOL first = TRUE;
int i;
ENTER();
*format = '\0';
for(i = 0; i < NUMBER_MAILLIST_COLUMNS; i++)
{
if(isFlagSet(C->MessageCols, (1<<i)))
{
int p;
if(first)
first = FALSE;
else
strlcat(format, " BAR,", sizeof(format));
p = strlen(format);
snprintf(&format[p], sizeof(format)-p, "COL=%d W=%d", i, defwidth[i]);
if(i == 5) // Size
strlcat(format, " P=\033r", sizeof(format));
else if(i == 3 || i == 1) // Subject || Sender
strlcat(format, " PCS=R", sizeof(format));
}
}
strlcat(format, " BAR", sizeof(format));
SHOWSTRING(DBF_GUI, format);
// set the new NList_Format to our object
set(obj, MUIA_NList_Format, format);
RETURN(0);
return 0;
}
///
/// DECLARE(RemoveMail)
// removes a mail visibly from the message listview
DECLARE(RemoveMail) // struct Mail* mail
{
IPTR result = 0;
ENTER();
// check if there are any mails in the list at all.
if(xget(obj, MUIA_NList_Entries) > 0)
{
LONG pos = MUIV_NList_GetPos_Start;
// now also remove the mail from the currently active list
DoMethod(obj, MUIM_NList_GetPos, msg->mail, &pos);
if(pos != MUIV_NList_GetPos_End)
result = DoMethod(obj, MUIM_NList_Remove, pos);
}
RETURN(result);
return result;
}
///
/// DECLARE(JumpToRecentMailOfFolder)
// jump to the first "new" mail of a folder
DECLARE(JumpToFirstNewMailOfFolder) // struct Folder *folder
{
struct Folder *folder = msg->folder;
int i, incr, newIdx = -1;
BOOL jumped;
ENTER();
if(folder->Sort[0] < 0 || folder->Sort[1] < 0)
{
i = xget(obj, MUIA_NList_Entries) - 1;
incr = -1;
}
else
{
i = 0;
incr = 1;
}
while(TRUE)
{
struct Mail *mail;
DoMethod(obj, MUIM_NList_GetEntry, i, &mail);
if(mail == NULL)
break;
if(hasStatusNew(mail) || !hasStatusRead(mail))
{
newIdx = i;
break;
}
i += incr;
}
if(newIdx >= 0 && newIdx != folder->LastActive)
{
DoMethod(obj, MUIM_NList_SetActive, newIdx, MUIV_NList_SetActive_Jump_Center);
jumped = TRUE;
}
else
jumped = FALSE;
RETURN(jumped);
return jumped;
}
///
/// DECLARE(JumpToRecentMailOfFolder)
// jump to the most recent mail of a folder
DECLARE(JumpToRecentMailOfFolder) // struct Folder *folder
{
struct MailNode *recent = NULL;
struct MailNode *mnode;
struct Folder *folder = msg->folder;
BOOL jumped;
ENTER();
LockMailList(folder->messages);
mnode = FirstMailNode(folder->messages);
while(mnode != NULL)
{
if(recent == NULL || CompareMailsByDate(mnode, recent) > 0)
{
// this mail is more recent than the yet most recent known
recent = mnode;
}
mnode = NextMailNode(mnode);
}
if(recent != NULL)
{
DoMethod(obj, MUIM_NList_SetActive, recent->mail, MUIV_NList_SetActive_Entry|MUIV_NList_SetActive_Jump_Center);
jumped = TRUE;
}
else
jumped = FALSE;
UnlockMailList(folder->messages);
RETURN(jumped);
return jumped;
}
///
/// DECLARE(DisplayMailsOfFolder)
// display the mails of the given folder
DECLARE(DisplayMailsOfFolder) // struct Folder *folder
{
struct Folder *folder = msg->folder;
int lastActive;
struct BusyNode *busy;
struct Mail **array = NULL;
ENTER();
lastActive = folder->LastActive;
busy = BusyBegin(BUSY_TEXT);
BusyText(busy, tr(MSG_BusyDisplayingList), "");
// we convert the mail list of the folder
// to a temporary array because that allows us
// to quickly populate the NList object.
if(folder->Total == 0 || (array = MailListToMailArray(folder->messages)) != NULL)
{
set(obj, MUIA_NList_Quiet, TRUE);
DoMethod(obj, MUIM_NList_Clear);
// perform the usual jumps to specific mails, if there are any left
if(folder->Total != 0)
{
BOOL jumped = FALSE;
DoMethod(obj, MUIM_NList_Insert, array, folder->Total, MUIV_NList_Insert_Sorted,
C->AutoColumnResize ? MUIF_NONE : MUIV_NList_Insert_Flag_Raw);
// Now we jump to messages that are NEW
if(jumped == FALSE && folder->JumpToUnread == TRUE && (folder->New != 0 || folder->Unread != 0))
jumped = DoMethod(obj, METHOD(JumpToFirstNewMailOfFolder), folder);
if(jumped == FALSE && lastActive >= 0)
{
DoMethod(obj, MUIM_NList_SetActive, lastActive, MUIV_NList_SetActive_Jump_Center);
jumped = TRUE;
}
if(jumped == FALSE && folder->JumpToRecent == TRUE)
jumped = DoMethod(obj, METHOD(JumpToRecentMailOfFolder), folder);
// if there is still no entry active in the NList we make the first one active
if(jumped == FALSE)
set(obj, MUIA_NList_Active, MUIV_NList_Active_Top);
}
set(obj, MUIA_NList_Quiet, FALSE);
free(array);
}
BusyEnd(busy);
// Now we have to recover the LastActive or otherwise it will be -1 later
folder->LastActive = lastActive;
RETURN(0);
return 0;
}
///