eculine.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*+-----------------------------------------------------------------------
  2. eculine.c -- ECU link-independent line handler
  3. wht@wht.net
  4. Defined functions:
  5. lgetc_timeout(msec)
  6. lgetc_xmtr()
  7. lgetc_xmtr_raw()
  8. lgets_timeout(lrwt)
  9. llookfor(lookfor, msecs, echo_flag)
  10. lputc(lchar)
  11. lputc_paced(pace_msec, lchar)
  12. lputs(string)
  13. lputs_paced(pace_msec, string)
  14. lquiet(msecs, echo_flag)
  15. lrdchk_xmtr()
  16. process_xmtr_rcvd_char(rchar, echo)
  17. Men go abroad to wonder at the height of mountains, at the huge
  18. waves of the sea, at the long courses of the ocean, at the
  19. circular motion of the stars; and they pass by themselves
  20. without wondering. -- Saint Augustine
  21. ------------------------------------------------------------------------*/
  22. /*+:EDITS:*/
  23. /*:04-26-2000-11:15-wht@bob-RELEASE 4.42 */
  24. /*:01-02-2000-14:07-wht@menlo-add continue on line error */
  25. /*:02-26-1998-03:11-wht@kepler-linux2/redhat */
  26. /*:01-24-1997-02:37-wht@yuriatin-SOURCE RELEASE 4.00 */
  27. /*:09-11-1996-20:00-wht@yuriatin-3.48-major telnet,curses,structural overhaul */
  28. /*:08-20-1996-12:39-wht@kepler-locale/ctype fixes from ache@nagual.ru */
  29. /*:11-23-1995-11:20-wht@kepler-source control 3.37 for tsx-11 */
  30. /*:11-14-1995-10:23-wht@kepler-3.37.80-source control point: SOCKETS */
  31. /*:11-04-1995-21:02-wht@kepler-add telnet_cmd handling to lgetc_xmtr */
  32. /*:10-18-1995-04:29-wht@kepler-always use select for nap */
  33. /*:10-18-1995-04:16-wht@kepler-break out serial dep into ldserial.c */
  34. /*:10-14-1995-17:08-wht@kepler-'struct termio' to 'struct TERMIO' */
  35. /*:10-14-1995-15:02-wht@kepler-remove Ioctl debug hack */
  36. /*:09-17-1995-16:31-wht@kepler-zero length read under LINUX graceful term */
  37. /*:08-27-1995-06:37-wht@n4hgf-handle hw flow control per shm->Lrtscts_val */
  38. /*:06-12-1995-15:03-wht@n4hgf-if ecu has uucp euid, make use of it */
  39. /*:05-11-1995-15:55-wht@n4hgf-ck_sigint fools optimizing compilers */
  40. /*:03-29-1995-01:09-wht@n4hgf-use ache internationalization code for all */
  41. /*:03-29-1995-01:06-wht@n4hgf-add SIMPLIFY code */
  42. /*:01-12-1995-15:19-wht@n4hgf-apply Andrew Chernov 8-bit clean+FreeBSD patch */
  43. /*:06-19-1994-11:52-wht@gyro-fix lflash_dtr for ESIXSVR4 */
  44. /*:06-03-1994-17:08-wht@kepler-turn off CRTSFL if val < 4 */
  45. /*:05-04-1994-04:38-wht@n4hgf-ECU release 3.30 */
  46. /*:10-27-1993-14:58-wht@n4hgf-bizarre fcntl bug finally fixed */
  47. /*:08-01-1993-02:12-wht@n4hgf-use got_delim in lgets_timeout */
  48. /*:07-20-1993-17:34-wht@n4hgf-set lgets_timeout timeout_counter = qc2 on NUL */
  49. /*:06-12-1993-12:18-wht@n4hgf-move LINST_text to ecuLCK for ecuungetty */
  50. /*:05-29-1993-20:21-wht@n4hgf-change linst_err_text to LINST_text */
  51. /*:05-29-1993-20:18-wht@n4hgf-change ugstat_text to UG_text */
  52. /*:03-01-1993-12:38-wht@n4hgf-defeat make depend on sys/ttold.h */
  53. /*:01-30-1993-12:27-wht@n4hgf-use TIO[CS]DTR on sun to flash DTR */
  54. /*:09-10-1992-13:58-wht@n4hgf-ECU release 3.20 */
  55. /*:08-22-1992-15:38-wht@n4hgf-ECU release 3.20 BETA */
  56. /*:08-21-1992-13:39-wht@n4hgf-rewire direct/modem device use */
  57. /*:08-19-1992-14:03-wht@n4hgf-2nd open in lflash_dtr needs O_NDELAY on SVR4 */
  58. /*:08-16-1992-02:52-wht@n4hgf-some vendors use SCO naming but ttyaa/ttyaA */
  59. /*:07-27-1992-05:49-wht@n4hgf-lopen SCO modem line to make CLOCAL effective */
  60. /*:07-24-1992-14:25-wht@n4hgf-more valiant efforts on lclose failure */
  61. /*:07-19-1992-09:19-wht@n4hgf-lopen validation for char special */
  62. /*:05-11-1992-16:35-wht@gyro-speed up lflash_DTR on sun */
  63. /*:05-04-1992-04:43-kortcs!tim-fix EAGAIN on line open with SVR4 */
  64. /*:04-27-1992-19:57-wht@n4hgf-add LINST_ECUUNGETTY error text */
  65. /*:04-24-1992-21:59-wht@n4hgf-more SCO tty name normalizing */
  66. /*:04-24-1992-21:44-wht@n4hgf-add SCO_direct_tty */
  67. /*:04-12-1992-06:31-wht@gyro-was not canceling alarm on lopen error */
  68. /*:03-29-1992-16:27-wht@n4hgf-put three second timer on lopen */
  69. /*:03-17-1992-18:26-wht@n4hgf-optimize parameter 1 to select() */
  70. /*:12-12-1991-05:14-wht@n4hgf-lgetc_timeout can now return a null character */
  71. /*:11-26-1991-19:47-wht@n4hgf-add ldcdwatch_str */
  72. /*:11-11-1991-22:28-wht@n4hgf-ldcdwatch and lCLOCAL code */
  73. /*:11-11-1991-14:38-wht@n4hgf-lzero_length_read_detected code */
  74. /*:09-01-1991-14:18-wht@n4hgf2-on sun, use termios and improve ldraino */
  75. /*:09-01-1991-02:51-wht@n4hgf2-sun CRTSCTS turn on bug fixed */
  76. /*:08-25-1991-14:39-wht@n4hgf-SVR4 port thanks to aega84!lh */
  77. /*:08-11-1991-18:06-wht@n4hgf-SCO_TTY_NAMING considerations */
  78. /*:08-06-1991-14:18-wht@n4hgf-bit rates below 300 get two stop bits */
  79. /*:07-29-1991-01:55-wht@n4hgf-remove unused externs */
  80. /*:07-25-1991-12:56-wht@n4hgf-ECU release 3.10 */
  81. /*:07-17-1991-07:04-wht@n4hgf-avoid SCO UNIX nap bug */
  82. /*:04-09-1991-16:11-wht@n4hgf-use B0 in lflash_DTR */
  83. /*:02-07-1991-01:00-wht@n4hgf-fix code in for lclose retry on remote XOFF */
  84. /*:01-29-1991-14:54-wht@n4hgf-put code in for lclose retry on remote XOFF */
  85. /*:01-25-1991-05:57-wht@n4hgf-cringe - lflush was flushing console not line */
  86. /*:01-09-1991-22:31-wht@n4hgf-ISC port */
  87. /*:01-09-1991-21:26-wht@n4hgf-don't prototype nap() (ISC port) */
  88. /*:08-14-1990-20:40-wht@n4hgf-ecu3.00-flush old edit history */
  89. #define DECLARE_LINEVARS_PUBLIC
  90. #include "ecu.h"
  91. #include "ecukey.h"
  92. #include "termecu.h"
  93. #include <pwd.h>
  94. #if defined(CFG_TelnetOption)
  95. #include <arpa/telnet.h>
  96. #endif /* defined(CFG_TelnetOption) */
  97. #ifndef O_NONBLOCK
  98. #define O_NONBLOCK 0
  99. #endif
  100. void lreset_ksr();
  101. void lzero_length_read_detected();
  102. void lCLOCAL();
  103. int zero_length_read_detected = 0;
  104. /*
  105. * with SCO UNIX, nap doesn't work as advertized; param MUST be > granularity
  106. * or nap will return immediately; not a problem with XENIX
  107. */
  108. #define LPUTS_NAP_COUNT (min((hzmsec * 2),20L))
  109. /*+-------------------------------------------------------------------------
  110. process_xmtr_rcvd_char(rchar,echo) - feed xmtr-rcvd char to rcvr code
  111. echo: 0 no echo
  112. 1 echo literally
  113. 2 "make printable"
  114. --------------------------------------------------------------------------*/
  115. void
  116. process_xmtr_rcvd_char(rchar, echo)
  117. UINT rchar;
  118. int echo;
  119. {
  120. if (process_rcvd_char(rchar))
  121. return;
  122. if (echo == 1)
  123. {
  124. if (rchar == NL)
  125. fputc(CRET, se);
  126. fputc(rchar, se);
  127. if (rchar != CRET)
  128. plogc(rchar);
  129. }
  130. else if (echo == 2)
  131. {
  132. pputs(graphic_char_text(rchar, 0));
  133. if (rchar == 0x0A)
  134. pputs("\n");
  135. }
  136. } /* end of process_xmtr_rcvd_char */
  137. /*+-------------------------------------------------------------------------
  138. lgetc_xmtr_raw() -- get character from line
  139. zero_length_read_detected is a public that will set if the
  140. DCD watcher is turned on and DCD is lost
  141. --------------------------------------------------------------------------*/
  142. UINT
  143. lgetc_xmtr_raw()
  144. {
  145. int itmp;
  146. uchar char_rtnd;
  147. READ_AGAIN:
  148. if ((itmp = read(shm->Liofd, (char *)&char_rtnd, 1)) < 1)
  149. {
  150. if (!itmp)
  151. {
  152. if(shm->Lsockserve)
  153. {
  154. close(shm->Liofd);
  155. shm->Lconnected = 0;
  156. return(0);
  157. }
  158. if (shm->Ldcdwatch)
  159. {
  160. lzero_length_read_detected();
  161. return (0);
  162. }
  163. errno = EIO; /* for termecu processing */
  164. termecu(TERMECU_LINE_READ_ERROR);
  165. }
  166. if (errno == EINTR) /* if signal interrupted, ... */
  167. {
  168. if (ck_sigint())
  169. return (0);
  170. goto READ_AGAIN;
  171. }
  172. if(shm->Lsockserve)
  173. {
  174. close(shm->Liofd);
  175. shm->Lconnected = 0;
  176. return(0);
  177. }
  178. termecu(TERMECU_LINE_READ_ERROR);
  179. }
  180. shm->rcvd_chars++;
  181. shm->rcvd_chars_this_connect++;
  182. return (char_rtnd);
  183. } /* end of lgetc_xmtr_raw */
  184. /*+-------------------------------------------------------------------------
  185. lgetc_xmtr() -- xmtr version of get char from line
  186. also called by rcvr code when lgetc_buf empty and vmin == 1
  187. zero_length_read_detected is a public that will set if the
  188. DCD watcher is turned on and DCD is lost
  189. if telnet session, intercept and process IAC
  190. --------------------------------------------------------------------------*/
  191. UINT
  192. lgetc_xmtr()
  193. {
  194. UINT char_rtnd = lgetc_xmtr_raw();
  195. #ifdef CFG_TelnetOption
  196. if (shm->Ltelnet && !shm->Ltelnet_raw && (char_rtnd == IAC))
  197. {
  198. telnet_cmd(0);
  199. char_rtnd = 0;
  200. }
  201. #endif
  202. if (shm->Lparity)
  203. char_rtnd &= 0x7F;
  204. return (char_rtnd);
  205. } /* end of lgetc_xmtr */
  206. /*+-------------------------------------------------------------------------
  207. lrdchk_xmtr() -- Rdchk(shm->Liofd) for xmtr
  208. --------------------------------------------------------------------------*/
  209. int
  210. lrdchk_xmtr()
  211. {
  212. return (Rdchk(shm->Liofd));
  213. } /* end of lrdchk_xmtr */
  214. /*+-------------------------------------------------------------------------
  215. char *lgets_timeout(LRWT *) - may be called by xmtr only
  216. to1 and to2 are unsigned long values in milliseconds (not
  217. currently supported well under BSD4); to1 is the time to wait
  218. for the first character, to2 the time to wait for subsequent
  219. characters.
  220. if raw_flag 0, non-printables are stripped from beginning
  221. and end of received characters (i.e., modem
  222. response reads); NULs discarded, parity stripped
  223. if raw_flag 1, full raw read buffer returned
  224. 0x80 in raw_flag indicates console interrupts should be enabled.
  225. if interrupt thus detected, the procedure returns "!Interrupted"
  226. without reseting variable 'interrupt'
  227. buffer is address to read chars into
  228. bufsize is buffer max size (allowing room for terminating null)
  229. which should be at least 2 if raw_size includes 0x80 bit,
  230. else at least 12 characters if 0x80 omitted.
  231. count is a int which, at return, receives the actual count read
  232. zero_length_read_detected is a public that will set if the
  233. DCD watcher is turned on and DCD is lost
  234. --------------------------------------------------------------------------*/
  235. char *
  236. lgets_timeout(lrwt)
  237. LRWT *lrwt;
  238. {
  239. int actual_count = 0;
  240. char *cp = lrwt->buffer;
  241. int max_count = lrwt->bufsize;
  242. int raw_mode = lrwt->raw_flag & 0x0F;
  243. int echo_flag = lrwt->echo_flag;
  244. int check_sigint = (lrwt->raw_flag & 0x80);
  245. int old_ttymode = get_ttymode(); /* save original tty mode */
  246. int delim_len;
  247. struct timeval tval;
  248. char *rtn_val;
  249. #ifdef CFG_HasFdSet
  250. CFG_FDSET fdset;
  251. FD_ZERO(&fdset);
  252. #else
  253. int fdset;
  254. #endif
  255. delim_len = (lrwt->delim) ? strlen(lrwt->delim) : 0;
  256. if ((shm->Lbitrate < 300) && lrwt->to2)
  257. {
  258. if (lrwt->to2 < 300L)
  259. lrwt->to2 = 300L;
  260. else if ((shm->Lbitrate < 1200) && lrwt->to2)
  261. {
  262. if (lrwt->to2 < 200L)
  263. lrwt->to2 = 100L;
  264. }
  265. }
  266. /* perform the lrtw function
  267. output: lrwt->count is actual count of return result
  268. lrwt->buffer is return read buffer
  269. */
  270. max_count--; /* leave room for null */
  271. if (check_sigint)
  272. ttymode(2); /* let console interrupt long timeouts */
  273. *cp = 0; /* init result string */
  274. lrwt->got_delim = 0; /* no delimiter read yet */
  275. while (1)
  276. {
  277. if (check_sigint && ck_sigint())
  278. goto INTERRUPTED;
  279. errno = 0;
  280. if (actual_count)
  281. {
  282. tval.tv_sec = lrwt->to2 / 1000L;
  283. tval.tv_usec = (lrwt->to2 % 1000L) * 1000L;
  284. }
  285. else
  286. {
  287. tval.tv_sec = lrwt->to1 / 1000L;
  288. tval.tv_usec = (lrwt->to1 % 1000L) * 1000L;
  289. }
  290. #ifdef CFG_HasFdSet
  291. FD_SET(shm->Liofd, &fdset);
  292. #else
  293. fdset = 1 << shm->Liofd; /* Liofd will always be <= 31, right? */
  294. #endif
  295. errno = 0;
  296. if (select(shm->Liofd + 1, &fdset,
  297. (SelBitmask *) 0, (SelBitmask *) 0, &tval) != 1)
  298. {
  299. if (errno == EINTR)
  300. continue;
  301. break;
  302. }
  303. #if 0
  304. while (Rdchk(shm->Liofd))
  305. {
  306. #endif
  307. zero_length_read_detected = 0;
  308. *cp = lgetc_xmtr();
  309. if (zero_length_read_detected)
  310. goto BOTTOM;
  311. if (check_sigint && ck_sigint())
  312. goto INTERRUPTED;
  313. if (*cp == 0)
  314. continue;
  315. process_xmtr_rcvd_char(*cp, !!echo_flag);
  316. if (!raw_mode && (*cp == CRET))
  317. continue;
  318. *++cp = 0;
  319. actual_count++;
  320. if (--max_count == 0)
  321. goto BOTTOM;
  322. if (delim_len && (actual_count >= delim_len) &&
  323. !strncmp(lrwt->delim, cp - delim_len, delim_len))
  324. {
  325. lrwt->got_delim = 1;
  326. goto BOTTOM;
  327. }
  328. #if 0
  329. }
  330. if (!lrwt->to2)
  331. break;
  332. #endif
  333. }
  334. /********* common post processing for select() / no select() ************/
  335. BOTTOM:
  336. if (check_sigint)
  337. ttymode(old_ttymode);
  338. if (raw_mode)
  339. {
  340. lrwt->count = actual_count;
  341. return (lrwt->buffer);
  342. }
  343. cp = lrwt->buffer;
  344. while (*cp && !isprint((uchar) * cp))
  345. cp++;
  346. rtn_val = cp;
  347. actual_count = 0;
  348. while (*cp && isprint((uchar) * cp))
  349. {
  350. cp++;
  351. actual_count++;
  352. }
  353. *cp = 0;
  354. strcpy(lrwt->buffer, rtn_val);
  355. lrwt->count = actual_count;
  356. return (lrwt->buffer);
  357. INTERRUPTED:
  358. ttymode(old_ttymode);
  359. strcpy(lrwt->buffer, "!Interrupted");
  360. lrwt->count = strlen(lrwt->buffer);
  361. return ((char *)0);
  362. } /* end of lgets_timeout */
  363. /*+-------------------------------------------------------------------------
  364. lgetc_timeout(msec) - may be called by xmtr only
  365. reads one character from line unless msec passes with no receipt.
  366. return char if received, else -1 if timeout
  367. --------------------------------------------------------------------------*/
  368. int
  369. lgetc_timeout(msec)
  370. long msec;
  371. {
  372. struct timeval tval;
  373. UINT ch;
  374. #ifdef CFG_HasFdSet
  375. CFG_FDSET fdset;
  376. FD_ZERO(&fdset);
  377. FD_SET(shm->Liofd, &fdset);
  378. #else
  379. int fdset = 1 << shm->Liofd; /* Liofd will always be <= 31, right? */
  380. #endif
  381. tval.tv_sec = msec / 1000L;
  382. tval.tv_usec = (msec % 1000L) * 1000L;
  383. if (select(shm->Liofd + 1, &fdset,
  384. (SelBitmask *) 0, (SelBitmask *) 0, &tval) != 1)
  385. {
  386. return (-1);
  387. }
  388. if (ck_sigint())
  389. return (-1);
  390. ch = lgetc_xmtr();
  391. return ((int)ch);
  392. } /* end of lgetc_timeout */
  393. /*+-------------------------------------------------------------------------
  394. llookfor(lookfor,msecs,echo_flag)
  395. return 1 if successful, else 0 if no match
  396. echo_flag: 0 no echo
  397. 1 echo literally
  398. 2 "make printable"
  399. --------------------------------------------------------------------------*/
  400. int
  401. llookfor(lookfor, msecs, echo_flag)
  402. char *lookfor;
  403. UINT32 msecs;
  404. int echo_flag;
  405. {
  406. int lookfor_len = strlen(lookfor);
  407. int lchar;
  408. uchar *lastfew = (uchar *)malloc(lookfor_len);
  409. int success_flag = 0;
  410. int old_ttymode = get_ttymode();
  411. if (!lastfew)
  412. {
  413. pputs("memory exhausted\n");
  414. return (0);
  415. }
  416. ttymode(2);
  417. memset(lastfew, 0, lookfor_len);
  418. while ((lchar = lgetc_timeout(msecs)) >= 0)
  419. {
  420. if (!lchar) /* skip nulls */
  421. continue;
  422. process_xmtr_rcvd_char(lchar, echo_flag);
  423. mem_cpy(lastfew, lastfew + 1, lookfor_len - 1);
  424. *(lastfew + lookfor_len - 1) = (uchar) lchar;
  425. if (!memcmp(lastfew, lookfor, lookfor_len))
  426. {
  427. success_flag = 1;
  428. break;
  429. }
  430. }
  431. free(lastfew);
  432. ttymode(old_ttymode);
  433. return (success_flag);
  434. } /* end of llookfor */
  435. /*+-------------------------------------------------------------------------
  436. lquiet(msecs,echo_flag)
  437. --------------------------------------------------------------------------*/
  438. void
  439. lquiet(msecs, echo_flag)
  440. UINT32 msecs;
  441. int echo_flag;
  442. {
  443. int lchar;
  444. int old_ttymode = get_ttymode();
  445. ttymode(2);
  446. while ((lchar = lgetc_timeout(msecs)) >= 0)
  447. {
  448. if (ck_sigint()) /* if interrupt, return */
  449. break;
  450. if (!lchar) /* skip nulls */
  451. continue;
  452. process_xmtr_rcvd_char(lchar, !!echo_flag);
  453. }
  454. ttymode(old_ttymode);
  455. } /* end of lquiet */
  456. /*+-----------------------------------------------------------------------
  457. lputc(lchar) -- write lchar to comm line
  458. ------------------------------------------------------------------------*/
  459. void
  460. lputc(lchar)
  461. char lchar;
  462. {
  463. while (write(shm->Liofd, &lchar, 1) < 0)
  464. {
  465. char s80[80];
  466. if (errno == EINTR)
  467. continue;
  468. if(shm->Ltelnet)
  469. {
  470. close(shm->Liofd);
  471. shm->Lconnected = 0;
  472. return;
  473. }
  474. sprintf(s80, "lputc write error fd=%d", shm->Liofd);
  475. pperror(s80);
  476. termecu(TERMECU_XMTR_WRITE_ERROR);
  477. }
  478. shm->xmit_chars++;
  479. shm->xmit_chars_this_connect++;
  480. } /* end of lputc */
  481. /*+-----------------------------------------------------------------------
  482. lputc_paced(pace_msec,lchar) -- write lchar to comm line
  483. with time between each character
  484. ------------------------------------------------------------------------*/
  485. void
  486. lputc_paced(pace_msec, lchar)
  487. int pace_msec;
  488. char lchar;
  489. {
  490. lputc(lchar);
  491. Nap((long)(pace_msec ? pace_msec : LPUTS_NAP_COUNT));
  492. } /* end of lputc_paced */
  493. /*+-----------------------------------------------------------------------
  494. lputs(string) -- write string to comm line
  495. ------------------------------------------------------------------------*/
  496. void
  497. lputs(string)
  498. char *string;
  499. {
  500. while (*string)
  501. lputc(*string++);
  502. }
  503. /*+-----------------------------------------------------------------------
  504. lputs_paced(pace_msec,string) -- write string to comm line
  505. with time between each character
  506. ------------------------------------------------------------------------*/
  507. void
  508. lputs_paced(pace_msec, string)
  509. int pace_msec;
  510. char *string;
  511. {
  512. while (*string)
  513. lputc_paced(pace_msec, *string++);
  514. } /* end of lputs_paced */
  515. /* vi: set tabstop=4 shiftwidth=4: */
  516. /* end of eculine.c */