//
// MUIEmail -- Easy way to email people when using Amiga UUCP.
//             й1993 by HemSoft Developments,
//             Written by Franz Hemmer, September 1993.
//
// Please use TAB=3.
//

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            I N C L U D E S									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
#include <exec/types.h>								// For UBYTE etc.
#include <exec/memory.h>							// For MEMF_ANY etc.
#include <clib/alib_protos.h>						// Protos for DoMethod() etc.
#include <clib/dos_protos.h>						// Protos for Open() etc.
#include <clib/exec_protos.h>						// Protos for OpenLibrary() etc.
#include <clib/icon_protos.h>						// Protos for GetDiskObject() etc.
#include <clib/intuition_protos.h>				// Protos for SetAttr() (MUI's set());
#include <clib/muimaster_protos.h>				// Protos for MUI_DisposeObject() etc.
#include <clib/utility_protos.h>					// Protos for Stricmp() etc.
#include <dos/dostags.h>							// For SYS_Output tag etc.
#include <libraries/asl.h>							// For struct FileRequester etc.
#include <libraries/gadtools.h>					// For struct NewMenu etc.
#include <libraries/mui.h>							// MUI library.
#include <pragmas/dos_pragmas.h>					// Pragmas for dos.library.
#include <pragmas/exec_pragmas.h>				// Pragmas for exec.library.
#include <pragmas/icon_pragmas.h>				// Pragmas for icon.library.
#include <pragmas/intuition_pragmas.h>			// Pragmas for intuition.library.
#include <pragmas/muimaster_pragmas.h>			// Pragmas for muimaster.library.
#include <pragmas/utility_pragmas.h>			// Pragmas for utility.library.
#include <ctype.h>									// For isalnum() etc.
#include <stdio.h>									// Protos for sprintf() etc.
#include <stdlib.h>									// Protos for exit() etc.
#include <string.h>									// Protos for strcpy() etc.

#include "MUIEmail.h"								// Version header.
UBYTE VersTag [] = VERSTAG;						// Version tag.

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             I M P O R T S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
extern struct DosLibrary	*DOSBase;			// dos.library.

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             S T R U C T S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Prefs
{
	UBYTE	p_AliasFile		[256];					// Full path spec. to alias file.
	UBYTE	p_EditorFile	[256];					// Full path to editor.
	UBYTE	p_EditorArgs	[256];					// Special arguments for editor.
	UBYTE	p_MailerFile	[256];					// Full path to mailer program.
	UBYTE p_MailerArgs	[256];					// Special arguments for mailer program.
};

struct ANode											// Used to store aliases.
{
	struct Node	an_Node;
	UBYTE			an_Alias		[80];
	UBYTE			an_Address	[80];
	UBYTE			an_Comment	[160];
};

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             D E F I N E S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
#define	ID_MAIL							1
#define	ID_SELECT_CHANGE				2
#define	ID_ABOUT							3
#define	ID_EDIT_ALIAS					4
#define	ID_PREFS							5
#define	ID_QUIT							6

#define	ID_PREFS_ALIAS_FILE_REQ		8
#define	ID_PREFS_EDITOR_FILE_REQ	9
#define	ID_PREFS_MAILER_FILE_REQ	10
#define	ID_PREFS_SAVE					11
#define	ID_PREFS_USE					12
#define	ID_PREFS_QUIT					13

/*----------------------------------*/
/* Macro for making identifcations: */
/*----------------------------------*/
#define	MAKE_ID(a,b,c,d)	((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))

/*----------------------------------*/
/* Node references into guide file: */
/*----------------------------------*/
#define	NODE_STATUS_OBJ			"STATUSOBJECT"
#define	NODE_LISTVIEW_OBJ			"LISTVIEWOBJECT"
#define	NODE_ADDRESS_OBJ			"ADDRESSOBJECT"
#define	NODE_COMMENT_OBJ			"COMMENTOBJECT"
#define	NODE_MAIL_OBJ				"MAILOBJECT"
#define	NODE_PREFS_ALIASFILE		"PREFSALIASFILEOBJECT"
#define	NODE_PREFS_EDITORFILE	"PREFSEDITORFILEOBJECT"
#define	NODE_PREFS_EDITORARGS	"PREFSEDITORARGSOBJECT"
#define	NODE_PREFS_MAILERFILE	"PREFSMAILERFILEOBJECT"
#define	NODE_PREFS_MAILERARGS	"PREFSMAILERARGSOBJECT"

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             G L O B A L S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*------------*/
/* Libraries: */
/*------------*/
struct Library	*IconBase		= NULL;			// icon.library.
struct Library	*IntuitionBase = NULL;			// intuition.library.
struct Library	*MUIMasterBase = NULL;			// muimaster.library.
struct Library	*UtilityBase	= NULL;			// utility.library.

/*--------*/
/* Prefs: */
/*--------*/
struct Prefs	*Prefs			= NULL;			// MUIEmail preferences.
UBYTE				oldaliasfile [256];				// For detecting alis file changes in prefs.

/*--------------------------------*/
/* Disk Object for iconification: */
/*--------------------------------*/
struct DiskObject	*dobj = NULL;					// Our icon.

/*--------*/
/* Lists: */
/*--------*/
struct List		AliasList;							// List of aliases.

/*--------------*/
/* MUI objects: */
/*--------------*/
APTR				appobj;								// MUI Application object.

APTR				winobj;								// Window	: Main.
APTR				statobj;								// Text		: Status info.
APTR				lvobj;								// Listview	: List of users to email.
APTR				addrobj;								// Text		: Address of active listview item.
APTR				commentobj;							// Text		: Comment on active listview item.
APTR				mailobj;								// Button	: Go and email!

APTR				prefswinobj;						// Window	: Preferences.
APTR				aliasfileobj;						// String	: Alias file path.
APTR				aliasfilereqobj;					// Req.		: Alias file path requester.
APTR				editorfileobj;						// String	: Editor file path.
APTR				editorfilereqobj;					// Req.		: Editor file path requester.
APTR				editorargsobj;						// String	: Arguments for editor.
APTR				mailerfileobj;						// String	: Mailer program path.
APTR				mailerfilereqobj;					// Req.		: Mailer program path requester.
APTR				mailerargsobj;						// String	: Arguments for mailer.
APTR				saveobj, useobj, cancelobj;	// Buttons	: Save/Use/Cancel.

/*-------*/
/* Text: */
/*-------*/
UBYTE				StatTxt [40];						// Status text.
ULONG				NumberOfAliases = 0;				// Number of aliases found in alias file.

/*-------*/
/* Menu: */
/*-------*/
struct NewMenu	MenuGlobal [] =
{
	NM_TITLE,	"Project",							0,		0, 0, 0,
	NM_ITEM,		"Mail...",							"M",	0, 0,	(APTR) ID_MAIL,
	NM_ITEM,		"Edit alias file...",			"E",	0,	0,	(APTR) ID_EDIT_ALIAS,
	NM_ITEM,		NM_BARLABEL,						0,		0,	0,	0,
	NM_ITEM,		"Preferences...",					"P",	0, 0,	(APTR) ID_PREFS,
	NM_ITEM,		NM_BARLABEL,						0,		0,	0,	0,
	NM_ITEM,		"About...",							"A",	0, 0,	(APTR) ID_ABOUT,
	NM_ITEM,		NM_BARLABEL,						0,		0,	0,	0,
	NM_ITEM,		"Quit",								"Q",	0, 0,	(APTR) ID_QUIT,

	NM_END,		NULL,									0,		0, 0, 0
};

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              P R O T O S										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*----------*/
/* email.c: */
/*----------*/
void				OpenLibs					(void);
void				HandleIDCMP				(void);
void				CleanExit				(UWORD exitcode, UBYTE *exitstr);

APTR				BuildAppObj				(void);
void				AppObjSetup				(void);

void				ReadAliases				(void);
void				SortList					(struct List *list, short col);
BOOL				EmptyList				(struct List *list);
void				FreeAllNodes			(struct List *l);
struct Node		*GetNodeNum				(struct List *l, ULONG num);

struct Prefs	*GetMyPrefs				(void);
struct Prefs	*BuildDefPrefs			(void);
BOOL				SavePrefs				(struct Prefs *prefs, BOOL save);
void				GetPrefsStrings		(void);

BOOL				FileReq					(APTR parentwinobj, APTR strobj, APTR reqobj, UBYTE *initialdirname,
												 UBYTE *filebuf, UBYTE *pattern);

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                                M A I N											*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
int main (int argc,char *argv [])
{
	/*-----------------*/
	/* Open libraries. */
	/*-----------------*/
	OpenLibs ();

	/*---------------------------*/
	/* Get MUIEmail preferences: */
	/*---------------------------*/
	if (!(Prefs = GetMyPrefs ()))
	{
		Prefs = BuildDefPrefs ();
	}

	/*---------------------*/
	/* Create MUI objects: */
	/*---------------------*/
	if (!(appobj = BuildAppObj ()))
	{
		CleanExit (RETURN_FAIL, "Failed to create Application object.\n");
	}

	/*-------------------*/
	/* Read aliases etc. */
	/*-------------------*/
	NewList (&AliasList);
	ReadAliases ();

	/*-------------------------*/
	/* Setup notification etc. */
	/*-------------------------*/
	AppObjSetup ();

	/*--------*/
	/* IDCMP. */
	/*--------*/
	HandleIDCMP ();

	/*--------------*/
	/* Shut down... */
	/*--------------*/
	CleanExit (RETURN_OK, NULL);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              OpenLibs()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void OpenLibs (void)
{
	/*-------------------------*/
	/* Open intuition.library. */
	/*-------------------------*/
	if (!(IntuitionBase = OpenLibrary ("intuition.library", 37L)))
	{
		CleanExit (RETURN_FAIL, "Failed to open intuition.library V37.\n");
	}

	/*-------------------------*/
	/* Open muimaster.library. */
	/*-------------------------*/
	if (!(MUIMasterBase = OpenLibrary (MUIMASTER_NAME, MUIMASTER_VMIN)))
	{
		CleanExit (RETURN_FAIL, "Failed to open " MUIMASTER_NAME ".\n");
	}

	/*-----------------------*/
	/* Open utility.library. */
	/*-----------------------*/
	if (!(UtilityBase = OpenLibrary ("utility.library", 37L)))
	{
		CleanExit (RETURN_FAIL, "Failed to open utility.library V37.\n");
	}

	/*--------------------*/
	/* Open icon.library. */
	/*--------------------*/
	if (!(IconBase = OpenLibrary ("icon.library", 37L)))
	{
		CleanExit (RETURN_FAIL, "Failed to open icon.library V37.\n");
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             HandleIDCMP()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void HandleIDCMP (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	BOOL	KeepGoing = TRUE;
	ULONG	signals;										// IDCMP signals.

	/*---------*/
	/* C O D E */
	/*---------*/
	/*------------------------*/
	/* Get application input. */
	/*------------------------*/
	while (KeepGoing)
	{
		/*-----------------*/
		/* Get MUI signal. */
		/*-----------------*/
		switch (DoMethod (appobj, MUIM_Application_Input, &signals))
		{
			/*--------------*/
			/* Main Window: */
			/*--------------*/
			case ID_MAIL :
			{
				LONG				active;
				struct ANode	*anode;
				UBYTE				cmdline [255];
				BPTR				dummyoutput = NULL;

				/*-------------------------------*/
				/* Get the active listview item. */
				/*-------------------------------*/
				get (lvobj, MUIA_List_Active, &active);
				if (active == -1)
				{
					MUI_Request (appobj, winobj, 0, NULL, "*Okay",
									 "\033c\0338MUIEmail V%ld.%ld\n\n\0332Select a person to email\n"
									 "in the listview first!!.",
									 VERSION, REVISION, TAG_END);
					break;
				}

				/*-----------------------------*/
				/* Get the corresponding node. */
				/*-----------------------------*/
				if (anode = (struct ANode *) GetNodeNum (&AliasList, active))
				{
					/*----------------------------------------------------*/
					/* Put our window to sleep before we call the mailer. */
					/*----------------------------------------------------*/
					set (winobj, MUIA_Window_Sleep, TRUE);

					/*---------------------*/
					/* Build command line: */
					/*---------------------*/
					sprintf (cmdline, "%s %s", Prefs->p_MailerFile, anode->an_Address);

					/*--------------*/
					/* Call Mailer: */
					/*--------------*/
					dummyoutput = Open ("NIL:", MODE_READWRITE);
					if (SystemTags (cmdline, SYS_Output, dummyoutput, TAG_END))
					{
						MUI_Request (appobj, winobj, 0, NULL, "*Okay",
										 "\033c\0338MUIEmail V%ld.%ld\n\n\0332Error: Couln't call Mailer.",
										 VERSION, REVISION, TAG_END);
					}
					Close (dummyoutput);

					/*-----------------------*/
					/* Wake up window again. */
					/*-----------------------*/
					set (winobj, MUIA_Window_Sleep, FALSE);
				}
				break;
			}
			case ID_SELECT_CHANGE :
			{
				LONG				active;
				struct ANode	*anode;

				/*----------------------*/
				/* Get the active item. */
				/*----------------------*/
				get (lvobj, MUIA_List_Active, &active);
				if (active != -1)
				{
					/*-----------------------------*/
					/* Get the corresponding node. */
					/*-----------------------------*/
					if (anode = (struct ANode *) GetNodeNum (&AliasList, active))
					{
						/*--------------------------------------*/
						/* Display the email address & comment. */
						/*--------------------------------------*/
						set (addrobj, MUIA_Text_Contents, anode->an_Address);
						set (commentobj, MUIA_Text_Contents, anode->an_Comment);
					}
				}
				break;
			}
			case ID_ABOUT :
			{
				MUI_Request (appobj, winobj, 0, NULL, "*Okay",
								 "\033c\0338MUIEmail V%ld.%ld (%s)\n\n\0332й1993 by HemSoft Developments.\n"
								 "Written by Franz Hemmer.\n\n"
								 "This is a MUI-Application.\n"
								 "MUI is (C)opyright by Stefan Stuntz.",
								 VERSION, REVISION, DATE, TAG_END);
				break;
			}
			case ID_EDIT_ALIAS :
			{
				struct ANode	*anode;
				char				*str;
				UBYTE				cmdline [768];

				/*---------------------------*/
				/* Put main window to sleep. */
				/*---------------------------*/
				set (winobj, MUIA_Window_Sleep, TRUE);

				/*-------------------------------------------*/
				/* Call editor with alias file as parameter. */
				/*-------------------------------------------*/
				sprintf (cmdline, "%s %s %s", Prefs->p_EditorFile, Prefs->p_EditorArgs, Prefs->p_AliasFile);
				if (!(SystemTagList (cmdline, TAG_END)))
				{
					/*--------------------*/
					/* Reread alias file. */
					/*--------------------*/
					NewList (&AliasList);
					NumberOfAliases = 0;
					ReadAliases ();

					/*------------------------------------------*/
					/* Remove all existing entries in listview. */
					/*------------------------------------------*/
					DoMethod (lvobj, MUIM_List_Clear);
					set (winobj, MUIA_Window_Sleep, TRUE);

					/*--------------------------------------------*/
					/* Add our alias list to the listview object: */
					/*--------------------------------------------*/
					for (anode = (struct ANode *) AliasList.lh_Head;
						  anode->an_Node.ln_Succ;
						  anode = (struct ANode *) anode->an_Node.ln_Succ)
					{
						str = &anode->an_Alias [0];
						DoMethod (lvobj, MUIM_List_Insert, &str, 1, MUIV_List_Insert_Bottom);
					}
					set (winobj, MUIA_Window_Sleep, FALSE);
				}

				/*----------------*/
				/* Awaken window. */
				/*----------------*/
				set (winobj, MUIA_Window_Sleep, FALSE);
				break;
			}
			case ID_PREFS :
			{
				/*---------------------------*/
				/* Put main window to sleep. */
				/*---------------------------*/
				set (winobj, MUIA_Window_Sleep, TRUE);

				/*--------------------*/
				/* Open prefs window. */
				/*--------------------*/
				set (prefswinobj, MUIA_Window_Open, TRUE);
				set (prefswinobj, MUIA_Window_ActiveObject, aliasfileobj);

				/*----------------------------------------------------------------------*/
				/* Remember the alias file string, since we want to check if it has		*/
				/* changed when the user hits save or use, which would trigger a reread */
				/* of the alias file.																	*/
				/*----------------------------------------------------------------------*/
				strcpy (oldaliasfile, Prefs->p_AliasFile);
				break;
			}
			case ID_QUIT :
			{
				KeepGoing = FALSE;
				break;
			}

			/*--------------*/
			/* Preferences: */
			/*--------------*/
			case ID_PREFS_ALIAS_FILE_REQ :
			{
				UBYTE pathpart [256];

				/*----------------------------*/
				/* Put prefs window to sleep. */
				/*----------------------------*/
				set (prefswinobj, MUIA_Window_Sleep, TRUE);

				/*----------------------------------------*/
				/* Get the path part from the alias file. */
				/*----------------------------------------*/
				strcpy (pathpart, Prefs->p_AliasFile);
				*PathPart (pathpart) = '\0';
				
				/*------------------------*/
				/* Put up file requester. */
				/*------------------------*/
				FileReq (prefswinobj, aliasfileobj, aliasfilereqobj, pathpart, Prefs->p_AliasFile, "#?");

				/*----------------*/
				/* Awaken window. */
				/*----------------*/
				set (prefswinobj, MUIA_Window_Sleep, FALSE);
				break;
			}
			case ID_PREFS_EDITOR_FILE_REQ :
			{
				UBYTE pathpart [256];

				/*----------------------------*/
				/* Put prefs window to sleep. */
				/*----------------------------*/
				set (prefswinobj, MUIA_Window_Sleep, TRUE);

				/*-----------------------------------------*/
				/* Get the path part from the editor file. */
				/*-----------------------------------------*/
				strcpy (pathpart, Prefs->p_EditorFile);
				*PathPart (pathpart) = '\0';
				
				/*------------------------*/
				/* Put up file requester. */
				/*------------------------*/
				FileReq (prefswinobj, editorfileobj, editorfilereqobj, pathpart, Prefs->p_EditorFile, "#?");

				/*----------------*/
				/* Awaken window. */
				/*----------------*/
				set (prefswinobj, MUIA_Window_Sleep, FALSE);
				break;
			}
			case ID_PREFS_MAILER_FILE_REQ :
			{
				UBYTE pathpart [256];

				/*----------------------------*/
				/* Put prefs window to sleep. */
				/*----------------------------*/
				set (prefswinobj, MUIA_Window_Sleep, TRUE);

				/*-----------------------------------------*/
				/* Get the path part from the mailer file. */
				/*-----------------------------------------*/
				strcpy (pathpart, Prefs->p_MailerFile);
				*PathPart (pathpart) = '\0';
				
				/*------------------------*/
				/* Put up file requester. */
				/*------------------------*/
				FileReq (prefswinobj, mailerfileobj, mailerfilereqobj, pathpart, Prefs->p_MailerFile, "#?");

				/*----------------*/
				/* Awaken window. */
				/*----------------*/
				set (prefswinobj, MUIA_Window_Sleep, FALSE);
				break;
			}
			case ID_PREFS_SAVE :
			{
				struct ANode	*anode;
				UBYTE				*str;

				/*-----------------------------------------------------------*/
				/* Grab the string object strings & put them into our prefs. */
				/*-----------------------------------------------------------*/
				GetPrefsStrings ();

				/*---------------------------------------------*/
				/* Save the preferences to both ENVARC: & ENV: */
				/*---------------------------------------------*/
				SavePrefs (Prefs, TRUE);

				/*-----------------------------------------*/
				/* Close pref window & awaken main window. */
				/*-----------------------------------------*/
				set (prefswinobj, MUIA_Window_Open, FALSE);
				set (winobj, MUIA_Window_Sleep, FALSE);

				/*------------------------------------------*/
				/* Check if we need to read the alias file. */
				/*------------------------------------------*/
				if (Stricmp (oldaliasfile, Prefs->p_AliasFile))
				{
					/*--------------------*/
					/* Reread alias file. */
					/*--------------------*/
					NewList (&AliasList);
					NumberOfAliases = 0;
					ReadAliases ();

					/*------------------------------------------*/
					/* Remove all existing entries in listview. */
					/*------------------------------------------*/
					DoMethod (lvobj, MUIM_List_Clear);
					set (winobj, MUIA_Window_Sleep, TRUE);

					/*--------------------------------------------*/
					/* Add our alias list to the listview object: */
					/*--------------------------------------------*/
					for (anode = (struct ANode *) AliasList.lh_Head;
						  anode->an_Node.ln_Succ;
						  anode = (struct ANode *) anode->an_Node.ln_Succ)
					{
						str = &anode->an_Alias [0];
						DoMethod (lvobj, MUIM_List_Insert, &str, 1, MUIV_List_Insert_Bottom);
					}
					set (winobj, MUIA_Window_Sleep, FALSE);
				}
				break;
			}
			case ID_PREFS_USE :
			{
				struct ANode	*anode;
				UBYTE				*str;

				/*-----------------------------------------------------------*/
				/* Grab the string object strings & put them into our prefs. */
				/*-----------------------------------------------------------*/
				GetPrefsStrings ();

				/*-----------------------------------*/
				/* Save the preferences only to ENV: */
				/*-----------------------------------*/
				SavePrefs (Prefs, FALSE);

				/*-----------------------------------------*/
				/* Close pref window & awaken main window. */
				/*-----------------------------------------*/
				set (prefswinobj, MUIA_Window_Open, FALSE);
				set (winobj, MUIA_Window_Sleep, FALSE);

				/*------------------------------------------*/
				/* Check if we need to read the alias file. */
				/*------------------------------------------*/
				if (Stricmp (oldaliasfile, Prefs->p_AliasFile))
				{
					/*--------------------*/
					/* Reread alias file. */
					/*--------------------*/
					NewList (&AliasList);
					NumberOfAliases = 0;
					ReadAliases ();

					/*------------------------------------------*/
					/* Remove all existing entries in listview. */
					/*------------------------------------------*/
					DoMethod (lvobj, MUIM_List_Clear);
					set (winobj, MUIA_Window_Sleep, TRUE);

					/*--------------------------------------------*/
					/* Add our alias list to the listview object: */
					/*--------------------------------------------*/
					for (anode = (struct ANode *) AliasList.lh_Head;
						  anode->an_Node.ln_Succ;
						  anode = (struct ANode *) anode->an_Node.ln_Succ)
					{
						str = &anode->an_Alias [0];
						DoMethod (lvobj, MUIM_List_Insert, &str, 1, MUIV_List_Insert_Bottom);
					}
					set (winobj, MUIA_Window_Sleep, FALSE);
				}
				break;
			}
			case ID_PREFS_QUIT :
			{
				/*-----------------------------------------*/
				/* Close pref window & awaken main window. */
				/*-----------------------------------------*/
				set (prefswinobj, MUIA_Window_Open, FALSE);
				set (winobj, MUIA_Window_Sleep, FALSE);
				break;
			}
		}
		if (KeepGoing && signals)
		{
			Wait (signals);
		}
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              CleanExit()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void CleanExit (UWORD exitvalue, UBYTE *exitstr)
{
	/*--------------------*/
	/* Close main window. */
	/*--------------------*/
	set (winobj, MUIA_Window_Open, FALSE);

	/*-----------------------*/
	/* Save MUI environment. */
	/*-----------------------*/
	DoMethod (appobj, MUIM_Application_Save, MUIV_Application_Save_ENV);
	DoMethod (appobj, MUIM_Application_Save, MUIV_Application_Save_ENVARC);

	/*------------------------*/
	/* Shut down application. */
	/*------------------------*/
	if (appobj)
	{
		MUI_DisposeObject (appobj);
	}

	/*-------------*/
	/* Free nodes. */
	/*-------------*/
	FreeAllNodes (&AliasList);

	if (dobj)
	{
		FreeDiskObject (dobj);
	}
	if (Prefs)
	{
		FreeVec (Prefs);
	}
	if (IconBase)
	{
		CloseLibrary (IconBase);
	}
	if (UtilityBase)
	{
		CloseLibrary (UtilityBase);
	}
	if (MUIMasterBase)
	{
		CloseLibrary (MUIMasterBase);
	}
	if (IntuitionBase)
	{
		CloseLibrary ((struct Library *) IntuitionBase);
	}
	if (exitstr)
	{
		PutStr (exitstr);
		exit (20);
	}
	exit (exitvalue);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             BuildAppObj()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
APTR BuildAppObj (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	APTR appObj;										// Application object to return to caller.

	/*---------*/
	/* C O D E */
	/*---------*/
	appObj =	ApplicationObject,
				MUIA_Application_Title,			"MUIEmail",
				MUIA_Application_Version,		VERS,
				MUIA_Application_Copyright,	"й1993 by HemSoft Developments",
				MUIA_Application_Author,		"Franz Hemmer",
				MUIA_Application_Description,	"MUI interface for emailing.",
				MUIA_Application_Base,			"MUIEmail",
				MUIA_Application_Menu,			MenuGlobal,
				MUIA_Application_DiskObject,	dobj = GetDiskObject ("PROGDIR:MUIEmail"),
				MUIA_Application_SingleTask,	TRUE,
				MUIA_HelpFile,						"MUIEmail.guide",

		/*--------------*/
		/* MAIN window: */
		/*--------------*/
		SubWindow, winobj = WindowObject,
								  MUIA_Window_Title,			VERS " - " DATE,
								  MUIA_Window_ID,				MAKE_ID ('E', 'M', 'A', 'L'),

			WindowContents, VGroup,

				Child, statobj		=	TextObject,				TextFrame,
											MUIA_HelpNode,			NODE_STATUS_OBJ,
											MUIA_Background,		MUII_BACKGROUND,
											MUIA_Text_PreParse,	"\33c\33i",
											MUIA_Text_Contents,	StatTxt,
											End,
				Child, lvobj		=	ListviewObject,
											MUIA_HelpNode,						NODE_LISTVIEW_OBJ,
											MUIA_Listview_DoubleClick,		TRUE,
											MUIA_Listview_List,				ListObject,
												InputListFrame,
										 		MUIA_List_ConstructHook,	MUIV_List_ConstructHook_String,
										 		MUIA_List_DestructHook,		MUIV_List_DestructHook_String,
										 		End,
											End,
				Child, addrobj		=	TextObject,				TextFrame,
											MUIA_HelpNode,			NODE_ADDRESS_OBJ,
											MUIA_Background,		MUII_BACKGROUND,
											MUIA_Text_PreParse,	"\33c\33i",
											MUIA_Text_Contents,	"Not selected.",
											End,
				Child, commentobj	=	TextObject,				TextFrame,
											MUIA_HelpNode,			NODE_COMMENT_OBJ,
											MUIA_Background,		MUII_BACKGROUND,
											MUIA_Text_PreParse,	"\33c\33i",
											MUIA_Text_Contents,	"None.",
											End,
				Child, mailobj		=	TextObject,				ButtonFrame,
											MUIA_HelpNode,			NODE_MAIL_OBJ,
											MUIA_Text_Contents,	"Mail",
											MUIA_Text_PreParse,	"\33c",
											MUIA_Text_SetMax,		FALSE,
											MUIA_Text_HiChar,		'm',
											MUIA_ControlChar,		'm',
											MUIA_InputMode,		MUIV_InputMode_RelVerify,
											MUIA_Background,		MUII_ButtonBack,
											End,

			End, // VGroup.

		End, // SubWindow.

		/*---------------*/
		/* PREFS window: */
		/*---------------*/
		SubWindow, prefswinobj = WindowObject,
										 MUIA_Window_Title,	"Preferences",
										 MUIA_Window_ID,		MAKE_ID ('P', 'R', 'E', 'F'),

			WindowContents, VGroup,

				Child, ColGroup (3), GroupFrameT ("Preference Items:"),

					Child, Label2 ("Alias File:"),
					Child, aliasfileobj		=	StringObject,				StringFrame,
														MUIA_HelpNode,				NODE_PREFS_ALIASFILE,
														MUIA_String_Contents,	Prefs->p_AliasFile,
														MUIA_String_MaxLen,		256,
														End,
					Child, aliasfilereqobj	=	ImageObject,				ButtonFrame,
														MUIA_Weight,				1,
														MUIA_Image_Spec,			MUII_PopFile,
														MUIA_Image_FreeVert,		TRUE,
														MUIA_ShowSelState,		TRUE,
														MUIA_InputMode,			MUIV_InputMode_RelVerify,
														End,

					Child, Label2 ("Editor:"),
					Child, editorfileobj		=	StringObject,				StringFrame,
														MUIA_HelpNode,				NODE_PREFS_EDITORFILE,
														MUIA_String_Contents,	Prefs->p_EditorFile,
														MUIA_String_MaxLen,		256,
														End,
					Child, editorfilereqobj	=	ImageObject,				ButtonFrame,
														MUIA_Weight,				1,
														MUIA_Image_Spec,			MUII_PopFile,
														MUIA_Image_FreeVert,		TRUE,
														MUIA_ShowSelState,		TRUE,
														MUIA_InputMode,			MUIV_InputMode_RelVerify,
														End,

					Child, Label2 ("Editor Arguments:"),
					Child, editorargsobj		=	StringObject,				StringFrame,
														MUIA_HelpNode,				NODE_PREFS_EDITORARGS,
														MUIA_String_Contents,	Prefs->p_EditorArgs,
														MUIA_String_MaxLen,		256,
														End,
					Child, HSpace (0),

					Child, Label2 ("Mailer:"),
					Child, mailerfileobj		=	StringObject,				StringFrame,
														MUIA_HelpNode,				NODE_PREFS_MAILERFILE,
														MUIA_String_Contents,	Prefs->p_MailerFile,
														MUIA_String_MaxLen,		256,
														End,
					Child, mailerfilereqobj	=	ImageObject,				ButtonFrame,
														MUIA_Weight,				1,
														MUIA_Image_Spec,			MUII_PopFile,
														MUIA_Image_FreeVert,		TRUE,
														MUIA_ShowSelState,		TRUE,
														MUIA_InputMode,			MUIV_InputMode_RelVerify,
														End,

					Child, Label2 ("Mailer Arguments:"),
					Child, mailerargsobj		=	StringObject,				StringFrame,
														MUIA_HelpNode,				NODE_PREFS_MAILERARGS,
														MUIA_String_Contents,	Prefs->p_MailerArgs,
														MUIA_String_MaxLen,		256,
														End,
					Child, HSpace (0),

				End, // ColGroup.

				Child, HGroup, MUIA_Group_SameSize, TRUE,

					Child, saveobj		=	KeyButton ("Save", 's'),
					Child, HSpace (0),
					Child, useobj		=	KeyButton ("Use", 'u'),
					Child, HSpace (0),
					Child, cancelobj	=	KeyButton ("Cancel", 'c'),

				End, // HGroup.

			End, // VGroup.

		End, // SubWindow.

	End; // App.

	/*--------------------*/
	/* Return the object. */
	/*--------------------*/
	return (appObj);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             AppObjSetup()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void AppObjSetup (void)
{
	//
	// This function takes care of MUI object notifications, and filling the
	// listview with the aliases etc.
	//
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct ANode	*anode;
	char				*str;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-----------------------*/
	/* Window Close Request: */
	/*-----------------------*/
	DoMethod (winobj,								MUIM_Notify,
				 MUIA_Window_CloseRequest, 	TRUE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_QUIT);
	DoMethod (prefswinobj,						MUIM_Notify,
				 MUIA_Window_CloseRequest, 	TRUE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_QUIT);

	/*----------*/
	/* Buttons: */
	/*----------*/
	DoMethod (mailobj,							MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_MAIL);
	DoMethod (saveobj,							MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_SAVE);
	DoMethod (useobj,								MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_USE);
	DoMethod (cancelobj,							MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_QUIT);

	/*------------*/
	/* Listviews: */
	/*------------*/
	DoMethod (lvobj,								MUIM_Notify,
				 MUIA_Listview_DoubleClick,	TRUE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_MAIL);
	DoMethod (lvobj,								MUIM_Notify,
				 MUIA_List_Active,				MUIV_EveryTime,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_SELECT_CHANGE);

	/*-------------*/
	/* Requesters: */
	/*-------------*/
	DoMethod (aliasfilereqobj,					MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_ALIAS_FILE_REQ);
	DoMethod (editorfilereqobj,				MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_EDITOR_FILE_REQ);
	DoMethod (mailerfilereqobj,				MUIM_Notify,
				 MUIA_Pressed,						FALSE,
				 appobj,								2,
				 MUIM_Application_ReturnID,	ID_PREFS_MAILER_FILE_REQ);

	/*---------------*/
	/* Cycle chains: */
	/*---------------*/
	DoMethod (winobj, MUIM_Window_SetCycleChain, lvobj, mailobj, NULL);
	DoMethod (prefswinobj, MUIM_Window_SetCycleChain,
				 aliasfileobj, aliasfilereqobj, editorfileobj, editorfilereqobj, editorargsobj,
				 mailerfileobj, mailerfilereqobj, mailerargsobj, NULL);
				

	/*--------------------------------------------*/
	/* Add our alias list to the listview object: */
	/*--------------------------------------------*/
	for (anode = (struct ANode *) AliasList.lh_Head;
		  anode->an_Node.ln_Succ;
		  anode = (struct ANode *) anode->an_Node.ln_Succ)
	{
		str = &anode->an_Alias [0];
		DoMethod (lvobj, MUIM_List_Insert, &str, 1, MUIV_List_Insert_Bottom);
	}

	/*----------------------------------------*/
	/* Load Environment & Open Status Window: */
	/*----------------------------------------*/
	DoMethod (appobj, MUIM_Application_Load, MUIV_Application_Load_ENV);
	set (winobj, MUIA_Window_Open, TRUE);

	/*--------------------------------*/
	/* Activate top item in listview. */
	/*--------------------------------*/
	set (winobj, MUIA_Window_ActiveObject, lvobj);
	set (lvobj, MUIA_List_Active, MUIV_List_Active_Top);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             ReadAliases()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void ReadAliases (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct ANode	*anode		= NULL;
	BPTR				aliasFile	= NULL;
	UBYTE				aliasBuf		[160];
	UBYTE				address		[80];
	UBYTE				alias			[80];
	UBYTE				comment		[160];
	COUNT				x				= 0;
	COUNT				y				= 0;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*------------------*/
	/* Open alias file. */
	/*------------------*/
	if (!(aliasFile = Open (Prefs->p_AliasFile, MODE_OLDFILE)))
	{
		MUI_Request (appobj, winobj, 0, NULL, "*Okay",
						 "\033c\0338MUIEmail V%ld.%ld\n\n\0332Couldn't open alias file. Check your preferences please.\n",
						 VERSION, REVISION, TAG_END);
		set (addrobj, MUIA_Text_Contents, "None selected");
		set (commentobj, MUIA_Text_Contents, "None");
		goto panic;
	}

	/*---------------*/
	/* Find aliases. */
	/*---------------*/
	while (FGets (aliasFile, aliasBuf, 159))
	{
		/*-----------------*/
		/* Reset counters. */
		/*-----------------*/
		x = y = 0;

		/*--------------------------------*/
		/* Skip comments and blank lines. */
		/*--------------------------------*/
		if (aliasBuf [0] != '#' && aliasBuf [0] != '\n' && aliasBuf [0] != '\r')
		{
			while (aliasBuf [x] != ':' && aliasBuf [x] != '\n' && aliasBuf [x] != '\r' && aliasBuf [x] != '\0')
			{
				alias [x] = aliasBuf [x];
				x++;
			}
			if (aliasBuf [x] == ':')
			{
				alias [x] = '\0';
				x++;
				while (aliasBuf [x] != ':' && aliasBuf [x] != '\n' && aliasBuf [x] != '\r' && aliasBuf [x] != '\0')
				{
					if (!isspace (aliasBuf [x]) && aliasBuf [x] != ',')
					{
						address [y++] = aliasBuf [x];
					}
					x++;
				}
				if (y > 0)
				{
					address [y] = '\0';

					/*------------------------------------*/
					/* Allocate memory for an alias node. */
					/*------------------------------------*/
					if (!(anode = AllocVec (sizeof (struct ANode), MEMF_ANY | MEMF_CLEAR)))
					{
						Close (aliasFile);
						CleanExit (RETURN_FAIL, "Out of memory...\n");
					}

					/*-------------*/
					/* Build node. */
					/*-------------*/
					strcpy (anode->an_Alias,	alias);
					strcpy (anode->an_Address,	address);
					strcpy (anode->an_Comment,	comment);
					anode->an_Node.ln_Name = anode->an_Alias;
					anode->an_Node.ln_Pri = 0;
					anode->an_Node.ln_Type = NT_USER;

					/*---------------------------*/
					/* Add the node to the list. */
					/*---------------------------*/
					AddTail (&AliasList, (struct Node *) anode);
					NumberOfAliases++;
				}
			}
		}
		else
		{
			if (aliasBuf [0] == '#')
			{
				x++;

				/*-------------------------------------------*/
				/* Remember this comment for the next alias. */
				/*-------------------------------------------*/
				while (aliasBuf [x] != '\n' && aliasBuf [x] != '\r' && aliasBuf [x] != '\0')
				{
					comment [y++] = aliasBuf [x++];
				}
				comment [y] = '\0';
			}
		}
	}

	if (NumberOfAliases == 0)
	{
		set (addrobj, MUIA_Text_Contents, "None selected");
		set (commentobj, MUIA_Text_Contents, "None");
	}

	/*-----------------*/
	/* Close the file. */
	/*-----------------*/
	Close (aliasFile);

	/*----------------*/
	/* Sort the list. */
	/*----------------*/
	SortList (&AliasList, 0);

 panic:

	/*-----------------------------*/
	/* Also build the status text. */
	/*-----------------------------*/
	sprintf (StatTxt, "%ld aliases displayed.", NumberOfAliases);
	set (statobj, MUIA_Text_Contents, StatTxt);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              SortList()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void SortList (struct List *list, short col)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct List		tmp;
	struct Node		*np, *np2;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-------------------------*/
	/* Check if list is empty. */
	/*-------------------------*/
	if (EmptyList (list))
	{
		return;
	}

	NewList (&tmp);

	while (!EmptyList (list))
	{
		np = RemHead (list);

		if (EmptyList (&tmp))
		{
			AddHead (&tmp, np);
		}
		else
		{
			if (Stricmp (&np->ln_Name [col], &tmp.lh_Head->ln_Name [col]) < 0)
			{
				AddHead (&tmp, np);
			}
			else
			{
				if (Stricmp (&np->ln_Name [col], &tmp.lh_TailPred->ln_Name [col]) > 0)
				{
					AddTail (&tmp, np);
				}
				else
				{
					for (np2 = tmp.lh_Head; np2->ln_Succ; np2 = np2->ln_Succ)
					{
						if (Stricmp (&np->ln_Name [col], &np2->ln_Name [col]) < 0)
						{
							Insert (&tmp, np, np2->ln_Pred);
							break;
						}
					}
				}
			}
		}
	}

	NewList (list);

	while (!EmptyList (&tmp))
	{
		np = RemHead (&tmp);
		AddTail (list, np);
	}

}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              EmptyList()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL EmptyList (struct List *list)
{
	if (list)
	{
		if (list->lh_TailPred == (struct Node *) list)
		{
			return (TRUE);
		}
	}
	return (FALSE);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            FreeAllNodes()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void FreeAllNodes (struct List *l)
{
	//
	// This function frees all nodes in a list, and deallocates memory for
	// each node. In the end a NewList() is performed on the list, so that
	// it is immidiately ready for use.
	//
	// NOTE! The nodes in the list must have been allocated with AllocVec(),
	//       otherwise, this function has about 100% change to crash :)
	//
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct Node *wn;									// Work node.
	struct Node *nn;									// Next node.

	/*---------*/
	/* C O D E */
	/*---------*/
	wn = l->lh_Head;									// Point to first in list.
	while (nn = wn->ln_Succ)
	{
		FreeVec (wn);
		wn = nn;
	}
	NewList (l);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             GetNodeNum()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Node *GetNodeNum (struct List *l, ULONG num)
{
	//
	// This function returns the <num>th node in list <l>, and is called
	// whenever a user clicks on an item in a listview. We don't do error
	// handling here, so be absolutely sure that <num> is valid.
	//
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	ULONG			count = 0;
	struct Node	*n;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-------------------------------------------------*/
	/* Traverse down the list, starting from the head. */
	/*-------------------------------------------------*/
	for (n = l->lh_Head; n->ln_Succ; n = n->ln_Succ)
	{
		if (count == num)
		{
			return (n);
		}
		count++;
	}
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                             GetMyPrefs()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Prefs *GetMyPrefs (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	BPTR				prefFile	= NULL;				// Prefs file handle.
	struct Prefs	*prefs;							// Prefs to get and return.

	/*---------*/
	/* C O D E */
	/*---------*/
	/*---------------------------------------*/
	/* Try to open ENV:MUIEmail.prefs first. */
	/*---------------------------------------*/
	if (!(prefFile = Open ("ENV:MUIEmail.prefs", MODE_OLDFILE)))
	{
		/*----------------------*/
		/* Try ENVARC: instead. */
		/*----------------------*/
		if (!(prefFile = Open ("ENVARC:MUIEmail.prefs", MODE_OLDFILE)))
		{
			/*-------------*/
			/* We give up. */
			/*-------------*/
			return (NULL);
		}
	}

	/*----------------------------------------------------------------------------*/
	/* We have opened the prefs file successfully. Now we allocate mem for prefs. */
	/*----------------------------------------------------------------------------*/
	if (!(prefs = AllocVec (sizeof (struct Prefs), MEMF_ANY | MEMF_CLEAR)))
	{
		Close (prefFile);
		return (NULL);
	}

	/*--------------------*/
	/* Read in the prefs. */
	/*--------------------*/
	if (Read (prefFile, prefs, sizeof (struct Prefs)) != sizeof (struct Prefs))
	{
		MUI_Request (appobj, winobj, 0, NULL, "Okay",
						 "MUIEmail V%ld.%ld\n\nThe preference file has a wrong length,\n"
						 							 "probably because it's an old version. I'm\n"
						 							 "going to use internal defaults.",
						 VERSION, REVISION, TAG_END);
		Close (prefFile);
		FreeVec (prefs);
		prefs = NULL;
		prefs = BuildDefPrefs ();
		return (prefs);
	}

	/*---------------------------------------------------------------*/
	/* Everything is A-Okay, we close the file and return the prefs. */
	/*---------------------------------------------------------------*/
	Close (prefFile);
	return (prefs);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                            BuildDefPrefs()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
struct Prefs *BuildDefPrefs (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	struct Prefs	*prefs;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*----------------------------*/
	/* We allocate mem for prefs. */
	/*----------------------------*/
	if (!(prefs = AllocVec (sizeof (struct Prefs), MEMF_ANY | MEMF_CLEAR)))
	{
		return (NULL);
	}

	/*-------------------------*/
	/* Fill in default values. */
	/*-------------------------*/
	strcpy (prefs->p_AliasFile,	"UULIB:aliases");
	strcpy (prefs->p_EditorFile,	"C:Ed");
	strcpy (prefs->p_EditorArgs,	"-sticky");
	strcpy (prefs->p_MailerFile,	"UUCP:C/Elm");
	strcpy (prefs->p_MailerArgs,	"");

	/*-------------------*/
	/* Return the prefs. */
	/*-------------------*/
	return (prefs);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                              SavePrefs()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL SavePrefs (struct Prefs *prefs, BOOL save)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	BPTR	prefFile;									// Prefs file handle.

	/*---------*/
	/* C O D E */
	/*---------*/
	/*-----------------------------------------*/
	/* We always want to at least save to ENV: */
	/*-----------------------------------------*/
	if (!(prefFile = Open ("ENV:MUIEmail.prefs", MODE_NEWFILE)))
	{
		return (FALSE);
	}

	/*---------------*/
	/* Write to ENV: */
	/*---------------*/
	if (Write (prefFile, prefs, sizeof (struct Prefs)) != sizeof (struct Prefs))
	{
		Close (prefFile);
		return (FALSE);
	}

	/*-----------------*/
	/* Close the file. */
	/*-----------------*/
	Close (prefFile);

	/*---------------------------------------------*/
	/* Check if we need to save it to ENVARC: too. */
	/*---------------------------------------------*/
	if (save)
	{
		/*--------------------*/
		/* We save to ENVARC: */
		/*--------------------*/
		if (!(prefFile = Open ("ENVARC:MUIEmail.prefs", MODE_NEWFILE)))
		{
			return (FALSE);
		}

		/*------------------*/
		/* Write to ENVARC: */
		/*------------------*/
		if (Write (prefFile, prefs, sizeof (struct Prefs)) != sizeof (struct Prefs))
		{
			Close (prefFile);
			return (FALSE);
		}

		/*-----------------*/
		/* Close the file. */
		/*-----------------*/
		Close (prefFile);
	}
	return (TRUE);
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                           GetPrefsStrings()									*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
void GetPrefsStrings (void)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	char *aliasfile, *editorfile, *editorargs, *mailerfile, *mailerargs;

	/*---------*/
	/* C O D E */
	/*---------*/
	get (aliasfileobj, MUIA_String_Contents, &aliasfile);
	strcpy (Prefs->p_AliasFile, aliasfile);

	get (editorfileobj, MUIA_String_Contents, &editorfile);
	strcpy (Prefs->p_EditorFile, editorfile);

	get (editorargsobj, MUIA_String_Contents, &editorargs);
	strcpy (Prefs->p_EditorArgs, editorargs);

	get (mailerfileobj, MUIA_String_Contents, &mailerfile);
	strcpy (Prefs->p_MailerFile, mailerfile);

	get (mailerargsobj, MUIA_String_Contents, &mailerargs);
	strcpy (Prefs->p_MailerArgs, mailerargs);
	return;
}

/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
/*                               FileReq()										*/
/*лллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл*/
BOOL FileReq (APTR parentwinobj, APTR strobj, APTR reqobj, UBYTE *initialdirname,
				  UBYTE *filebuf, UBYTE *pattern)
{
	/*-------------*/
	/* L O C A L S */
	/*-------------*/
	BOOL				rc = TRUE;
	APTR				aslreq = NULL;

	struct Screen	*scr = NULL;
	struct Window	*win = NULL;
	LONG				left, top, width, height;

	/*---------*/
	/* C O D E */
	/*---------*/
	/*---------------------------------------------------------------------*/
	/* Put rest of applicatoin to sleep while we put up the asl requester. */
	/*---------------------------------------------------------------------*/
	set (parentwinobj, MUIA_Window_Sleep, TRUE);

	/*--------------------------------------------------------------*/
	/* Get information about our main window for the asl requester. */
	/*--------------------------------------------------------------*/
	if (reqobj)
	{
		get (reqobj, MUIA_Window,		&win);
		get (reqobj, MUIA_LeftEdge,	&left);
		get (reqobj, MUIA_TopEdge,		&top);
		get (reqobj, MUIA_Width,		&width);
		get (reqobj, MUIA_Height,		&height);
	}
	else
	{
		get (parentwinobj, MUIA_Window, &win);
		left	 = 0;
		top	 = 0;
		width	 = win->Width;
		height = win->RPort->TxHeight + 3;
	}

	/*---------------------*/
	/* Get screen pointer. */
	/*---------------------*/
	get (parentwinobj, MUIA_Window_Screen, &scr);

	/*---------------------------*/
	/* Allocate MUI asl request. */
	/*---------------------------*/
	if (aslreq = MUI_AllocAslRequestTags (ASL_FileRequest, TAG_DONE))
	{
		if (MUI_AslRequestTags (aslreq,
										ASLFR_Screen,				scr,
										ASLFR_Window,				NULL,
										ASLFR_PrivateIDCMP,		TRUE,
										ASLFR_TitleText,			"Select File:",
										ASLFR_InitialLeftEdge,	win->LeftEdge + left,
										ASLFR_InitialTopEdge,	win->TopEdge + top + height,
										ASLFR_InitialWidth,		width,
										ASLFR_InitialHeight,		250,
										ASLFR_InitialDrawer,		initialdirname,
										ASLFR_InitialPattern,	pattern,
										TAG_DONE))
		{
			strcpy (filebuf, ((struct FileRequester *) aslreq)->fr_Drawer);
			AddPart (filebuf, ((struct FileRequester *) aslreq)->fr_File, 256);
			if (strobj)
			{
				set (strobj, MUIA_String_Contents, filebuf);
			}
		}
		else
		{
			rc = FALSE;
		}
		MUI_FreeAslRequest (aslreq);
	}

	/*---------------------------*/
	/* Wakeup main window again. */
	/*---------------------------*/
	set (parentwinobj, MUIA_Window_Sleep, FALSE);

	return (rc);
}
