xref: /386bsd/usr/src/libexec/uucp/port.c (revision a2142627)
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