/*****************************************************************************/
/*                                                                           */
/*      asmail - AfterStep Mail                                              */
/*                                                                           */
/*      By Per Liden                                                         */
/*      per@oden.rsn.hk-r.se                                                 */
/*      http://oden.rsn.hk-r.se/~per                                         */
/*                                                                           */
/*****************************************************************************/

/* Version ****************************************************************** */
#define VERSION "0.50"

/* Headers ****************************************************************** */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>

/* XPM struct and icons ***************************************************** */
typedef struct _XpmIcon {
	Pixmap pixmap;
	Pixmap mask;
	XpmAttributes attributes;
	struct XpmIcon *next;
} XpmIcon;

XpmIcon *NoMail, *OldMail, *NewMail, *Current;

#include "pixmaps/newmail.xpm"
#include "pixmaps/oldmail.xpm"
#include "pixmaps/nomail.xpm"
#include "pixmaps/newmail_s.xpm"
#include "pixmaps/oldmail_s.xpm"
#include "pixmaps/nomail_s.xpm"

/* Functions **************************************************************** */
int CheckMailBox(char **Mbox, int NumOfMbox);
int IsNewMail(char *Mbox);
int IsMail(char *Mbox);
int NoOfNewMail(char *Mbox);
int CheckTimeStamp(char **Mbox, int NumOfMbox);
int GetGStatus(void);
void CheckMailCallback(XtPointer XtP, XtIntervalId * XtI);
void Help(void);
void CreateWindow(int argc, char *argv[]);
void MakeSettings(int argc, char *argv[]);
void ParseCfgFile(FILE * File);
void StartLoop(void);
void GetXPM(int Shaped);
void LoadXPMFile(XpmIcon * Icon, char *XpmFile);
void XPMError(int Code);
void RedrawWindow(void);
void ButtonHandler(Widget W, XtPointer P, XEvent * E);
void ExposeHandler(Widget W, XtPointer P, XEvent * E);
void AnimCallback(XtPointer XtP, XtIntervalId * XtI);
Pixel GetColor(char *name);
void AddXpmToAnim(XpmIcon * Icon, XpmIcon * List, int ListNo);

/* Global stuff ************************************************************* */
#define DEFCFGFILE		"/GNUstep/Library/AfterStep/asmail"
/* Default configuration file where ~home is added */
#define DEFINTERVAL		5	/* Default interval 5 sec */
#define DEFANIMATIONSPEED	10	/* Default animationspeed 10 */
#define LEFTBUTTON		1	/* Left mousebutton id */
#define RIGHTBUTTON		3	/* Right mousebutton id */
#define MAXNUMOFMAILBOXES	256	/* Maximim number of mailboxes */
Display *Disp = 0;
Window Root;
char Execute[256] = "";
char NewMailExecute[256] = "";
char ExecuteOnUpdate[256] = "";
char *MailBoxes[MAXNUMOFMAILBOXES];
int NumOfMailBoxes = 0;
int ExecuteFlag = 0;
int NewMailExecuteFlag = 0;
int ExecuteOnUpdateFlag = 0;
int AlwaysNewMailExecute = 0;
int IsNew = 1;
int Interval = DEFINTERVAL;
int Beep = 1;
int Shape = 1;
int *NewMailCounter = 0;
int MailCounter = 0;
int TimeStampMode = 0;
int LockShape = 0;
int *IStatus = 0;
int *GStatus = 0;
int NumOfMsgX = 10;
int NumOfMsgY = 10;
int NumOfMsgMode = 0;
XTextItem NumOfMsg;
GC WinGC;
Widget MainWin;
XtAppContext AsmailApp;
int AnimationSpeed[3] =
{DEFANIMATIONSPEED,
 DEFANIMATIONSPEED,
 DEFANIMATIONSPEED};
char HelpMessage[] =
{
	"asmail - Version %s, by Per Liden (per@oden.rsn.hk-r.se)\n"
	"usage:  asmail [file] [options ...] \n"
	"file:\n"
	"        configuration file to use (default ~/.asmailrc)\n"
	"options:\n"
	"        -geometry <geom>     geometry of asmail\n"
	"        -display  <disp>     specifies the display to use\n"
	"        -title    <string>   title string\n"
 "        -name     <string>   client instance, icon and title strings\n"
	"\n"};

/*****************************************************************************/
void main(int argc, char *argv[])
{
	CreateWindow(argc, argv);
	StartLoop();
}

/*****************************************************************************/
void Help()
{
	/* Print help message */
	fprintf(stderr, HelpMessage, VERSION);
	exit(1);
}

/****************************************************************************/
void MakeSettings(int argc, char *argv[])
{
	char CfgFile[256];
	FILE *File = 0;

	/* Get config file */
	if (argc == 1) {
		strcpy(CfgFile, (char *) getenv("HOME"));
		strcat(CfgFile, DEFCFGFILE);
	} else if (argc == 2) {
		/* Check if option */
		if (argv[1][0] == '-')
			Help();
		else
			strcpy(CfgFile, argv[1]);
	} else
		Help();


	/* Open config file */
	File = fopen(CfgFile, "r");
	if (File != NULL) {
		ParseCfgFile(File);
		fclose(File);
	} else
		fprintf(stderr, "asmail: '%s' not found, using default settings\n", CfgFile);


	/* Check interval */
	if (!Interval) {
		fprintf(stderr, "asmail: invalid update frequency specified, using default\n");
		Interval = DEFINTERVAL;		/* Use default */
	}
	/* Check animationspeed */
	if (!AnimationSpeed[0] || !AnimationSpeed[1] || !AnimationSpeed[2]) {
		fprintf(stderr, "asmail: invalid animationspeed specified, using default\n");
		AnimationSpeed[0] = DEFANIMATIONSPEED;	/* Use default */
		AnimationSpeed[1] = DEFANIMATIONSPEED;	/* Use default */
		AnimationSpeed[2] = DEFANIMATIONSPEED;	/* Use default */
	}
	AnimationSpeed[0] *= 100;
	AnimationSpeed[1] *= 100;
	AnimationSpeed[2] *= 100;

	/* If no MaiiFile option search for $MAIL */
	if (NumOfMailBoxes == 0) {
		if (getenv("MAIL") != NULL) {
			NumOfMailBoxes = 1;
			GStatus = (int *) calloc(NumOfMailBoxes, sizeof(int));
			IStatus = (int *) calloc(NumOfMailBoxes, sizeof(int));
			NewMailCounter = (int *) calloc(NumOfMailBoxes, sizeof(int));
			MailBoxes[0] = (char *) calloc(strlen((char *) getenv("MAIL")) + 1, sizeof(char));
			strcpy(MailBoxes[0], (char *) getenv("MAIL"));
		} else {
			fprintf(stderr, "asmail: no mailfile specified\n");
			exit(1);
		}
	}
	/* Check NumOfMsgMode */
	if (NumOfMsgMode < 0 || NumOfMsgMode > 3) {
		fprintf(stderr, "asmail: invalid NumOfMsgMode specified\n");
		exit(1);
	}
}

/****************************************************************************/
void AddXpmToAnim(XpmIcon * Icon, XpmIcon * List, int ListNo)
{
	static XpmIcon *First[3];
	static XpmIcon *Last[3];
	static Count[3] =
	{0, 0, 0};

	if (Count[ListNo] == 0) {
		switch (ListNo) {
		case 0:
			NoMail = Icon;
			break;
		case 1:
			OldMail = Icon;
			break;
		case 2:
			NewMail = Icon;
			break;
		}

		First[ListNo] = Icon;
		List = First[ListNo];
		List->next = (struct XpmIcon *) List;
		Last[ListNo] = First[ListNo];
		Count[ListNo]++;
	} else {
		Last[ListNo]->next = (struct XpmIcon *) Icon;
		Last[ListNo] = Icon;
		Last[ListNo]->next = (struct XpmIcon *) First[ListNo];
	}
}

/****************************************************************************/
void ParseCfgFile(FILE * File)
{
	char Buffer[256];
	int i;
	char c;
	XpmIcon *Icon;

	while (!feof(File)) {
		/* Read string */
		fscanf(File, "%s", Buffer);

		/* Comment */
		if (Buffer[0] == '#') {
			/* Got to next line */
			fgets(Buffer, 255, File);
		}
		/* NoBeep */
		else if (!strcasecmp(Buffer, "NoBeep")) {
			Beep = 0;
		}
		/* NoShape */
		else if (!strcasecmp(Buffer, "NoShape")) {
			Shape = 0;
			GetXPM(0);
		}
		/* LockShape */
		else if (!strcasecmp(Buffer, "LockShape")) {
			LockShape = 1;
		}
		/* MailFiles <...> */
		else if (!strcasecmp(Buffer, "MailFiles")) {
			i = 0;
			while (1) {
				fscanf(File, "%s", Buffer);
				/* End */
				if (!strcasecmp(Buffer, "End")) {
					/* If no mailfiles specified */
					if (i == 0) {
						fprintf(stderr, "asmail: no mailfiles specified in config");
						exit(1);
					}
					NumOfMailBoxes = i;
					GStatus = (int *) calloc(NumOfMailBoxes, sizeof(int));
					IStatus = (int *) calloc(NumOfMailBoxes, sizeof(int));
					NewMailCounter = (int *) calloc(NumOfMailBoxes, sizeof(int));
					break;
				}
				/* Mailfile */
				else {
					/* Check maximin number of mailboxes */
					if (i > MAXNUMOFMAILBOXES) {
						fprintf(stderr, "asmail: too many mailboxes specified");
						exit(1);
					}
					/* Check NumOfMsgMode */
					else if (i > 1 && NumOfMsgMode != 0) {
						fprintf(stderr, "asmail: NumOfMsg can not be used if you have multiple mailboxes");
						exit(1);
					}
					/* Add mailbox */
					MailBoxes[i] = (char *) calloc(strlen(Buffer) + 1, sizeof(char));
					strcpy(MailBoxes[i], Buffer);
					i++;
				}
			}
		}
		/* Update <sec> */
		else if (!strcasecmp(Buffer, "Update")) {
			fscanf(File, "%d ", &Interval);
		}
		/* Execute <program> */
		else if (!strcasecmp(Buffer, "Execute")) {
			fgetc(File);
			fgets(Execute, 255, File);
			ExecuteFlag = 1;
		}
		/* ExecuteOnUpdate <program> */
		else if (!strcasecmp(Buffer, "ExecuteOnUpdate")) {
			fgetc(File);
			fgets(ExecuteOnUpdate, 255, File);
			ExecuteOnUpdateFlag = 1;
		}
		/* NumOfMsgMode <mode> */
		else if (!strcasecmp(Buffer, "NumOfMsgMode")) {
			/* Check NumOfMailBoxes */
			if (NumOfMailBoxes > 1) {
				fprintf(stderr, "asmail: NumOfMsg can not be used if you have multiple mailboxes");
				exit(1);
			}
			fscanf(File, "%d ", &NumOfMsgMode);
			NumOfMsg.chars = malloc(50);
			NumOfMsg.font = XLoadFont(Disp, "-*-lucida-*-*-*-*-*-*-*-*-*-*-*-*");
			NumOfMsg.delta = 1;
		}
		/* NumOfMsgPosition <x> <y> */
		else if (!strcasecmp(Buffer, "NumOfMsgPosition")) {
			fscanf(File, "%d ", &NumOfMsgX);
			fscanf(File, "%d ", &NumOfMsgY);
		}
		/* NumOfMsgFont <string> */
		else if (!strcasecmp(Buffer, "NumOfMsgFont")) {
			fscanf(File, "%s ", &Buffer);
			NumOfMsg.font = XLoadFont(Disp, Buffer);
		}
		/* NewMailExecute <program> */
		else if (!strcasecmp(Buffer, "NewMailExecute")) {
			fgetc(File);
			fgets(NewMailExecute, 255, File);
			NewMailExecuteFlag = 1;
		}
		/* AlwaysNewMailExecute */
		else if (!strcasecmp(Buffer, "AlwaysNewMailExecute")) {
			AlwaysNewMailExecute = 1;
		}
		/* TimeStampMode */
		else if (!strcasecmp(Buffer, "TimeStampMode")) {
			TimeStampMode = 1;
		}
		/* AnimationSpeed <nomail> <oldmail <newmail> */
		else if (!strcasecmp(Buffer, "AnimationSpeed")) {
			fscanf(File, "%d ", &AnimationSpeed[0]);
			fscanf(File, "%d ", &AnimationSpeed[1]);
			fscanf(File, "%d ", &AnimationSpeed[2]);
		}
		/* NoMail <...> */
		else if (!strcasecmp(Buffer, "NoMail")) {
			free(NoMail);
			while (1) {
				fscanf(File, "%s ", Buffer);
				if (!strcasecmp(Buffer, "End"))
					break;
				Icon = (XpmIcon *) calloc(1, sizeof(XpmIcon));
				LoadXPMFile(Icon, Buffer);
				AddXpmToAnim(Icon, NoMail, 0);
			}
			Current = NoMail;
		}
		/* OldMail <...> */
		else if (!strcasecmp(Buffer, "OldMail")) {
			free(OldMail);
			while (1) {
				fscanf(File, "%s ", Buffer);
				if (!strcasecmp(Buffer, "End"))
					break;
				Icon = (XpmIcon *) calloc(1, sizeof(XpmIcon));
				LoadXPMFile(Icon, Buffer);
				AddXpmToAnim(Icon, OldMail, 1);
			}
		}
		/* NewMail <...> */
		else if (!strcasecmp(Buffer, "NewMail")) {
			free(NewMail);
			while (1) {
				fscanf(File, "%s ", Buffer);
				if (!strcasecmp(Buffer, "End"))
					break;
				Icon = (XpmIcon *) calloc(1, sizeof(XpmIcon));
				LoadXPMFile(Icon, Buffer);
				AddXpmToAnim(Icon, NewMail, 2);
			}
		}
		/* Unknown keyword */
		else {
			for (i = 0, c = 0; i < strlen(Buffer); i++)
				c += isgraph(Buffer[i]);
			if (c != 0) {
				fprintf(stderr, "asmail: unknown keyword '%s'\n", Buffer);
				exit(1);
			}
		}
	}
}

/****************************************************************************/
void CreateWindow(int argc, char *argv[])
{
	XSizeHints SizeHints;
	XWMHints WmHints;
	XGCValues gcv;
	unsigned long gcm;

	/* Create Main window */
	MainWin = XtAppInitialize(&AsmailApp, "asmail", NULL, 0, &argc, argv, NULL, NULL, 0);
	Disp = XtDisplay(MainWin);
	Root = RootWindow(Disp, DefaultScreen(Disp));

	/* Add eventhandlers */
	XtAddEventHandler(MainWin, ExposureMask, FALSE, (XtEventHandler) ExposeHandler, NULL);
	XtAddEventHandler(MainWin, ButtonPressMask, FALSE, (XtEventHandler) ButtonHandler, NULL);

	/* Get XPM data */
	GetXPM(1);

	/* Make settings */
	MakeSettings(argc, argv);

	/* Set window attributes */
	XtResizeWidget(MainWin, Current->attributes.width, Current->attributes.height, 1);
	XtRealizeWidget(MainWin);

	/* Create GC */
	gcm = GCForeground | GCBackground | GCGraphicsExposures;
	gcv.foreground = GetColor("white");
	gcv.background = GetColor("white");
	gcv.graphics_exposures = False;
	WinGC = XCreateGC(Disp, Root, gcm, &gcv);

	/* Map mainwindow */
	XtMapWidget(MainWin);
	RedrawWindow();
}

/****************************************************************************/
void RedrawWindow(void)
{
	int GS = GetGStatus();

	/* Select icon */
	switch (GS) {
	case 0:
		Current = NoMail;
		break;
	case 1:
		Current = OldMail;
		break;
	case 2:
		Current = NewMail;
		break;
	}

	/* Shape window */
	if (Shape) {
		XShapeCombineMask(Disp, XtWindow(MainWin), ShapeBounding, 0, 0,
				  Current->mask, ShapeSet);
		if (LockShape)
			Shape = 0;
	}
	/* Draw icon */
	XCopyArea(Disp, Current->pixmap, XtWindow(MainWin), WinGC, 0, 0,
	    Current->attributes.width, Current->attributes.height, 0, 0);

	/* Draw number of messages */
	if (GS && NumOfMsgMode) {
		/* Create string */
		switch (NumOfMsgMode) {
		case 1:
			sprintf(NumOfMsg.chars, "%d/%d", NewMailCounter[0], MailCounter);
			break;
		case 2:
			sprintf(NumOfMsg.chars, "%d", NewMailCounter[0]);
			break;
		case 3:
			sprintf(NumOfMsg.chars, "%d", MailCounter);
			break;
		}
		NumOfMsg.nchars = strlen(NumOfMsg.chars);
		XDrawText(Disp, XtWindow(MainWin), WinGC, NumOfMsgX, NumOfMsgY, &NumOfMsg, 1);
	}
}

/****************************************************************************/
void ButtonHandler(Widget W, XtPointer P, XEvent * E)
{
	int i;
	int Redraw = 0;

	/* Left button */
	if (E->xbutton.button == LEFTBUTTON && ExecuteFlag == 1)
		system(Execute);

	/* Right button */
	else if (E->xbutton.button == RIGHTBUTTON) {
		for (i = 0; i < NumOfMailBoxes; i++) {
			if (GStatus[i] == 2) {
				if (TimeStampMode) {
					GStatus[i] = 1;
					IStatus[i] = 1;
				} else {
					GStatus[i] = 1;
					IStatus[i] = 3;
					NewMailCounter[i] = NoOfNewMail(MailBoxes[i]);
				}
				Redraw++;
			}
		}
	}
	if (Redraw)
		RedrawWindow();
}

/****************************************************************************/
void ExposeHandler(Widget W, XtPointer P, XEvent * E)
{
	RedrawWindow();
}

/****************************************************************************/
void StartLoop(void)
{
	/* Check mailbox at statup */
	if (CheckMailBox(MailBoxes, NumOfMailBoxes))
		RedrawWindow();

	/* Set timeout */
	XtAppAddTimeOut(AsmailApp, Interval * 1000,
			(XtTimerCallbackProc) CheckMailCallback, NULL);

	/* Set animation timeout's */
	XtAppAddTimeOut(AsmailApp, AnimationSpeed[GetGStatus()],
			(XtTimerCallbackProc) AnimCallback, NULL);

	/* Start looping */
	XFlush(Disp);
	XtAppMainLoop(AsmailApp);
}

/****************************************************************************/
void AnimCallback(XtPointer XtP, XtIntervalId * XtI)
{
	/* Change to next image */
	NoMail = (XpmIcon *) NoMail->next;
	OldMail = (XpmIcon *) OldMail->next;
	NewMail = (XpmIcon *) NewMail->next;

	/* Redraw */
	RedrawWindow();

	/* Set animation timeout */
	XtAppAddTimeOut(AsmailApp, AnimationSpeed[GetGStatus()],
			(XtTimerCallbackProc) AnimCallback, NULL);
}

/****************************************************************************/
void CheckMailCallback(XtPointer XtP, XtIntervalId * XtI)
{
	/* Check if ExecuteOnUpdate */
	if (ExecuteOnUpdateFlag)
		system(ExecuteOnUpdate);

	/* Check mailbox */
	if (TimeStampMode && CheckTimeStamp(MailBoxes, NumOfMailBoxes))
		RedrawWindow();
	else {
		if (CheckMailBox(MailBoxes, NumOfMailBoxes))
			RedrawWindow();
	}

	/* Set timeout */
	XtAppAddTimeOut(AsmailApp, Interval * 1000,
			(XtTimerCallbackProc) CheckMailCallback, NULL);
}

/************************************************************/
int CheckTimeStamp(char **Mbox, int NumOfMbox)
{
	struct stat St;
	int i;
	int Result = 0;
	int ExecFlag = 0;
	int BeepFlag = 0;

	if (NumOfMbox == 0)
		return 0;

	for (i = 0; i < NumOfMbox; i++) {
		/* Check if modified */
		if (!stat(Mbox[i], &St)) {
			if (St.st_mtime >= St.st_atime) {
				/* Changed */
				if (IsNew) {
					BeepFlag = 1;

					if (IStatus[i] == 2 && AlwaysNewMailExecute && NewMailExecuteFlag)
						ExecFlag = 1;
					else if (IStatus[i] != 2 && NewMailExecuteFlag)
						ExecFlag = 1;
					IsNew = 0;
					IStatus[i] = 2;
					GStatus[i] = 2;
				}
				Result = 1;
			}
		}
	}

	/* Beep and execute */
	if (BeepFlag && Beep)
		XBell(Disp, 0);
	if (ExecFlag)
		system(NewMailExecute);

	return Result;
}

/****************************************************************************/
int CheckMailBox(char **Mbox, int NumOfMbox)
{
	static int iCheckingMailbox = 0;
	int i;
	int Prev;
	int Result = 0;
	int BeepFlag = 0;
	int ExecFlag = 0;

	if (!iCheckingMailbox) {
		iCheckingMailbox = 1;
		for (i = 0; i < NumOfMbox; i++) {
			Prev = GStatus[i];
/************************************************************/
			if (IsMail(Mbox[i])) {
				if (IsNewMail(Mbox[i])) {
					if (NoOfNewMail(Mbox[i]) > NewMailCounter[i]) {
						if (IsNew) {
							if (IStatus[i] == 2 && AlwaysNewMailExecute && NewMailExecuteFlag)
								ExecFlag = 1;
							else if (IStatus[i] != 2 && NewMailExecuteFlag)
								ExecFlag = 1;
							BeepFlag = 1;
							IsNew = 0;
							NewMailCounter[i] = NoOfNewMail(Mbox[i]);
						}
						IStatus[i] = 2;
						GStatus[i] = 2;

					} else {
						IsNew = 1;
						if (IStatus[i] == 3)
							GStatus[i] = 1;
						else
							GStatus[i] = 2;
					}

				} else {
					IsNew = 1;
					IStatus[i] = 1;
					GStatus[i] = 1;
					NewMailCounter[i] = 0;
				}
			} else {
				IsNew = 1;
				IStatus[i] = 0;
				GStatus[i] = 0;
				NewMailCounter[i] = 0;
			}
/************************************************************/
			iCheckingMailbox = 0;
		}
		Result |= (Prev != GStatus[i]);
	}
	/* Check for execute and beep */
	if (ExecFlag)
		system(NewMailExecute);
	if (Beep && BeepFlag)
		XBell(Disp, 0);

	return Result;
}

/****************************************************************************/
int NoOfNewMail(char *Mbox)
{
	FILE *MailFile = 0;
	char Buffer[30] = "";
	int NewMailn = 0;

	MailFile = fopen(Mbox, "r");

	if (MailFile == NULL)
		return 0;

	while (!feof(MailFile)) {
		fgets(Buffer, 29, MailFile);
		if (!strncmp(Buffer, "From ", 5))
			NewMailn++;
		else if (!strncmp(Buffer, "Status: RO", 10))
			NewMailn--;
	}
	fclose(MailFile);

	return NewMailn;
}

/****************************************************************************/
int IsNewMail(char *Mbox)
{
	FILE *MailFile = 0;
	char Buffer[30] = "";
	int WasStatus = 1;
	int NewMailn = 0;

	MailCounter = 0;
	MailFile = fopen(Mbox, "r");

	if (MailFile == NULL)
		return 0;

	while (!feof(MailFile)) {
		fgets(Buffer, 29, MailFile);
		if (!strncmp(Buffer, "From ", 5)) {
			MailCounter++;
			if (!WasStatus)
				NewMailn++;
			WasStatus = 0;
		} else if (!strncmp(Buffer, "Status: RO", 10))
			WasStatus = 1;
	}
	fclose(MailFile);

	return (NewMailn || !WasStatus);
}

/****************************************************************************/
int IsMail(char *Mbox)
{
	FILE *MailFile = 0;
	int Ret = 0;

	MailFile = fopen(Mbox, "r");
	if (MailFile == 0)
		Ret = 0;
	else {
		fgetc(MailFile);
		if (feof(MailFile))
			Ret = 0;
		else
			Ret = 1;

		fclose(MailFile);
	}

	return Ret;
}

/****************************************************************************/
int GetGStatus(void)
{
	int i;
	int j = 0;

	/* Get highest GStatus */
	for (i = 0; i < NumOfMailBoxes; i++)
		if (j < GStatus[i])
			j = GStatus[i];
	return j;
}

/****************************************************************************/
void GetXPM(int Shaped)
{
	/* Create default icons */
	if (Shaped) {
		/* Shaped */
		NoMail = (XpmIcon *) calloc(1, sizeof(XpmIcon));
		OldMail = (XpmIcon *) calloc(1, sizeof(XpmIcon));
		NewMail = (XpmIcon *) calloc(1, sizeof(XpmIcon));

		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 nomail_s,
						 &NoMail->pixmap,
						 &NoMail->mask,
						 &NoMail->attributes));
		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 newmail_s,
						 &NewMail->pixmap,
						 &NewMail->mask,
						 &NewMail->attributes));
		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 oldmail_s,
						 &OldMail->pixmap,
						 &OldMail->mask,
						 &OldMail->attributes));

		NoMail->next = (struct XpmIcon *) NoMail;
		OldMail->next = (struct XpmIcon *) OldMail;
		NewMail->next = (struct XpmIcon *) NewMail;

		/* Set startup-status to Nomail */
		Current = NoMail;
	} else {
		/* Normal */
		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 nomail,
						 &NoMail->pixmap,
						 &NoMail->mask,
						 &NoMail->attributes));
		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 newmail,
						 &NewMail->pixmap,
						 &NewMail->mask,
						 &NewMail->attributes));
		XPMError(XpmCreatePixmapFromData(Disp, Root,
						 oldmail,
						 &OldMail->pixmap,
						 &OldMail->mask,
						 &OldMail->attributes));
	}
}

/****************************************************************************/
void LoadXPMFile(XpmIcon * Icon, char *XpmFile)
{
	char *Home, *realfilename;

/* home dir ? */
	if (strncmp(XpmFile, "~/", 2) == 0) {
/* get home */
		Home = getenv("HOME");
		if (Home == NULL)
			Home = "./";
/* alloc it */
		realfilename = (char *) safemalloc(strlen(Home) + strlen(&XpmFile[2]) + 3);
/* put it */
		strcpy(realfilename, Home);
		strcat(realfilename, "/");
		strcat(realfilename, &XpmFile[2]);
	} else
		realfilename = XpmFile;


	if (XpmReadFileToPixmap(Disp, Root,
				realfilename,
				&Icon->pixmap,
				&Icon->mask,
				&Icon->attributes) != XpmSuccess) {
		fprintf(stderr, "asmail: could not load '%s'\n", realfilename);
		exit(1);
	}
	/* Check if mask is ok */
	if (Icon->mask == 0) {
		fprintf(stderr, "asmail: '%s' does not have a transparent color\n", realfilename);
		exit(1);
	}
}
/****************************************************************************/
void XPMError(int Code)
{
	switch (Code) {
	case 0:
		break;
	case 1:
	case -4:
		fprintf(stderr, "asmail: not enough free color cells\n");
		break;
	case -1:
	case -2:
		fprintf(stderr, "asmail: could not load xpm\n");
		break;
	case -3:
		fprintf(stderr, "asmail: not enough memory free\n");
		break;
	default:
		fprintf(stderr, "asmail: unknown xpm-error\n");
		break;
	}
	if (Code != 0)
		exit(1);
}

/****************************************************************************/
Pixel GetColor(char *ColorName)
{
	XColor Color;
	XWindowAttributes Attributes;

	XGetWindowAttributes(Disp, Root, &Attributes);
	Color.pixel = 0;

	if (!XParseColor(Disp, Attributes.colormap, ColorName, &Color))
		fprintf(stderr, "asmail: can't parse %s\n", ColorName);
	else if (!XAllocColor(Disp, Attributes.colormap, &Color))
		fprintf(stderr, "asmail: can't allocate %s\n", ColorName);

	return Color.pixel;
}				/* END OF FILE ************************************************************* */
