/* Sabot */

#include <exec/types.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/notify.h>
#include <dos/dostags.h>
#include <libraries/dos.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>

#include <proto/icon.h>
#include <proto/exec.h>
#include <proto/wb.h>
#include <proto/dos.h>
#ifdef TIMER
#include <proto/timer.h>
#include <time.h>
#endif

#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <wb2cli.h>

#define BIGSTRING 255
#define SMALLSTRING 128

enum args
	{
	MAIL,
	NOMAIL,
	OLDMAIL,
	MAILBOX,
	ICONNAME,
	XPOS,
	YPOS,
	CLICKCOMMAND,
	CLICKSTACK,
	MAILCOMMAND,
	MAILSTACK,
	DROPCOMMAND,
	DROPSTACK,
	BEEPLOTS,
	COUNTDELETE,
#ifdef TIMER
	TIME,
#endif
	MAILRDY
	};



void __regargs __chkabort(void) {}
int __oslibversion=37;
long __stack = 20000;
#ifndef TIMER
static const char VersionID[]="\0$VER:Sabot 1.8 "__AMIGADATE__;
#endif
#ifdef TIMER
static const char VersionID[]="\0$VER:Sabot-Timer 1.8 "__AMIGADATE__;
#endif

extern struct DosLibrary *DOSBase;
extern struct WBStartup *_WBenchMsg;
struct Library *IconBase;
struct Library *WorkbenchBase;

char *havemail;
char *nomail;
char *oldmail;
char *watch;
char *iconname;
char *clickcomname;
char *mailcomname;
char *dropcomname;
char *dropname;
char *droptemp;

BOOL mailrdy=FALSE;
ULONG xpos;
ULONG ypos;

BOOL beeplots=FALSE;
ULONG clickcomstack=20000;
ULONG mailcomstack=20000;
ULONG dropcomstack=20000;

LONG mbsize=0;
LONG prevsize=0;

struct AppIcon *appicon=NULL;
struct DiskObject *image=NULL;
struct MsgPort *myport=NULL;

struct RDArgs   *RDA;

enum active_args
	{
	NONE,
	OLD,
	NEW
	};

USHORT active=NONE;
BOOL beeped=FALSE;
BOOL countdelete=FALSE;

#ifdef TIMER
int setuptime( void );
int closetime(void );
void timereq( void );
struct MsgPort *timer_mp;
struct timerequest *timerio;
extern struct Library *TimerBase;
int timecheck=5;
#endif

BOOL addicon(struct MsgPort *, struct DiskObject *);
void killicon( void );
BOOL getimage( char * );
void killimage( void );
void changeicon( void );
void doinfo( void );
void compare( void );
BOOL parse( int );
void FreeParameters( LONG * );
void docommand(char *, int);
BOOL makevars( void );
void freevars( void );

int main (int argc, char **argv)
{
	struct AppMessage *appmsg;

#ifndef TIMER
	struct NotifyRequest *note;
#endif

	struct MsgPort *mailport=NULL;
	ULONG mailportsig=NULL;

	BOOL going=TRUE;
	ULONG mysig;
	LONG signum;
	LONG count;
	ULONG myportsig;

	if ( !makevars() )
	{
		freevars();
		return(20);
	}

	WB2CLI( _WBenchMsg , __stack , DOSBase); /* Creates Path for System()'ed commands */

	if ( !parse(argc) )
	{
		freevars();
		return(5);
	}

	if (mailrdy)
	{
		if ( mailport=CreatePort("T:MailRdy",0) )
		{
			mailportsig = 1L << mailport->mp_SigBit;
		}
	}

	if ( (IconBase=OpenLibrary("icon.library",37)) && (WorkbenchBase=OpenLibrary("workbench.library",37)) )
	{
		if ( getimage(nomail) )
		{
			if ( myport=CreatePort(NULL,0) )
			{
				myportsig = 1L << myport->mp_SigBit;

				if ( addicon(myport,image) )
				{
#ifndef TIMER
					if ( note=AllocVec(sizeof(struct NotifyRequest),MEMF_CLEAR) )
					{
						if ( (signum=AllocSignal(-1L)) != -1)
						{
							note->nr_Name=watch;
							note->nr_Flags=NRF_SEND_SIGNAL;
							note->nr_stuff.nr_Signal.nr_Task= (struct Task *)FindTask(NULL);
							note->nr_stuff.nr_Signal.nr_SignalNum=signum;

							if ( (StartNotify(note))==DOSTRUE )
							{
								doinfo();
								if ( mbsize )		/* Show appropriate icon on startup */
								{
									active=OLD;
            						changeicon();
								}
#endif
#ifdef TIMER
				if ( setuptime() )
				{
					signum = timer_mp->mp_SigBit;
					timereq();
					doinfo();
					prevsize=mbsize;
					compare();
#endif

								while ( going )
								{
									mysig = Wait( myportsig | SIGBREAKF_CTRL_C | (1L << signum) | mailportsig );

									if ( mysig & SIGBREAKF_CTRL_C )
									{
										going=FALSE;
									}

									if (mysig & mailportsig)
									{
										active=OLD;
										changeicon();
									}

									if (mysig & (1L << signum))
									{
										doinfo();
										compare();
#ifdef TIMER
										timereq();
#endif
									}

									if ( mysig & myportsig)
									{
#ifdef TIMER
										prevsize=mbsize;
#endif
										if ( mailrdy && (active!=NONE) )
										{
											active=NONE;
											changeicon();
										}

										while( appmsg=(struct AppMessage *)GetMsg(myport) )
										{
											if ( appmsg->am_NumArgs==0L )
											{
												if ( clickcomname )
												{
													docommand(clickcomname,clickcomstack);
												}
												prevsize=mbsize;
											}
											else if ( appmsg->am_NumArgs > 0L )
											{
												if ( dropcomname )
												{
                                            		count = appmsg->am_NumArgs;

													while ( count )
													{
														--count;

														if (NameFromLock(appmsg->am_ArgList[count].wa_Lock,dropname,BIGSTRING))
														{
															if(AddPart(dropname,appmsg->am_ArgList[count].wa_Name,BIGSTRING))
															{
																sprintf(droptemp,"%s \"%s\"",dropcomname,dropname);
                                            					docommand(droptemp,dropcomstack);
															}
														}

														strcpy(droptemp,"");
														strcpy(dropname,"");
													}
												}
											}
											ReplyMsg( (struct Message *)appmsg );
										}
									}
#ifdef TIMER
				}
			closetime();
#endif
#ifndef TIMER
								}
							}
							FreeSignal(signum);
						}
						EndNotify(note);
						FreeVec(note);
#endif
					}
				}
				killicon();
			}

			while(appmsg=(struct AppMessage *)GetMsg(myport))
			{
				ReplyMsg((struct Message *)appmsg);
			}

			DeletePort(myport);
		}
		killimage();
	}

	if (mailport)
	{
		DeletePort(mailport);
	}

	CloseLibrary(WorkbenchBase);
	CloseLibrary(IconBase);

	freevars();

	return(0);
}

BOOL addicon(struct MsgPort *port, struct DiskObject *image)
{
	if ( appicon=AddAppIconA(0L,0L,iconname,port,NULL,image,NULL) )
	{
		return(TRUE);
	}

	return(FALSE);
}

void killicon( void )
{
	RemoveAppIcon(appicon);
}

BOOL getimage( char *name )
{
	if ( image=GetDiskObject(name) )
	{
		image->do_Type=NULL;
		image->do_CurrentX=xpos;
		image->do_CurrentY=ypos;
		return(TRUE);
	}

	return(FALSE);
}

void killimage( void )
{
	if (image)
	{
		FreeDiskObject(image);
	}
}

void changeicon( void )
{
	killicon();
	killimage();

	switch (active)
	{
		case OLD:
			getimage(oldmail);
			break;

		case NEW:
			getimage(havemail);
			break;

		case NONE:
			getimage(nomail);
			break;
	}

	addicon(myport,image);
}

void doinfo( void )
{
	BPTR lock;
	struct FileInfoBlock *fib;

	if ( lock=Lock(watch,ACCESS_READ) )
	{
		if ( fib=(struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_END) )
		{
			Examine(lock,fib);

			mbsize=fib->fib_Size;

			FreeDosObject(DOS_FIB,fib);
		}
	}
	else
	{
		if ( countdelete ) mbsize=0;
	}

	UnLock(lock);
}

void compare( void )
{
	if (mbsize)
	{
		if ( mbsize > (prevsize+130) ) /* Allow 130 bytes of breathing room */
		{
			if (active!=NEW)
			{
				active=NEW;
				changeicon();
			}

			if ( mailcomname && ( !beeped || beeplots) )
			{
				docommand(mailcomname,mailcomstack);
				beeped=TRUE;
			}
		}
		else
		{
#ifdef TIMER
			if ( active != OLD )
			{
#endif
			active=OLD;
			changeicon();
			beeped=FALSE;
#ifdef TIMER
			}
#endif
		}
	}
	else
	{
#ifdef TIMER
		if ( active != NONE )
		{
#endif
		active=NONE;
		changeicon();
		beeped=FALSE;
#ifdef TIMER
		}
#endif
	}

#ifndef TIMER
	prevsize=mbsize;
#endif

}

BOOL parse(int argc)
{
	char	*OriginalTemplate = "Mail/A,NoMail/A,OldMail/A,"
								"MB=MailBox/A,IN=IconName/K,"
								"XPos/K/N,YPos/K/N,CC=ClickCommand/K,"
								"CS=ClickStack/K/N,MC=MailCommand/K,"
								"MS=MailStack/K/N,DC=DropCommand/K,"
								"DS=DropStack/K/N,BeepLots/S,CountDelete/S,"
#ifdef TIMER
								"Time/K/N,"
#endif
								"MailRdy/S";


	LONG	*ArgumentArray;		/* array for storing arguments retrieved by */

	char	**ToolArrayIndex,	/* workbench tooltypes array */
			*ToolStringIndex,	/* index into string of concatenated workbench tooltypes */
			*Template;			/* readargs template - varies slightly for WB or CLI */

	struct DiskObject	*DiskObject;	/* pointer to diskobject associated with program icon */
	WORD	ArgCount = 1;		/* number of arguments in template */


	RDA = AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
	RDA->RDA_ExtHelp = NULL;

	Template = AllocVec(strlen(OriginalTemplate)+16,MEMF_CLEAR);

	for (	ToolStringIndex = OriginalTemplate;
			ToolStringIndex = strchr(ToolStringIndex,',');
			ToolStringIndex++, ArgCount++);

	ArgumentArray = AllocVec((ArgCount+1)*4,MEMF_CLEAR);

	if (argc==0)
	{
		if (IconBase = OpenLibrary("icon.library", 36L ) )
		{

			CurrentDir(_WBenchMsg->sm_ArgList->wa_Lock);

			if (DiskObject = GetDiskObject(_WBenchMsg->sm_ArgList->wa_Name))
			{
				for (	ToolArrayIndex = DiskObject->do_ToolTypes;
						*ToolArrayIndex;
						ToolArrayIndex++)
				{
					RDA->RDA_Source.CS_Length += (strlen(*ToolArrayIndex)+1);
				}

				if (RDA->RDA_Source.CS_Length)
				{
					RDA->RDA_Source.CS_Buffer = AllocVec(RDA->RDA_Source.CS_Length+1,MEMF_CLEAR);
					ToolStringIndex = RDA->RDA_Source.CS_Buffer;

					for (	ToolArrayIndex = DiskObject->do_ToolTypes;
							*ToolArrayIndex;
							ToolArrayIndex++)
					{
						ToolStringIndex = stpcpy(stpcpy(ToolStringIndex,*ToolArrayIndex)," ");
					}

					*(ToolStringIndex-1) = '\n';
					FreeDiskObject(DiskObject);
				}
			}

			stpcpy(stpcpy(Template,OriginalTemplate),",ThrowAway/M");

			CloseLibrary(IconBase);
		}
	}
	else
	{
		strcpy(Template,OriginalTemplate);
	}

	RDA = ReadArgs(Template,ArgumentArray,RDA);

	FreeVec(Template);

	if (RDA)
	{
		strcpy(havemail,(char *)ArgumentArray[MAIL]);
		strcpy(nomail,(char *)ArgumentArray[NOMAIL]);
		strcpy(oldmail,(char *)ArgumentArray[OLDMAIL]);
		strcpy(watch,(char *)ArgumentArray[MAILBOX]);

		if ( ArgumentArray[ICONNAME] )
		{
			strcpy(iconname,(char *)ArgumentArray[ICONNAME]);
		}
		else
		{
			strcpy(iconname,"MailBox");
		}

		if ( ArgumentArray[XPOS] )
		{
			xpos=*(int *)ArgumentArray[XPOS];
		}
		else
		{
			xpos=NO_ICON_POSITION;
		}

		if ( ArgumentArray[YPOS] )
		{
			ypos=*(int *)ArgumentArray[YPOS];
		}
		else
		{
			ypos=NO_ICON_POSITION;
		}

		if ( ArgumentArray[CLICKCOMMAND] )
		{
			strcpy(clickcomname,(char *)ArgumentArray[CLICKCOMMAND]);
		}

		if ( ArgumentArray[CLICKSTACK] )
		{
			clickcomstack=*(int *)ArgumentArray[CLICKSTACK];
		}

		if ( ArgumentArray[MAILCOMMAND] )
		{
			strcpy(mailcomname,(char *)ArgumentArray[MAILCOMMAND]);
		}

		if ( ArgumentArray[MAILSTACK] )
		{
			mailcomstack=*(int *)ArgumentArray[MAILSTACK];
		}

		if ( ArgumentArray[DROPCOMMAND] )
		{
			strcpy(dropcomname,(char *)ArgumentArray[DROPCOMMAND]);
		}

		if ( ArgumentArray[DROPSTACK] )
		{
			dropcomstack=*(int *)ArgumentArray[DROPSTACK];
		}

		if ( ArgumentArray[BEEPLOTS] )
		{
			beeplots=TRUE;
		}

		if ( ArgumentArray[COUNTDELETE] )
		{
			countdelete=TRUE;
		}

#ifdef TIMER
		if ( ArgumentArray[TIME] )
		{
			timecheck=*(int *)ArgumentArray[TIME];
		}
#endif

		if ( ArgumentArray[MAILRDY] )
		{
			mailrdy=TRUE;
		}

		FreeParameters(ArgumentArray);

		return(TRUE);
	}
	else
	{
		FreeParameters(ArgumentArray);

		return(FALSE);
	}
}

void FreeParameters(LONG *ArgumentArray)
{
	if (RDA)
	{
		if ((RDA->RDA_Source.CS_Length) && (RDA->RDA_Source.CS_Buffer))
		{
			FreeVec(RDA->RDA_Source.CS_Buffer);
		}

		FreeArgs(RDA);
		FreeDosObject(DOS_RDARGS,RDA);
	}
	else
	{
		PrintFault(IoErr(), NULL);
	}

	if (ArgumentArray)
	{
		FreeVec(ArgumentArray);
	}
}

void docommand(char *command, int stack)
{
    BPTR ofh,ifh;

	if ( ofh=Open("NIL:",MODE_READWRITE) )
	{
		if ( ifh=Open("NIL:",MODE_READWRITE) )
		{
			if ( SystemTags(	command,
						SYS_Input, ifh,
						SYS_Output, ofh,
						SYS_UserShell, DOSTRUE,
						SYS_Asynch, DOSTRUE,
						NP_StackSize, stack,
						NP_CopyVars, DOSTRUE,
						NP_Cli, DOSTRUE,
						TAG_END) != -1 )
			{
				return;
			}

			Close(ifh);
		}
		Close(ofh);
	}
}

BOOL makevars(void)
{
	if ( havemail=AllocVec(11*BIGSTRING,MEMF_CLEAR) )
	{
		nomail=havemail+BIGSTRING;
		oldmail=nomail+BIGSTRING;
		watch=oldmail+BIGSTRING;
		iconname=watch+BIGSTRING;
		clickcomname=iconname+BIGSTRING;
		mailcomname=clickcomname+BIGSTRING;
		dropcomname=mailcomname+BIGSTRING;
		dropname=dropcomname+BIGSTRING;
		droptemp=dropname+(2*BIGSTRING);
		return(TRUE);
	}
	return(FALSE);
}

void freevars(void)
{
	if (havemail) FreeVec(havemail);
}

#ifdef TIMER

int setuptime( void )
{
	timer_mp = CreateMsgPort();

	if (timer_mp == NULL )
	{
		return(0);
	}

	timerio=(struct timerequest *)CreateExtIO(timer_mp,sizeof(struct timerequest));

	if ( OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timerio,0) )
	{
		return(0);
	}
	return(1);
}

int closetime( void )
{
	if (timer_mp)
	{
		if (timerio)
		{
			AbortIO( (struct IORequest *)timerio);
			WaitIO( (struct IORequest *)timerio);
			CloseDevice( (struct IORequest *)timerio );
			DeleteExtIO( (struct IORequest *)timerio);
		}

		DeleteMsgPort(timer_mp);
	}

	timer_mp=NULL;
	timerio=NULL;

	return(0);
}

void timereq(void)
{
	timerio->tr_node.io_Command	= TR_ADDREQUEST;
	timerio->tr_time.tv_secs	= (60*timecheck);
	timerio->tr_time.tv_micro	= 0;
	SendIO( (struct IORequest *)timerio );
}

#endif

