home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 12 / MA_Cover_12.iso / devs / hyperio-install-idc / goodies / hydra.lha / hydracom-source.lha / amiga.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-21  |  50.7 KB  |  2,466 lines

  1. /*
  2. **    :ts=4
  3. **
  4. **    Amiga support module for HYDRA protocol sample implementation.
  5. **
  6. **    Written by    Olaf Barthel
  7. **            Brabeckstrasse 35
  8. **            D-30559 Hannover
  9. **
  10. **            eMail: olsen@sourcery.han.de
  11. **
  12. **    Freely distributable.
  13. */
  14.  
  15.     /* System includes. */
  16.  
  17. #include <intuition/intuitionbase.h>
  18.  
  19. #include <libraries/gadtools.h>
  20. #include <libraries/locale.h>
  21. #include <libraries/asl.h>
  22.  
  23. #include <graphics/gfxbase.h>
  24.  
  25. #include <utility/date.h>
  26.  
  27. #include <devices/conunit.h>
  28. #include <devices/serial.h>
  29. #include <devices/timer.h>
  30.  
  31. #include <hardware/cia.h>
  32.  
  33. #include <dos/dosextens.h>
  34. #include <dos/filehandler.h>
  35. #include <dos/dostags.h>
  36. #include <dos/dosasl.h>
  37.  
  38. #include <exec/memory.h>
  39.  
  40. #include <clib/intuition_protos.h>
  41. #include <clib/gadtools_protos.h>
  42. #include <clib/graphics_protos.h>
  43. #include <clib/utility_protos.h>
  44. #include <clib/locale_protos.h>
  45. #include <clib/timer_protos.h>
  46. #include <clib/exec_protos.h>
  47. #include <clib/dos_protos.h>
  48. #include <clib/asl_protos.h>
  49. #include <clib/macros.h>
  50.  
  51. #include <pragmas/exec_sysbase_pragmas.h>
  52. #include <pragmas/intuition_pragmas.h>
  53. #include <pragmas/gadtools_pragmas.h>
  54. #include <pragmas/graphics_pragmas.h>
  55. #include <pragmas/utility_pragmas.h>
  56. #include <pragmas/locale_pragmas.h>
  57. #include <pragmas/timer_pragmas.h>
  58. #include <pragmas/dos_pragmas.h>
  59. #include <pragmas/asl_pragmas.h>
  60.  
  61. #include <errno.h>
  62.  
  63. //#define DB(x)    x
  64. #define DB(x) ;
  65.  
  66. void kprintf(STRPTR,...);
  67.  
  68. #include "Rendezvous.h"
  69. #include "hydracom.h"
  70.  
  71.     /* Difference between Unix time and Amiga time. */
  72.  
  73. #define UNIX_TIME_OFFSET    252482400
  74.  
  75.     /* Minimum of lines to reserve for local input. */
  76.  
  77. #define MIN_LINES            3
  78.  
  79.     /* Serial buffer size. */
  80.  
  81. #define BUFFER_SIZE            8192
  82.  
  83.     /* Maximum length of a file name for now. */
  84.  
  85. #define MAX_FILENAME_LENGTH    256
  86.  
  87.     /* A handy macro. */
  88.  
  89. #define ClrSignal(s)    SetSignal(0,s)
  90.  
  91.     /* this macro lets us long-align structures on the stack */
  92.  
  93. #define D_S(type,name) char a_##name[sizeof(type)+3]; \
  94.                        type *name = (type *)((LONG)(a_##name+3) & ~3);
  95.  
  96.     /* Signal masks. */
  97.  
  98. #define SIG_SERREAD        (1UL << ReadPort->mp_SigBit)
  99. #define SIG_SERWRITE    (1UL << WritePort->mp_SigBit)
  100. #define SIG_CONREAD        (1UL << ConsoleReadPort->mp_SigBit)
  101. #define SIG_TIMER        (1UL << TimePort->mp_SigBit)
  102. #define SIG_WINDOW        (1UL << WindowPort->mp_SigBit)
  103. #define SIG_HANDSHAKE    SIGF_SINGLE
  104. #define SIG_KILL        SIGBREAKF_CTRL_C
  105.  
  106.     /* A serial buffer structure. */
  107.  
  108. struct SerialBuffer
  109. {
  110.     struct IOExtSer    *SerialRequest;
  111.     UBYTE            *SerialBuffer,
  112.                     *SerialIndex,
  113.                     *SerialTop;
  114.     LONG             SerialSize,
  115.                      SerialFilled;
  116.     BOOL             IsClone,
  117.                      IsBusy;
  118. };
  119.  
  120.     /* Special rendezvous data. */
  121.  
  122. STATIC struct RendezvousData        *RendezvousData;
  123. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  124.  
  125.     /* Library bases. */
  126.  
  127. extern struct ExecBase        *SysBase;
  128. extern struct DosLibrary    *DOSBase;
  129.  
  130. struct IntuitionBase        *IntuitionBase;
  131. struct GfxBase                *GfxBase;
  132. struct LocaleBase            *LocaleBase;
  133. struct Library                *GadToolsBase,
  134.                             *UtilityBase,
  135.                             *TimerBase,
  136.                             *AslBase;
  137.  
  138.     /* Timer data. */
  139.  
  140. struct MsgPort        *TimePort;
  141. struct timerequest    *TimeRequest;
  142.  
  143.     /* Serial data. */
  144.  
  145. struct MsgPort        *ReadPort,
  146.                     *WritePort;
  147.  
  148. struct SerialBuffer    *ThisBuffer,
  149.                     *NextBuffer,
  150.                     *ReadBuffer;
  151.  
  152.     /* Console data. */
  153.  
  154. struct MsgPort        *WindowPort;
  155.  
  156. struct Window        *FileWindow,
  157.                     *RemoteWindow,
  158.                     *LocalWindow,
  159.                     *LogWindow;
  160.  
  161. struct MsgPort        *ConsoleWritePort,
  162.                     *ConsoleReadPort;
  163. struct IOStdReq        *ConsoleReadRequest;
  164. UBYTE                 ConsoleChar;
  165. BOOL                 ConsoleReady = FALSE,
  166.                      WindowReady = FALSE;
  167.  
  168. struct IOStdReq        *FileRequest,
  169.                     *RemoteRequest,
  170.                     *LocalRequest,
  171.                     *LogRequest;
  172.  
  173.     /* DOS Data. */
  174.  
  175. struct Process        *ThisProcess;
  176. APTR                 OldPtr;
  177. LONG                 OldPri;
  178.  
  179. struct AnchorPath    *Anchor;
  180. BOOL                 AnchorUsed = FALSE;
  181.  
  182.     /* Screen data. */
  183.  
  184. struct Screen        *PublicScreen,
  185.                     *Screen;
  186.  
  187.     /* Menu data. */
  188.  
  189. APTR                 VisualInfo;
  190. struct Menu            *Menu;
  191.  
  192. struct NewMenu MenuTemplate[] =
  193. {
  194.     { NM_TITLE, "Project",                 0 ,    0,    0,    (APTR)0},
  195.     {  NM_ITEM, "Toggle chat",            "C",    0,    0,    (APTR)Alt_C},
  196.     {  NM_ITEM, NM_BARLABEL,             0 ,    0,    0,    (APTR)0},
  197.     {  NM_ITEM, "Hang up",                "H",    0,    0,    (APTR)Alt_H},
  198.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  199.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  200.     {  NM_ITEM, NM_BARLABEL,             0 ,    0,    0,    (APTR)0},
  201.     {  NM_ITEM, "Start upload",            "U",    0,    0,    (APTR)PgUp},
  202.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  203.     {  NM_ITEM, NM_BARLABEL,             0 ,    0,    0,    (APTR)0},
  204.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  205.     {  NM_ITEM, NM_BARLABEL,             0 ,    0,    0,    (APTR)0},
  206.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  207.     { NM_END }
  208. };
  209.  
  210.     /* Time data. */
  211.  
  212. LONG             GMT_Offset = UNIX_TIME_OFFSET;
  213.  
  214.     /* Standard file requester. */
  215.  
  216. struct FileRequester *FileRequester;
  217.  
  218.     /* Version ID. */
  219.  
  220. STRPTR VersionTag = "$VER: hydracom 1.0r9 (2.1.97)\r\n";
  221.  
  222.     /* CloseWindowSafely(struct Window *Window):
  223.      *
  224.      *    Close a window sharing its UserPort with other
  225.      *    windows.
  226.      */
  227.  
  228. STATIC VOID
  229. CloseWindowSafely(struct Window *Window)
  230. {
  231.     Forbid();
  232.  
  233.     if(Window->UserPort)
  234.     {
  235.         struct Node *Node,*Next;
  236.  
  237.         for(Node = Window->UserPort->mp_MsgList.lh_Head ; Next = Node->ln_Succ ; Node = Next)
  238.         {
  239.             if(((struct IntuiMessage *)Node)->IDCMPWindow == Window)
  240.             {
  241.                 Remove(Node);
  242.                 ReplyMsg((struct Message *)Node);
  243.             }
  244.         }
  245.  
  246.         Window->UserPort = NULL;
  247.     }
  248.  
  249.     ModifyIDCMP(Window,NULL);
  250.  
  251.     Permit();
  252.  
  253.     CloseWindow(Window);
  254. }
  255.  
  256.     /* UpdateTime(struct timeval *Now):
  257.      *
  258.      *    Get the current time and/or update the current
  259.      *    time offset data.
  260.      */
  261.  
  262. STATIC VOID
  263. UpdateTime(struct timeval *Now)
  264. {
  265.     if(Now)
  266.         Now->tv_secs = Now->tv_micro = 0;
  267.  
  268.     if(TimePort = CreateMsgPort())
  269.     {
  270.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  271.         {
  272.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  273.             {
  274.                 TimerBase = (struct Library *)TimeRequest->tr_node.io_Device;
  275.  
  276.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  277.                 {
  278.                     struct Locale *Locale = OpenLocale(NULL);
  279.  
  280.                     GMT_Offset = 60 * Locale->loc_GMTOffset + UNIX_TIME_OFFSET;
  281.                     CloseLocale(Locale);
  282.  
  283.                     CloseLibrary(LocaleBase);
  284.                     LocaleBase = NULL;
  285.                 }
  286.  
  287.                 if(Now)
  288.                     GetSysTime(Now);
  289.  
  290.                 TimerBase = NULL;
  291.                 CloseDevice(TimeRequest);
  292.             }
  293.  
  294.             DeleteIORequest(TimeRequest);
  295.             TimeRequest = NULL;
  296.         }
  297.  
  298.         DeleteMsgPort(TimePort);
  299.         TimePort = NULL;
  300.     }
  301. }
  302.  
  303. STATIC VOID
  304. AddString(STRPTR Buffer,LONG MaxLen,STRPTR NewString)
  305. {
  306.     LONG i,Len,BufferLen;
  307.     BOOL HasSpace;
  308.  
  309.     Len            = strlen(NewString);
  310.     BufferLen    = strlen(Buffer);
  311.     HasSpace    = FALSE;
  312.  
  313.     for(i = 0 ; i < Len ; i++)
  314.     {
  315.         if(NewString[i] == ' ')
  316.         {
  317.             HasSpace = TRUE;
  318.             Len += 2;
  319.             break;
  320.         }
  321.     }
  322.  
  323.     Len++;
  324.  
  325.     if(BufferLen + Len < MaxLen)
  326.     {
  327.         if(HasSpace)
  328.             sprintf(&Buffer[BufferLen],"\"%s\" ",NewString);
  329.         else
  330.             sprintf(&Buffer[BufferLen],"%s ",NewString);
  331.     }
  332. }
  333.  
  334.     /* GetFiles(char *Buffer,int MaxLen):
  335.      *
  336.      *    Get a list of file names.
  337.      */
  338.  
  339. char *
  340. GetFiles(char *Buffer,int MaxLen)
  341. {
  342.     if(AslRequestTags(FileRequester,
  343.         ASLFR_Window,        LocalWindow,
  344.         ASLFR_SleepWindow,    TRUE,
  345.     TAG_DONE))
  346.     {
  347.         if(FileRequester->fr_NumArgs > 0)
  348.         {
  349.             UBYTE    LocalBuffer[MAX_FILENAME_LENGTH];
  350.             LONG    Len,Count,i;
  351.  
  352.             for(i = Count = 0 ; i < FileRequester->fr_NumArgs ; i++)
  353.             {
  354.                 if(FileRequester->fr_ArgList[i].wa_Lock)
  355.                 {
  356.                     if(!NameFromLock(FileRequester->fr_ArgList[i].wa_Lock,LocalBuffer,sizeof(LocalBuffer)))
  357.                     {
  358.                         Count = -1;
  359.                         break;
  360.                     }
  361.                 }
  362.                 else
  363.                 {
  364.                     Len = strlen(FileRequester->fr_Drawer);
  365.  
  366.                     if(Len >= sizeof(LocalBuffer))
  367.                     {
  368.                         Count = -1;
  369.                         break;
  370.                     }
  371.                     else
  372.                         strcpy(LocalBuffer,FileRequester->fr_Drawer);
  373.                 }
  374.  
  375.                 if(AddPart(LocalBuffer,FileRequester->fr_ArgList[i].wa_Name,sizeof(LocalBuffer)))
  376.                 {
  377.                     LONG j;
  378.  
  379.                     Len = strlen(LocalBuffer) + 1;
  380.  
  381.                     for(j = 0 ; j < Len ; j++)
  382.                     {
  383.                         if(j == ' ')
  384.                         {
  385.                             Len += 2;
  386.                             break;
  387.                         }
  388.                     }
  389.  
  390.                     if(Len < sizeof(LocalBuffer))
  391.                     {
  392.                         if(Count + Len < MaxLen)
  393.                             Count += Len;
  394.                         else
  395.                         {
  396.                             Count = -1;
  397.                             break;
  398.                         }
  399.                     }
  400.                 }
  401.             }
  402.  
  403.             if(Count > 0)
  404.             {
  405.                 Buffer[0] = 0;
  406.  
  407.                 for(i = 0 ; i < FileRequester->fr_NumArgs ; i++)
  408.                 {
  409.                     if(FileRequester->fr_ArgList[i].wa_Lock)
  410.                     {
  411.                         if(!NameFromLock(FileRequester->fr_ArgList[i].wa_Lock,LocalBuffer,sizeof(LocalBuffer)))
  412.                             break;
  413.                     }
  414.                     else
  415.                     {
  416.                         Len = strlen(FileRequester->fr_Drawer);
  417.  
  418.                         if(Len >= sizeof(LocalBuffer))
  419.                             break;
  420.                         else
  421.                             strcpy(LocalBuffer,FileRequester->fr_Drawer);
  422.                     }
  423.  
  424.                     if(AddPart(LocalBuffer,FileRequester->fr_ArgList[i].wa_Name,sizeof(LocalBuffer)))
  425.                         AddString(Buffer,MaxLen,LocalBuffer);
  426.                 }
  427.  
  428.                 return(Buffer);
  429.             }
  430.         }
  431.         else
  432.         {
  433.             if(FileRequester->fr_File[0])
  434.             {
  435.                 LONG Len;
  436.  
  437.                 Len = strlen(FileRequester->fr_Drawer) + strlen(FileRequester->fr_File) + 2 + 2;
  438.  
  439.                 if(Len <= MaxLen)
  440.                 {
  441.                     strcpy(Buffer,FileRequester->fr_Drawer);
  442.                     AddPart(Buffer,FileRequester->fr_File,MaxLen);
  443.  
  444.                     return(Buffer);
  445.                 }
  446.             }
  447.         }
  448.     }
  449.  
  450.     return(NULL);
  451. }
  452.  
  453.     /* OpenConsole():
  454.      *
  455.      *    Open a console window.
  456.      */
  457.  
  458. STATIC BOOL
  459. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  460. {
  461.     struct Window *Window;
  462.  
  463.     if(Window = OpenWindowTags(NULL,
  464.         WA_Left,            0,
  465.         WA_Top,                Top,
  466.         WA_Width,            Screen->Width,
  467.         WA_Height,            Height,
  468.         WA_Title,            Title,
  469.         WA_SimpleRefresh,    TRUE,
  470.         WA_DepthGadget,        TRUE,
  471.         WA_DragBar,            TRUE,
  472.         WA_SizeGadget,        Resize,
  473.         WA_SizeBRight,        TRUE,
  474.         WA_CustomScreen,    Screen,
  475.         WA_NewLookMenus,    TRUE,
  476.     TAG_DONE))
  477.     {
  478.         Window->UserPort = WindowPort;
  479.  
  480.         SetMenuStrip(Window,Menu);
  481.  
  482.         if(ModifyIDCMP(Window,IDCMP_MENUPICK))
  483.         {
  484.             struct IOStdReq *ConsoleRequest;
  485.  
  486.             if(Window->RPort->Font->tf_Flags & FPF_PROPORTIONAL)
  487.                 SetFont(Window->RPort,GfxBase->DefaultFont);
  488.  
  489.             if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  490.             {
  491.                 ConsoleRequest->io_Data = Window;
  492.  
  493.                 if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  494.                 {
  495.                     WindowLimits(Window,Window->BorderLeft + 10 * Window->RPort->Font->tf_XSize * 10 + Window->BorderRight,Window->BorderTop + 2 * Window->RPort->Font->tf_YSize + Window->BorderBottom,Screen->Width,Screen->Height);
  496.  
  497.                         /* Turn off the cursor. */
  498.  
  499.                     ConPrintf(ConsoleRequest,"\033[0 p");
  500.  
  501.                     *WindowPtr    = Window;
  502.                     *ConsolePtr    = ConsoleRequest;
  503.  
  504.                     return(TRUE);
  505.                 }
  506.  
  507.                 DeleteIORequest(ConsoleRequest);
  508.             }
  509.         }
  510.  
  511.         ClearMenuStrip(Window);
  512.  
  513.         CloseWindowSafely(Window);
  514.     }
  515.  
  516.     return(FALSE);
  517. }
  518.  
  519.     /* CloseConsole():
  520.      *
  521.      *    Close a console window.
  522.      */
  523.  
  524. STATIC VOID
  525. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  526. {
  527.     if(*ConsolePtr)
  528.     {
  529.         CloseDevice(*ConsolePtr);
  530.  
  531.         DeleteIORequest(*ConsolePtr);
  532.  
  533.         *ConsolePtr = NULL;
  534.     }
  535.  
  536.     if(*WindowPtr)
  537.     {
  538.         ClearMenuStrip(*WindowPtr);
  539.  
  540.         CloseWindowSafely(*WindowPtr);
  541.  
  542.         *WindowPtr = NULL;
  543.     }
  544. }
  545.  
  546.     /* CloneSerialBuffer():
  547.      *
  548.      *    Clone a SerialBuffer structure.
  549.      */
  550.  
  551. STATIC struct SerialBuffer *
  552. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  553. {
  554.     struct SerialBuffer *Buffer;
  555.  
  556.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source->SerialSize,MEMF_ANY | MEMF_PUBLIC))
  557.     {
  558.         Buffer->SerialBuffer    = Buffer->SerialIndex = (UBYTE *)(Buffer + 1);
  559.         Buffer->SerialFilled    = 0;
  560.         Buffer->SerialTop        = Buffer->SerialBuffer + Source->SerialSize;
  561.         Buffer->SerialSize        = Source->SerialSize;
  562.         Buffer->IsClone            = TRUE;
  563.         Buffer->IsBusy            = FALSE;
  564.  
  565.         if(Buffer->SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  566.         {
  567.             CopyMem(Source->SerialRequest,Buffer->SerialRequest,sizeof(struct IOExtSer));
  568.  
  569.             Buffer->SerialRequest->IOSer.io_Message.mn_ReplyPort = MsgPort;
  570.  
  571.             return(Buffer);
  572.         }
  573.         else
  574.             cprint("Could not create serial request\n");
  575.  
  576.         FreeVec(Buffer);
  577.     }
  578.     else
  579.         cprint("Could not create serial buffer\n");
  580.  
  581.     return(NULL);
  582. }
  583.  
  584.     /* DeleteSerialBuffer():
  585.      *
  586.      *    Delete a SerialBuffer structure.
  587.      */
  588.  
  589. STATIC VOID
  590. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  591. {
  592.     if(Buffer)
  593.     {
  594.         if(Buffer->IsBusy)
  595.         {
  596.             if(!CheckIO(Buffer->SerialRequest))
  597.                 AbortIO(Buffer->SerialRequest);
  598.  
  599.             WaitIO(Buffer->SerialRequest);
  600.         }
  601.  
  602.         if(Buffer->IsClone)
  603.             FreeVec(Buffer->SerialRequest);
  604.         else
  605.         {
  606.             CloseDevice(Buffer->SerialRequest);
  607.  
  608.             DeleteIORequest(Buffer->SerialRequest);
  609.         }
  610.  
  611.         FreeVec(Buffer);
  612.     }
  613. }
  614.  
  615.     /* CreateSerialBuffer():
  616.      *
  617.      *    Create a serial buffer structure.
  618.      */
  619.  
  620. STATIC struct SerialBuffer *
  621. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  622. {
  623.     struct SerialBuffer *Buffer;
  624.  
  625.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  626.     {
  627.         Buffer->SerialBuffer    = Buffer->SerialIndex = (UBYTE *)(Buffer + 1);
  628.         Buffer->SerialFilled    = 0;
  629.         Buffer->SerialTop        = Buffer->SerialBuffer + Size;
  630.         Buffer->SerialSize        = Size;
  631.         Buffer->IsClone            = FALSE;
  632.         Buffer->IsBusy            = FALSE;
  633.  
  634.         if(Buffer->SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  635.         {
  636.             Buffer->SerialRequest->io_SerFlags = SERF_SHARED|SERF_7WIRE;
  637.  
  638.             if(!OpenDevice(Device,Unit,Buffer->SerialRequest,NULL))
  639.                 return(Buffer);
  640.             else
  641.             {
  642.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  643.  
  644.                 DeleteIORequest(Buffer->SerialRequest);
  645.             }
  646.         }
  647.         else
  648.             cprint("Could not create serial request\n");
  649.  
  650.         FreeVec(Buffer);
  651.     }
  652.     else
  653.         cprint("Could not create serial buffer\n");
  654.  
  655.     return(NULL);
  656. }
  657.  
  658.     /* OpenAll():
  659.      *
  660.      *    Allocate all the resources required.
  661.      */
  662.  
  663. STATIC BOOL
  664. OpenAll(STRPTR Device,LONG Unit)
  665. {
  666.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  667.     UWORD Pens = (UWORD)~0;
  668.  
  669.     ThisProcess = (struct Process *)FindTask(NULL);
  670.  
  671.     if(pri != 1000)
  672.     {
  673.         if(pri < -128)
  674.             pri = 128;
  675.         else
  676.         {
  677.             if(pri > 127)
  678.                 pri = 127;
  679.         }
  680.  
  681.         OldPri = SetTaskPri(ThisProcess,pri);
  682.     }
  683.  
  684.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  685.     {
  686.         cprint("Could not open intuition.library v37\n");
  687.  
  688.         return(FALSE);
  689.     }
  690.  
  691.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  692.     {
  693.         cprint("Could not open graphics.library v37\n");
  694.  
  695.         return(FALSE);
  696.     }
  697.  
  698.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  699.     {
  700.         cprint("Could not open gadtools.library v37\n");
  701.  
  702.         return(FALSE);
  703.     }
  704.  
  705.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  706.     {
  707.         cprint("Could not open utility.library v37\n");
  708.  
  709.         return(FALSE);
  710.     }
  711.  
  712.     if(!(AslBase = OpenLibrary("asl.library",37)))
  713.     {
  714.         cprint("Could not open asl.library v37\n");
  715.  
  716.         return(FALSE);
  717.     }
  718.  
  719.     if(!(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  720.         ASLFR_TitleText,        "Select file(s) to upload",
  721.         ASLFR_InitialPattern,    "#?",
  722.         ASLFR_Flags1,            FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  723.     TAG_DONE)))
  724.     {
  725.         cprint("Could not allocate file requester.\n");
  726.  
  727.         return(FALSE);
  728.     }
  729.  
  730.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  731.     {
  732.         struct Locale *Locale;
  733.  
  734.         if(Locale = OpenLocale(NULL))
  735.         {
  736.             GMT_Offset = 60 * Locale->loc_GMTOffset + UNIX_TIME_OFFSET;
  737.  
  738.             CloseLocale(Locale);
  739.         }
  740.  
  741.         CloseLibrary(LocaleBase);
  742.     }
  743.  
  744.     if(!(TimePort = CreateMsgPort()))
  745.     {
  746.         cprint("Could not create timer port\n");
  747.  
  748.         return(FALSE);
  749.     }
  750.  
  751.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  752.     {
  753.         cprint("Could not create timer request\n");
  754.  
  755.         return(FALSE);
  756.     }
  757.  
  758.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  759.     {
  760.         cprint("Could not open timer\n");
  761.  
  762.         return(FALSE);
  763.     }
  764.  
  765.     TimerBase = (struct Library *)TimeRequest->tr_node.io_Device;
  766.  
  767.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  768.     {
  769.         cprint("Could not allocate pattern matching buffe\n");
  770.  
  771.         return(FALSE);
  772.     }
  773.  
  774.     Anchor->ap_Strlen = 512;
  775.  
  776.     if(!(ReadPort = CreateMsgPort()))
  777.     {
  778.         cprint("Could not create serial read port\n");
  779.  
  780.         return(FALSE);
  781.     }
  782.  
  783.     if(!(WritePort = CreateMsgPort()))
  784.     {
  785.         cprint("Could not create serial write port\n");
  786.  
  787.         return(FALSE);
  788.     }
  789.  
  790.     Forbid();
  791.  
  792.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  793.     {
  794.         ObtainSemaphore(RendezvousSemaphore);
  795.  
  796.         if(!(RendezvousData = (*RendezvousSemaphore->rs_Login)(ReadPort,WritePort,NULL)))
  797.         {
  798.             Permit();
  799.  
  800.             ReleaseSemaphore(RendezvousSemaphore);
  801.  
  802.             RendezvousSemaphore = NULL;
  803.  
  804.             cprint("Could not link to `term' port \"%s\"\n",Device);
  805.  
  806.             return(FALSE);
  807.         }
  808.     }
  809.  
  810.     Permit();
  811.  
  812.     if(!(ConsoleReadPort = CreateMsgPort()))
  813.     {
  814.         cprint("Could not create console read port\n");
  815.  
  816.         return(FALSE);
  817.     }
  818.  
  819.     if(!(ConsoleWritePort = CreateMsgPort()))
  820.     {
  821.         cprint("Could not create console write port\n");
  822.  
  823.         return(FALSE);
  824.     }
  825.  
  826.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  827.     {
  828.         cprint("Could not create console read request\n");
  829.  
  830.         return(FALSE);
  831.     }
  832.  
  833.     if(!RendezvousData)
  834.     {
  835.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  836.             return(FALSE);
  837.     }
  838.     else
  839.     {
  840.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  841.         {
  842.             ReadBuffer->SerialBuffer    = ReadBuffer->SerialIndex = (UBYTE *)(ReadBuffer + 1);
  843.             ReadBuffer->SerialFilled    = 0;
  844.             ReadBuffer->SerialTop        = ReadBuffer->SerialBuffer + BUFFER_SIZE;
  845.             ReadBuffer->SerialSize        = BUFFER_SIZE;
  846.             ReadBuffer->IsClone            = TRUE;
  847.             ReadBuffer->IsBusy            = FALSE;
  848.             ReadBuffer->SerialRequest    = &RendezvousData->rd_ReadRequest;
  849.  
  850.                 /* Ralph Seichter suggested reusing the data
  851.                  * stored in the rendezvous data.
  852.                  */
  853.  
  854.             com_speed = ReadBuffer->SerialRequest->io_Baud;
  855.  
  856.             if(cur_speed > com_speed)
  857.                 cur_speed = com_speed;
  858.  
  859.             if(ReadBuffer->SerialRequest->io_ReadLen == 7 && ReadBuffer->SerialRequest->io_WriteLen == 7 && (ReadBuffer->SerialRequest->io_SerFlags & (SERF_PARTY_ON|SERF_PARTY_ODD)) == SERF_PARTY_ON && !(ReadBuffer->SerialRequest->io_SerFlags & (SEXTF_MSPON|SEXTF_MARK)))
  860.             {
  861.                 parity = true;
  862.                 hydra_options |= HOPT_HIGHBIT;
  863.             }
  864.             else
  865.                 parity = false;
  866.         }
  867.         else
  868.         {
  869.             cprint("Could not create serial ReadBuffer\n");
  870.  
  871.             return(FALSE);
  872.         }
  873.     }
  874.  
  875.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  876.         return(FALSE);
  877.  
  878.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  879.         return(FALSE);
  880.  
  881.     if(!(PublicScreen = LockPubScreen(NULL)))
  882.     {
  883.         cprint("Could not find default public screen\n");
  884.  
  885.         return(FALSE);
  886.     }
  887.  
  888.     if(RendezvousData)
  889.     {
  890.         if(!(Screen = RendezvousData->rd_Screen))
  891.             Screen = PublicScreen;
  892.     }
  893.     else
  894.     {
  895.         if(!(Screen = OpenScreenTags(NULL,
  896.             SA_DisplayID,    GetVPModeID(&PublicScreen->ViewPort),
  897.             SA_Overscan,    OSCAN_TEXT,
  898.             SA_Depth,        2,
  899.             SA_Title,        PRGNAME " " VERSION " " HC_OS " Amiga rev 9, ported by Olaf `Olsen' Barthel",
  900.             SA_Behind,        TRUE,
  901.             SA_SysFont,        1,
  902.             SA_Pens,        &Pens,
  903.             SA_Interleaved,    TRUE,
  904.         TAG_DONE)))
  905.         {
  906.             cprint("Could not open screen\n");
  907.  
  908.             return(FALSE);
  909.         }
  910.     }
  911.  
  912.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  913.     {
  914.         cprint("Could not obtain screen visual info\n");
  915.  
  916.         return(FALSE);
  917.     }
  918.  
  919.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  920.     {
  921.         cprint("Could not create menus\n");
  922.  
  923.         return(FALSE);
  924.     }
  925.  
  926.     if(!LayoutMenus(Menu,VisualInfo,
  927.         GTMN_TextAttr,        Screen->Font,
  928.         GTMN_NewLookMenus,    TRUE,
  929.     TAG_DONE))
  930.     {
  931.         cprint("Could not layout menus\n");
  932.  
  933.         return(FALSE);
  934.     }
  935.  
  936.     Top                = Screen->BarHeight + 1;
  937.     BorderSize        = Screen->WBorTop + Screen->Font->ta_YSize + 1 + Screen->WBorBottom;
  938.     FontSize        = GfxBase->DefaultFont->tf_YSize;
  939.     TotalHeight        = Screen->Height - Top;
  940.     Lines            = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  941.     ExtraLines        = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  942.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  943.  
  944.     if(Lines < MIN_LINES)
  945.     {
  946.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  947.  
  948.         return(FALSE);
  949.     }
  950.  
  951.     if(!(WindowPort = CreateMsgPort()))
  952.     {
  953.         cprint("Could not create window port\n");
  954.  
  955.         return(FALSE);
  956.     }
  957.  
  958.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  959.     {
  960.         cprint("Could not open console window #1\n");
  961.  
  962.         return(FALSE);
  963.     }
  964.  
  965.     TotalHeight    -= LogWindow->Height + 1;
  966.     Top            += LogWindow->Height + 1;
  967.  
  968.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  969.     {
  970.         cprint("Could not open console window #2\n");
  971.  
  972.         return(FALSE);
  973.     }
  974.  
  975.     ConPrintf(FileRequest,"\033[?7l");
  976.  
  977.     TotalHeight    -= FileWindow->Height + 1;
  978.     Top            += FileWindow->Height + 1;
  979.  
  980.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  981.     {
  982.         cprint("Could not open console window #3\n");
  983.  
  984.         return(FALSE);
  985.     }
  986.  
  987.     TotalHeight    -= RemoteWindow->Height + 1;
  988.     Top            += RemoteWindow->Height + 1;
  989.  
  990.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  991.     {
  992.         cprint("Could not open console window #4\n");
  993.  
  994.         return(FALSE);
  995.     }
  996.  
  997.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  998.  
  999.     ConsoleReadRequest->io_Message.mn_ReplyPort = ConsoleReadPort;
  1000.  
  1001.         /* Turn the cursors back on. */
  1002.  
  1003.     ConPrintf(LocalRequest,"\33[ p");
  1004.     ConPrintf(RemoteRequest,"\33[ p");
  1005.  
  1006.     ConsoleReadRequest->io_Command    = CMD_READ;
  1007.     ConsoleReadRequest->io_Data        = &ConsoleChar;
  1008.     ConsoleReadRequest->io_Length    = 1;
  1009.  
  1010.     ClrSignal(SIG_CONREAD);
  1011.     SendIO(ConsoleReadRequest);
  1012.  
  1013.     OldPtr = ThisProcess->pr_WindowPtr;
  1014.  
  1015.     ThisProcess->pr_WindowPtr = (APTR)LocalWindow;
  1016.  
  1017.     if(!quiet)
  1018.     {
  1019.         ScreenToFront(Screen);
  1020.  
  1021.         ActivateWindow(LocalWindow);
  1022.     }
  1023.  
  1024.     UnlockPubScreen(NULL,PublicScreen);
  1025.  
  1026.     PublicScreen = NULL;
  1027.  
  1028.     if(!RendezvousData)
  1029.         com_flow(flowflags);
  1030.  
  1031.     return(TRUE);
  1032. }
  1033.  
  1034.     /* CloseAll():
  1035.      *
  1036.      *    Close all the resources.
  1037.      */
  1038.  
  1039. STATIC VOID
  1040. CloseAll(VOID)
  1041. {
  1042.     STATIC BOOL CleanupDone = FALSE;
  1043.  
  1044.     if(CleanupDone)
  1045.         return;
  1046.     else
  1047.         CleanupDone = TRUE;
  1048.  
  1049.     if(FileRequester)
  1050.         FreeAslRequest(FileRequester);
  1051.  
  1052.     if(LocalWindow)
  1053.         ClearMenuStrip(LocalWindow);
  1054.  
  1055.     if(Menu)
  1056.         FreeMenus(Menu);
  1057.  
  1058.     if(VisualInfo)
  1059.         FreeVisualInfo(VisualInfo);
  1060.  
  1061.     if(AnchorUsed)
  1062.         MatchEnd(Anchor);
  1063.  
  1064.     if(Anchor)
  1065.         FreeVec(Anchor);
  1066.  
  1067.     if(ThisProcess)
  1068.         ThisProcess->pr_WindowPtr = OldPtr;
  1069.  
  1070.     if(ConsoleReadRequest)
  1071.     {
  1072.         if(ConsoleReadRequest->io_Device)
  1073.         {
  1074.             if(!CheckIO(ConsoleReadRequest))
  1075.                 AbortIO(ConsoleReadRequest);
  1076.  
  1077.             WaitIO(ConsoleReadRequest);
  1078.         }
  1079.  
  1080.         FreeVec(ConsoleReadRequest);
  1081.     }
  1082.  
  1083.     CloseConsole(&LocalWindow,&LocalRequest);
  1084.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1085.     CloseConsole(&FileWindow,&FileRequest);
  1086.     CloseConsole(&LogWindow,&LogRequest);
  1087.  
  1088.     if(WindowPort)
  1089.         DeleteMsgPort(WindowPort);
  1090.  
  1091.     if(!RendezvousData && Screen)
  1092.         CloseScreen(Screen);
  1093.  
  1094.     if(PublicScreen)
  1095.         UnlockPubScreen(NULL,PublicScreen);
  1096.  
  1097.     DeleteSerialBuffer(NextBuffer);
  1098.     DeleteSerialBuffer(ThisBuffer);
  1099.  
  1100.     if(RendezvousData)
  1101.     {
  1102.         if(ReadBuffer->IsBusy)
  1103.         {
  1104.             if(!CheckIO(ReadBuffer->SerialRequest))
  1105.                 AbortIO(ReadBuffer->SerialRequest);
  1106.  
  1107.             WaitIO(ReadBuffer->SerialRequest);
  1108.         }
  1109.  
  1110.         FreeVec(ReadBuffer);
  1111.     }
  1112.     else
  1113.         DeleteSerialBuffer(ReadBuffer);
  1114.  
  1115.     if(ConsoleWritePort)
  1116.         DeleteMsgPort(ConsoleWritePort);
  1117.  
  1118.     if(ConsoleReadPort)
  1119.         DeleteMsgPort(ConsoleReadPort);
  1120.  
  1121.     if(WritePort)
  1122.         DeleteMsgPort(WritePort);
  1123.  
  1124.     if(ReadPort)
  1125.         DeleteMsgPort(ReadPort);
  1126.  
  1127.     if(TimeRequest)
  1128.     {
  1129.         if(TimeRequest->tr_node.io_Device)
  1130.             CloseDevice(TimeRequest);
  1131.  
  1132.         DeleteIORequest(TimeRequest);
  1133.     }
  1134.  
  1135.     if(TimePort)
  1136.         DeleteMsgPort(TimePort);
  1137.  
  1138.     if(UtilityBase)
  1139.         CloseLibrary(UtilityBase);
  1140.  
  1141.     if(AslBase)
  1142.         CloseLibrary(AslBase);
  1143.  
  1144.     if(GadToolsBase)
  1145.         CloseLibrary(GadToolsBase);
  1146.  
  1147.     if(GfxBase)
  1148.         CloseLibrary(GfxBase);
  1149.  
  1150.     if(IntuitionBase)
  1151.         CloseLibrary(IntuitionBase);
  1152.  
  1153.     if(RendezvousData)
  1154.     {
  1155.         (*RendezvousSemaphore->rs_Logoff)(RendezvousData);
  1156.  
  1157.         RendezvousData = NULL;
  1158.     }
  1159.  
  1160.     if(RendezvousSemaphore)
  1161.     {
  1162.         ReleaseSemaphore(RendezvousSemaphore);
  1163.  
  1164.         RendezvousSemaphore = NULL;
  1165.     }
  1166.  
  1167.     if(pri != 1000)
  1168.         OldPri = SetTaskPri(ThisProcess,OldPri);
  1169. }
  1170.  
  1171.     /* ConPrintf():
  1172.      *
  1173.      *    Formatted console output.
  1174.      */
  1175.  
  1176. VOID
  1177. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1178. {
  1179.     if(Request)
  1180.     {
  1181.         STATIC UBYTE Buffer[512];
  1182.  
  1183.         va_list    VarArgs;
  1184.         LONG    Len;
  1185.  
  1186.         va_start(VarArgs,Format);
  1187.         vsprintf(Buffer,Format,VarArgs);
  1188.         va_end(VarArgs);
  1189.  
  1190.         Len = strlen(Buffer);
  1191.  
  1192.         if(Buffer[0] != '\033' && Request == FileRequest)
  1193.         {
  1194.             struct ConUnit *Unit = (struct ConUnit *)Request->io_Unit;
  1195.  
  1196.             if(Unit->cu_XCCP + Len > Unit->cu_XMax)
  1197.             {
  1198.                 if((Len = Unit->cu_XMax - Unit->cu_XCCP) < 1)
  1199.                     return;
  1200.             }
  1201.         }
  1202.  
  1203.         Request->io_Command    = CMD_WRITE;
  1204.         Request->io_Data    = Buffer;
  1205.         Request->io_Length    = Len;
  1206.  
  1207.         DoIO(Request);
  1208.     }
  1209. }
  1210.  
  1211.     /* ConMove():
  1212.      *
  1213.      *    Move the cursor to a new position.
  1214.      */
  1215.  
  1216. VOID
  1217. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1218. {
  1219.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1220. }
  1221.  
  1222.     /* ConGetKey():
  1223.      *
  1224.      *    Read a character from a console window.
  1225.      */
  1226.  
  1227. int
  1228. ConGetKey()
  1229. {
  1230.     if(ConsoleReady)
  1231.     {
  1232.         int Result = ConsoleChar;
  1233.  
  1234.         ConsoleReady = FALSE;
  1235.  
  1236.         ConsoleReadRequest->io_Command    = CMD_READ;
  1237.         ConsoleReadRequest->io_Data        = &ConsoleChar;
  1238.         ConsoleReadRequest->io_Length    = 1;
  1239.  
  1240.         ClrSignal(SIG_CONREAD);
  1241.         SendIO(ConsoleReadRequest);
  1242.  
  1243.         return(Result);
  1244.     }
  1245.     else
  1246.     {
  1247.         int Result = 0;
  1248.  
  1249.         if(WindowReady)
  1250.         {
  1251.             struct IntuiMessage *IntuiMessage;
  1252.             ULONG MsgClass;
  1253.             UWORD MsgCode;
  1254.  
  1255.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow->UserPort))
  1256.             {
  1257.                 MsgClass    = IntuiMessage->Class;
  1258.                 MsgCode        = IntuiMessage->Code;
  1259.  
  1260.                 ReplyMsg(IntuiMessage);
  1261.  
  1262.                 if(MsgClass == IDCMP_MENUPICK)
  1263.                 {
  1264.                     struct MenuItem *Item;
  1265.  
  1266.                     while(MsgCode != MENUNULL)
  1267.                     {
  1268.                         if(Item = ItemAddress(Menu,MsgCode))
  1269.                         {
  1270.                             if(MENU_USERDATA(Item))
  1271.                             {
  1272.                                 if(!Result)
  1273.                                     Result = (int)MENU_USERDATA(Item);
  1274.                             }
  1275.  
  1276.                             MsgCode = Item->NextSelect;
  1277.                         }
  1278.                         else
  1279.                             break;
  1280.                     }
  1281.                 }
  1282.             }
  1283.  
  1284.             WindowReady = FALSE;
  1285.         }
  1286.  
  1287.         return(Result);
  1288.     }
  1289. }
  1290.  
  1291.     /* ConScanKey():
  1292.      *
  1293.      *    Check for a keyboard event.
  1294.      */
  1295.  
  1296. int
  1297. ConScanKey()
  1298. {
  1299.     if(ConsoleReady || WindowReady)
  1300.         return(1);
  1301.     else
  1302.     {
  1303.         int Result = 0;
  1304.  
  1305.         if(CheckSignal(SIG_WINDOW))
  1306.         {
  1307.             WindowReady = TRUE;
  1308.  
  1309.             Result = 1;
  1310.         }
  1311.  
  1312.         if(CheckIO(ConsoleReadRequest))
  1313.         {
  1314.             if(!WaitIO(ConsoleReadRequest))
  1315.             {
  1316.                 ConsoleReady = TRUE;
  1317.  
  1318.                 return(1);
  1319.             }
  1320.             else
  1321.             {
  1322.                 ConsoleReadRequest->io_Command    = CMD_READ;
  1323.                 ConsoleReadRequest->io_Data        = &ConsoleChar;
  1324.                 ConsoleReadRequest->io_Length    = 1;
  1325.  
  1326.                 ClrSignal(SIG_CONREAD);
  1327.                 SendIO(ConsoleReadRequest);
  1328.             }
  1329.         }
  1330.  
  1331.         return(Result);
  1332.     }
  1333.  
  1334.     return(0);
  1335. }
  1336.  
  1337.     /* dtr_out(byte flag):
  1338.      *
  1339.      *    If flag == 0->drop DTR signal, else set it.
  1340.      */
  1341.  
  1342. VOID
  1343. dtr_out(byte flag)
  1344. {
  1345.     if(!flag && !RendezvousData)
  1346.     {
  1347.         if(ThisBuffer->IsBusy)
  1348.         {
  1349.             WaitIO(ThisBuffer->SerialRequest);
  1350.  
  1351.             ThisBuffer->IsBusy        = FALSE;
  1352.             ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1353.         }
  1354.  
  1355.         if(ReadBuffer->IsBusy)
  1356.         {
  1357.             if(!CheckIO(ReadBuffer->SerialRequest))
  1358.                 AbortIO(ReadBuffer->SerialRequest);
  1359.  
  1360.             WaitIO(ReadBuffer->SerialRequest);
  1361.  
  1362.             ReadBuffer->IsBusy            = FALSE;
  1363.             ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1364.             ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  1365.  
  1366.             ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1367.  
  1368.             DoIO(ReadBuffer->SerialRequest);
  1369.  
  1370.             if(ReadBuffer->SerialRequest->IOSer.io_Actual)
  1371.             {
  1372.                 LONG Size = ReadBuffer->SerialSize - ReadBuffer->SerialFilled;
  1373.  
  1374.                 if(Size > 0)
  1375.                 {
  1376.                     if(Size > ReadBuffer->SerialRequest->IOSer.io_Actual)
  1377.                         Size = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1378.  
  1379.                     ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  1380.                     ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer + ReadBuffer->SerialFilled;
  1381.                     ReadBuffer->SerialRequest->IOSer.io_Length    = Size;
  1382.  
  1383.                     DoIO(ReadBuffer->SerialRequest);
  1384.  
  1385.                     ReadBuffer->SerialFilled += ReadBuffer->SerialRequest->IOSer.io_Actual;
  1386.                 }
  1387.             }
  1388.         }
  1389.  
  1390.         CloseDevice(ReadBuffer->SerialRequest);
  1391.  
  1392.         TimeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  1393.         TimeRequest->tr_time.tv_secs    = 1;
  1394.         TimeRequest->tr_time.tv_micro    = 0;
  1395.  
  1396.         DoIO(TimeRequest);
  1397.  
  1398.         if(OpenDevice(device,port,ReadBuffer->SerialRequest,NULL))
  1399.         {
  1400.             CloseAll();
  1401.  
  1402.             exit(10);
  1403.         }
  1404.         else
  1405.         {
  1406.             ReadBuffer->SerialRequest->io_Baud        = ThisBuffer->SerialRequest->io_Baud;
  1407.             ReadBuffer->SerialRequest->io_ReadLen    = ThisBuffer->SerialRequest->io_ReadLen;
  1408.             ReadBuffer->SerialRequest->io_WriteLen    = ThisBuffer->SerialRequest->io_WriteLen;
  1409.             ReadBuffer->SerialRequest->io_SerFlags    = ThisBuffer->SerialRequest->io_SerFlags;
  1410.  
  1411.             ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  1412.  
  1413.             DoIO(ReadBuffer->SerialRequest);
  1414.  
  1415.             CopyMem(ReadBuffer->SerialRequest,ThisBuffer->SerialRequest,sizeof(struct IOExtSer));
  1416.  
  1417.             ThisBuffer->SerialRequest->IOSer.io_Message.mn_ReplyPort = WritePort;
  1418.  
  1419.             CopyMem(ReadBuffer->SerialRequest,NextBuffer->SerialRequest,sizeof(struct IOExtSer));
  1420.  
  1421.             NextBuffer->SerialRequest->IOSer.io_Message.mn_ReplyPort = WritePort;
  1422.         }
  1423.     }
  1424. }
  1425.  
  1426.     /* com_flow(byte flags):
  1427.      *
  1428.      *    The bit mask `flags' determines the style(s) of
  1429.      *    handshaking:
  1430.      *
  1431.      *    if (flags & 9)->enable xON/xOFF software handshaking,
  1432.      *    if (flags & 2)->enable RTS/CTS hardware handshaking
  1433.      */
  1434.  
  1435. VOID
  1436. com_flow(byte flags)
  1437. {
  1438.     if(ThisBuffer->IsBusy)
  1439.     {
  1440.         WaitIO(ThisBuffer->SerialRequest);
  1441.  
  1442.         ThisBuffer->IsBusy        = FALSE;
  1443.         ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1444.     }
  1445.  
  1446.     if(ReadBuffer->IsBusy)
  1447.     {
  1448.         if(!CheckIO(ReadBuffer->SerialRequest))
  1449.             AbortIO(ReadBuffer->SerialRequest);
  1450.  
  1451.         WaitIO(ReadBuffer->SerialRequest);
  1452.  
  1453.         ReadBuffer->IsBusy            = FALSE;
  1454.         ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1455.         ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  1456.  
  1457.         ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1458.  
  1459.         DoIO(ReadBuffer->SerialRequest);
  1460.  
  1461.         if(ReadBuffer->SerialRequest->IOSer.io_Actual)
  1462.         {
  1463.             LONG Size = ReadBuffer->SerialSize - ReadBuffer->SerialFilled;
  1464.  
  1465.             if(Size > 0)
  1466.             {
  1467.                 if(Size > ReadBuffer->SerialRequest->IOSer.io_Actual)
  1468.                     Size = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1469.  
  1470.                 ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  1471.                 ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer + ReadBuffer->SerialFilled;
  1472.                 ReadBuffer->SerialRequest->IOSer.io_Length    = Size;
  1473.  
  1474.                 DoIO(ReadBuffer->SerialRequest);
  1475.  
  1476.                 ReadBuffer->SerialFilled += ReadBuffer->SerialRequest->IOSer.io_Actual;
  1477.             }
  1478.         }
  1479.     }
  1480.  
  1481.     if(flags & 2)
  1482.         ReadBuffer->SerialRequest->io_SerFlags |= SERF_7WIRE;
  1483.     else
  1484.         ReadBuffer->SerialRequest->io_SerFlags &= ~SERF_7WIRE;
  1485.  
  1486.     if(flags & 9)
  1487.         ReadBuffer->SerialRequest->io_SerFlags &= ~SERF_XDISABLED;
  1488.     else
  1489.         ReadBuffer->SerialRequest->io_SerFlags |= SERF_XDISABLED;
  1490.  
  1491.     ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  1492.  
  1493.     DoIO(ReadBuffer->SerialRequest);
  1494.  
  1495.     ThisBuffer->SerialRequest->io_SerFlags = ReadBuffer->SerialRequest->io_SerFlags;
  1496.     NextBuffer->SerialRequest->io_SerFlags = ReadBuffer->SerialRequest->io_SerFlags;
  1497. }
  1498.  
  1499.     /* com_setspeed(long speed):
  1500.      *
  1501.      *    Set the transfer speed (in bits/second).
  1502.      */
  1503.  
  1504. VOID
  1505. com_setspeed(long speed)
  1506. {
  1507.     if(ThisBuffer->IsBusy)
  1508.     {
  1509.         WaitIO(ThisBuffer->SerialRequest);
  1510.  
  1511.         ThisBuffer->IsBusy        = FALSE;
  1512.         ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1513.     }
  1514.  
  1515.     if(ReadBuffer->IsBusy)
  1516.     {
  1517.         if(!CheckIO(ReadBuffer->SerialRequest))
  1518.             AbortIO(ReadBuffer->SerialRequest);
  1519.  
  1520.         WaitIO(ReadBuffer->SerialRequest);
  1521.  
  1522.         ReadBuffer->IsBusy            = FALSE;
  1523.         ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1524.         ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  1525.  
  1526.         ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1527.  
  1528.         DoIO(ReadBuffer->SerialRequest);
  1529.  
  1530.         if(ReadBuffer->SerialRequest->IOSer.io_Actual)
  1531.         {
  1532.             LONG Size = ReadBuffer->SerialSize - ReadBuffer->SerialFilled;
  1533.  
  1534.             if(Size > 0)
  1535.             {
  1536.                 if(Size > ReadBuffer->SerialRequest->IOSer.io_Actual)
  1537.                     Size = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1538.  
  1539.                 ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  1540.                 ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer + ReadBuffer->SerialFilled;
  1541.                 ReadBuffer->SerialRequest->IOSer.io_Length    = Size;
  1542.  
  1543.                 DoIO(ReadBuffer->SerialRequest);
  1544.  
  1545.                 ReadBuffer->SerialFilled += ReadBuffer->SerialRequest->IOSer.io_Actual;
  1546.             }
  1547.         }
  1548.     }
  1549.  
  1550.     ReadBuffer->SerialRequest->io_Baud = speed;
  1551.  
  1552.     if(parity)
  1553.     {
  1554.         ReadBuffer->SerialRequest->io_ReadLen = ReadBuffer->SerialRequest->io_WriteLen = 7;
  1555.         ReadBuffer->SerialRequest->io_SerFlags |= SERF_PARTY_ON;
  1556.     }
  1557.     else
  1558.     {
  1559.         ReadBuffer->SerialRequest->io_ReadLen = ReadBuffer->SerialRequest->io_WriteLen = 8;
  1560.         ReadBuffer->SerialRequest->io_SerFlags &= ~SERF_PARTY_ON;
  1561.     }
  1562.  
  1563.     ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_SETPARAMS;
  1564.  
  1565.     DoIO(ReadBuffer->SerialRequest);
  1566.  
  1567.     ThisBuffer->SerialRequest->io_Baud        = ReadBuffer->SerialRequest->io_Baud;
  1568.     ThisBuffer->SerialRequest->io_ReadLen    = ReadBuffer->SerialRequest->io_ReadLen;
  1569.     ThisBuffer->SerialRequest->io_WriteLen    = ReadBuffer->SerialRequest->io_WriteLen;
  1570.     ThisBuffer->SerialRequest->io_SerFlags    = ReadBuffer->SerialRequest->io_SerFlags;
  1571.  
  1572.     NextBuffer->SerialRequest->io_Baud        = ReadBuffer->SerialRequest->io_Baud;
  1573.     NextBuffer->SerialRequest->io_ReadLen    = ReadBuffer->SerialRequest->io_ReadLen;
  1574.     NextBuffer->SerialRequest->io_WriteLen    = ReadBuffer->SerialRequest->io_WriteLen;
  1575.     NextBuffer->SerialRequest->io_SerFlags    = ReadBuffer->SerialRequest->io_SerFlags;
  1576. }
  1577.  
  1578.     /* com_putblock(byte *s,long len):
  1579.      *
  1580.      *    Send a data block asynchronously.
  1581.      */
  1582.  
  1583. VOID
  1584. com_putblock(byte *s,long len)
  1585. {
  1586.     struct SerialBuffer *Swap = ThisBuffer;
  1587.  
  1588.     if(ThisBuffer->IsBusy)
  1589.         WaitIO(ThisBuffer->SerialRequest);
  1590.     else
  1591.     {
  1592.         if(ThisBuffer->SerialIndex > ThisBuffer->SerialBuffer)
  1593.         {
  1594.             ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1595.             ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1596.             ThisBuffer->SerialRequest->IOSer.io_Length    = ThisBuffer->SerialIndex - ThisBuffer->SerialBuffer;
  1597.  
  1598.             DoIO(ThisBuffer->SerialRequest);
  1599.         }
  1600.     }
  1601.  
  1602.     ThisBuffer->IsBusy        = FALSE;
  1603.     ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1604.  
  1605.     ThisBuffer = NextBuffer;
  1606.     NextBuffer = Swap;
  1607.  
  1608.     if(ThisBuffer->SerialIndex > ThisBuffer->SerialBuffer)
  1609.     {
  1610.         ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1611.         ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1612.         ThisBuffer->SerialRequest->IOSer.io_Length    = ThisBuffer->SerialIndex - ThisBuffer->SerialBuffer;
  1613.  
  1614.         DoIO(ThisBuffer->SerialRequest);
  1615.     }
  1616.  
  1617.     ThisBuffer->IsBusy        = FALSE;
  1618.     ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1619.  
  1620.     while(len > 2 * ThisBuffer->SerialSize)
  1621.     {
  1622.         ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1623.         ThisBuffer->SerialRequest->IOSer.io_Data    = s;
  1624.         ThisBuffer->SerialRequest->IOSer.io_Length    = ThisBuffer->SerialSize;
  1625.  
  1626.         s    += ThisBuffer->SerialSize;
  1627.         len    -= ThisBuffer->SerialSize;
  1628.  
  1629.         DoIO(ThisBuffer->SerialRequest);
  1630.     }
  1631.  
  1632.     CopyMem(s,ThisBuffer->SerialBuffer,MIN(len,ThisBuffer->SerialSize));
  1633.  
  1634.     ThisBuffer->IsBusy                            = TRUE;
  1635.     ThisBuffer->SerialIndex                        = ThisBuffer->SerialBuffer + MIN(len,ThisBuffer->SerialSize);
  1636.     ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1637.     ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1638.     ThisBuffer->SerialRequest->IOSer.io_Length    = MIN(len,ThisBuffer->SerialSize);
  1639.  
  1640.     len    -= ThisBuffer->SerialRequest->IOSer.io_Length;
  1641.     s    += ThisBuffer->SerialRequest->IOSer.io_Length;
  1642.  
  1643.     ClrSignal(SIG_SERWRITE);
  1644.     SendIO(ThisBuffer->SerialRequest);
  1645.  
  1646.     if(len > 0)
  1647.     {
  1648.         CopyMem(s,NextBuffer->SerialBuffer,len);
  1649.  
  1650.         NextBuffer->SerialIndex = NextBuffer->SerialBuffer + len;
  1651.     }
  1652. }
  1653.  
  1654.     /* breakfunc():
  1655.      *
  1656.      *    Cleanup routine for SAS/C.
  1657.      */
  1658.  
  1659. static int
  1660. breakfunc(void)
  1661. {
  1662.     CloseAll();
  1663.  
  1664.     return(1);
  1665. }
  1666.  
  1667.     /* sys_init(VOID):
  1668.      *
  1669.      *    Initialize this driver implementation.
  1670.      */
  1671.  
  1672. VOID
  1673. sys_init(VOID)
  1674. {
  1675.     if(!OpenAll(device,port))
  1676.     {
  1677.         CloseAll();
  1678.  
  1679.         endprog(2);
  1680.     }
  1681.  
  1682.     onbreak(breakfunc);
  1683. }
  1684.  
  1685.     /* sys_reset(VOID):
  1686.      *
  1687.      *    Perform cleanup for this driver implementation.
  1688.      */
  1689.  
  1690. VOID
  1691. sys_reset(VOID)
  1692. {
  1693.     CloseAll();
  1694. }
  1695.  
  1696.     /* sys_idle(VOID):
  1697.      *
  1698.      *    This routine gets called when the system is idle.
  1699.      *    That's a nice one. We are supposed to call the
  1700.      *    system scheduler, etc.
  1701.      */
  1702.  
  1703. VOID
  1704. sys_idle(VOID)
  1705. {
  1706.     ULONG Signals;
  1707.  
  1708.     if(ReadBuffer->SerialFilled <= 0 && !ReadBuffer->IsBusy)
  1709.     {
  1710.         ReadBuffer->IsBusy                            = TRUE;
  1711.         ReadBuffer->SerialIndex                        = ReadBuffer->SerialBuffer;
  1712.         ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  1713.         ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer;
  1714.         ReadBuffer->SerialRequest->IOSer.io_Length    = 1;
  1715.  
  1716.         ClrSignal(SIG_SERREAD);
  1717.         SendIO(ReadBuffer->SerialRequest);
  1718.     }
  1719.  
  1720.     TimeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  1721.     TimeRequest->tr_time.tv_secs    = 1;
  1722.     TimeRequest->tr_time.tv_micro    = 0;
  1723.  
  1724.     ClrSignal(SIG_TIMER);
  1725.     SendIO(TimeRequest);
  1726.  
  1727.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1728.  
  1729.     if(!(Signals & SIG_TIMER))
  1730.     {
  1731.         if(!CheckIO(TimeRequest))
  1732.             AbortIO(TimeRequest);
  1733.     }
  1734.  
  1735.     WaitIO(TimeRequest);
  1736.  
  1737.     if(Signals & SIG_SERREAD)
  1738.     {
  1739.         WaitIO(ReadBuffer->SerialRequest);
  1740.  
  1741.         ReadBuffer->IsBusy            = FALSE;
  1742.         ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1743.         ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  1744.  
  1745.         ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1746.  
  1747.         DoIO(ReadBuffer->SerialRequest);
  1748.  
  1749.         if(ReadBuffer->SerialRequest->IOSer.io_Actual)
  1750.         {
  1751.             LONG Size = ReadBuffer->SerialSize - ReadBuffer->SerialFilled;
  1752.  
  1753.             if(Size > 0)
  1754.             {
  1755.                 if(Size > ReadBuffer->SerialRequest->IOSer.io_Actual)
  1756.                     Size = ReadBuffer->SerialRequest->IOSer.io_Actual;
  1757.  
  1758.                 ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  1759.                 ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer + ReadBuffer->SerialFilled;
  1760.                 ReadBuffer->SerialRequest->IOSer.io_Length    = Size;
  1761.  
  1762.                 DoIO(ReadBuffer->SerialRequest);
  1763.  
  1764.                 ReadBuffer->SerialFilled += ReadBuffer->SerialRequest->IOSer.io_Actual;
  1765.             }
  1766.         }
  1767.     }
  1768.  
  1769.     if(Signals & SIG_SERWRITE)
  1770.     {
  1771.         struct SerialBuffer *Swap = ThisBuffer;
  1772.  
  1773.         WaitIO(ThisBuffer->SerialRequest);
  1774.  
  1775.         ThisBuffer->IsBusy        = FALSE;
  1776.         ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1777.  
  1778.         ThisBuffer = NextBuffer;
  1779.         NextBuffer = Swap;
  1780.     }
  1781.  
  1782.     if(Signals & SIG_CONREAD)
  1783.     {
  1784.         WaitIO(ConsoleReadRequest);
  1785.  
  1786.         ConsoleReady = TRUE;
  1787.     }
  1788.  
  1789.     if(Signals & SIG_WINDOW)
  1790.         WindowReady = TRUE;
  1791. }
  1792.  
  1793.     /* com_outfull(VOID):
  1794.      *
  1795.      *    Return number of bytes still to be transferred.
  1796.      */
  1797.  
  1798. int
  1799. com_outfull(VOID)
  1800. {
  1801.     return(ThisBuffer->SerialIndex - ThisBuffer->SerialBuffer + NextBuffer->SerialIndex - NextBuffer->SerialBuffer);
  1802. }
  1803.  
  1804.     /* carrier(VOID):
  1805.      *
  1806.      *    Return current carrier status.
  1807.      */
  1808.  
  1809. int
  1810. carrier(VOID)
  1811. {
  1812.     if(nocarrier)
  1813.         return(1);
  1814.     else
  1815.     {
  1816.         if(!ThisBuffer->IsBusy)
  1817.         {
  1818.             ThisBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1819.  
  1820.             DoIO(ThisBuffer->SerialRequest);
  1821.  
  1822.             if(ThisBuffer->SerialRequest->io_Status & CIAF_COMCD)
  1823.                 return(0);
  1824.             else
  1825.                 return(1);
  1826.         }
  1827.         else
  1828.         {
  1829.             NextBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  1830.  
  1831.             DoIO(NextBuffer->SerialRequest);
  1832.  
  1833.             if(NextBuffer->SerialRequest->io_Status & CIAF_COMCD)
  1834.                 return(0);
  1835.             else
  1836.                 return(1);
  1837.         }
  1838.     }
  1839. }
  1840.  
  1841.     /* com_flush(VOID):
  1842.      *
  1843.      *    Make sure all pending data gets written.
  1844.      */
  1845.  
  1846. VOID
  1847. com_flush(VOID)
  1848. {
  1849.     if(ThisBuffer->IsBusy)
  1850.     {
  1851.         WaitIO(ThisBuffer->SerialRequest);
  1852.  
  1853.         ThisBuffer->IsBusy        = FALSE;
  1854.         ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1855.     }
  1856.  
  1857.     if(NextBuffer->SerialIndex > NextBuffer->SerialBuffer)
  1858.     {
  1859.         NextBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1860.         NextBuffer->SerialRequest->IOSer.io_Data    = NextBuffer->SerialBuffer;
  1861.         NextBuffer->SerialRequest->IOSer.io_Length    = NextBuffer->SerialIndex - NextBuffer->SerialBuffer;
  1862.  
  1863.         DoIO(NextBuffer->SerialRequest);
  1864.  
  1865.         NextBuffer->SerialIndex = NextBuffer->SerialBuffer;
  1866.     }
  1867. }
  1868.  
  1869.     /* com_putbyte(byte c):
  1870.      *
  1871.      *    Transmit a single byte, queueing it if necessary.
  1872.      */
  1873.  
  1874. VOID
  1875. com_putbyte(byte c)
  1876. {
  1877.     if(ThisBuffer->IsBusy)
  1878.     {
  1879.         if(NextBuffer->SerialIndex + 1 >= NextBuffer->SerialTop)
  1880.         {
  1881.             struct SerialBuffer *Swap = ThisBuffer;
  1882.  
  1883.             WaitIO(ThisBuffer->SerialRequest);
  1884.  
  1885.             ThisBuffer->IsBusy        = FALSE;
  1886.             ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1887.  
  1888.             ThisBuffer = NextBuffer;
  1889.             NextBuffer = Swap;
  1890.  
  1891.             ThisBuffer->IsBusy                            = TRUE;
  1892.             ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1893.             ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1894.             ThisBuffer->SerialRequest->IOSer.io_Length    = ThisBuffer->SerialIndex - ThisBuffer->SerialBuffer;
  1895.  
  1896.             ClrSignal(SIG_SERWRITE);
  1897.             SendIO(ThisBuffer->SerialRequest);
  1898.         }
  1899.  
  1900.         *NextBuffer->SerialIndex++ = c;
  1901.     }
  1902.     else
  1903.     {
  1904.         if(ThisBuffer->SerialIndex + 1 < ThisBuffer->SerialTop)
  1905.         {
  1906.             *ThisBuffer->SerialIndex++ = c;
  1907.  
  1908.             ThisBuffer->IsBusy                            = TRUE;
  1909.             ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1910.             ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1911.             ThisBuffer->SerialRequest->IOSer.io_Length    = 1;
  1912.  
  1913.             ClrSignal(SIG_SERWRITE);
  1914.             SendIO(ThisBuffer->SerialRequest);
  1915.         }
  1916.         else
  1917.         {
  1918.             ThisBuffer->IsBusy                            = TRUE;
  1919.             ThisBuffer->SerialRequest->IOSer.io_Command    = CMD_WRITE;
  1920.             ThisBuffer->SerialRequest->IOSer.io_Data    = ThisBuffer->SerialBuffer;
  1921.             ThisBuffer->SerialRequest->IOSer.io_Length    = ThisBuffer->SerialIndex - ThisBuffer->SerialBuffer;
  1922.  
  1923.             ClrSignal(SIG_SERWRITE);
  1924.             SendIO(ThisBuffer->SerialRequest);
  1925.  
  1926.             *NextBuffer->SerialIndex++ = c;
  1927.         }
  1928.     }
  1929. }
  1930.  
  1931.     /* com_purge(VOID):
  1932.      *
  1933.      *    Clear the read/write buffers.
  1934.      */
  1935.  
  1936. VOID
  1937. com_purge(VOID)
  1938. {
  1939.     if(ThisBuffer->IsBusy)
  1940.     {
  1941.         if(!CheckIO(ThisBuffer->SerialRequest))
  1942.             AbortIO(ThisBuffer->SerialRequest);
  1943.  
  1944.         WaitIO(ThisBuffer->SerialRequest);
  1945.     }
  1946.  
  1947.     ThisBuffer->IsBusy        = FALSE;
  1948.     ThisBuffer->SerialIndex    = ThisBuffer->SerialBuffer;
  1949.  
  1950.     NextBuffer->IsBusy        = FALSE;
  1951.     NextBuffer->SerialIndex    = NextBuffer->SerialBuffer;
  1952.  
  1953.     if(ReadBuffer->IsBusy)
  1954.     {
  1955.         if(!CheckIO(ReadBuffer->SerialRequest))
  1956.             AbortIO(ReadBuffer->SerialRequest);
  1957.  
  1958.         WaitIO(ReadBuffer->SerialRequest);
  1959.     }
  1960.  
  1961.     ReadBuffer->IsBusy            = FALSE;
  1962.     ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  1963.     ReadBuffer->SerialFilled    = 0;
  1964.  
  1965.     ThisBuffer->SerialRequest->IOSer.io_Command = CMD_CLEAR;
  1966.     DoIO(ThisBuffer->SerialRequest);
  1967. }
  1968.  
  1969.     /* com_dump(VOID):
  1970.      *
  1971.      *    Wait for asynchronous write request to terminate.
  1972.      */
  1973.  
  1974. VOID
  1975. com_dump(VOID)
  1976. {
  1977.     com_flush();
  1978. }
  1979.  
  1980.     /* com_getbyte(VOID):
  1981.      *
  1982.      *    Read a single byte from the serial line. If not available,
  1983.      *    return EOF.
  1984.      */
  1985.  
  1986. int
  1987. com_getbyte(VOID)
  1988. {
  1989.     int Result;
  1990.  
  1991.     if(ReadBuffer->SerialFilled <= 0)
  1992.     {
  1993.         if(ReadBuffer->IsBusy)
  1994.         {
  1995.             if(!CheckIO(ReadBuffer->SerialRequest))
  1996.                 return(EOF);
  1997.             else
  1998.                 WaitIO(ReadBuffer->SerialRequest);
  1999.  
  2000.             ReadBuffer->IsBusy            = FALSE;
  2001.             ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  2002.             ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  2003.  
  2004.             ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  2005.  
  2006.             DoIO(ReadBuffer->SerialRequest);
  2007.  
  2008.             if(ReadBuffer->SerialRequest->IOSer.io_Actual)
  2009.             {
  2010.                 LONG Size = ReadBuffer->SerialSize - ReadBuffer->SerialFilled;
  2011.  
  2012.                 if(Size > 0)
  2013.                 {
  2014.                     if(Size > ReadBuffer->SerialRequest->IOSer.io_Actual)
  2015.                         Size = ReadBuffer->SerialRequest->IOSer.io_Actual;
  2016.  
  2017.                     ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  2018.                     ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer + ReadBuffer->SerialFilled;
  2019.                     ReadBuffer->SerialRequest->IOSer.io_Length    = Size;
  2020.  
  2021.                     DoIO(ReadBuffer->SerialRequest);
  2022.  
  2023.                     ReadBuffer->SerialFilled += ReadBuffer->SerialRequest->IOSer.io_Actual;
  2024.                 }
  2025.             }
  2026.         }
  2027.         else
  2028.         {
  2029.             ReadBuffer->SerialRequest->IOSer.io_Command = SDCMD_QUERY;
  2030.  
  2031.             DoIO(ReadBuffer->SerialRequest);
  2032.  
  2033.             if(!ReadBuffer->SerialRequest->IOSer.io_Actual)
  2034.                 return(EOF);
  2035.             else
  2036.             {
  2037.                 ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  2038.                 ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer;
  2039.                 ReadBuffer->SerialRequest->IOSer.io_Length    = MIN(ReadBuffer->SerialRequest->IOSer.io_Actual,ReadBuffer->SerialSize);
  2040.  
  2041.                 DoIO(ReadBuffer->SerialRequest);
  2042.  
  2043.                 if(!ReadBuffer->SerialRequest->IOSer.io_Actual)
  2044.                     return(EOF);
  2045.                 else
  2046.                 {
  2047.                     ReadBuffer->SerialFilled    = ReadBuffer->SerialRequest->IOSer.io_Actual;
  2048.                     ReadBuffer->SerialIndex        = ReadBuffer->SerialBuffer;
  2049.                 }
  2050.             }
  2051.         }
  2052.     }
  2053.  
  2054.     Result = *ReadBuffer->SerialIndex++;
  2055.  
  2056.     ReadBuffer->SerialFilled--;
  2057.  
  2058.     if(ReadBuffer->SerialFilled <= 0)
  2059.     {
  2060.         ReadBuffer->IsBusy                    = TRUE;
  2061.         ReadBuffer->SerialIndex                = ReadBuffer->SerialBuffer;
  2062.  
  2063.         ReadBuffer->SerialRequest->IOSer.io_Command    = CMD_READ;
  2064.         ReadBuffer->SerialRequest->IOSer.io_Data    = ReadBuffer->SerialBuffer;
  2065.         ReadBuffer->SerialRequest->IOSer.io_Length    = 1;
  2066.  
  2067.         ClrSignal(SIG_SERREAD);
  2068.         SendIO(ReadBuffer->SerialRequest);
  2069.     }
  2070.  
  2071.     return(Result);
  2072. }
  2073.  
  2074.     /* setstamp(STRPTR Name,LONG Time):
  2075.      *
  2076.      *    Set time/date of a file.
  2077.      */
  2078.  
  2079. VOID
  2080. setstamp(char *Name,long Time)
  2081. {
  2082.     struct DateStamp Date;
  2083.     ULONG Seconds;
  2084.  
  2085.     DB(kprintf("setstamp |%s| %ld\n",Name,Time));
  2086.  
  2087.         /* Translate it into an Amiga date. */
  2088.  
  2089.     if(Time > GMT_Offset)
  2090.         Seconds = Time - GMT_Offset;
  2091.     else
  2092.         Seconds = 0;
  2093.  
  2094.     Date.ds_Days    = Seconds / (24 * 60 * 60);
  2095.     Date.ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2096.     Date.ds_Tick    = (Seconds % 60) * TICKS_PER_SECOND;
  2097.  
  2098.     SetFileDate(Name,&Date);
  2099. }
  2100.  
  2101.     /* freespace(STRPTR DrivePath):
  2102.      *
  2103.      *    Get free disk space for specified drive.
  2104.      */
  2105.  
  2106. long
  2107. freespace(char *DrivePath)
  2108. {
  2109.     struct DevProc    *DevProc;
  2110.     struct DosList    *DosList;
  2111.     BOOL             GoodDevice;
  2112.     LONG             Size;
  2113.  
  2114.     if(!DrivePath)
  2115.         DrivePath = "";
  2116.  
  2117.     DB(kprintf("freespace |%s|\n",DrivePath));
  2118.  
  2119.     DevProc = GetDeviceProc(DrivePath,NULL);
  2120.  
  2121.     GoodDevice = FALSE;
  2122.     Size = (LONG)((ULONG)~0 >> 2);
  2123.  
  2124.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2125.     {
  2126.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2127.         {
  2128.             if(DosList->dol_Task == DevProc->dvp_Port)
  2129.             {
  2130.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList->dol_misc.dol_handler.dol_Startup);
  2131.  
  2132.                 if(TypeOfMem(FSSM))
  2133.                 {
  2134.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM->fssm_Environ);
  2135.                     STRPTR Name = (STRPTR)BADDR(FSSM->fssm_Device);
  2136.  
  2137.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2138.                     {
  2139.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2140.                         {
  2141.                             struct IOStdReq IORequest;
  2142.  
  2143.                             memset(&IORequest,0,sizeof(IORequest));
  2144.                             IORequest.io_Message.mn_Length = sizeof(IORequest);
  2145.  
  2146.                             if(!OpenDevice(Name + 1,FSSM->fssm_Unit,&IORequest,FSSM->fssm_Unit))
  2147.                             {
  2148.                                 CloseDevice(&IORequest);
  2149.  
  2150.                                 if(DosEnvec->de_TableSize > 0 && DosEnvec->de_LowCyl <= DosEnvec->de_HighCyl)
  2151.                                     GoodDevice = TRUE;
  2152.                             }
  2153.                         }
  2154.                     }
  2155.                 }
  2156.             }
  2157.         }
  2158.  
  2159.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2160.     }
  2161.  
  2162.     FreeDeviceProc(DevProc);
  2163.  
  2164.     if(GoodDevice)
  2165.     {
  2166.         struct InfoData *InfoData;
  2167.  
  2168.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2169.         {
  2170.             UBYTE NewName[MAX_FILENAME_LENGTH],*Index;
  2171.             BPTR FileLock;
  2172.  
  2173.             memcpy(NewName,DrivePath,sizeof(NewName) - 1);
  2174.  
  2175.             NewName[sizeof(NewName) - 1] = 0;
  2176.  
  2177.             Index = PathPart(NewName);
  2178.  
  2179.             *Index = 0;
  2180.  
  2181.             FileLock = Lock(NewName,ACCESS_READ);
  2182.  
  2183.             if(FileLock)
  2184.             {
  2185.                 if(Info(FileLock,InfoData))
  2186.                     Size = InfoData->id_BytesPerBlock * (InfoData->id_NumBlocks - InfoData->id_NumBlocksUsed);
  2187.  
  2188.                 UnLock(FileLock);
  2189.             }
  2190.  
  2191.             FreeVec(InfoData);
  2192.         }
  2193.     }
  2194.  
  2195.     return(Size);
  2196. }
  2197.  
  2198.     /* ffirst(char *FileSpec):
  2199.      *
  2200.      *    Return name of first file matching the given specs.
  2201.      */
  2202.  
  2203. char *
  2204. ffirst(char *filespec)
  2205. {
  2206.     AnchorUsed = TRUE;
  2207.  
  2208.     DB(kprintf("ffirst |%s|\n",filespec));
  2209.  
  2210.     if(MatchFirst(filespec,Anchor))
  2211.         return(NULL);
  2212.     else
  2213.         return((char *)Anchor->ap_Buf);
  2214. }
  2215.  
  2216.     /* fnext(VOID):
  2217.      *
  2218.      *    Return name of next file matching the given specs.
  2219.      */
  2220.  
  2221. char *
  2222. fnext(VOID)
  2223. {
  2224.     AnchorUsed = TRUE;
  2225.  
  2226.     DB(kprintf("fnext\n"));
  2227.  
  2228.     if(MatchNext(Anchor))
  2229.         return(NULL);
  2230.     else
  2231.         return((char *)Anchor->ap_Buf);
  2232. }
  2233.  
  2234.     /* time(time_t *timeptr):
  2235.      *
  2236.      *    Get the current time.
  2237.      */
  2238.  
  2239. time_t
  2240. time(time_t *timeptr)
  2241. {
  2242.     struct timeval    Now;
  2243.     time_t            CurrentTime;
  2244.  
  2245.     DB(kprintf("time 0x%08lx\n",timeptr));
  2246.  
  2247.         /* If the timer is already available,
  2248.          * just read the time. Otherwise, open what
  2249.          * we need to tell the time.
  2250.          */
  2251.  
  2252.     if(TimerBase)
  2253.         GetSysTime(&Now);
  2254.     else
  2255.         UpdateTime(&Now);
  2256.  
  2257.         /* Determine the current time, taking the time
  2258.          * zone into account.
  2259.          */
  2260.  
  2261.     CurrentTime = (time_t)(Now.tv_secs + GMT_Offset);
  2262.  
  2263.     if(timeptr)
  2264.         *timeptr = CurrentTime;
  2265.  
  2266.     return(CurrentTime);
  2267. }
  2268.  
  2269.     /* localtime(const time_t *t):
  2270.      *
  2271.      *    Convert UTC into local time.
  2272.      */
  2273.  
  2274. struct tm *
  2275. localtime(const time_t *t)
  2276. {
  2277.     STATIC struct tm Time;
  2278.  
  2279.     ULONG                Seconds,
  2280.                         Delta;
  2281.     struct ClockData    ClockData;
  2282.     BOOL                CloseIt = FALSE;
  2283.  
  2284.     DB(kprintf("localtime 0x%08lx\n",t));
  2285.  
  2286.         /* We need utility.library for the date conversion. */
  2287.  
  2288.     if(!UtilityBase)
  2289.     {
  2290.         if(UtilityBase = OpenLibrary("utility.library",37))
  2291.             CloseIt = TRUE;
  2292.     }
  2293.  
  2294.         /* Any luck? */
  2295.  
  2296.     if(!UtilityBase)
  2297.     {
  2298.         memset(&Time,0,sizeof(struct tm));
  2299.  
  2300.         return(&Time);
  2301.     }
  2302.  
  2303.         /* Update the time data. */
  2304.  
  2305.     if(!TimerBase)
  2306.         UpdateTime(NULL);
  2307.  
  2308.         /* Add the offset. */
  2309.  
  2310.     if(*t < GMT_Offset)
  2311.         Seconds = 0;
  2312.     else
  2313.         Seconds = (ULONG)*t - GMT_Offset;
  2314.  
  2315.         /* Convert the seconds into time data. */
  2316.  
  2317.     Amiga2Date(Seconds,&ClockData);
  2318.  
  2319.         /* Convert the time data. */
  2320.  
  2321.     Time.tm_sec        = ClockData.sec;
  2322.     Time.tm_min        = ClockData.min;
  2323.     Time.tm_hour    = ClockData.hour;
  2324.     Time.tm_mday    = ClockData.mday;
  2325.     Time.tm_mon        = ClockData.month - 1;
  2326.     Time.tm_year    = ClockData.year - 1900;
  2327.     Time.tm_wday    = ClockData.wday;
  2328.  
  2329.         /* No daylight savings time info is provided. */
  2330.  
  2331.     Time.tm_isdst = 0;
  2332.  
  2333.         /* We will need to fill in the yday entry. */
  2334.  
  2335.     ClockData.mday    = 1;
  2336.     ClockData.month    = 1;
  2337.  
  2338.     Delta = Date2Amiga(&ClockData);
  2339.  
  2340.     Time.tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2341.  
  2342.         /* Clean up if necessary. */
  2343.  
  2344.     if(CloseIt)
  2345.     {
  2346.         CloseLibrary(UtilityBase);
  2347.  
  2348.         UtilityBase = NULL;
  2349.     }
  2350.  
  2351.     return(&Time);
  2352. }
  2353.  
  2354.     /* stat(const char *file,struct stat *st):
  2355.      *
  2356.      *    Get information on a file.
  2357.      */
  2358.  
  2359. int
  2360. stat(const char *file,struct stat *st)
  2361. {
  2362.     BPTR FileLock;
  2363.     D_S(struct FileInfoBlock,FileInfo);
  2364.  
  2365.     DB(kprintf("stat |%s| 0%08lx\n",file,st));
  2366.  
  2367.         /* Try to get a lock on the file. */
  2368.  
  2369.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2370.     {
  2371.         STATIC char    Volume[MAX_FILENAME_LENGTH],Comment[80];
  2372.         D_S(struct InfoData,InfoData);
  2373.  
  2374.             /* Get information on file and filing system. */
  2375.  
  2376.         if(Examine(FileLock,FileInfo) && Info(FileLock,InfoData))
  2377.         {
  2378.             unsigned short mode = 0;
  2379.  
  2380.                 /* Try to get the name of the volume. */
  2381.  
  2382.             if(!NameFromLock(FileLock,Volume,sizeof(Volume)))
  2383.                 Volume[0] = 0;
  2384.             else
  2385.             {
  2386.                 WORD i;
  2387.  
  2388.                     /* Chop off everything after the colon. */
  2389.  
  2390.                 for(i = 0 ; i < sizeof(Volume) ; i++)
  2391.                 {
  2392.                     if(Volume[i] == ':')
  2393.                     {
  2394.                         Volume[i + 1] = 0;
  2395.  
  2396.                         break;
  2397.                     }
  2398.                 }
  2399.             }
  2400.  
  2401.             UnLock(FileLock);
  2402.  
  2403.                 /* Build the protection bits. */
  2404.  
  2405.             if(!(FileInfo->fib_Protection & FIBF_EXECUTE))
  2406.                 mode |= S_IEXECUTE;
  2407.  
  2408.             if(!(FileInfo->fib_Protection & FIBF_DELETE))
  2409.                 mode |= S_IDELETE;
  2410.  
  2411.             if(!(FileInfo->fib_Protection & FIBF_READ))
  2412.                 mode |= S_IREAD;
  2413.  
  2414.             if(!(FileInfo->fib_Protection & FIBF_WRITE))
  2415.                 mode |= S_IWRITE;
  2416.  
  2417.             if(!(FileInfo->fib_Protection & FIBF_ARCHIVE))
  2418.                 mode |= S_IARCHIVE;
  2419.  
  2420.             if(FileInfo->fib_Protection & FIBF_PURE)
  2421.                 mode |= S_IPURE;
  2422.  
  2423.             if(FileInfo->fib_Protection & FIBF_SCRIPT)
  2424.                 mode |= S_ISCRIPT;
  2425.  
  2426.                 /* Keep the comment. */
  2427.  
  2428.             CopyMem(FileInfo->fib_Comment,Comment,79);
  2429.             Comment[79] = 0;
  2430.  
  2431.                 /* Fix the time if necessary. */
  2432.  
  2433.             if(!TimerBase)
  2434.                 UpdateTime(NULL);
  2435.  
  2436.                 /* Fill in the data. */
  2437.  
  2438.             st->st_mode        = mode;
  2439.             st->st_ino        = FileInfo->fib_DiskKey;
  2440.             st->st_dev        = InfoData->id_DiskType;
  2441.             st->st_rdev        = Volume;
  2442.             st->st_nlink    = FileInfo->fib_DirEntryType == ST_SOFTLINK || FileInfo->fib_DirEntryType == ST_LINKDIR || FileInfo->fib_DirEntryType == ST_LINKFILE;
  2443.             st->st_uid        = FileInfo->fib_OwnerUID;
  2444.             st->st_gid        = FileInfo->fib_OwnerGID;
  2445.             st->st_size        = FileInfo->fib_Size;
  2446.             st->st_atime    = GMT_Offset + (FileInfo->fib_Date.ds_Days * 24 * 60 + FileInfo->fib_Date.ds_Minute) * 60 + (FileInfo->fib_Date.ds_Tick / TICKS_PER_SECOND);
  2447.             st->st_mtime    = st->st_atime;
  2448.             st->st_ctime    = st->st_atime;
  2449.             st->st_type        = FileInfo->fib_DirEntryType;
  2450.             st->st_comment    = Comment;
  2451.  
  2452.                 /* Success. */
  2453.  
  2454.             return(0);
  2455.         }
  2456.  
  2457.         UnLock(FileLock);
  2458.     }
  2459.  
  2460.         /* What else should I choose? */
  2461.  
  2462.     errno = _OSERR = EIO;
  2463.  
  2464.     return(-1);
  2465. }
  2466.