/*-- AutoRev header do NOT edit! * * Program : main.c * Copyright : © Copyright 1992 Jaba Development * Author : Jan van den Baard * Creation Date : 08-Mar-92 * Current version : 1.0 * Translator : Dice v2.06.40 * * REVISION HISTORY * * Date Version Comment * --------- ------- ------------------------------------------ * 08-Mar-92 1.0 Main file for JbSpool. * *-- REV_END --*/ /* * include a whole bunch of stuff. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef abs #define abs #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "JbSpoolGadgets.h" /* GadToolsBox file */ #include "Protos.h" /* routine protos. */ /* * Some internally used structures * to tie the files together. */ struct JbFile { struct JbFile *jb_Next; /* next file */ struct JbFile *jb_Prev; /* previous file */ UBYTE jb_Bull0; /* not used */ BYTE jb_Bull1; /* not used */ UBYTE *jb_Name; /* ptr to name */ UBYTE jb_NameBytes[ 108 ]; /* the name */ ULONG jb_Size; /* the size */ UWORD jb_Flags; /* flags */ }; #define ISCHECKED 0x0001 /* file checked */ struct JbList { struct JbFile *jb_First; /* first file */ struct JbFile *jb_EndMark; /* always null */ struct JbFile *jb_Last; /* last file */ }; /* * commodity muck */ /* * An easy way to switch the commodity on or off */ #define CxOn( b ) ActivateCxObj( b, TRUE ) #define CxOff( b ) ActivateCxObj( b, FALSE ); /* * The following strings represent the * possible tooltypes of the JbSpool icon. */ UBYTE *CX_PRIORITY = "CX_PRIORITY"; UBYTE *CX_POPUP = "CX_POPUP"; UBYTE *CX_POPKEY = "CX_POPKEY"; UBYTE *CX_QUIT = "QUIT"; UBYTE *CX_MINUTES = "MINUTES"; UBYTE *CX_SECONDS = "SECONDS"; UBYTE *CX_HALT = "DONTSTART"; UBYTE *CX_APP = "NOAPPICON"; /* * Following are the default JbSpool * settings which can be changed with * the command line or the icon tooltypes. */ #define CX_DEFPRI 0 #define CX_DEFMINS 1 #define CX_DEFSECS 0 UBYTE *CX_DEFPOPKEY = "control lshift j"; UBYTE *CX_DEFPOPUP = "YES"; UBYTE *CX_DEFQUIT = "control lshift q"; /* * Two HotKey events. */ #define CX_SHOW 1L /* show window */ #define CX_SHUTUP 2L /* quit JbSpool */ /* * Miscellanious program information. */ #define JbVersion "v1.0" #define JbName "JbSpool" #define JbDescr "Printer spooler." #define JbCopy "© 1992 Jaba Development" #define JbTitle JbName " " JbVersion ", " JbCopy struct MsgPort *JbComPort = NULL; /* commodity port */ ULONG JbMask = NULL; /* the port bit-mask */ UBYTE *JbTTypes = NULL; /* the tooltype array */ ULONG *JbArgs; /* shell args array */ CxObj *JbBroker = NULL; /* the broker */ /* * The NewBroker structure defining * some important information for * the commodities.library and Exchange. */ struct NewBroker JbNBrok = { NB_VERSION, JbName, JbTitle, JbDescr, NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE, NULL, 0 }; /* * DCBack required data. DCBack is a tiny link library * Iv'e written to make it possible to write auto-detachable * programs with Dice. DCBack also parses the argument line * for you using ReadArgs(). */ UBYTE *_procname = JbName "_" JbVersion; UBYTE *_template = "CX_PRIORITY/K/N,CX_POPUP/K,CX_POPKEY/K,QUIT/K,MINUTES/K/N,SECONDS/K/N,DONTSTART/S,NOAPPICON/S"; UBYTE *_exthelp = NULL; LONG _stack = 2048L; LONG _priority = NULL; LONG _BackGroundIO = NULL; /* * Shell version string. */ static UBYTE JbVer[] = "$VER: JbSpool 37.54 (18.4.92)"; /* * Required libraries that are not in Dice * it's auto-init library. */ struct Library *CxBase = NULL; struct Library *IconBase = NULL; struct Library *WorkbenchBase = NULL; /* * The following libraries are all auto-init. */ extern struct IntuitionBase *IntuitionBase; extern struct UtilityBase *UtilityBase; extern struct GadToolsBase *GadToolsBase; /* * Some other usefull global data */ struct WBStartup *WbMsg = NULL; /* workbench message */ struct MsgPort *JbIdPort = NULL; /* IDCMP port */ UBYTE *JbPopkey; /* popkey string ptr */ ULONG JbIdMask = NULL; /* IDCMP port bit-mask */ UBYTE JbIsOpen = FALSE; /* window open? */ UBYTE JbPop = TRUE; /* open on startup? */ UBYTE JbFF = TRUE; /* insert a FF? */ UBYTE JbPrinting = FALSE; /* are we printing? */ UBYTE JbWTitle[80]; /* window title */ UBYTE JbStopped = FALSE; /* stopped? */ UBYTE JbDelQuit = FALSE; /* delayed quit? */ UBYTE JbJobCan = FALSE; /* Job cancelled? */ UBYTE JbDoIcon = TRUE; /* Add icon? */ UBYTE JbNoPrt = TRUE; /* print? */ LONG JbMins, JbSecs; /* minutes and seconds */ ULONG JbDone = NULL; /* bytes printed */ UWORD JbNodeNum = 0; /* active node number */ struct JbList JbFiles; /* list of files */ struct JbFile *JbCurrentJob = NULL; /* printing this file */ struct JbFile *JbActionNode = NULL; /* put this up or down */ BPTR JbPrinter = NULL; /* printer file */ BPTR JbInput = NULL; /* file to print */ BPTR JbDirLock = NULL; /* lock to JBS: */ /* * ASL requester tags & data. */ UBYTE JbFileN[ 32 ]; /* file name */ UBYTE JbDir[ 256 ]; /* path name */ struct TagItem JbTags[] = { ASL_Hail, "Pick file to add:", /* req title */ ASL_Window, NULL, /* the window */ ASL_File, JbFileN, /* file name buffer */ ASL_Dir, JbDir, /* path name buffer */ ASL_OKText, "Add", /* make OK Add */ ASL_FuncFlags, FILF_MULTISELECT, /* multi selections! */ TAG_DONE }; /* * This is the size of the * buffer I am using for ExAll(); */ #define EXALLSIZE (( ULONG ) 10 * sizeof( struct ExAllData )) /* * The JbSpool directory from which * the files to be printed are read. */ UBYTE *JbDirName = "JBS:"; /* * timer.device stuff */ struct MsgPort *timerPort = NULL; /* timer reply port */ ULONG timerMask = NULL; /* port bit-mask */ struct timerequest *timerReq = NULL; /* timerequest */ long timerErr = NULL; /* device error */ UBYTE timerOn = FALSE; /* are we timing? */ /* * The data for the application icon. */ __chip UWORD AppData1[] = { 0x0000,0x0000,0x0000,0x0400,0x0000,0x0000,0x0000,0x0C00, 0x0000,0x0000,0x0000,0x0C00,0x0000,0x0000,0x0000,0x0C00, 0x01FF,0xFFFF,0xFFFC,0x0C00,0x0100,0x0000,0x0004,0x0C00, 0x0103,0xEFF1,0xF404,0x0C00,0x0101,0xF7FB,0xFE04,0x0C00, 0x0101,0xE7BF,0x86C4,0x0C00,0x0101,0xE7BF,0xE2E4,0x0C00, 0x0101,0xE7FD,0xF864,0x0C00,0x0119,0xE7F8,0xFC04,0x0C00, 0x011D,0xE7BE,0x3E04,0x0C00,0x011D,0xE7BF,0x0EC4,0x0C00, 0x010F,0xEFFF,0xFEE4,0x0C00,0x0107,0xC7F9,0x7C64,0x0C00, 0x0100,0x0000,0x0004,0x0C00,0x01FF,0xFFFF,0xFFFC,0x0C00, 0x0000,0x0000,0x0000,0x0C00,0x0000,0x0000,0x0000,0x0C00, 0x0000,0x0000,0x0000,0x0C00,0x7FFF,0xFFFF,0xFFFF,0xFC00, 0xFFFF,0xFFFF,0xFFFF,0xF800,0xD555,0x5555,0x5555,0x5000, 0xD555,0x5555,0x5555,0x5000,0xD555,0x5555,0x5555,0x5000, 0xD400,0x0000,0x0001,0x5000,0xD4FF,0xFFFF,0xFFF9,0x5000, 0xD4FF,0xFFFF,0xFFF9,0x5000,0xD4FF,0xCF3F,0x0DF9,0x5000, 0xD4FF,0xDF7B,0xFDF9,0x5000,0xD4FF,0xDF7B,0xFDD9,0x5000, 0xD4FF,0xDFF3,0xFF99,0x5000,0xD4FF,0xDF3F,0x7FF9,0x5000, 0xD4FB,0xDF7B,0xDDF9,0x5000,0xD4F3,0xDF7B,0xFDF9,0x5000, 0xD4FF,0x9FF2,0xF9D9,0x5000,0xD4F8,0x3806,0x8399,0x5000, 0xD4FF,0xFFFF,0xFFF9,0x5000,0xD400,0x0000,0x0001,0x5000, 0xD555,0x5555,0x5555,0x5000,0xD555,0x5555,0x5555,0x5000, 0xD555,0x5555,0x5555,0x5000,0x8000,0x0000,0x0000,0x0000, }; __chip UWORD AppData2[] = { 0xFFFF,0xFFFF,0xFFFF,0xF800,0xC000,0x0000,0x0000,0x0000, 0xC000,0x0000,0x0000,0x0000,0xC000,0x0000,0x0000,0x0000, 0xC1FF,0xFFFF,0xFFFC,0x0000,0xC100,0x0000,0x0004,0x0000, 0xC103,0xEFF1,0xF404,0x0000,0xC101,0xF7FB,0xFE04,0x0000, 0xC101,0xE7BF,0x86C4,0x0000,0xC101,0xE7BF,0xE2E4,0x0000, 0xC101,0xE7FD,0xF864,0x0000,0xC119,0xE7F8,0xFC04,0x0000, 0xC11D,0xE7BE,0x3E04,0x0000,0xC11D,0xE7BF,0x0EC4,0x0000, 0xC10F,0xEFFF,0xFEE4,0x0000,0xC107,0xC7F9,0x7C64,0x0000, 0xC100,0x0000,0x0004,0x0000,0xC1FF,0xFFFF,0xFFFC,0x0000, 0xC000,0x0000,0x0000,0x0000,0xC000,0x0000,0x0000,0x0000, 0xC000,0x0000,0x0000,0x0000,0x8000,0x0000,0x0000,0x0000, 0x0000,0x0000,0x0000,0x0400,0x1555,0x5555,0x5555,0x5C00, 0x1555,0x5555,0x5555,0x5C00,0x1555,0x5555,0x5555,0x5C00, 0x1400,0x0000,0x0001,0x5C00,0x14FF,0xFFFF,0xFFF9,0x5C00, 0x14FF,0xFFFF,0xFFF9,0x5C00,0x14FF,0xCF3F,0x0DF9,0x5C00, 0x14FF,0xDF7B,0xFDF9,0x5C00,0x14FF,0xDF7B,0xFDD9,0x5C00, 0x14FF,0xDFF3,0xFF99,0x5C00,0x14FF,0xDF3F,0x7FF9,0x5C00, 0x14FB,0xDF7B,0xDDF9,0x5C00,0x14F3,0xDF7B,0xFDF9,0x5C00, 0x14FF,0x9FF2,0xF9D9,0x5C00,0x14F8,0x3806,0x8399,0x5C00, 0x14FF,0xFFFF,0xFFF9,0x5C00,0x1400,0x0000,0x0001,0x5C00, 0x1555,0x5555,0x5555,0x5C00,0x1555,0x5555,0x5555,0x5C00, 0x1555,0x5555,0x5555,0x5C00,0x7FFF,0xFFFF,0xFFFF,0xFC00, }; /* * Images for the application icon. */ struct Image AppIm1 = { 0,0,54,22,2,AppData1,0x0003,0x0000,NULL }; struct Image AppIm2 = { 0,0,54,22,2,AppData2,0x0003,0x0000,NULL }; /* * The DiskObject structure for the application icon. */ struct DiskObject AppIc = { WB_DISKMAGIC,WB_DISKVERSION, { NULL,0,0,54,23,GADGIMAGE|GADGHIMAGE, RELVERIFY,BOOLGADGET, (APTR)&AppIm1,(APTR)&AppIm2, NULL,NULL,NULL,100,(APTR) 0x0001, }, WBTOOL,NULL,NULL,NO_ICON_POSITION, NO_ICON_POSITION,NULL,NULL,0 }; struct AppIcon *JbApIcon = NULL; /* The AppIcon */ struct MsgPort *JbWbPort = NULL; /* The AppIcon port */ ULONG JbWbMask = NULL; /* And the bit mask */ /* * Whe the AppIcon isn't setup yet this * routine will try to set it up again. */ void SetupAppIcon( void ) { if ( ! JbApIcon && JbDoIcon ) { if ( JbWbPort = CreateMsgPort()) { JbWbMask = ( 1L << JbWbPort->mp_SigBit ); if ( JbApIcon = AddAppIcon( NULL, NULL, "JbSpool", JbWbPort, NULL, &AppIc, TAG_DONE )) return; } CloseDownAppIcon(); } } /* * This deletes the AppIcon again. */ void CloseDownAppIcon( void ) { struct Message *msg; if ( JbApIcon ) { RemoveAppIcon( JbApIcon ); JbApIcon = NULL; } if ( JbWbPort ) { DeleteMsgPort( JbWbPort ); JbWbPort = NULL; JbWbMask = NULL; } } /* * This structure is used to determine wether * or not the (parallel) printer is online and * has paper in it. * (Amiga ROM Kernel Reference : Devices 3rd. edition page 186 ) */ struct Data { UBYTE LSB, MSB; }; /* * Query the printer status. This * will check if the printer is online * and if it has paper in it. Note that * this will only work with parallel printers. */ BOOL QueryPrinter( __A0 UBYTE *name ) { struct MsgPort *port; struct IOStdReq *pio; struct Data data; UBYTE *ptr; ULONG size = 1L; BOOL ret = TRUE; if ( port = CreateMsgPort()) { if ( pio = CreateStdIO( port )) { if ( ! OpenDevice( "printer.device", NULL, ( struct IORequest * )pio, NULL )) { retry: pio->io_Data = (APTR)&data; pio->io_Command = PRD_QUERY; DoIO(( struct IORequest * )pio ); /* * If bit 0 of the LSB (Least Significant Byte) is * set it means that the printer is offline. * If bit 1 of the LSB is set it means that there * is no paper in the printer. */ if ( data.LSB & 1 ) { if ( Req( "Retry|Cancel", "I want to print \"%s\" but\nyour printer isn't online.", name )) goto retry; else ret = FALSE; } else if ( data.LSB & 2 ) { if ( Req( "Retry|Cancel", "I want to print\"%s\" but\nyour printer doesn't have any paper.", name )) goto retry; else ret = FALSE; } CloseDevice(( struct IORequest * )pio ); } DeleteStdIO( pio ); } DeleteMsgPort( port ); } /* * Flush the memory forcing the system * to un-load the printer.device when it's * use count is 0. This will ensure the * correct preferences settings of the * printer when JbSpool prints it's files. */ while( ptr = AllocMem( size, MEMF_PUBLIC )) { FreeMem( ptr, size ); size <<= 1L; } return( ret ); } /* * Set the window gadgets and menus * accoording to the different program flags. */ void SetupDisplay( __D0 BOOL prc ) { if ( JbIsOpen ) { if ( prc ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_DONE ], SpoolWnd, NULL, GTNM_Number, ( JbDone * 100 ) / JbCurrentJob->jb_Size, TAG_DONE ); else { if ( JbActionNode ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, &JbFiles, GTLV_Selected, JbNodeNum, GTLV_Top, JbNodeNum ); else GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, &JbFiles, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_MINS ], SpoolWnd, NULL, GTIN_Number, JbMins, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_SECS ], SpoolWnd, NULL, GTIN_Number, JbSecs, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_FF ], SpoolWnd, NULL, GTCB_Checked, JbFF, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_DONE ], SpoolWnd, NULL, GTNM_Number, NULL, TAG_DONE ); if ( ! JbActionNode ) { GT_SetGadgetAttrs( SpoolGadgets[ GDX_REMOVE ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_UP ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_DOWN ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_TOP ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_BOTTOM ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); OffMenu( SpoolWnd, SHIFTMENU(0)|SHIFTITEM(3)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(0)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(1)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(2)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(3)|SHIFTSUB(NOSUB)); } else { GT_SetGadgetAttrs( SpoolGadgets[ GDX_REMOVE ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_UP ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_DOWN ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_TOP ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_BOTTOM ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); OnMenu( SpoolWnd, SHIFTMENU(0)|SHIFTITEM(3)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(0)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(1)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(2)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(3)|SHIFTSUB(NOSUB)); } if ( JbPrinting && JbCurrentJob ) { GT_SetGadgetAttrs( SpoolGadgets[ GDX_CURRENT ], SpoolWnd, NULL, GTTX_Text, JbCurrentJob->jb_Name, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_STOP ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_CONT ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_ABORT ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(5)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(6)|SHIFTSUB(NOSUB)); OnMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(8)|SHIFTSUB(NOSUB)); } else { if ( JbJobCan ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_CURRENT ], SpoolWnd, NULL, GTTX_Text, "*** DELAYED ***", TAG_DONE ); else if ( ! JbFiles.jb_First->jb_Next ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_CURRENT ], SpoolWnd, NULL, GTTX_Text, "*** IDLE ***", TAG_DONE ); else if ( JbStopped ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_CURRENT ], SpoolWnd, NULL, GTTX_Text, "*** STOPPED ***", TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_STOP ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_CONT ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_ABORT ], SpoolWnd, NULL, GA_Disabled, TRUE, TAG_DONE ); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(5)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(6)|SHIFTSUB(NOSUB)); OffMenu( SpoolWnd, SHIFTMENU(1)|SHIFTITEM(8)|SHIFTSUB(NOSUB)); } if ( JbStopped ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_CONT ], SpoolWnd, NULL, GA_Disabled, FALSE, TAG_DONE ); } } } /* * This routine checks if the character * is a valid ascii character. */ long IsAsciiChar( __D0 UBYTE chr ) { if( chr > 0x00 && chr < 0x09 ) return FALSE; if( chr > 0x0D && chr < 0x1B ) return FALSE; if( chr > 0x1B && chr < 0x20 ) return FALSE; if( chr > 0x7F && chr < 0x9b ) return FALSE; return TRUE; } /* * This routine will check if the file is * really an ascii text file. This way it * is made sure that JbSpool only prints * the text files. */ long CheckAscii( __A0 struct JbFile *jf ) { BPTR file; UBYTE memory[ 100 ], chr; ULONG cnt, ret = TRUE, len; if( file = Open( jf->jb_Name, MODE_OLDFILE )) { if ( len = Read( file, memory, 100L )) { for( cnt = 0; cnt < len; cnt++ ) { chr = memory[ cnt ]; if( ! IsAsciiChar( chr )) { ret = FALSE; break; } } Close(file); } else ret = FALSE; } if ( ! ret ) DeleteFile( jf->jb_Name ); return( ret ); } /* * Get the JbFile node "num" from * the queue. */ struct JbFile *FindNode( UWORD node ) { struct JbFile *file; UWORD num = 0; if ( JbIsOpen ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, ~0, TAG_DONE ); for ( file = JbFiles.jb_First; file->jb_Next; file = file->jb_Next ) { if ( num++ == node ) break; } if ( JbIsOpen ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, &JbFiles, GTLV_Selected, num - 1, TAG_DONE ); return( file ); } /* * Check if the file in the directory is * already in the queue list. The routine simply * goes through the list of files and checks * if the name already is in the file list. */ long CheckIfExists( __A0 UBYTE *name ) { struct JbFile *file; if ( JbCurrentJob ) { if ( ! stricmp( name, JbCurrentJob->jb_Name )) return( TRUE ); } for ( file = JbFiles.jb_First; file->jb_Next; file = file->jb_Next ) { if ( ! stricmp( name, file->jb_Name )) return( TRUE ); } return( FALSE ); } /* * Remove the files from the queue that doesn't * exist anymore. This to prevent the program from * trying to read and print a file that doesn't * exist in the JBS: directory anymore. Also all * non-ascii files are removed by this routine. */ void RemoveObsoleteFiles( void ) { struct JbFile *file; BPTR lock, cd; cd = CurrentDir( JbDirLock ); goAgain: for ( file = JbFiles.jb_First; file->jb_Next; file = file->jb_Next ) { if (( file->jb_Flags & ISCHECKED ) != ISCHECKED ) { /* * Remove the non-ascii files. */ if ( ! CheckAscii( file )) goto skipIt; if ( ! ( lock = Lock ( file->jb_Name, ACCESS_READ ))) { /* * The file in the list doesn't actually * exists on the disk anymore so we * remove it from the list. */ skipIt: Remove(( struct Node * )file ); FreeVec( file ); goto goAgain; } else { UnLock( lock ); /* * Set the ISCHECKED flag which saves time on * the next pass through the list. */ file->jb_Flags |= ISCHECKED; } } } /* * Clear all ISCHECKED flags again. */ for ( file = JbFiles.jb_First; file->jb_Next; file = file->jb_Next ) file->jb_Flags &= ~ISCHECKED; CurrentDir( cd ); } /* * Scan through the JBS: directory to find out * if there are new files to be added to the queue */ void ScanDirectory( void ) { struct ExAllControl *eac; struct ExAllData *ead, *tmp; struct FileInfoBlock *fib; struct JbFile *file; BPTR lock; BOOL ismore; if ( JbIsOpen ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, ~0, TAG_DONE ); if ( lock = Lock( JbDirName, ACCESS_READ )) { if ( fib = ( struct FileInfoBlock * )AllocDosObject( DOS_FIB, NULL )) { if ( Examine( lock, fib )) { if ( fib->fib_DirEntryType > 0 ) { if ( eac = ( struct ExAllControl * ) AllocDosObject( DOS_EXALLCONTROL, NULL )) { /* * THIS IS VERY IMPORTANT !!!! */ eac->eac_LastKey = NULL; if ( ead = ( struct ExAllData * )AllocVec( EXALLSIZE, MEMF_PUBLIC | MEMF_CLEAR )) { do { ismore = ExAll( lock, ead, EXALLSIZE, ED_SIZE, eac ); if (( ! ismore ) && ( IoErr() != ERROR_NO_MORE_ENTRIES )) break; if ( ! eac->eac_Entries ) continue; tmp = ead; do { if ( tmp->ed_Type < 0 ) { if ( ! CheckIfExists( tmp->ed_Name )) { if ( file = ( struct JbFile * )AllocVec(( ULONG )sizeof( struct JbFile ), MEMF_PUBLIC | MEMF_CLEAR )) { file->jb_Name = &file->jb_NameBytes[ 0 ]; strcpy( file->jb_Name, tmp->ed_Name ); file->jb_Size = tmp->ed_Size; AddTail(( struct List * )&JbFiles, ( struct Node * )file ); } } } tmp = tmp->ed_Next; } while ( tmp ); } while( ismore ); FreeVec( ead ); } FreeDosObject( DOS_EXALLCONTROL, eac ); } } } FreeDosObject( DOS_FIB, fib ); } UnLock( lock ); } /* * Remove all unwanted files from the list. */ RemoveObsoleteFiles(); /* * Try to setup an AppIcon. * This is done after each directory * scan so that when the user open the * workbench we have an AppIcon on it. */ SetupAppIcon(); SetupDisplay( FALSE ); if ( JbIsOpen ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, &JbFiles, TAG_DONE ); } /* * Open up all required resources. Check the * arguments passed to JbSpool from the argument * line if run from the shell or the tool types * when run from the workbench. */ void SetupSpool( void ) { CxObj *tmp; UBYTE *quitkey, *popup; WORD priority; LONG error; NewList(( struct List * )&JbFiles ); JbFileN[ 0 ] = JbDir[ 0 ] = 0; if ( ! ( CxBase = OpenLibrary( "commodities.library", 37L ))) { error = 20L; goto ohMyGodAnErrorOccurred; } /* * This one is required by the Argxxxx() * routines from the amigas20.lib. */ if ( ! ( IconBase = OpenLibrary( "icon.library", 34L ))) { error = 21L; goto ohMyGodAnErrorOccurred; } if ( ! ( WorkbenchBase = OpenLibrary( "workbench.library", 37L ))) { error = 22L; goto ohMyGodAnErrorOccurred; } if ( WbMsg ) { /* * When WbMsg is non-null it means that * JbSpool was started from the workbench. */ JbTTypes = ( UBYTE * )ArgArrayInit( NULL, ( UBYTE ** )WbMsg ); priority = ArgInt(( char ** )JbTTypes, CX_PRIORITY, CX_DEFPRI ); popup = ArgString(( char ** )JbTTypes, CX_POPUP, CX_DEFPOPUP ); JbPopkey = ArgString(( char ** )JbTTypes, CX_POPKEY, CX_DEFPOPKEY ); quitkey = ArgString(( char ** )JbTTypes, CX_QUIT, CX_DEFQUIT ); JbMins = ArgInt(( char ** )JbTTypes, CX_MINUTES, CX_DEFMINS ); JbSecs = ArgInt(( char ** )JbTTypes, CX_SECONDS, CX_DEFSECS ); if ( ArgString(( char ** )JbTTypes, CX_HALT, NULL )) JbStopped = TRUE; if ( ArgString(( char ** )JbTTypes, CX_APP, NULL )) JbDoIcon = FALSE; } else { /* * Otherwise JbSpool was started from the shell. */ if ( JbArgs[ 0 ] ) priority = ( WORD )*(( ULONG * )JbArgs[ 0 ] ); else priority = CX_DEFPRI; if ( JbArgs[ 1 ] ) popup = ( UBYTE * )JbArgs[ 1 ]; else popup = CX_DEFPOPUP; if ( JbArgs[ 2 ] ) JbPopkey = ( UBYTE * )JbArgs[ 2 ]; else JbPopkey = CX_DEFPOPKEY; if ( JbArgs[ 3 ] ) quitkey = ( UBYTE * )JbArgs[ 3 ]; else quitkey = CX_DEFQUIT; if ( JbArgs[ 4 ] ) JbMins = ( WORD )*(( ULONG * )JbArgs[ 4 ] ); else JbMins = CX_DEFMINS; if ( JbArgs[ 5 ] ) JbSecs = ( WORD )*(( ULONG * )JbArgs[ 5 ] ); else JbSecs = CX_DEFSECS; if ( JbArgs[ 6 ] ) JbStopped= TRUE; if ( JbArgs[ 7 ] ) JbDoIcon = FALSE; } if ( JbMins < 0 ) JbMins = 0; if ( ! JbMins && ( JbSecs < 5 )) JbSecs = 5; JbNBrok.nb_Pri = priority; if ( Stricmp( popup, CX_DEFPOPUP )) JbPop = FALSE; if ( JbComPort = CreateMsgPort()) { JbMask = ( 1L << JbComPort->mp_SigBit ); JbNBrok.nb_Port = JbComPort; if ( JbBroker = CxBroker( &JbNBrok, NULL )) { if ( tmp = HotKey( JbPopkey, JbComPort, CX_SHOW )) { AttachCxObj( JbBroker, tmp ); if ( tmp = HotKey( quitkey, JbComPort, CX_SHUTUP )) { AttachCxObj( JbBroker, tmp ); if ( ! CxObjError( JbBroker )) { CxOn( JbBroker ); if ( SetupTimer()) { if ( JbDirLock = Lock ( JbDirName, ACCESS_READ )) { SetupAppIcon(); return; } else error = 22L; } else error = 23L; } else error = 24L; } else error = 25L; } else error = 26L; } else error = 27L; } else error = 28L; ohMyGodAnErrorOccurred: CloseDownSpool( error ); } /* * Close down and deallocate all resources * taken from the system. */ void CloseDownSpool( __D0 LONG code ) { struct JbFile *file; struct Message *tmp; BPTR od; CloseDownTimer(); CloseDownAppIcon(); od = CurrentDir( JbDirLock ); while( file = ( struct JbFile * )RemHead(( struct List * )&JbFiles )) { DeleteFile( file->jb_Name ); FreeVec( file ); } CurrentDir( od ); if ( JbDirLock ) UnLock( JbDirLock ); if ( JbBroker ) DeleteCxObjAll( JbBroker ); if ( JbComPort ) { while ( tmp = GetMsg( JbComPort )) ReplyMsg( tmp ); DeleteMsgPort( JbComPort ); } if ( JbTTypes) ArgArrayDone(); if ( WorkbenchBase ) CloseLibrary( WorkbenchBase ); if ( IconBase ) CloseLibrary( IconBase ); if ( CxBase ) CloseLibrary( CxBase ); exit( code ); } /* * Setup the timer.device to create a delay * between directory scans. The timer.device * is also used to create a 1 second delay * between printer writes. */ long SetupTimer( void ) { if ( timerPort = CreateMsgPort()) { timerMask = ( 1L << timerPort->mp_SigBit ); if ( timerReq = ( struct timerequest * )CreateExtIO( timerPort, ( long )sizeof( struct timerequest ))) { if ( ! ( timerErr = OpenDevice( TIMERNAME, UNIT_VBLANK, ( struct IORequest * )timerReq, NULL ))) return( TRUE ); } } CloseDownTimer(); return( FALSE ); } /* * Close down the timer.device */ void CloseDownTimer( void ) { if ( timerReq ) { AbortTimer(); if ( ! timerErr ){ CloseDevice(( struct IORequest * )timerReq ); timerErr = NULL; } DeleteExtIO(( struct IORequest * )timerReq ); timerReq = NULL; } if ( timerPort ) { DeleteMsgPort( timerPort ); timerMask = NULL; timerPort = NULL; } timerOn = FALSE; } /* * Abort the currently running * timer request. */ void AbortTimer( void ) { if ( timerOn ) { AbortIO(( struct IORequest * )timerReq ); WaitIO(( struct IORequest * )timerReq ); timerOn = FALSE; } } /* * Move the "JbActiveNode" up, down, to the top or to the bottom. */ UWORD MoveTheNode( __D0 UWORD num, __D1 UWORD dir ) { struct JbFile *tmp = NULL; GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, ~0, TAG_DONE ); if ( JbActionNode ) { if ( dir == 1 ) { if ( JbActionNode != JbFiles.jb_First ) tmp = JbActionNode->jb_Prev->jb_Prev; } else if ( ! dir ) { if ( JbActionNode != JbFiles.jb_Last ) tmp = JbActionNode->jb_Next; } else tmp = JbActionNode; if ( tmp ) { Remove(( struct Node * )JbActionNode ); if ( dir <= 1 ) Insert(( struct List * )&JbFiles, ( struct Node * )JbActionNode, ( struct Node * )tmp ); else if ( dir == 2 ) AddHead(( struct List * )&JbFiles, ( struct Node * )JbActionNode ); else AddTail(( struct List * )&JbFiles, ( struct Node * )JbActionNode ); } } if ( tmp ) { if ( dir == 1 ) num--; else if ( ! dir ) num++; else if ( dir == 2 ) num = 0; else { num = 0; for ( tmp = JbFiles.jb_First; tmp->jb_Next; tmp = tmp->jb_Next ) num++; num--; } } GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, &JbFiles, GTLV_Selected, num, GTLV_Top, num, TAG_DONE ); return( num ); } /* * Put up a simple requester. */ long Req( UBYTE *gadgets, UBYTE *body, ... ) { static struct EasyStruct req = { sizeof( struct EasyRequest ), NULL, NULL, NULL, NULL }; va_list args; LONG rc; va_start( args, body ); req.es_Title = "JbSpool"; req.es_TextFormat = body; req.es_GadgetFormat = gadgets; rc = EasyRequestArgs( NULL, &req, NULL, args ); va_end( args ); return( rc ); } /* * Remove the selected node from the * list and, if requested, delete the * corresponding file from the * JBS: directory. */ void RemoveTheNode( void ) { BPTR od; if ( JbActionNode ) { od = CurrentDir( JbDirLock ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, ~0, TAG_DONE ); Remove(( struct Node * )JbActionNode ); if ( Req( "Yes|No", "Shall I delete the file\nfrom the JBS: directory too?" )) DeleteFile( JbActionNode->jb_Name ); FreeVec( JbActionNode ); JbActionNode = NULL; JbNodeNum = 0; CurrentDir( od ); AbortTimer(); if ( JbPrinting ) ScanDirectory(); } } /* * This copies the file from it's * original directory in the JBS: * directory so that it can be printed. */ void CopyTheFile( __A0 BPTR slock, __A1 UBYTE *fname ) { BPTR filein, fileout; BPTR od; UBYTE *ptr; ULONG size; od = CurrentDir( slock ); if ( filein = Open( fname, MODE_OLDFILE )) { Seek( filein, NULL, OFFSET_END ); size = Seek( filein, NULL, OFFSET_BEGINNING ); if ( ptr = ( UBYTE * )AllocMem( size, MEMF_PUBLIC )) { if ( Read( filein, ptr, size ) == size ) { CurrentDir( JbDirLock ); if ( fileout = Open( fname, MODE_NEWFILE )) { if ( Write( fileout, ptr, size ) != size ) Req( "Continue", "Error writing file !" ); Close( fileout ); } else Req( "Continue", "Error opening write file !" ); } else Req( "Continue", "Error reading file !" ); FreeMem( ptr, size ); } else Req( "Continue", "Out of memory !" ); Close( filein ); } else Req( "Continue", "Error opening read file !" ); CurrentDir( od ); } /* * Show the ASL FileRequester to let the * user add a file to the queue. */ void AddANode( void ) { struct WBArg *wba; struct FileRequester *freq; UBYTE *ptr; ULONG size, i; BPTR lock; JbTags[ 1 ].ti_Data = (ULONG)SpoolWnd; if ( freq = AllocAslRequest( ASL_FileRequest, JbTags )) { if ( RequestFile( freq )) { strcpy( JbDir, freq->rf_Dir ); strcpy( JbFileN, freq->rf_File ); if ( freq->rf_NumArgs ) { wba = freq->rf_ArgList; for ( i = 0; i < freq->rf_NumArgs; i++, wba++ ) CopyTheFile( wba->wa_Lock, wba->wa_Name ); } else if ( lock = Lock( JbDir, ACCESS_READ )) { /* * There is a bug in the asl.library. When you have * the multi-select option in the filerequester the * requester doesn't give the correct result when * you select _one_ file by _double-clicking_ it. */ CopyTheFile( lock, JbFileN ); UnLock( lock ); } } FreeAslRequest( freq ); } AbortTimer(); if ( JbPrinting ) ScanDirectory(); JbJobCan = FALSE; } /* * Interpred and act on the menu events. * Note that this routine supports drag-selection * but when Hide is selected the drag-selection * loop will break. */ UWORD DoTheMenus( __D0 UWORD menucode ) { struct MenuItem *mi; UWORD menu, item, breakloop = FALSE, ret = 0; while ( menucode != MENUNULL && ! breakloop ) { mi = ( struct MenuItem * )ItemAddress( SpoolMenus, menucode ); menu = MENUNUM( menucode ); item = ITEMNUM( menucode ); switch ( menu ) { case 0: switch ( item ) { case 0: /* About */ Req( "Continue", "%s\n" "© Copyright 1992 Jaba Development\n\n" "Release 1 - FreeWare\n\n" "Written using Dice v2.06.40 by\n" "Jan van den Baard", &JbVer[ 6 ] ); break; case 2: /* Add */ AddANode(); break; case 3: /* Remove */ RemoveTheNode(); break; case 5: /* Hide */ CloseTheWindow(); breakloop = TRUE; break; case 7: /* Quit */ ret = 1; break; } break; case 1: switch ( item ) { case 0: /* Up */ JbNodeNum = MoveTheNode( JbNodeNum, 1 ); break; case 1: /* Down */ JbNodeNum = MoveTheNode( JbNodeNum, 0 ); break; case 2: /* Top */ JbNodeNum = MoveTheNode( JbNodeNum, 2 ); break; case 3: /* Bottom */ JbNodeNum = MoveTheNode( JbNodeNum, 3 ); break; case 5: /* Stop */ JbStopped = TRUE; break; case 6: /* Continue */ JbStopped = FALSE; break; case 8: /* Abort */ ret = 2; break; } break; } menucode = mi->NextSelect; } return( ret ); } /* * The main program loop which wait for events from * the different ports that are setup by the program. */ void EventHandler( void ) { struct Message *msg; struct IntuiMessage *imsg; struct Gadget *gad; struct JbFile *tmp; ULONG sig, type, id, class, min, sec, rd; UWORD code; UBYTE running = TRUE, doit, buffer[ 128 ]; BPTR od; /* * Open JbSpool it's window when * CX_POPUP is YES. */ if ( JbPop ) OpenTheWindow(); ScanDirectory(); /* Perform a directory scan */ do { /* * If the delayed quit flag is set and * JbSpool isn't busy printing a file we * quit. */ if ( ! JbPrinting && JbDelQuit ) goto QuitIt; setupTimer: /* * If the timer delay isn't running we * send a new request to get it * started again. */ if ( ! timerOn ) { sec = JbSecs; min = JbMins; if ( JbPrinting ) { /* * When the printing is in progress * JbSpool sends 128 bytes every * second to the printer. I have done this * because I dont want to hold up the * system with a busy loop. */ JbSecs = 1; JbMins = 0; } timerReq->tr_node.io_Command = TR_ADDREQUEST; timerReq->tr_time.tv_micro = 0; timerReq->tr_time.tv_secs = JbMins * 60 + JbSecs; SendIO(( struct IORequest * )timerReq ); timerOn = TRUE; if ( JbPrinting ) { JbSecs = sec; JbMins = min; } } /* * When we ar not printing and there is still a file * in the queue and JbSpool hasn't been stopped and * the offline/paper requester isn't cancelled we * remove the first file from the queue and open it * plus that we open the printer to write to. */ if ( ! JbPrinting && JbFiles.jb_First->jb_Next && ! JbStopped && ! JbJobCan ) { if ( JbIsOpen ) GT_SetGadgetAttrs( SpoolGadgets[ GDX_QUEUE ], SpoolWnd, NULL, GTLV_Labels, ~0, TAG_DONE ); JbCurrentJob = ( struct JbFile * )RemHead(( struct List * )&JbFiles ); if ( QueryPrinter( JbCurrentJob->jb_Name )) { od = CurrentDir( JbDirLock ); SetProtection( JbCurrentJob->jb_Name, FIBF_WRITE | FIBF_DELETE ); if ( JbInput = Open( JbCurrentJob->jb_Name, MODE_OLDFILE )) { if ( JbPrinter = Open( "PRT:", MODE_NEWFILE )) { /* * Stop the timer so that it * can be setup for the printer * delay time. */ AbortTimer(); JbPrinting = TRUE; JbDone = NULL; } } CurrentDir( od ); } else { /* * The offline/paper requester has been cancelled. * Now we re-queue the file on top of the list * and we set the job canceled flag. */ AddTail(( struct List * )&JbFiles, ( struct Node * )JbCurrentJob ); JbCurrentJob = NULL; JbJobCan = TRUE; } SetupDisplay( FALSE ); } /* * Wait for the timer, commodity and (if open) the window ports. */ sig = Wait( JbMask | JbIdMask | timerMask | JbWbMask ); if (( sig & timerMask ) == timerMask ) { if ( JbPrinter && JbInput && JbPrinting ) { /* * Read the next 128 bytes from the file and, * if no eof or error occured, send them to * the printer. */ if (( rd = Read( JbInput, buffer, 128L )) > 0 ) { JbDone += rd; SetupDisplay( TRUE ); Write( JbPrinter, buffer, rd ); } else { /* * Here we have either reached the end-of-file * or a read error occured. In both cases the * the file will be removed from the list and * the JBS: directory. */ AbortPrint: /* * Send a form-feed to the printer * when this is requested. */ if ( ! rd && JbFF ) FPutC( JbPrinter, '\f' ); Close( JbInput ); Close( JbPrinter ); JbInput = JbPrinter = NULL; od = CurrentDir( JbDirLock ); SetProtection( JbCurrentJob->jb_Name, NULL ); DeleteFile( JbCurrentJob->jb_Name ); FreeVec( JbCurrentJob ); JbCurrentJob = NULL; CurrentDir( od ); JbPrinting = FALSE; } } /* * The timer is done which means that we must * re-scan the JBS: directory when we are not * printing. */ timerOn = FALSE; while( msg = GetMsg( timerPort )) { if (( timerReq->tr_node.io_Error & IOERR_ABORTED ) != IOERR_ABORTED ) JbJobCan = FALSE; } if ( ! JbPrinting ) ScanDirectory(); Forbid(); } if (( sig & JbMask ) == JbMask ) { /* * A commodity message came through. */ while ( msg = GetMsg( JbComPort )) { id = CxMsgID(( CxMsg * )msg ); type = CxMsgType(( CxMsg * )msg ); ReplyMsg( msg ); switch ( type ) { case CXM_IEVENT: switch ( id ) { case CX_SHOW: OpenTheWindow(); break; case CX_SHUTUP: if ( ! JbPrinting ) running = FALSE; else JbDelQuit = TRUE; break; } break; case CXM_COMMAND: switch ( id ) { case CXCMD_KILL: if ( ! JbPrinting ) running = FALSE; else JbDelQuit = TRUE; break; case CXCMD_DISABLE: CxOff( JbBroker ); break; case CXCMD_ENABLE: CxOn( JbBroker ); break; case CXCMD_UNIQUE: case CXCMD_APPEAR: OpenTheWindow(); break; case CXCMD_DISAPPEAR: CloseTheWindow(); break; } break; } } } if ( JbIsOpen ) { if (( sig & JbIdMask ) == JbIdMask ) { /* * A window message came through. */ while ( JbIdPort && ( imsg = GT_GetIMsg( JbIdPort ))) { class = imsg->Class; code = imsg->Code; gad = ( struct Gadget * )imsg->IAddress; GT_ReplyIMsg( imsg ); switch ( class ) { case IDCMP_REFRESHWINDOW: GT_BeginRefresh( SpoolWnd ); GT_EndRefresh( SpoolWnd, TRUE ); break; case IDCMP_CLOSEWINDOW: CloseTheWindow(); break; case IDCMP_CHANGEWINDOW: SpoolLeft = SpoolWnd->LeftEdge; SpoolTop = SpoolWnd->TopEdge; break; case IDCMP_GADGETUP: case IDCMP_GADGETDOWN: switch ( gad->GadgetID ) { case GD_QUEUE: JbActionNode = FindNode( code ); JbNodeNum = code; SetupDisplay( FALSE ); break; case GD_ADD: AddANode(); break; case GD_ABORT: Abort: AbortTimer(); FPuts( JbPrinter, "\n\n*** JbSpool: Dump aborted! ***\n" ); rd = 1; goto AbortPrint; case GD_STOP: JbStopped = TRUE; break; case GD_CONT: JbStopped = FALSE; break; case GD_REMOVE: RemoveTheNode(); break; case GD_UP: JbNodeNum = MoveTheNode( JbNodeNum, 1 ); break; case GD_DOWN: JbNodeNum = MoveTheNode( JbNodeNum, 0 ); break; case GD_TOP: JbNodeNum = MoveTheNode( JbNodeNum, 2 ); break; case GD_BOTTOM: JbNodeNum = MoveTheNode( JbNodeNum, 3 ); break; case GD_SECS: JbSecs = (( struct StringInfo * )gad->SpecialInfo )->LongInt; goto setTimer; case GD_MINS: JbMins = (( struct StringInfo * )gad->SpecialInfo )->LongInt; setTimer: if ( JbSecs >= 0 && JbMins >= 0 ) { if ( ! JbMins && ( JbSecs < 5 )) { GT_SetGadgetAttrs( SpoolGadgets[ GDX_SECS ], SpoolWnd, NULL, GTIN_Number, 5L, TAG_END ); JbSecs = 5; } AbortTimer(); } else { GT_SetGadgetAttrs( SpoolGadgets[ GDX_MINS ], SpoolWnd, NULL, GTIN_Number, min, TAG_END ); GT_SetGadgetAttrs( SpoolGadgets[ GDX_SECS ], SpoolWnd, NULL, GTIN_Number, sec, TAG_END ); JbMins = min; JbSecs = sec; } break; case GD_FF: if ( JbFF ) JbFF = FALSE; else JbFF = TRUE; SetupDisplay( FALSE ); break; case GD_HIDE: CloseTheWindow(); break; case GD_QUIT: Quit: if ( ! JbPrinting ) running = FALSE; else JbDelQuit = TRUE; break; } break; case IDCMP_MENUPICK: switch( DoTheMenus( code )) { case 1: goto Quit; case 2: goto Abort; } break; } } } } if ( JbApIcon ) { if (( sig & JbWbMask ) == JbWbMask ) { /* * We have gotten a message from * our AppIcon. */ struct AppMessage *apm; struct WBArg *wba; UWORD i; while ( apm = ( struct AppMessage * )GetMsg( JbWbPort )) { if ( apm->am_NumArgs ) { /* * When am_NumArgs is non-zero it means * that someone has dropped one or more * icon on our AppIcon. */ wba = apm->am_ArgList; for ( i = 0; i < apm->am_NumArgs; i++, wba++ ) /* * Copy all the files dropped over our * AppIcon into the JBS: directory. */ CopyTheFile( wba->wa_Lock, wba->wa_Name ); } else if ( ! JbIsOpen ) /* * No am_NumArgs? Then we popup * the window if it isn't opened. */ OpenTheWindow(); /* * All that's left is to reply * the message. */ ReplyMsg(( struct Message * )apm ); } AbortTimer(); if ( JbPrinting ) ScanDirectory(); JbJobCan = FALSE; } } } while ( running ); QuitIt: CloseTheWindow(); CxOff( JbBroker ); } /* * Open up the main window and get * the pointer to the userport and * the port it's bit mask. */ void OpenTheWindow( void ) { if ( ! JbIsOpen ) { JbIsOpen = TRUE; if ( SetupScreen()) { CloseTheWindow(); return; } strcpy( JbWTitle, JbName " " JbVersion " : " ); strcat( JbWTitle, JbPopkey ); /* * The GadToolsBox generated source gives me * the possibility to set the window title * at run-time which is done here. */ SpoolWdt = &JbWTitle[ 0 ]; if ( OpenSpoolWindow()) { CloseTheWindow(); return; } SetupDisplay( FALSE ); if ( JbPrinting ) SetupDisplay( TRUE ); JbIdPort = SpoolWnd->UserPort; JbIdMask = ( 1L << JbIdPort->mp_SigBit ); return; } } /* * Close the main window and * clear the userport and bit mask. */ void CloseTheWindow( void ) { if ( JbIsOpen ) { CloseSpoolWindow(); CloseDownScreen(); JbIdPort = NULL; JbIdMask = NULL; JbIsOpen = FALSE; } } /* * Here we get started when called from the Shell. */ void main( long argc, long *array ) { JbArgs = array; SetupSpool(); EventHandler(); CloseDownSpool( NULL ); } /* * Here we get started when called from the workbench. */ void wbmain( struct WBStartup *wbs ) { WbMsg = wbs; SetupSpool(); EventHandler(); CloseDownSpool( NULL ); }