1 /* port.c
2 Port manipulation routines for the Taylor UUCP package.
3
4 Copyright (C) 1991, 1992 Ian Lance Taylor
5
6 This file is part of the Taylor UUCP package.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 The author of the program may be contacted at ian@airs.com or
23 c/o AIRS, P.O. Box 520, Waltham, MA 02254.
24
25 $Log: port.c,v $
26 Revision 1.17 1992/04/01 22:31:05 ian
27 Initialize stdin port
28
29 Revision 1.16 1992/03/28 19:57:22 ian
30 David J. MacKenzie: send port device for /Y rather than port name
31
32 Revision 1.15 1992/03/17 01:03:03 ian
33 Miscellaneous cleanup
34
35 Revision 1.14 1992/03/15 06:58:12 ian
36 Show fport_read and fport_write calls under DEBUG_PORT
37
38 Revision 1.13 1992/03/12 19:54:43 ian
39 Debugging based on types rather than number
40
41 Revision 1.12 1992/03/04 00:36:44 ian
42 Michael Richardson: better chat script debugging
43
44 Revision 1.11 1992/02/08 19:34:07 ian
45 Cast result of alloca
46
47 Revision 1.10 1992/02/08 03:54:18 ian
48 Include <string.h> only in <uucp.h>, added 1992 copyright
49
50 Revision 1.9 1991/12/28 04:20:36 ian
51 Cleaned up debugging code
52
53 Revision 1.8 1991/12/20 02:18:35 ian
54 Complete diagnostics for fport_io
55
56 Revision 1.7 1991/12/15 03:42:33 ian
57 Added tprocess_chat_cmd for all chat commands, and added CMDTABTYPE_PREFIX
58
59 Revision 1.6 1991/12/10 19:45:05 ian
60 Added ulog_device to record device name for log file
61
62 Revision 1.5 1991/11/14 03:20:13 ian
63 Added seven-bit and reliable commands to help when selecting protocols
64
65 Revision 1.4 1991/11/13 20:38:00 ian
66 Added TCP port type for connections over TCP
67
68 Revision 1.3 1991/11/11 23:47:24 ian
69 Added chat-program to run a program to do a chat script
70
71 Revision 1.2 1991/11/11 00:39:45 ian
72 Open port in seven bit mode, added fport_set to change to eight bit
73
74 Revision 1.1 1991/09/10 19:40:31 ian
75 Initial revision
76
77 */
78
79 #include "uucp.h"
80
81 #if USE_RCS_ID
82 char port_rcsid[] = "$Id: port.c,v 1.17 1992/04/01 22:31:05 ian Rel $";
83 #endif
84
85 #include <ctype.h>
86
87 #include "port.h"
88
89 #if DEBUG > 1
90
91 /* A debugging routine used when displaying buffers. */
92
93 int
cdebug_char(z,ichar)94 cdebug_char (z, ichar)
95 char *z;
96 int ichar;
97 {
98 char b;
99
100 if (isprint (BUCHAR (ichar))
101 && ichar != '\"'
102 && ichar != '\\')
103 {
104 *z++ = (char) ichar;
105 *z = '\0';
106 return 1;
107 }
108
109 *z++ = '\\';
110
111 switch (ichar)
112 {
113 case '\n':
114 b = 'n';
115 break;
116 case '\r':
117 b = 'r';
118 break;
119 case '\"':
120 b = '\"';
121 break;
122 case '\\':
123 b = '\\';
124 break;
125 default:
126 sprintf (z, "%03o", (unsigned int) BUCHAR (ichar));
127 return strlen (z) + 1;
128 }
129
130 *z++ = b;
131 *z = '\0';
132 return 2;
133 }
134
135 /* Display a buffer when debugging. */
136
137 void
udebug_buffer(zhdr,zbuf,clen)138 udebug_buffer (zhdr, zbuf, clen)
139 const char *zhdr;
140 const char *zbuf;
141 int clen;
142 {
143 char *z, *zalc;
144 int i;
145
146 z = zalc = (char *) xmalloc (clen * 4 + 1);
147 for (i = 0; i < clen && i < 80; i++)
148 z += cdebug_char (z, zbuf[i]);
149 if (i < clen)
150 {
151 *z++ = '.';
152 *z++ = '.';
153 *z++ = '.';
154 }
155 *z = '\0';
156
157 ulog (LOG_DEBUG, "%s %d \"%s\"", zhdr, clen, zalc);
158 xfree ((pointer) zalc);
159 }
160
161 #endif /* DEBUG > 1 */
162
163 /* The open port. */
164
165 struct sport *qPort;
166
167 /* The port dispatch table. The order of entries in this table must
168 be the same as the tporttype enumeration. */
169
170 const struct sportcmds asPortcmds[] =
171 {
172 { fsysdep_stdin_lock, fsysdep_stdin_open, fsysdep_stdin_close,
173 fsysdep_stdin_reset, NULL, fsysdep_stdin_read,
174 fsysdep_stdin_write, fsysdep_stdin_io, fsysdep_stdin_break,
175 fsysdep_stdin_set, fsysdep_stdin_chat, isysdep_stdin_baud },
176 { fsysdep_modem_lock, fsysdep_modem_open, fsysdep_modem_close,
177 fsysdep_modem_reset, fmodem_dial, fsysdep_modem_read,
178 fsysdep_modem_write, fsysdep_modem_io, fsysdep_modem_break,
179 fsysdep_modem_set, fsysdep_modem_chat, isysdep_modem_baud },
180 { fsysdep_direct_lock, fsysdep_direct_open, fsysdep_direct_close,
181 fsysdep_direct_reset, NULL, fsysdep_direct_read,
182 fsysdep_direct_write, fsysdep_direct_io, fsysdep_direct_break,
183 fsysdep_direct_set, fsysdep_direct_chat, isysdep_direct_baud },
184 #if HAVE_TCP
185 { ftcp_lock, ftcp_open, ftcp_close,
186 ftcp_reset, ftcp_dial, fsysdep_tcp_read,
187 fsysdep_tcp_write, fsysdep_tcp_io, NULL,
188 NULL, fsysdep_tcp_chat, itcp_baud },
189 #endif /* HAVE_TCP */
190 };
191
192 /* Port dispatch routines. These could probably become macros,
193 although the port argument would have to be evaluated twice. */
194
195 /* Lock a port. */
196
197 boolean
fport_lock(qport,fin)198 fport_lock (qport, fin)
199 struct sport *qport;
200 boolean fin;
201 {
202 return (*asPortcmds[(int) qport->ttype].pflock) (qport, fin);
203 }
204
205 /* The port structure we use when opening standard input as a port. */
206
207 static struct sport sPstdin =
208 {
209 "stdin",
210 PORTTYPE_STDIN,
211 NULL,
212 0,
213 NULL,
214 0,
215 NULL
216 };
217
218 /* Open a port. */
219
220 boolean
fport_open(qport,ibaud,ihighbaud,fwait)221 fport_open (qport, ibaud, ihighbaud, fwait)
222 struct sport *qport;
223 long ibaud;
224 long ihighbaud;
225 boolean fwait;
226 {
227 boolean fret;
228
229 #if DEBUG > 1
230 if (FDEBUGGING (DEBUG_PORT))
231 {
232 char abspeed[20];
233
234 if (ibaud == (long) 0)
235 strcpy (abspeed, "default speed");
236 else
237 sprintf (abspeed, "speed %ld", ibaud);
238
239 if (qport == NULL)
240 ulog (LOG_DEBUG, "fport_open: Opening stdin port (%s)",
241 abspeed);
242 else if (qport->zname == NULL)
243 ulog (LOG_DEBUG, "fport_open: Opening unnamed port (%s)",
244 abspeed);
245 else
246 ulog (LOG_DEBUG, "fport_open: Opening port %s (%s)",
247 qport->zname, abspeed);
248 }
249 #endif
250
251 if (qport == NULL)
252 {
253 qport = &sPstdin;
254 SYSDEP_STDIN_INIT (&qport->u.sstdin.s);
255 }
256 qPort = NULL;
257
258 /* If the system provides a range of baud rates, we select the
259 highest baud rate supported by the port. */
260 if (ihighbaud != 0)
261 {
262 ibaud = ihighbaud;
263 if (qport->ttype == PORTTYPE_MODEM)
264 {
265 if (qport->u.smodem.ihighbaud != 0)
266 {
267 if (qport->u.smodem.ihighbaud < ihighbaud)
268 ibaud = qport->u.smodem.ihighbaud;
269 }
270 else if (qport->u.smodem.ibaud != 0)
271 ibaud = qport->u.smodem.ibaud;
272 }
273 else if (qport->ttype == PORTTYPE_DIRECT)
274 {
275 if (qport->u.sdirect.ibaud != 0)
276 ibaud = qport->u.sdirect.ibaud;
277 }
278 }
279
280 /* This will normally be overridden by the port specific open
281 routine. */
282 ulog_device (qport->zname);
283
284 fret = (*asPortcmds[(int) qport->ttype].pfopen) (qport, ibaud, fwait);
285 if (fret)
286 qPort = qport;
287 else
288 ulog_device ((const char *) NULL);
289 return fret;
290 }
291
292 /* Close and unlock the port. */
293
294 boolean
fport_close(fsuccess)295 fport_close (fsuccess)
296 boolean fsuccess;
297 {
298 boolean fret;
299
300 if (qPort == NULL)
301 return TRUE;
302
303 DEBUG_MESSAGE0 (DEBUG_PORT, "fport_close: Closing port");
304
305 fret = (*asPortcmds[(int) qPort->ttype].pfclose) (qPort, fsuccess);
306 qPort = NULL;
307 ulog_device ((const char *) NULL);
308 return fret;
309 }
310
311 /* Reset the port. */
312
313 boolean
fport_reset()314 fport_reset ()
315 {
316 DEBUG_MESSAGE0 (DEBUG_PORT, "fport_reset: Resetting port");
317
318 return (*asPortcmds[(int) qPort->ttype].pfreset) (qPort);
319 }
320
321 /* Dial out on the port. */
322
323 boolean
fport_dial(qsys,pcproto_params,pqproto_params,pireliable)324 fport_dial (qsys, pcproto_params, pqproto_params, pireliable)
325 const struct ssysteminfo *qsys;
326 int *pcproto_params;
327 struct sproto_param **pqproto_params;
328 int *pireliable;
329 {
330 boolean (*pfdial) P((struct sport *, const struct ssysteminfo *,
331 int *, struct sproto_param **, int *));
332
333 pfdial = asPortcmds[(int) qPort->ttype].pfdial;
334 if (pfdial == NULL)
335 {
336 *pcproto_params = 0;
337 *pqproto_params = NULL;
338 *pireliable = 0;
339 return TRUE;
340 }
341 return (*pfdial) (qPort, qsys, pcproto_params, pqproto_params,
342 pireliable);
343 }
344
345 /* Read data from the port. */
346
347 boolean
fport_read(zbuf,pclen,cmin,ctimeout,freport)348 fport_read (zbuf, pclen, cmin, ctimeout, freport)
349 char *zbuf;
350 int *pclen;
351 int cmin;
352 int ctimeout;
353 boolean freport;
354 {
355 boolean fret;
356
357 fret = (*asPortcmds[(int) qPort->ttype].pfread) (qPort, zbuf, pclen,
358 cmin, ctimeout,
359 freport);
360 #if DEBUG > 1
361 if (FDEBUGGING (DEBUG_INCOMING))
362 udebug_buffer ("fport_read: Read", zbuf, *pclen);
363 else if (FDEBUGGING (DEBUG_PORT))
364 ulog (LOG_DEBUG, "fport_read: Read %d", *pclen);
365 #endif
366
367 return fret;
368 }
369
370 /* Write data to the port. */
371
372 boolean
fport_write(zbuf,clen)373 fport_write (zbuf, clen)
374 const char *zbuf;
375 int clen;
376 {
377 #if DEBUG > 1
378 if (FDEBUGGING (DEBUG_OUTGOING))
379 udebug_buffer ("fport_write: Writing", zbuf, clen);
380 else if (FDEBUGGING (DEBUG_PORT))
381 ulog (LOG_DEBUG, "fport_write: Writing %d", clen);
382 #endif
383
384 return (*asPortcmds[(int) qPort->ttype].pfwrite) (qPort, zbuf, clen);
385 }
386
387 /* Read and write data. */
388
389 boolean
fport_io(zwrite,pcwrite,zread,pcread)390 fport_io (zwrite, pcwrite, zread, pcread)
391 const char *zwrite;
392 int *pcwrite;
393 char *zread;
394 int *pcread;
395 {
396 boolean fret;
397 #if DEBUG > 1
398 int cwrite = *pcwrite;
399 int cread = *pcread;
400
401 if (cread <= 0 || cwrite <= 0)
402 ulog (LOG_FATAL, "fport_io: cread %d; cwrite %d", cread, cwrite);
403 #endif
404
405 #if DEBUG > 1
406 if (FDEBUGGING (DEBUG_OUTGOING))
407 udebug_buffer ("fport_io: Writing", zwrite, cwrite);
408 #endif
409
410 fret = (*asPortcmds[(int) qPort->ttype].pfio) (qPort, zwrite, pcwrite,
411 zread, pcread);
412
413 DEBUG_MESSAGE4 (DEBUG_PORT,
414 "fport_io: Wrote %d of %d, read %d of %d",
415 *pcwrite, cwrite, *pcread, cread);
416
417 #if DEBUG > 1
418 if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
419 udebug_buffer ("fport_io: Read", zread, *pcread);
420 #endif
421
422 return fret;
423 }
424
425 /* Send a break character to a port. Some port types may not support
426 break characters, in which case we just return TRUE. */
427
428 boolean
fport_break()429 fport_break ()
430 {
431 boolean (*pfbreak) P((struct sport *));
432
433 DEBUG_MESSAGE0 (DEBUG_PORT, "fport_break: Sending break character");
434
435 pfbreak = asPortcmds[(int) qPort->ttype].pfbreak;
436 if (pfbreak == NULL)
437 return TRUE;
438 return (*pfbreak) (qPort);
439 }
440
441 /* Change the setting of a port. Some port types may not support
442 this, in which case we just return TRUE. */
443
444 boolean
fport_set(tset)445 fport_set (tset)
446 enum tportsetting tset;
447 {
448 boolean (*pfset) P((struct sport *, enum tportsetting));
449
450 DEBUG_MESSAGE1 (DEBUG_PORT,
451 "fport_set: Changing setting to %d", (int) tset);
452
453 pfset = asPortcmds[(int) qPort->ttype].pfset;
454 if (pfset == NULL)
455 return TRUE;
456 return (*pfset) (qPort, tset);
457 }
458
459 /* Run a chat program on a port. */
460
461 boolean
fport_run_chat(zprog)462 fport_run_chat (zprog)
463 const char *zprog;
464 {
465 return (*asPortcmds[(int) qPort->ttype].pfchat) (qPort, zprog);
466 }
467
468 /* Get the baud rate of a port. */
469
470 long
iport_baud()471 iport_baud ()
472 {
473 return (*asPortcmds[(int) qPort->ttype].pibaud) (qPort);
474 }
475
476 /* Modem dialing routines. */
477
478 static boolean fpdo_dial P((struct sdialer *qdial, const char *zphone,
479 boolean ftranslate));
480
481 boolean
fmodem_dial(qport,qsys,pcproto_params,pqproto_params,pireliable)482 fmodem_dial (qport, qsys, pcproto_params, pqproto_params, pireliable)
483 struct sport *qport;
484 const struct ssysteminfo *qsys;
485 int *pcproto_params;
486 struct sproto_param **pqproto_params;
487 int *pireliable;
488 {
489 if (qport->u.smodem.zdialer != NULL)
490 {
491 char *zcopy, *zdialer;
492 boolean ffirst;
493
494 /* The zdialer string is a sequence of dialer/token pairs. The
495 dialer portion names a dialer to use. The token portion is
496 what \D and \T in the chat script expand to. If there is no
497 token for the last dialer, the phone number for the system is
498 used. */
499
500 ffirst = TRUE;
501 *pcproto_params = 0;
502 *pqproto_params = NULL;
503 *pireliable = 0;
504
505 zcopy = (char *) alloca (strlen (qport->u.smodem.zdialer) + 1);
506 strcpy (zcopy, qport->u.smodem.zdialer);
507
508 zdialer = strtok (zcopy, " \t");
509 while (zdialer != NULL)
510 {
511 struct sdialer s;
512 char *ztoken;
513 boolean ftranslate, ftoken;
514
515 if (! fread_dialer_info (zdialer, &s))
516 return FALSE;
517
518 ztoken = strtok ((char *) NULL, " \t");
519 ftoken = ztoken != NULL;
520
521 ftranslate = FALSE;
522 if (ztoken == NULL
523 || strcmp (ztoken, "\\D") == 0)
524 ztoken = qsys->zphone;
525 else if (strcmp (ztoken, "\\T") == 0)
526 {
527 ztoken = qsys->zphone;
528 ftranslate = TRUE;
529 }
530
531 /* Perhaps we should accumulate the protocol parameters. */
532 if (ffirst)
533 {
534 *pcproto_params = s.cproto_params;
535 *pqproto_params = s.qproto_params;
536 *pireliable = s.ireliable;
537 ffirst = FALSE;
538 }
539
540 if (! fpdo_dial (&s, ztoken, ftranslate))
541 return FALSE;
542
543 if (! ftoken)
544 zdialer = NULL;
545 else
546 zdialer = strtok ((char *) NULL, " \t");
547 }
548
549 return TRUE;
550 }
551 else if (qport->u.smodem.qdialer != NULL)
552 {
553 *pcproto_params = qport->u.smodem.qdialer->cproto_params;
554 *pqproto_params = qport->u.smodem.qdialer->qproto_params;
555 *pireliable = qport->u.smodem.qdialer->ireliable;
556 return fpdo_dial (qport->u.smodem.qdialer, qsys->zphone, FALSE);
557 }
558 else
559 {
560 ulog (LOG_ERROR, "No dialer information");
561 return FALSE;
562 }
563 }
564
565 /* Actually use a dialer. We set up the modem (which may include
566 opening the dialer device), run the chat script, and finish dealing
567 with the modem. */
568
569 static boolean
fpdo_dial(qdial,zphone,ftranslate)570 fpdo_dial (qdial, zphone, ftranslate)
571 struct sdialer *qdial;
572 const char *zphone;
573 boolean ftranslate;
574 {
575 if (! fsysdep_modem_begin_dial (qPort, qdial))
576 return FALSE;
577
578 if (! fchat (&qdial->schat, (const struct ssysteminfo *) NULL, qdial,
579 zphone, ftranslate, qPort->zname, iport_baud ()))
580 return FALSE;
581
582 return fsysdep_modem_end_dial (qPort, qdial);
583 }
584
585 /* Permit no carrier from a port. */
586
587 boolean
fport_no_carrier()588 fport_no_carrier ()
589 {
590 return fsysdep_modem_no_carrier (qPort);
591 }
592
593 /* Require carrier from a port. */
594
595 boolean
fport_need_carrier()596 fport_need_carrier ()
597 {
598 return fsysdep_modem_need_carrier (qPort);
599 }
600