
/*************************************************************************/
/*			     WBLink V1.10				 */
/*									 */
/* WBLink is Copyright 1991 by Dave Schreiber.	All Rights Reserved	 */
/*									 */
/* WBLink puts an AppIcon on the Workbench.  When a file is dropped onto */
/* the icon, a link to that file is generated.				 */
/*************************************************************************/


#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <dos/dos.h>

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

#include "WBLink.h"

/* Function prototypes*/
void _main();
BOOL GetLinkFilename(char *src,char *dest);
void MakeName(char *src,char *dest,int c);
void FindOrig(char *src,char *dest);
void cleanup(UWORD err);
void parseArgs(void);

#pragma libcall UtilityBase Strnicmp a8 09803

/* Global variables */
struct Library *WorkbenchBase=NULL;
struct Library *IconBase=NULL;
struct Library *IntuitionBase=NULL;
struct Library *UtilityBase=NULL;
struct Port *port=NULL;
struct AppIcon *appIcon=NULL;
extern struct WBStartup *WBenchMsg;


/*The version string*/
char *version="$VER: WBLink V1.10 (8.2.92)";

void _main()
{
   struct AppMessage *mesg;
   char dest[256],src[256],temp[256];
   BPTR oldDir,fileLock;
   struct DiskObject *diskObj;

   BOOL abort=FALSE;
   BOOL status;
   BOOL isDir=FALSE;
   UBYTE c;

   /* Open libraries */
   WorkbenchBase=OpenLibrary("workbench.library",37L);
   if(WorkbenchBase==NULL)
      cleanup(50);

   IconBase=OpenLibrary("icon.library",37L);
   if(IconBase==NULL)
      cleanup(75);

   IntuitionBase=OpenLibrary("intuition.library",37L);
   if(IntuitionBase==NULL)
      cleanup(85);

   UtilityBase=OpenLibrary("utility.library",37L);
   if(UtilityBase==NULL)
      cleanup(95);

   /* Get any user arguments */
   parseArgs();

   /* Create a port for Workbench to use to communicate with us */
   port=CreatePort("",0);
   if(port==NULL)
      cleanup(100);

   /* Create the application icon */
   appIcon = AddAppIcon(1,1,"WBLink",port,NULL,&iconObj,TAG_DONE,NULL);

   if(appIcon==NULL)
      cleanup(300);

   /* Loop until the user asks to quit */
   while(!abort)
   {
      /* Wait for a message from Workbench */
      WaitPort(port);

      /* Get the message */
      mesg=(struct AppMessage *)GetMsg(port);

      /* If am_NumArgs != 0, it means one or more icons were dropped on */
      /* the AppIcon */
      if(mesg->am_NumArgs!=0)
      {
	 /* Loop for each file */
	 for(c=0;c<mesg->am_NumArgs;c++)
	 {
	    /* Check to see if this is a drawer */
	    if(mesg->am_ArgList[c].wa_Name[0]==0 &&
		  mesg->am_ArgList[c].wa_Lock != NULL)
	    {
	       isDir=TRUE;

	       /* If it is a drawer, we didn't get the name from Workbench*/
	       /* So we need to get the name from the lock instead*/
	       if(!NameFromLock(mesg->am_ArgList[c].wa_Lock,temp,255))
		  continue;

	       /* The name we get is the full path name.  This function*/
	       /* call will leave us with just the directory name*/
	       strcpy(src,FilePart(temp));
	    }
	    else
	    {
	       /* If it is a file, just copy the filename */
	       strcpy(src,mesg->am_ArgList[c].wa_Name);
	       isDir=FALSE;
	    }

	    /* Move to the file's directory*/
	    if(isDir)
	       /* If we got a drawer, the lock is to the directory */
	       /* itself.  To get the directory that the drawer is in, */
	       /* we need to use ParentDir() */
	       oldDir=CurrentDir(ParentDir(mesg->am_ArgList[c].wa_Lock));
	    else
	       oldDir=CurrentDir(mesg->am_ArgList[c].wa_Lock);

	    /* Get the destination filename (i.e. foo -> Link_to_foo ) */
	    if(GetLinkFilename(src,dest))
	    {
	       /* Get a lock on the file that was given */
	       if(isDir)
		  fileLock=mesg->am_ArgList[c].wa_Lock;
	       else
		  fileLock=Lock(src,SHARED_LOCK);

	       /* If we got the lock, make the link */
	       if(fileLock!=NULL)
	       {
		  status=MakeLink(dest,fileLock,FALSE);
		  if(!isDir)
		     UnLock(fileLock);

		  /* If we managed to make the link, copy (NOT link) the */
		  /* source's icon */
		  if(status)
		  {
		     /* Get the source file's icon */
		     diskObj=GetDiskObjectNew(src);

		     if(diskObj!=NULL)
		     {
			/* Reset the icon's position*/
			diskObj->do_CurrentY=NO_ICON_POSITION;
			diskObj->do_CurrentX=NO_ICON_POSITION;

			/* Store the icon as the destination's icon */
			PutDiskObject(dest,diskObj);

			/* Free the disk object's memory */
			FreeDiskObject(diskObj);
		     }
		  }
		  else
		     EasyRequest(NULL,&erError2,NULL,
				 "Couldn't create the link",dest);
	       }
	       else
		  EasyRequest(NULL,&erError3,NULL,"Couldn't open",
			      src,"for linking");
	    }
	    else
	       EasyRequest(NULL,&erError2,NULL,"Couldn't create",
			   "a filename for the link");
	    /* Restore the old directory */
	    CurrentDir(oldDir);
	 }
      }
      else  /* If am_NumArgs==0, the user double clicked on the icon */
	    /* So put up the About... requestor, and quit if the user */
	    /* clicks on the "Quit WBLink" button  */
	 abort=(EasyRequestArgs(NULL,&erAboutWBLink,NULL,"")==1);

      /* Reply to the message */
      ReplyMsg((struct Message *)mesg);
   }

   /* We're done, so exit */
   cleanup(0);
}


/* Create a link filename (i.e. foo -> Link_to_foo ) */
BOOL GetLinkFilename(char *src,char *dest)
{
   UWORD c;
   BPTR lock=1;
   char realSrc[256];

   /* Strip away the link portion of the filename, leaving the original */
   /* filename */
   FindOrig(src,realSrc);

   /* Loop until we get a unused filename slot */
   for(c=1;c<1000 && lock!=NULL;c++)
   {
      /* Create a filename (e.g. Link_22_to_HelloWorld) */
      MakeName(realSrc,dest,c);

      /* See if it exists */
      lock=Lock(dest,SHARED_LOCK);

      /* If the lock was successful, unlock the file */
      if(lock!=NULL)
	 UnLock(lock);
   }

   /* Return TRUE if the destination file name is <26 characters ( so */
   /* that the filename + .info won't exceed the Amiga's 30 character */
   /* filename limit) and if c<1000 (1000 is the upper limit on the   */
   /* number of files that will be created; it's in place as a safe-  */
   /* guard, to keep the above loop from becoming infinite)	      */
   return((strlen(dest)<=25) && !(c==1000));
}

/* Add the link prefix to the given filename */
void MakeName(char *src,char *dest,int c)
{
   /* For c==1, don't use a number (e.g. foo -> Link_to_foo) */
   if(c==1)
   {
      strcpy(dest,"Link_to_");
      strcat(dest,src);
   }
   /* For all others, include the given number (e.g. for c==2, foo -> */
   /* Link_2_to_foo */
   else
   {
      strcpy(dest,"Link_");
      stci_d(&dest[5],c);
      strcat(dest,"_to_");
      strcat(dest,src);
   }
}


/* Strip the link information from the filename (i.e. convert */
/* Link_22_to_foobar into foobar) to make the 'original' filename */
void FindOrig(char *src,char *dest)
{
   UBYTE c,numUS;

   if((Strnicmp(src,"link_",5))==0)
      if((Strnicmp(src,"link_to_",8))==0)
	 /* This handles Link_to_<filename> */
	 strcpy(dest,&src[8]);
      else
      {
	 /* This handles Link_<number>_to_<filename> */
	 /* Move past two underscores (there are two after the <number>) */
	 for(c=5,numUS=0;c<30;c++)
	 {
	    if(src[c]=='_')
	       numUS++;
	    if(numUS==2)
	    {
	       /* Whatever is left is the original filename */
	       strcpy(dest,&src[c+1]);
	       return;
	    }
	 }
	 /*If we couldn't find two underscores, just copy the whole thing*/
	 strcpy(dest,src);
      }
   else  /*This is just a regular filename, so copy the whole thing */
      strcpy(dest,src);
}

/* This frees allocated resources */
void cleanup(UWORD err)
{
   /* The AppIcon */
   if(appIcon!=NULL)
      RemoveAppIcon(appIcon);

   /* The port */
   if(port!=NULL)
      DeletePort(port);

   /* The libraries */
   if(WorkbenchBase!=NULL)
      CloseLibrary(WorkbenchBase);

   if(IconBase!=NULL)
      CloseLibrary(IconBase);

   if(IntuitionBase!=NULL)
      CloseLibrary(IntuitionBase);

   if(UtilityBase!=NULL)
      CloseLibrary(UtilityBase);

   /* Exit the program, using the specified error code */
   exit(err);
}

/* Parse the user's arguments */
void parseArgs(void)
{
   char *str;
   struct DiskObject *diskObj;

   if(WBenchMsg!=NULL)
   {
      /* Get the icon for this program */
      diskObj=GetDiskObject(WBenchMsg->sm_ArgList[0].wa_Name);
      if(diskObj==NULL)
	 return;

      /* Get the X coordinate, if given */
      str=FindToolType(diskObj->do_ToolTypes,"ICONX");
      if(str!=NULL)
	 StrToLong(str,&iconObj.do_CurrentX);

      /* Get the Y coordinate, if given */
      str=FindToolType(diskObj->do_ToolTypes,"ICONY");
      if(str!=NULL)
	 StrToLong(str,&iconObj.do_CurrentY);

      /* Free the memory used by the disk object */
      FreeDiskObject(diskObj);
   }
   else
   {
      LONG args[2];
      struct RDArgs *ra;

      args[0]=args[1]=NULL;

      /* Read the command-line arguments */
      ra=ReadArgs("ICONX/N,ICONY/N",args,NULL);

      /* Get the X coordinate, if given */
      if(args[0]!=NULL)
	 iconObj.do_CurrentX=*(ULONG *)args[0];

      /* Get the Y coordinate, if given */
      if(args[1]!=NULL)
	 iconObj.do_CurrentY=*(ULONG *)args[1];

      FreeArgs(ra);
   }

   return;
}

