/* AppCon Main Source
**
** Done by Stephan Fuhrmann
**
*/

#define EXEC_MINIMUM 36
#define MY_ID 3111973

#include <AppCon.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <exec/tasks.h>
#include <devices/console.h>
#include <devices/conunit.h>
#include <devices/keymap.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/wb.h>
#include <proto/console.h>
#include <proto/keymap.h>

const char vt[]=VERSTAG;

struct Process *AppConTask;
struct CommandLineInterface *AppCLI;
struct Window *AppConWindow;

extern struct ExecBase *SysBase;
extern struct IntuitionBase *IntuitionBase;
extern struct Library *WorkbenchBase;
extern struct Library *KeymapBase;
extern struct Library *DosBase;
struct Library *ConsoleDevice;

struct MsgPort *appport;
struct MsgPort *ioreply;
struct IOStdReq *iorequest;

struct MsgPort *con;

struct StandardPacket packet;
struct InfoData id;

struct AppWindow *AppWindow;

struct AppMessage *AppMessage;

struct InputEvent *InputEvent;

ULONG WaitSignals=SIGBREAKF_CTRL_C;
ULONG ReceivedSignals;

long __OSlibversion=EXEC_MINIMUM;

char filename[FILENAME_MAX];
char dirname[FILENAME_MAX];
char pathname[FILENAME_MAX*2];

char AppConName[]="AppCon";
char Couldnt[]="Couldn't %s %s!\n";

struct InputEvent *BrewInputevent(char *ASCII);
void FreeIEs (struct InputEvent *firstie);

int main(int argc,char *argv[])
{
	fprintf (stderr,VSTRING);
	fprintf (stderr,"PUBLIC DOMAIN written 1993 by Stephan Fuhrmann\n");

	if (argc==0 || (argc==2 && !strcmp("?",argv[1])))
	{
		fprintf (stderr,"Usage: AppCon\n");
		fprintf (stderr,"\tAppCon is a tool that enables you to drop icons on CON:-windows.\n\tThe names of the icons are displayed in the CON:-window exactly\n\tas if you typed them on the keyboard!\n");
		return (0);
	}
	
	if ((ioreply=CreateMsgPort()) && (appport=CreateMsgPort()))
	{

		appport->mp_Node.ln_Name=AppConName;

		WaitSignals |= 1 << (ioreply->mp_SigBit);
		WaitSignals |= 1 << (appport->mp_SigBit);

		if (iorequest=CreateIORequest(ioreply,sizeof(struct IOStdReq)))
		{
			AppConTask=(struct Process *) FindTask(NULL);

			if (!OpenDevice ("console.device",-1,(struct IORequest *)iorequest,0))
			{
				ConsoleDevice=(struct Library *)iorequest->io_Device;

				if (AppConTask->pr_Task.tc_Node.ln_Type == NT_PROCESS)
				{
					con=AppConTask->pr_ConsoleTask;
					packet.sp_Msg.mn_Node.ln_Name=(char *)&(packet.sp_Pkt);
					packet.sp_Pkt.dp_Link=&(packet.sp_Msg);
					packet.sp_Pkt.dp_Port=ioreply;
					packet.sp_Pkt.dp_Type=ACTION_DISK_INFO;
					packet.sp_Pkt.dp_Arg1=((ULONG) &id) >> 2;
					PutMsg (con,(struct Message *)&packet);
					WaitPort (ioreply);

					AppConWindow=(struct Window *)id.id_VolumeNode;

					if (AppWindow=AddAppWindowA (MY_ID,0,AppConWindow,appport,0))
					{
						ReceivedSignals=0;

						while (!(ReceivedSignals & SIGBREAKF_CTRL_C))
						{
							ReceivedSignals=Wait (WaitSignals);

							if (ReceivedSignals & (1 << (appport->mp_SigBit)))
							{
								while (AppMessage = (struct AppMessage *)GetMsg (appport))
								{
									register long cnt,max;
									register struct WBArg *curarg;

									if (AppMessage->am_Type != MTYPE_APPWINDOW)
										continue;

									ActivateWindow (AppConWindow);

									max=AppMessage->am_NumArgs;
									curarg=AppMessage->am_ArgList;

									if (max==0)
										continue;

									for (cnt=0;cnt<max;cnt++)
									{
										if ((curarg+cnt)->wa_Lock)
											NameFromLock((curarg+cnt)->wa_Lock,dirname,FILENAME_MAX);

										strcpy (pathname,dirname);

										if ((curarg+cnt)->wa_Name)
											AddPart(pathname,(curarg+cnt)->wa_Name,FILENAME_MAX*2);

										if (cnt)
										{
											if (InputEvent=BrewInputevent (" "))
											{
												CDInputHandler (InputEvent,ConsoleDevice);
												FreeIEs (InputEvent);
											}
										}

										if (InputEvent=BrewInputevent (pathname))
										{
											CDInputHandler (InputEvent,ConsoleDevice);
											FreeIEs (InputEvent);
										}
									}
									ReplyMsg((struct Message *)AppMessage);
								}
							}
						}

						RemoveAppWindow (AppWindow);
					}
					else
						fprintf (stderr,Couldnt,"add","AppWindow");
				}
				else
					fprintf (stderr,Couldnt,"get","process-structure");

				CloseDevice ((struct IORequest *)iorequest);
			}
			else
				fprintf (stderr,Couldnt,"open","console.device");
				
			DeleteIORequest (iorequest);
		}
		else
			fprintf (stderr,Couldnt,"create","IORequest");
			
		DeleteMsgPort (ioreply);
		DeleteMsgPort (appport);
	}
	else
		fprintf (stderr,Couldnt,"create","msgport");
		
	return (0);
}

void FreeIEs (struct InputEvent *firstie)
{
	register struct InputEvent *nextie;

	while (firstie)
	{
		nextie=firstie->ie_NextEvent;
		free (firstie);
		firstie=nextie;
	}
}

struct InputEvent *BrewInputevent(char *ASCII)
{
	struct InputEvent *thisie,*oldie,*grandpa,*firstie;
	register long cnt;
	long junksize;
	WORD *junkbuf;
	long rawsize;

	firstie=0;
	thisie=0;
	oldie=0;

	junksize=strlen(ASCII)*3;

	junkbuf=malloc(junksize*sizeof(WORD));

	rawsize=MapANSI (ASCII,strlen(ASCII),(STRPTR)junkbuf,junksize,0);

	switch (rawsize)
	{
		case 0:return (0);
		case -1:return (0);
		case -2:return (0);
	}

	for (cnt=0;cnt<rawsize;cnt++)
	{
		grandpa=oldie;
		oldie=thisie;

		thisie=calloc (1,sizeof (struct InputEvent));

		if (!thisie)
		{
			FreeIEs(firstie);
			return (0);
		}
		
		if (oldie)
			oldie->ie_NextEvent=thisie;
		else
			firstie=thisie;

		/* PARANOIA! */
		thisie->ie_NextEvent=0;

		thisie->ie_Class=IECLASS_RAWKEY;
		thisie->ie_SubClass=0;
		thisie->ie_Code=(*(junkbuf+cnt)>>8) & 255;
		thisie->ie_Qualifier=*(junkbuf+cnt) & 255;
		CurrentTime (&(thisie->ie_TimeStamp.tv_secs),&(thisie->ie_TimeStamp.tv_micro));

		if (oldie)
		{
			thisie->ie_position.ie_dead.ie_prev1DownCode=oldie->ie_Code;
			thisie->ie_position.ie_dead.ie_prev1DownQual=oldie->ie_Qualifier;
		}

		if (grandpa)
		{
			thisie->ie_position.ie_dead.ie_prev2DownCode=grandpa->ie_Code;
			thisie->ie_position.ie_dead.ie_prev2DownQual=grandpa->ie_Qualifier;
		}
	}
	
	return (firstie);
}
