src/mui/ReadWindow.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_Window
Description: Window for reading emails
***************************************************************************/
#include "ReadWindow_cl.h"
#include <string.h>
#include <proto/dos.h>
#include <proto/muimaster.h>
#include <libraries/gadtools.h>
#include <libraries/iffparse.h>
#include <mui/NList_mcc.h>
#include <mui/TextEditor_mcc.h>
#include <mui/TheBar_mcc.h>
#include "SDI_hook.h"
#include "YAM.h"
#include "YAM_find.h"
#include "YAM_mainFolder.h"
#include "mui/MainMailList.h"
#include "mui/MainMailListGroup.h"
#include "mui/ReadMailGroup.h"
#include "mui/ReadWindowStatusBar.h"
#include "mui/ReadWindowToolbar.h"
#include "mui/YAMApplication.h"
#include "BayesFilter.h"
#include "Config.h"
#include "FolderList.h"
#include "Locale.h"
#include "Logfile.h"
#include "MailList.h"
#include "MimeTypes.h"
#include "MUIObjects.h"
#include "Requesters.h"
#include "Debug.h"
/* CLASSDATA
struct Data
{
Object *MI_EDIT;
Object *MI_MOVE;
Object *MI_ARCHIVE;
Object *MI_DELETE;
Object *MI_DETACH;
Object *MI_DELETEATT;
Object *MI_CHSUBJ;
Object *MI_NAVIG;
Object *MI_WRAPH;
Object *MI_TSTYLE;
Object *MI_FFONT;
Object *MI_PGP;
Object *MI_EXTKEY;
Object *MI_CHKSIG;
Object *MI_SAVEDEC;
Object *MI_REPLY;
Object *MI_FORWARD;
Object *MI_FORWARD_ATTACH;
Object *MI_FORWARD_INLINE;
Object *MI_REDIRECT;
Object *MI_NEXTTHREAD;
Object *MI_PREVTHREAD;
Object *MI_STATUS;
Object *MI_TOMARKED;
Object *MI_TOUNMARKED;
Object *MI_TOUNREAD;
Object *MI_TOREAD;
Object *MI_TOSPAM;
Object *MI_TOHAM;
Object *MI_SEARCH;
Object *MI_SEARCHAGAIN;
Object *MI_TCOLOR;
Object *windowToolbar;
Object *statusBar;
Object *readMailGroup;
char windowTitle[SIZE_SUBJECT+1];
char screenTitle[SIZE_SUBJECT+1];
int windowNumber;
};
*/
// menu item IDs
enum
{
RMEN_EDIT=501,RMEN_MOVE,RMEN_COPY,RMEN_ARCHIVE,RMEN_DELETE,RMEN_PRINT,RMEN_SAVE,RMEN_DISPLAY,
RMEN_DETACH,RMEN_DELETEATT,RMEN_NEW,RMEN_REPLY,RMEN_FORWARD_ATTACH,RMEN_FORWARD_INLINE,
RMEN_REDIRECT,RMEN_SAVEADDR,RMEN_CHSUBJ,RMEN_PREV,RMEN_NEXT,RMEN_URPREV,RMEN_URNEXT,RMEN_PREVTH,
RMEN_NEXTTH,RMEN_EXTKEY,RMEN_CHKSIG,RMEN_SAVEDEC,RMEN_HNONE,RMEN_HSHORT,RMEN_HFULL,
RMEN_SNONE,RMEN_SDATA,RMEN_SFULL,RMEN_WRAPH,RMEN_TSTYLE,RMEN_FFONT,RMEN_SIMAGE,RMEN_TOMARKED,
RMEN_TOUNMARKED,RMEN_TOUNREAD,RMEN_TOREAD,RMEN_TOSPAM,RMEN_TOHAM,
RMEN_SEARCH,RMEN_SEARCHAGAIN,RMEN_EDIT_COPY,RMEN_EDIT_SALL,RMEN_EDIT_SNONE,RMEN_TCOLOR
};
/* Private Functions */
/// SelectMessage()
// Activates a message in the main window's message listview
INLINE LONG SelectMessage(struct Mail *mail)
{
LONG pos = MUIV_NList_GetPos_Start;
// make sure the folder of the mail is currently the
// active one.
MA_ChangeFolder(mail->Folder, TRUE);
// get the position of the mail in the main mail listview
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, mail, &pos);
// if it is currently viewable we go and set it as the
// active mail
if(pos != MUIV_NList_GetPos_End)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, pos);
// return the position to the caller
return pos;
}
///
/* Overloaded Methods */
/// OVERLOAD(OM_NEW)
OVERLOAD(OM_NEW)
{
ULONG i=0;
struct Data *data;
struct Data *tmpData;
Object *menuStripObject;
ENTER();
// generate a temporarly struct Data to which we store our data and
// copy it later on
if((data = tmpData = calloc(1, sizeof(struct Data))) == NULL)
{
RETURN(0);
return 0;
}
// before we create all objects of this new read window we have to
// check which number we can set for this window. Therefore we search in our
// current ReadMailData list and check which number we can give this window
do
{
struct ReadMailData *rmData;
BOOL found = FALSE;
IterateList(&G->readMailDataList, struct ReadMailData *,rmData)
{
if(rmData->readWindow != NULL &&
xget(rmData->readWindow, MUIA_ReadWindow_Num) == i)
{
found = TRUE;
break;
}
}
// if we didn't find a window with the current ID then we can choose it as
// our ReadWindow ID
if(found == FALSE)
{
D(DBF_GUI, "Free window number %ld found.", i);
data->windowNumber = i;
break;
}
i++;
}
while(TRUE);
//
// now we create the Menustrip object with all the menu items
// and corresponding shortcuts
//
// The following shortcut list should help to identify the hard-coded
// shortcuts:
//
// A Select all text (RMEN_EDIT_SALL)
// B Redirect mail (RMEN_REDIRECT)
// C Copy selected text (RMEN_EDIT_COPY)
// D Display mail part (RMEN_DISPLAY)
// E Edit mail in Editor (RMEN_EDIT)
// F Search in mail (RMEN_SEARCH)
// G Search again in mail (RMEN_SEARCHAGAIN)
// H Enable/Disabled 'Wrap Header' (RMEN_WRAPH)
// I Enable/Disbaled 'Fixed Font' (RMEN_FFONT)
// J Save address (RMEN_SAVEADDR)
// K Check PGP signature (RMEN_CHKSIG)
// L Save all attachments (RMEN_DETACH)
// M Move mail (RMEN_MOVE)
// N Create new mail (RMEN_NEW)
// O Delete attachments (RMEN_DELETEATT)
// P Print mail part (RMEN_PRINT)
// Q
// R Reply mail (RMEN_REPLY)
// S Save mail part (RMEN_SAVE)
// T Enable/Disable Text Colors (RMEN_TCOLOR)
// U
// V Save PGP decrypted mail (RMEN_SAVEDEC)
// W Forward mail (RMEN_FORWARD_ATTACH or RMEN_FORWARD_INLINE)
// X Extract PGP key from mail (RMEN_EXTKEY)
// Y Copy mail (RMEN_COPY)
// Z
// Del Remove mail (RMEN_DELETE)
// , Set status to 'marked' (RMEN_TOMARKED)
// . Set status to 'unmarked' (RMEN_TOUNMARKED)
// [ Set status to 'unread' (RMEN_TOUNREAD)
// ] Set status to 'read' (RMEN_TOREAD)
//
// InputEvent shortcuts:
//
// -capslock del : delete mail (RMEN_DELETE)
// -capslock shift del : delete mail at once
// -repeat -capslock space : move one page forward in texteditor display
// -repeat -capslock backspace : move one page backward in texteditor display
// -repeat -capslock left : Display previous mail in folder (RMEN_PREV)
// -repeat -capslock right : Display next mail in folder (RMEN_NEXT)
// -repeat -capslock shift left : Display previous unread mail in folder (RMEN_URPREV)
// -repeat -capslock shift right: Display next unread mail in folder (RMEN_URNEXT)
// -repeat -capslock alt left : Display previous mail in message thread (RMEN_PREVTH)
// -repeat -capslock alt right : Display next mail in message thread (RMEN_NEXTTH)
//
//
menuStripObject = MenustripObject,
MenuChild, MenuObject,
MUIA_Menu_Title, tr(MSG_Message),
MUIA_Menu_CopyStrings, FALSE,
MenuChild, data->MI_EDIT = Menuitem(tr(MSG_MA_MEDIT), "E", TRUE, FALSE, RMEN_EDIT),
MenuChild, data->MI_MOVE = Menuitem(tr(MSG_MA_MMOVE), "M", TRUE, FALSE, RMEN_MOVE),
MenuChild, Menuitem(tr(MSG_MA_MCOPY), "Y", TRUE, FALSE, RMEN_COPY),
MenuChild, data->MI_ARCHIVE = Menuitem(tr(MSG_MA_MARCHIVE), NULL, TRUE, FALSE, RMEN_ARCHIVE),
MenuChild, data->MI_DELETE = Menuitem(tr(MSG_MA_MDelete), "Del", TRUE, TRUE, RMEN_DELETE),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_Print), "P", TRUE, FALSE, RMEN_PRINT),
MenuChild, Menuitem(tr(MSG_MA_Save), "S", TRUE, FALSE, RMEN_SAVE),
MenuChild, MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_Attachments),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_RE_MDisplay), "D", TRUE, FALSE, RMEN_DISPLAY),
MenuChild, data->MI_DETACH = Menuitem(tr(MSG_RE_SaveAll), "L", TRUE, FALSE, RMEN_DETACH),
MenuChild, data->MI_DELETEATT = Menuitem(tr(MSG_MA_DELETEATT), "O", TRUE, FALSE, RMEN_DELETEATT),
End,
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_New), "N", TRUE, FALSE, RMEN_NEW),
MenuChild, data->MI_REPLY = Menuitem(tr(MSG_MA_MREPLY), "R", TRUE, FALSE, RMEN_REPLY),
MenuChild, data->MI_FORWARD = MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_MA_MFORWARD),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, data->MI_FORWARD_ATTACH = Menuitem(tr(MSG_MA_MFORWARD_ATTACH), NULL, TRUE, FALSE, RMEN_FORWARD_ATTACH),
MenuChild, data->MI_FORWARD_INLINE = Menuitem(tr(MSG_MA_MFORWARD_INLINE), NULL, TRUE, FALSE, RMEN_FORWARD_INLINE),
End,
MenuChild, data->MI_REDIRECT = Menuitem(tr(MSG_MA_MREDIRECT), "B", TRUE, FALSE, RMEN_REDIRECT),
MenuChild, MenuBarLabel,
MenuChild, data->MI_SEARCH = Menuitem(tr(MSG_RE_SEARCH), "F", TRUE, FALSE, RMEN_SEARCH),
MenuChild, data->MI_SEARCHAGAIN = Menuitem(tr(MSG_RE_SEARCH_AGAIN), "G", TRUE, FALSE, RMEN_SEARCHAGAIN),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_MGetAddress), "J", TRUE, FALSE, RMEN_SAVEADDR),
MenuChild, data->MI_STATUS = MenuitemObject,
MUIA_Menuitem_Title, tr(MSG_MA_SetStatus),
MUIA_Menuitem_CopyStrings, FALSE,
MenuChild, data->MI_TOMARKED = Menuitem(tr(MSG_MA_TOMARKED), ",", TRUE, FALSE, RMEN_TOMARKED),
MenuChild, data->MI_TOUNMARKED = Menuitem(tr(MSG_MA_TOUNMARKED), ".", TRUE, FALSE, RMEN_TOUNMARKED),
MenuChild, data->MI_TOREAD = Menuitem(tr(MSG_MA_TOREAD), "]", TRUE, FALSE, RMEN_TOREAD),
MenuChild, data->MI_TOUNREAD = Menuitem(tr(MSG_MA_TOUNREAD), "[", TRUE, FALSE, RMEN_TOUNREAD),
End,
MenuChild, data->MI_CHSUBJ = Menuitem(tr(MSG_MA_ChangeSubj), NULL, TRUE, FALSE, RMEN_CHSUBJ),
End,
MenuChild, MenuObject,
MUIA_Menu_Title, tr(MSG_MA_EDIT),
MUIA_Menu_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_MA_EDIT_COPY), "C", TRUE, FALSE, RMEN_EDIT_COPY),
MenuChild, MenuBarLabel,
MenuChild, Menuitem(tr(MSG_MA_EDIT_SALL), "A", TRUE, FALSE, RMEN_EDIT_SALL),
MenuChild, Menuitem(tr(MSG_MA_EDIT_SNONE), NULL, TRUE, FALSE, RMEN_EDIT_SNONE),
End,
MenuChild, data->MI_NAVIG = MenuObject,
MUIA_Menu_Title, tr(MSG_RE_Navigation),
MUIA_Menu_CopyStrings, FALSE,
MenuChild, Menuitem(tr(MSG_RE_MNext), "right", TRUE, TRUE, RMEN_NEXT),
MenuChild, Menuitem(tr(MSG_RE_MPrev), "left", TRUE, TRUE, RMEN_PREV),
MenuChild, Menuitem(tr(MSG_RE_MURNext), "shift right", TRUE, TRUE, RMEN_URNEXT),
MenuChild, Menuitem(tr(MSG_RE_MURPrev), "shift left", TRUE, TRUE, RMEN_URPREV),
MenuChild, data->MI_NEXTTHREAD = Menuitem(tr(MSG_RE_MNextTh), "alt right", TRUE, TRUE, RMEN_NEXTTH),
MenuChild, data->MI_PREVTHREAD = Menuitem(tr(MSG_RE_MPrevTh), "alt left", TRUE, TRUE, RMEN_PREVTH),
End,
MenuChild, data->MI_PGP = MenuObject,
MUIA_Menu_Title, "PGP",
MUIA_Menu_CopyStrings, FALSE,
MenuChild, data->MI_EXTKEY = Menuitem(tr(MSG_RE_ExtractKey), "X", TRUE, FALSE, RMEN_EXTKEY),
MenuChild, data->MI_CHKSIG = Menuitem(tr(MSG_RE_SigCheck), "K", TRUE, FALSE, RMEN_CHKSIG),
MenuChild, data->MI_SAVEDEC = Menuitem(tr(MSG_RE_SaveDecrypted), "V", TRUE, FALSE, RMEN_SAVEDEC),
End,
MenuChild, MenuObject,
MUIA_Menu_Title, tr(MSG_MA_Settings),
MUIA_Menu_CopyStrings, FALSE,
MenuChild, MenuitemCheck(tr(MSG_RE_NoHeaders), "0", TRUE, C->ShowHeader==HM_NOHEADER, FALSE, 0x06, RMEN_HNONE),
MenuChild, MenuitemCheck(tr(MSG_RE_ShortHeaders), "1", TRUE, C->ShowHeader==HM_SHORTHEADER, FALSE, 0x05, RMEN_HSHORT),
MenuChild, MenuitemCheck(tr(MSG_RE_FullHeaders), "2", TRUE, C->ShowHeader==HM_FULLHEADER, FALSE, 0x03, RMEN_HFULL),
MenuChild, MenuBarLabel,
MenuChild, MenuitemCheck(tr(MSG_RE_NoSInfo), "3", TRUE, C->ShowSenderInfo==SIM_OFF, FALSE, 0xE0, RMEN_SNONE),
MenuChild, MenuitemCheck(tr(MSG_RE_SInfo), "4", TRUE, C->ShowSenderInfo==SIM_DATA, FALSE, 0xD0, RMEN_SDATA),
MenuChild, MenuitemCheck(tr(MSG_RE_SInfoImage), "5", TRUE, C->ShowSenderInfo==SIM_ALL, FALSE, 0x90, RMEN_SFULL),
MenuChild, MenuitemCheck(tr(MSG_RE_SImageOnly), "6", TRUE, C->ShowSenderInfo==SIM_IMAGE, FALSE, 0x70, RMEN_SIMAGE),
MenuChild, MenuBarLabel,
MenuChild, data->MI_WRAPH = MenuitemCheck(tr(MSG_RE_WrapHeader), "H", TRUE, C->WrapHeader, TRUE, 0, RMEN_WRAPH),
MenuChild, data->MI_FFONT = MenuitemCheck(tr(MSG_RE_FixedFont), "I", TRUE, C->FixedFontEdit, TRUE, 0, RMEN_FFONT),
MenuChild, data->MI_TCOLOR = MenuitemCheck(tr(MSG_RE_TEXTCOLORS), "T", TRUE, C->UseTextColorsRead, TRUE, 0, RMEN_TCOLOR),
MenuChild, data->MI_TSTYLE = MenuitemCheck(tr(MSG_RE_Textstyles), NULL, TRUE, C->UseTextStylesRead, TRUE, 0, RMEN_TSTYLE),
End,
End;
// create the read window object
if(menuStripObject != NULL && (obj = DoSuperNew(cl, obj,
MUIA_HelpNode, "Windows/Readwindow",
MUIA_Window_ID, MAKE_ID('R','D','W', data->windowNumber),
MUIA_Window_Menustrip, menuStripObject,
WindowContents, VGroup,
Child, hasHideToolBarFlag(C->HideGUIElements) ?
(RectangleObject, MUIA_ShowMe, FALSE, End) :
(VGroup,
Child, HGroupV,
Child, data->windowToolbar = ReadWindowToolbarObject,
MUIA_HelpNode, "Windows/Readwindow#Toolbar",
End,
End,
Child, data->statusBar = ReadWindowStatusBarObject,
End,
End),
Child, VGroup,
Child, data->readMailGroup = ReadMailGroupObject,
MUIA_ReadMailGroup_HGVertWeight, G->Weights[10],
MUIA_ReadMailGroup_TGVertWeight, G->Weights[11],
End,
End,
End,
TAG_MORE, inittags(msg))) != NULL)
{
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
if(rmData == NULL ||
(data = (struct Data *)INST_DATA(cl,obj)) == NULL)
{
RETURN(0);
return 0;
}
// copy back the data stored in our temporarly struct Data
memcpy(data, tmpData, sizeof(struct Data));
// place this newly created window to the readMailData structure aswell
rmData->readWindow = obj;
// set the MUIA_UserData attribute to our readMailData struct
// as we might need it later on
set(obj, MUIA_UserData, rmData);
// Add the window to the application object
DoMethod(G->App, OM_ADDMEMBER, obj);
// setup the toolbar notifies
if(data->windowToolbar != NULL)
DoMethod(data->windowToolbar, MUIM_ReadWindowToolbar_InitNotify, obj, data->readMailGroup);
// set the default window object
set(obj, MUIA_Window_DefaultObject, data->readMailGroup);
// set some Notifies
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_EDIT, obj, 3, METHOD(NewMail), NMM_EDIT, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_MOVE, obj, 1, METHOD(MoveMailRequest));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_COPY, obj, 1, METHOD(CopyMailRequest));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_ARCHIVE, obj, 1, METHOD(ArchiveMailRequest));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_DELETE, obj, 2, METHOD(DeleteMailRequest), 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_PRINT, data->readMailGroup, 1, MUIM_ReadMailGroup_PrintMailRequest);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SAVE, data->readMailGroup, 1, MUIM_ReadMailGroup_SaveMailRequest);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_DISPLAY, data->readMailGroup, 1, MUIM_ReadMailGroup_DisplayMailRequest);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_DETACH, data->readMailGroup, 1, MUIM_ReadMailGroup_SaveAllAttachments);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_DELETEATT, data->readMailGroup, 1, MUIM_ReadMailGroup_DeleteAttachmentsRequest);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_NEW, obj, 3, METHOD(NewMail), NMM_NEW, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_REPLY, obj, 3, METHOD(NewMail), NMM_REPLY, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_FORWARD_ATTACH, obj, 3, METHOD(NewMail), NMM_FORWARD_ATTACH, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_FORWARD_INLINE, obj, 3, METHOD(NewMail), NMM_FORWARD_INLINE, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_REDIRECT, obj, 3, METHOD(NewMail), NMM_REDIRECT, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SAVEADDR, obj, 1, METHOD(GrabSenderAddress));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SEARCH, data->readMailGroup, 2, MUIM_ReadMailGroup_Search, MUIF_NONE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SEARCHAGAIN, data->readMailGroup, 2, MUIM_ReadMailGroup_Search, MUIF_ReadMailGroup_Search_Again);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOUNREAD, obj, 3, METHOD(SetStatusTo), SFLAG_NONE, SFLAG_NEW|SFLAG_READ);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOREAD, obj, 3, METHOD(SetStatusTo), SFLAG_READ, SFLAG_NEW);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOMARKED, obj, 3, METHOD(SetStatusTo), SFLAG_MARKED, SFLAG_NONE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOUNMARKED, obj, 3, METHOD(SetStatusTo), SFLAG_NONE, SFLAG_MARKED);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOSPAM, obj, 2, METHOD(ClassifyMessage), BC_SPAM);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TOHAM, obj, 2, METHOD(ClassifyMessage), BC_HAM);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_CHSUBJ, obj, 1, METHOD(ChangeSubjectRequest));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_EDIT_COPY, data->readMailGroup, 2, MUIM_ReadMailGroup_DoEditAction, EA_COPY, MUIF_NONE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_EDIT_SALL, data->readMailGroup, 2, MUIM_ReadMailGroup_DoEditAction, EA_SELECTALL, MUIF_NONE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_EDIT_SNONE, data->readMailGroup, 2, MUIM_ReadMailGroup_DoEditAction, EA_SELECTNONE, MUIF_NONE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_PREV, obj, 3, METHOD(SwitchMail), -1, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_NEXT, obj, 3, METHOD(SwitchMail), +1, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_URPREV, obj, 3, METHOD(SwitchMail), -1, IEQUALIFIER_LSHIFT);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_URNEXT, obj, 3, METHOD(SwitchMail), +1, IEQUALIFIER_LSHIFT);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_PREVTH, obj, 2, METHOD(FollowThread), -1);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_NEXTTH, obj, 2, METHOD(FollowThread), +1);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_EXTKEY, data->readMailGroup, 1, MUIM_ReadMailGroup_ExtractPGPKey);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_CHKSIG, data->readMailGroup, 2, MUIM_ReadMailGroup_CheckPGPSignature, TRUE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SAVEDEC, data->readMailGroup, 1, MUIM_ReadMailGroup_SaveDecryptedMail);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_HNONE, obj, 2, METHOD(ChangeHeaderMode), HM_NOHEADER);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_HSHORT, obj, 2, METHOD(ChangeHeaderMode), HM_SHORTHEADER);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_HFULL, obj, 2, METHOD(ChangeHeaderMode), HM_FULLHEADER);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SNONE, obj, 2, METHOD(ChangeSenderInfoMode), SIM_OFF);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SDATA, obj, 2, METHOD(ChangeSenderInfoMode), SIM_DATA);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SFULL, obj, 2, METHOD(ChangeSenderInfoMode), SIM_ALL);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_SIMAGE, obj, 2, METHOD(ChangeSenderInfoMode), SIM_IMAGE);
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_WRAPH, obj, 1, METHOD(StyleOptionsChanged));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TCOLOR, obj, 1, METHOD(StyleOptionsChanged));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_TSTYLE, obj, 1, METHOD(StyleOptionsChanged));
DoMethod(obj, MUIM_Notify, MUIA_Window_MenuAction, RMEN_FFONT, obj, 1, METHOD(StyleOptionsChanged));
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-capslock del", obj, 2, METHOD(DeleteMailRequest), 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-capslock shift del", obj, 2, METHOD(DeleteMailRequest), IEQUALIFIER_LSHIFT);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock space", data->readMailGroup, 2, MUIM_TextEditor_ARexxCmd, "Next Page");
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock backspace", data->readMailGroup, 2, MUIM_TextEditor_ARexxCmd, "Previous Page");
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock left", obj, 3, METHOD(SwitchMail), -1, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock right", obj, 3, METHOD(SwitchMail), +1, 0);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock shift left", obj, 3, METHOD(SwitchMail), -1, IEQUALIFIER_LSHIFT);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock shift right", obj, 3, METHOD(SwitchMail), +1, IEQUALIFIER_LSHIFT);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock alt left", obj, 2, METHOD(FollowThread), -1);
DoMethod(obj, MUIM_Notify, MUIA_Window_InputEvent, "-repeat -capslock alt right", obj, 2, METHOD(FollowThread), +1);
// update the "Forward" items' shortcut
DoMethod(obj, METHOD(UpdateMenuShortcuts));
// make sure the right menus/toolbar spam button items are available
DoMethod(obj, METHOD(UpdateSpamControls));
// before we continue we make sure we connect a notify to the new window
// so that we get informed if the window is closed and therefore can be
// disposed
// However, please note that because we do kill the window upon closing it
// we have to use MUIM_Application_PushMethod instead of calling the
// CleanupReadMailData method directly
DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
MUIV_Notify_Application, 6,
MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
}
else
obj = NULL;
// free the temporary mem we allocated before
free(tmpData);
RETURN((IPTR)obj);
return (IPTR)obj;
}
///
/// OVERLOAD(OM_GET)
OVERLOAD(OM_GET)
{
GETDATA;
IPTR *store = ((struct opGet *)msg)->opg_Storage;
switch(((struct opGet *)msg)->opg_AttrID)
{
case ATTR(ReadMailData) : *store = (ULONG)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData); return TRUE;
case ATTR(Num) : *store = data->windowNumber; return TRUE;
}
return DoSuperMethodA(cl, obj, msg);
}
///
/// OVERLOAD(OM_SET)
OVERLOAD(OM_SET)
{
GETDATA;
struct TagItem *tags = inittags(msg), *tag;
while((tag = NextTagItem((APTR)&tags)) != NULL)
{
switch(tag->ti_Tag)
{
// we also catch foreign attributes
case MUIA_Window_CloseRequest:
{
// if the window is supposed to be closed and the StatusChangeDelay is
// active and no embeddedReadPane is active we have to cancel an eventually
// existing timerequest to set the status of a mail to read.
if(tag->ti_Data == TRUE &&
C->StatusChangeDelayOn == TRUE && C->EmbeddedReadPane == FALSE &&
xget(obj, MUIA_Window_Open) == TRUE)
{
StopTimer(TIMER_READSTATUSUPDATE);
}
}
break;
case MUIA_Window_DefaultObject:
{
// if the user clicks somewhere where the default
// object would be set to NULL we make sure we set
// it back to the default object of the readmail group
if((Object *)tag->ti_Data == NULL)
tag->ti_Data = xget(data->readMailGroup, MUIA_ReadMailGroup_DefaultObject);
}
break;
}
}
return DoSuperMethodA(cl, obj, msg);
}
///
/// OVERLOAD(MUIM_Window_Snapshot)
OVERLOAD(MUIM_Window_Snapshot)
{
struct MUIP_Window_Snapshot *snap = (struct MUIP_Window_Snapshot *)msg;
GETDATA;
// remember the weights for snapshot operations, but not for unsnapshot operations
if(snap->flags != 0)
{
// on a snapshot request we save the weights of all our objects here.
G->Weights[10] = xget(data->readMailGroup, MUIA_ReadMailGroup_HGVertWeight);
G->Weights[11] = xget(data->readMailGroup, MUIA_ReadMailGroup_TGVertWeight);
// make sure the layout is saved
SaveLayout(TRUE);
}
return DoSuperMethodA(cl, obj, msg);
}
///
/* Public Methods */
/// DECLARE(ReadMail)
DECLARE(ReadMail) // struct Mail *mail
{
GETDATA;
struct Mail *mail = msg->mail;
struct Folder *folder = mail->Folder;
BOOL isRealMail = !isVirtualMail(mail);
BOOL isSentMail = isRealMail && isSentMailFolder(folder);
BOOL hasAttach = isMP_MixedMail(mail);
BOOL inSpamFolder = isRealMail && isSpamFolder(folder);
BOOL result = FALSE;
BOOL initialCall = IsStrEmpty(data->windowTitle); // TRUE if this is the first call
BOOL prevMailAvailable = FALSE;
BOOL nextMailAvailable = FALSE;
ENTER();
D(DBF_GUI, "setting up readWindow for reading a mail");
// check the status of the next/prev thread nagivation
if(isRealMail == TRUE)
{
if(AllFolderLoaded() == TRUE)
{
prevMailAvailable = FindThreadInFolder(mail, mail->Folder, FALSE) != NULL;
nextMailAvailable = FindThreadInFolder(mail, mail->Folder, TRUE) != NULL;
}
else
{
prevMailAvailable = TRUE;
nextMailAvailable = TRUE;
}
}
// change the menu item title of the
// Edit item so that we either display "Edit" or "Edit as New"
if(isRealMail == TRUE && isDraftsFolder(folder))
set(data->MI_EDIT, MUIA_Menuitem_Title, tr(MSG_MA_MEDIT));
else
set(data->MI_EDIT, MUIA_Menuitem_Title, tr(MSG_MA_MEDITASNEW));
// enable/disable some menuitems in advance
set(data->MI_EDIT, MUIA_Menuitem_Enabled, isRealMail && !inSpamFolder);
set(data->MI_MOVE, MUIA_Menuitem_Enabled, isRealMail);
set(data->MI_ARCHIVE, MUIA_Menuitem_Enabled, isRealMail);
set(data->MI_DELETE, MUIA_Menuitem_Enabled, isRealMail);
set(data->MI_DETACH, MUIA_Menuitem_Enabled, hasAttach);
set(data->MI_DELETEATT, MUIA_Menuitem_Enabled, isRealMail && hasAttach);
set(data->MI_CHSUBJ, MUIA_Menuitem_Enabled, isRealMail && !inSpamFolder);
set(data->MI_NAVIG, MUIA_Menu_Enabled, isRealMail);
set(data->MI_REPLY, MUIA_Menuitem_Enabled, !inSpamFolder && !hasStatusSpam(mail));
set(data->MI_REDIRECT, MUIA_Menuitem_Enabled, !isSentMail);
set(data->MI_NEXTTHREAD,MUIA_Menuitem_Enabled, nextMailAvailable);
set(data->MI_PREVTHREAD,MUIA_Menuitem_Enabled, prevMailAvailable);
// Enable if:
// * the mail is a real (non-virtual) mail
DoMethod(obj, MUIM_MultiSet, MUIA_Menuitem_Enabled, isRealMail, data->MI_TOMARKED,
data->MI_TOUNMARKED,
NULL);
// Enable if:
// * the mail is a real (non-virtual) mail
// * NOT in the "Sent" folder
DoMethod(obj, MUIM_MultiSet, MUIA_Menuitem_Enabled, isRealMail && !isSentMail, data->MI_TOREAD,
data->MI_TOUNREAD,
NULL);
if(data->windowToolbar != NULL)
{
LONG pos = MUIV_NList_GetPos_Start;
// query the position of the mail in the current listview
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, mail, &pos);
// now set some items of the toolbar ghosted/enabled
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_PREV, MUIA_TheBar_Attr_Disabled, isRealMail ? pos == 0 : TRUE);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_NEXT, MUIA_TheBar_Attr_Disabled, isRealMail ? pos == (folder->Total-1) : TRUE);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_PREVTHREAD, MUIA_TheBar_Attr_Disabled, !prevMailAvailable);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_NEXTTHREAD, MUIA_TheBar_Attr_Disabled, !nextMailAvailable);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_DELETE, MUIA_TheBar_Attr_Disabled, !isRealMail);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_MOVE, MUIA_TheBar_Attr_Disabled, !isRealMail);
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_REPLY, MUIA_TheBar_Attr_Disabled, inSpamFolder || hasStatusSpam(mail));
}
// update the status bar
DoMethod(data->statusBar, MUIM_ReadWindowStatusBar_Update, mail);
// now we read in the mail in our read mail group
if(DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ReadMail, mail,
initialCall == FALSE ? MUIF_ReadMailGroup_ReadMail_StatusChangeDelay : MUIF_NONE))
{
size_t titleLen;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
BOOL hasPGPKey = rmData->hasPGPKey;
BOOL hasPGPSig = (hasPGPSOldFlag(rmData) || hasPGPSMimeFlag(rmData));
BOOL isPGPEnc = isRealMail && (hasPGPEMimeFlag(rmData) || hasPGPEOldFlag(rmData));
// if the title of the window is empty, we can assume that no previous mail was
// displayed in this readwindow, so we can set the mailTextObject of the readmailgroup
// as the active object so that the user can browse through the mailtext immediatley after
// opening the window
if(initialCall == TRUE)
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ActivateMailText);
// set the title of the readWindow now
if(C->MultipleReadWindows == TRUE ||
rmData == G->ActiveRexxRMData)
{
titleLen = snprintf(data->windowTitle, sizeof(data->windowTitle), "[%d] %s %s: ", data->windowNumber+1,
isSentMail ? tr(MSG_To) : tr(MSG_From),
isSentMail ? AddrName(mail->To) : AddrName(mail->From));
}
else
{
titleLen = snprintf(data->windowTitle, sizeof(data->windowTitle), "%s %s: ", isSentMail ? tr(MSG_To) : tr(MSG_From),
isSentMail ? AddrName(mail->To) : AddrName(mail->From));
}
if(strlen(mail->Subject)+titleLen > sizeof(data->windowTitle)-1)
{
if(titleLen < sizeof(data->windowTitle)-4)
{
strlcat(data->windowTitle, mail->Subject, sizeof(data->windowTitle)-titleLen-4);
strlcat(data->windowTitle, "...", sizeof(data->windowTitle)); // signals that the string was cut.
}
else
strlcat(&data->windowTitle[sizeof(data->windowTitle)-5], "...", 4);
}
else
strlcat(data->windowTitle, mail->Subject, sizeof(data->windowTitle));
xset(obj, MUIA_Window_Title, data->windowTitle,
MUIA_Window_ScreenTitle, CreateScreenTitle(data->screenTitle, sizeof(data->screenTitle), data->windowTitle));
// enable some Menuitems depending on the read mail
set(data->MI_PGP, MUIA_Menu_Enabled, hasPGPKey || hasPGPSig || isPGPEnc);
set(data->MI_EXTKEY, MUIA_Menuitem_Enabled, hasPGPKey);
set(data->MI_CHKSIG, MUIA_Menuitem_Enabled, hasPGPSig);
set(data->MI_SAVEDEC, MUIA_Menuitem_Enabled, isPGPEnc);
// everything worked fine
result = TRUE;
}
// update the spam/no spam menu items as well as the toolbar
DoMethod(obj, METHOD(UpdateSpamControls));
RETURN(result);
return result;
}
///
/// DECLARE(RereadMail)
DECLARE(RereadMail) // struct Mail *mail, ULONG flags
{
GETDATA;
ENTER();
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ReadMail, msg->mail, msg->flags);
RETURN(0);
return 0;
}
///
/// DECLARE(NewMail)
DECLARE(NewMail) // enum NewMailMode mode, ULONG qualifier
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
ENTER();
// then create a new mail depending on the current mode
if(MailExists(mail, NULL) == TRUE)
{
enum NewMailMode mode;
int flags;
// get the newmail flags depending on the currently
// set qualifier keys. We submit these flags to the
// NewMessage() function later on
mode = CheckNewMailQualifier(msg->mode, msg->qualifier, &flags);
switch(mode)
{
case NMM_NEW:
NewWriteMailWindow(mail, flags);
break;
case NMM_EDIT:
NewEditMailWindow(mail, flags);
break;
case NMM_REDIRECT:
{
struct MailList *mlist;
if((mlist = CreateMailList()) != NULL)
{
AddNewMailNode(mlist, mail);
NewRedirectMailWindow(mlist, flags);
DeleteMailList(mlist);
}
}
break;
case NMM_FORWARD:
case NMM_FORWARD_ATTACH:
case NMM_FORWARD_INLINE:
{
struct MailList *mlist;
if((mlist = CreateMailList()) != NULL)
{
AddNewMailNode(mlist, mail);
NewForwardMailWindow(mlist, flags);
DeleteMailList(mlist);
}
}
break;
case NMM_REPLY:
{
struct MailList *mlist;
// we create a fake mail list with only one entry
// (the mail showing in this window)
if((mlist = CreateMailList()) != NULL)
{
char *replytext;
// in case there is only one mail selected we have to check wheter there is
// text currently selected by the user
replytext = (char *)DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ExportSelectedText);
// we only add one mail to the fake list
AddNewMailNode(mlist, mail);
// now we create a new reply mail window
NewReplyMailWindow(mlist, flags, replytext);
// free the replytext in case we go one
if(replytext != NULL)
FreeVec(replytext);
// cleanup the temporarly created mail list
DeleteMailList(mlist);
}
}
break;
default:
// nothing
break;
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(MoveMailRequest)
DECLARE(MoveMailRequest)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *srcfolder = mail->Folder;
ENTER();
if(MailExists(mail, srcfolder) == TRUE)
{
struct Folder *dstfolder = FolderRequest(tr(MSG_MA_MoveMsg),
tr(MSG_MA_MoveMsgReq),
tr(MSG_MA_MoveGad),
tr(MSG_Cancel),
NULL,
obj);
if(dstfolder != NULL && dstfolder != srcfolder)
{
BOOL closeAfter = FALSE;
int pos = SelectMessage(mail); // select the message in the folder and return position
int entries;
// determine the index of the mail to be selected afterwards
if(xget(G->MA->GUI.PG_MAILLIST, MUIA_MainMailList_SortOrderReversed) == TRUE)
{
if(pos >= 1)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, --pos);
else
closeAfter = TRUE;
}
// move the mail to the selected destination folder
MA_MoveCopy(mail, dstfolder, "manual move", 0);
// erase the old pointer as this has been free()ed by MA_MoveCopy()
rmData->mail = NULL;
// if there are still mails in the current folder we make sure
// it is displayed in this window now or close it
if(closeAfter == FALSE &&
(entries = xget(G->MA->GUI.PG_MAILLIST, MUIA_NList_Entries)) >= pos+1)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, pos, &mail);
if(mail != NULL)
DoMethod(obj, METHOD(ReadMail), mail);
else
closeAfter = TRUE;
}
else
closeAfter = TRUE;
// make sure the read window is closed in case there is no further
// mail for deletion in this direction
if(closeAfter == TRUE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
AppendToLogfile(LF_NORMAL, 22, tr(MSG_LOG_Moving), 1, srcfolder->Name, dstfolder->Name);
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(CopyMailRequest)
DECLARE(CopyMailRequest)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *srcfolder = mail->Folder;
ENTER();
if(MailExists(mail, srcfolder) == TRUE)
{
struct Folder *dstfolder = FolderRequest(tr(MSG_MA_CopyMsg),
tr(MSG_MA_MoveMsgReq),
tr(MSG_MA_CopyGad),
tr(MSG_Cancel),
NULL,
obj);
if(dstfolder != NULL)
{
// if there is no source folder this is a virtual mail that we
// export to the destination folder
if(srcfolder != NULL)
{
MA_MoveCopy(mail, dstfolder, "manual copy", MVCPF_COPY);
AppendToLogfile(LF_NORMAL, 24, tr(MSG_LOG_Copying), 1, srcfolder->Name, dstfolder->Name);
}
else
{
char mfilePath[SIZE_PATHFILE];
if(MA_NewMailFile(dstfolder, mfilePath, sizeof(mfilePath)) == TRUE)
{
strlcpy(mail->MailFile, FilePart(mfilePath), sizeof(mail->MailFile));
if(RE_Export(rmData, rmData->readFile, mfilePath, "", 0, FALSE, FALSE, IntMimeTypeArray[MT_ME_EMAIL].ContentType) == TRUE)
{
struct Mail *newmail;
if((newmail = CloneMail(mail)) != NULL)
{
AddMailToFolder(newmail, dstfolder);
if(GetCurrentFolder() == dstfolder)
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_InsertSingle, newmail, MUIV_NList_Insert_Sorted);
setStatusToRead(newmail); // OLD status
}
}
}
}
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(ArchiveMailRequest)
DECLARE(ArchiveMailRequest)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *srcfolder = mail->Folder;
ENTER();
if(MailExists(mail, srcfolder) == TRUE)
{
BOOL closeAfter = FALSE;
int pos = SelectMessage(mail); // select the message in the folder and return position
int entries;
// determine the index of the mail to be selected afterwards
if(xget(G->MA->GUI.PG_MAILLIST, MUIA_MainMailList_SortOrderReversed) == TRUE)
{
if(pos >= 1)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, --pos);
else
closeAfter = TRUE;
}
// archive the mail
MA_ArchiveMail(mail);
// erase the old pointer as this has been free()ed by MA_DeleteSingle()
rmData->mail = NULL;
// if there are still mails in the current folder we make sure
// it is displayed in this window now or close it
if(closeAfter == FALSE &&
(entries = xget(G->MA->GUI.PG_MAILLIST, MUIA_NList_Entries)) >= pos+1)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, pos, &mail);
if(mail != NULL)
DoMethod(obj, METHOD(ReadMail), mail);
else
closeAfter = TRUE;
}
else
closeAfter = TRUE;
// make sure the read window is closed in case there is no further
// mail for deletion in this direction
if(closeAfter == TRUE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
}
RETURN(0);
return 0;
}
///
/// DECLARE(DeleteMailRequest)
DECLARE(DeleteMailRequest) // ULONG qualifier
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *folder = mail->Folder;
ENTER();
if(MailExists(mail, folder))
{
BOOL closeAfter = FALSE;
int pos = SelectMessage(mail); // select the message in the folder and return position
int entries;
struct Folder *delfolder = FO_GetFolderByType(FT_TRASH, NULL);
BOOL delatonce = isAnyFlagSet(msg->qualifier, (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT));
// determine the index of the mail to be selected afterwards
if(xget(G->MA->GUI.PG_MAILLIST, MUIA_MainMailList_SortOrderReversed) == TRUE)
{
if(pos >= 1)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, --pos);
else
closeAfter = TRUE;
}
// delete the mail
MA_DeleteSingle(mail, delatonce ? DELF_AT_ONCE|DELF_UPDATE_APPICON|DELF_CHECK_CONNECTIONS : DELF_UPDATE_APPICON|DELF_CHECK_CONNECTIONS);
// erase the old pointer as this has been free()ed by MA_DeleteSingle()
rmData->mail = NULL;
// if there are still mails in the current folder we make sure
// it is displayed in this window now or close it
if(closeAfter == FALSE &&
(entries = xget(G->MA->GUI.PG_MAILLIST, MUIA_NList_Entries)) >= pos+1)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, pos, &mail);
if(mail != NULL)
DoMethod(obj, METHOD(ReadMail), mail);
else
closeAfter = TRUE;
}
else
closeAfter = TRUE;
// make sure the read window is closed in case there is no further
// mail for deletion in this direction
if(closeAfter == TRUE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
if(delatonce || isSpamFolder(folder))
AppendToLogfile(LF_NORMAL, 20, tr(MSG_LOG_Deleting), 1, folder->Name);
else
AppendToLogfile(LF_NORMAL, 22, tr(MSG_LOG_Moving), 1, folder->Name, delfolder->Name);
}
RETURN(0);
return 0;
}
///
/// DECLARE(ClassifyMessage)
DECLARE(ClassifyMessage) // enum BayesClassification class
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *folder = mail->Folder;
struct Folder *spamFolder = FO_GetFolderByType(FT_SPAM, NULL);
struct Folder *incomingFolder = FO_GetFolderByType(FT_INCOMING, NULL);
enum BayesClassification class = msg->class;
ENTER();
if(MailExists(mail, folder) && spamFolder != NULL && incomingFolder != NULL)
{
if(hasStatusSpam(mail) == FALSE && class == BC_SPAM)
{
BOOL closeAfter = FALSE;
int pos = SelectMessage(mail); // select the message in the folder and return position
int entries;
// determine the index of the mail to be selected afterwards
if(xget(G->MA->GUI.PG_MAILLIST, MUIA_MainMailList_SortOrderReversed) == TRUE)
{
if(pos >= 1)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, --pos);
else
closeAfter = TRUE;
}
// mark the mail as user spam
AppendToLogfile(LF_VERBOSE, 90, tr(MSG_LOG_MAILISSPAM), AddrName(mail->From), mail->Subject);
BayesFilterSetClassification(mail, BC_SPAM);
setStatusToUserSpam(mail);
// move the mail
MA_MoveCopy(mail, spamFolder, "mark as spam", 0);
// erase the old pointer as this has been free()ed by MA_MoveCopy()
rmData->mail = NULL;
// if there are still mails in the current folder we make sure
// it is displayed in this window now or close it
if(closeAfter == FALSE &&
(entries = xget(G->MA->GUI.PG_MAILLIST, MUIA_NList_Entries)) >= pos+1)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, pos, &mail);
if(mail != NULL)
DoMethod(obj, METHOD(ReadMail), mail);
else
closeAfter = TRUE;
}
else
closeAfter = TRUE;
// make sure the read window is closed in case there is no further
// mail for deletion in this direction
if(closeAfter == TRUE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
else
{
// only update the menu/toolbar if we are already in the spam folder
// otherwise a new mail will be read later or the window is closed
if(folder == spamFolder)
DoMethod(obj, METHOD(UpdateSpamControls));
// update the status bar
DoMethod(obj, METHOD(UpdateStatusBar));
}
}
else if(hasStatusHam(mail) == FALSE && class == BC_HAM)
{
BOOL closeAfter = FALSE;
int pos = SelectMessage(mail); // select the message in the folder and return position
int entries;
// determine the index of the mail to be selected afterwards
if(xget(G->MA->GUI.PG_MAILLIST, MUIA_MainMailList_SortOrderReversed) == TRUE)
{
if(pos >= 1)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, --pos);
else
closeAfter = TRUE;
}
// mark the mail as ham
AppendToLogfile(LF_VERBOSE, 90, tr(MSG_LOG_MAILISNOTSPAM), AddrName(mail->From), mail->Subject);
BayesFilterSetClassification(mail, BC_HAM);
setStatusToHam(mail);
if(C->MoveHamToIncoming == TRUE)
{
BOOL moveToIncoming = TRUE;
// first try to apply the filters to this mail, if requested
if(C->FilterHam == TRUE)
{
struct MinList *filterList;
if((filterList = CloneFilterList(APPLY_USER)) != NULL)
{
// FI_FilterSingleMail() returns TRUE if the filters didn't move or delete the mail.
// If the mail is still in place after filtering we will move it back to the incoming
// folder later.
moveToIncoming = FI_FilterSingleMail(filterList, mail, NULL, NULL);
DeleteFilterList(filterList);
}
}
// if the mail has not been moved to another folder before we move it to the incoming folder now.
if(moveToIncoming == TRUE)
MA_MoveCopy(mail, incomingFolder, "mark as ham", 0);
// erase the old pointer as this has been free()ed by MA_MoveCopy() or by the filter action
rmData->mail = NULL;
// if there are still mails in the current folder we make sure
// it is displayed in this window now or close it
if(closeAfter == FALSE &&
(entries = xget(G->MA->GUI.PG_MAILLIST, MUIA_NList_Entries)) >= pos+1)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, pos, &mail);
if(mail != NULL)
DoMethod(obj, METHOD(ReadMail), mail);
else
closeAfter = TRUE;
}
else
closeAfter = TRUE;
// make sure the read window is closed in case there is no further
// mail for deletion in this direction
if(closeAfter == TRUE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
else
{
// only update the menu/toolbar if we are already in the incoming folder
// otherwise a new mail will be read later or the window is closed
if(folder == incomingFolder)
DoMethod(obj, METHOD(UpdateSpamControls));
// update the status bar
DoMethod(obj, METHOD(UpdateStatusBar));
}
}
else
{
// update the menu/toolbar
DoMethod(obj, METHOD(UpdateSpamControls));
// update the status bar
DoMethod(obj, METHOD(UpdateStatusBar));
}
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(GrabSenderAddress)
// Stores sender address of current message in the address book
DECLARE(GrabSenderAddress)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
ENTER();
if(MailExists(mail, mail->Folder) == TRUE)
{
struct MailList *mlist;
if((mlist = CreateMailList()) != NULL)
{
AddNewMailNode(mlist, mail);
MA_GetAddress(mlist, NULL, 0);
DeleteMailList(mlist);
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(SetStatusTo)
// Sets the status of the current mail to the define value
DECLARE(SetStatusTo) // int addflags, int clearflags
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
ENTER();
MA_ChangeMailStatus(mail, msg->addflags, msg->clearflags);
DoMethod(data->statusBar, MUIM_ReadWindowStatusBar_Update, mail);
DisplayStatistics(NULL, TRUE);
RETURN(0);
return 0;
}
///
/// DECLARE(ChangeSubjectRequest)
// Changes the subject of the current message
DECLARE(ChangeSubjectRequest)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
struct Folder *folder = mail->Folder;
ENTER();
if(MailExists(mail, folder))
{
char subj[SIZE_SUBJECT];
strlcpy(subj, mail->Subject, sizeof(subj));
if(StringRequest(subj, SIZE_SUBJECT,
tr(MSG_MA_ChangeSubj),
tr(MSG_MA_ChangeSubjReq),
tr(MSG_Okay), NULL, tr(MSG_Cancel), FALSE, obj))
{
MA_ChangeSubject(mail, subj);
if(DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_MainMailListGroup_RedrawMail, mail))
{
MA_ChangeSelected(TRUE);
DisplayStatistics(mail->Folder, TRUE);
}
// update this window
DoMethod(obj, METHOD(ReadMail), mail);
}
}
RETURN(0);
return 0;
}
///
/// DECLARE(SwitchMail)
// Goes to next or previous (new) message in list
DECLARE(SwitchMail) // LONG direction, ULONG qualifier
{
GETDATA;
struct ReadMailData *rmData;
struct Mail *mail;
struct Folder *folder;
LONG direction;
LONG act = MUIV_NList_GetPos_Start;
BOOL onlynew;
BOOL found = FALSE;
ENTER();
rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
mail = rmData->mail;
folder = mail->Folder;
direction = msg->direction;
onlynew = isAnyFlagSet(msg->qualifier, (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT));
// we have to make sure that the folder the next/prev mail will
// be showed from is active, that`s why we call ChangeFolder with TRUE.
MA_ChangeFolder(folder, TRUE);
// after changing the folder we have to get the MailInfo (Position etc.)
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, mail, &act);
D(DBF_GUI, "act: %ld - direction: %ld", act, direction);
if(act != MUIV_NList_GetPos_End)
{
for(act += direction; act >= 0; act += direction)
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, act, &mail);
if(mail == NULL)
break;
if(onlynew == FALSE ||
(hasStatusNew(mail) || !hasStatusRead(mail)))
{
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, act);
DoMethod(obj, METHOD(ReadMail), mail);
// this is a valid break and not break because of an error
found = TRUE;
break;
}
}
}
// check if there are following/previous folders with unread
// mails and change to there if the user wants
if(found == FALSE && onlynew == TRUE)
{
if(C->AskJumpUnread == TRUE)
{
struct FolderNode *fnode;
BOOL abortJump;
BOOL turnOver;
LockFolderListShared(G->folders);
// look for the current folder in the array
ForEachFolderNode(G->folders, fnode)
{
if(fnode->folder == folder)
break;
}
abortJump = FALSE;
turnOver = FALSE;
while(found == FALSE && abortJump == FALSE)
{
struct FolderNode *fnode2;
// look for first folder with at least one unread mail
// and if found read that mail
do
{
// either go forward or backward
if(direction > 0)
fnode2 = (fnode == NULL) ? FirstFolderNode(G->folders) : NextFolderNode(fnode);
else
fnode2 = (fnode == NULL) ? LastFolderNode(G->folders) : PreviousFolderNode(fnode);
if(fnode2 != NULL)
{
struct Folder *fo = fnode2->folder;
// skip group folders, outgoing, trash and spam folder when looking for still unread mail
if(!isGroupFolder(fo) &&
!isOutgoingFolder(fo) &&
!isTrashFolder(fo) &&
!isSpamFolder(fo) &&
fo->Unread > 0)
{
if(fo != folder)
{
if(MUI_Request(_app(obj), obj, MUIF_NONE, tr(MSG_MA_ConfirmReq),
tr(MSG_YesNoReq),
tr(MSG_RE_MoveNextFolderReq), fo->Name) == 0)
{
abortJump = TRUE;
break;
}
MA_ChangeFolder(fo, TRUE);
}
else
{
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_MainMailListGroup_JumpToFirstNewMailOfFolder, fo);
}
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &mail);
if(mail == NULL)
break;
DoMethod(obj, METHOD(ReadMail), mail);
// this is a valid break and not break because of an error
found = TRUE;
break;
}
fnode = fnode2;
}
}
while(fnode2 != NULL);
// beep if no folder with unread mails was found
if(found == FALSE && fnode2 == NULL)
{
if(turnOver == TRUE)
{
// we already run through the complete list and found nothing
DisplayBeep(_screen(obj));
// get out of this loop
break;
}
else
{
// we just reached the end of the folder list for the first time,
// so let's try it again from the opposite side
turnOver = TRUE;
fnode = NULL;
}
}
}
UnlockFolderList(G->folders);
}
else
DisplayBeep(_screen(obj));
}
// if we didn't find any next/previous mail (mail == NULL) then
// we can close the window accordingly. This signals a user that he/she
// reached the end of the mail list
if(found == FALSE)
DoMethod(_app(obj), MUIM_Application_PushMethod, _app(obj), 2, MUIM_YAMApplication_CleanupReadMailData, rmData);
RETURN(0);
return 0;
}
///
/// DECLARE(FollowThread)
// Follows a thread in either direction
DECLARE(FollowThread) // LONG direction
{
GETDATA;
struct ReadMailData *rmData;
struct Mail *mail;
struct Mail *fmail;
ENTER();
rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
mail = rmData->mail;
// depending on the direction we get the Question or Answer to the current Message
if((fmail = FindThread(mail, msg->direction > 0)) != NULL)
{
LONG pos = MUIV_NList_GetPos_Start;
// we have to make sure that the folder where the message will be showed
// from is active and ready to display the mail
MA_ChangeFolder(fmail->Folder, TRUE);
// get the position of the mail in the currently active listview
DoMethod(G->MA->GUI.PG_MAILLIST, MUIM_NList_GetPos, fmail, &pos);
// if the mail is displayed we make it the active one
if(pos != MUIV_NList_GetPos_End)
set(G->MA->GUI.PG_MAILLIST, MUIA_NList_Active, pos);
DoMethod(obj, METHOD(ReadMail), fmail);
}
else
{
// set the correct toolbar image and menuitem ghosted
if(msg->direction <= 0)
{
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_PREVTHREAD, MUIA_TheBar_Attr_Disabled, TRUE);
set(data->MI_PREVTHREAD, MUIA_Menuitem_Enabled, FALSE);
}
else
{
DoMethod(data->windowToolbar, MUIM_TheBar_SetAttr, TB_READ_NEXTTHREAD, MUIA_TheBar_Attr_Disabled, TRUE);
set(data->MI_NEXTTHREAD, MUIA_Menuitem_Enabled, FALSE);
}
DisplayBeep(_screen(obj));
}
RETURN(0);
return 0;
}
///
/// DECLARE(ChangeHeaderMode)
// Changes display options (header)
DECLARE(ChangeHeaderMode) // enum HeaderMode hmode
{
GETDATA;
ENTER();
// forward this method to the readMailGroup, it will update itself if necessary
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ChangeHeaderMode, msg->hmode);
RETURN(0);
return 0;
}
///
/// DECLARE(ChangeSenderInfoMode)
// Changes display options (sender info)
DECLARE(ChangeSenderInfoMode) // enum SInfoMode simode
{
GETDATA;
ENTER();
// forward this method to the readMailGroup, it will update itself if necessary
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ChangeSenderInfoMode, msg->simode);
RETURN(0);
return 0;
}
///
/// DECLARE(StyleOptionsChanged)
DECLARE(StyleOptionsChanged)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
BOOL updateHeader = FALSE;
BOOL updateText = FALSE;
BOOL tmp;
ENTER();
// check wrapHeaders diff
if((tmp = xget(data->MI_WRAPH, MUIA_Menuitem_Checked)) != rmData->wrapHeaders)
{
rmData->wrapHeaders = tmp;
updateHeader = TRUE;
}
// check useTextcolors diff
if((tmp = xget(data->MI_TCOLOR, MUIA_Menuitem_Checked)) != rmData->useTextcolors)
{
rmData->useTextcolors = tmp;
updateText = TRUE;
}
// check useTextstyles diff
if((tmp = xget(data->MI_TSTYLE, MUIA_Menuitem_Checked)) != rmData->useTextstyles)
{
rmData->useTextstyles = tmp;
updateText = TRUE;
}
// check useFixedFont diff
if((tmp = xget(data->MI_FFONT, MUIA_Menuitem_Checked)) != rmData->useFixedFont)
{
rmData->useFixedFont = tmp;
// update the font settings of TE_EDIT
set(data->readMailGroup, MUIA_TextEditor_FixedFont, rmData->useFixedFont);
}
// issue an update of the readMailGroup's components
if(updateHeader && updateText)
{
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ReadMail, rmData->mail,
MUIF_ReadMailGroup_ReadMail_UpdateOnly);
}
else if(updateText)
{
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_ReadMail, rmData->mail,
(MUIF_ReadMailGroup_ReadMail_UpdateOnly |
MUIF_ReadMailGroup_ReadMail_UpdateTextOnly));
}
else if(updateHeader)
{
DoMethod(data->readMailGroup, MUIM_ReadMailGroup_UpdateHeaderDisplay,
MUIF_ReadMailGroup_ReadMail_UpdateOnly);
}
RETURN(0);
return 0;
}
///
/// DECLARE(UpdateStatusBar)
DECLARE(UpdateStatusBar)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
ENTER();
// Update the status bar
if(rmData->mail != NULL)
DoMethod(data->statusBar, MUIM_ReadWindowStatusBar_Update, rmData->mail);
RETURN(0);
return 0;
}
///
/// DECLARE(UpdateSpamControls)
DECLARE(UpdateSpamControls)
{
GETDATA;
struct ReadMailData *rmData = (struct ReadMailData *)xget(data->readMailGroup, MUIA_ReadMailGroup_ReadMailData);
struct Mail *mail = rmData->mail;
ENTER();
if(C->SpamFilterEnabled)
{
BOOL isSpamMail = (mail != NULL) && !isVirtualMail(mail) && hasStatusSpam(mail);
// for each entry check if it exists and if it is part of the menu
// if not, create a new entry and add it to the current layout
if(data->MI_TOHAM == NULL || isChildOfFamily(data->MI_STATUS, data->MI_TOHAM) == FALSE)
{
if((data->MI_TOHAM = Menuitem(tr(MSG_MA_TONOTSPAM), NULL, TRUE, FALSE, RMEN_TOHAM)) != NULL)
DoMethod(data->MI_STATUS, MUIM_Family_Insert, data->MI_TOHAM, data->MI_TOUNREAD);
}
if(data->MI_TOHAM != NULL)
set(data->MI_TOHAM, MUIA_Menuitem_Enabled, isSpamMail);
if(data->MI_TOSPAM == NULL || isChildOfFamily(data->MI_STATUS, data->MI_TOSPAM) == FALSE)
{
if((data->MI_TOSPAM = Menuitem(tr(MSG_MA_TOSPAM), NULL, TRUE, FALSE, RMEN_TOSPAM)) != NULL)
DoMethod(data->MI_STATUS, MUIM_Family_Insert, data->MI_TOSPAM, data->MI_TOUNREAD);
}
if(data->MI_TOSPAM != NULL)
set(data->MI_TOSPAM, MUIA_Menuitem_Enabled, !isSpamMail);
}
else
{
// for each entry check if it exists and if it is part of the menu
// if yes, then remove the entry and dispose it
if(data->MI_TOSPAM != NULL && isChildOfFamily(data->MI_STATUS, data->MI_TOSPAM))
{
DoMethod(data->MI_STATUS, MUIM_Family_Remove, data->MI_TOSPAM);
MUI_DisposeObject(data->MI_TOSPAM);
data->MI_TOSPAM = NULL;
}
if(data->MI_TOHAM != NULL && isChildOfFamily(data->MI_STATUS, data->MI_TOHAM))
{
DoMethod(data->MI_STATUS, MUIM_Family_Remove, data->MI_TOHAM);
MUI_DisposeObject(data->MI_TOHAM);
data->MI_TOHAM = NULL;
}
}
// update the toolbar as well, so lets delegate
// the method call to it.
if(data->windowToolbar != NULL)
DoMethod(data->windowToolbar, MUIM_ReadWindowToolbar_UpdateSpamControls, mail);
RETURN(0);
return 0;
}
///
/// DECLARE(UpdateMenuShortcuts)
DECLARE(UpdateMenuShortcuts)
{
GETDATA;
ENTER();
// update the "Forward" items' shortcut
if(C->ForwardMode == FWM_ATTACH)
{
set(data->MI_FORWARD_ATTACH, MUIA_Menuitem_Shortcut, "W");
set(data->MI_FORWARD_INLINE, MUIA_Menuitem_Shortcut, NULL);
}
else if(C->ForwardMode == FWM_INLINE)
{
set(data->MI_FORWARD_ATTACH, MUIA_Menuitem_Shortcut, NULL);
set(data->MI_FORWARD_INLINE, MUIA_Menuitem_Shortcut, "W");
}
RETURN(0);
return 0;
}
///