home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 550b.lha / Term_v1.8a / Source.LZH / termAux.c < prev    next >
C/C++ Source or Header  |  1991-07-20  |  49KB  |  2,493 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1990 by Olaf 'Olsen' Barthel & MXM
  4.  *
  5.  *    Name .....: TermAux.c
  6.  *    Created ..: Monday 21-Jan-91 20:12
  7.  *    Revision .: 0
  8.  *
  9.  *    Date            Author          Comment
  10.  *    =========       ========        ====================
  11.  *    21-Jan-91       Olsen           Created this file!
  12.  *
  13.  * $Revision Header ********************************************************/
  14.  
  15. #include "TermGlobal.h"
  16.  
  17.     /* The following static strings are displayed in the status
  18.      * window.
  19.      */
  20.  
  21. STATIC UBYTE *ConfigFont[2] =
  22. {
  23.     "Topaz",
  24.     "IBM  "
  25. };
  26.  
  27. STATIC UBYTE *ConfigEmulation[3] =
  28. {
  29.     "ANSI/VT",
  30.     "Atomic ",
  31.     "TTY    "
  32. };
  33.  
  34. STATIC UBYTE *ConfigParity[5] =
  35. {
  36.     "None",
  37.     "Even",
  38.     "Odd ",
  39.     "Mark",
  40.     "Spac"
  41. };
  42.  
  43. STATIC UBYTE *ConfigStatus[7] =
  44. {
  45.     "Ready   ",
  46.     "Holding ",
  47.     "Dialing ",
  48.     "Upload  ",
  49.     "Download",
  50.     "Breaking",
  51.     "Hang Up "
  52. };
  53.  
  54.     /* Block window nest count. */
  55.  
  56. STATIC SHORT BlockNestCount;
  57.  
  58.     /* GetConUnit():
  59.      *
  60.      *    Extract the ConUnit pointer from the current output stream
  61.      *    console.
  62.      */
  63.  
  64. struct ConUnit *
  65. GetConUnit(struct MsgPort *ConsoleTask)
  66. {
  67.     struct InfoData    *InfoData;
  68.     struct ConUnit    *ConUnit = NULL;
  69.  
  70.     if(!ConsoleTask)
  71.         ConsoleTask = (struct MsgPort *)((struct Process *)SysBase -> ThisTask) -> pr_ConsoleTask;
  72.  
  73.     if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR))
  74.     {
  75.             /* Send the inquiry packet to the console task. */
  76.  
  77.         if(DoPkt1(ConsoleTask,ACTION_DISK_INFO,MKBADDR(InfoData)))
  78.             ConUnit = (struct ConUnit *)((struct IOStdReq *)InfoData -> id_InUse) -> io_Unit;
  79.  
  80.         FreeVec(InfoData);
  81.     }
  82.  
  83.     return(ConUnit);
  84. }
  85.  
  86.     /* AddDownloadObject(UBYTE *Line):
  87.      *
  88.      *    Add another downloaded object to the list.
  89.      */
  90.  
  91. VOID
  92. AddDownloadObject(UBYTE *Line)
  93. {
  94.     struct Node *SomeNode;
  95.  
  96.         /* Allocate space for the node itself and the
  97.          * string to be put into the node name.
  98.          */
  99.  
  100.     if(SomeNode = (struct Node *)AllocVec(sizeof(struct Node) + strlen(Line) + 1,MEMF_PUBLIC|MEMF_CLEAR))
  101.     {
  102.             /* Block list modification. */
  103.  
  104.         ObtainSemaphore(DownloadSemaphore);
  105.  
  106.             /* Enter the name. */
  107.  
  108.         SomeNode -> ln_Name = (UBYTE *)(SomeNode + 1);
  109.  
  110.             /* Copy the line over. */
  111.  
  112.         strcpy(SomeNode -> ln_Name,Line);
  113.  
  114.             /* Add it to the list. */
  115.  
  116.         AddTail(&DownloadList,SomeNode);
  117.  
  118.             /* Increment number of downloads. */
  119.  
  120.         DownloadLineCount++;
  121.  
  122.         ReleaseSemaphore(DownloadSemaphore);
  123.     }
  124. }
  125.  
  126.     /* ClearDownloadObjects():
  127.      *
  128.      *    Clear the list of downloaded objects.
  129.      */
  130.  
  131. VOID
  132. ClearDownloadObjects()
  133. {
  134.     struct Node *SomeNode,*NextNode;
  135.  
  136.     ObtainSemaphore(DownloadSemaphore);
  137.  
  138.     SomeNode = DownloadList . lh_Head;
  139.  
  140.     while(SomeNode -> ln_Succ)
  141.     {
  142.         NextNode = SomeNode -> ln_Succ;
  143.  
  144.         Remove(SomeNode);
  145.  
  146.         FreeVec(SomeNode);
  147.  
  148.         SomeNode = NextNode;
  149.     }
  150.  
  151.     DownloadNode = NULL;
  152.  
  153.     DownloadLineCount = 0;
  154.  
  155.     ReleaseSemaphore(DownloadSemaphore);
  156. }
  157.  
  158.     /* SequenceFilter(UBYTE Char):
  159.      *
  160.      *    Yet another byte sequence filter, this time it's the
  161.      *    ARexx interface to make the call.
  162.      */
  163.  
  164. struct ScanNode *
  165. SequenceFilter(UBYTE Char)
  166. {
  167.     struct ScanNode    *SomeNode,*Matching = NULL;
  168.     BYTE         Matches = 0;
  169.  
  170.         /* Convert input character to upper case. */
  171.  
  172.     Char = ToUpper(Char);
  173.  
  174.         /* Get the first node in the list. */
  175.  
  176.     SomeNode = (struct ScanNode *)SequenceList . lh_Head;
  177.  
  178.         /* Scan until the last node is found. */
  179.  
  180.     while(SomeNode -> Node . mln_Succ)
  181.     {
  182.             /* This sequence had a couple of matches. */
  183.  
  184.         if(SomeNode -> Count == SequenceCount)
  185.         {
  186.                 /* The next character in the sequence
  187.                  * still matches.
  188.                  */
  189.  
  190.             if(Char == SomeNode -> Sequence[SequenceCount])
  191.             {
  192.                     /* Increase number of matching
  193.                      * characters.
  194.                      */
  195.  
  196.                 SomeNode -> Count++;
  197.  
  198.                     /* If there's another character
  199.                      * in the sequence, increase
  200.                      * the match counter.
  201.                      */
  202.  
  203.                 if(SomeNode -> Sequence[SequenceCount + 1])
  204.                     Matches++;
  205.                 else
  206.                 {
  207.                         /* We were able to make
  208.                          * a perfect match.
  209.                          */
  210.  
  211.                     Matches = 0;
  212.  
  213.                     Matching = SomeNode;
  214.                 }
  215.             }
  216.         }
  217.  
  218.             /* Skip to the next node. */
  219.  
  220.         SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
  221.     }
  222.  
  223.     if(!Matches)
  224.     {
  225.             /* Clear the list entry counters. */
  226.  
  227.         if(SequenceCount)
  228.         {
  229.             SomeNode = (struct ScanNode *)SequenceList . lh_Head;
  230.  
  231.             while(SomeNode -> Node . mln_Succ)
  232.             {
  233.                 SomeNode -> Count = 0;
  234.  
  235.                 SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
  236.             }
  237.  
  238.             SequenceCount = 0;
  239.         }
  240.     }
  241.     else
  242.         SequenceCount++;
  243.  
  244.     return(Matching);
  245. }
  246.  
  247.     /* AddSequenceObject(UBYTE *Sequence):
  248.      *
  249.      *    Add another sequence to the list of byte sequences
  250.      *    the routine above will look at whilst parsing.
  251.      */
  252.  
  253. VOID
  254. AddSequenceObject(UBYTE *Sequence)
  255. {
  256.     struct ScanNode *SomeNode;
  257.  
  258.     if(SomeNode = AllocVec(sizeof(struct ScanNode) + strlen(Sequence) + 1,MEMF_PUBLIC|MEMF_CLEAR))
  259.     {
  260.         SHORT i;
  261.  
  262.         SomeNode -> Sequence = (UBYTE *)(SomeNode + 1);
  263.  
  264.         for(i = 0 ; i <= strlen(Sequence) ; i++)
  265.             SomeNode -> Sequence[i] = ToUpper(Sequence[i]);
  266.  
  267.         AddTail(&SequenceList,(struct Node *)SomeNode);
  268.     }
  269. }
  270.  
  271.     /* ClearSequenceObjects():
  272.      *
  273.      *    Clear the list of scan sequences.
  274.      */
  275.  
  276. VOID
  277. ClearSequenceObjects()
  278. {
  279.     struct Node *SomeNode,*NextNode;
  280.  
  281.     SomeNode = SequenceList . lh_Head;
  282.  
  283.     while(SomeNode -> ln_Succ)
  284.     {
  285.         NextNode = SomeNode -> ln_Succ;
  286.  
  287.         Remove(SomeNode);
  288.  
  289.         FreeVec(SomeNode);
  290.  
  291.         SomeNode = NextNode;
  292.     }
  293. }
  294.  
  295.     /* LogAction(UBYTE *String,...):
  296.      *
  297.      *    Write an action to the default log file.
  298.      */
  299.  
  300. VOID __stdargs
  301. LogAction(UBYTE *String,...)
  302. {
  303.     if(Config . LogActions && Config . LogFile[0])
  304.     {
  305.         UBYTE    DummyBuffer[256];
  306.         BPTR    File;
  307.  
  308.         va_list    VarArgs;
  309.  
  310.             /* Build a valid string. */
  311.  
  312.         va_start(VarArgs,String);
  313.         VSPrintf(DummyBuffer,String,VarArgs);
  314.         va_end(VarArgs);
  315.  
  316.             /* Does the log file already exist? */
  317.  
  318.         if(GetFileSize(Config . LogFile))
  319.         {
  320.                 /* It does, let's append the data. */
  321.  
  322.             if(File = Open(Config . LogFile,MODE_READWRITE))
  323.             {
  324.                 if(Seek(File,0,OFFSET_END) == -1)
  325.                 {
  326.                     Close(File);
  327.  
  328.                     File = NULL;
  329.                 }
  330.             }
  331.         }
  332.         else
  333.         {
  334.                 /* Create a new file. */
  335.  
  336.             if(File = Open(Config . LogFile,MODE_NEWFILE))
  337.                 FPrintf(File,"Date      Time     Action\n--------- -------- ----------------------------------------\n");
  338.         }
  339.  
  340.             /* The file is open, build the date/time string and
  341.              * write the log action.
  342.              */
  343.  
  344.         if(File)
  345.         {
  346.             UBYTE        TimeBuffer[20],DateBuffer[20];
  347.             struct DateTime    DateTime;
  348.  
  349.                 /* Obtain current time. */
  350.  
  351.             DateStamp(&DateTime . dat_Stamp);
  352.  
  353.                 /* Convert it to human readable form. */
  354.  
  355.             DateTime . dat_Format    = FORMAT_DOS;
  356.             DateTime . dat_Flags    = 0;
  357.             DateTime . dat_StrDay    = NULL;
  358.             DateTime . dat_StrDate    = DateBuffer;
  359.             DateTime . dat_StrTime    = TimeBuffer;
  360.  
  361.                 /* Conversion succeeded? */
  362.  
  363.             if(DateToStr(&DateTime))
  364.                 FPrintf(File,"%s %s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
  365.  
  366.                 /* Done! */
  367.  
  368.             Close(File);
  369.         }
  370.     }
  371. }
  372.  
  373.     /* FlushMsg(struct Window *Window):
  374.      *
  375.      *    Cancel all pending messages of a window.
  376.      */
  377.  
  378. VOID
  379. FlushMsg(struct Window *Window)
  380. {
  381.     struct IntuiMessage *Massage;
  382.  
  383.     while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  384.         ReplyMsg(&Massage -> ExecMessage);
  385. }
  386.  
  387.     /* Local2Upper(UBYTE c):
  388.      *
  389.      *    Very much the same as the macro expression ToUpper, but
  390.      *    more suitable for expressions such as `ToUpper(*a++)'.
  391.      */
  392.  
  393. UBYTE
  394. Local2Upper(UBYTE c)
  395. {
  396.     return((UBYTE)((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : (c)));
  397. }
  398.  
  399.     /* GetString(UBYTE *Prompt,UBYTE *Buffer):
  400.      *
  401.      *    Get a string from the user, very much the same as xpr_gets,
  402.      *    but also including the `Load File' gadget.
  403.      */
  404.  
  405. BYTE
  406. GetString(UBYTE *Prompt,UBYTE *Buffer)
  407. {
  408.     struct Gadget        *GadgetList;
  409.     struct Gadget        *GadgetArray[4];
  410.     struct Window        *PanelWindow;
  411.     struct Menu        *PanelMenu;
  412.     UBYTE             DummyBuffer[256];
  413.     struct FileRequester    *FileRequest;
  414.     LONG             Width;
  415.     BYTE             Success = FALSE;
  416.  
  417.     STATIC struct NewMenu GetStringMenu[] =
  418.     {
  419.         { NM_TITLE, "Project",         0 , 0, 0, (APTR)0},
  420.         {  NM_ITEM, "Okay",        "O", 0, 0, (APTR)1},
  421.         {  NM_ITEM, "Cancel",        "C", 0, 0, (APTR)3},
  422.         {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  423.         {  NM_ITEM, "Load File...",    "L", 0, 0, (APTR)2},
  424.         {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  425.         {  NM_ITEM, "Quit",        "Q", 0, 0, (APTR)3},
  426.         { NM_END, 0,             0 , 0, 0, (APTR)0}
  427.     };
  428.  
  429.     if(CreateAllGetsGadgets(TRUE,Buffer,Prompt,&Width,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1))
  430.     {
  431.         if(PanelMenu = CreateMenus(GetStringMenu,
  432.             GTMN_FrontPen, 0,
  433.         TAG_DONE))
  434.         {
  435.             if(LayoutMenus(PanelMenu,VisualInfo,
  436.                 GTMN_TextAttr,&DefaultFont,
  437.             TAG_DONE))
  438.             {
  439.                 if(PanelWindow = OpenWindowTags(NULL,
  440.                     WA_Width,    Width,
  441.                     WA_Height,    56,
  442.                     WA_Left,    (Screen -> Width - Width) >> 1,
  443.                     WA_Top,        (Screen -> Height - 56) >> 1,
  444.                     WA_Activate,    TRUE,
  445.                     WA_DragBar,    TRUE,
  446.                     WA_DepthGadget,    TRUE,
  447.                     WA_CloseGadget,    TRUE,
  448.                     WA_RMBTrap,    TRUE,
  449.                     WA_CustomScreen,Screen,
  450.                     WA_IDCMP,    IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_MENUPICK | IDCMP_RAWKEY,
  451.                     WA_Title,    "Enter A String",
  452.                 TAG_DONE))
  453.                 {
  454.                     struct IntuiMessage    *Massage;
  455.                     ULONG             Class,Code;
  456.                     struct Gadget        *Gadget;
  457.                     BYTE             Terminated = FALSE;
  458.  
  459.                     PushWindow(PanelWindow);
  460.  
  461.                     SetMenuStrip(PanelWindow,PanelMenu);
  462.  
  463.                     PanelWindow -> Flags &= ~WFLG_RMBTRAP;
  464.  
  465.                     AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
  466.                     RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
  467.                     GT_RefreshWindow(PanelWindow,NULL);
  468.  
  469.                     ActiveGadget = GadgetArray[0];
  470.  
  471.                     ActivateGadget(GadgetArray[0],PanelWindow,NULL);
  472.  
  473.                     while(!Terminated)
  474.                     {
  475.                         WaitPort(PanelWindow -> UserPort);
  476.  
  477.                         while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
  478.                         {
  479.                             Class    = Massage -> Class;
  480.                             Code    = Massage -> Code;
  481.                             Gadget    = (struct Gadget *)Massage -> IAddress;
  482.  
  483.                             GT_ReplyIMsg(Massage);
  484.  
  485.                             if(Class == IDCMP_GADGETDOWN)
  486.                             {
  487.                                 if((Gadget -> GadgetType & GTYP_GTYPEMASK) == STRGADGET)
  488.                                     ActiveGadget = Gadget;
  489.                             }
  490.  
  491.                             if(Class == IDCMP_RAWKEY)
  492.                             {
  493.                                 if(Code == IECODE_UP_PREFIX|103 && CommandWindow == PanelWindow)
  494.                                     ActivateGadget(CommandGadget,PanelWindow,NULL);
  495.                             }
  496.  
  497.                             if(Class == IDCMP_ACTIVEWINDOW)
  498.                                 ActivateGadget(GadgetArray[0],PanelWindow,NULL);
  499.  
  500.                             if(Class == IDCMP_MENUPICK)
  501.                             {
  502.                                 struct MenuItem *MenuItem;
  503.  
  504.                                 while(Code != MENUNULL)
  505.                                 {
  506.                                     MenuItem = ItemAddress(PanelMenu,Code);
  507.  
  508.                                     switch((ULONG)MENU_USERDATA(MenuItem))
  509.                                     {
  510.                                         case 3:            Class = IDCMP_CLOSEWINDOW;
  511.                                                     break;
  512.  
  513.                                         case 1:            strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
  514.  
  515.                                                     Success = TRUE;
  516.  
  517.                                                     Terminated = TRUE;
  518.                                                     break;
  519.  
  520.                                         case 2:            GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
  521.                                                         GA_Disabled,TRUE,
  522.                                                     TAG_DONE);
  523.  
  524.                                                     SetWait(PanelWindow);
  525.  
  526.                                                     PanelWindow -> Flags |= WFLG_RMBTRAP;
  527.  
  528.                                                     if(FileRequest = GetFile("Load File...","","",DummyBuffer,NULL,FALSE,FALSE))
  529.                                                     {
  530.                                                         GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
  531.                                                             GTST_String,DummyBuffer,
  532.                                                         TAG_DONE);
  533.  
  534.                                                         RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
  535.  
  536.                                                         FreeAslRequest(FileRequest);
  537.                                                     }
  538.  
  539.                                                     GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
  540.                                                         GA_Disabled,FALSE,
  541.                                                     TAG_DONE);
  542.  
  543.                                                     ClearPointer(PanelWindow);
  544.  
  545.                                                     PanelWindow -> Flags &= ~WFLG_RMBTRAP;
  546.                                                     break;
  547.                                     }
  548.  
  549.                                     Code = MenuItem -> NextSelect;
  550.                                 }
  551.  
  552.                                 if(ActiveGadget)
  553.                                     ActivateGadget(ActiveGadget,PanelWindow,NULL);
  554.                             }
  555.  
  556.                             if(Class == IDCMP_CLOSEWINDOW)
  557.                                 Terminated = TRUE;
  558.  
  559.                             if(Class == IDCMP_GADGETUP)
  560.                             {
  561.                                 if(!DontActivate)
  562.                                 {
  563.                                     switch(Gadget -> GadgetID)
  564.                                     {
  565.                                         case 0:
  566.                                         case 1:    strcpy(Buffer,((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer);
  567.  
  568.                                             Success = TRUE;
  569.  
  570.                                             Terminated = TRUE;
  571.                                             break;
  572.  
  573.                                         case 2:    GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
  574.                                                         GA_Disabled,TRUE,
  575.                                                     TAG_DONE);
  576.                                             SetWait(PanelWindow);
  577.  
  578.                                             PanelWindow -> Flags |= WFLG_RMBTRAP;
  579.  
  580.                                             if(FileRequest = GetFile("Load File...","","",DummyBuffer,NULL,FALSE,FALSE))
  581.                                             {
  582.                                                 strcpy(((struct StringInfo *)GadgetArray[0] -> SpecialInfo) -> Buffer,DummyBuffer);
  583.  
  584.                                                 RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
  585.  
  586.                                                 FreeAslRequest(FileRequest);
  587.                                             }
  588.  
  589.                                             OnGadget(GadgetArray[0],PanelWindow,NULL);
  590.                                             ClearPointer(PanelWindow);
  591.  
  592.                                             PanelWindow -> Flags &= ~WFLG_RMBTRAP;
  593.                                             break;
  594.  
  595.                                         case 3:    Terminated = TRUE;
  596.                                             break;
  597.                                     }
  598.                                 }
  599.                                 else
  600.                                     DontActivate = FALSE;
  601.                             }
  602.                         }
  603.                     }
  604.  
  605.                     PanelWindow -> Flags |= WFLG_RMBTRAP;
  606.  
  607.                     ClearMenuStrip(PanelWindow);
  608.  
  609.                     RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
  610.  
  611.                     PopWindow();
  612.  
  613.                     CloseWindow(PanelWindow);
  614.                 }
  615.  
  616.                 FreeGadgets(GadgetList);
  617.             }
  618.  
  619.             FreeMenus(PanelMenu);
  620.         }
  621.     }
  622.  
  623.     return(Success);
  624. }
  625.  
  626.     /* WakeUp(struct Window *Window):
  627.      *
  628.      *    Pop a window to the front and alert the user.
  629.      */
  630.  
  631. VOID
  632. WakeUp(struct Window *Window)
  633. {
  634.     if(Window)
  635.         BumpWindow(Window);
  636.  
  637.     Beep();
  638.  
  639.     WaitTime(2,0);
  640. /*
  641.     Beep();
  642.  
  643.     WaitTime(0,MILLION / 4);
  644.  
  645.     Beep();
  646.  
  647.     WaitTime(0,MILLION / 4);*/
  648. }
  649.  
  650.     /* SendAmigaDOSCommand(UBYTE *Name):
  651.      *
  652.      *    Let the current default Shell execute an AmigaDOS
  653.      *    command. Block until the command has returned.
  654.      */
  655.  
  656. VOID
  657. SendAmigaDOSCommand(UBYTE *Name)
  658. {
  659.     BYTE DummyBuffer[2];
  660.     BPTR File;
  661.  
  662.         /* Let the asynchronous Rexx server pick up and process
  663.          * all incoming messages rather than sending them to the
  664.          * main process (hopefully avoids deadlock situations).
  665.          */
  666.  
  667.     BatchMode = TRUE;
  668.  
  669.         /* Open the console window or whatever the user
  670.          * wants us to open here.
  671.          */
  672.  
  673.     if(File = Open(WindowName,MODE_NEWFILE))
  674.     {
  675.         ULONG         Tags[3];
  676.         struct ConUnit    *ConUnit = GetConUnit(((struct FileHandle *)BADDR(File)) -> fh_Type);
  677.  
  678.         Tags[0] = SYS_Output;
  679.         Tags[1] = (ULONG)File;
  680.         Tags[2] = TAG_DONE;
  681.  
  682.         if(ConUnit)
  683.         {
  684.             if(ConUnit -> cu_Window)
  685.                 BumpWindow(ConUnit -> cu_Window);
  686.         }
  687.  
  688.             /* Make the Shell execute the command. */
  689.  
  690. /*        SystemTags(Name,SYS_Output,File,TAG_DONE);*/
  691.  
  692.         System(Name,(APTR)&Tags[0]);
  693.  
  694.             /* Wait for some impressive user action. */
  695.  
  696.         Write(File,"Press \33[1mRETURN\33[0m or close window to continue. ",51);
  697.  
  698.         Read(File,DummyBuffer,1);
  699.  
  700.         Close(File);
  701.     }
  702.  
  703.         /* Bring the `term' main screen to the front and
  704.          * fall back into asynchronous Rexx message processing.
  705.          */
  706.  
  707.     BumpWindow(Window);
  708.  
  709.     BatchMode = FALSE;
  710. }
  711.  
  712.     /* RexxBackgroundServer():
  713.      *
  714.      *    The background process to handle the rexx
  715.      *    massaging.
  716.      */
  717.  
  718. VOID __saveds
  719. RexxBackgroundServer()
  720. {
  721.     BPTR         OldCOS,OldCIS,NewCOS,NewCIS;
  722.     struct MsgPort    *OldConsoleTask,*ReplyPort;
  723.  
  724.     BYTE         DummyBuffer[2];
  725.  
  726.     struct RexxMsg    *RexxMsg;
  727.  
  728.     struct Process    *BackgroundProcess;
  729.     struct Message    *SetupMsg;
  730.  
  731.         /* Look who we are. */
  732.  
  733.     BackgroundProcess = (struct Process *)SysBase -> ThisTask;
  734.  
  735.         /* Wait for startup message. */
  736.  
  737.     WaitPort(&BackgroundProcess -> pr_MsgPort);
  738.  
  739.         /* Pick the message up. */
  740.  
  741.     SetupMsg = GetMsg(&BackgroundProcess -> pr_MsgPort);
  742.  
  743.         /* Create a reply port the Rexx message is to
  744.          * return to after processing.
  745.          */
  746.  
  747.     if(ReplyPort = (struct MsgPort *)CreateMsgPort())
  748.     {
  749.             /* Remember previous I/O streams and
  750.              * console handler.
  751.              */
  752.  
  753.         OldCOS        = BackgroundProcess -> pr_COS;
  754.         OldCIS        = BackgroundProcess -> pr_CIS;
  755.  
  756.         OldConsoleTask    = BackgroundProcess -> pr_ConsoleTask;
  757.  
  758.             /* The following lines perform an `almost illegal'
  759.              * action: new console I/O streams are opened for
  760.              * the `term' main process. This is due to a rather
  761.              * helpful Rexx server feature. Errors, messages
  762.              * and other data are sent to the current output
  763.              * stream.
  764.              */
  765.  
  766.         if(NewCIS = Open(WindowName,MODE_NEWFILE))
  767.         {
  768.             struct FileHandle    *FileHandle = (struct FileHandle *)BADDR(NewCIS);
  769.             struct ConUnit        *ConUnit = GetConUnit(((struct FileHandle *)BADDR(NewCIS)) -> fh_Type);
  770.  
  771.                 /* Lock until we're done with the forgery. */
  772.  
  773.             Forbid();
  774.  
  775.             BackgroundProcess -> pr_ConsoleTask    = (APTR)FileHandle -> fh_Type;
  776.  
  777.             BackgroundProcess -> pr_CIS        = NewCIS;
  778.             BackgroundProcess -> pr_COS        = NewCOS = Open("*",MODE_NEWFILE);
  779.  
  780.             Permit();
  781.  
  782.             RexxWindow = NULL;
  783.  
  784.             if(ConUnit)
  785.             {
  786.                 if(RexxWindow = ConUnit -> cu_Window)
  787.                     BumpWindow(RexxWindow);
  788.             }
  789.  
  790.                 /* Send the command and wait for a reply. */
  791.  
  792.             if(SendRexxCommand(ReplyPort,SetupMsg -> mn_Node . ln_Name,NULL,NULL))
  793.             {
  794.                 ULONG SignalSet;
  795.  
  796.                 SignalSet = Wait((1 << ReplyPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
  797.  
  798.                 if(SignalSet & SIGBREAKF_CTRL_C)
  799.                     Signal(ThisProcess,SIGBREAKF_CTRL_D);
  800.  
  801.                 if(!(SignalSet & (1 << ReplyPort -> mp_SigBit)))
  802.                     Wait(1 << ReplyPort -> mp_SigBit);
  803.  
  804.                     /* Pick up the RexxMsg (SendRexxCommand
  805.                      * had allocated it for us) and
  806.                      * examine the return codes.
  807.                      */
  808.  
  809.                 if(RexxMsg = (struct RexxMsg *)GetMsg(ReplyPort))
  810.                 {
  811.                     if(!ExitQuietly)
  812.                     {
  813.                         /* This doesn't look too
  814.                          * good, does it?
  815.                          */
  816.  
  817.                         if(RexxMsg -> rm_Result1)
  818.                             FPrintf(NewCIS,"\nCommand \"%s\" has terminated with code %ld, %ld.\n",SetupMsg -> mn_Node . ln_Name,RexxMsg -> rm_Result1,RexxMsg -> rm_Result2);
  819.  
  820.                         /* Show our hand and return
  821.                          * to the usual business.
  822.                          */
  823.  
  824.                         Write(BackgroundProcess -> pr_COS,"Press \33[1mRETURN\33[0m or close window to continue. ",51);
  825.  
  826.                         Rexx2Front();
  827.  
  828.                         Read(NewCIS,DummyBuffer,1);
  829.  
  830.                         Term2Front();
  831.                     }
  832.                     else
  833.                         ExitQuietly = FALSE;
  834.  
  835.                         /* Release the message. */
  836.  
  837.                     FreeRexxCommand(RexxMsg);
  838.                 }
  839.             }
  840.  
  841.             Forbid();
  842.  
  843.             RexxWindow = NULL;
  844.  
  845.             Permit();
  846.  
  847.             BumpWindow(Window);
  848.  
  849.                 /* Close our fake I/O streams. */
  850.  
  851.             Forbid();
  852.  
  853.             Close(NewCIS);
  854.             Close(NewCOS);
  855.  
  856.                 /* And install the previous pointers. */
  857.  
  858.             BackgroundProcess -> pr_ConsoleTask    = (APTR)OldConsoleTask;
  859.  
  860.             BackgroundProcess -> pr_CIS        = OldCIS;
  861.             BackgroundProcess -> pr_COS        = OldCOS;
  862.  
  863.             Permit();
  864.         }
  865.  
  866.             /* Remove the reply port. */
  867.  
  868.         DeleteMsgPort(ReplyPort);
  869.     }
  870.  
  871.         /* We are done, lock and reply the message causing the
  872.          * main process to return to the input loop.
  873.          */
  874.  
  875.     Forbid();
  876.  
  877.     ReplyMsg(SetupMsg);
  878. }
  879.  
  880.     /* SendARexxCommand(UBYTE *Name):
  881.      *
  882.      *    Let the ARexx server execute a command (or a script
  883.      *    file if necessary) and block until the command
  884.      *    has returned.
  885.      */
  886.  
  887. VOID
  888. SendARexxCommand(UBYTE *Name)
  889. {
  890.     struct Process    *BackgroundProcess;
  891.     struct Message    *SetupMsg;
  892.     struct MsgPort    *ReplyPort;
  893.  
  894.     ULONG         SignalSet;
  895.  
  896.         /* Create a reply port for the info message. */
  897.  
  898.     if(ReplyPort = CreateMsgPort())
  899.     {
  900.             /* Allocate the message body. */
  901.  
  902.         if(SetupMsg = (struct Message *)AllocVec(sizeof(struct Message),MEMF_PUBLIC|MEMF_CLEAR))
  903.         {
  904.                 /* Set up the message itself. */
  905.  
  906.             SetupMsg -> mn_Node . ln_Name    = Name;
  907.             SetupMsg -> mn_ReplyPort    = ReplyPort;
  908.             SetupMsg -> mn_Length        = sizeof(struct Message);
  909.  
  910.                 /* Create the background process which will
  911.                  * handle all the messy rexx message sending
  912.                  * for us.
  913.                  */
  914.  
  915.             if(BackgroundProcess = (struct Process *)CreateNewProcTags(
  916.                 NP_Entry,    RexxBackgroundServer,
  917.                 NP_Name,    "term Rexx Background Process",
  918.                 NP_StackSize,    16384,
  919.             TAG_END))
  920.             {
  921.                 SetSignal(0,SIGBREAKF_CTRL_D);
  922.  
  923.                     /* Send the startup message. */
  924.  
  925.                 PutMsg(&BackgroundProcess -> pr_MsgPort,SetupMsg);
  926.  
  927.                     /* Go into loop and wait for the
  928.                      * background process to return.
  929.                      */
  930.  
  931.                 FOREVER
  932.                 {
  933.                     SignalSet = Wait(SIG_REXX | (1 << ReplyPort -> mp_SigBit));
  934.  
  935.                         /* Yet another rexx message. */
  936.  
  937.                     if(SignalSet & SIG_REXX)
  938.                         HandleRexx();
  939.  
  940.                         /* The background server has
  941.                          * finished.
  942.                          */
  943.  
  944.                     if(SignalSet & (1 << ReplyPort -> mp_SigBit))
  945.                         break;
  946.                 }
  947.  
  948.                 SetSignal(0,SIGBREAKF_CTRL_D);
  949.             }
  950.  
  951.                 /* Free the message. */
  952.  
  953.             FreeVec(SetupMsg);
  954.         }
  955.  
  956.             /* Delete the reply port. */
  957.  
  958.         DeleteMsgPort(ReplyPort);
  959.     }
  960. }
  961.  
  962.     /* ahtoi(UBYTE *String):
  963.      *
  964.      *    Turn a hexadecimal string into an integer (borrowed from
  965.      *    Matt Dillon's dmouse.c).
  966.      */
  967.  
  968. LONG
  969. ahtoi(UBYTE *String)
  970. {
  971.     LONG Value = 0;
  972.     UBYTE c;
  973.  
  974.     while(c = *String)
  975.     {
  976.         Value <<= 4;
  977.  
  978.         if(c >= '0' && c <= '9')
  979.             Value |= (c & 15);
  980.         else
  981.             Value |= (c & 15) + 9;
  982.  
  983.         ++String;
  984.     }
  985.  
  986.     return(Value);
  987. }
  988.  
  989.     /* BlockWindows():
  990.      *
  991.      *    Block the main window and the status window (i.e. disable
  992.      *    the menu and attach a wait pointer).
  993.      */
  994.  
  995. VOID
  996. BlockWindows()
  997. {
  998.     if(!(BlockNestCount++))
  999.     {
  1000.         SetWait(Window);
  1001.         SetWait(StatusWindow);
  1002.  
  1003.         if(PacketWindow)
  1004.         {
  1005.             SetWait(PacketWindow);
  1006.  
  1007.             PacketWindow -> Flags |= WFLG_RMBTRAP;
  1008.  
  1009.             GT_SetGadgetAttrs(PacketGadgetArray[0],PacketWindow,NULL,
  1010.                 GA_Disabled,TRUE,
  1011.             TAG_DONE);
  1012.         }
  1013.  
  1014.         Window        -> Flags |= WFLG_RMBTRAP;
  1015.         StatusWindow    -> Flags |= WFLG_RMBTRAP;
  1016.  
  1017.         WeAreBlocking = TRUE;
  1018.     }
  1019. }
  1020.  
  1021.     /* ReleaseWindows():
  1022.      *
  1023.      *    Reenable the menus and clear the wait pointer.
  1024.      */
  1025.  
  1026. VOID
  1027. ReleaseWindows()
  1028. {
  1029.     if(!(--BlockNestCount))
  1030.     {
  1031.         Window        -> Flags &= ~WFLG_RMBTRAP;
  1032.         StatusWindow    -> Flags &= ~WFLG_RMBTRAP;
  1033.  
  1034.         ClearPointer(Window);
  1035.         ClearPointer(StatusWindow);
  1036.  
  1037.         if(PacketWindow)
  1038.         {
  1039.             PacketWindow -> Flags &= ~WFLG_RMBTRAP;
  1040.  
  1041.             ClearPointer(PacketWindow);
  1042.  
  1043.             OnGadget(PacketGadgetArray[0],PacketWindow,NULL);
  1044.         }
  1045.  
  1046.         FlushMsg(Window);
  1047.  
  1048.         WeAreBlocking = FALSE;
  1049.     }
  1050. }
  1051.  
  1052.     /* LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars):
  1053.      *
  1054.      *    Read a few bytes from a file (à la gets).
  1055.      */
  1056.  
  1057. BYTE
  1058. LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars)
  1059. {
  1060.     STATIC UBYTE Data[1024];
  1061.     STATIC LONG RIdx = 0,RLen = 0;
  1062.  
  1063.     LONG i;
  1064.  
  1065.     if(File)
  1066.     {
  1067.         for(i = 0 ; i < MaxChars ; i++)
  1068.         {
  1069.             if(RIdx >= RLen)
  1070.             {
  1071.                 RLen = Read(File,Data,1024);
  1072.  
  1073.                 RIdx = 0;
  1074.  
  1075.                 if(RLen <= 0)
  1076.                 {
  1077.                     Buffer[i] = 0;
  1078.                     return(FALSE);
  1079.                 }
  1080.             }
  1081.  
  1082.             if((Buffer[i] = Data[RIdx]) != '\r')
  1083.             {
  1084.                 if(Data[RIdx++] == '\n')
  1085.                 {
  1086.                     Buffer[i + 1] = 0;
  1087.                     break;
  1088.                 }
  1089.             }
  1090.         }
  1091.     }
  1092.     else
  1093.         RIdx = RLen = 0;
  1094.  
  1095.     return(TRUE);
  1096. }
  1097.  
  1098.     /* FlowInit():
  1099.      *
  1100.      *    Set up the data flow parser. The parser scans the serial
  1101.      *    output data for more or less interesting modem output
  1102.      *    (carrier lost, connect, etc.).
  1103.      */
  1104.  
  1105. VOID
  1106. FlowInit()
  1107. {
  1108.     FlowInfo . Changed = FALSE;
  1109.  
  1110.     FlowInfo . NoCarrier = FlowInfo . ZModemUpload = FlowInfo . Connect = FlowInfo . Voice = FlowInfo . Ring = FlowInfo . Busy = FALSE;
  1111.  
  1112.     AttentionBuffers[0] = Config . NoCarrier;
  1113.     AttentionBuffers[1] = Config . Ring;
  1114.     AttentionBuffers[2] = Config . Voice;
  1115.     AttentionBuffers[3] = "*B01";
  1116.     AttentionBuffers[4] = "**B01";
  1117.     AttentionBuffers[5] = Config . Connect;
  1118.     AttentionBuffers[6] = Config . Busy;
  1119.  
  1120.     FlowCount = 0;
  1121.  
  1122.     memset(&AttentionCount[0],0,7);
  1123.  
  1124.     BaudPending = FALSE;
  1125.  
  1126.     FullCheck = FALSE;
  1127. }
  1128.  
  1129.     /* FlowFilter(UBYTE Char):
  1130.      *
  1131.      *    Send a character through the data flow parser and look
  1132.      *    if it's part of a modem message.
  1133.      */
  1134.  
  1135. VOID
  1136. FlowFilter(UBYTE Char)
  1137. {
  1138.     STATIC BYTE IgnoreChar;
  1139.     BYTE i,Matches = 0,Start,End,WasOnline = Online;
  1140.  
  1141.         /* Full data check is a lot slower than looking for
  1142.          * just a single sequence (such as the `CONNECT'
  1143.          * below). This mode is reserved for the dial panel.
  1144.          */
  1145.  
  1146.     if(FullCheck)
  1147.     {
  1148.         Start    = 1;
  1149.         End    = 7;
  1150.     }
  1151.     else
  1152.     {
  1153.         Start    = 0;
  1154.  
  1155.         if(UsesZModem)
  1156.             End = 5;
  1157.         else
  1158.             End = 3;
  1159.     }
  1160.  
  1161.         /* We already got a `CONNECT' and the
  1162.          * `connect auto-baud' feature is enabled.
  1163.          * Continue scanning the serial output
  1164.          * data for the actual baud rate.
  1165.          */
  1166.  
  1167.     if(BaudPending)
  1168.     {
  1169.         if(Char >= '0' && Char <= '9')
  1170.         {
  1171.             BaudBuffer[BaudCount++] = Char;
  1172.  
  1173.             if(IgnoreChar)
  1174.                 IgnoreChar = 0;
  1175.         }
  1176.         else
  1177.         {
  1178.                 /* The scanner has found a
  1179.                  * non-numerical character.
  1180.                  * This is either a blank
  1181.                  * space or something else.
  1182.                  * The latter tells us
  1183.                  * that the baud rate has
  1184.                  * been identified and is
  1185.                  * ready to be used.
  1186.                  */
  1187.  
  1188.             if(Char != IgnoreChar)
  1189.             {
  1190.                 BaudBuffer[BaudCount] = 0;
  1191.  
  1192.                 BaudPending = FALSE;
  1193.             }
  1194.         }
  1195.     }
  1196.  
  1197.     if(!BaudPending)
  1198.     {
  1199.             /* Scan all ID strings for matches. */
  1200.  
  1201.         for(i = Start ; i < End ; i++)
  1202.         {
  1203.                 /* This sequence is a probable
  1204.                  * match.
  1205.                  */
  1206.  
  1207.             if(AttentionCount[i] == FlowCount)
  1208.             {
  1209.                     /* Does the character
  1210.                      * fit into the sequence?
  1211.                      */
  1212.  
  1213.                 if(Char == AttentionBuffers[i][FlowCount])
  1214.                 {
  1215.                         /* Increment the
  1216.                          * number of matching
  1217.                          * characters in this
  1218.                          * sequence.
  1219.                          */
  1220.  
  1221.                     AttentionCount[i]++;
  1222.  
  1223.                         /* Did we hit the
  1224.                          * last character
  1225.                          * in the sequence?
  1226.                          */
  1227.  
  1228.                     if(AttentionBuffers[i][FlowCount + 1])
  1229.                         Matches++;
  1230.                     else
  1231.                     {
  1232.                         Matches = 0;
  1233.  
  1234.                             /* We've got a valid
  1235.                              * sequence, now look
  1236.                              * which flags to change.
  1237.                              */
  1238.  
  1239.                         switch(i)
  1240.                         {
  1241.                                 /* We got a `no carrier' message. */
  1242.  
  1243.                             case 0:    if(!FlowInfo . NoCarrier)
  1244.                                 {
  1245.                                     FlowInfo . NoCarrier    = TRUE;
  1246.                                     FlowInfo . Changed    = TRUE;
  1247.                                 }
  1248.  
  1249.                                 Online = FALSE;
  1250.  
  1251.                                     /* Clear the password. */
  1252.  
  1253.                                 Password[0] = 0;
  1254.  
  1255.                                 if(WasOnline)
  1256.                                 {
  1257.                                     if(CurrentPay)
  1258.                                         LogAction("Carrier lost (cost %ld.%02ld).",CurrentPay / 100,CurrentPay % 100);
  1259.                                     else
  1260.                                         LogAction("Carrier lost.");
  1261.  
  1262.                                     Say("Carrier lost.");
  1263.                                 }
  1264.                                 break;
  1265.  
  1266.                                 /* Got a voice call. */
  1267.  
  1268.                             case 1:    if(!FlowInfo . Voice)
  1269.                                 {
  1270.                                     FlowInfo . Voice    = TRUE;
  1271.                                     FlowInfo . Changed    = TRUE;
  1272.                                 }
  1273.                                 break;
  1274.  
  1275.                                 /* Got another call. */
  1276.  
  1277.                             case 2:    if(!FlowInfo . Ring)
  1278.                                 {
  1279.                                     FlowInfo . Ring        = TRUE;
  1280.                                     FlowInfo . Changed    = TRUE;
  1281.                                 }
  1282.                                 break;
  1283.  
  1284.                             case 3:
  1285.                             case 4:    if(!FlowInfo . ZModemUpload)
  1286.                                 {
  1287.                                     FlowInfo . ZModemUpload    = TRUE;
  1288.                                     FlowInfo . Changed    = TRUE;
  1289.                                 }
  1290.                                 break;
  1291.  
  1292.                                 /* Got a connect message. */
  1293.  
  1294.                             case 5:    if(!FlowInfo . Connect)
  1295.                                 {
  1296.                                     FlowInfo . Connect    = TRUE;
  1297.                                     FlowInfo . Changed    = TRUE;
  1298.                                 }
  1299.  
  1300.                                 if(Config . ConnectAutoBaud)
  1301.                                 {
  1302.                                     BaudBuffer[0] = 0;
  1303.  
  1304.                                     BaudPending = TRUE;
  1305.                                     BaudCount = 0;
  1306.  
  1307.                                     IgnoreChar = ' ';
  1308.                                 }
  1309.  
  1310.                                 break;
  1311.  
  1312.                                 /* Line is busy. */
  1313.  
  1314.                             case 6:    if(!FlowInfo . Busy)
  1315.                                 {
  1316.                                     FlowInfo . Busy        = TRUE;
  1317.                                     FlowInfo . Changed    = TRUE;
  1318.                                 }
  1319.                                 break;
  1320.                         }
  1321.                     }
  1322.                 }
  1323.             }
  1324.         }
  1325.  
  1326.             /* We've got a good match (recognized
  1327.              * a sequence, so reset the data flow
  1328.              * scanner.
  1329.              */
  1330.  
  1331.         if(!Matches)
  1332.         {
  1333.             if(FlowCount)
  1334.             {
  1335.                 FlowCount = 0;
  1336.  
  1337.                 memset(&AttentionCount[0],0,7);
  1338.             }
  1339.         }
  1340.         else
  1341.             FlowCount++;
  1342.     }
  1343.     else
  1344.     {
  1345.             /* This checks for just a single sequence:
  1346.              * the notorious `NO CARRIER'.
  1347.              */
  1348.  
  1349.         if(AttentionCount[0] == FlowCount)
  1350.         {
  1351.             if(Char == AttentionBuffers[0][FlowCount])
  1352.             {
  1353.                 AttentionCount[0]++;
  1354.  
  1355.                 if(AttentionBuffers[0][FlowCount + 1])
  1356.                     Matches++;
  1357.                 else
  1358.                 {
  1359.                     Matches = 0;
  1360.  
  1361.                     if(!FlowInfo . NoCarrier)
  1362.                     {
  1363.                         FlowInfo . NoCarrier    = TRUE;
  1364.                         FlowInfo . Changed    = TRUE;
  1365.                     }
  1366.  
  1367.                     Online = FALSE;
  1368.  
  1369.                         /* Clear the password. */
  1370.  
  1371.                     Password[0] = 0;
  1372.  
  1373.                     if(WasOnline)
  1374.                     {
  1375.                         if(CurrentPay)
  1376.                             LogAction("Carrier lost (cost %ld.%02ld).",CurrentPay / 100,CurrentPay % 100);
  1377.                         else
  1378.                             LogAction("Carrier lost.");
  1379.  
  1380.                         Say("Carrier lost.");
  1381.                     }
  1382.                 }
  1383.             }
  1384.         }
  1385.  
  1386.         if(!Matches)
  1387.         {
  1388.             if(FlowCount)
  1389.             {
  1390.                 FlowCount = 0;
  1391.  
  1392.                 memset(&AttentionCount[0],0,7);
  1393.             }
  1394.         }
  1395.         else
  1396.             FlowCount++;
  1397.     }
  1398. }
  1399.  
  1400.     /* LoadMacros(UBYTE *Name,struct MacroKeys *Keys):
  1401.      *
  1402.      *    Load the keyboard macros from a file.
  1403.      */
  1404.  
  1405. BYTE
  1406. LoadMacros(UBYTE *Name,struct MacroKeys *Keys)
  1407. {
  1408.     struct IFFHandle    *Handle;
  1409.     BYTE             Success = FALSE;
  1410.     struct StoredProperty    *Prop;
  1411.     struct TermInfo        *TermInfo;
  1412.  
  1413.     if(Handle = AllocIFF())
  1414.     {
  1415.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  1416.         {
  1417.             InitIFFasDOS(Handle);
  1418.  
  1419.             if(!OpenIFF(Handle,IFFF_READ))
  1420.             {
  1421.                 /* Collect version number ID if
  1422.                  * available.
  1423.                  */
  1424.  
  1425.                 if(!PropChunks(Handle,&VersionProps[0],1))
  1426.                 {
  1427.                     /* The following line tells iffparse to stop at the
  1428.                      * very beginning of a `Type' chunk contained in a
  1429.                      * `TERM' FORM chunk.
  1430.                      */
  1431.  
  1432.                     if(!StopChunk(Handle,'TERM','KEYS'))
  1433.                     {
  1434.                         /* Parse the file... */
  1435.  
  1436.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  1437.                         {
  1438.                             /* Did we get a version ID? */
  1439.  
  1440.                             if(Prop = FindProp(Handle,'TERM','VERS'))
  1441.                             {
  1442.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  1443.  
  1444.                                 /* Is it the file format we are able
  1445.                                  * to read?
  1446.                                  */
  1447.  
  1448.                                 if(TermInfo -> Version == TermVersion && TermInfo -> Revision <= TermRevision && TermInfo -> Revision >= 6)
  1449.                                 {
  1450.                                     /* The file read pointer is positioned
  1451.                                      * just in front of the first data
  1452.                                      * to be read, so let's don't disappoint
  1453.                                      * iffparse and read it.
  1454.                                      */
  1455.  
  1456.                                     if(ReadChunkBytes(Handle,Keys,sizeof(struct MacroKeys)) == sizeof(struct MacroKeys))
  1457.                                         Success = TRUE;
  1458.                                 }
  1459.                                 else
  1460.                                 {
  1461.                                         /* Probably an older revision. */
  1462.  
  1463.                                     if(TermInfo -> Version == 1 && TermInfo -> Revision < 6)
  1464.                                     {
  1465.                                         memset(Keys,0,sizeof(struct MacroKeys));
  1466.  
  1467.                                         if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  1468.                                             Success = TRUE;
  1469.                                     }
  1470.                                 }
  1471.                             }
  1472.                             else
  1473.                             {
  1474.                                     /* File was created by WriteIFFData previous
  1475.                                      * to revision 1.4.
  1476.                                      */
  1477.  
  1478.                                 memset(Keys,0,sizeof(struct MacroKeys));
  1479.  
  1480.                                 if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  1481.                                     Success = TRUE;
  1482.                             }
  1483.                         }
  1484.                     }
  1485.                 }
  1486.  
  1487.                 CloseIFF(Handle);
  1488.             }
  1489.  
  1490.             Close(Handle -> iff_Stream);
  1491.         }
  1492.  
  1493.         FreeIFF(Handle);
  1494.     }
  1495.  
  1496.     return(Success);
  1497. }
  1498.  
  1499.     /* FindThisItem(ULONG MenuID):
  1500.      *
  1501.      *    Scan the main menu for a menuitem associated with a
  1502.      *    menu ID.
  1503.      */
  1504.  
  1505. struct MenuItem *
  1506. FindThisItem(ULONG MenuID)
  1507. {
  1508.     struct Menu    *FirstMenu;
  1509.     struct MenuItem    *FirstItem;
  1510.  
  1511.     for(FirstMenu = Menu ; FirstMenu -> NextMenu ; FirstMenu = FirstMenu -> NextMenu)
  1512.     {
  1513.         for(FirstItem = FirstMenu -> FirstItem ; FirstItem -> NextItem ; FirstItem = FirstItem -> NextItem)
  1514.         {
  1515.             if((ULONG)GTMENUITEM_USERDATA(FirstItem) == MenuID)
  1516.                 return(FirstItem);
  1517.         }
  1518.     }
  1519.  
  1520.     return(NULL);
  1521. }
  1522.  
  1523.     /* GetFileSize(UBYTE *Name):
  1524.      *
  1525.      *    Simple routine to return the size of a file in
  1526.      *    bytes.
  1527.      */
  1528.  
  1529. LONG
  1530. GetFileSize(UBYTE *Name)
  1531. {
  1532.     struct FileInfoBlock    *FileInfo;
  1533.     BPTR             FileLock;
  1534.     LONG             FileSize = 0;
  1535.  
  1536.     if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
  1537.     {
  1538.         if(FileLock = Lock(Name,ACCESS_READ))
  1539.         {
  1540.             if(Examine(FileLock,FileInfo))
  1541.                 FileSize = FileInfo -> fib_Size;
  1542.  
  1543.             UnLock(FileLock);
  1544.         }
  1545.  
  1546.         FreeMem(FileInfo,sizeof(struct FileInfoBlock));
  1547.     }
  1548.  
  1549.     return(FileSize);
  1550. }
  1551.  
  1552.     /* StrCmp(UBYTE *a,UBYTE *b):
  1553.      *
  1554.      *    Perform case insensitive string comparison. I know
  1555.      *    that Stricmp in utility.library handles the same
  1556.      *    job, but by the time I had spread calls to this
  1557.      *    routine across a number of modules I lost interest
  1558.      *    in changing the call.
  1559.      */
  1560.  
  1561. LONG
  1562. StrCmp(UBYTE *a,UBYTE *b)
  1563. {
  1564.     for( ; Local2Upper(*a) == Local2Upper(*b) ; a++, b++)
  1565.     {
  1566.         if(!(*a))
  1567.             return(0);
  1568.     }
  1569.  
  1570.     return((LONG)(Local2Upper(*a) - Local2Upper(*b)));
  1571. }
  1572.  
  1573.     /* GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect):
  1574.      *
  1575.      *    Call the asl.library file requester to select a single or
  1576.      *    a couple of files.
  1577.      */
  1578.  
  1579. struct FileRequester *
  1580. GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect)
  1581. {
  1582.     struct FileRequester    *AslFileRequest;
  1583.     BYTE             Result = FALSE;
  1584.     LONG             Flags;
  1585.  
  1586.     STATIC UBYTE         DirBuffer[256];
  1587.  
  1588.         /* We use this tag array to remember the size and
  1589.          * position of the asl requester window.
  1590.          */
  1591.  
  1592.     STATIC struct {
  1593.         ULONG Tag1,    LeftEdge;
  1594.         ULONG Tag2,    TopEdge;
  1595.         ULONG Tag3,    Width;
  1596.         ULONG Tag4,    Height;
  1597.         ULONG Tag5;
  1598.     } Dims = {
  1599.         ASL_LeftEdge,    0,
  1600.         ASL_TopEdge,    0,
  1601.         ASL_Width,    0,
  1602.         ASL_Height,    0,
  1603.         TAG_DONE
  1604.     };
  1605.  
  1606.         /* Empty directory string? Revert to the last directory
  1607.          * name.
  1608.          */
  1609.  
  1610.     if(!Directory[0])
  1611.         Directory = DirBuffer;
  1612.  
  1613.         /* If a wildcard pattern is required, add a gadget
  1614.          * to display it.
  1615.          */
  1616.  
  1617.     if(Pattern)
  1618.     {
  1619.         Flags = FILF_PATGAD;
  1620.  
  1621.         if(!Pattern[0])
  1622.             Pattern = "#?";
  1623.     }
  1624.     else
  1625.     {
  1626.         Flags = 0;
  1627.  
  1628.         Pattern = "#?";
  1629.     }
  1630.  
  1631.         /* Set the save flag if we are about to save something. */
  1632.  
  1633.     if(SaveFlag)
  1634.         Flags |= FILF_SAVE;
  1635.  
  1636.         /* Set the multiselect bit if multiple files are
  1637.          * to be selected (e.g. for batch file upload).
  1638.          */
  1639.  
  1640.     if(MultiSelect)
  1641.         Flags |= FILF_MULTISELECT;
  1642.  
  1643.         /* Allocate the asl.library directory requester
  1644.          * and display it.
  1645.          */
  1646.  
  1647.     if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  1648.         ASL_Window,    Window,
  1649.         ASL_File,    Name,
  1650.         ASL_Dir,    Directory,
  1651.         ASL_Hail,    Title,
  1652.         ASL_FuncFlags,    Flags,
  1653.         ASL_Pattern,    Pattern,
  1654.         ASL_OKText,    SaveFlag ? "Save" : "Open",
  1655.     Dims . Width ? TAG_MORE : TAG_END,&Dims))
  1656.     {
  1657.         if(AslRequestTags(AslFileRequest,TAG_DONE))
  1658.         {
  1659.             Dims . LeftEdge    = AslFileRequest -> rf_LeftEdge;
  1660.             Dims . TopEdge    = AslFileRequest -> rf_TopEdge;
  1661.             Dims . Width    = AslFileRequest -> rf_Width;
  1662.             Dims . Height    = AslFileRequest -> rf_Height;
  1663.  
  1664.                 /* Do we have a valid file name? */
  1665.  
  1666.             if(AslFileRequest -> rf_File[0])
  1667.             {
  1668.                     /* Build a legal path/file string. */
  1669.  
  1670.                 strcpy(Buffer,AslFileRequest -> rf_Dir);
  1671.  
  1672.                 AddPart((UBYTE *)Buffer,(UBYTE *)AslFileRequest -> rf_File,256);
  1673.  
  1674.                 Result = TRUE;
  1675.  
  1676.                 strcpy(DirBuffer,AslFileRequest -> rf_Dir);
  1677.             }
  1678.         }
  1679.     }
  1680.  
  1681.         /* We didn't get a file, no need to keep the
  1682.          * file requester.
  1683.          */
  1684.  
  1685.     if(!Result && AslFileRequest)
  1686.     {
  1687.         FreeAslRequest(AslFileRequest);
  1688.         return(NULL);
  1689.     }
  1690.     else
  1691.         return(AslFileRequest);
  1692. }
  1693.  
  1694.     /* MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...):
  1695.      *
  1696.      *    Really quite simple varargs version of Intuition's
  1697.      *    EasyRequest requester.
  1698.      */
  1699.  
  1700. SHORT __stdargs
  1701. MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...)
  1702. {
  1703.     struct EasyStruct    Easy;
  1704.     SHORT            Result;
  1705.     ULONG            IDCMP = NULL;
  1706.     va_list             VarArgs;
  1707.  
  1708.         /* Standard data. */
  1709.  
  1710.     Easy . es_StructSize    = sizeof(struct EasyStruct);
  1711.     Easy . es_Flags        = NULL;
  1712.     Easy . es_Title        = (UBYTE *)"term Request";
  1713.     Easy . es_TextFormat    = (UBYTE *)Text;
  1714.     Easy . es_GadgetFormat    = (UBYTE *)Gadgets;
  1715.  
  1716.         /* Use the argument array to build the
  1717.          * requester and display it.
  1718.          */
  1719.  
  1720.     va_start(VarArgs,Gadgets);
  1721.     Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs);
  1722.     va_end(VarArgs);
  1723.  
  1724.     return(Result);
  1725. }
  1726.  
  1727.     /* A handy positioning macro. */
  1728.  
  1729. #define MoveItem(X,Y) Move(RPort,((11 + X * 20) * 8) + ((Screen -> Width - 640) >> 1),2 + 6 + Y * 8)
  1730.  
  1731.     /* StatusServer():
  1732.      *
  1733.      *    Asynchronous task to continuosly display the current
  1734.      *    terminal settings.
  1735.      */
  1736.  
  1737. VOID __saveds
  1738. StatusServer()
  1739. {
  1740.     struct RastPort        *RPort = StatusWindow -> RPort;
  1741.     UBYTE             Buffer[20];
  1742.  
  1743.     struct timerequest    *TimeRequest;
  1744.     struct MsgPort        *TimePort;
  1745.  
  1746.     struct timeval         OnlineTime;
  1747.     BYTE             GotOnline = FALSE;
  1748.  
  1749.     BYTE             KeepGoing = TRUE;
  1750.  
  1751.     BYTE             LastFont = -1;
  1752.     BYTE             LastEmulation = -1;
  1753.  
  1754.     BYTE             LastProtocol[40],ProtocolBuffer[10],i;
  1755.  
  1756.     LONG             LastBaud = -1;
  1757.     BYTE             LastBitsPerChar = -1;
  1758.     BYTE             LastParity = -1;
  1759.     BYTE             LastStopBits = -1;
  1760.  
  1761.     BYTE             LastStatus = -1;
  1762.  
  1763.     LONG             SecCount;
  1764.     BYTE             FlagBit;
  1765.  
  1766.     LONG             ThisHour,ThisMinute,TestTime;
  1767.  
  1768.     BYTE             FlashIt = FALSE;
  1769.  
  1770.     LastProtocol[0] = 0;
  1771.  
  1772.         /* Create a timer device request. */
  1773.  
  1774.     if(TimePort = (struct MsgPort *)CreateMsgPort())
  1775.     {
  1776.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  1777.         {
  1778.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
  1779.             {
  1780.                     /* Signal our father process
  1781.                      * that we're running.
  1782.                      */
  1783.  
  1784.                 Signal(ThisProcess,SIGBREAKF_CTRL_C);
  1785.  
  1786.                 MoveItem(3,1);
  1787.                 Print("00:00:00");
  1788.  
  1789.                     /* Keep on displaying. */
  1790.  
  1791.                 while(KeepGoing)
  1792.                 {
  1793.                         /* Are we to quit? */
  1794.  
  1795.                     if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
  1796.                     {
  1797.                         KeepGoing = FALSE;
  1798.  
  1799.                         SetSignal(0,SIGBREAKF_CTRL_C);
  1800.                     }
  1801.  
  1802.                         /* Get the current time. */
  1803.  
  1804.                     TimeRequest -> tr_node . io_Command = TR_GETSYSTIME;
  1805.                     DoIO(TimeRequest);
  1806.  
  1807.                         /* A connection has just
  1808.                          * been established.
  1809.                          */
  1810.  
  1811.                     if(Online && !GotOnline)
  1812.                     {
  1813.                         OnlineTime = TimeRequest -> tr_time;
  1814.  
  1815.                         GotOnline = TRUE;
  1816.  
  1817.                         SecCount = 0;
  1818.  
  1819.                         FlagBit = FALSE;
  1820.                     }
  1821.  
  1822.                         /* Print the current time. */
  1823.  
  1824.                     ThisHour    = (TimeRequest -> tr_time . tv_secs % 86400) / 3600;
  1825.                     ThisMinute    = (TimeRequest -> tr_time . tv_secs % 3600) / 60;
  1826.  
  1827.                     SPrintf(Buffer,"%02ld:%02ld:%02ld",ThisHour,ThisMinute,TimeRequest -> tr_time . tv_secs % 60);
  1828.  
  1829.                     MoveItem(3,0);
  1830.                     Print(Buffer);
  1831.  
  1832.                     if(Online)
  1833.                     {
  1834.                         struct timeval TempTime;
  1835.  
  1836.                         if(PayPerUnit[0] || PayPerUnit[1])
  1837.                         {
  1838.                             TestTime = ThisHour * 6 + ThisMinute / 10;
  1839.  
  1840.                             if(TestTime >= TimeOfDay[0] && TestTime <= TimeOfDay[1])
  1841.                                 PreferredTime = 0;
  1842.                             else
  1843.                             {
  1844.                                 if(TestTime >= TimeOfDay[1] && TestTime <= TimeOfDay[0])
  1845.                                     PreferredTime = 1;
  1846.                                 else
  1847.                                 {
  1848.                                     if(TestTime >= TimeOfDay[0] && TestTime >= TimeOfDay[1])
  1849.                                     {
  1850.                                         if(TimeOfDay[0] > TimeOfDay[1])
  1851.                                             PreferredTime = 0;
  1852.                                         else
  1853.                                             PreferredTime = 1;
  1854.                                     }
  1855.                                     else
  1856.                                     {
  1857.                                         if(TestTime <= TimeOfDay[0] && TestTime <= TimeOfDay[1])
  1858.                                         {
  1859.                                             if(TimeOfDay[0] > TimeOfDay[1])
  1860.                                                 PreferredTime = 0;
  1861.                                             else
  1862.                                                 PreferredTime = 1;
  1863.                                         }
  1864.                                     }
  1865.                                 }
  1866.                             }
  1867.  
  1868.                             if(!CurrentPay)
  1869.                                 CurrentPay = PayPerUnit[PreferredTime];
  1870.  
  1871.                             FlagBit ^= TRUE;
  1872.  
  1873.                             if(!FlagBit)
  1874.                             {
  1875.                                 if((SecCount++) == SecPerUnit[PreferredTime])
  1876.                                 {
  1877.                                     SecCount = 0;
  1878.  
  1879.                                     CurrentPay += PayPerUnit[PreferredTime];
  1880.                                 }
  1881.                             }
  1882.                         }
  1883.  
  1884.                             /* Show the time
  1885.                              * we have been online
  1886.                              * yet.
  1887.                              */
  1888.  
  1889.                         TempTime = TimeRequest -> tr_time;
  1890.  
  1891.                         SubTime(&TempTime,&OnlineTime);
  1892.  
  1893.                         SPrintf(Buffer,"%02ld:%02ld:%02ld",(TempTime . tv_secs % 86400) / 3600,(TempTime . tv_secs % 3600) / 60,TempTime . tv_secs % 60);
  1894.  
  1895.                         MoveItem(3,1);
  1896.                         
  1897.                         Print(Buffer);
  1898.                     }
  1899.                     else
  1900.                     {
  1901.                         if(GotOnline)
  1902.                             GotOnline = FALSE;
  1903.                     }
  1904.  
  1905.                         /* Display the current terminal
  1906.                          * status.
  1907.                          */
  1908.  
  1909.                     if(LastStatus != Status)
  1910.                     {
  1911.                         LastStatus = Status;
  1912.  
  1913.                         MoveItem(0,0);
  1914.                         Print(ConfigStatus[LastStatus]);
  1915.                     }
  1916.  
  1917.                         /* Show the current transfer
  1918.                          * protocol.
  1919.                          */
  1920.  
  1921.                     if(strcmp(LastProtocol,FilePart(Config . Protocol)))
  1922.                     {
  1923.                         strcpy(LastProtocol,FilePart(Config . Protocol));
  1924.  
  1925.                         strcpy(ProtocolBuffer,"        ");
  1926.  
  1927.                         for(i = 0 ; i < 8 ; i++)
  1928.                         {
  1929.                             if(!LastProtocol[i + 3] || LastProtocol[i + 3] == '.')
  1930.                                 break;
  1931.                             else
  1932.                                 ProtocolBuffer[i] = LastProtocol[i + 3];
  1933.                         }
  1934.  
  1935.                         MoveItem(1,0);
  1936.                         Print(ProtocolBuffer);
  1937.                     }
  1938.  
  1939.                         /* Show the current baud
  1940.                          * rate.
  1941.                          */
  1942.  
  1943.                     if(LastBaud != Config . BaudRate)
  1944.                     {
  1945.                         LastBaud = Config . BaudRate;
  1946.  
  1947.                         SPrintf(Buffer,"%ld        ",LastBaud);
  1948.  
  1949.                         Buffer[8] = 0;
  1950.  
  1951.                         MoveItem(2,0);
  1952.                         Print(Buffer);
  1953.                     }
  1954.  
  1955.                         /* Show the current
  1956.                          * terminal font.
  1957.                          */
  1958.  
  1959.                     if(LastFont != Config . Font)
  1960.                     {
  1961.                         LastFont = Config . Font;
  1962.  
  1963.                         MoveItem(0,1);
  1964.                         Print(ConfigFont[LastFont]);
  1965.                     }
  1966.  
  1967.                         /* Show the current terminal
  1968.                          * emulation.
  1969.                          */
  1970.  
  1971.                     if(LastEmulation != Config . Emulation)
  1972.                     {
  1973.                         LastEmulation = Config . Emulation;
  1974.  
  1975.                         MoveItem(1,1);
  1976.                         Print(ConfigEmulation[LastEmulation]);
  1977.                     }
  1978.  
  1979.                         /* Show the current serial
  1980.                          * parameters (parity, etc).
  1981.                          */
  1982.  
  1983.                     if(LastBitsPerChar != Config . BitsPerChar || LastParity != Config . Parity || LastStopBits != Config . StopBits)
  1984.                     {
  1985.                         LastBitsPerChar    = Config . BitsPerChar;
  1986.                         LastParity    = Config . Parity;
  1987.                         LastStopBits    = Config . StopBits;
  1988.  
  1989.                         SPrintf(Buffer,"%ld-%s-%ld",LastBitsPerChar,ConfigParity[LastParity],LastStopBits);
  1990.  
  1991.                         MoveItem(2,1);
  1992.                         Print(Buffer);
  1993.                     }
  1994.  
  1995.                         /* Wait another half a second. */
  1996.  
  1997.                     if(KeepGoing)
  1998.                     {
  1999.                         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2000.                         TimeRequest -> tr_time . tv_secs    = 0;
  2001.                         TimeRequest -> tr_time . tv_micro    = MILLION / 2;
  2002.  
  2003.                         DoIO(TimeRequest);
  2004.                     }
  2005.  
  2006.                         /* Make the colours blink. */
  2007.  
  2008.                     if((Window -> Flags & WFLG_MENUSTATE) || (Window -> Pointer))
  2009.                     {
  2010.                         if(!FlashIt)
  2011.                         {
  2012.                             if(Screen == IntuitionBase -> FirstScreen)
  2013.                                 LoadRGB4(VPort,Config . Colours,16);
  2014.  
  2015.                             FlashIt = TRUE;
  2016.                         }
  2017.                     }
  2018.                     else
  2019.                     {
  2020.                             /* Are we to flash the display? */
  2021.  
  2022.                         if(!Config . DisableBlinking)
  2023.                         {
  2024.                             if(Screen == IntuitionBase -> FirstScreen)
  2025.                             {
  2026.                                 if(FlashIt)
  2027.                                     LoadRGB4(VPort,BlinkColours,16);
  2028.                                 else
  2029.                                     LoadRGB4(VPort,Config . Colours,16);
  2030.                             }
  2031.  
  2032.                             FlashIt ^= TRUE;
  2033.                         }
  2034.                     }
  2035.                 }
  2036.  
  2037.                 CloseDevice(TimeRequest);
  2038.             }
  2039.  
  2040.             DeleteIORequest(TimeRequest);
  2041.         }
  2042.  
  2043.         DeleteMsgPort(TimePort);
  2044.     }
  2045.  
  2046.         /* Signal the father process that we're done
  2047.          * and quietly remove ourselves.
  2048.          */
  2049.  
  2050.     Forbid();
  2051.  
  2052.     Signal(ThisProcess,SIGBREAKF_CTRL_C);
  2053.  
  2054.     StatusTask = NULL;
  2055.  
  2056.     RemTask(SysBase -> ThisTask);
  2057. }
  2058.  
  2059.     /* CloseWindowSafely(struct Window *Window):
  2060.      *
  2061.      *    Close a window freeing all messages pending at
  2062.      *    its user port (taken from example source code
  2063.      *    published once upon a time in Amiga Mail).
  2064.      */
  2065.  
  2066. VOID
  2067. CloseWindowSafely(struct Window *Window)
  2068. {
  2069.     struct IntuiMessage    *IntuiMessage;
  2070.     struct Node        *Successor;
  2071.  
  2072.     Forbid();
  2073.  
  2074.     IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  2075.  
  2076.     while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  2077.     {
  2078.         if(IntuiMessage -> IDCMPWindow == Window)
  2079.         {
  2080.             Remove(IntuiMessage);
  2081.  
  2082.             ReplyMsg((struct Message *)IntuiMessage);
  2083.         }
  2084.  
  2085.         IntuiMessage = (struct IntuiMessage *)Successor;
  2086.     }
  2087.  
  2088.     Window -> UserPort = NULL;
  2089.  
  2090.     ModifyIDCMP(Window,NULL);
  2091.     Permit();
  2092.  
  2093.     CloseWindow(Window);
  2094. }
  2095.  
  2096.     /* WaitTime(LONG Secs,LONG Micros):
  2097.      *
  2098.      *    Wait a given period of time.
  2099.      */
  2100.  
  2101. VOID
  2102. WaitTime(LONG Secs,LONG Micros)
  2103. {
  2104.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  2105.     TimeRequest -> tr_time . tv_secs    = Secs;
  2106.     TimeRequest -> tr_time . tv_micro    = Micros;
  2107.  
  2108.     DoIO(TimeRequest);
  2109. }
  2110.  
  2111.     /* GetEnvDOS(UBYTE *Name,UBYTE *Buffer):
  2112.      *
  2113.      *    Get the contents of a vanilla AmigaDOS environment
  2114.      *    variable.
  2115.      */
  2116.  
  2117. UBYTE *
  2118. GetEnvDOS(UBYTE *Name,UBYTE *Buffer)
  2119. {
  2120.     LONG    Size;
  2121.     BPTR    File,SomeLock;
  2122.  
  2123.     Buffer[0] = 0;
  2124.  
  2125.         /* Is ENV: present? */
  2126.  
  2127.     if(SomeLock = Lock("ENV:",ACCESS_READ))
  2128.     {
  2129.         UBYTE SomeBuffer[80];
  2130.  
  2131.         UnLock(SomeLock);
  2132.  
  2133.         strcpy(SomeBuffer,"ENV:");
  2134.         strcat(SomeBuffer,Name);
  2135.  
  2136.             /* Open the file. */
  2137.  
  2138.         if(File = Open(SomeBuffer,MODE_OLDFILE))
  2139.         {
  2140.                 /* Read the contents. */
  2141.  
  2142.             Size = Read(File,Buffer,256);
  2143.  
  2144.             Close(File);
  2145.  
  2146.             if(Size > 0)
  2147.             {
  2148.                 Buffer[Size] = 0;
  2149.  
  2150.                 return(Buffer);
  2151.             }
  2152.         }
  2153.     }
  2154.  
  2155.     return(NULL);
  2156. }
  2157.  
  2158.     /* SetEnvDOS(UBYTE *Name,UBYTE *Value):
  2159.      *
  2160.      *    Set the contents of a vanilla AmigaDOS environment
  2161.      *    variable.
  2162.      */
  2163.  
  2164. BYTE
  2165. SetEnvDOS(UBYTE *Name,UBYTE *Value)
  2166. {
  2167.     UBYTE    Buffer[80],*Destination;
  2168.     LONG    Length = 0;
  2169.     BPTR    File,FileLock;
  2170.     BYTE    Success = FALSE;
  2171.     SHORT    i;
  2172.  
  2173.     for(i = 0 ; i < 2 ; i++)
  2174.     {
  2175.         if(i)
  2176.             Destination = "ENVARC:";
  2177.         else
  2178.             Destination = "ENV:";
  2179.  
  2180.             /* Is ENV:/ENVARC: present? */
  2181.     
  2182.         if(FileLock = Lock(Destination,ACCESS_READ))
  2183.         {
  2184.             UnLock(FileLock);
  2185.  
  2186.             strcpy(Buffer,Destination);
  2187.             strcat(Buffer,Name);
  2188.  
  2189.                 /* There already is a variable of that
  2190.                  * name in the environment storage
  2191.                  * directory.
  2192.                  */
  2193.  
  2194.             if(FileLock = Lock(Buffer,ACCESS_WRITE))
  2195.             {
  2196.                 UnLock(FileLock);
  2197.  
  2198.                     /* Delete the variable. */
  2199.  
  2200.                 if(!DeleteFile(Buffer))
  2201.                 {
  2202.                     Success = FALSE;
  2203.                     continue;
  2204.                 }
  2205.             }
  2206.  
  2207.                 /* Set the new variable. */
  2208.  
  2209.             if(Length = strlen(Value))
  2210.             {
  2211.                 if(File = Open(Buffer,MODE_NEWFILE))
  2212.                 {
  2213.                     if(Write(File,Value,Length) != Length)
  2214.                     {
  2215.                         Close(File);
  2216.                         DeleteFile(Buffer);
  2217.  
  2218.                         Success = FALSE;
  2219.                     }
  2220.                     else
  2221.                     {
  2222.                         Close(File);
  2223.                         SetProtection(Buffer,FIBF_EXECUTE);
  2224.  
  2225.                         Success = TRUE;
  2226.                     }
  2227.                 }
  2228.                 else
  2229.                     Success = FALSE;
  2230.             }
  2231.             else
  2232.                 Success = TRUE;
  2233.         }
  2234.         else
  2235.             Success = FALSE;
  2236.     }
  2237.  
  2238.     return(Success);
  2239. }
  2240.  
  2241.     /* BumpWindow(struct Window *SomeWindow):
  2242.      *
  2243.      *    Bring a window to the front (and shift the screen
  2244.      *    back to its initial position).
  2245.      */
  2246.  
  2247. VOID
  2248. BumpWindow(struct Window *SomeWindow)
  2249. {
  2250.     MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,-SomeWindow -> WScreen -> TopEdge);
  2251.  
  2252.     ScreenToFront(SomeWindow -> WScreen);
  2253.  
  2254.     ActivateWindow(SomeWindow);
  2255. }
  2256.  
  2257.     /* BumpDefault():
  2258.      *
  2259.      *    Bring the current default screen to the front.
  2260.      */
  2261.  
  2262. VOID
  2263. BumpDefault()
  2264. {
  2265.     struct Screen *DefaultScreen;
  2266.  
  2267.     if(DefaultScreen = (struct Screen *)LockPubScreen(NULL))
  2268.     {
  2269.         MoveScreen(DefaultScreen,-DefaultScreen -> LeftEdge,-DefaultScreen -> TopEdge);
  2270.  
  2271.         ScreenToFront(DefaultScreen);
  2272.  
  2273.         UnlockPubScreen(NULL,DefaultScreen);
  2274.     }
  2275. }
  2276.  
  2277.     /* WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
  2278.      *
  2279.      *    Write data to an IFF file (via iffparse.library).
  2280.      */
  2281.  
  2282. BYTE
  2283. WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
  2284. {
  2285.     struct IFFHandle    *Handle;
  2286.     BYTE             Success = FALSE;
  2287.  
  2288.         /* Allocate a handle. */
  2289.  
  2290.     if(Handle = AllocIFF())
  2291.     {
  2292.             /* Open an output stream. */
  2293.  
  2294.         if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  2295.         {
  2296.                 /* Tell iffparse that this is
  2297.                  * a DOS handle.
  2298.                  */
  2299.  
  2300.             InitIFFasDOS(Handle);
  2301.  
  2302.                 /* Open the handle for writing. */
  2303.  
  2304.             if(!OpenIFF(Handle,IFFF_WRITE))
  2305.             {
  2306.                     /* Push outmost chunk onto stack. */
  2307.  
  2308.                 if(!PushChunk(Handle,'TERM','FORM',IFFSIZE_UNKNOWN))
  2309.                 {
  2310.                         /* Add a version identifier. */
  2311.  
  2312.                     if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
  2313.                     {
  2314.                         struct TermInfo TermInfo;
  2315.  
  2316.                         TermInfo . Version    = TermVersion;
  2317.                         TermInfo . Revision    = TermRevision;
  2318.  
  2319.                             /* Write the version data. */
  2320.  
  2321.                         if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
  2322.                         {
  2323.                                 /* Pop the version chunk, i.e. write it to the file. */
  2324.  
  2325.                             if(PopChunk(Handle))
  2326.                                 Success = FALSE;
  2327.                             else
  2328.                             {
  2329.                                     /* Push the real data chunk on the stack. */
  2330.  
  2331.                                 if(!PushChunk(Handle,0,Type,IFFSIZE_UNKNOWN))
  2332.                                 {
  2333.                                         /* Write the data. */
  2334.  
  2335.                                     if(WriteChunkBytes(Handle,Data,Size) == Size)
  2336.                                         Success = TRUE;
  2337.  
  2338.                                             /* Pop the data chunk. */
  2339.  
  2340.                                     if(PopChunk(Handle))
  2341.                                         Success = FALSE;
  2342.                                 }
  2343.                                 else
  2344.                                     Success = FALSE;
  2345.                             }
  2346.                         }
  2347.                         else
  2348.                             Success = FALSE;
  2349.                     }
  2350.  
  2351.                         /* Seems that we're done, now try to pop the FORM chunk
  2352.                          * and return.
  2353.                          */
  2354.  
  2355.                     if(PopChunk(Handle))
  2356.                         Success = FALSE;
  2357.                 }
  2358.  
  2359.                     /* Close the handle (flush any pending data). */
  2360.  
  2361.                 CloseIFF(Handle);
  2362.             }
  2363.  
  2364.                 /* Close the DOS handle itself. */
  2365.  
  2366.             Close(Handle -> iff_Stream);
  2367.         }
  2368.  
  2369.             /* And free the IFF handle. */
  2370.  
  2371.         FreeIFF(Handle);
  2372.     }
  2373.  
  2374.     if(Success)
  2375.         SetProtection(Name,FIBF_EXECUTE);
  2376.  
  2377.     return(Success);
  2378. }
  2379.  
  2380.     /* ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
  2381.      *
  2382.      *    Read data from a `TERM' FORM chunk contained in an IFF file.
  2383.      */
  2384.  
  2385. BYTE
  2386. ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
  2387. {
  2388.     struct IFFHandle    *Handle;
  2389.     BYTE             Success = FALSE;
  2390.     struct StoredProperty    *Prop;
  2391.     struct TermInfo        *TermInfo;
  2392.  
  2393.     if(Handle = AllocIFF())
  2394.     {
  2395.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  2396.         {
  2397.             InitIFFasDOS(Handle);
  2398.  
  2399.             if(!OpenIFF(Handle,IFFF_READ))
  2400.             {
  2401.                 /* Collect version number ID if
  2402.                  * available.
  2403.                  */
  2404.  
  2405.                 if(!PropChunks(Handle,&VersionProps[0],1))
  2406.                 {
  2407.                     /* The following line tells iffparse to stop at the
  2408.                      * very beginning of a `Type' chunk contained in a
  2409.                      * `TERM' FORM chunk.
  2410.                      */
  2411.  
  2412.                     if(!StopChunk(Handle,'TERM',Type))
  2413.                     {
  2414.                         /* Parse the file... */
  2415.  
  2416.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  2417.                         {
  2418.                             /* Did we get a version ID? */
  2419.  
  2420.                             if(Prop = FindProp(Handle,'TERM','VERS'))
  2421.                             {
  2422.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  2423.  
  2424.                                 /* Is it the file format we are able
  2425.                                  * to read?
  2426.                                  */
  2427.  
  2428.                                 if(TermInfo -> Version == TermVersion && TermInfo -> Revision <= TermRevision && TermInfo -> Revision >= 6)
  2429.                                 {
  2430.                                     /* The file read pointer is positioned
  2431.                                      * just in front of the first data
  2432.                                      * to be read, so let's don't disappoint
  2433.                                      * iffparse and read it.
  2434.                                      */
  2435.  
  2436.                                     if(ReadChunkBytes(Handle,Data,Size) == Size)
  2437.                                         Success = TRUE;
  2438.                                 }
  2439.                             }
  2440.                         }
  2441.                     }
  2442.                 }
  2443.  
  2444.                 CloseIFF(Handle);
  2445.             }
  2446.  
  2447.             Close(Handle -> iff_Stream);
  2448.         }
  2449.  
  2450.         FreeIFF(Handle);
  2451.     }
  2452.  
  2453.     return(Success);
  2454. }
  2455.  
  2456.     /* PushWindow(struct Window *Window):
  2457.      *
  2458.      *    Push/PopWindow implement a single lifo window stack
  2459.      *    which always updates the window to activate when
  2460.      *    LSHIFT+RSHIFT+RETURN is pressed. This routine will
  2461.      *    push a window on the stack.
  2462.      */
  2463.  
  2464. VOID
  2465. PushWindow(struct Window *Window)
  2466. {
  2467.     if(WindowStackPtr < 5)
  2468.     {
  2469.         WindowStack[WindowStackPtr++] = Window;
  2470.  
  2471.         TopWindow = Window;
  2472.     }
  2473. }
  2474.  
  2475.     /* PopWindow():
  2476.      *
  2477.      *    Remove topmost window from window stack.
  2478.      */
  2479.  
  2480. VOID
  2481. PopWindow()
  2482. {
  2483.     if(WindowStackPtr > 0)
  2484.     {
  2485.         WindowStackPtr--;
  2486.  
  2487.         if(WindowStackPtr)
  2488.             TopWindow = WindowStack[WindowStackPtr - 1];
  2489.         else
  2490.             TopWindow = Window;
  2491.     }
  2492. }
  2493.