home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / uucp_mods.lha.30.12.93 / uucp_mods / uucico / sysdep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  13.7 KB  |  730 lines

  1.  
  2. /*
  3.  *  SYSDEP.C
  4.  *
  5.  *  $Header: Beta:src/uucp/src/uucico/RCS/sysdep.c,v 1.1 90/02/02 11:56:16 dillon Exp Locker: dillon $
  6.  *
  7.  * (C) Copyright 1987 by John Gilmore
  8.  * Copying and use of this program are controlled by the terms of the Free
  9.  * Software Foundation's GNU Emacs General Public License.
  10.  *
  11.  *  Amiga Changes Copyright 1988 by William Loftus. All rights reserved.
  12.  *  Additional chgs Copyright 1989 by Matthew Dillon, All Rights Reserved.
  13.  *
  14.  *  Hierarchical Spool Conversion 1 Dec 93,
  15.  *                          Mike J. Bruins. bruins@hal9000.apana.org.au
  16.  */
  17.  
  18. #include <exec/types.h>
  19. #include <exec/exec.h>
  20. #include "includes.h"
  21. #include <hardware/cia.h>
  22. #include <devices/timer.h>
  23. #include <devices/serial.h>
  24. #include <libraries/dos.h>
  25. #include <pwd.h>
  26. #include "uucp.h"
  27. #include "version.h"
  28. #include <OwnDevUnit.h>
  29.  
  30. #define Assert(x)   if (!(x)) _assert_failed(__LINE__);
  31.  
  32. Prototype int openout(char *, int);
  33. Prototype int sigint(void);
  34. Prototype void cleanup(void);
  35. Prototype int xdatardy(void);
  36. Prototype int xgetc(int);
  37. Prototype int xwrite(const void *, int);
  38. Prototype int xwritea(const void *, int);
  39. Prototype int xxwrite(const void *, int, int);
  40. Prototype void SendBreak(void);
  41. Prototype int CheckCarrier(void);
  42. Prototype void *bzero(void *, long);
  43. Prototype void *bcopy(const void *, void *, long);
  44. Prototype void munge_filename(char *, char *);
  45. Prototype int hangup(void);
  46. Prototype int work_scan(char *);
  47. Prototype char *work_next(void);
  48. Prototype void amiga_setup(void);
  49. Prototype void set_baud(int);
  50. Prototype void OpenSerial(int);
  51. Prototype void CloseSerial(int);
  52. Prototype void xexit(int);
  53. Prototype void printc(unsigned char);
  54. Prototype void NiceAbortIO(void *);
  55.  
  56. static void _assert_failed(int);
  57.  
  58. IDENT(".03");
  59.  
  60. /*
  61.  *  Split out of uuslave.c by John Gilmore, 8 August 1987.
  62.  *  ported to the Amiga by William Loftus, 20 September 1987.
  63.  *  rewritten by Matthew Dillon, October 1989
  64.  */
  65.  
  66. /* FIXME -- System dependent defines (not really -- should be in a .h) */
  67. /*
  68.  * Timeout for raw characters -- if we don't hear a char within BYTE_TIMEOUT
  69.  * seconds, we assume the other side has gone away.  Has nothing to do with
  70.  * retransmission timeouts (if any!).
  71.  */
  72.  
  73. extern int debug;
  74. extern int SevenWire;
  75.  
  76. #define FAILURE  1
  77.  
  78. struct IOExtSer Iosr;
  79. struct IOExtSer Iosw;
  80. struct IOExtSer Ioss;
  81. struct timerequest Iot0;
  82. char   *OldTaskName;
  83.  
  84. char    *DeviceName = "serial.device";
  85. long    DeviceUnit = 0;
  86.  
  87. unsigned char    XInBuf[256];       /*  for xgetc() */
  88. char    LockFileName[128];
  89. short    XInIdx = 0;
  90. short    XInLen = 0;
  91. short    IoswIP = 0;
  92. short    IosrIP = 0;
  93. short    IotIP = 0;
  94.  
  95. short    InExitRoutine = 0;
  96. short    debugRead = 0;
  97.  
  98. extern char path[];
  99. extern int Getty;
  100. extern int IgnoreCD;
  101.  
  102. int
  103. openout(acu, baud)
  104. char *acu;
  105. int  baud;
  106. {
  107.     set_baud(baud);
  108.  
  109.     return SUCCESS;
  110. }
  111.  
  112. /*
  113.  * Basement level I/O routines
  114.  *
  115.  * xwrite() writes a character string to the serial port
  116.  * xgetc() returns a character from the serial port, or an EOF for timeout.
  117.  * sigint() restores the state of the serial port on exit.
  118.  */
  119.  
  120. int
  121. sigint()
  122. {
  123.     xexit(10);
  124.     return(0);
  125. }
  126.  
  127.  
  128. void
  129. cleanup()
  130. {
  131.  
  132.     signal(SIGINT, SIG_IGN);
  133.  
  134.     ++InExitRoutine;
  135.  
  136.     if (InExitRoutine == 1 && Iosr.IOSer.io_Device && CheckCarrier())
  137.     reset_modem();
  138.  
  139.     CloseSerial(1);
  140.  
  141.     {
  142.     struct Task *task = (struct Task *)FindTask(NULL);
  143.     if (OldTaskName)
  144.         task->tc_Node.ln_Name = OldTaskName;
  145.     }
  146.  
  147.     if (Iot0.tr_node.io_Device) {
  148.     CloseDevice(&Iot0);
  149.     Iot0.tr_node.io_Device = NULL;
  150.     }
  151.     if (Iot0.tr_node.io_Message.mn_ReplyPort) {
  152.     DeletePort(Iot0.tr_node.io_Message.mn_ReplyPort);
  153.     Iot0.tr_node.io_Message.mn_ReplyPort = NULL;
  154.     }
  155.     chdir(path);
  156.  
  157.     mountrequest(1);
  158.  
  159.     UnLockFiles();      /*  unlock any hanging locks */
  160. }
  161.  
  162. int
  163. xdatardy()
  164. {
  165.     if (XInIdx != XInLen)
  166.     return(1);
  167.     CheckCarrier();
  168.     return (Ioss.IOSer.io_Actual > 0);
  169. }
  170.  
  171. int
  172. xgetc(byteto)
  173. int byteto;
  174. {
  175.     int ch, n;
  176.     long smask;
  177.     long tmask;
  178.     short bytetimeout;
  179.  
  180. top:
  181.     if (XInIdx != XInLen) {
  182.     if (debug > 8) {
  183.         if (debugRead == 0)
  184.         printf("\nREAD: ");
  185.         debugRead = 1;
  186.         printc(XInBuf[XInIdx]);
  187.     }
  188.     return((int)XInBuf[XInIdx++]);
  189.     }
  190.  
  191.     XInIdx = 0;
  192.     XInLen = 0;
  193.  
  194.     if (!CheckCarrier())                        /*  carrier lost?     */
  195.     return(EOF);
  196.  
  197.     Assert(Iosr.IOSer.io_Device);
  198.  
  199.     if ((n = Ioss.IOSer.io_Actual) > 0) {       /*  at least one..    */
  200.     Iosr.IOSer.io_Command = CMD_READ;
  201.     Iosr.IOSer.io_Data = (APTR)XInBuf;
  202.     if (n > sizeof(XInBuf))
  203.         n = sizeof(XInBuf);
  204.     Iosr.IOSer.io_Length = n;
  205.     DoIO(&Iosr);
  206.     if (Iosr.IOSer.io_Actual > 0) {
  207.         if (debug > 8)
  208.         printf("(r%d/%d)", n, Iosr.IOSer.io_Actual);
  209.         XInIdx = 0;
  210.         XInLen = Iosr.IOSer.io_Actual;
  211.         goto top;
  212.     }
  213.     }
  214.  
  215.     /*
  216.      *    no bytes ready, byteto is 0 (no wait)
  217.      */
  218.  
  219.     if (byteto == 0)
  220.     return(EOF);
  221.  
  222.     /*
  223.      *    no bytes ready, wait for one.
  224.      *
  225.      *    once every 3 seconds check carrier detect.
  226.      */
  227.  
  228.     bytetimeout = byteto;
  229.     Iot0.tr_time.tv_secs = 3;
  230.     Iot0.tr_time.tv_micro= 0;
  231.     SendIO(&Iot0);
  232.     IotIP = 1;
  233.  
  234.     Iosr.IOSer.io_Command = CMD_READ;
  235.     Iosr.IOSer.io_Data = (APTR)XInBuf;
  236.     Iosr.IOSer.io_Length = 1;
  237.     Iosr.IOSer.io_Actual = 0;    /*  trying to find a bug... */
  238.     SendIO(&Iosr);
  239.     IosrIP = 1;
  240.  
  241.     smask = 1L << Iosr.IOSer.io_Message.mn_ReplyPort->mp_SigBit;
  242.     tmask = 1L << Iot0.tr_node.io_Message.mn_ReplyPort->mp_SigBit;
  243.  
  244.     for (;;) {
  245.     long mask = Wait(tmask | smask | SIGBREAKF_CTRL_C);
  246.  
  247.     if (mask & SIGBREAKF_CTRL_C) {
  248.         NiceAbortIO(&Iosr);
  249.         WaitIO(&Iosr);
  250.         IosrIP = 0;
  251.         AbortIO(&Iot0);
  252.         WaitIO(&Iot0);
  253.         IotIP = 0;
  254.         xexit(10);
  255.     }
  256.     if (CheckIO(&Iosr)) {
  257.         WaitIO(&Iosr);
  258.         IosrIP = 0;
  259.         AbortIO(&Iot0);
  260.         WaitIO(&Iot0);
  261.         IotIP = 0;
  262.  
  263.         ch = (int)XInBuf[0];
  264.  
  265.         if (debug > 8) {
  266.         if (debugRead == 0)
  267.             printf("\nREAD ");
  268.         debugRead = 1;
  269.         printf("(waitc%d)", Iosr.IOSer.io_Actual);
  270.         printc((unsigned char)ch);
  271.         }
  272.         return(ch);
  273.     }
  274.     if (CheckIO(&Iot0)) {
  275.         WaitIO(&Iot0);
  276.         IotIP = 0;
  277.  
  278.         Iot0.tr_time.tv_secs = 3;
  279.         Iot0.tr_time.tv_micro= 0;
  280.  
  281.         bytetimeout -= Iot0.tr_time.tv_secs;
  282.         if (bytetimeout > 0) {
  283.         if (CheckCarrier() == 0) {
  284.             NiceAbortIO(&Iosr);
  285.             WaitIO(&Iosr);
  286.             IosrIP = 0;
  287.             break;
  288.         }
  289.         SendIO(&Iot0);
  290.         IotIP = 1;
  291.         } else {
  292.         NiceAbortIO(&Iosr);
  293.         WaitIO(&Iosr);
  294.         IosrIP = 0;
  295.         if (Iosr.IOSer.io_Actual == 1)
  296.             return((int)XInBuf[0]);
  297.         break;
  298.         }
  299.     }
  300.     }
  301.     if (debug > 8)
  302.     printf("\nRecv-EOF\n");
  303.     return(EOF);
  304. }
  305.  
  306. int
  307. xwrite(buf, ctr)
  308. const void *buf;
  309. int ctr;
  310. {
  311.     return(xxwrite(buf, ctr, 0));
  312. }
  313.  
  314. int
  315. xwritea(buf, ctr)
  316. const void *buf;
  317. int ctr;
  318. {
  319.     xxwrite(buf, ctr, 1);
  320.     return(ctr);
  321. }
  322.  
  323. int
  324. xxwrite(buf, ctr, async)
  325. const void *buf;
  326. int ctr;
  327. int async;
  328. {
  329.     Assert(Iosr.IOSer.io_Device);
  330.     if (debug > 8) {
  331.     short i;
  332.     if (debugRead)
  333.         printf("\nWRITE ");
  334.     debugRead = 0;
  335.     for (i = 0; i < ctr; ++i) {
  336.         printc(((unsigned char *)buf)[i]);
  337.     }
  338.     printf("\n");
  339.     }
  340.     if (IoswIP) {
  341.     WaitIO(&Iosw);
  342.     IoswIP = 0;
  343.     }
  344.  
  345.     Iosw.IOSer.io_Command = CMD_WRITE;
  346.     Iosw.IOSer.io_Length = ctr;
  347.     Iosw.IOSer.io_Data = (APTR)buf;
  348.     if (async) {
  349.     SendIO(&Iosw);
  350.     IoswIP = 1;
  351.     } else {
  352.     DoIO(&Iosw);
  353.     }
  354.     return ctr;
  355. }
  356.  
  357. void
  358. SendBreak()
  359. {
  360.     Assert(Iosr.IOSer.io_Device);
  361.     Ioss.IOSer.io_Command = SDCMD_BREAK;
  362.     DoIO(&Ioss);
  363. }
  364.  
  365. int
  366. CheckCarrier()
  367. {
  368.     Assert(Iosr.IOSer.io_Device);
  369.     Ioss.IOSer.io_Command = SDCMD_QUERY;
  370.     DoIO(&Ioss);
  371.     if (IgnoreCD)
  372.     return(1);
  373.     if (Ioss.io_Status & CIAF_COMCD)    /*  non-zero == no carrier */
  374.     return(0);
  375.     return(1);
  376. }
  377.  
  378. void *
  379. bzero(s, cnt)
  380. void   *s;
  381. long   cnt;
  382. {
  383.     setmem(s, cnt, 0);
  384.     return(s);
  385. }
  386.  
  387. void *
  388. bcopy(from, to, cnt)
  389. const void   *from;
  390. void   *to;
  391. long   cnt;
  392. {
  393.     movmem(from, to, cnt);
  394.     return(to);
  395. }
  396.  
  397. /*
  398.  * Transform a filename from a uucp packet (in Unix format) into a local
  399.  * filename that will work in the local file system.
  400.  */
  401.  
  402. void
  403. munge_filename(s, d)
  404. char *s, *d;
  405. {
  406.     if (*s != '~') {
  407.     if (s != d)
  408.         strcpy(d, s);
  409.     return;
  410.     }
  411.  
  412.     /*
  413.      *    ~/ ...    convert to UUPUB:
  414.      *    ~user/...   convert to <homedir>/...
  415.      */
  416.  
  417.     {
  418.     short i;
  419.     short c;
  420.     char *t;
  421.     struct passwd *pw;
  422.  
  423.     for (i = 1; s[i] && s[i] != '/'; ++i);
  424.     c = s[i];
  425.  
  426.     s[i] = 0;
  427.     if (i == 1)
  428.         pw = NULL;
  429.     else
  430.         pw = getpwnam(s + 1);
  431.     s[i] = c;
  432.  
  433.     if (c == '/')
  434.         ++i;
  435.  
  436.     if (pw) {
  437.         t = malloc(strlen(pw->pw_dir) + strlen(s + i) + 1);
  438.         strcpy(t, pw->pw_dir);
  439.     } else {
  440.         t = malloc(strlen(s + i) + 32);
  441.         strcpy(t, GetConfigDir(UUPUB));
  442.     }
  443.     strcat(t, s + i);
  444.     strcpy(d, t);
  445.     free(t);
  446.     }
  447. }
  448.  
  449. int
  450. hangup()
  451. {
  452.     static char buf[128];
  453.  
  454.     reset_modem();
  455.  
  456.     sprintf(buf, "run >nil: <nil: %s", GetConfigProgram(UUXQT));
  457.  
  458.     if (PriMode)
  459.     SetTaskPri(FindTask(NULL), OldPri - 1);
  460.  
  461.     if (Execute(buf, NULL, NULL) == 0)
  462.     puts("Unable to run UUXQT");
  463.  
  464.     if (PriMode)
  465.     SetTaskPri(FindTask(NULL), OldPri + 1);
  466.  
  467.     return SUCCESS;
  468. }
  469.  
  470. static char names[MAXFILES*16];
  471. static char *pointers[MAXFILES];
  472. static int file_pointer;
  473.  
  474. int
  475. bp_strcmp(s1, s2)
  476. char **s1;
  477. char **s2;
  478. {
  479.     return(strcmp(*s1, *s2));
  480. }
  481.  
  482. int
  483. work_scan(system_name)
  484. char *system_name;
  485. {
  486.     static char name[128];
  487.     int count;
  488.  
  489.     file_pointer = 0;
  490.  
  491.     if (strlen(system_name) > 7)
  492.     system_name[7] = '\0';
  493.  
  494.     sprintf(name, "C.%s#?", system_name); /* bruins@hal9000.apana.org.au */
  495. /*    sprintf(name, "%sC.%s#?", MakeConfigPath(UUSPOOL, ""), system_name); */
  496.  
  497.     if (debug > 2)
  498.     printf("Looking for %s\n",name);
  499.  
  500.     count = getfnl(name,names,sizeof(names),0);
  501.  
  502.     if (count > 0) {
  503.     if (strbpl(pointers,MAXFILES,names) != count) {
  504.         printf("Too many command files for %s.\n",system_name);
  505.         return(0);
  506.     }
  507.     } else {
  508.     return(0);
  509.     }
  510.     qsort(pointers, count, sizeof(char *), bp_strcmp);
  511.     if (debug > 2)
  512.     printf("Found -> %s\n", pointers[file_pointer]);
  513.     return(1);
  514. }
  515.  
  516. char *
  517. work_next()
  518. {
  519.     char *ptr;
  520.  
  521.     if (ptr = pointers[file_pointer]) {
  522.     if (debug > 2)
  523.         printf("Found -> %s\n", ptr);
  524.     ++file_pointer;
  525.     }
  526.     return(ptr);
  527. }
  528.  
  529. void
  530. amiga_setup()
  531. {
  532.     mountrequest(0);        /*  disallow requesters */
  533.  
  534.     OpenSerial(1);
  535.  
  536.     if (OpenDevice(TIMERNAME, UNIT_VBLANK, &Iot0, 0))  {
  537.     Iot0.tr_node.io_Device = NULL;
  538.     printf("Can't open timer device.");
  539.     xexit(10);
  540.     }
  541.  
  542.     Iot0.tr_node.io_Message.mn_ReplyPort = (struct MsgPort *)CreatePort("UUCICO-Timer", 0L);
  543.     Iot0.tr_node.io_Command = TR_ADDREQUEST;
  544.     Iot0.tr_node.io_Error = 0;
  545.  
  546.     {
  547.     struct Task *task = (struct Task *)FindTask(NULL);
  548.     OldTaskName = task->tc_Node.ln_Name;
  549.     task->tc_Node.ln_Name = "uucico";
  550.     }
  551. }
  552.  
  553. void
  554. set_baud(baud)
  555. int baud;
  556. {
  557.     Assert(Iosr.IOSer.io_Device);
  558.  
  559.     /*
  560.      *    only modify serial parameters if not run from a Getty.    This is
  561.      *    to get around a bug in the A2232 serial.device (possibly also
  562.      *    the normal serial.device) having to do with hanging semaphores.
  563.      *
  564.      *    it is also possible that this might be desirable for operation.
  565.      */
  566.  
  567.     if (Getty == 0) {
  568.     Iosr.IOSer.io_Command = SDCMD_SETPARAMS;
  569.     Iosr.io_SerFlags =  SERF_SHARED | SERF_XDISABLED;
  570.     Iosr.io_Baud = baud;
  571.     Iosr.io_ReadLen = 8L;
  572.     Iosr.io_WriteLen = 8L;
  573.     Iosr.io_CtlChar = 0x11130000L;
  574.     Iosr.io_RBufLen = 4096;
  575.     Iosr.io_StopBits= 1;
  576.     Iosr.io_BrkTime = 500000;
  577.  
  578.     if (SevenWire)
  579.         Iosr.io_SerFlags |= SERF_7WIRE;
  580.  
  581.     DoIO(&Iosr);
  582.     }
  583. }
  584.  
  585. extern short DoAttempt;
  586.  
  587. void
  588. OpenSerial(lock)
  589. int lock;
  590. {
  591.     unsigned char *error;
  592.  
  593.     if (Iosr.IOSer.io_Device) {
  594.     puts("softerror, OpenSerial: Serial Port already open!");
  595.     return;
  596.     }
  597.  
  598.     Iosr.io_SerFlags = SERF_SHARED | SERF_XDISABLED;
  599.     Iosr.IOSer.io_Message.mn_ReplyPort = (struct MsgPort *)CreatePort("Read_RS",0);
  600.  
  601.     if (SevenWire)
  602.     Iosr.io_SerFlags |= SERF_7WIRE;
  603.  
  604.     if (lock && Getty == 0) {
  605.     if (DoAttempt)
  606.         error = AttemptDevUnit(DeviceName, DeviceUnit, "UUcico", 0);
  607.     else
  608.         error = LockDevUnit(DeviceName, DeviceUnit, "UUcico", 0);
  609.  
  610.     if (error) {
  611.         if (error[0] == ODUERR_LEADCHAR[0])
  612.         printf("Unable to lock serial port: %s\n", &error[1]);
  613.         else
  614.         printf("%s unit %d already owned by %s\n",
  615.             DeviceName, DeviceUnit, error);
  616.  
  617.         xexit(10);
  618.     }
  619.     }
  620.  
  621.     if (OpenDevice(DeviceName, DeviceUnit, &Iosr, NULL)) {
  622.     Iosr.IOSer.io_Device = NULL;
  623.     DeletePort(Iosr.IOSer.io_Message.mn_ReplyPort);
  624.     Iosr.IOSer.io_Message.mn_ReplyPort = NULL;
  625.     printf("Can not open serial port for read.\n");
  626.     xexit(TRUE);
  627.     }
  628.  
  629.     Iosw = Iosr;
  630.     Iosw.IOSer.io_Message.mn_ReplyPort = (struct MsgPort *)CreatePort("Write_RS", 0);
  631.     Ioss = Iosw;
  632.  
  633.     Iosr.IOSer.io_Command = SDCMD_QUERY;
  634.     DoIO(&Iosr);
  635.  
  636.     set_baud(Iosr.io_Baud);
  637. }
  638.  
  639. void
  640. CloseSerial(lock)
  641. int lock;
  642. {
  643.     if (IosrIP) {
  644.     NiceAbortIO(&Iosr);
  645.     WaitIO(&Iosr);
  646.     IosrIP = 0;
  647.     }
  648.     if (IotIP) {
  649.     AbortIO(&Iot0);
  650.     WaitIO(&Iot0);
  651.     IotIP = 0;
  652.     }
  653.     if (IoswIP) {
  654.     WaitIO(&Iosw);
  655.     IoswIP = 0;
  656.     }
  657.     if (Iosr.IOSer.io_Device) {
  658.     CloseDevice(&Iosr);
  659.     Iosr.IOSer.io_Device = NULL;
  660.     Iosw.IOSer.io_Device = NULL;
  661.     Ioss.IOSer.io_Device = NULL;
  662.     } else {
  663.     puts("softerr, CloseSerial: Serial Port already closed!");
  664.     }
  665.     if (Iosr.IOSer.io_Message.mn_ReplyPort) {
  666.     DeletePort(Iosr.IOSer.io_Message.mn_ReplyPort);
  667.     Iosr.IOSer.io_Message.mn_ReplyPort = NULL;
  668.     }
  669.     if (Iosw.IOSer.io_Message.mn_ReplyPort) {
  670.     DeletePort(Iosw.IOSer.io_Message.mn_ReplyPort);
  671.     Iosw.IOSer.io_Message.mn_ReplyPort = NULL;
  672.     }
  673.     if (lock && Getty == 0)
  674.     FreeDevUnit(DeviceName, DeviceUnit);
  675. }
  676.  
  677. void
  678. xexit(code)
  679. int code;
  680. {
  681.     cleanup();
  682.  
  683.     if (code)
  684.     printf("\nAbnormal Termination, code %d.\n", code);
  685.     exit(code);
  686. }
  687.  
  688. void
  689. printc(c)
  690. unsigned char c;
  691. {
  692.     c &= 0x7F;
  693.  
  694.     if (c < 32)
  695.     printf("^%c", c | 0x40);
  696.     else if (c == 32)
  697.     printf("_");
  698.     else if (c < 128)
  699.     printf("%c", c);
  700.     else
  701.     printf("(%02x)", c);
  702. }
  703.  
  704. void
  705. _assert_failed(line)
  706. {
  707.     static short reent;
  708.  
  709.     if (reent == 0) {
  710.     ++reent;
  711.     printf("Software Error line %d sysdep.c (uucico)\n", line);
  712.     xexit(20);
  713.     }
  714. }
  715.  
  716. /*
  717.  *  bug fix for older A2232 serial.device's
  718.  */
  719.  
  720. void
  721. NiceAbortIO(ior)
  722. void *ior;
  723. {
  724.     Disable();
  725.     if (((struct Message *)ior)->mn_Node.ln_Type != NT_REPLYMSG)
  726.     AbortIO(ior);
  727.     Enable();
  728. }
  729.  
  730.