home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / utility / misc / toolmana.lha / ToolManager / Source / library / execobj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-26  |  22.0 KB  |  765 lines

  1. /*
  2.  * execobj.c  V2.0
  3.  *
  4.  * TMObject, Type: Exec
  5.  *
  6.  * (c) 1990-1992 Stefan Becker
  7.  */
  8.  
  9. #include "ToolManagerLib.h"
  10.  
  11. /* extended TMObject structure for TMOBJTYPE_Exec objects */
  12. struct TMObjectExec {
  13.                      struct TMObject    eo_Object;
  14.                      UWORD              eo_Type;
  15.                      UWORD              eo_Flags;
  16.                      char              *eo_Command;
  17.                      char              *eo_CurrentDir;
  18.                      LONG               eo_Delay;
  19.                      char              *eo_HotKey;
  20.                      char              *eo_Output;
  21.                      char              *eo_Path;
  22.                      LONG               eo_Priority;
  23.                      char              *eo_PubScreen;
  24.                      LONG               eo_Stack;
  25.                      CxObj             *eo_CxObj;
  26.                      struct TMLink      eo_Link;
  27.                      struct TMTimerReq  eo_TimerReq;
  28.                     };
  29.  
  30. /* eo_Flags */
  31. #define EO_Arguments (1L<<0)
  32. #define EO_ToFront   (1L<<1)
  33.  
  34. /* Tag to Flag mapping table for PackBoolTags */
  35. static struct TagItem flagmap[]={TMOP_Arguments, EO_Arguments,
  36.                                  TMOP_ToFront,   EO_ToFront,
  37.                                  TAG_DONE};
  38.  
  39. /* Structure for path list */
  40. struct PathList {
  41.                  BPTR NextPath; /* Pointer to next PathList */
  42.                  BPTR PathLock; /* Lock on directory */
  43.                 };
  44.  
  45. /* Create an Exec object */
  46. struct TMObject *CreateTMObjectExec(struct TMHandle *handle, char *name,
  47.                                     struct TagItem *tags)
  48. {
  49.  struct TMObjectExec *tmobj;
  50.  
  51.  /* allocate memory for object */
  52.  if (tmobj=AllocateTMObject(sizeof(struct TMObjectExec))) {
  53.   struct TagItem *ti,*tstate;
  54.   BOOL noerror=TRUE;
  55.  
  56.   /* Set object defaults */
  57.   tmobj->eo_Type=TMET_CLI;
  58.   tmobj->eo_Command=DefaultNoName;
  59.   tmobj->eo_CurrentDir=DefaultDirName;
  60.   tmobj->eo_Output=DefaultOutput;
  61.   tmobj->eo_Stack=4096;
  62.  
  63.   /* Scan tag list */
  64.   tstate=tags;
  65.   while (noerror && (ti=NextTagItem(&tstate))) {
  66.  
  67.    DEBUG_PRINTF("Got Tag (0x%08lx)\n",ti->ti_Tag);
  68.  
  69.    switch (ti->ti_Tag) {
  70.     case TMOP_Command:    {
  71.                            char *s=(char *) ti->ti_Data;
  72.                            if (s) tmobj->eo_Command=s;
  73.                           }
  74.                           break;
  75.     case TMOP_CurrentDir: {
  76.                            char *s=(char *) ti->ti_Data;
  77.                            if (s) tmobj->eo_CurrentDir=s;
  78.                           }
  79.                           break;
  80.     case TMOP_Delay:      tmobj->eo_Delay=ti->ti_Data;
  81.                           break;
  82.     case TMOP_ExecType:   tmobj->eo_Type=ti->ti_Data;
  83.  
  84.                           /* Sanity check */
  85.                           if (tmobj->eo_Type>=TMETYPES) noerror=FALSE;
  86.                           break;
  87.     case TMOP_HotKey:     tmobj->eo_HotKey=(char *) ti->ti_Data;
  88.                           break;
  89.     case TMOP_Output:     {
  90.                            char *s=(char *) ti->ti_Data;
  91.                            if (s) tmobj->eo_Output=s;
  92.                           }
  93.                           break;
  94.     case TMOP_Path:       tmobj->eo_Path=(char *) ti->ti_Data;
  95.                           break;
  96.     case TMOP_Priority:   tmobj->eo_Priority=ti->ti_Data;
  97.                           break;
  98.     case TMOP_PubScreen:  tmobj->eo_PubScreen=(char *) ti->ti_Data;
  99.                           break;
  100.     case TMOP_Stack:      tmobj->eo_Stack=ti->ti_Data;
  101.                           break;
  102.    }
  103.   }
  104.  
  105.   /* No errors? */
  106.   if (noerror) {
  107.    BOOL hotkey=tmobj->eo_HotKey!=NULL;
  108.  
  109.    /* HotKey set? Create Commodities object from HotKey description */
  110.    if  (hotkey && (tmobj->eo_CxObj=HotKey(tmobj->eo_HotKey,BrokerPort,
  111.                                           (ULONG) &tmobj->eo_Link))) {
  112.  
  113.     DEBUG_PRINTF("Created CxObj (0x%08lx)\n",tmobj->eo_CxObj);
  114.  
  115.     /* Attach object to broker */
  116.     AttachCxObj(Broker,tmobj->eo_CxObj);
  117.    }
  118.  
  119.    /* No HotKey or no HotKey error? */
  120.    if (!hotkey || (tmobj->eo_CxObj && !CxObjError(Broker))) {
  121.     /* No. Set flags */
  122.     tmobj->eo_Flags=PackBoolTags(EO_Arguments,tags,flagmap);
  123.  
  124.     /* Initialize rest of structure */
  125.     tmobj->eo_Link.tml_Linked=tmobj;
  126.     tmobj->eo_Link.tml_Active=FALSE;
  127.     tmobj->eo_TimerReq.tmtr_Request=*deftimereq;
  128.     tmobj->eo_TimerReq.tmtr_Link=&tmobj->eo_Link;
  129.  
  130.     /* All OK */
  131.     return(tmobj);
  132.    }
  133.  
  134.    /* Free resources */
  135.    if (tmobj->eo_CxObj) SafeDeleteCxObjAll(tmobj->eo_CxObj,&tmobj->eo_Link);
  136.   }
  137.   FreeMem(tmobj,sizeof(struct TMObjectExec));
  138.  }
  139.  
  140.  /* call failed */
  141.  return(NULL);
  142. }
  143.  
  144. /* Delete an Exec object */
  145. BOOL DeleteTMObjectExec(struct TMObjectExec *tmobj)
  146. {
  147.  DEBUG_PRINTF("Delete/Exec (0x%08lx)\n",tmobj);
  148.  
  149.  /* timer request active? */
  150.  if (tmobj->eo_Link.tml_Active) {
  151.   struct IORequest *tr=&tmobj->eo_TimerReq;
  152.  
  153.   /* If timer request still active, abort it */
  154.   if (!CheckIO(tr)) AbortIO(tr);
  155.  
  156.   /* Remove timer request */
  157.   WaitIO(tr);
  158.   tmobj->eo_Link.tml_Active=FALSE;
  159.  }
  160.  
  161.  /* Remove links */
  162.  DeleteAllLinksTMObject((struct TMObject *) tmobj);
  163.  
  164.  /* Free resources */
  165.  if (tmobj->eo_CxObj) SafeDeleteCxObjAll(tmobj->eo_CxObj,&tmobj->eo_Link);
  166.  
  167.  /* Remove object from list */
  168.  Remove((struct Node *) tmobj);
  169.  
  170.  /* Free object */
  171.  FreeMem(tmobj,sizeof(struct TMObjectExec));
  172.  
  173.  /* All OK. */
  174.  return(TRUE);
  175. }
  176.  
  177. /* Change an Exec object */
  178. struct TMObject *ChangeTMObjectExec(struct TMHandle *handle,
  179.                                     struct TMObjectExec *tmobj,
  180.                                     struct TagItem *tags)
  181. {
  182.  struct TagItem *ti,*tstate;
  183.  
  184.  /* Scan tag list */
  185.  tstate=tags;
  186.  while (ti=NextTagItem(&tstate)) {
  187.  
  188.   DEBUG_PRINTF("Got Tag (0x%08lx)\n",ti->ti_Tag);
  189.  
  190.   switch (ti->ti_Tag) {
  191.    case TMOP_Command:    {
  192.                           char *s=(char *) ti->ti_Data;
  193.                           if (s) tmobj->eo_Command=s;
  194.                          }
  195.                          break;
  196.    case TMOP_CurrentDir: {
  197.                           char *s=(char *) ti->ti_Data;
  198.                           if (s) tmobj->eo_CurrentDir=s;
  199.                          }
  200.                          break;
  201.    case TMOP_Delay:      tmobj->eo_Delay=ti->ti_Data;
  202.                          break;
  203.    case TMOP_ExecType:   /* Sanity check */
  204.                          if ((tmobj->eo_Type>=0) && (tmobj->eo_Type<TMETYPES))
  205.                           tmobj->eo_Type=ti->ti_Data;
  206.                          break;
  207.    case TMOP_HotKey:     if (tmobj->eo_CxObj) {
  208.                           SafeDeleteCxObjAll(tmobj->eo_CxObj,&tmobj->eo_Link);
  209.                           tmobj->eo_CxObj=NULL;
  210.                          }
  211.  
  212.                          tmobj->eo_HotKey=(char *) ti->ti_Data;
  213.                          break;
  214.    case TMOP_Output:     {
  215.                           char *s=(char *) ti->ti_Data;
  216.                           if (s) tmobj->eo_Output=s;
  217.                          }
  218.                          break;
  219.    case TMOP_Path:       tmobj->eo_Path=(char *) ti->ti_Data;
  220.                          break;
  221.    case TMOP_Priority:   tmobj->eo_Priority=ti->ti_Data;
  222.                          break;
  223.    case TMOP_PubScreen:  tmobj->eo_PubScreen=(char *) ti->ti_Data;
  224.                          break;
  225.    case TMOP_Stack:      tmobj->eo_Stack=ti->ti_Data;
  226.                          break;
  227.   }
  228.  }
  229.  
  230.  /* HotKey set? Create Commodities object from HotKey description */
  231.  if  (tmobj->eo_HotKey && !tmobj->eo_CxObj &&
  232.       (tmobj->eo_CxObj=HotKey(tmobj->eo_HotKey,BrokerPort,
  233.                               (ULONG) &tmobj->eo_Link))) {
  234.  
  235.   DEBUG_PRINTF("Created CxObj (0x%08lx)\n",tmobj->eo_CxObj);
  236.  
  237.   /* Attach object to broker */
  238.   AttachCxObj(Broker,tmobj->eo_CxObj);
  239.  
  240.   /* Commodities error? */
  241.   if (CxObjError(Broker)) {
  242.    SafeDeleteCxObjAll(tmobj->eo_CxObj,&tmobj->eo_Link);
  243.    tmobj->eo_CxObj=NULL;
  244.   }
  245.  }
  246.  
  247.  /* Set flags */
  248.  tmobj->eo_Flags=PackBoolTags(tmobj->eo_Flags,tags,flagmap);
  249.  
  250.  /* All OK */
  251.  return(TRUE);
  252. }
  253.  
  254. /* Allocate & Initialize a TMLink structure */
  255. struct TMLink *AllocLinkTMObjectExec(struct TMObjectExec *tmobj)
  256. {
  257.  struct TMLink *tml;
  258.  
  259.  /* Allocate memory for link structure */
  260.  if (tml=AllocMem(sizeof(struct TMLink),MEMF_CLEAR|MEMF_PUBLIC))
  261.   /* Initialize link structure */
  262.   tml->tml_Size=sizeof(struct TMLink);
  263.  
  264.  return(tml);
  265. }
  266.  
  267. /* Copy a path list */
  268. BOOL CopyPathList(struct PathList **pla, struct PathList **plc,
  269.                   struct PathList *oldpl)
  270. {
  271.  struct PathList *pl1=oldpl,*pl2=*plc,*pl3=NULL;
  272.  
  273.  while (pl1) {
  274.   /* Get memory for path list entry */
  275.   if (!(pl3 || (pl3=AllocVec(sizeof(struct PathList),MEMF_PUBLIC|MEMF_CLEAR))))
  276.    return(FALSE); /* No more memory... */
  277.  
  278.   /* Copy path entry */
  279.   if (pl3->PathLock=DupLock(pl1->PathLock)) {
  280.    /* Copy successful, append new entry to list. Head of list? */
  281.    if (*pla)
  282.     pl2->NextPath=MKBADDR(pl3); /* No, append it to list */
  283.    else
  284.     *pla=pl3;                   /* Yes, set list anchor */
  285.  
  286.    /* Save pointer */
  287.    pl2=pl3;
  288.  
  289.    /* Invalidate pointer, next time a new PathList will be allocated */
  290.    pl3=NULL;
  291.   }
  292.  
  293.   /* Get next path list entry */
  294.   pl1=BADDR(pl1->NextPath);
  295.  }
  296.  
  297.  /* Free memory */
  298.  if (pl3) FreeVec(pl3);
  299.  
  300.  /* All OK */
  301.  *plc=pl2; /* Save pointer to new end of list */
  302.  return(TRUE);
  303. }
  304.  
  305. /* Free a path list */
  306. void FreePathList(struct PathList *pla)
  307. {
  308.  /* Check for NULL */
  309.  if (pla) {
  310.   struct PathList *pl1=pla,*pl2;
  311.  
  312.   /* Scan list */
  313.   do {
  314.    /* Get pointer to next entry */
  315.    pl2=BADDR(pl1->NextPath);
  316.  
  317.    /* Free entry */
  318.    UnLock(pl1->PathLock);
  319.    FreeVec(pl1);
  320.   } while (pl1=pl2);
  321.  }
  322. }
  323.  
  324. /* Build a path list from a string */
  325. static BOOL BuildPathList(struct PathList **pla, struct PathList **plc, char *s)
  326. {
  327.  struct FileInfoBlock *fib;
  328.  char *cp1,*cp2=s;
  329.  struct PathList *pl1=*plc,*pl2=NULL;
  330.  
  331.  /* Get memory for FIB */
  332.  if (!(fib=AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)))
  333.   return(FALSE);
  334.  
  335.  /* For every path part */
  336.  while (cp1=cp2) {
  337.   /* Search next path part */
  338.   if (cp2=strchr(cp1,',')) *cp2='\0'; /* Add string end character */
  339.  
  340.   /* Get memory for path list entry */
  341.   if (!(pl2 ||
  342.        (pl2=AllocVec(sizeof(struct PathList),MEMF_PUBLIC|MEMF_CLEAR)))) {
  343.    FreeVec(fib);
  344.    return(FALSE); /* No more memory */
  345.   }
  346.  
  347.   /* Get lock */
  348.   if (pl2->PathLock=Lock(cp1,SHARED_LOCK))
  349.    /* Is it a directory? */
  350.    if (Examine(pl2->PathLock,fib) && (fib->fib_DirEntryType>0)) {
  351.     /* Yes, it is a directory, append it to the list. Head of list? */
  352.     if (*pla)
  353.      pl1->NextPath=MKBADDR(pl2); /* No, append it to list */
  354.     else
  355.      *pla=pl2;                   /* Yes, set list anchor */
  356.  
  357.     /* Save pointer */
  358.     pl1=pl2;
  359.  
  360.     /* Invalidate pointer, next time a new PathList will be allocated */
  361.     pl2=NULL;
  362.    }
  363.    else UnLock(pl2->PathLock); /* No, it is a file */
  364.  
  365.   /* Restore string and move to next character */
  366.   if (cp2) *cp2++=',';
  367.  }
  368.  
  369.  *plc=pl1;              /* Save end of list */
  370.  if (pl2) FreeVec(pl2); /* Last Lock() failed, free memory */
  371.  FreeVec(fib);
  372.  
  373.  /* All OK. */
  374.  return(TRUE);
  375. }
  376.  
  377. #define NAMELEN    256  /* Buffer length for a file name */
  378. #define CMDLINELEN 4096 /* Buffer length for command line */
  379.  
  380. /* Build a CLI or ARexx command line (supports [] argument substitution) */
  381. static ULONG BuildCommandLine(char *buf, char *command, BPTR curdir,
  382.                               struct AppMessage *msg)
  383. {
  384.  ULONG cmdlen;      /* Command line length */
  385.  char *lp;          /* Pointer to current cmdline pos. */
  386.  char *com=command;
  387.  
  388.  /* Copy command name to command line */
  389.  if (lp=strchr(command,'[')) {
  390.   /* [] parameter place holder found, copy first part of command */
  391.   cmdlen=lp-com;
  392.   strncpy(buf,com,cmdlen);
  393.   buf[cmdlen]='\0';
  394.  }
  395.  else {
  396.   strcpy(buf,command); /* No [] parameter place holder */
  397.   cmdlen=strlen(buf);
  398.  }
  399.  lp=buf+cmdlen;
  400.  
  401.  /* Check for arguments */
  402.  if (msg) {
  403.   char *dir; /* Buffer for file names */
  404.  
  405.   /* Get memory for file names */
  406.   if (dir=AllocMem(NAMELEN,MEMF_PUBLIC)) {
  407.    struct WBArg *wa=msg->am_ArgList;  /* Pointer to WBArgs */
  408.    int i;                             /* Counter for WBArgs */
  409.  
  410.    for (i=msg->am_NumArgs; i; i--,wa++) {
  411.     char *name,*space;
  412.     ULONG namelen;
  413.  
  414.     /* Skip args which don't support locks! */
  415.     if (!wa->wa_Lock) continue;
  416.  
  417.     /* Append a space for each parameter */
  418.     if (cmdlen>CMDLINELEN-2) break;
  419.     *lp++=' ';
  420.     cmdlen++;
  421.  
  422.     /* Build parameter from Lock & name */
  423.     DEBUG_PRINTF("wa_Name: 0x%08lx\n",wa->wa_Name);
  424.     DEBUG_PRINTF("wa_Name: '%s'\n",wa->wa_Name);
  425.     if (*(wa->wa_Name)!='\0')
  426.      /* File name --> build complete path name */
  427.      if (SameLock(curdir,wa->wa_Lock)==LOCK_SAME)
  428.       /* File in current directory -> "<file>" */
  429.       name=wa->wa_Name;
  430.      else {
  431.       /* File in other directory -> "<path><seperator><file>" */
  432.       if (!NameFromLock(wa->wa_Lock,dir,NAMELEN)) continue;
  433.       if (!AddPart(dir,wa->wa_Name,NAMELEN)) continue;
  434.       name=dir;
  435.      }
  436.     else {
  437.      /* No file name --> Drawer */
  438.      if (!NameFromLock(wa->wa_Lock,dir,NAMELEN)) continue;
  439.      name=dir;
  440.     }
  441.     namelen=strlen(name);
  442.  
  443.     /* Handle special case: Space in a filename */
  444.     if (space=strchr(name,' ')) namelen+=2;
  445.  
  446.     /* Does parameter fit into commandline? */
  447.     if (cmdlen+namelen>CMDLINELEN-2) break;
  448.  
  449.     if (space) *lp++='"';   /* Quote file name (beginning) */
  450.     strcpy(lp,name);        /* Append parameter */
  451.     lp+=namelen;            /* Correct pointer */
  452.     if (space) {
  453.      lp--;                  /* Correct pointer */
  454.      *(lp-1)='"';           /* Quote file name (end) */
  455.     }
  456.     cmdlen+=namelen;        /* New command line length */
  457.  
  458.     DEBUG_PRINTF("Parameter: '%s'\n",buf);
  459.    }
  460.    FreeMem(dir,NAMELEN);
  461.   }
  462.  }
  463.  
  464.  /* Check for [] parameter place holder, Find closing bracket */
  465.  if ((com=strchr(com,']')) && (cmdlen+strlen(++com)<CMDLINELEN-1)) {
  466.   strcpy(lp,com);   /* Copy second part of command */
  467.   lp=lp+strlen(lp); /* Move to end of string */
  468.  }
  469.  else
  470.   *lp='\0';       /* Set string terminator */
  471.  
  472.  /* Return command line length */
  473.  return(lp-buf);
  474. }
  475.  
  476. /* Start CLI program */
  477. static BOOL StartCLIProgram(struct TMObjectExec *tmobj, struct AppMessage *msg)
  478. {
  479.  char *cmd;     /* Buffer for command line */
  480.  BOOL rc=FALSE;
  481.  
  482.  /* Get memory for command line */
  483.  if (cmd=AllocMem(CMDLINELEN,MEMF_PUBLIC)) {
  484.   BPTR newcd; /* Lock for program's current directory */
  485.  
  486.   if (newcd=Lock(tmobj->eo_CurrentDir,SHARED_LOCK)) {
  487.    BPTR ofh; /* AmigaDOS file handle (output) */
  488.  
  489.    /* Build command line */
  490.    BuildCommandLine(cmd,tmobj->eo_Command,newcd,msg);
  491.  
  492.    /* Open output file */
  493.    if (ofh=Open(tmobj->eo_Output,MODE_NEWFILE)) {
  494.     BPTR ifh; /* AmigaDOS file handle (input) */
  495.     struct MsgPort *newct=NULL;          /* New ConsoleTask pointer */
  496.  
  497.     /* Is the output file an interactive file? */
  498.     if (IsInteractive(ofh)) {
  499.      struct MsgPort *oldct;  /* Old ConsoleTask pointer */
  500.  
  501.      /* Yes. We need the same file as input file for CTRL-C/D/E/F redirection */
  502.      /* Set our ConsoleTask to the new output file, so that we can re-open it */
  503.      newct=((struct FileHandle *) BADDR(ofh))->fh_Type;
  504.      oldct=SetConsoleTask(newct);
  505.  
  506.      /* Open the new input file (Now ifh points to the same file as ofh) */
  507.      ifh=Open("CONSOLE:",MODE_OLDFILE);
  508.  
  509.      /* Change back to old ConsoleTask */
  510.      SetConsoleTask(oldct);
  511.     }
  512.     /* Non-interactive output, open dummy input file */
  513.     else ifh=Open(DefaultOutput,MODE_OLDFILE);
  514.  
  515.     if (ifh) {
  516.      struct PathList *pla=NULL,*plc=NULL;
  517.  
  518.      /* Build path list, local path first, then global path*/
  519.      if (BuildPathList(&pla,&plc,tmobj->eo_Path) &&
  520.          CopyPathList(&pla,&plc,GlobalPath)) {
  521.       BPTR oldcd; /* pointer to old current directory */
  522.  
  523.       /* Go to program's current directory */
  524.       oldcd=CurrentDir(newcd);
  525.  
  526.       /* Start program */
  527.       if (SystemTags(cmd,SYS_Output,     ofh,
  528.                          SYS_Input,      ifh,
  529.                          SYS_Asynch,     TRUE, /* Run program asynchron */
  530.                          SYS_UserShell,  TRUE, /* Use user specified shell */
  531.                          NP_StackSize,   tmobj->eo_Stack,
  532.                          NP_Priority,    tmobj->eo_Priority,
  533.                          NP_Path,        MKBADDR(pla),
  534.                          NP_ConsoleTask, newct,
  535.                          TAG_DONE)!=-1)
  536.        rc=TRUE; /* Program started! */
  537.  
  538.       /* Go back to old current directory */
  539.       CurrentDir(oldcd);
  540.      }
  541.      if (!rc) FreePathList(pla); /* Free path list if program wasn't started */
  542.      if (!rc) Close(ifh); /* Close input file if program wasn't started */
  543.     }
  544.     if (!rc) Close(ofh); /* Close output file if program wasn't started */
  545.    }
  546.    UnLock(newcd);
  547.   }
  548.   FreeMem(cmd,CMDLINELEN);
  549.  }
  550.  return(rc);
  551. }
  552.  
  553. /* Start WB program */
  554. static BOOL StartWBProgram(struct TMObjectExec *tmobj, struct AppMessage *msg)
  555. {
  556.  struct MsgPort *hp;     /* Port of WBStart-Handler */
  557.  struct WBStartMsg wbsm; /* Message for WBStart-Handler */
  558.  BOOL rc=FALSE;
  559.  
  560.  /* Build message for WBStart-Handler */
  561.  wbsm.wbsm_Msg.mn_Node.ln_Pri= 0;
  562.  wbsm.wbsm_Msg.mn_ReplyPort  = DummyPort;
  563.  wbsm.wbsm_Name              = tmobj->eo_Command;
  564.  wbsm.wbsm_DirLock           = Lock(tmobj->eo_CurrentDir,SHARED_LOCK);
  565.  wbsm.wbsm_Stack             = tmobj->eo_Stack;
  566.  wbsm.wbsm_Prio              = tmobj->eo_Priority;
  567.  wbsm.wbsm_NumArgs           = msg ? msg->am_NumArgs : 0;
  568.  wbsm.wbsm_ArgList           = msg ? msg->am_ArgList : 0;
  569.  
  570.  /* Try to send a message to the WBStart-Handler */
  571.  Forbid();
  572.  hp=FindPort(WBS_PORTNAME);
  573.  if (hp) PutMsg(hp,(struct Message *) &wbsm);
  574.  Permit();
  575.  
  576.  /* No WBStart-Handler, try to start it! */
  577.  if (!hp) {
  578.   BPTR ifh;
  579.  
  580.   if (ifh=Open(DefaultOutput,MODE_NEWFILE)) {
  581.    BPTR ofh;
  582.  
  583.    if (ofh=Open(DefaultOutput,MODE_OLDFILE))
  584.     /* Start handler */
  585.     if (SystemTags(WBS_LOADNAME,SYS_Input,ifh,
  586.                                 SYS_Output,ofh,
  587.                                 SYS_Asynch,TRUE,
  588.                                 SYS_UserShell,TRUE,
  589.                                 NP_ConsoleTask,NULL,
  590.                                 NP_WindowPtr,NULL,
  591.                                 TAG_DONE) != -1) {
  592.      int i;
  593.  
  594.      /* Handler started, try to send message (Retry up to 5 seconds) */
  595.      for (i=0; i<10; i++) {
  596.       /* Try to send message */
  597.       Forbid();
  598.       hp=FindPort(WBS_PORTNAME);
  599.       if (hp) PutMsg(hp,(struct Message *) &wbsm);
  600.       Permit();
  601.  
  602.       /* Message sent? Yes, leave loop */
  603.       if (hp) break;
  604.  
  605.       /* No, wait 1/2 second */
  606.       Delay(25);
  607.      }
  608.     }
  609.     /* Handler not started, close file handles */
  610.     else {
  611.      Close(ofh);
  612.      Close(ifh);
  613.     }
  614.    else Close(ifh);
  615.   }
  616.  }
  617.  
  618.  /* Could we send the message? */
  619.  if (hp) {
  620.   /* Get reply message */
  621.   WaitPort(DummyPort);
  622.   GetMsg(DummyPort);
  623.   rc=wbsm.wbsm_Stack; /* Has tool been started? */
  624.   DEBUG_PRINTF("Return Code %ld\n",rc);
  625.  }
  626.  
  627.  /* Free lock */
  628.  if (wbsm.wbsm_DirLock) UnLock(wbsm.wbsm_DirLock);
  629.  
  630.  return(rc);
  631. }
  632.  
  633. /* Start ARexx program */
  634. static BOOL StartARexxProgram(struct TMObjectExec *tmobj,
  635.                               struct AppMessage *msg)
  636. {
  637.  char *cmd;     /* Buffer for command line */
  638.  BOOL rc=FALSE;
  639.  
  640.  /* Get memory for command line */
  641.  if (cmd=AllocMem(CMDLINELEN,MEMF_PUBLIC)) {
  642.   BPTR newcd; /* Lock for program's current directory */
  643.  
  644.   if (newcd=Lock(tmobj->eo_CurrentDir,SHARED_LOCK)) {
  645.    ULONG cmdlen; /* Command line length */
  646.    BPTR oldcd;   /* Lock for old current directory */
  647.  
  648.    /* Build command line */
  649.    cmdlen=BuildCommandLine(cmd,tmobj->eo_Command,newcd,msg);
  650.  
  651.    /* Go to program's current directory */
  652.    oldcd=CurrentDir(newcd);
  653.  
  654.    /* Send ARexx command */
  655.    rc=SendARexxCommand(cmd,cmdlen);
  656.  
  657.    /* Go back to old current directory */
  658.    CurrentDir(oldcd);
  659.    UnLock(newcd);
  660.   }
  661.   FreeMem(cmd,CMDLINELEN);
  662.  }
  663.  return(rc);
  664. }
  665.  
  666. /* Start program */
  667. static void StartProgram(struct TMObjectExec *tmobj, struct AppMessage *msg)
  668. {
  669.  struct AppMessage *args=(tmobj->eo_Flags & EO_Arguments) ? msg : NULL;
  670.  BOOL rc=FALSE;
  671.  
  672.  /* Check for command */
  673.  if (!tmobj->eo_Command) return; /* Nothing to do */
  674.  
  675.  /* Check for ToFront flag */
  676.  if (tmobj->eo_Flags & EO_ToFront) {
  677.   /* Move screen to front */
  678.   struct Screen *s=LockPubScreen(tmobj->eo_PubScreen);
  679.  
  680.   if (s) {
  681.    ScreenToFront(s);
  682.    UnlockPubScreen(NULL,s);
  683.   }
  684.  }
  685.  
  686.  /* Check for program type */
  687.  switch (tmobj->eo_Type) {
  688.   case TMET_CLI:  rc=StartCLIProgram(tmobj,args);
  689.                   break;
  690.   case TMET_WB:   rc=StartWBProgram(tmobj,args);
  691.                   break;
  692.   case TMET_ARexx:rc=StartARexxProgram(tmobj,args);
  693.                   break;
  694.   case TMET_Hook: {
  695.                    struct Hook *hook=(struct Hook *) tmobj->eo_Command;
  696.                    BOOL (*Entry)(__A0 struct Hook *, __A1 struct AppMessage *,
  697.                                  __A2 void *)=hook->h_Entry;
  698.  
  699.                    /* Call hook function. Calling conventions:          */
  700.                    /* A0 (hook)   : pointer to hook structure           */
  701.                    /* A1 (message): pointer to AppMessage (may be NULL) */
  702.                    /* A2 (object) : value of hook->h_Data               */
  703.                    /* Return Code : BOOL, FALSE for failure             */
  704.                    rc=Entry(hook,args,hook->h_Data);
  705.                   }
  706.                   break;
  707.  }
  708.  
  709.  /* Error? */
  710.  if (!rc) DisplayBeep(NULL);
  711. }
  712.  
  713. /* Send timer request */
  714. static void SendTimerRequest(struct TMObjectExec *tmobj)
  715. {
  716.  struct timerequest *tr=&tmobj->eo_TimerReq;
  717.  
  718.  /* Initialize timer request */
  719.  tr->tr_node.io_Command=TR_ADDREQUEST;
  720.  tr->tr_time.tv_secs=labs(tmobj->eo_Delay);
  721.  tr->tr_time.tv_micro=0;
  722.  
  723.  /* Send timer request */
  724.  SendIO((struct IORequest *) tr);
  725.  tmobj->eo_Link.tml_Active=(void *) TRUE;
  726. }
  727.  
  728. /* Activate an Exec object */
  729. void ActivateTMObjectExec(struct TMLink *tml, struct AppMessage *msg)
  730. {
  731.  struct TMObjectExec *tmobj=tml->tml_Linked;
  732.  
  733.  DEBUG_PRINTF("Activate/Exec (0x%08lx)\n",msg);
  734.  
  735.  /* Is timer active? */
  736.  if (tmobj->eo_Link.tml_Active) {
  737.   /* Yes. a) got timer event, b) user wants to stop last request */
  738.   struct IORequest *tr=&tmobj->eo_TimerReq;
  739.  
  740.   /* Check timer request */
  741.   if (CheckIO(tr)) {
  742.    /* a) Timer event finished, remove it. */
  743.    WaitIO(tr);
  744.    tmobj->eo_Link.tml_Active=FALSE;
  745.  
  746.    /* Start program, no arguments */
  747.    StartProgram(tmobj,NULL);
  748.  
  749.    /* repeat event? */
  750.    if (tmobj->eo_Delay<0) SendTimerRequest(tmobj);
  751.   }
  752.   else {
  753.    /* b) user wants to stop last request, abort it */
  754.    AbortIO(tr);
  755.    WaitIO(tr);
  756.    tmobj->eo_Link.tml_Active=FALSE;
  757.   }
  758.  }
  759.  /* Timer not active, start program or time request */
  760.  else if (tmobj->eo_Delay!=0) SendTimerRequest(tmobj);
  761.  
  762.  /* Start program */
  763.  else StartProgram(tmobj,msg);
  764. }
  765.