home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 500-599 / ff589.lza / Term / TermSrc.lha / termAux.c < prev    next >
C/C++ Source or Header  |  1991-12-10  |  51KB  |  2,593 lines

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