1/* conn.c
2   Connection routines for the Taylor UUCP package.
3
4   Copyright (C) 1991, 1992, 1993, 1994, 2002 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char conn_rcsid[] = "$Id: conn.c,v 1.18 2002/03/05 19:10:41 ian Rel $";
29#endif
30
31#include <ctype.h>
32
33#include "uudefs.h"
34#include "uuconf.h"
35#include "conn.h"
36
37/* Create a new connection.  This relies on system dependent functions
38   to set the qcmds and psysdep fields.  If qport is NULL, it opens a
39   standard input port, in which case ttype is the type of port to
40   use.  */
41
42boolean
43fconn_init (qport, qconn, ttype)
44     struct uuconf_port *qport;
45     struct sconnection *qconn;
46     enum uuconf_porttype ttype;
47{
48  qconn->qport = qport;
49  switch (qport == NULL ? ttype : qport->uuconf_ttype)
50    {
51    case UUCONF_PORTTYPE_STDIN:
52      return fsysdep_stdin_init (qconn);
53    case UUCONF_PORTTYPE_MODEM:
54      return fsysdep_modem_init (qconn);
55    case UUCONF_PORTTYPE_DIRECT:
56      return fsysdep_direct_init (qconn);
57#if HAVE_TCP
58    case UUCONF_PORTTYPE_TCP:
59      return fsysdep_tcp_init (qconn);
60#endif
61#if HAVE_TLI
62    case UUCONF_PORTTYPE_TLI:
63      return fsysdep_tli_init (qconn);
64#endif
65    case UUCONF_PORTTYPE_PIPE:
66      return fsysdep_pipe_init (qconn);
67    default:
68      ulog (LOG_ERROR, "Unknown or unsupported port type");
69      return FALSE;
70    }
71}
72
73/* Connection dispatch routines.  */
74
75/* Free a connection.  */
76
77void
78uconn_free (qconn)
79     struct sconnection *qconn;
80{
81  (*qconn->qcmds->pufree) (qconn);
82}
83
84/* Lock a connection.   */
85
86boolean
87fconn_lock (qconn, fin, fuser)
88     struct sconnection *qconn;
89     boolean fin;
90     boolean fuser;
91{
92  boolean (*pflock) P((struct sconnection *, boolean, boolean));
93
94  pflock = qconn->qcmds->pflock;
95  if (pflock == NULL)
96    return TRUE;
97  return (*pflock) (qconn, fin, fuser);
98}
99
100/* Unlock a connection.  */
101
102boolean
103fconn_unlock (qconn)
104     struct sconnection *qconn;
105{
106  boolean (*pfunlock) P((struct sconnection *));
107
108  pfunlock = qconn->qcmds->pfunlock;
109  if (pfunlock == NULL)
110    return TRUE;
111  return (*pfunlock) (qconn);
112}
113
114/* Open a connection.  */
115
116boolean
117fconn_open (qconn, ibaud, ihighbaud, fwait, fuser)
118     struct sconnection *qconn;
119     long ibaud;
120     long ihighbaud;
121     boolean fwait;
122     boolean fuser;
123{
124  boolean fret;
125
126#if DEBUG > 1
127  if (FDEBUGGING (DEBUG_PORT))
128    {
129      char abspeed[20];
130
131      if (ibaud == (long) 0)
132	strcpy (abspeed, "default speed");
133      else
134	sprintf (abspeed, "speed %ld", ibaud);
135
136      if (qconn->qport == NULL)
137	ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)",
138	      abspeed);
139      else if (qconn->qport->uuconf_zname == NULL)
140	ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)",
141	      abspeed);
142      else
143	ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)",
144	      qconn->qport->uuconf_zname, abspeed);
145    }
146#endif
147
148  /* If the system provides a range of baud rates, we select the
149     highest baud rate supported by the port.  */
150  if (ihighbaud != 0 && qconn->qport != NULL)
151    {
152      struct uuconf_port *qport;
153
154      qport = qconn->qport;
155      ibaud = ihighbaud;
156      if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
157	{
158	  if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0)
159	    {
160	      if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud)
161		ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud;
162	    }
163	  else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0)
164	    ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
165	}
166      else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
167	{
168	  if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0)
169	    ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
170	}
171    }
172
173  /* This will normally be overridden by the port specific open
174     routine.  */
175  if (qconn->qport == NULL)
176    ulog_device ("stdin");
177  else
178    ulog_device (qconn->qport->uuconf_zname);
179
180  fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait, fuser);
181
182  if (! fret)
183    ulog_device ((const char *) NULL);
184
185  return fret;
186}
187
188/* Close a connection.  */
189
190boolean
191fconn_close (qconn, puuconf, qdialer, fsuccess)
192     struct sconnection *qconn;
193     pointer puuconf;
194     struct uuconf_dialer *qdialer;
195     boolean fsuccess;
196{
197  boolean fret;
198
199  DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection");
200
201  /* Don't report hangup signals while we're closing.  */
202  fLog_sighup = FALSE;
203
204  fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess);
205
206  /* Ignore any SIGHUP we may have gotten, and make sure any signal
207     reporting has been done before we reset fLog_sighup.  */
208  afSignal[INDEXSIG_SIGHUP] = FALSE;
209  ulog (LOG_ERROR, (const char *) NULL);
210  fLog_sighup = TRUE;
211
212  ulog_device ((const char *) NULL);
213
214  return fret;
215}
216
217/* Dial out on the connection.  */
218
219boolean
220fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
221     struct sconnection *qconn;
222     pointer puuconf;
223     const struct uuconf_system *qsys;
224     const char *zphone;
225     struct uuconf_dialer *qdialer;
226     enum tdialerfound *ptdialerfound;
227{
228  struct uuconf_dialer sdialer;
229  enum tdialerfound tfound;
230  boolean (*pfdial) P((struct sconnection *, pointer,
231		       const struct uuconf_system *, const char *,
232		       struct uuconf_dialer *, enum tdialerfound *));
233
234  if (qdialer == NULL)
235    qdialer = &sdialer;
236  if (ptdialerfound == NULL)
237    ptdialerfound = &tfound;
238
239  qdialer->uuconf_zname = NULL;
240  *ptdialerfound = DIALERFOUND_FALSE;
241
242  pfdial = qconn->qcmds->pfdial;
243  if (pfdial == NULL)
244    return TRUE;
245  return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound);
246}
247
248/* Read data from the connection.  */
249
250boolean
251fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
252     struct sconnection *qconn;
253     char *zbuf;
254     size_t *pclen;
255     size_t cmin;
256     int ctimeout;
257     boolean freport;
258{
259  boolean fret;
260
261  fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout,
262				  freport);
263
264#if DEBUG > 1
265  if (FDEBUGGING (DEBUG_INCOMING))
266    udebug_buffer ("fconn_read: Read", zbuf, *pclen);
267  else if (FDEBUGGING (DEBUG_PORT))
268    ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen);
269#endif
270
271  return fret;
272}
273
274/* Write data to the connection.  */
275
276boolean
277fconn_write (qconn, zbuf, clen)
278     struct sconnection *qconn;
279     const char *zbuf;
280     size_t clen;
281{
282#if DEBUG > 1
283  if (FDEBUGGING (DEBUG_OUTGOING))
284    udebug_buffer ("fconn_write: Writing", zbuf, clen);
285  else if (FDEBUGGING (DEBUG_PORT))
286    ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen);
287#endif
288
289  return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen);
290}
291
292/* Read and write data.  */
293
294boolean
295fconn_io (qconn, zwrite, pcwrite, zread, pcread)
296     struct sconnection *qconn;
297     const char *zwrite;
298     size_t *pcwrite;
299     char *zread;
300     size_t *pcread;
301{
302  boolean fret;
303#if DEBUG > 1
304  size_t cwrite = *pcwrite;
305  size_t cread = *pcread;
306
307  if (cread == 0 || cwrite == 0)
308    ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu",
309	  (unsigned long) cread, (unsigned long) cwrite);
310#endif
311
312#if DEBUG > 1
313  if (FDEBUGGING (DEBUG_OUTGOING))
314    udebug_buffer ("fconn_io: Writing", zwrite, cwrite);
315#endif
316
317  fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread);
318
319  DEBUG_MESSAGE4 (DEBUG_PORT,
320		  "fconn_io: Wrote %lu of %lu, read %lu of %lu",
321		  (unsigned long) *pcwrite, (unsigned long) cwrite,
322		  (unsigned long) *pcread, (unsigned long) cread);
323
324#if DEBUG > 1
325  if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
326    udebug_buffer ("fconn_io: Read", zread, *pcread);
327#endif
328
329  return fret;
330}
331
332/* Send a break character to a connection.  Some port types may not
333   support break characters, in which case we just return TRUE.  */
334
335boolean
336fconn_break (qconn)
337     struct sconnection *qconn;
338{
339  boolean (*pfbreak) P((struct sconnection *));
340
341  pfbreak = qconn->qcmds->pfbreak;
342  if (pfbreak == NULL)
343    return TRUE;
344
345  DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character");
346
347  return (*pfbreak) (qconn);
348}
349
350/* Change the setting of a connection.  Some port types may not
351   support this, in which case we just return TRUE.  */
352
353boolean
354fconn_set (qconn, tparity, tstrip, txonxoff)
355     struct sconnection *qconn;
356     enum tparitysetting tparity;
357     enum tstripsetting tstrip;
358     enum txonxoffsetting txonxoff;
359{
360  boolean (*pfset) P((struct sconnection *, enum tparitysetting,
361		      enum tstripsetting, enum txonxoffsetting));
362
363  pfset = qconn->qcmds->pfset;
364  if (pfset == NULL)
365    return TRUE;
366
367  DEBUG_MESSAGE3 (DEBUG_PORT,
368		  "fconn_set: Changing setting to %d, %d, %d",
369		  (int) tparity, (int) tstrip, (int) txonxoff);
370
371  return (*pfset) (qconn, tparity, tstrip, txonxoff);
372}
373
374/* Require or ignore carrier on a connection.  */
375
376boolean
377fconn_carrier (qconn, fcarrier)
378     struct sconnection *qconn;
379     boolean fcarrier;
380{
381  boolean (*pfcarrier) P((struct sconnection *, boolean));
382
383  pfcarrier = qconn->qcmds->pfcarrier;
384  if (pfcarrier == NULL)
385    return TRUE;
386  return (*pfcarrier) (qconn, fcarrier);
387}
388
389/* Run a chat program on a connection.  */
390
391boolean
392fconn_run_chat (qconn, pzprog)
393     struct sconnection *qconn;
394     char **pzprog;
395{
396  return (*qconn->qcmds->pfchat) (qconn, pzprog);
397}
398
399/* Get the baud rate of a connection.  */
400
401long
402iconn_baud (qconn)
403     struct sconnection *qconn;
404{
405  long (*pibaud) P((struct sconnection *));
406
407  pibaud = qconn->qcmds->pibaud;
408  if (pibaud == NULL)
409    return 0;
410  return (*pibaud) (qconn);
411}
412
413/* Run through a dialer sequence.  The pzdialer argument is a list of
414   strings, which are considered in dialer/token pairs.  The dialer
415   string names a dialer to use.  The token string is what \D and \T
416   in the chat script expand to.  If there is no token for the last
417   dialer, the zphone argument is used.  The qdialer argument is
418   filled in with information for the first dialer, and *ptdialerfound
419   is set to whether the information should be freed or not.  However,
420   if *ptdialerfound is not DIALERFOUND_FALSE when this function is
421   called, then the information for the first dialer is already in
422   qdialer.  */
423
424boolean
425fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, qdialer,
426		     ptdialerfound)
427     struct sconnection *qconn;
428     pointer puuconf;
429     char **pzdialer;
430     const struct uuconf_system *qsys;
431     const char *zphone;
432     struct uuconf_dialer *qdialer;
433     enum tdialerfound *ptdialerfound;
434{
435  const char *zname;
436  boolean ffirst, ffreefirst;
437
438  if (qconn->qport == NULL)
439    zname = NULL;
440  else
441    zname = qconn->qport->uuconf_zname;
442  ffirst = TRUE;
443  ffreefirst = FALSE;
444  while (*pzdialer != NULL)
445    {
446      struct uuconf_dialer *q;
447      struct uuconf_dialer s;
448      const char *ztoken;
449      boolean ftranslate;
450
451      if (! ffirst)
452	q = &s;
453      else
454	q = qdialer;
455
456      if (! ffirst || *ptdialerfound == DIALERFOUND_FALSE)
457	{
458	  int iuuconf;
459
460	  iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
461	  if (iuuconf == UUCONF_NOT_FOUND)
462	    {
463	      ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
464	      if (ffreefirst)
465		(void) uuconf_dialer_free (puuconf, qdialer);
466	      return FALSE;
467	    }
468	  else if (iuuconf != UUCONF_SUCCESS)
469	    {
470	      ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
471	      if (ffreefirst)
472		(void) uuconf_dialer_free (puuconf, qdialer);
473	      return FALSE;
474	    }
475
476	  if (ffirst)
477	    {
478	      *ptdialerfound = DIALERFOUND_FREE;
479	      ffreefirst = TRUE;
480	    }
481	}
482
483      ++pzdialer;
484      ztoken = *pzdialer;
485
486      ftranslate = FALSE;
487      if (ztoken == NULL
488	  || strcmp (ztoken, "\\D") == 0)
489	ztoken = zphone;
490      else if (strcmp (ztoken, "\\T") == 0)
491	{
492	  ztoken = zphone;
493	  ftranslate = TRUE;
494	}
495
496      if (! fchat (qconn, puuconf, &q->uuconf_schat, qsys, q, ztoken,
497		   ftranslate, zname, iconn_baud (qconn)))
498	{
499	  if (q == &s)
500	    (void) uuconf_dialer_free (puuconf, q);
501	  if (ffreefirst)
502	    (void) uuconf_dialer_free (puuconf, qdialer);
503	  return FALSE;
504	}
505
506      if (ffirst)
507	ffirst = FALSE;
508      else
509	(void) uuconf_dialer_free (puuconf, q);
510
511      if (*pzdialer != NULL)
512	++pzdialer;
513    }
514
515  return TRUE;
516}
517
518/* Modem dialing routine.  */
519
520/*ARGSUSED*/
521boolean
522fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
523     struct sconnection *qconn;
524     pointer puuconf;
525     const struct uuconf_system *qsys;
526     const char *zphone;
527     struct uuconf_dialer *qdialer;
528     enum tdialerfound *ptdialerfound;
529{
530  char **pzdialer;
531
532  *ptdialerfound = DIALERFOUND_FALSE;
533
534  pzdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
535  if (pzdialer != NULL && *pzdialer != NULL)
536    {
537      int iuuconf;
538      boolean fret;
539
540      iuuconf = uuconf_dialer_info (puuconf, *pzdialer, qdialer);
541      if (iuuconf == UUCONF_NOT_FOUND)
542	{
543	  ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
544	  return FALSE;
545	}
546      else if (iuuconf != UUCONF_SUCCESS)
547	{
548	  ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
549	  return FALSE;
550	}
551
552      *ptdialerfound = DIALERFOUND_FREE;
553
554      fret = (fsysdep_modem_begin_dial (qconn, qdialer)
555	      && fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone,
556				      qdialer, ptdialerfound)
557	      && fsysdep_modem_end_dial (qconn, qdialer));
558
559      if (! fret)
560	(void) uuconf_dialer_free (puuconf, qdialer);
561
562      return fret;
563    }
564  else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL)
565    {
566      struct uuconf_dialer *q;
567      const char *zname;
568
569      q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
570      *qdialer = *q;
571      *ptdialerfound = DIALERFOUND_TRUE;
572
573      if (qconn->qport == NULL)
574	zname = NULL;
575      else
576	zname = qconn->qport->uuconf_zname;
577
578      return (fsysdep_modem_begin_dial (qconn, q)
579	      && fchat (qconn, puuconf, &q->uuconf_schat, qsys, q,
580			zphone, FALSE, zname, iconn_baud (qconn))
581	      && fsysdep_modem_end_dial (qconn, q));
582    }
583  else
584    {
585      ulog (LOG_ERROR, "No dialer information");
586      return FALSE;
587    }
588}
589