/// Include
#include <exec/libraries.h>                 // exec
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>                        // dos
#include <dos/rdargs.h>
#include <libraries/mui.h>                  // libraries
#include <libraries/asl.h>
#include <libraries/gadtools.h>
#include <libraries/bbsread.h>
#include <mui/nlistview_mcc.h>              // mui
#include <mui/nlist_mcc.h>
#include <mui/textinput_mcc.h>
#include <clib/muimaster_protos.h>          // clib
#include <clib/alib_protos.h>
#include <clib/bbsread_protos.h>
#include <pragmas/muimaster_pragmas.h>      // pragmas
#include <pragmas/bbsread_pragmas.h>
#include <proto/exec.h>                     // proto
#include <proto/dos.h>
#include <proto/utility.h>
#include <proto/icon.h>

#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include <extrafuncs.h>
///
/// Support stuff
#ifndef REG
#ifdef _DCC
#define REG(x) __ ## x
#else
#define REG(x) register __ ## x
#endif
#endif

#ifndef ASM
#if defined __MAXON__ || defined __STORM__ || defined _DCC
#define ASM
#else
#define ASM __asm
#endif
#endif

#ifndef SAVEDS
#ifdef __MAXON__
#define SAVEDS
#endif
#if defined __STORM__ || defined __SASC
#define SAVEDS __saveds
#endif
#if defined _GCC || defined _DCC
#define SAVEDS __geta4
#endif
#endif
///
/// Defines
#define NEWSTACK_SIZE       (1024 * 16)

#define VERSION     "1.0"
#define VERSDATE    "1.9.98"

#define sprintf mysprintf

#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d)    ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

#define YOUR_MUI_SERIAL 1   // change this

#ifndef TAGBASE
#define TAGBASE ( TAG_USER | ( YOUR_MUI_SERIAL << 16 ))
#endif

#define MUIM_MyApp_DisposeObj           (TAGBASE + 1)

struct MUIP_MyApp_DisposeObj { ULONG MethodID; Object *Object; };

#define MUIM_MainWindow_Open            (TAGBASE + 1)
#define MUIM_MainWindow_Close           (TAGBASE + 2)
#define MUIM_MainWindow_AddFilter       (TAGBASE + 3)
#define MUIM_MainWindow_AddTrigger      (TAGBASE + 4)
#define MUIM_MainWindow_SetTrigger      (TAGBASE + 5)
#define MUIM_MainWindow_SetFilter       (TAGBASE + 6)
#define MUIM_MainWindow_AddAction       (TAGBASE + 7)
#define MUIM_MainWindow_SetAction       (TAGBASE + 8)
#define MUIM_MainWindow_GetTrigger      (TAGBASE + 9)
#define MUIM_MainWindow_GetFilter       (TAGBASE + 10)
#define MUIM_MainWindow_GetAction       (TAGBASE + 11)
#define MUIM_MainWindow_SetActionGroup  (TAGBASE + 12)

#define ACTION_GROUPS   7

struct MainWindowData {
        Object         *EMail;
        Object         *Outgoing;
        Object         *SortOutgoing;
        Object         *List;
        Object         *Filters;
        Object         *Actions;
        Object         *TriggerName;
        Object         *TriggerGroups;
        Object         *TriggerLeaveEMail;
        Object         *TriggerAddOutgoing;
        Object         *TriggerAddUser;
        Object         *TriggerMatchAll;
        Object         *FilterType;
        Object         *FilterWhere;
        Object         *FilterNot;
        Object         *FilterPattern;
        Object         *FilterKeyword;
        Object         *ActionAction;
        Object         *ActionGroups[ ACTION_GROUPS ];
        Object         *MailSystem;
        Object         *MailConf;
        Object         *MailAddress;
        Object         *RecentAdd;
        Object         *RecentDupes;
        Object         *RecentNoStats;
        Object         *SavePath;
        Object         *SaveFile;
        Object         *SaveSubFrom;
        Object         *SaveSubWith;
        Object         *SaveHeaders;
        Object         *SaveAppend;
        Object         *SaveBin;
        Object         *FwdConference;
        Object         *FwdAddress;
        Object         *FwdSubject;
        Object         *FwdFile;
        Object         *ScriptFile;
        Object         *ScriptArgs;
        struct Trigger *CurrentTrigger;
};

struct MUIP_MainWindow_Close      { ULONG MethodID; ULONG Save; };
struct MUIP_MainWindow_GetTrigger { ULONG MethodID; ULONG Redraw; };
struct MUIP_MainWindow_GetAction  { ULONG MethodID; ULONG Redraw; };

struct Trigger {
        TEXT            Name[80];
        BOOL            DelMsg;
        BOOL            DelUser;
        BOOL            MatchAll;
        BOOL            NoLocal;
        TEXT            Groups[512];
        struct MinList  Filters;
        struct MinList  Actions;
};

struct Filter {
        struct Filter  *Succ;
        struct Filter  *Pred;
        TEXT            Pattern[80];
        TEXT            Keyword[80];
        UBYTE           Type;
        UBYTE           Where;
        UBYTE           Not;
};

enum { FT_SUBSTR = 0, FT_STRING, FT_PATTERN };

#define FW_HEADER 6

struct Action {
        struct Action  *Succ;
        struct Action  *Pred;
        UBYTE           Action;

        union {

            struct CopyData {
                TEXT    System[80];
                TEXT    Conference[80];
                TEXT    Address[80];
            } Copy;     // also used for Split digest

            struct RecentData {
                BOOL    Add;
                BOOL    CheckDupes;
                BOOL    NoStats;
            } Recent;

            struct SaveMsgData {
                TEXT    Path[256];
                BOOL    Dir;
                TEXT    SubstituteFrom[80];
                TEXT    SubstituteWith[30];
                BOOL    Headers;
                BOOL    Append;
                BOOL    SaveBin;
            } SaveMsg;

            struct MailData {
                TEXT    Conference[80];
                TEXT    Address[80];
                TEXT    Subject[80];
                TEXT    TextFile[256];
            } Mail;     // also used for Forward

            struct ScriptData {
                TEXT    Script[256];
                TEXT    Args[80];
            } Script;

        } Data;
};

enum { ACT_COPY = 0, ACT_RECENT, ACT_SAVE, ACT_DIGEST, ACT_FORWARD, ACT_MAIL, ACT_SCRIPT };

#define MUIA_ConfWindow_Data            (TAGBASE + 1)

#define MUIM_ConfWindow_Open            (TAGBASE + 1)
#define MUIM_ConfWindow_Close           (TAGBASE + 2)

struct ConfWindowData {
        Object             *List;
        Object             *Conf;
        Object             *NewConf;
        struct PopConfData *PopData;
};

struct MUIP_ConfWindow_Close { ULONG MethodID; ULONG Ok; };

struct AddrWindowData {
        Object             *List;
        struct PopConfData *PopData;
};

#define MUIA_PopConf_System             (TAGBASE + 1)
#define MUIA_PopConf_Multi              (TAGBASE + 2)
#define MUIA_PopConf_DoAddress          (TAGBASE + 3)

#define MUIM_PopConf_Open               (TAGBASE + 1)

#ifdef String
#undef String
#endif

struct PopConfData {
        Object     *String;
        Object     *Popup;
        Object     *System;
        BOOL        Multi;
        BOOL        DoAddr;
};

struct UserInfo {
        TEXT        Name[80];
        TEXT        EMail[80];
};
///
/// Prototypes
void        FPutString( BPTR, STRPTR );
void        FGetString( BPTR, STRPTR );
Object     *MakeButton( STRPTR );
Object     *MakeString( STRPTR, ULONG );
Object     *MakeLabel( STRPTR );
Object     *MakeCheck( STRPTR );
Object     *MakeCycle( STRPTR *, STRPTR );
BOOL        GetFile( struct MainWindowData *, STRPTR );
LONG        xget( Object *, ULONG );
void        getstr( Object *, STRPTR );
ULONG       DoSuperNew( struct IClass *, Object *, ULONG, ... );

int                         main( int, char ** );
static void                 RealMain( void );
static void                 Setup( void );
static void                 CleanUp( ULONG );
static struct Library      *OpenBRLibrary( LONG );
static struct Node         *FindiName( struct List *, STRPTR );
static void                 ParseArguments( void );

static ULONG SAVEDS ASM     Application_Dispatcher( REG( a0 ) struct IClass *, REG( a2 ) Object *, REG( a1 ) Msg );
static ULONG                Application_DisposeObj( struct IClass *, Object *, struct MUIP_MyApp_DisposeObj * );

static ULONG SAVEDS ASM     MainWindow_Dispatcher( REG( a0 ) struct IClass *, REG( a2 ) Object *, REG( a1 ) Msg );
static ULONG                MainWindow_New( struct IClass *, Object *, struct opSet * );
static ULONG                MainWindow_Open( struct IClass *, Object *, struct opSet * );
static ULONG                MainWindow_Close( struct IClass *, Object *, struct MUIP_MainWindow_Close * );
static ULONG                MainWindow_AddTrigger( struct IClass *, Object *, Msg );
static ULONG                MainWindow_SetTrigger( struct IClass *, Object *, Msg );
static ULONG                MainWindow_GetTrigger( struct IClass *, Object *, struct MUIP_MainWindow_GetTrigger * );
static ULONG                MainWindow_AddFilter( struct IClass *, Object *, Msg );
static ULONG                MainWindow_SetFilter( struct IClass *, Object *, Msg );
static ULONG                MainWindow_GetFilter( struct IClass *, Object *, Msg );
static ULONG                MainWindow_SetActionGroup( struct IClass *, Object *, Msg );
static ULONG                MainWindow_AddAction( struct IClass *, Object *, Msg );
static ULONG                MainWindow_SetAction( struct IClass *, Object *, Msg );
static ULONG                MainWindow_GetAction( struct IClass *, Object *, struct MUIP_MainWindow_GetAction * );

static void                 RestoreTriggerLists( struct MainWindowData * );

static void SAVEDS ASM      System_ObjStrHook( REG( a2 ) Object *, REG( a1 ) Object * );

static ULONG SAVEDS ASM     List_DispHook( REG( a2 ) STRPTR *, REG( a1 ) struct Trigger * );
static void SAVEDS          List_DestHook( REG( a1 ) struct Trigger * );
static ULONG SAVEDS ASM     Filter_DispHook( REG( a2 ) STRPTR *, REG( a1 ) struct Filter * );
static void SAVEDS          Filter_DestHook( REG( a1 ) struct Filter * );
static ULONG SAVEDS ASM     Action_DispHook( REG( a2 ) STRPTR *, REG( a1 ) struct Action * );
static void SAVEDS          Action_DestHook( REG( a1 ) struct Action * );

static ULONG SAVEDS ASM     PopConf_Dispatcher( REG( a0 ) struct IClass *, REG( a2 ) Object *, REG( a1 ) Msg );
static ULONG                PopConf_New( struct IClass *, Object *, struct opSet * );
static ULONG                PopConf_Set( struct IClass *, Object *, struct opSet * );
static ULONG                PopConf_Open( struct IClass *, Object *, Msg );

static ULONG SAVEDS ASM     ConfWindow_Dispatcher( REG( a0 ) struct IClass *, REG( a2 ) Object *, REG( a1 ) Msg );
static ULONG                ConfWindow_New( struct IClass *, Object *, struct opSet * );
static ULONG                ConfWindow_Open( struct IClass *, Object *, Msg );
static ULONG                ConfWindow_Close( struct IClass *, Object *, struct MUIP_ConfWindow_Close * );

static ULONG SAVEDS ASM     AddrWindow_Dispatcher( REG( a0 ) struct IClass *, REG( a2 ) Object *, REG( a1 ) Msg );
static ULONG                AddrWindow_New( struct IClass *, Object *, struct opSet * );
static ULONG                AddrWindow_Open( struct IClass *, Object *, Msg );
static ULONG                AddrWindow_Close( struct IClass *, Object *, struct MUIP_ConfWindow_Close * );

static ULONG SAVEDS ASM     User_DispHook( REG( a2 ) STRPTR *, REG( a1 ) struct UserInfo * );
static void SAVEDS          User_DestHook( REG( a1 ) struct UserInfo * );
static LONG SAVEDS ASM      User_CmpHook( REG( a1 ) struct UserInfo *, REG( a2 ) struct UserInfo * );
///
/// Data
struct Library         *MUIMasterBase;
struct IntuitionBase   *IntuitionBase;
struct Library         *IconBase;
struct Library         *UtilityBase;
struct Library         *BBSReadBase;

static TEXT             Version[] = "\0SortMailPrefs "VERSION" ("VERSDATE") ©1998 Simone Tellini";

static struct StackSwapStruct   StackSwapper;
static BOOL                     StackSwapped = FALSE;
static struct Process          *MyTask;

#ifdef _DCC
extern struct WBStartup *_WBMsg;
#else
static struct WBStartup *_WBMsg;
#endif

extern struct ExecBase *SysBase;

static struct MUI_CustomClass  *CL_MyApp;
static struct MUI_CustomClass  *CL_MainWindow;
static struct MUI_CustomClass  *CL_ConfWindow;
static struct MUI_CustomClass  *CL_AddrWindow;
static struct MUI_CustomClass  *CL_PopConf;

static struct DiskObject   *SleepIcon = NULL;

static TEXT                 SystemName[256], ConfigName[256];

static struct List         *BBSList;
static struct BBSListItem  *CurrentBBS;

static STRPTR       WhereLabels[] = {
                        "from address",
                        "from name",
                        "to address",
                        "to name",
                        "subject",
                        "Reply-To",
                        "header",
                        "body",
                        NULL
                    };

static STRPTR       WhereTags[] = {
                        "FROMADDR",
                        "FROMNAME",
                        "TOADDR",
                        "TONAME",
                        "SUBJECT",
                        "REPLYTO",
                        "HEADER",
                        "BODY"
                    };

static STRPTR   ActionTags[] = {
                        "COPY",
                        "RECENT",
                        "SAVEMESSAGE",
                        "SPLITDIGEST",
                        "FORWARD",
                        "MAIL",
                        "EXTERNAL"
                };

static struct Hook  FilterDestHook = {
                        { NULL, NULL },
                        (HOOKFUNC)Filter_DestHook,
                        NULL, NULL
                    };

static struct Hook  ActionDestHook = {
                        { NULL, NULL },
                        (HOOKFUNC)Action_DestHook,
                        NULL, NULL
                    };
///


/// xget
LONG xget( Object *obj, ULONG attribute )
{
    LONG    x;

    get( obj, attribute, &x );

    return( x );
}
///
/// getstr
void getstr( Object *obj, STRPTR str )
{
    strcpy( str, (STRPTR)xget( obj, MUIA_String_Contents ));
}
///

/// DoSuperNew
ULONG DoSuperNew( struct IClass *cl, Object *obj, ULONG tag1, ... )
{
    return( DoSuperMethod( cl, obj, OM_NEW, &tag1, NULL ));
}
///
/// MakeButton
Object *MakeButton( STRPTR str )
{
    Object *obj = MUI_MakeObject( MUIO_Button, str );

    if( obj )
        set( obj, MUIA_CycleChain, TRUE );

    return( obj );
}
///
/// MakeString
Object *MakeString( STRPTR str, ULONG maxlen )
{
    Object *obj;
    UBYTE   ch = '\0', *ptr;

    if( ptr = strchr( str, '_' ))
        if( ch = ptr[1])
            ch = tolower( ch );

    obj = TextinputObject,
                StringFrame,
                MUIA_CycleChain,                            1,
                MUIA_Textinput_AdvanceOnCR,                 TRUE,
                MUIA_Textinput_Multiline,                   FALSE,
                MUIA_Textinput_MaxLen,                      maxlen,
                ch ? MUIA_ControlChar : TAG_IGNORE,         ch,
          End;

    return( obj );
}
///
/// MakeLabel
Object *MakeLabel( STRPTR str )
{
    return( MUI_MakeObject( MUIO_Label, str, MUIO_Label_SingleFrame ));
}
///
/// MakeCheck
Object *MakeCheck( STRPTR str )
{
    Object *obj = MUI_MakeObject( MUIO_Checkmark, str );

    if( obj )
        set( obj, MUIA_CycleChain, TRUE );

    return( obj );
}
///
/// MakeCycle
Object *MakeCycle( STRPTR *array, STRPTR title )
{
    Object *obj = MUI_MakeObject( MUIO_Cycle, title, array );

    if( obj )
        set( obj, MUIA_CycleChain, TRUE );

    return( obj );
}
///

/// Setup
static void Setup( void )
{
    if(!( IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", 37 )))
        CleanUp( 20 );

    if(!( IconBase = OpenLibrary( "icon.library", 36 )))
        CleanUp( 20 );

    if(!( UtilityBase = OpenLibrary( "utility.library", 36 )))
        CleanUp( 20 );

    if(!( MUIMasterBase = OpenLibrary( "muimaster.library", MUIMASTER_VMIN )))
        CleanUp( 20 );

    if(!( BBSReadBase = OpenBRLibrary( 3 )))
        CleanUp( 20 );

    CL_MyApp = MUI_CreateCustomClass( NULL, MUIC_Application,
                                      NULL, 0,
                                      Application_Dispatcher );

    CL_MainWindow = MUI_CreateCustomClass( NULL, MUIC_Window,
                                           NULL, sizeof( struct MainWindowData ),
                                           MainWindow_Dispatcher );

    CL_ConfWindow = MUI_CreateCustomClass( NULL, MUIC_Window,
                                           NULL, sizeof( struct ConfWindowData ),
                                           ConfWindow_Dispatcher );

    CL_AddrWindow = MUI_CreateCustomClass( NULL, MUIC_Window,
                                           NULL, sizeof( struct AddrWindowData ),
                                           AddrWindow_Dispatcher );

    CL_PopConf = MUI_CreateCustomClass( NULL, MUIC_Group,
                                        NULL, sizeof( struct PopConfData ),
                                        PopConf_Dispatcher );

    if(!( CL_MyApp && CL_MainWindow && CL_ConfWindow && CL_AddrWindow && CL_PopConf ))
        CleanUp( 20 );

    ParseArguments();

    if( SystemName[0] ) {

        if( BBSList = GetBBSList() )
            if( CurrentBBS = ( struct BBSListItem * )FindiName( BBSList, SystemName )) {

                stccpy( ConfigName, CurrentBBS->bl_BBSPath, sizeof( ConfigName ));

                AddPart( ConfigName, "SortMail.cfg", sizeof( ConfigName ));
            }
    }
}
///
/// CleanUp
static void CleanUp( ULONG RetCode )
{
    if( BBSList )
        FreeBRObject( BBSList );

    if( CL_MainWindow )     MUI_DeleteCustomClass( CL_MainWindow );
    if( CL_ConfWindow )     MUI_DeleteCustomClass( CL_ConfWindow );
    if( CL_AddrWindow )     MUI_DeleteCustomClass( CL_AddrWindow );
    if( CL_PopConf    )     MUI_DeleteCustomClass( CL_PopConf    );
    if( CL_MyApp      )     MUI_DeleteCustomClass( CL_MyApp      );

    if( SleepIcon )
        FreeDiskObject( SleepIcon );

    if( StackSwapped ) {
        StackSwap( &StackSwapper );
        FreeMem( StackSwapper.stk_Lower, NEWSTACK_SIZE );
    }

    if( BBSReadBase     )   CloseLibrary( BBSReadBase   );
    if( MUIMasterBase   )   CloseLibrary( MUIMasterBase );
    if( UtilityBase     )   CloseLibrary( UtilityBase   );
    if( IconBase        )   CloseLibrary( IconBase      );
    if( IntuitionBase   )   CloseLibrary((struct Library *)IntuitionBase );

    exit( RetCode );
}
///
/// OpenBRLibrary
static struct Library *OpenBRLibrary( LONG version )
{
    TEXT            envbuf[256];
    struct Library *BBSReadBase = NULL;

    if( GetVar( ENV_THORPATH, envbuf, 256, GVF_GLOBAL_ONLY )) {

        if( AddPart( envbuf, "libs/" BBSREADNAME, 256 )) {
            BBSReadBase = OpenLibrary( envbuf, version );
        }
    }

    if(!( BBSReadBase ))
        BBSReadBase = OpenLibrary( BBSREADNAME, version );

    return( BBSReadBase );
}
///
/// FindiName
static struct Node *FindiName( struct List *list, STRPTR name )
{
    struct Node *node;

    node = ( struct Node * )&list->lh_Head;

    while(( node = node->ln_Succ )->ln_Succ )
        if( stricmp( name, node->ln_Name ) == 0 )
            return( node );

    return( NULL );
}
///
/// ParseArguments
enum {
    ARG_SYSTEM = 0,
    NUM_ARGS
};

static void ParseArguments( void )
{
    struct DiskObject  *icon;

    if (!( _WBMsg )) {
        struct RDArgs  *Arguments;
        ULONG           ArgArray[ NUM_ARGS ];
        TEXT            buf[256], name[256];

        memset( ArgArray, 0, sizeof( ArgArray ));

        if( Arguments = ReadArgs( "SYSTEM/A",
                                  (LONG *)ArgArray, NULL )) {

            stccpy( SystemName, (STRPTR)ArgArray[ ARG_SYSTEM ], sizeof( SystemName ));
        }

        GetProgramName( buf, sizeof( buf ));

        sprintf( name, "PROGDIR:%s", buf );

        icon = GetDiskObject( name );

    } else {
        struct WBArg   *Args;

        Args = _WBMsg->sm_ArgList;

        if( icon = GetDiskObject( Args[0].wa_Name )) {
            STRPTR  value;

            if( value = FindToolType( icon->do_ToolTypes, "SYSTEM" ))
                stccpy( SystemName, value, sizeof( SystemName ));
        }
    }

    if( icon )
        SleepIcon = icon;
}
///


/// main
void wbmain( void *Msg )
{
#ifndef _DCC
    _WBMsg = Msg;
#endif

    main( 0, NULL );
}

int main( int argc, char *argv[] )
{
    if( SysBase->LibNode.lib_Version < 37 ) {

        if( IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", 0 )) {
            static UBYTE AlertData[] = "\0\214\020SortMailPrefs requires kickstart v37+ !!!\0\0";

            DisplayAlert( RECOVERY_ALERT, AlertData, 30 );

            CloseLibrary(( struct Library * )IntuitionBase );
        }

        exit( 30 );
    }

    MyTask = (struct Process *) FindTask( NULL );

    if(((ULONG)MyTask->pr_Task.tc_SPUpper - (ULONG)MyTask->pr_Task.tc_SPLower ) < NEWSTACK_SIZE ) {

        if(!( StackSwapper.stk_Lower = AllocMem( NEWSTACK_SIZE, 0L )))
            CleanUp( 20 );

        StackSwapper.stk_Upper   = (ULONG)StackSwapper.stk_Lower + NEWSTACK_SIZE;
        StackSwapper.stk_Pointer = (APTR)StackSwapper.stk_Upper;

        StackSwap( &StackSwapper );
        StackSwapped = TRUE;
    }

    RealMain();
}
///
/// RealMain
static void RealMain( void )
{
    Object *AppObj, *MainWin;

    Setup();

    if( AppObj = NewObject( CL_MyApp->mcc_Class, NULL,

                        MUIA_Application_Title,         "SortMail Prefs",
                        MUIA_Application_Version,       "SortMail Prefs "VERSION" ("VERSDATE")",
                        MUIA_Application_Copyright,     "Copyright ©1998 by Simone Tellini",
                        MUIA_Application_Author,        "Simone Tellini <wiz@pragmanet.it>",
                        MUIA_Application_Description,   "SortMail MUI Prefs editor",
                        MUIA_Application_Base,          "SORTMAILPREFS",

                        SubWindow, MainWin = NewObject( CL_MainWindow->mcc_Class, NULL, TAG_DONE ),
                   End ) {
        ULONG   sigs = 0;

        DoMethod( MainWin, MUIM_MainWindow_Open );

        while( DoMethod( AppObj, MUIM_Application_NewInput, &sigs ) != MUIV_Application_ReturnID_Quit ) {
            if( sigs ) {

                sigs = Wait( sigs | SIGBREAKF_CTRL_C );

                if( sigs & SIGBREAKF_CTRL_C )
                    break;
            }
        }

        MUI_DisposeObject( AppObj );
    }

    CleanUp( 0 );
}
///

/// Application_Dispatcher
static ULONG SAVEDS ASM Application_Dispatcher( REG( a0 ) struct IClass *cl, REG( a2 ) Object *obj, REG( a1 ) Msg msg )
{
    switch( msg->MethodID ) {

        case MUIM_MyApp_DisposeObj:
            return( Application_DisposeObj( cl, obj, (APTR)msg ));
    }

    return( DoSuperMethodA( cl, obj, msg ));
}
///
/// Application_DisposeObj
static ULONG Application_DisposeObj( struct IClass *cl, Object *obj, struct MUIP_MyApp_DisposeObj *msg )
{
    MUI_DisposeObject( msg->Object );

    return( 0 );
}
///

/// MainWindow_Dispatcher
static ULONG SAVEDS ASM MainWindow_Dispatcher( REG( a0 ) struct IClass *cl, REG( a2 ) Object *obj, REG( a1 ) Msg msg )
{
    switch( msg->MethodID ) {

        case OM_NEW:
            return( MainWindow_New( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_Open:
            return( MainWindow_Open( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_Close:
            return( MainWindow_Close( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_AddTrigger:
            return( MainWindow_AddTrigger( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_SetTrigger:
            return( MainWindow_SetTrigger( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_GetTrigger:
            return( MainWindow_GetTrigger( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_AddFilter:
            return( MainWindow_AddFilter( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_SetFilter:
            return( MainWindow_SetFilter( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_GetFilter:
            return( MainWindow_GetFilter( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_SetActionGroup:
            return( MainWindow_SetActionGroup( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_AddAction:
            return( MainWindow_AddAction( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_SetAction:
            return( MainWindow_SetAction( cl, obj, (APTR)msg ));

        case MUIM_MainWindow_GetAction:
            return( MainWindow_GetAction( cl, obj, (APTR)msg ));
    }

    return( DoSuperMethodA( cl, obj, msg ));
}
///
/// MainWindow_New
static ULONG MainWindow_New( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct MainWindowData   temp = { 0 };
    static struct Hook      DispHook = {
                { NULL, NULL },
                (HOOKFUNC)List_DispHook,
                NULL, NULL
    };
    static struct Hook      DestHook = {
                { NULL, NULL },
                (HOOKFUNC)List_DestHook,
                NULL, NULL
    };
    static struct Hook      FilterDispHook = {
                { NULL, NULL },
                (HOOKFUNC)Filter_DispHook,
                NULL, NULL
    };
    static struct Hook      ActionDispHook = {
                { NULL, NULL },
                (HOOKFUNC)Action_DispHook,
                NULL, NULL
    };
    static struct Hook      StrHook = {
                { NULL, NULL },
                (HOOKFUNC)System_ObjStrHook,
                NULL, NULL
    };
    static STRPTR           Labels[] = {
                                "Filters",
                                "Actions",
                                NULL
                            };
    static STRPTR           InLabels[] = {
                                "in",
                                "not in",
                                NULL
                            };
    static STRPTR           FilterTypes[] = {
                                "sub string",
                                "string",
                                "pattern",
                                NULL
                            };
    static STRPTR           Actions[] = {
                                "Copy message to another conference",
                                "Parse AmiNet RECENT message",
                                "Save message to disk",
                                "Split digest",
                                "Forward message",
                                "Mail text file",
                                "Run an external ARexx script",
                                NULL
                            };
    static STRPTR           SaveLabels[] = {
                                "File",
                                "Dir",
                                NULL
                            };
    enum { M_ABOUT_MUI = 1, M_QUIT, M_SAVE, M_PREFS_MUI };
    static struct NewMenu   MainNewMenu[] = {
                NM_TITLE, "Project", NULL, 0, 0, NULL,
                  NM_ITEM, "About MUI...", "", 0, 0, (APTR)M_ABOUT_MUI,
                  NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0, NULL,
                  NM_ITEM, "Save & Quit", "S", 0, 0, (APTR)M_SAVE,
                  NM_ITEM, "Quit", "Q", 0, 0, (APTR)M_QUIT,
                NM_TITLE, "Settings", NULL, 0, 0, NULL,
                  NM_ITEM, "MUI...", "M", 0, 0, (APTR)M_PREFS_MUI,
                NM_END, NULL, NULL, 0, 0L, NULL
        };
    Object *AddTrigger, *RemTrigger, *Save, *Cancel, *AddFilter, *RemFilter;
    Object *AddAction, *RemAction, *TriggerGrp, *strip;
    Object *SettingsGrp, *PopActSystem, *SysList;

    if( obj = ( Object * )DoSuperNew( cl, obj,

                            MUIA_Window_Title,      "SortMail Prefs ©1998 by Simone Tellini",
                            MUIA_Window_ID,         MAKE_ID( 'M', 'A', 'I', 'N' ),
                            MUIA_Window_Menustrip,  strip = MUI_MakeObject( MUIO_MenustripNM, MainNewMenu, 0 ),

                            WindowContents, VGroup,

                                Child, VGroup, GroupFrameT( "Global options" ),

                                    Child, HGroup,
                                        Child, MakeLabel( "EMail conference" ),
                                        Child, temp.EMail = NewObject( CL_PopConf->mcc_Class, NULL, End,
                                    End,

                                    Child, HGroup,
                                        Child, MakeLabel( "Sort outgoing mail" ),
                                        Child, HGroup, MUIA_Group_Spacing, 0,
                                            Child, temp.SortOutgoing = MakeCheck( "Sort outgoing mail" ),
                                            Child, temp.Outgoing = NewObject( CL_PopConf->mcc_Class, NULL, End,
                                        End,
                                    End,
                                End,

                                Child, VGroup, GroupFrameT( "Triggers" ),

                                    Child, HGroup,

                                        Child, VGroup,

                                            Child, VGroup,

                                                MUIA_Group_Spacing, 0,

                                                Child, temp.List = NListviewObject,
                                                    MUIA_CycleChain,        TRUE,
                                                    MUIA_NListview_NList,   NListObject,
                                                        InputListFrame,
                                                        MUIA_NList_AutoVisible,     TRUE,
                                                        MUIA_NList_DragSortable,    TRUE,
                                                        MUIA_NList_DestructHook,    &DestHook,
                                                        MUIA_NList_DisplayHook,     &DispHook,
                                                        MUIA_NList_DragType,        MUIV_NList_DragType_Immediate,
                                                    End,
                                                End,

                                                Child, HGroup, MUIA_Group_Spacing, 0,
                                                    Child, AddTrigger = MakeButton( "Add" ),
                                                    Child, RemTrigger = MakeButton( "Remove" ),
                                                End,
                                            End,

                                            Child, TriggerGrp = VGroup,

                                                Child, ColGroup( 2 ),

                                                    Child, MakeLabel( "Name" ),
                                                    Child, temp.TriggerName = MakeString( "Name", 80 ),

                                                    Child, MakeLabel( "Groups" ),
                                                    Child, temp.TriggerGroups = NewObject( CL_PopConf->mcc_Class, NULL,
                                                        MUIA_PopConf_Multi, TRUE,
                                                    End,
                                                End,

                                                Child, ColGroup( 2 ),

                                                    Child, MakeLabel( "Leave in EMail" ),
                                                    Child, HGroup,
                                                        Child, temp.TriggerLeaveEMail = MakeCheck( "Leave in EMail" ),
                                                        Child, HSpace( 0 ),
                                                        Child, MakeLabel( "Add user" ),
                                                        Child, temp.TriggerAddUser = MakeCheck( "Add user" ),
                                                    End,

                                                    Child, MakeLabel( "Add outgoing messages" ),
                                                    Child, HGroup,
                                                        Child, temp.TriggerAddOutgoing = MakeCheck( "Add outgoung messages" ),
                                                        Child, HSpace( 0 ),
                                                        Child, MakeLabel( "Match all criterias" ),
                                                        Child, temp.TriggerMatchAll = MakeCheck( "Match all criterias" ),
                                                    End,
                                                End,
                                            End,
                                        End,

                                        Child, SettingsGrp = RegisterGroup( Labels ),

                                            /*              Filters             */
                                            Child, VGroup,

                                                Child, VGroup, MUIA_Group_Spacing, 0,

                                                    Child, temp.Filters = NListviewObject,
                                                        MUIA_CycleChain,        TRUE,
                                                        MUIA_NListview_NList,   NListObject,
                                                            InputListFrame,
                                                            MUIA_NList_Title,           TRUE,
                                                            MUIA_NList_AutoVisible,     TRUE,
                                                            MUIA_NList_DragSortable,    TRUE,
                                                            MUIA_NList_Format,          "BAR,BAR,",
                                                            MUIA_NList_DestructHook,    &FilterDestHook,
                                                            MUIA_NList_DisplayHook,     &FilterDispHook,
                                                            MUIA_NList_DragType,        MUIV_NList_DragType_Immediate,
                                                        End,
                                                    End,

                                                    Child, HGroup, MUIA_Group_Spacing, 0,
                                                        Child, AddFilter = MakeButton( "Add" ),
                                                        Child, RemFilter = MakeButton( "Remove" ),
                                                    End,
                                                End,

                                                Child, HGroup,
                                                    Child, MakeLabel( "Search for" ),
                                                    Child, temp.FilterPattern = MakeString( "", 80 ),
                                                End,

                                                Child, HGroup,
                                                    Child, MakeLabel( "as" ),
                                                    Child, temp.FilterType  = MakeCycle( FilterTypes, "" ),
                                                    Child, temp.FilterNot   = MakeCycle( InLabels, "" ),
                                                End,

                                                Child, HGroup,
                                                    Child, temp.FilterWhere   = MakeCycle( WhereLabels, "" ),
                                                    Child, temp.FilterKeyword = MakeString( "", 80 ),
                                                End,
                                            End,

                                            /*              Actions             */
                                            Child, VGroup,

                                                Child, VGroup, MUIA_Group_Spacing, 0,

                                                    Child, temp.Actions = NListviewObject,
                                                        MUIA_CycleChain,        TRUE,
                                                        MUIA_NListview_NList,   NListObject,
                                                            InputListFrame,
                                                            MUIA_NList_Title,           TRUE,
                                                            MUIA_NList_AutoVisible,     TRUE,
                                                            MUIA_NList_DragSortable,    TRUE,
                                                            MUIA_NList_Format,          "BAR,",
                                                            MUIA_NList_DestructHook,    &ActionDestHook,
                                                            MUIA_NList_DisplayHook,     &ActionDispHook,
                                                            MUIA_NList_DragType,        MUIV_NList_DragType_Immediate,
                                                        End,
                                                    End,

                                                    Child, HGroup, MUIA_Group_Spacing, 0,
                                                        Child, AddAction = MakeButton( "Add" ),
                                                        Child, RemAction = MakeButton( "Remove" ),
                                                    End,
                                                End,

                                                Child, HGroup,
                                                    Child, MakeLabel( "Action" ),
                                                    Child, temp.ActionAction = MakeCycle( Actions, "" ),
                                                End,

                                                Child, temp.ActionGroups[ ACT_COPY ] = temp.ActionGroups[ ACT_DIGEST ] = ColGroup( 2 ),

                                                    Child, MakeLabel( "System" ),
                                                    Child, PopActSystem = PopobjectObject,
                                                            MUIA_Popstring_String,      temp.MailSystem = MakeString( "System", 256 ),
                                                            MUIA_Popstring_Button,      PopButton( MUII_PopUp ),
                                                            MUIA_Popobject_ObjStrHook,  &StrHook,
                                                            MUIA_Popobject_Object,      SysList = ListviewObject,
                                                                    MUIA_Listview_List, ListObject,
                                                                        InputListFrame,
                                                                        MUIA_List_ConstructHook,    MUIV_List_ConstructHook_String,
                                                                        MUIA_List_DestructHook,     MUIV_List_DestructHook_String,
                                                                    End,
                                                            End,
                                                    End,

                                                    Child, MakeLabel( "Conference" ),
                                                    Child, temp.MailConf = NewObject( CL_PopConf->mcc_Class, NULL, End,

                                                    Child, MakeLabel( "Address" ),
                                                    Child, temp.MailAddress = NewObject( CL_PopConf->mcc_Class, NULL,
                                                        MUIA_PopConf_DoAddress, TRUE,
                                                    End,
                                                End,

                                                Child, temp.ActionGroups[ ACT_RECENT ] = ColGroup( 2 ),

                                                    MUIA_ShowMe,    FALSE,

                                                    Child, MakeLabel( "Add files" ),
                                                    Child, HGroup,
                                                        Child, temp.RecentAdd = MakeCheck( "Add files" ),
                                                        Child, HSpace( 0 ),
                                                        Child, MakeLabel( "Check dupes" ),
                                                        Child, temp.RecentDupes = MakeCheck( "Check dupes" ),
                                                    End,

                                                    Child, MakeLabel( "No statistics" ),
                                                    Child, HGroup,
                                                        Child, temp.RecentNoStats = MakeCheck( "No statistics" ),
                                                        Child, HSpace( 0 ),
                                                    End,
                                                End,

                                                Child, temp.ActionGroups[ ACT_SAVE ] = ColGroup( 2 ),

                                                    MUIA_ShowMe,    FALSE,

                                                    Child, temp.SaveFile = MakeCycle( SaveLabels, "" ),
                                                    Child, PopaslObject,
                                                        MUIA_Popstring_String,  temp.SavePath = MakeString( "", 256 ),
                                                        MUIA_Popstring_Button,  PopButton( MUII_PopFile ),
                                                        MUIA_Popasl_Type,       ASL_FileRequest,
                                                    End,

                                                    Child, MakeLabel( "Substitute" ),
                                                    Child, HGroup,
                                                        Child, temp.SaveSubFrom = MakeString( "", 80 ),
                                                        Child, MakeLabel( "with" ),
                                                        Child, temp.SaveSubWith = MakeString( "", 30 ),
                                                    End,

                                                    Child, MakeLabel( "Save headers" ),
                                                    Child, HGroup,
                                                        Child, temp.SaveHeaders =  MakeCheck( "" ),
                                                        Child, HSpace( 0 ),
                                                        Child, MakeLabel( "Append" ),
                                                        Child, temp.SaveAppend = MakeCheck( "" ),
                                                    End,

                                                    Child, MakeLabel( "Save binaries" ),
                                                    Child, HGroup,
                                                        Child, temp.SaveBin = MakeCheck( "" ),
                                                        Child, HSpace( 0 ),
                                                    End,
                                                End,

                                                Child, temp.ActionGroups[ ACT_FORWARD ] = temp.ActionGroups[ ACT_MAIL ] = ColGroup( 2 ),

                                                    MUIA_ShowMe,    FALSE,

                                                    Child, MakeLabel( "Conference" ),
                                                    Child, temp.FwdConference = NewObject( CL_PopConf->mcc_Class, NULL, End,

                                                    Child, MakeLabel( "Address" ),
                                                    Child, temp.FwdAddress = NewObject( CL_PopConf->mcc_Class, NULL,
                                                        MUIA_PopConf_DoAddress, TRUE,
                                                    End,

                                                    Child, MakeLabel( "Subject" ),
                                                    Child, temp.FwdSubject = MakeString( "", 80 ),

                                                    Child, MakeLabel( "Text file" ),
                                                    Child, PopaslObject,
                                                        MUIA_Popstring_String,  temp.FwdFile = MakeString( "", 256 ),
                                                        MUIA_Popstring_Button,  PopButton( MUII_PopFile ),
                                                        MUIA_Popasl_Type,       ASL_FileRequest,
                                                    End,
                                                End,

                                                Child, temp.ActionGroups[ ACT_SCRIPT ] = ColGroup( 2 ),

                                                    MUIA_ShowMe,    FALSE,

                                                    Child, MakeLabel( "Script" ),
                                                    Child, PopaslObject,
                                                        MUIA_Popstring_String,  temp.ScriptFile = MakeString( "", 256 ),
                                                        MUIA_Popstring_Button,  PopButton( MUII_PopFile ),
                                                        MUIA_Popasl_Type,       ASL_FileRequest,
                                                    End,

                                                    Child, MakeLabel( "Args" ),
                                                    Child, temp.ScriptArgs = MakeString( "", 80 ),

                                                    Child, HSpace( 0 ),
                                                    Child, TextObject,
                                                        MUIA_Font,          MUIV_Font_Tiny,
                                                        MUIA_Text_Contents, "%s - system name\n%c - email conference name\n%n - number of the message",
                                                    End,
                                                End,
                                            End,
                                        End,
                                    End,
                                End,

                                Child, HGroup, MUIA_Group_SameSize, TRUE,
                                    Child, Save   = MakeButton( "_Save" ),
                                    Child, Cancel = MakeButton( "_Cancel" ),
                                End,
                            End,

                        TAG_MORE, msg->ops_AttrList )) {

        struct MainWindowData  *data = INST_DATA( cl, obj );
        struct Node            *node;

        *data = temp;

        set( temp.Outgoing,       MUIA_Disabled,        TRUE );
        set( TriggerGrp,          MUIA_Disabled,        TRUE );
        set( SettingsGrp,         MUIA_Disabled,        TRUE );
        set( temp.FilterKeyword,  MUIA_Disabled,        TRUE );
        set( temp.MailConf,       MUIA_PopConf_System,  temp.MailSystem );

        for( node = BBSList->lh_Head; node->ln_Succ; node = node->ln_Succ )
            DoMethod( SysList, MUIM_List_InsertSingle, node->ln_Name, MUIV_List_Insert_Sorted );

        /*  Window  */
        DoMethod( obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 2, MUIM_MainWindow_Close, FALSE );

        /*  Gadgets */
        DoMethod( temp.SortOutgoing, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, temp.Outgoing, 3, MUIM_Set, MUIA_Disabled, MUIV_NotTriggerValue );

        DoMethod( temp.List, MUIM_Notify, MUIA_NList_Active, MUIV_EveryTime, obj, 1, MUIM_MainWindow_SetTrigger );
        DoMethod( temp.List, MUIM_Notify, MUIA_NList_Entries, MUIV_EveryTime, TriggerGrp, 3, MUIM_Set, MUIA_Disabled, MUIV_NotTriggerValue );
        DoMethod( temp.List, MUIM_Notify, MUIA_NList_Entries, MUIV_EveryTime, SettingsGrp, 3, MUIM_Set, MUIA_Disabled, MUIV_NotTriggerValue );

        DoMethod( temp.Filters, MUIM_Notify, MUIA_NList_Active, MUIV_EveryTime, obj, 1, MUIM_MainWindow_SetFilter );
        DoMethod( temp.Actions, MUIM_Notify, MUIA_NList_Active, MUIV_EveryTime, obj, 1, MUIM_MainWindow_SetAction );

        DoMethod( AddTrigger, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_MainWindow_AddTrigger );
        DoMethod( AddFilter,  MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_MainWindow_AddFilter  );
        DoMethod( AddAction,  MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_MainWindow_AddAction  );

        DoMethod( RemTrigger, MUIM_Notify, MUIA_Pressed, FALSE, temp.List,    2, MUIM_NList_Remove, MUIV_NList_Remove_Active );
        DoMethod( RemFilter,  MUIM_Notify, MUIA_Pressed, FALSE, temp.Filters, 2, MUIM_NList_Remove, MUIV_NList_Remove_Active );
        DoMethod( RemAction,  MUIM_Notify, MUIA_Pressed, FALSE, temp.Actions, 2, MUIM_NList_Remove, MUIV_NList_Remove_Active );

        DoMethod( temp.TriggerName,        MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, TRUE  );
        DoMethod( temp.TriggerGroups,      MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, FALSE );
        DoMethod( temp.TriggerLeaveEMail,  MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, FALSE );
        DoMethod( temp.TriggerAddOutgoing, MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, FALSE );
        DoMethod( temp.TriggerAddUser,     MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, FALSE );
        DoMethod( temp.TriggerMatchAll,    MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetTrigger, FALSE );

        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 0, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 1, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 2, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 3, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 4, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 5, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 6, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, FALSE );
        DoMethod( temp.FilterWhere, MUIM_Notify, MUIA_Cycle_Active, 7, temp.FilterKeyword, 3, MUIM_Set, MUIA_Disabled, TRUE  );

        DoMethod( temp.FilterType,    MUIM_Notify, MUIA_Cycle_Active,    MUIV_EveryTime, obj, 1, MUIM_MainWindow_GetFilter );
        DoMethod( temp.FilterWhere,   MUIM_Notify, MUIA_Cycle_Active,    MUIV_EveryTime, obj, 1, MUIM_MainWindow_GetFilter );
        DoMethod( temp.FilterNot,     MUIM_Notify, MUIA_Cycle_Active,    MUIV_EveryTime, obj, 1, MUIM_MainWindow_GetFilter );
        DoMethod( temp.FilterPattern, MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 1, MUIM_MainWindow_GetFilter );
        DoMethod( temp.FilterKeyword, MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 1, MUIM_MainWindow_GetFilter );

        DoMethod( temp.ActionAction, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, obj, 1, MUIM_MainWindow_SetActionGroup );

        DoMethod( temp.MailSystem,    MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.MailConf,      MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.MailAddress,   MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, TRUE  );
        DoMethod( temp.RecentAdd,     MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.RecentDupes,   MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.RecentNoStats, MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SavePath,      MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, TRUE  );
        DoMethod( temp.SaveFile,      MUIM_Notify, MUIA_Cycle_Active,    MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SaveSubFrom,   MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SaveSubWith,   MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SaveHeaders,   MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SaveAppend,    MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.SaveBin,       MUIM_Notify, MUIA_Selected,        MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.FwdConference, MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.FwdAddress,    MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, TRUE  );
        DoMethod( temp.FwdSubject,    MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.FwdFile,       MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );
        DoMethod( temp.ScriptFile,    MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, TRUE  );
        DoMethod( temp.ScriptArgs,    MUIM_Notify, MUIA_String_Contents, MUIV_EveryTime, obj, 2, MUIM_MainWindow_GetAction, FALSE );

        DoMethod( SysList, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, PopActSystem, 2, MUIM_Popstring_Close, TRUE );

        DoMethod( Save,   MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_MainWindow_Close, TRUE  );
        DoMethod( Cancel, MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_MainWindow_Close, FALSE );

        /*  Menus   */
        DoMethod(( Object * )DoMethod( strip, MUIM_FindUData, M_ABOUT_MUI ),
                  MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
                  MUIV_Notify_Application, 2, MUIM_Application_AboutMUI, obj );

        DoMethod(( Object * )DoMethod( strip, MUIM_FindUData, M_SAVE ),
                 MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, obj, 2, MUIM_MainWindow_Close, TRUE );

        DoMethod(( Object * )DoMethod( strip, MUIM_FindUData, M_QUIT ),
                 MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime, obj, 2, MUIM_MainWindow_Close, FALSE );

        DoMethod(( Object * )DoMethod( strip, MUIM_FindUData, M_PREFS_MUI ),
                  MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
                  MUIV_Notify_Application, 2, MUIM_Application_OpenConfigWindow, 0 );

        return(( ULONG )obj );
    }

    return( 0 );
}
///
/// MainWindow_Open
static ULONG MainWindow_Open( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    BPTR                    file;

    if( file = Open( ConfigName, MODE_OLDFILE )) {
        struct RDArgs  *args;

        if( args = AllocDosObject( DOS_RDARGS, NULL )) {
            TEXT    buf[1024];

            while( FGets( file, buf, sizeof( buf ) - 1 )) {

                strcat( buf, "\12" );

                args->RDA_Source.CS_CurChr = 0;
                args->RDA_DAList           = NULL;
                args->RDA_Buffer           = NULL;
                args->RDA_BufSiz           = 0L;
                args->RDA_Flags           |= RDAF_NOPROMPT;

                if( strncmp( buf, "GLOBAL", 6 ) == 0 ) {
                    enum { GLOBAL_SYSTEM = 0, GLOBAL_CONF, GLOBAL_STATS, GLOBAL_NOWARN,
                           GLOBAL_LOGINSTATE, GLOBAL_LOCALTO, NUM_GLOBAL_ARGS };
                    LONG            ArgArray[ NUM_GLOBAL_ARGS ];
                    struct RDArgs  *rdargs;

                    memset(( char * )ArgArray, 0, sizeof( ArgArray ));

                    args->RDA_Source.CS_Buffer = &buf[6];
                    args->RDA_Source.CS_Length = strlen( &buf[6] );

                    if( rdargs = ReadArgs( "SYSTEM/K,CONFERENCE/A,STATISTICS/S,NOWARN/S,LOGINSTATE/S,LOCALTO/K",
                                           ArgArray, args )) {

                        set( data->EMail, MUIA_String_Contents, ArgArray[ GLOBAL_CONF ]);

                        if( ArgArray[ GLOBAL_LOCALTO ]) {
                            set( data->SortOutgoing, MUIA_Selected, TRUE );
                            set( data->Outgoing, MUIA_String_Contents, ArgArray[ GLOBAL_LOCALTO ]);
                        }

                        FreeArgs( rdargs );
                    }

                } else if( strncmp( buf, "TRIGGER", 7 ) == 0 ) {
                    enum { TRIGGER_NAME = 0, TRIGGER_DELMSG, TRIGGER_DELUSER,
                           TRIGGER_MATCHALL, TRIGGER_NOLOCAL, TRIGGER_GROUPS, NUM_TRIGGER_ARGS };
                    LONG            ArgArray[ NUM_TRIGGER_ARGS ];
                    struct RDArgs  *rdargs;
                    struct Trigger *trigger;

                    memset(( char * )ArgArray, 0, sizeof( ArgArray ));

                    args->RDA_Source.CS_Buffer = &buf[7];
                    args->RDA_Source.CS_Length = strlen( &buf[7] );

                    if( rdargs = ReadArgs( "NAME/A,DELMSG/S,DELUSER/S,MATCHALL/S,NOLOCAL/S,GROUPS/K",
                                           ArgArray, args )) {

                        if( trigger = AllocMem( sizeof( struct Trigger ), MEMF_CLEAR )) {

                            NewList(( struct List * )&trigger->Filters );
                            NewList(( struct List * )&trigger->Actions );

                            stccpy( trigger->Name, (STRPTR)ArgArray[ TRIGGER_NAME ], sizeof( trigger->Name ));

                            if( ArgArray[ TRIGGER_DELMSG ])
                                trigger->DelMsg = TRUE;

                            if( ArgArray[ TRIGGER_DELUSER ])
                                trigger->DelUser = TRUE;

                            if( ArgArray[ TRIGGER_MATCHALL ])
                                trigger->MatchAll = TRUE;

                            if( ArgArray[ TRIGGER_NOLOCAL ])
                                trigger->NoLocal = TRUE;

                            if( ArgArray[ TRIGGER_GROUPS ])
                                stccpy( trigger->Groups, (STRPTR)ArgArray[ TRIGGER_GROUPS ], sizeof( trigger->Groups ));
                            else
                                strcpy( trigger->Groups, "EMail" );

                            DoMethod( data->List, MUIM_NList_InsertSingle, trigger, MUIV_NList_Insert_Bottom );

                        } else
                            break;

                        FreeArgs( rdargs );
                    }

                    while( FGets( file, buf, sizeof( buf ))) {

                        if( strncmp( buf, "ENDTRIGGER", 10 ) == 0 )
                            break;

                        strcat( buf, "\12" );

                        args->RDA_Source.CS_CurChr = 0;
                        args->RDA_DAList           = NULL;
                        args->RDA_Buffer           = NULL;
                        args->RDA_BufSiz           = 0L;
                        args->RDA_Flags           |= RDAF_NOPROMPT;

                        if( strncmp( buf, "SEARCH", 6 ) == 0 ) {
                            enum { SEARCH_TYPE = 0, SEARCH_CRITERIA, SEARCH_SUBSTR,
                                   SEARCH_KEYWORD, SEARCH_PATTERN, SEARCH_NOT, NUM_SEARCH_ARGS };
                            LONG            ArgArray[ NUM_SEARCH_ARGS ];
                            struct RDArgs  *rdargs;

                            memset(( char * )ArgArray, 0, sizeof( ArgArray ));

                            args->RDA_Source.CS_Buffer = &buf[6];
                            args->RDA_Source.CS_Length = strlen( &buf[6] );

                            if( rdargs = ReadArgs( "TYPE/A,CRITERIA/K,SUBSTR/K,KEYWORD/K,PATTERN/K,NOT/S",
                                                   ArgArray, args )) {
                                struct Filter  *filter;

                                if( filter = AllocMem( sizeof( struct Filter ), MEMF_CLEAR )) {
                                    ULONG   i;

                                    AddTail(( struct List * )&trigger->Filters, ( struct Node * )filter );

                                    for( i = 0; i < (sizeof( WhereTags ) / sizeof( STRPTR )); i++ )
                                        if( strcmp( WhereTags[ i ], (STRPTR)ArgArray[ SEARCH_TYPE ]) == 0 ) {
                                            filter->Where = i;
                                            break;
                                        }

                                    if( ArgArray[ SEARCH_CRITERIA ]) {
                                        filter->Type = FT_STRING;
                                        stccpy( filter->Pattern, (STRPTR)ArgArray[ SEARCH_CRITERIA ], sizeof( filter->Pattern ));
                                    }

                                    if( ArgArray[ SEARCH_SUBSTR ]) {
                                        filter->Type = FT_SUBSTR;
                                        stccpy( filter->Pattern, (STRPTR)ArgArray[ SEARCH_SUBSTR ], sizeof( filter->Pattern ));
                                    }

                                    if( ArgArray[ SEARCH_PATTERN ]) {
                                        filter->Type = FT_PATTERN;
                                        stccpy( filter->Pattern, (STRPTR)ArgArray[ SEARCH_PATTERN ], sizeof( filter->Pattern ));
                                    }

                                    if( ArgArray[ SEARCH_KEYWORD ])
                                        stccpy( filter->Keyword, (STRPTR)ArgArray[ SEARCH_KEYWORD ], sizeof( filter->Keyword ));

                                    if( ArgArray[ SEARCH_NOT ])
                                        filter->Not = TRUE;
                                }

                                FreeArgs( rdargs );
                            }

                        } else if( strncmp( buf, "ACTION", 6 ) == 0 ) {
                            enum { ACTION_TYPE = 0, ACTION_DESTCONF, ACTION_DESTSYS, ACTION_REPLYADDR,
                                   ACTION_SCRIPT, ACTION_SCRIPTOPTS, ACTION_FILE, ACTION_DIR,
                                   ACTION_SUBSTITUTE, ACTION_WITH, ACTION_SENDTO, ACTION_TEXTFILE,
                                   ACTION_SUBJECT, ACTION_HEADER, ACTION_APPEND, ACTION_NOBIN,
                                   ACTION_CHECKDUPES, ACTION_DONTADD, ACTION_NOSTATS,
                                   NUM_ACTION_ARGS };
                            LONG            ArgArray[ NUM_ACTION_ARGS ];
                            struct RDArgs  *rdargs;

                            memset(( char * )ArgArray, 0, sizeof( ArgArray ));

                            args->RDA_Source.CS_Buffer = &buf[6];
                            args->RDA_Source.CS_Length = strlen( &buf[6] );

                            if( rdargs = ReadArgs( "TYPE/A,DESTCONF/K,DESTSYS/K,REPLYADDR/K,SCRIPTNAME/K,"
                                                   "SCRIPTOPTS/K,FILENAME/K,DIRECTORY/K,SUBSTITUTE/K,WITH/K,"
                                                   "SENDTO/K,TEXTFILE/K,SUBJECT/K,HEADER/S,APPEND/S,NOBIN/S,"
                                                   "CHECKDUPES/S,DONTADD/S,NOSTATS/S",
                                                   ArgArray, args )) {
                                struct Action  *action;

                                if( action = AllocMem( sizeof( struct Action ), MEMF_CLEAR )) {
                                    ULONG   i;

                                    AddTail(( struct List * )&trigger->Actions, ( struct Node * )action );

                                    for( i = 0; i < (sizeof( ActionTags ) / sizeof( STRPTR )); i++ )
                                        if( strcmp( ActionTags[ i ], (STRPTR)ArgArray[ ACTION_TYPE ]) == 0 ) {
                                            action->Action = i;
                                            break;
                                        }

                                    switch( action->Action ) {

                                        case ACT_COPY:
                                        case ACT_DIGEST:
                                            if( ArgArray[ ACTION_DESTSYS ])
                                                stccpy( action->Data.Copy.System, (STRPTR)ArgArray[ ACTION_DESTSYS ], sizeof( action->Data.Copy.System ));

                                            if( ArgArray[ ACTION_DESTCONF ])
                                                stccpy( action->Data.Copy.Conference, (STRPTR)ArgArray[ ACTION_DESTCONF ], sizeof( action->Data.Copy.Conference ));

                                            if( ArgArray[ ACTION_REPLYADDR ])
                                                stccpy( action->Data.Copy.Address, (STRPTR)ArgArray[ ACTION_REPLYADDR ], sizeof( action->Data.Copy.Address ));
                                            break;

                                        case ACT_SAVE:
                                            if( ArgArray[ ACTION_FILE ])
                                                stccpy( action->Data.SaveMsg.Path, (STRPTR)ArgArray[ ACTION_FILE ], sizeof( action->Data.SaveMsg.Path ));

                                            if( ArgArray[ ACTION_DIR ]) {
                                                stccpy( action->Data.SaveMsg.Path, (STRPTR)ArgArray[ ACTION_DIR ], sizeof( action->Data.SaveMsg.Path ));
                                                action->Data.SaveMsg.Dir = TRUE;
                                            }

                                            if( ArgArray[ ACTION_SUBSTITUTE ])
                                                stccpy( action->Data.SaveMsg.SubstituteFrom, (STRPTR)ArgArray[ ACTION_SUBSTITUTE ], sizeof( action->Data.SaveMsg.SubstituteFrom ));

                                            if( ArgArray[ ACTION_WITH ])
                                                stccpy( action->Data.SaveMsg.SubstituteWith, (STRPTR)ArgArray[ ACTION_WITH ], sizeof( action->Data.SaveMsg.SubstituteWith ));

                                            if( ArgArray[ ACTION_HEADER ])
                                                action->Data.SaveMsg.Headers = TRUE;

                                            if( ArgArray[ ACTION_APPEND ])
                                                action->Data.SaveMsg.Append = TRUE;

                                            if(!( ArgArray[ ACTION_NOBIN ]))
                                                action->Data.SaveMsg.SaveBin = TRUE;
                                            break;

                                        case ACT_MAIL:
                                        case ACT_FORWARD:
                                            if( ArgArray[ ACTION_DESTCONF ])
                                                stccpy( action->Data.Mail.Conference, (STRPTR)ArgArray[ ACTION_DESTCONF ], sizeof( action->Data.Mail.Conference ));

                                            if( ArgArray[ ACTION_REPLYADDR ])
                                                stccpy( action->Data.Mail.Address, (STRPTR)ArgArray[ ACTION_REPLYADDR ], sizeof( action->Data.Mail.Address ));

                                            if( ArgArray[ ACTION_SUBJECT ])
                                                stccpy( action->Data.Mail.Subject, (STRPTR)ArgArray[ ACTION_SUBJECT ], sizeof( action->Data.Mail.Subject ));

                                            if( ArgArray[ ACTION_TEXTFILE ])
                                                stccpy( action->Data.Mail.TextFile, (STRPTR)ArgArray[ ACTION_TEXTFILE ], sizeof( action->Data.Mail.TextFile ));
                                            break;

                                        case ACT_RECENT:
                                            if( ArgArray[ ACTION_CHECKDUPES ])
                                                action->Data.Recent.CheckDupes = TRUE;

                                            if(!( ArgArray[ ACTION_DONTADD ]))
                                                action->Data.Recent.Add = TRUE;

                                            if( ArgArray[ ACTION_NOSTATS ])
                                                action->Data.Recent.NoStats = TRUE;
                                            break;

                                        case ACT_SCRIPT:
                                            if( ArgArray[ ACTION_SCRIPT ])
                                                stccpy( action->Data.Script.Script, (STRPTR)ArgArray[ ACTION_SCRIPT ], sizeof( action->Data.Script.Script ));

                                            if( ArgArray[ ACTION_SCRIPTOPTS ])
                                                stccpy( action->Data.Script.Args, (STRPTR)ArgArray[ ACTION_SCRIPTOPTS ], sizeof( action->Data.Script.Args ));
                                            break;
                                    }
                                }

                                FreeArgs( rdargs );
                            }
                        }
                    }
                }
            }

            FreeDosObject( DOS_RDARGS, args );
        }

        Close( file );
    }

    set( data->List, MUIA_NList_Active, MUIV_NList_Active_Top );

    set( obj, MUIA_Window_Open, TRUE );

    return( 0 );
}
///
/// MainWindow_Close
static ULONG MainWindow_Close( struct IClass *cl, Object *obj, struct MUIP_MainWindow_Close *msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );

    RestoreTriggerLists( data );

    if( msg->Save ) {
        BPTR    file;

        if( file = Open( ConfigName, MODE_NEWFILE )) {
            TEXT    buf[512], line[1024];
            ULONG   i;

            getstr( data->EMail, buf );

            sprintf( line, "GLOBAL CONFERENCE \"%s\"", buf );

            if( xget( data->SortOutgoing, MUIA_Selected )) {

                strcat( line, " LOCALTO \"" );

                getstr( data->Outgoing, &line[ strlen( line ) ]);

                strcat( line, "\"" );
            }

            FPrintf( file, "%s\n", line );

            for( i = 0;; i++ ) {
                struct Trigger *trigger;
                struct Filter  *filter;
                struct Action  *action;

                DoMethod( data->List, MUIM_NList_GetEntry, i, &trigger );

                if( trigger == NULL )
                    break;

                sprintf( line, "\nTRIGGER NAME \"%s\"", trigger->Name );

                if( trigger->DelMsg )
                    strcat( line, " DELMSG" );

                if( trigger->DelUser )
                    strcat( line, " DELUSER" );

                if( trigger->MatchAll )
                    strcat( line, " MATCHALL" );

                if( trigger->NoLocal )
                    strcat( line, " NOLOCAL" );

                if( trigger->Groups[0] && strcmp( trigger->Groups, "EMail" )) {
                    sprintf( buf, " GROUPS \"%s\"", trigger->Groups );
                    strcat( line, buf );
                }

                FPrintf( file, "%s\n", line );

                for( filter = (struct Filter *)trigger->Filters.mlh_Head; filter->Succ; filter = filter->Succ ) {
                    static STRPTR   TypeTags[] = { "SUBSTR", "CRITERIA", "PATTERN" };

                    sprintf( line, "SEARCH %s %s \"%s\"", WhereTags[ filter->Where ], TypeTags[ filter->Type ], filter->Pattern );

                    if( filter->Not )
                        strcat( line, " NOT" );

                    if( filter->Where == FW_HEADER ) {
                        sprintf( buf, " KEYWORD \"%s\"", filter->Keyword );
                        strcat( line, buf );
                    }

                    FPrintf( file, "%s\n", line );
                }

                for( action = (struct Action *)trigger->Actions.mlh_Head; action->Succ; action = action->Succ ) {

                    sprintf( line, "ACTION %s", ActionTags[ action->Action ]);

                    switch( action->Action ) {

                        case ACT_COPY:
                        case ACT_DIGEST:
                            if( action->Data.Copy.System[0] ) {
                                strcat( line, " DESTSYS \"" );
                                strcat( line, action->Data.Copy.System );
                                strcat( line, "\"" );
                            }

                            strcat( line, " DESTCONF \"" );
                            strcat( line, action->Data.Copy.Conference );
                            strcat( line, "\"" );

                            if( action->Data.Copy.Address[0] ) {
                                strcat( line, " REPLYADDR \"" );
                                strcat( line, action->Data.Copy.Address );
                                strcat( line, "\"" );
                            }
                            break;

                        case ACT_SAVE:
                            strcat( line, action->Data.SaveMsg.Dir ? " DIRECTORY \"" : " FILENAME \"" );
                            strcat( line, action->Data.SaveMsg.Path );
                            strcat( line, "\"" );

                            if( action->Data.SaveMsg.SubstituteFrom[0] ) {
                                strcat( line, " SUBSTITUTE \"" );
                                strcat( line, action->Data.SaveMsg.SubstituteFrom );
                                strcat( line, "\"" );
                            }

                            if( action->Data.SaveMsg.SubstituteWith[0] ) {
                                strcat( line, " WITH \"" );
                                strcat( line, action->Data.SaveMsg.SubstituteWith );
                                strcat( line, "\"" );
                            }

                            if( action->Data.SaveMsg.Headers )
                                strcat( line, " HEADER" );

                            if( action->Data.SaveMsg.Append )
                                strcat( line, " APPEND" );

                            if(!( action->Data.SaveMsg.SaveBin ))
                                strcat( line, " NOBIN" );
                            break;

                        case ACT_MAIL:
                        case ACT_FORWARD:
                            if( action->Data.Mail.Conference[0] ) {
                                strcat( line, " DESTCONF \"" );
                                strcat( line, action->Data.Mail.Conference );
                                strcat( line, "\"" );
                            }

                            if( action->Data.Mail.Address[0] ) {
                                strcat( line, " REPLYADDR \"" );
                                strcat( line, action->Data.Mail.Address );
                                strcat( line, "\"" );
                            }

                            if( action->Data.Mail.Subject[0] ) {
                                strcat( line, " SUBJECT \"" );
                                strcat( line, action->Data.Mail.Subject );
                                strcat( line, "\"" );
                            }

                            if( action->Data.Mail.TextFile[0] ) {
                                strcat( line, " TEXTFILE \"" );
                                strcat( line, action->Data.Mail.TextFile );
                                strcat( line, "\"" );
                            }
                            break;

                        case ACT_RECENT:
                            if( action->Data.Recent.CheckDupes )
                                strcat( line, " CHECKDUPES" );

                            if(!( action->Data.Recent.Add ))
                                strcat( line, " DONTADD" );

                            if( action->Data.Recent.NoStats )
                                strcat( line, " NOSTATS" );
                            break;

                        case ACT_SCRIPT:
                            strcat( line, " SCRIPTNAME \"" );
                            strcat( line, action->Data.Script.Script );

                            strcat( line, "\" SCRIPTOPTS \"" );
                            strcat( line, action->Data.Script.Args );
                            strcat( line, "\"" );
                            break;
                    }

                    FPrintf( file, "%s\n", line );
                }

                FPuts( file, "ENDTRIGGER\n" );
            }

            Close( file );
        }
    }

    set( obj, MUIA_Window_Open, FALSE );

    DoMethod( _app( obj ), MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit );

    return( 0 );
}
///
/// MainWindow_AddTrigger
static ULONG MainWindow_AddTrigger( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Trigger         *trigger;

    if( trigger = AllocMem( sizeof( *trigger ), MEMF_CLEAR )) {

        NewList(( struct List * )&trigger->Filters );
        NewList(( struct List * )&trigger->Actions );

        strcpy( trigger->Name, "- New Trigger -" );
        strcpy( trigger->Groups, "EMail" );

        DoMethod( data->List, MUIM_NList_InsertSingle, trigger, MUIV_NList_Insert_Bottom );

        set( data->List, MUIA_NList_Active, MUIV_NList_Active_Bottom );
    }

    return( 0 );
}
///
/// MainWindow_SetTrigger
static ULONG MainWindow_SetTrigger( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Trigger         *trigger;

    DoMethod( data->List, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &trigger );

    set( data->Filters, MUIA_NList_Quiet, TRUE );
    set( data->Actions, MUIA_NList_Quiet, TRUE );

    RestoreTriggerLists( data );

    if( data->CurrentTrigger = trigger ) {
        struct Filter  *filter;
        struct Action  *action;

        nnset( data->TriggerName,   MUIA_String_Contents, trigger->Name   );
        nnset( data->TriggerGroups, MUIA_String_Contents, trigger->Groups );

        nnset( data->TriggerLeaveEMail,  MUIA_Selected, !trigger->DelMsg  );
        nnset( data->TriggerAddOutgoing, MUIA_Selected, !trigger->NoLocal );
        nnset( data->TriggerAddUser,     MUIA_Selected, !trigger->DelUser );
        nnset( data->TriggerMatchAll,    MUIA_Selected, trigger->MatchAll );

        while( filter = (struct Filter *) RemHead(( struct List * )&trigger->Filters ))
            DoMethod( data->Filters, MUIM_NList_InsertSingle, filter, MUIV_NList_Insert_Bottom );

        set( data->Filters, MUIA_NList_Active, MUIV_NList_Active_Top );

        while( action = (struct Action *) RemHead(( struct List * )&trigger->Actions ))
            DoMethod( data->Actions, MUIM_NList_InsertSingle, action, MUIV_NList_Insert_Bottom );

        set( data->Actions, MUIA_NList_Active, MUIV_NList_Active_Top );
    }

    set( data->Filters, MUIA_NList_Quiet, FALSE );
    set( data->Actions, MUIA_NList_Quiet, FALSE );

    return( 0 );
}
///
/// MainWindow_GetTrigger
static ULONG MainWindow_GetTrigger( struct IClass *cl, Object *obj, struct MUIP_MainWindow_GetTrigger *msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Trigger         *trigger;

    DoMethod( data->List, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &trigger );

    if( trigger ) {

        getstr( data->TriggerName,   trigger->Name   );
        getstr( data->TriggerGroups, trigger->Groups );

        trigger->DelMsg   = !xget( data->TriggerLeaveEMail,  MUIA_Selected );
        trigger->NoLocal  = !xget( data->TriggerAddOutgoing, MUIA_Selected );
        trigger->DelUser  = !xget( data->TriggerAddUser,     MUIA_Selected );
        trigger->MatchAll =  xget( data->TriggerMatchAll,    MUIA_Selected );

        if( msg->Redraw )
            DoMethod( data->List, MUIM_NList_Redraw, MUIV_NList_Redraw_Active );
    }

    return( 0 );
}
///
/// MainWindow_AddFilter
static ULONG MainWindow_AddFilter( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Filter          *entry;

    if( entry = AllocMem( sizeof( *entry ), MEMF_CLEAR )) {

        DoMethod( data->Filters, MUIM_NList_InsertSingle, entry, MUIV_NList_Insert_Bottom );

        set( data->Filters, MUIA_NList_Active, MUIV_NList_Active_Bottom );
    }

    return( 0 );
}
///
/// MainWindow_SetFilter
static ULONG MainWindow_SetFilter( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Filter          *entry;

    DoMethod( data->Filters, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &entry );

    if( entry ) {

        nnset( data->FilterPattern, MUIA_String_Contents, entry->Pattern );
        nnset( data->FilterKeyword, MUIA_String_Contents, entry->Keyword );

        nnset( data->FilterType,  MUIA_Cycle_Active, entry->Type  );
        nnset( data->FilterWhere, MUIA_Cycle_Active, entry->Where );
        nnset( data->FilterNot,   MUIA_Cycle_Active, entry->Not   );

        set( data->FilterKeyword, MUIA_Disabled, entry->Where != FW_HEADER );
    }

    return( 0 );
}
///
/// MainWindow_GetFilter
static ULONG MainWindow_GetFilter( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Filter          *entry;

    DoMethod( data->Filters, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &entry );

    if( entry ) {

        getstr( data->FilterPattern, entry->Pattern );
        getstr( data->FilterKeyword, entry->Keyword );

        entry->Type  = xget( data->FilterType,  MUIA_Cycle_Active );
        entry->Where = xget( data->FilterWhere, MUIA_Cycle_Active );
        entry->Not   = xget( data->FilterNot,   MUIA_Cycle_Active );

        DoMethod( data->Filters, MUIM_NList_Redraw, MUIV_NList_Redraw_Active );
    }

    return( 0 );
}
///
/// MainWindow_SetActionGroup
static ULONG MainWindow_SetActionGroup( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    ULONG                   act;
    Object                 *parent;
    struct Action          *action;

    get( data->ActionAction, MUIA_Cycle_Active, &act );

    DoMethod( data->Actions, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &action );

    if( action ) {

        memset( &action->Data, 0, sizeof( action->Data ));

        action->Action = act;

        DoMethod( data->Actions, MUIM_NList_Redraw, MUIV_NList_Redraw_Active );
    }

    get( data->ActionGroups[0], MUIA_Parent, &parent );

    DoMethod( parent, MUIM_Group_InitChange );

    set( data->ActionGroups[ ACT_COPY   ], MUIA_ShowMe, ( act == ACT_COPY ) || ( act == ACT_DIGEST  ));
    set( data->ActionGroups[ ACT_MAIL   ], MUIA_ShowMe, ( act == ACT_MAIL ) || ( act == ACT_FORWARD ));
    set( data->ActionGroups[ ACT_RECENT ], MUIA_ShowMe, act == ACT_RECENT );
    set( data->ActionGroups[ ACT_SAVE   ], MUIA_ShowMe, act == ACT_SAVE   );
    set( data->ActionGroups[ ACT_SCRIPT ], MUIA_ShowMe, act == ACT_SCRIPT );

    DoMethod( parent, MUIM_Group_ExitChange );

    return( 0 );
}
///
/// MainWindow_AddAction
static ULONG MainWindow_AddAction( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Action          *entry;

    if( entry = AllocMem( sizeof( *entry ), MEMF_CLEAR )) {

        DoMethod( data->Actions, MUIM_NList_InsertSingle, entry, MUIV_NList_Insert_Bottom );

        set( data->Actions, MUIA_NList_Active, MUIV_NList_Active_Bottom );
    }

    return( 0 );
}
///
/// MainWindow_SetAction
static ULONG MainWindow_SetAction( struct IClass *cl, Object *obj, Msg msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Action          *action;

    DoMethod( data->Actions, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &action );

    if( action ) {
        Object *parent;

        nnset( data->ActionAction, MUIA_Cycle_Active, action->Action );

        switch( action->Action ) {

            case ACT_COPY:
            case ACT_DIGEST:
                nnset( data->MailSystem,  MUIA_String_Contents, action->Data.Copy.System     );
                nnset( data->MailConf,    MUIA_String_Contents, action->Data.Copy.Conference );
                nnset( data->MailAddress, MUIA_String_Contents, action->Data.Copy.Address    );
                break;

            case ACT_RECENT:
                nnset( data->RecentAdd,     MUIA_Selected, action->Data.Recent.Add        );
                nnset( data->RecentDupes,   MUIA_Selected, action->Data.Recent.CheckDupes );
                nnset( data->RecentNoStats, MUIA_Selected, action->Data.Recent.NoStats    );
                break;

            case ACT_SAVE:
                nnset( data->SavePath,    MUIA_String_Contents, action->Data.SaveMsg.Path           );
                nnset( data->SaveFile,    MUIA_Cycle_Active,    action->Data.SaveMsg.Dir            );
                nnset( data->SaveSubFrom, MUIA_String_Contents, action->Data.SaveMsg.SubstituteFrom );
                nnset( data->SaveSubWith, MUIA_String_Contents, action->Data.SaveMsg.SubstituteWith );
                nnset( data->SaveHeaders, MUIA_Selected,        action->Data.SaveMsg.Headers        );
                nnset( data->SaveAppend,  MUIA_Selected,        action->Data.SaveMsg.Append         );
                nnset( data->SaveBin,     MUIA_Selected,        action->Data.SaveMsg.SaveBin        );
                break;

            case ACT_MAIL:
            case ACT_FORWARD:
                nnset( data->FwdConference, MUIA_String_Contents, action->Data.Mail.Conference );
                nnset( data->FwdAddress,    MUIA_String_Contents, action->Data.Mail.Address    );
                nnset( data->FwdSubject,    MUIA_String_Contents, action->Data.Mail.Subject    );
                nnset( data->FwdFile,       MUIA_String_Contents, action->Data.Mail.TextFile   );
                break;

            case ACT_SCRIPT:
                nnset( data->ScriptFile, MUIA_String_Contents, action->Data.Script.Script );
                nnset( data->ScriptArgs, MUIA_String_Contents, action->Data.Script.Args   );
                break;
        }

        get( data->ActionGroups[0], MUIA_Parent, &parent );

        DoMethod( parent, MUIM_Group_InitChange );

        set( data->ActionGroups[ ACT_COPY   ], MUIA_ShowMe, ( action->Action == ACT_COPY ) || ( action->Action == ACT_DIGEST  ));
        set( data->ActionGroups[ ACT_MAIL   ], MUIA_ShowMe, ( action->Action == ACT_MAIL ) || ( action->Action == ACT_FORWARD ));
        set( data->ActionGroups[ ACT_RECENT ], MUIA_ShowMe, action->Action == ACT_RECENT );
        set( data->ActionGroups[ ACT_SAVE   ], MUIA_ShowMe, action->Action == ACT_SAVE   );
        set( data->ActionGroups[ ACT_SCRIPT ], MUIA_ShowMe, action->Action == ACT_SCRIPT );

        DoMethod( parent, MUIM_Group_ExitChange );

        DoMethod( data->Actions, MUIM_NList_Redraw, MUIV_NList_Redraw_All );
    }

    return( 0 );
}
///
/// MainWindow_GetAction
static ULONG MainWindow_GetAction( struct IClass *cl, Object *obj, struct MUIP_MainWindow_GetAction *msg )
{
    struct MainWindowData  *data = INST_DATA( cl, obj );
    struct Action          *action;

    DoMethod( data->Actions, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &action );

    if( action ) {

        switch( action->Action ) {

            case ACT_COPY:
            case ACT_DIGEST:
                getstr( data->MailSystem,  action->Data.Copy.System     );
                getstr( data->MailConf,    action->Data.Copy.Conference );
                getstr( data->MailAddress, action->Data.Copy.Address    );
                break;

            case ACT_RECENT:
                action->Data.Recent.Add        = xget( data->RecentAdd,     MUIA_Selected );
                action->Data.Recent.CheckDupes = xget( data->RecentDupes,   MUIA_Selected );
                action->Data.Recent.NoStats    = xget( data->RecentNoStats, MUIA_Selected );
                break;

            case ACT_SAVE:
                getstr( data->SavePath,    action->Data.SaveMsg.Path           );
                getstr( data->SaveSubFrom, action->Data.SaveMsg.SubstituteFrom );
                getstr( data->SaveSubWith, action->Data.SaveMsg.SubstituteWith );

                action->Data.SaveMsg.Dir     = xget( data->SaveFile,    MUIA_Cycle_Active );
                action->Data.SaveMsg.Headers = xget( data->SaveHeaders, MUIA_Selected     );
                action->Data.SaveMsg.Append  = xget( data->SaveAppend,  MUIA_Selected     );
                action->Data.SaveMsg.SaveBin = xget( data->SaveBin,     MUIA_Selected     );
                break;

            case ACT_MAIL:
            case ACT_FORWARD:
                getstr( data->FwdConference, action->Data.Mail.Conference );
                getstr( data->FwdAddress,    action->Data.Mail.Address    );
                getstr( data->FwdSubject,    action->Data.Mail.Subject    );
                getstr( data->FwdFile,       action->Data.Mail.TextFile   );
                break;

            case ACT_SCRIPT:
                getstr( data->ScriptFile, action->Data.Script.Script );
                getstr( data->ScriptArgs, action->Data.Script.Args   );
                break;
        }

        if( msg->Redraw )
            DoMethod( data->Actions, MUIM_NList_Redraw, MUIV_NList_Redraw_Active );
    }

    return( 0 );
}
///

/// RestoreTriggerLists
static void RestoreTriggerLists( struct MainWindowData *data )
{
    set( data->Filters, MUIA_NList_DestructHook, NULL );
    set( data->Actions, MUIA_NList_DestructHook, NULL );

    if( data->CurrentTrigger ) {
        ULONG   i;

        for( i = 0;; i++ ) {
            struct Filter  *entry;

            DoMethod( data->Filters, MUIM_NList_GetEntry, i, &entry );

            if( entry == NULL )
                break;

            AddTail(( struct List * )&data->CurrentTrigger->Filters, ( struct Node * )entry );
        }

        for( i = 0;; i++ ) {
            struct Action  *entry;

            DoMethod( data->Actions, MUIM_NList_GetEntry, i, &entry );

            if( entry == NULL )
                break;

            AddTail(( struct List * )&data->CurrentTrigger->Actions, ( struct Node * )entry );
        }

        DoMethod( data->Filters, MUIM_NList_Clear );
        DoMethod( data->Actions, MUIM_NList_Clear );
    }

    set( data->Filters, MUIA_NList_DestructHook, &FilterDestHook );
    set( data->Actions, MUIA_NList_DestructHook, &ActionDestHook );
}
///

/// System_ObjStrHook
static void SAVEDS ASM System_ObjStrHook( REG( a2 ) Object *list, REG( a1 ) Object *str )
{
    STRPTR  entry;

    DoMethod( list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &entry );

    set( str, MUIA_String_Contents, entry );
}
///

/// List_DispHook
static ULONG SAVEDS ASM List_DispHook( REG( a2 ) STRPTR *array, REG( a1 ) struct Trigger *entry )
{
    if( entry )
        *array = entry->Name;

    return( 0 );
}
///
/// List_DestHook
static void SAVEDS List_DestHook( REG( a1 ) struct Trigger *entry )
{
    struct Filter  *filter;
    struct Action  *action;

    while( filter = (struct Filter *) RemTail(( struct List * )&entry->Filters ))
        FreeMem( filter, sizeof( struct Filter ));

    while( action = (struct Action *) RemTail(( struct List * )&entry->Actions ))
        FreeMem( action, sizeof( struct Action ));

    FreeMem( entry, sizeof( struct Trigger ));
}
///

/// Filter_DispHook
static ULONG SAVEDS ASM Filter_DispHook( REG( a2 ) STRPTR *array, REG( a1 ) struct Filter *entry )
{
    if( entry ) {
        static TEXT buf[20];

        strcpy( buf, entry->Not ? "not in " : "in " );
        strcat( buf, WhereLabels[ entry->Where ]);

        *array++ = entry->Pattern;
        *array++ = buf;
        *array   = entry->Keyword;

    } else {

        *array++ = "Search";
        *array++ = "Where";
        *array   = "Keyword";
    }

    return( 0 );
}
///
/// Filter_DestHook
static void SAVEDS Filter_DestHook( REG( a1 ) struct Filter *entry )
{
    FreeMem( entry, sizeof( *entry ));
}
///

/// Action_DispHook
static ULONG SAVEDS ASM Action_DispHook( REG( a2 ) STRPTR *array, REG( a1 ) struct Action *entry )
{
    if( entry ) {
        static STRPTR   Actions[] = {
                                "Copy msg to",
                                "Parse AmiNet RECENT",
                                "Save message to disk",
                                "Split digest",
                                "Forward to",
                                "Mail text file",
                                "Run script",
                        };

        *array++ = Actions[ entry->Action ];

        switch( entry->Action ) {

            case ACT_COPY:
            case ACT_DIGEST:
                *array = entry->Data.Copy.Address;
                break;

            case ACT_MAIL:
            case ACT_FORWARD:
                *array = entry->Data.Mail.Address;
                break;

            case ACT_SCRIPT:
                *array = entry->Data.Script.Script;
                break;

            case ACT_SAVE:
                *array = entry->Data.SaveMsg.Path;
                break;

            default:
               *array = "";
               break;
        }

    } else {

        *array++ = "Action";
        *array   = "";
    }

    return( 0 );
}
///
/// Action_DestHook
static void SAVEDS Action_DestHook( REG( a1 ) struct Action *entry )
{
    FreeMem( entry, sizeof( *entry ));
}
///

/// PopConf_Dispatcher
static ULONG SAVEDS ASM PopConf_Dispatcher( REG( a0 ) struct IClass *cl, REG( a2 ) Object *obj, REG( a1 ) Msg msg )
{
    switch( msg->MethodID ) {

        case OM_NEW:
            return( PopConf_New( cl, obj, (APTR)msg ));

        case OM_SET:
            return( PopConf_Set( cl, obj, (APTR)msg ));

        case MUIM_PopConf_Open:
            return( PopConf_Open( cl, obj, (APTR)msg ));
    }

    return( DoSuperMethodA( cl, obj, msg ));
}
///
/// PopConf_New
static ULONG PopConf_New( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct PopConfData      temp = { 0 };

    if( obj = ( Object * )DoSuperNew( cl, obj,

                                MUIA_Group_Horiz,   TRUE,
                                MUIA_Group_Spacing, 0,

                                Child, temp.String = MakeString( "", 256 ),
                                Child, temp.Popup  = PopButton( MUII_PopUp ),

                        TAG_MORE, msg->ops_AttrList )) {

        struct PopConfData     *data = INST_DATA( cl, obj );

        *data = temp;

        DoMethod( temp.Popup, MUIM_Notify, MUIA_Selected, FALSE, obj, 1, MUIM_PopConf_Open );

        data->System = (Object *)GetTagData( MUIA_PopConf_System, NULL, msg->ops_AttrList );
        data->Multi  = GetTagData( MUIA_PopConf_Multi, FALSE, msg->ops_AttrList );
        data->DoAddr = GetTagData( MUIA_PopConf_DoAddress, FALSE, msg->ops_AttrList );

        return(( ULONG )obj );
    }

    return( 0 );
}
///
/// PopConf_Set
static ULONG PopConf_Set( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct PopConfData *data = INST_DATA( cl, obj );
    struct TagItem     *tag;

    if( tag = FindTagItem( MUIA_PopConf_System, msg->ops_AttrList ))
        data->System = (Object *)tag->ti_Data;

    return( DoSuperMethodA( cl, obj, (Msg)msg ));
}
///
/// PopConf_Open
static ULONG PopConf_Open( struct IClass *cl, Object *obj, Msg msg )
{
    struct PopConfData *data = INST_DATA( cl, obj );
    Object             *wnd;

    if( wnd = NewObject(( data->DoAddr ? CL_AddrWindow : CL_ConfWindow )->mcc_Class, NULL,
                         MUIA_ConfWindow_Data, data,
                         TAG_DONE )) {

        DoMethod( _app( obj ), OM_ADDMEMBER, wnd );

        set( data->Popup, MUIA_Disabled, TRUE );

        DoMethod( wnd, MUIM_ConfWindow_Open );
    }

    return( 0 );
}
///

/// ConfWindow_Dispatcher
static ULONG SAVEDS ASM ConfWindow_Dispatcher( REG( a0 ) struct IClass *cl, REG( a2 ) Object *obj, REG( a1 ) Msg msg )
{
    switch( msg->MethodID ) {

        case OM_NEW:
            return( ConfWindow_New( cl, obj, (APTR)msg ));

        case MUIM_ConfWindow_Open:
            return( ConfWindow_Open( cl, obj, (APTR)msg ));

        case MUIM_ConfWindow_Close:
            return( ConfWindow_Close( cl, obj, (APTR)msg ));
    }

    return( DoSuperMethodA( cl, obj, msg ));
}
///
/// ConfWindow_New
static ULONG ConfWindow_New( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct ConfWindowData   temp = { 0 };
    Object                 *Ok, *Cancel;

    if(!( temp.PopData = (struct PopConfData *)GetTagData( MUIA_ConfWindow_Data, NULL, msg->ops_AttrList )))
        return( 0 );

    if( obj = ( Object * )DoSuperNew( cl, obj,

                            MUIA_Window_Title,      "Select a conference",
                            MUIA_Window_ID,         MAKE_ID( 'C', 'O', 'N', 'F' ),

                            WindowContents, VGroup,

                                Child, temp.List = NListviewObject,
                                    MUIA_CycleChain,        TRUE,
                                    MUIA_NListview_NList,   NListObject,
                                        InputListFrame,
                                        MUIA_NList_AutoVisible,     TRUE,
                                        MUIA_NList_ConstructHook,   MUIV_NList_ConstructHook_String,
                                        MUIA_NList_DestructHook,    MUIV_NList_DestructHook_String,
                                        MUIA_NList_MultiSelect,     temp.PopData->Multi,
                                    End,
                                End,

                                Child, HGroup,
                                    Child, MakeLabel( "Create new conf" ),
                                    Child, HGroup, MUIA_Group_Spacing, 0,
                                        Child, temp.NewConf = MakeCheck( "" ),
                                        Child, temp.Conf    = MakeString( "", temp.PopData->Multi ? 512 : 80 ),
                                    End,
                                End,

                                Child, HGroup,
                                    Child, Ok     = MakeButton( "_Ok" ),
                                    Child, HSpace( 0 ),
                                    Child, Cancel = MakeButton( "_Cancel" ),
                                End,
                            End,

                        TAG_MORE, msg->ops_AttrList )) {

        struct ConfWindowData  *data = INST_DATA( cl, obj );

        *data = temp;

        set( temp.Conf, MUIA_Disabled, TRUE );

        /*  Window  */
        DoMethod( obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 2, MUIM_ConfWindow_Close, FALSE );

        /*  Gadgets */
        DoMethod( temp.List, MUIM_Notify, MUIA_NList_DoubleClick, TRUE, obj, 2, MUIM_ConfWindow_Close, TRUE );

        DoMethod( temp.NewConf, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, temp.Conf, 3, MUIM_Set, MUIA_Disabled, MUIV_NotTriggerValue );

        DoMethod( Ok,     MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_ConfWindow_Close, TRUE  );
        DoMethod( Cancel, MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_ConfWindow_Close, FALSE );

        return(( ULONG )obj );
    }

    return( 0 );
}
///
/// ConfWindow_Open
static ULONG ConfWindow_Open( struct IClass *cl, Object *obj, Msg msg )
{
    struct ConfWindowData  *data = INST_DATA( cl, obj );
    struct BBSListItem     *bbs;

    if( bbs = ( struct BBSListItem * )FindiName( BBSList, data->PopData->System ?
                                                 (STRPTR)xget( data->PopData->System, MUIA_String_Contents )
                                                 : SystemName )) {
        struct List    *conflist;

        if( conflist = GetConfList( bbs )) {
            struct Node    *node;

            for( node = conflist->lh_Head; node->ln_Succ; node = node->ln_Succ )
                DoMethod( data->List, MUIM_NList_InsertSingle, node->ln_Name, MUIV_NList_Insert_Sorted );

            FreeBRObject( conflist );
        }
    }

    set( obj, MUIA_Window_Open, TRUE );

    return( 0 );
}
///
/// ConfWindow_Close
static ULONG ConfWindow_Close( struct IClass *cl, Object *obj, struct MUIP_ConfWindow_Close *msg )
{
    struct ConfWindowData  *data = INST_DATA( cl, obj );
    Object                 *app;

    if( msg->Ok ) {
        TEXT  str[512];

        if( xget( data->NewConf, MUIA_Selected ))
            getstr( data->Conf, str );
        else {
            ULONG   pos, multi;

            pos    = MUIV_NList_NextSelected_Start;

            if( data->PopData->Multi ) {

                str[0] = '(';
                str[1] = '\0';
                multi  = 1

            } else {

                str[0] = '\0';
                multi  = 0;
            }

            DoMethod( data->List, MUIM_NList_NextSelected, &pos );

            while( pos != MUIV_NList_NextSelected_End ) {
                STRPTR  entry;

                DoMethod( data->List, MUIM_NList_GetEntry, pos, &entry );

                if( str[ multi ])
                    strcat( str, "|" );

                strcat( str, entry );

                DoMethod( data->List, MUIM_NList_NextSelected, &pos );
            }

            if( multi ){

                if( str[1] == '\0' )
                    str[0] = '\0';
                else
                    strcat( str, ")" );
            }
        }

        if( str[0] )
            set( data->PopData->String, MUIA_String_Contents, str );
    }

    set( obj, MUIA_Window_Open, FALSE );

    set( data->PopData->Popup, MUIA_Disabled, FALSE );

    get( obj, MUIA_ApplicationObject, &app );

    DoMethod( app, OM_REMMEMBER, obj );

    DoMethod( app, MUIM_Application_PushMethod, app, 2, MUIM_MyApp_DisposeObj, obj );

    return( 0 );
}
///

/// AddrWindow_Dispatcher
static ULONG SAVEDS ASM AddrWindow_Dispatcher( REG( a0 ) struct IClass *cl, REG( a2 ) Object *obj, REG( a1 ) Msg msg )
{
    switch( msg->MethodID ) {

        case OM_NEW:
            return( AddrWindow_New( cl, obj, (APTR)msg ));

        case MUIM_ConfWindow_Open:
            return( AddrWindow_Open( cl, obj, (APTR)msg ));

        case MUIM_ConfWindow_Close:
            return( AddrWindow_Close( cl, obj, (APTR)msg ));
    }

    return( DoSuperMethodA( cl, obj, msg ));
}
///
/// AddrWindow_New
static ULONG AddrWindow_New( struct IClass *cl, Object *obj, struct opSet *msg )
{
    struct AddrWindowData   temp = { 0 };
    Object                 *Ok, *Cancel;
    static struct Hook      DispHook = {
                { NULL, NULL },
                (HOOKFUNC)User_DispHook,
                NULL, NULL
    };
    static struct Hook      DestHook = {
                { NULL, NULL },
                (HOOKFUNC)User_DestHook,
                NULL, NULL
    };
    static struct Hook      CmpHook = {
                { NULL, NULL },
                (HOOKFUNC)User_CmpHook,
                NULL, NULL
    };

    if(!( temp.PopData = (struct PopConfData *)GetTagData( MUIA_ConfWindow_Data, NULL, msg->ops_AttrList )))
        return( 0 );

    if( obj = ( Object * )DoSuperNew( cl, obj,

                            MUIA_Window_Title,      "Select an user",
                            MUIA_Window_ID,         MAKE_ID( 'U', 'S', 'E', 'R' ),

                            WindowContents, VGroup,

                                Child, temp.List = NListviewObject,
                                    MUIA_CycleChain,        TRUE,
                                    MUIA_NListview_NList,   NListObject,
                                        InputListFrame,
                                        MUIA_NList_AutoVisible,     TRUE,
                                        MUIA_NList_Title,           TRUE,
                                        MUIA_NList_Format,          "BAR,",
                                        MUIA_NList_DestructHook,    &DestHook,
                                        MUIA_NList_DisplayHook,     &DispHook,
                                        MUIA_NList_CompareHook,     &CmpHook,
                                    End,
                                End,

                                Child, HGroup,
                                    Child, Ok     = MakeButton( "_Ok" ),
                                    Child, HSpace( 0 ),
                                    Child, Cancel = MakeButton( "_Cancel" ),
                                End,
                            End,

                        TAG_MORE, msg->ops_AttrList )) {

        struct AddrWindowData  *data = INST_DATA( cl, obj );

        *data = temp;

        /*  Window  */
        DoMethod( obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, obj, 2, MUIM_ConfWindow_Close, FALSE );

        /*  Gadgets */
        DoMethod( temp.List, MUIM_Notify, MUIA_NList_DoubleClick, TRUE, obj, 2, MUIM_ConfWindow_Close, TRUE );

        DoMethod( Ok,     MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_ConfWindow_Close, TRUE  );
        DoMethod( Cancel, MUIM_Notify, MUIA_Pressed, FALSE, obj, 2, MUIM_ConfWindow_Close, FALSE );

        return(( ULONG )obj );
    }

    return( 0 );
}
///
/// AddrWindow_Open
static ULONG AddrWindow_Open( struct IClass *cl, Object *obj, Msg msg )
{
    struct AddrWindowData  *data = INST_DATA( cl, obj );
    struct BBSListItem     *bbs;

    if( bbs = ( struct BBSListItem * )FindiName( BBSList, data->PopData->System ?
                                                 (STRPTR)xget( data->PopData->System, MUIA_String_Contents )
                                                 : SystemName )) {
        ULONG   i;

        for( i = bbs->bl_Internal->bi_FirstUser; i <= bbs->bl_Internal->bi_LastUser; i++ ) {
            APTR            thoruser;
            ULONG           flags;
            struct TagItem *tags;

            if( thoruser = ReadBRUserTags( bbs, i,
                                           RBRUSR_UserTagsPtr,  &tags,
                                           RBRUSR_Flags,        &flags,
                                           TAG_DONE )) {
                struct UserInfo    *user;

                if( tags == NULL )
                    continue;

                if( user = AllocMem( sizeof( struct UserInfo ), MEMF_CLEAR )) {
                    struct TagItem *tag;

                    while( tag = NextTagItem( &tags )) {

                        switch( tag->ti_Tag ) {

                            case BRUSR_Name:
                                stccpy( user->Name, (STRPTR)tag->ti_Data, sizeof( user->Name ));
                                break;

                            case BRUSR_Address:
                                stccpy( user->EMail, (STRPTR)tag->ti_Data, sizeof( user->EMail ));
                                break;
                        }
                    }

                    DoMethod( data->List, MUIM_NList_InsertSingle, user, MUIV_NList_Insert_Sorted );
                }

                FreeBRObject( thoruser );
            }
        }
    }

    set( obj, MUIA_Window_Open, TRUE );

    return( 0 );
}
///
/// AddrWindow_Close
static ULONG AddrWindow_Close( struct IClass *cl, Object *obj, struct MUIP_ConfWindow_Close *msg )
{
    struct AddrWindowData  *data = INST_DATA( cl, obj );
    Object                 *app;

    if( msg->Ok ) {
        struct UserInfo    *user;

        DoMethod( data->List, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &user );

        if( user )
            set( data->PopData->String, MUIA_String_Contents, user->EMail );
    }

    set( obj, MUIA_Window_Open, FALSE );

    set( data->PopData->Popup, MUIA_Disabled, FALSE );

    get( obj, MUIA_ApplicationObject, &app );

    DoMethod( app, OM_REMMEMBER, obj );

    DoMethod( app, MUIM_Application_PushMethod, app, 2, MUIM_MyApp_DisposeObj, obj );

    return( 0 );
}
///

/// User_DispHook
static ULONG SAVEDS ASM User_DispHook( REG( a2 ) STRPTR *array, REG( a1 ) struct UserInfo *entry )
{
    if( entry ) {

        *array++ = entry->Name;
        *array   = entry->EMail;

    } else {

        *array++ = "Name";
        *array   = "EMail";
    }

    return( 0 );
}
///
/// User_DestHook
static void SAVEDS User_DestHook( REG( a1 ) struct UserInfo *entry )
{
    FreeMem( entry, sizeof( *entry ));
}
///
/// User_CmpHook
static LONG SAVEDS ASM User_CmpHook( REG( a1 ) struct UserInfo *e1, REG( a2 ) struct UserInfo *e2 )
{
    return( strcmp( e1->Name, e2->Name ));
}
///

