char cc1[] = "\0$VER: ClipWindow 1.0  August 22, 1993";
char cc2[] = "Jim Harvey, 18538 Inkster, Redford Mich, 48240";
/* An AppWindow that stuffs the clipboard from Project Icons.
   Text can be stored in either a text file associated with
   the Project icon, or directly in the icon ToolTypes.  A
   Project icon with the word RESET as the default tool will
   flush the clipboard.

   Requires the CBIO.C and CB.H ClipBoard IO library files from
   the ROM Kernal Reference Manual - Devices chapter 3.  These
   are available on Fish Disk 741 in the RKRM_Devices archive.

   Makefile for Manx 5.0D (with debug) is:

    ClipWindow: ClipWindow.o Cbio.o
     ln -g ClipWindow Cbio -lc

    ClipWindow.o: ClipWindow.c
     cc -wl -pl -bs ClipWindow.c

    Cbio.o: Cbio.c
     cc -wn -pl -bs Cbio.c

   Revisions: 1.0 initial release August 22, 1993
*/

#define BUFFSIZE 8192L		/* maxsize of clipboard */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <functions.h>
#include <exec/types.h>		/* Need this for the Amiga variable types  */
#include <workbench/workbench.h>/* This has DiskObject and AppWindow       */
#include <workbench/startup.h>	/* This has WBStartup and WBArg structs    */
#include <exec/libraries.h>	/* Need this to check library versions     */

#include <stdio.h>

#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
#include <clib/wb_protos.h>

/* includes for clipboard */

#include "exec/ports.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "devices/clipboard.h"
#include "cb.h"

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>

struct IntuitionBase *IntuitionBase;
struct WorkbenchBase *WorkbenchBase;
struct IconBase *IconBase;

struct MsgPort *myport;
struct AppWindow *appwin;
struct IntuiMessage *imsg;
struct AppMessage *appmsg;
struct WBArg *wbargs;

char *conname = "CON:200/30/500/100/ Clip Window /CLOSE";
FILE *conwin = NULL;		/* will be handle for the above window */
struct Screen *tstscr;		/* dummy for finding ptr to window */
struct Window *homewindow;	/* pointer to AppWindow opened */
struct MsgPort *myport = NULL;	/* message port for AppWindow */
struct DiskObject *dobject;
char **tooltypes = NULL;
ULONG id = 1, userdata = 0;

/* function prototypes */
void cleanexit (char *, LONG);
void openup ();
void cleanup (void);
void message (char *);
BOOL getToolTypes (struct WBArg *, char **);

LONG olddir = -1;		/* will remember if we changed directory */
extern int Enable_Abort;	/* MANX C Reference abort enable */

void
main (int argc, char **argv)
{
  ULONG winsig, appwinsig, signals;	/* Wait() signals */
  BOOL done = FALSE;
  int x, i;			/* gen purpose counters */
  char tempname[33];		/* holds a filename */
  char tempstring[] = "\n";	/* holds a dummy line to clipboard */
  struct IOClipReq *ior = NULL;	/* IO request for clipboard use */
  struct cbbuf *bigbuf = NULL;	/* holds contents of retrieved clipboard */
  char *newstuff = NULL;	/* holds contents of dropped icon tooltypes */
  char *stuffend = NULL;	/* point to position of next avail space in newstuff */
  char *deftool = NULL;		/* Default icon Tool */
  FILE *textfile;		/* for text file associated with Project icon */
  int inchar, laschar;		/* for reading associated text file */

  Enable_Abort = 0;		/* turn off CTRL-C */
  openup ();			/* gets things started */

InitializeClip:		/* target for a RESET */

  /* initalize clipboard zero by writing a short string */
  /* note: must write at least one byte */

  if ((ior = CBOpen (0l)) == NULL)
    cleanexit ("Can't open ClipBoard\n", RETURN_FAIL);

  if ((CBWriteFTXT (ior, tempstring)) == FALSE)
    cleanexit ("Can't write to ClipBoard\n", RETURN_FAIL);

  CBClose (ior);

  fprintf (conwin, " Drag Project icons here, tooltypes\n");
  fprintf (conwin, "      will be appended to ClipBoard\n");

  winsig = 1L << homewindow->UserPort->mp_SigBit;	/* for close gadget */
  appwinsig = 1L << myport->mp_SigBit;	/* for AppWindow */

  while (!done) {
    signals = Wait (winsig | appwinsig);	/* Wait for IDCMP and AppMessages */

    if (signals & winsig) {	/** Got an IDCMP message **/

      while (imsg = (struct IntuiMessage *) GetMsg (homewindow->UserPort)) {
	if (imsg->Class = CLOSEWINDOW)	/* check for close button */
	  done = TRUE;
	ReplyMsg ((struct Message *) imsg);	/* spit it back */
      }
    }
    if (signals & appwinsig) {	/** Got an AppMessage **/

      if ((stuffend = newstuff =
	   AllocMem (BUFFSIZE, MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
	cleanexit ("Can't allocate memory for buffer\n", RETURN_FAIL);

      /* read entire clipboard into struct cbbuf buffer */
      if ((ior = CBOpen (0l)) == NULL)
	cleanexit ("Can't open ClipBoard\n", RETURN_FAIL);

      if (CBQueryFTXT (ior)) {	/* Look for FTXT */
	bigbuf = CBReadCHRS (ior);	/* Obtain a copy of the contents */
	CBReadDone (ior);	/* must read to EOF */
	CBClose (ior);
      }
      else {
	CBClose (ior);
	cleanexit ("ClipBoard is Empty!\n", RETURN_FAIL);
      }

      /* copy the contents to temp buffer */
      strcpy (newstuff, (char *) bigbuf->mem);

      /* if first time, point stuffend to 1st data byte, */
      /*if > first point to byte following the string */
      x = strlen (newstuff);
      stuffend += (x > 1) ? x : x - 1;

      /* read through all messages (may be more than one if a multiple select) */
      while (appmsg = (struct AppMessage *) GetMsg (myport)) {

	/* get information for this icon */
	for (x = 0, wbargs = appmsg->am_ArgList;
	     x < appmsg->am_NumArgs;
	     x++, wbargs++) {

	  if (!(*wbargs->wa_Name)) {
	    message (" Sorry, must be a Project Icon!\n");
	    break;
	  }

	  strcpy (tempname, wbargs->wa_Name);	/* copy name of icon */

	  /* CD to directory of this icon */
	  olddir = -1;		/* will remember if CD was necessary */
	  if ((wbargs->wa_Lock) && (*wbargs->wa_Name))
	    olddir = CurrentDir (wbargs->wa_Lock);	/* remember old directory */

	  if (getToolTypes (wbargs, &deftool)) {	/* now parse tooltypes */

	    if (dobject->do_Type != WBPROJECT) {
	      message (" Sorry, must be a Project Icon!\n");
	      break;		/* proceed to process next icon */
	    }

	    /* see if user wants to flush clipboard */
	    if (!strcmp (deftool, "RESET") || !strcmp (deftool, "reset")) {
	      fprintf (conwin,
		       "\f      %c3;7m%s%c0m\n", 0x9b, "* Resetting Clipboard *", 0x9b);
	      FreeDiskObject (dobject);	/* Free the diskobject we got */

	      /* Clear away any messages that arrived at the last moment */
	      while (appmsg = (struct AppMessage *) GetMsg (myport))
		ReplyMsg ((struct Message *) appmsg);	/* spit it back */
	      while (imsg = (struct IntuiMessage *) GetMsg (homewindow->UserPort))
		ReplyMsg ((struct Message *) imsg);	/* spit it back */

	      if (bigbuf)
		CBFreeBuf (bigbuf);	/* discard clip read buffer */
	      if (newstuff)
		FreeMem (newstuff, BUFFSIZE);	/* discard clip write buffer */
	      goto InitializeClip;	/* start over */
	    }

	    /* now check for a text file associated with the Project icon */
	    if ((textfile = fopen (tempname, "r")) != NULL) {

	      laschar = 0;
	      fprintf (conwin, "%c1;7m%s:%c0m", 0x9b, tempname, 0x9b);
	      /* associated textfile was found, append contents to temp buffer */
	      while ((inchar = fgetc (textfile)) != EOF) {
		*stuffend++ = (char) inchar;
		if (laschar == 0x0a)
		  fprintf (conwin, "%c1;7m%s:%c0m", 0x9b, tempname, 0x9b);
		fputc (inchar, conwin);	/* echo */
		laschar = inchar;	/* remember last real character */
	      }
	      if (laschar != 0x0a) {
		*stuffend++ = '\n';	/* ensure last line has line feed */
		fputc (0x0a, conwin);	/* echo */
	      }
	      fclose (textfile);
	    }

	    /* no associated text file found, get info from tooltypes */
	    else {
	      for (i = 0; tooltypes[i]; i++) {	/* exit on NULL tooltype */
		fprintf (conwin, "%c1m%s:%c0m%s\n", 0x9b, tempname, 0x9b, tooltypes[i]);
		strcpy (stuffend, tooltypes[i]);	/* append tooltype to buffer */
		stuffend += strlen (tooltypes[i]);	/* pos to end string */
		*stuffend++ = '\n';	/* append a line feed */
		if ((int) (stuffend - newstuff) >= BUFFSIZE)	/* check memory */
		  cleanexit ("Buffer Memory Overflow\n", RETURN_FAIL);
	      }
	    }
	  }
	  FreeDiskObject (dobject);	/* Free the diskobject we got */

	  if (olddir != -1)
	    CurrentDir (olddir);/* cd back home if necessary */
	}
	ReplyMsg ((struct Message *) appmsg);	/* spit message back */
      }

      /** write entire appended buffer to clipboard **/
      if ((ior = CBOpen (0l)) == NULL)
	cleanexit ("Can't open ClipBoard\n", RETURN_FAIL);

      if (!CBWriteFTXT (ior, newstuff))
	cleanexit ("ClipBoard rewrite error!\n", RETURN_FAIL);


      /* Free buffer allocated by CBReadCHRS() */
      if (bigbuf)
	CBFreeBuf (bigbuf);
      /* Free buffer used for incoming tooltypes */
      if (newstuff)
	FreeMem (newstuff, BUFFSIZE);
    }
  }				/* done */

  /* Clear away any messages that arrived at the last moment */
  while (appmsg = (struct AppMessage *) GetMsg (myport))
    ReplyMsg ((struct Message *) appmsg);
  cleanup ();
}

void
openup ()
{
  if ((IntuitionBase = (struct IntuitionBase *)
       OpenLibrary ((STRPTR) "intuition.library", 0l)) == NULL)
    cleanexit ("Can't open Intuition\n", RETURN_FAIL);

  if ((WorkbenchBase = (struct WorkbenchBase *)
       OpenLibrary ((STRPTR) "workbench.library", 37)) == NULL)
    cleanexit ("Can't open Workbench.library\n", RETURN_FAIL);

  if ((IconBase = (struct IconBase *)
       OpenLibrary ((STRPTR) "icon.library", 37)) == NULL)
    cleanexit ("Can't open Icon.library\n", RETURN_FAIL);

  if ((conwin = fopen (conname, "r+")) == NULL)
    cleanexit ("Can't open output window\n", RETURN_FAIL);

  if ((tstscr =			/* get copy of wkbnch screen */
       AllocMem (sizeof (struct Screen), MEMF_FAST)) == NULL)
      cleanexit ("Memory too low for screen\n", RETURN_FAIL);

  if ((GetScreenData
     (tstscr, sizeof (struct Screen), (ULONG) WBENCHSCREEN, NULL)) == FALSE)
      cleanexit ("Can't get WorkBench screen data\n", RETURN_FAIL);
  homewindow = tstscr->FirstWindow;

  if (strcmp ((char *) homewindow->Title, " Clip Window ") != 0)
    cleanexit ("Wrong Window found\n", RETURN_FAIL);

  /* this creates a message port automatically */
  ModifyIDCMP (homewindow, IDCMP_CLOSEWINDOW);

  /* The CreateMsgPort() function is in Exec version 37 and later only */
  if ((myport = CreateMsgPort ()) == NULL)
    cleanexit ("Can't get Message Port\n", RETURN_FAIL);

  if ((appwin = AddAppWindowA (id, userdata, homewindow, myport, NULL)) == NULL)
    cleanexit ("Appwindow atachment failed\n", RETURN_FAIL);
}

void
cleanexit (char *s, LONG n)
{
  if (*s)
    message (s);
  Delay (100l);
  cleanup ();
  exit (n);
}

void
cleanup ()
{
  if (olddir != -1)
    CurrentDir (olddir);	/* cd back home */
  if (myport)
    DeleteMsgPort (myport);
  if (conwin)
    RemoveAppWindow (appwin);
  if (conwin)
    fclose (conwin);
  if (tstscr)
    FreeMem (tstscr, sizeof (struct Screen));
  if (IconBase)
    CloseLibrary ((struct Library *) IconBase);
  if (WorkbenchBase)
    CloseLibrary ((struct Library *) WorkbenchBase);
  if (IntuitionBase)
    CloseLibrary ((struct Library *) IntuitionBase);
}

void
message (char *s)
{
  if (conwin)
    fprintf (conwin, s, strlen (s));
  else
    printf (s, strlen (s));
}


/*  Extract all ToolTypes */
BOOL
getToolTypes (struct WBArg *wbarg, char **defaulttool)
{
  BOOL success = FALSE;

  dobject = GetDiskObject ((UBYTE *) (wbarg->wa_Name));
  if ((*wbarg->wa_Name) && dobject) {
    tooltypes = (char **) dobject->do_ToolTypes;

    *defaulttool = dobject->do_DefaultTool;

    success = TRUE;
  }
  else if (!(*wbarg->wa_Name))
    fprintf (conwin, "  Must be a disk or drawer icon\n");
  else
    fprintf (conwin, "  Can't find any DiskObject (icon) for this WBArg\n");
  return (success);
}
