summaryrefslogtreecommitdiff
path: root/gnu/libexec
diff options
context:
space:
mode:
authorjtc <jtc@NetBSD.org>1993-08-04 19:30:29 +0000
committerjtc <jtc@NetBSD.org>1993-08-04 19:30:29 +0000
commit6964362f5bcd4e7b71ab23edd38df03e3a8eba20 (patch)
tree95b2fe86c9d4bb344979cbb0523ae6bc41dccb4d /gnu/libexec
parent7283ab9b15064eb3c97e3bb99c8f1aef16934d6b (diff)
Upgrade to Taylor UUCP 1.04
Diffstat (limited to 'gnu/libexec')
-rw-r--r--gnu/libexec/uucp/common_sources/chat.c1429
-rw-r--r--gnu/libexec/uucp/common_sources/conf.h444
-rw-r--r--gnu/libexec/uucp/common_sources/conn.c552
-rw-r--r--gnu/libexec/uucp/common_sources/conn.h312
-rw-r--r--gnu/libexec/uucp/common_sources/copy.c202
-rw-r--r--gnu/libexec/uucp/common_sources/cu.h80
-rw-r--r--gnu/libexec/uucp/common_sources/getopt.h120
-rw-r--r--gnu/libexec/uucp/common_sources/log.c699
-rw-r--r--gnu/libexec/uucp/common_sources/policy.h521
-rw-r--r--gnu/libexec/uucp/common_sources/prot.c237
-rw-r--r--gnu/libexec/uucp/common_sources/prot.h250
-rw-r--r--gnu/libexec/uucp/common_sources/sysdep.h530
-rw-r--r--gnu/libexec/uucp/common_sources/system.h950
-rw-r--r--gnu/libexec/uucp/common_sources/tcp.c470
-rw-r--r--gnu/libexec/uucp/common_sources/tli.c644
-rw-r--r--gnu/libexec/uucp/common_sources/trans.h268
-rw-r--r--gnu/libexec/uucp/common_sources/util.c144
-rw-r--r--gnu/libexec/uucp/common_sources/uuconf.h1496
-rw-r--r--gnu/libexec/uucp/common_sources/uucp.h367
-rw-r--r--gnu/libexec/uucp/common_sources/uudefs.h445
-rw-r--r--gnu/libexec/uucp/contrib/Dial.Hayes108
-rw-r--r--gnu/libexec/uucp/contrib/Hangup.Hayes57
-rw-r--r--gnu/libexec/uucp/contrib/Login.LAT137
-rw-r--r--gnu/libexec/uucp/contrib/Login.PortSel133
-rw-r--r--gnu/libexec/uucp/contrib/Login.VMS96
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.uurt30
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.xchat31
-rw-r--r--gnu/libexec/uucp/contrib/README46
-rw-r--r--gnu/libexec/uucp/contrib/README-UURATE20
-rw-r--r--gnu/libexec/uucp/contrib/README-XCHAT42
-rw-r--r--gnu/libexec/uucp/contrib/savelog.man130
-rwxr-xr-xgnu/libexec/uucp/contrib/savelog.sh247
-rwxr-xr-xgnu/libexec/uucp/contrib/stats.sh27
-rw-r--r--gnu/libexec/uucp/contrib/tstout.c158
-rw-r--r--gnu/libexec/uucp/contrib/uuclean23
-rwxr-xr-xgnu/libexec/uucp/contrib/uuq.sh125
-rw-r--r--gnu/libexec/uucp/contrib/uurate.c657
-rw-r--r--gnu/libexec/uucp/contrib/uurate.man217
-rw-r--r--gnu/libexec/uucp/contrib/uureroute91
-rw-r--r--gnu/libexec/uucp/contrib/uusnap.c321
-rw-r--r--gnu/libexec/uucp/contrib/uutraf203
-rw-r--r--gnu/libexec/uucp/contrib/uutry43
-rw-r--r--gnu/libexec/uucp/contrib/xc-conf.h-dist38
-rw-r--r--gnu/libexec/uucp/contrib/xchat.c1444
-rw-r--r--gnu/libexec/uucp/contrib/xchat.man614
-rw-r--r--gnu/libexec/uucp/cu/Makefile15
-rw-r--r--gnu/libexec/uucp/cu/cu.1286
-rw-r--r--gnu/libexec/uucp/cu/cu.c2068
-rw-r--r--gnu/libexec/uucp/libunix/MANIFEST76
-rw-r--r--gnu/libexec/uucp/libunix/Makefile21
-rw-r--r--gnu/libexec/uucp/libunix/access.c83
-rw-r--r--gnu/libexec/uucp/libunix/addbas.c50
-rw-r--r--gnu/libexec/uucp/libunix/app3.c29
-rw-r--r--gnu/libexec/uucp/libunix/app4.c33
-rw-r--r--gnu/libexec/uucp/libunix/basnam.c22
-rw-r--r--gnu/libexec/uucp/libunix/bytfre.c19
-rw-r--r--gnu/libexec/uucp/libunix/chmod.c25
-rw-r--r--gnu/libexec/uucp/libunix/cohtty.c244
-rw-r--r--gnu/libexec/uucp/libunix/cusub.c1163
-rw-r--r--gnu/libexec/uucp/libunix/cwd.c55
-rw-r--r--gnu/libexec/uucp/libunix/detach.c186
-rw-r--r--gnu/libexec/uucp/libunix/dirent.c123
-rw-r--r--gnu/libexec/uucp/libunix/dup2.c69
-rw-r--r--gnu/libexec/uucp/libunix/efopen.c132
-rw-r--r--gnu/libexec/uucp/libunix/epopen.c85
-rw-r--r--gnu/libexec/uucp/libunix/exists.c16
-rw-r--r--gnu/libexec/uucp/libunix/filnam.c376
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.c231
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.h31
-rw-r--r--gnu/libexec/uucp/libunix/ftw.c250
-rw-r--r--gnu/libexec/uucp/libunix/getcwd.c59
-rw-r--r--gnu/libexec/uucp/libunix/indir.c133
-rw-r--r--gnu/libexec/uucp/libunix/init.c394
-rw-r--r--gnu/libexec/uucp/libunix/isdir.c18
-rw-r--r--gnu/libexec/uucp/libunix/isfork.c25
-rw-r--r--gnu/libexec/uucp/libunix/iswait.c159
-rw-r--r--gnu/libexec/uucp/libunix/jobid.c101
-rw-r--r--gnu/libexec/uucp/libunix/lcksys.c41
-rw-r--r--gnu/libexec/uucp/libunix/link.c38
-rw-r--r--gnu/libexec/uucp/libunix/locfil.c95
-rw-r--r--gnu/libexec/uucp/libunix/lock.c477
-rw-r--r--gnu/libexec/uucp/libunix/loctim.c25
-rw-r--r--gnu/libexec/uucp/libunix/mail.c85
-rw-r--r--gnu/libexec/uucp/libunix/mkdir.c58
-rw-r--r--gnu/libexec/uucp/libunix/mkdirs.c49
-rw-r--r--gnu/libexec/uucp/libunix/mode.c33
-rw-r--r--gnu/libexec/uucp/libunix/move.c176
-rw-r--r--gnu/libexec/uucp/libunix/opensr.c244
-rw-r--r--gnu/libexec/uucp/libunix/pause.c96
-rw-r--r--gnu/libexec/uucp/libunix/picksb.c230
-rw-r--r--gnu/libexec/uucp/libunix/portnm.c51
-rw-r--r--gnu/libexec/uucp/libunix/proctm.c197
-rw-r--r--gnu/libexec/uucp/libunix/recep.c197
-rw-r--r--gnu/libexec/uucp/libunix/remove.c13
-rw-r--r--gnu/libexec/uucp/libunix/rename.c27
-rw-r--r--gnu/libexec/uucp/libunix/rmdir.c43
-rw-r--r--gnu/libexec/uucp/libunix/run.c75
-rw-r--r--gnu/libexec/uucp/libunix/seq.c126
-rw-r--r--gnu/libexec/uucp/libunix/serial.c2977
-rw-r--r--gnu/libexec/uucp/libunix/signal.c208
-rw-r--r--gnu/libexec/uucp/libunix/sindir.c26
-rw-r--r--gnu/libexec/uucp/libunix/size.c27
-rw-r--r--gnu/libexec/uucp/libunix/sleep.c14
-rw-r--r--gnu/libexec/uucp/libunix/spawn.c398
-rw-r--r--gnu/libexec/uucp/libunix/splcmd.c115
-rw-r--r--gnu/libexec/uucp/libunix/splnam.c19
-rw-r--r--gnu/libexec/uucp/libunix/spool.c420
-rw-r--r--gnu/libexec/uucp/libunix/srmdir.c112
-rw-r--r--gnu/libexec/uucp/libunix/statsb.c572
-rw-r--r--gnu/libexec/uucp/libunix/status.c212
-rw-r--r--gnu/libexec/uucp/libunix/strerr.c22
-rw-r--r--gnu/libexec/uucp/libunix/time.c32
-rw-r--r--gnu/libexec/uucp/libunix/tmpfil.c83
-rw-r--r--gnu/libexec/uucp/libunix/trunc.c157
-rw-r--r--gnu/libexec/uucp/libunix/uacces.c205
-rw-r--r--gnu/libexec/uucp/libunix/ufopen.c218
-rw-r--r--gnu/libexec/uucp/libunix/ultspl.c21
-rw-r--r--gnu/libexec/uucp/libunix/unknwn.c43
-rw-r--r--gnu/libexec/uucp/libunix/uuto.c31
-rw-r--r--gnu/libexec/uucp/libunix/walk.c59
-rw-r--r--gnu/libexec/uucp/libunix/wldcrd.c212
-rw-r--r--gnu/libexec/uucp/libunix/work.c765
-rw-r--r--gnu/libexec/uucp/libunix/xqtfil.c265
-rw-r--r--gnu/libexec/uucp/libunix/xqtsub.c698
-rw-r--r--gnu/libexec/uucp/libuuconf/COPYING.LIB481
-rw-r--r--gnu/libexec/uucp/libuuconf/MANIFEST92
-rw-r--r--gnu/libexec/uucp/libuuconf/Makefile25
-rw-r--r--gnu/libexec/uucp/libuuconf/README113
-rw-r--r--gnu/libexec/uucp/libuuconf/addblk.c56
-rw-r--r--gnu/libexec/uucp/libuuconf/addstr.c139
-rw-r--r--gnu/libexec/uucp/libuuconf/allblk.c51
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.c82
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.h71
-rw-r--r--gnu/libexec/uucp/libuuconf/base.c54
134 files changed, 33226 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/common_sources/chat.c b/gnu/libexec/uucp/common_sources/chat.c
new file mode 100644
index 00000000000..86a68d9b945
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/chat.c
@@ -0,0 +1,1429 @@
+/* chat.c
+ Chat routine for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char chat_rcsid[] = "$Id: chat.c,v 1.1 1993/08/04 19:30:29 jtc Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "prot.h"
+#include "system.h"
+
+/* Local functions. */
+
+static int icexpect P((struct sconnection *qconn, int cstrings,
+ char **azstrings, size_t *aclens,
+ int ctimeout, boolean fstrip));
+static boolean fcsend P((struct sconnection *qconn, pointer puuconf,
+ const char *zsend,
+ const struct uuconf_system *qsys,
+ const struct uuconf_dialer *qdial,
+ const char *zphone,
+ boolean ftranslate, boolean fstrip));
+static boolean fcecho_send_strip P((struct sconnection *qconn,
+ const char *z, size_t clen));
+static boolean fcecho_send_nostrip P((struct sconnection *qconn,
+ const char *z, size_t clen));
+static boolean fcecho_send P((struct sconnection *qconn, const char *z,
+ size_t clen, boolean fstrip));
+static boolean fcphone P((struct sconnection *qconn,
+ pointer puuconf,
+ const struct uuconf_dialer *qdial,
+ const char *zphone,
+ boolean (*pfwrite) P((struct sconnection *qc,
+ const char *zwrite,
+ size_t cwrite)),
+ boolean ftranslate, boolean *pfquote));
+static boolean fctranslate P((pointer puuconf, const char *zphone,
+ const char **pzprefix,
+ const char **pzsuffix));
+static boolean fcprogram P((struct sconnection *qconn, pointer puuconf,
+ char **pzprogram,
+ const struct uuconf_system *qsys,
+ const struct uuconf_dialer *qdial,
+ const char *zphone, const char *zport,
+ long ibaud));
+
+/* Run a chat script with the other system. The chat script is a
+ series of expect send pairs. We wait for the expect string to show
+ up, and then we send the send string. The chat string for a system
+ holds the expect and send strings separated by a single space. */
+
+boolean
+fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_chat *qchat;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+ const char *zport;
+ long ibaud;
+{
+ int cstrings;
+ char **azstrings;
+ size_t *aclens;
+ char **pzchat;
+ char *zbuf;
+ size_t cbuflen;
+ boolean fret;
+ int i;
+
+ /* First run the program, if any. */
+ if (qchat->uuconf_pzprogram != NULL)
+ {
+ if (! fcprogram (qconn, puuconf, qchat->uuconf_pzprogram, qsys, qdial,
+ zphone, zport, ibaud))
+ return FALSE;
+ }
+
+ /* If there's no chat script, we're done. */
+ if (qchat->uuconf_pzchat == NULL)
+ return TRUE;
+
+ if (qchat->uuconf_pzfail == NULL)
+ {
+ cstrings = 1;
+ azstrings = (char **) xmalloc (sizeof (char *));
+ aclens = (size_t *) xmalloc (sizeof (size_t));
+ }
+ else
+ {
+ char **pz;
+
+ /* We leave string number 0 for the chat script. */
+ cstrings = 1;
+ for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++)
+ ++cstrings;
+
+ azstrings = (char **) xmalloc (cstrings * sizeof (char *));
+ aclens = (size_t *) xmalloc (cstrings * sizeof (size_t));
+
+ /* Get the strings into the array, and handle all the escape
+ characters. */
+ for (cstrings = 1, pz = qchat->uuconf_pzfail;
+ *pz != NULL;
+ cstrings++, pz++)
+ {
+ azstrings[cstrings] = zbufcpy (*pz);
+ aclens[cstrings] = cescape (azstrings[cstrings]);
+ }
+ }
+
+ cbuflen = 0;
+ zbuf = NULL;
+ fret = TRUE;
+
+ pzchat = qchat->uuconf_pzchat;
+
+ while (*pzchat != NULL)
+ {
+ size_t clen;
+
+ /* Loop over subexpects and subsends. */
+ while (TRUE)
+ {
+ /* Copy the expect string into the buffer so that we can
+ modify it in cescape. */
+ clen = strlen (*pzchat);
+ if (clen >= cbuflen)
+ {
+ ubuffree (zbuf);
+ zbuf = zbufalc (clen + 1);
+ cbuflen = clen;
+ }
+ memcpy (zbuf, *pzchat, clen + 1);
+
+ azstrings[0] = zbuf;
+ if (azstrings[0][0] == '-')
+ ++azstrings[0];
+ aclens[0] = cescape (azstrings[0]);
+
+ if (aclens[0] == 0
+ || (aclens[0] == 2
+ && strcmp (azstrings[0], "\"\"") == 0))
+ {
+ /* There is no subexpect sequence. If there is a
+ subsend sequence we move on to it. Otherwise we let
+ this expect succeed. This is somewhat inconsistent,
+ but it seems to be the traditional approach. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ break;
+ }
+ else
+ {
+ int istr;
+
+ istr = icexpect (qconn, cstrings, azstrings, aclens,
+ qchat->uuconf_ctimeout,
+ qchat->uuconf_fstrip);
+
+ /* If we found the string, break out of the
+ subexpect/subsend loop. */
+ if (istr == 0)
+ break;
+
+ /* If we got an error, return FALSE. */
+ if (istr < -1)
+ {
+ fret = FALSE;
+ break;
+ }
+
+ /* If we found a failure string, log it and get out. */
+ if (istr > 0)
+ {
+ ulog (LOG_ERROR, "Chat script failed: Got \"%s\"",
+ qchat->uuconf_pzfail[istr - 1]);
+ fret = FALSE;
+ break;
+ }
+
+ /* We timed out; look for a send subsequence. If none,
+ the chat script has failed. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ {
+ ulog (LOG_ERROR, "Timed out in chat script");
+ fret = FALSE;
+ break;
+ }
+ }
+
+ /* Send the send subsequence without the leading '-'. A
+ \"\" will send nothing. An empty string will send a
+ carriage return. */
+ ++pzchat;
+ if (! fcsend (qconn, puuconf, *pzchat + 1, qsys, qdial, zphone,
+ ftranslate, qchat->uuconf_fstrip))
+ {
+ fret = FALSE;
+ break;
+ }
+
+ /* If there is no expect subsequence, we are done. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ break;
+
+ /* Move on to next expect subsequence. */
+ ++pzchat;
+ }
+
+ if (! fret)
+ break;
+
+ /* Move on to the send string. If there is none, we have
+ succeeded. */
+ do
+ {
+ ++pzchat;
+ }
+ while (*pzchat != NULL && (*pzchat)[0] == '-');
+
+ if (*pzchat == NULL)
+ break;
+
+ if (**pzchat != '\0')
+ {
+ if (! fcsend (qconn, puuconf, *pzchat, qsys, qdial, zphone,
+ ftranslate, qchat->uuconf_fstrip))
+ {
+ fret = FALSE;
+ break;
+ }
+ }
+
+ ++pzchat;
+ }
+
+ ubuffree (zbuf);
+ for (i = 1; i < cstrings; i++)
+ ubuffree (azstrings[i]);
+ xfree ((pointer) azstrings);
+ xfree ((pointer) aclens);
+
+ return fret;
+}
+
+/* Read characters and wait for one of a set of memory strings to come
+ in. This returns the index into the array of the string that
+ arrives, or -1 on timeout, or -2 on error. */
+
+static int
+icexpect (qconn, cstrings, azstrings, aclens, ctimeout, fstrip)
+ struct sconnection *qconn;
+ int cstrings;
+ char **azstrings;
+ size_t *aclens;
+ int ctimeout;
+ boolean fstrip;
+{
+ int i;
+ size_t cmax;
+ char *zhave;
+ size_t chave;
+ long iendtime;
+#if DEBUG > 1
+ int cchars;
+ int iolddebug;
+#endif
+
+ cmax = aclens[0];
+ for (i = 1; i < cstrings; i++)
+ if (cmax < aclens[i])
+ cmax = aclens[i];
+
+ zhave = zbufalc (cmax);
+ chave = 0;
+
+ iendtime = ixsysdep_time ((long *) NULL) + ctimeout;
+
+#if DEBUG > 1
+ cchars = 0;
+ iolddebug = iDebug;
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ udebug_buffer ("icexpect: Looking for", azstrings[0],
+ aclens[0]);
+ ulog (LOG_DEBUG_START, "icexpect: Got \"");
+ iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
+ }
+#endif
+
+ while (TRUE)
+ {
+ int bchar;
+
+ /* If we have no more time, get out. */
+ if (ctimeout <= 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ ulog (LOG_DEBUG_END, "\" (timed out)");
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return -1;
+ }
+
+ /* Read one character at a time. We could use a more complex
+ algorithm to read in larger batches, but it's probably not
+ worth it. If the buffer is full, shift it left; we already
+ know that no string matches, and the buffer holds the largest
+ string, so this can't lose a match. */
+ if (chave >= cmax)
+ {
+ size_t imove;
+
+ for (imove = 0; imove < cmax - 1; imove++)
+ zhave[imove] = zhave[imove + 1];
+ --chave;
+ }
+
+ /* The timeout/error return values from breceive_char are the
+ same as for this function. */
+ bchar = breceive_char (qconn, ctimeout, TRUE);
+ if (bchar < 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ /* If there was an error, it will probably be logged in
+ the middle of our string, but this is only debugging
+ so it's not a big deal. */
+ ulog (LOG_DEBUG_END, "\" (%s)",
+ bchar == -1 ? "timed out" : "error");
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return bchar;
+ }
+
+ /* Strip the parity bit if desired. */
+ if (fstrip)
+ bchar &= 0x7f;
+
+ zhave[chave] = (char) bchar;
+ ++chave;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ char ab[5];
+
+ ++cchars;
+ if (cchars > 60)
+ {
+ ulog (LOG_DEBUG_END, "\"");
+ ulog (LOG_DEBUG_START, "icexpect: Got \"");
+ cchars = 0;
+ }
+ (void) cdebug_char (ab, bchar);
+ ulog (LOG_DEBUG_CONTINUE, "%s", ab);
+ }
+#endif
+
+ /* See if any of the strings can be found in the buffer. Since
+ we read one character at a time, the string can only be found
+ at the end of the buffer. */
+ for (i = 0; i < cstrings; i++)
+ {
+ if (aclens[i] <= chave
+ && memcmp (zhave + chave - aclens[i], azstrings[i],
+ aclens[i]) == 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ if (i == 0)
+ ulog (LOG_DEBUG_END, "\" (found it)");
+ else
+ {
+ ulog (LOG_DEBUG_END, "\"");
+ udebug_buffer ("icexpect: Found", azstrings[i],
+ aclens[i]);
+ }
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return i;
+ }
+ }
+
+ ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL));
+ }
+}
+
+#if DEBUG > 1
+
+/* Debugging function for fcsend. This takes the fquote variable, the
+ length of the string (0 if this an informational string which can
+ be printed directly) and the string itself. It returns the new
+ value for fquote. The fquote variable is TRUE if the debugging
+ output is in the middle of a quoted string. */
+
+static size_t cCsend_chars;
+static int iColddebug;
+
+static boolean fcsend_debug P((boolean, size_t, const char *));
+
+static boolean
+fcsend_debug (fquote, clen, zbuf)
+ boolean fquote;
+ size_t clen;
+ const char *zbuf;
+{
+ size_t cwas;
+
+ if (! FDEBUGGING (DEBUG_CHAT))
+ return TRUE;
+
+ cwas = cCsend_chars;
+ if (clen > 0)
+ cCsend_chars += clen;
+ else
+ cCsend_chars += strlen (zbuf);
+ if (cCsend_chars > 60 && cwas > 10)
+ {
+ ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : "");
+ fquote = FALSE;
+ ulog (LOG_DEBUG_START, "fcsend: Writing");
+ cCsend_chars = 0;
+ }
+
+ if (clen == 0)
+ {
+ ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf);
+ return FALSE;
+ }
+ else
+ {
+ int i;
+
+ if (! fquote)
+ ulog (LOG_DEBUG_CONTINUE, " \"");
+ for (i = 0; i < clen; i++)
+ {
+ char ab[5];
+
+ (void) cdebug_char (ab, zbuf[i]);
+ ulog (LOG_DEBUG_CONTINUE, "%s", ab);
+ }
+
+ return TRUE;
+ }
+}
+
+/* Finish up the debugging information for fcsend. */
+
+static void ucsend_debug_end P((boolean, boolean));
+
+static void
+ucsend_debug_end (fquote, ferr)
+ boolean fquote;
+ boolean ferr;
+{
+ if (! FDEBUGGING (DEBUG_CHAT))
+ return;
+
+ if (fquote)
+ ulog (LOG_DEBUG_CONTINUE, "\"");
+
+ if (ferr)
+ ulog (LOG_DEBUG_CONTINUE, " (error)");
+
+ ulog (LOG_DEBUG_END, "%s", "");
+
+ iDebug = iColddebug;
+}
+
+#else /* DEBUG <= 1 */
+
+/* Use macro definitions to make fcsend look neater. */
+
+#define fcsend_debug(fquote, clen, zbuf) TRUE
+
+#define ucsend_debug_end(fquote, ferror)
+
+#endif /* DEBUG <= 1 */
+
+/* Send a string out. This has to parse escape sequences as it goes.
+ Note that it handles the dialer escape sequences (\e, \E, \D, \T)
+ although they make no sense for chatting with a system. */
+
+static boolean
+fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const char *z;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+ boolean fstrip;
+{
+ boolean fnocr;
+ boolean (*pfwrite) P((struct sconnection *, const char *, size_t));
+ char *zcallout_login;
+ char *zcallout_pass;
+ boolean fquote;
+
+ if (strcmp (z, "\"\"") == 0)
+ return TRUE;
+
+ fnocr = FALSE;
+ pfwrite = fconn_write;
+ zcallout_login = NULL;
+ zcallout_pass = NULL;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ ulog (LOG_DEBUG_START, "fcsend: Writing");
+ fquote = FALSE;
+ cCsend_chars = 0;
+ iColddebug = iDebug;
+ iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT);
+ }
+#endif
+
+ while (*z != '\0')
+ {
+ const char *zlook;
+ boolean fsend;
+ char bsend;
+
+ zlook = z + strcspn ((char *) z, "\\BE");
+
+ if (zlook > z)
+ {
+ size_t c;
+
+ c = zlook - z;
+ fquote = fcsend_debug (fquote, c, z);
+ if (! (*pfwrite) (qconn, z, c))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+
+ if (*zlook == '\0')
+ break;
+
+ z = zlook;
+
+ fsend = FALSE;
+ switch (*z)
+ {
+ case 'B':
+ if (strncmp (z, "BREAK", 5) == 0)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 0, "break");
+ if (! fconn_break (qconn))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ fnocr = TRUE;
+ z += 5;
+ }
+ else
+ {
+ fsend = TRUE;
+ bsend = 'B';
+ ++z;
+ }
+ break;
+ case 'E':
+ if (strncmp (z, "EOT", 3) == 0)
+ {
+ fsend = TRUE;
+ bsend = '\004';
+ fnocr = TRUE;
+ z += 3;
+ }
+ else
+ {
+ fsend = TRUE;
+ bsend = 'E';
+ ++z;
+ }
+ break;
+ case '\\':
+ ++z;
+ switch (*z)
+ {
+ case '-':
+ fsend = TRUE;
+ bsend = '-';
+ break;
+ case 'b':
+ fsend = TRUE;
+ bsend = '\b';
+ break;
+ case 'c':
+ fnocr = TRUE;
+ break;
+ case 'd':
+ fquote = fcsend_debug (fquote, (size_t) 0, "sleep");
+ usysdep_sleep (2);
+ break;
+ case 'e':
+ fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off");
+ pfwrite = fconn_write;
+ break;
+ case 'E':
+ fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-on");
+ if (fstrip)
+ pfwrite = fcecho_send_strip;
+ else
+ pfwrite = fcecho_send_nostrip;
+ break;
+ case 'K':
+ fquote = fcsend_debug (fquote, (size_t) 0, "break");
+ if (! fconn_break (qconn))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'n':
+ fsend = TRUE;
+ bsend = '\n';
+ break;
+ case 'N':
+ fsend = TRUE;
+ bsend = '\0';
+ break;
+ case 'p':
+ fquote = fcsend_debug (fquote, (size_t) 0, "pause");
+ usysdep_pause ();
+ break;
+ case 'r':
+ fsend = TRUE;
+ bsend = '\r';
+ break;
+ case 's':
+ fsend = TRUE;
+ bsend = ' ';
+ break;
+ case 't':
+ fsend = TRUE;
+ bsend = '\t';
+ break;
+ case '\0':
+ --z;
+ /* Fall through. */
+ case '\\':
+ fsend = TRUE;
+ bsend = '\\';
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ fsend = TRUE;
+ bsend = *z - '0';
+ if (z[1] >= '0' && z[1] <= '7')
+ bsend = (char) (8 * bsend + *++z - '0');
+ if (z[1] >= '0' && z[1] <= '7')
+ bsend = (char) (8 * bsend + *++z - '0');
+ break;
+ case 'x':
+ fsend = TRUE;
+ bsend = 0;
+ while (isxdigit (BUCHAR (z[1])))
+ {
+ if (isdigit (BUCHAR (z[1])))
+ bsend = (char) (16 * bsend + *++z - '0');
+ else if (isupper (BUCHAR (z[1])))
+ bsend = (char) (16 * bsend + *++z - 'A');
+ else
+ bsend = (char) (16 * bsend + *++z - 'a');
+ }
+ break;
+ case 'L':
+ {
+ const char *zlog;
+
+ if (qsys == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\L");
+ return FALSE;
+ }
+ zlog = qsys->uuconf_zcall_login;
+ if (zlog == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No login defined");
+ return FALSE;
+ }
+ if (zlog[0] == '*' && zlog[1] == '\0')
+ {
+ if (zcallout_login == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_login == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No login defined");
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ }
+ zlog = zcallout_login;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "login");
+ fquote = fcsend_debug (fquote, strlen (zlog), zlog);
+ if (! (*pfwrite) (qconn, zlog, strlen (zlog)))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ case 'P':
+ {
+ const char *zpass;
+
+ if (qsys == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\P");
+ return FALSE;
+ }
+ zpass = qsys->uuconf_zcall_password;
+ if (zpass == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No password defined");
+ return FALSE;
+ }
+ if (zpass[0] == '*' && zpass[1] == '\0')
+ {
+ if (zcallout_pass == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_pass == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No password defined");
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ }
+ zpass = zcallout_pass;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "password");
+ fquote = fcsend_debug (fquote, strlen (zpass), zpass);
+ if (! (*pfwrite) (qconn, zpass, strlen (zpass)))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ case 'D':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\D");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "\\D");
+ if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite,
+ ftranslate, &fquote))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'T':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\T");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "\\T");
+ if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, TRUE,
+ &fquote))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'M':
+ if (qdial == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\M");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "ignore-carrier");
+ if (! fconn_carrier (qconn, FALSE))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'm':
+ if (qdial == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\m");
+ return FALSE;
+ }
+ if (qdial->uuconf_fcarrier)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 0, "need-carrier");
+ if (! fconn_carrier (qconn, TRUE))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ /* This error message will screw up any debugging
+ information, but it's easily avoidable. */
+ ulog (LOG_ERROR,
+ "Unrecognized escape sequence \\%c in send string",
+ *z);
+ fsend = TRUE;
+ bsend = *z;
+ break;
+ }
+ ++z;
+ break;
+#if DEBUG > 0
+ default:
+ ulog (LOG_FATAL, "fcsend: Can't happen");
+ break;
+#endif
+ }
+
+ if (fsend)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 1, &bsend);
+ if (! (*pfwrite) (qconn, &bsend, (size_t) 1))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ }
+
+ xfree ((pointer) zcallout_login);
+ xfree ((pointer) zcallout_pass);
+
+ /* Output a final carriage return, unless there was a \c. Don't
+ bother to check for an echo. */
+ if (! fnocr)
+ {
+ char b;
+
+ b = '\r';
+ fquote = fcsend_debug (fquote, (size_t) 1, &b);
+ if (! fconn_write (qconn, &b, (size_t) 1))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+
+ ucsend_debug_end (fquote, FALSE);
+
+ return TRUE;
+}
+
+/* Write out a phone number with optional dialcode translation. The
+ pfquote argument is only used for debugging. */
+
+static boolean
+fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, pfquote)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite,
+ size_t cwrite));
+ boolean ftranslate;
+ boolean *pfquote;
+{
+ const char *zprefix, *zsuffix;
+
+ if (ftranslate)
+ {
+ if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
+ return FALSE;
+ }
+ else
+ {
+ zprefix = zphone;
+ zsuffix = NULL;
+ }
+
+ while (zprefix != NULL)
+ {
+ while (TRUE)
+ {
+ const char *z;
+ const char *zstr;
+
+ z = zprefix + strcspn ((char *) zprefix, "=-");
+ if (z > zprefix)
+ {
+ size_t clen;
+
+ clen = z - zprefix;
+ *pfquote = fcsend_debug (*pfquote, clen, zprefix);
+ if (! (*pfwrite) (qconn, zprefix, clen))
+ return FALSE;
+ }
+
+ if (*z == '=')
+ zstr = qdial->uuconf_zdialtone;
+ else if (*z == '-')
+ zstr = qdial->uuconf_zpause;
+ else /* *z == '\0' */
+ break;
+
+ if (zstr != NULL)
+ {
+ *pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr);
+ if (! (*pfwrite) (qconn, zstr, strlen (zstr)))
+ return FALSE;
+ }
+
+ zprefix = z + 1;
+ }
+
+ zprefix = zsuffix;
+ zsuffix = NULL;
+ }
+
+ return TRUE;
+}
+
+/* Given a phone number, run it through dial code translation
+ returning two strings. */
+
+static boolean
+fctranslate (puuconf, zphone, pzprefix, pzsuffix)
+ pointer puuconf;
+ const char *zphone;
+ const char **pzprefix;
+ const char **pzsuffix;
+{
+ int iuuconf;
+ char *zdialcode, *zto;
+ const char *zfrom;
+ char *ztrans;
+
+ *pzprefix = zphone;
+ *pzsuffix = NULL;
+
+ zdialcode = zbufalc (strlen (zphone) + 1);
+ zfrom = zphone;
+ zto = zdialcode;
+ while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom)))
+ *zto++ = *zfrom++;
+ *zto = '\0';
+
+ if (*zdialcode == '\0')
+ {
+ ubuffree (zdialcode);
+ return TRUE;
+ }
+
+ iuuconf = uuconf_dialcode (puuconf, zdialcode, &ztrans);
+
+ ubuffree (zdialcode);
+
+ if (iuuconf == UUCONF_NOT_FOUND)
+ return TRUE;
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ else
+ {
+ /* We really should figure out a way to free up ztrans here. */
+ *pzprefix = ztrans;
+ *pzsuffix = zfrom;
+ return TRUE;
+ }
+}
+
+/* Write out a string making sure the each character is echoed back.
+ There are two versions of this function, one which strips the
+ parity bit from the characters and one which does not. This is so
+ that I can use a single function pointer in fcsend, and to avoid
+ using any static variables so that I can put chat scripts in a
+ library some day. */
+
+static boolean
+fcecho_send_strip (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ return fcecho_send (qconn, zwrite, cwrite, TRUE);
+}
+
+static boolean
+fcecho_send_nostrip (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ return fcecho_send (qconn, zwrite, cwrite, FALSE);
+}
+
+static boolean
+fcecho_send (qconn, zwrite, cwrite, fstrip)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+ boolean fstrip;
+{
+ const char *zend;
+
+ zend = zwrite + cwrite;
+
+ for (; zwrite < zend; zwrite++)
+ {
+ int b;
+ char bwrite;
+
+ bwrite = *zwrite;
+ if (! fconn_write (qconn, &bwrite, (size_t) 1))
+ return FALSE;
+ if (fstrip)
+ bwrite &= 0x7f;
+ do
+ {
+ /* We arbitrarily wait five seconds for the echo. */
+ b = breceive_char (qconn, 5, TRUE);
+ /* Now b == -1 on timeout, -2 on error. */
+ if (b < 0)
+ {
+ if (b == -1)
+ ulog (LOG_ERROR, "Character not echoed");
+ return FALSE;
+ }
+ if (fstrip)
+ b &= 0x7f;
+ }
+ while (b != BUCHAR (bwrite));
+ }
+
+ return TRUE;
+}
+
+/* Run a chat program. Expand any escape sequences and call a system
+ dependent program to run it. */
+
+static boolean
+fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
+ struct sconnection *qconn;
+ pointer puuconf;
+ char **pzprogram;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ const char *zport;
+ long ibaud;
+{
+ size_t cargs;
+ char **pzpass, **pzarg;
+ char **pz;
+ char *zcallout_login;
+ char *zcallout_pass;
+ boolean fret;
+
+ cargs = 1;
+ for (pz = pzprogram; *pz != NULL; pz++)
+ ++cargs;
+
+ pzpass = (char **) xmalloc (cargs * sizeof (char *));
+
+ zcallout_login = NULL;
+ zcallout_pass = NULL;
+ fret = TRUE;
+
+ /* Copy the string into memory expanding escape sequences. */
+ for (pz = pzprogram, pzarg = pzpass; *pz != NULL; pz++, pzarg++)
+ {
+ const char *zfrom;
+ size_t calc, clen;
+ char *zto;
+
+ if (strchr (*pz, '\\') == NULL)
+ {
+ *pzarg = zbufcpy (*pz);
+ continue;
+ }
+
+ *pzarg = NULL;
+ zto = NULL;
+ calc = 0;
+ clen = 0;
+
+ for (zfrom = *pz; *zfrom != '\0'; zfrom++)
+ {
+ const char *zadd = NULL;
+ size_t cadd;
+ char abadd[15];
+
+ if (*zfrom != '\\')
+ {
+ if (clen + 2 > calc)
+ {
+ char *znew;
+
+ calc = clen + 50;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ *zto++ = *zfrom;
+ ++clen;
+ continue;
+ }
+
+ ++zfrom;
+ switch (*zfrom)
+ {
+ case '\0':
+ --zfrom;
+ /* Fall through. */
+ case '\\':
+ zadd = "\\";
+ break;
+ case 'L':
+ {
+ const char *zlog;
+
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\L");
+ fret = FALSE;
+ break;
+ }
+ zlog = qsys->uuconf_zcall_login;
+ if (zlog == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: No login defined");
+ fret = FALSE;
+ break;
+ }
+ if (zlog[0] == '*' && zlog[1] == '\0')
+ {
+ if (zcallout_login == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_login == NULL)
+ {
+ ulog (LOG_ERROR,
+ "chat-program: No login defined");
+ fret = FALSE;
+ break;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ break;
+ }
+ }
+ zlog = zcallout_login;
+ }
+ zadd = zlog;
+ }
+ break;
+ case 'P':
+ {
+ const char *zpass;
+
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\P");
+ fret = FALSE;
+ break;
+ }
+ zpass = qsys->uuconf_zcall_password;
+ if (zpass == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: No password defined");
+ fret = FALSE;
+ break;
+ }
+ if (zpass[0] == '*' && zpass[1] == '\0')
+ {
+ if (zcallout_pass == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_pass == NULL)
+ {
+ ulog (LOG_ERROR,
+ "chat-program: No password defined");
+ fret = FALSE;
+ break;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ break;
+ }
+ }
+ zpass = zcallout_pass;
+ }
+ zadd = zpass;
+ }
+ break;
+ case 'D':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\D");
+ fret = FALSE;
+ break;
+ }
+ zadd = zphone;
+ break;
+ case 'T':
+ {
+ const char *zprefix, *zsuffix;
+
+ if (qdial == NULL || zphone == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\T");
+ fret = FALSE;
+ break;
+ }
+
+ if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
+ {
+ fret = FALSE;
+ break;
+ }
+
+ if (zsuffix == NULL)
+ zadd = zprefix;
+ else
+ {
+ size_t cprefix;
+
+ cprefix = strlen (zprefix);
+ if (clen + cprefix + 1 > calc)
+ {
+ char *znew;
+
+ calc = clen + cprefix + 20;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ memcpy (zto, zprefix, cprefix);
+ zto += cprefix;
+ clen += cprefix;
+ zadd = zsuffix;
+ }
+ }
+ break;
+ case 'Y':
+ if (zLdevice == NULL && zport == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\Y");
+ fret = FALSE;
+ break;
+ }
+ /* zLdevice will generally make more sense than zport, but
+ it might not be set yet. */
+ zadd = zLdevice;
+ if (zadd == NULL)
+ zadd = zport;
+ break;
+ case 'Z':
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\Z");
+ fret = FALSE;
+ break;
+ }
+ zadd = qsys->uuconf_zname;
+ break;
+ case 'S':
+ {
+ if (ibaud == 0)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\S");
+ fret = FALSE;
+ break;
+ }
+ sprintf (abadd, "%ld", ibaud);
+ zadd = abadd;
+ }
+ break;
+ default:
+ {
+ ulog (LOG_ERROR,
+ "chat-program: Unrecognized escape sequence \\%c",
+ *zfrom);
+ abadd[0] = *zfrom;
+ abadd[1] = '\0';
+ zadd = abadd;
+ }
+ break;
+ }
+
+ if (! fret)
+ break;
+
+ cadd = strlen (zadd);
+ if (clen + cadd + 1 > calc)
+ {
+ char *znew;
+
+ calc = clen + cadd + 20;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ memcpy (zto, zadd, cadd + 1);
+ zto += cadd;
+ clen += cadd;
+ }
+
+ if (! fret)
+ break;
+
+ *zto++ = '\0';
+ ++clen;
+ }
+
+ *pzarg = NULL;
+
+ if (fret)
+ fret = fconn_run_chat (qconn, pzpass);
+
+ for (pz = pzpass; *pz != NULL; pz++)
+ ubuffree (*pz);
+ xfree ((pointer) pzpass);
+ xfree ((pointer) zcallout_login);
+ xfree ((pointer) zcallout_pass);
+
+ return fret;
+}
diff --git a/gnu/libexec/uucp/common_sources/conf.h b/gnu/libexec/uucp/common_sources/conf.h
new file mode 100644
index 00000000000..431ba4d11b1
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/conf.h
@@ -0,0 +1,444 @@
+/* conf.h. Generated automatically by configure. */
+/* Configuration header file for Taylor UUCP. -*- C -*- */
+
+/* Set MAIL_PROGRAM to a program which takes a mail address as an
+ argument and accepts a mail message to send to that address on
+ stdin (e.g. "/bin/mail"). */
+#define MAIL_PROGRAM "/usr/bin/mail"
+
+/* Set ECHO_PROGRAM to a program which echoes its arguments; if echo
+ is a shell builtin you can just use "echo". */
+#define ECHO_PROGRAM "echo"
+
+/* The following macros indicate what header files you have. Set the
+ macro to 1 if you have the corresponding header file, or 0 if you
+ do not. */
+#define HAVE_STDDEF_H 1 /* <stddef.h> */
+#define HAVE_STRING_H 1 /* <string.h> */
+#define HAVE_STRINGS_H 1 /* <strings.h> */
+#define HAVE_UNISTD_H 1 /* <unistd.h> */
+#define HAVE_STDLIB_H 1 /* <stdlib.h> */
+#define HAVE_LIMITS_H 1 /* <limits.h> */
+#define HAVE_TIME_H 1 /* <time.h> */
+#define HAVE_SYS_WAIT_H 1 /* <sys/wait.h> */
+#define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */
+#define HAVE_DIRENT_H 1 /* <dirent.h> */
+#define HAVE_MEMORY_H 1 /* <memory.h> */
+#define HAVE_SYS_PARAM_H 1 /* <sys/param.h> */
+#define HAVE_UTIME_H 1 /* <utime.h> */
+#define HAVE_FCNTL_H 1 /* <fcntl.h> */
+#define HAVE_SYS_FILE_H 1 /* <sys/file.h> */
+#define HAVE_SYS_TIMES_H 1 /* <sys/times.h> */
+#define HAVE_LIBC_H 0 /* <libc.h> */
+#define HAVE_SYSEXITS_H 1 /* <sysexits.h> */
+#define HAVE_POLL_H 0 /* <poll.h> */
+#define HAVE_TIUSER_H 0 /* <tiuser.h> */
+#define HAVE_XTI_H 0 /* <xti.h> */
+#define HAVE_SYS_TLI_H 0 /* <sys/tli.h> */
+#define HAVE_STROPTS_H 0 /* <stropts.h> */
+#define HAVE_FTW_H 0 /* <ftw.h> */
+#define HAVE_GLOB_H 1 /* <glob.h> */
+#define HAVE_SYS_SELECT_H 0 /* <sys/select.h> */
+#define HAVE_SYS_TYPES_TCP_H 0 /* <sys/types.tcp.h> */
+
+/* If major and minor are not defined in <sys/types.h>, but are in
+ <sys/mkdev.h>, set MAJOR_IN_MKDEV to 1. If they are in
+ <sys/sysmacros.h>, set MAJOR_IN_SYSMACROS to 1. */
+#define MAJOR_IN_MKDEV 0
+#define MAJOR_IN_SYSMACROS 0
+
+/* If the macro offsetof is not defined in <stddef.h>, you may give it
+ a definition here. If you do not, the code will use a definition
+ (in uucp.h) that should be fairly portable. */
+/* #define offsetof */
+
+/* Set RETSIGTYPE to the return type of a signal handler. On newer
+ systems this will be void; some older systems use int. */
+#define RETSIGTYPE void
+
+/* Set HAVE_SYS_TIME_AND_TIME_H to 1 if <time.h> and <sys/time.h> can both
+ be included in a single source file; if you don't have either or both of
+ them, it doesn't matter what you set this to. */
+#define HAVE_SYS_TIME_AND_TIME_H 1
+
+/* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if <termios.h> and <sys/ioctl.h>
+ can both be included in a single source file; if you don't have either
+ or both of them, it doesn't matter what you set this to. */
+#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1
+
+/* If you are configuring by hand, you should set one of the terminal
+ driver options in policy.h. If you are autoconfiguring, the script
+ will check whether your system defines CBREAK, which is a terminal
+ setting; if your system supports CBREAK, and you don't set a terminal
+ driver in policy.h, the code will assume that you have a BSD style
+ terminal driver. */
+#define HAVE_CBREAK 1
+
+/* The package needs several standard types. If you are using the
+ configure script, it will look in standard places for these types,
+ and give default definitions for them here if it doesn't find them.
+ The default definitions should work on most systems, but you may
+ want to check them. If you are configuring by hand, you will have
+ to figure out whether the types are defined on your system, and
+ what they should be defined to.
+
+ Any type that is not defined on your system should get a macro
+ definition. The definition should be of the name of the type in
+ all capital letters. For example, #define PID_T int. If the type
+ is defined in a standard header file, the macro name should not be
+ defined. */
+
+/* The type pid_t is used to hold a process ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the
+ functions fork or getpid. Usually int will work fine. */
+#undef PID_T
+
+/* The type uid_t is used to hold a user ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the getuid
+ function. Usually int will work fine. */
+#undef UID_T
+
+/* The type gid_t is used to hold a group ID number. It is sometimes
+ defined in <sys/types.h>. This is the type returned by the getgid
+ function. Usually int will work fine. */
+#undef GID_T
+
+/* The type off_t is used to hold an offset in a file. It is sometimes
+ defined in <sys/types.h>. This is the type of the second argument to
+ the lseek function. Usually long will work fine. */
+#undef OFF_T
+
+/* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined
+ in <signal.h> as required by ANSI C. */
+#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 1
+
+/* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined
+ in <sys/types.h>. This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is
+ set to 1. */
+#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0
+
+/* The type sig_atomic_t is used to hold a value which may be
+ referenced in a single atomic operation. If it is not defined in
+ either <signal.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use char. If your
+ compiler does not support sig_atomic_t, there is no type which is
+ really correct; fortunately, for this package it does not really
+ matter very much. */
+#undef SIG_ATOMIC_T
+
+/* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in
+ <stddef.h> as required by ANSI C. */
+#define HAVE_SIZE_T_IN_STDDEF_H 1
+
+/* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in
+ <sys/types.h>. This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set
+ to 1. */
+#define HAVE_SIZE_T_IN_TYPES_H 1
+
+/* The type size_t is used to hold the size of an object. In
+ particular, an argument of this type is passed as the size argument
+ to the malloc and realloc functions. If size_t is not defined in
+ either <stddef.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use unsigned. */
+#undef SIZE_T
+
+/* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in
+ <time.h>, as required by the ANSI C standard. */
+#define HAVE_TIME_T_IN_TIME_H 1
+
+/* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in
+ <sys/types.h>. This is ignored if HAVE_TIME_T_IN_TIME_H is set to
+ 1. */
+#define HAVE_TIME_T_IN_TYPES_H 1
+
+/* When Taylor UUCP is talking to another instance of itself, it will
+ tell the other side the size of a file before it is transferred.
+ If the package can determine how much disk space is available, it
+ will use this information to avoid filling up the disk. Define one
+ of the following macros to tell the code how to determine the
+ amount of available disk space. It is possible that none of these
+ are appropriate; it will do no harm to use none of them, but, of
+ course, nothing will then prevent the package from filling up the
+ disk. Note that this space check is only useful when talking to
+ another instance of Taylor UUCP.
+
+ STAT_STATVFS statvfs function
+ STAT_STATFS2_BSIZE two argument statfs function with f_bsize field
+ STAT_STATFS2_FSIZE two argument statfs function with f_fsize field
+ STAT_STATFS2_FS_DATA two argument statfs function with fd_req field
+ STAT_STATFS4 four argument statfs function
+ STAT_USTAT the ustat function with 512 byte blocks. */
+#define STAT_STATVFS 0
+#define STAT_STATFS2_BSIZE 0
+#define STAT_STATFS2_FSIZE 1
+#define STAT_STATFS2_FS_DATA 0
+#define STAT_STATFS4 0
+#define STAT_USTAT 0
+
+/* Set HAVE_VOID to 1 if the compiler supports declaring functions with
+ a return type of void and casting values to void. */
+#define HAVE_VOID 1
+
+/* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned
+ char. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in <errno.h>. */
+#define HAVE_ERRNO_DECLARATION 1
+
+/* There are now a number of functions to check for. For each of
+ these, the macro HAVE_FUNC should be set to 1 if your system has
+ FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system
+ has vfprintf, 0 otherwise. */
+
+/* Taylor UUCP will take advantage of the following functions if they
+ are available, but knows how to deal with their absence. */
+#define HAVE_VFPRINTF 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_LTRUNC 0
+#define HAVE_WAITPID 1
+#define HAVE_WAIT4 1
+#define HAVE_GLOB 1
+#define HAVE_SETREUID 1
+
+/* There are several functions which are replaced in the subdirectory
+ lib. If they are missing, the configure script will automatically
+ add them to lib/Makefile to force them to be recompiled. If you
+ are configuring by hand, you will have to do this yourself. The
+ string @LIBOBJS@ in lib/Makefile.in should be replaced by a list of
+ object files in lib/Makefile. The following comments tell you
+ which object file names to add (they are generally fairly obvious,
+ given that the file names have no more than six characters before
+ the period). */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to lib/Makefile. */
+#define HAVE_BSEARCH 1 /* bsrch.o */
+#define HAVE_GETLINE 0 /* getlin.o */
+#define HAVE_MEMCHR 1 /* memchr.o */
+#define HAVE_STRDUP 1 /* strdup.o */
+#define HAVE_STRSTR 1 /* strstr.o */
+#define HAVE_STRTOL 1 /* strtol.o */
+
+/* If neither of these functions exists, you should add bzero.o to
+ lib/Makefile. */
+#define HAVE_BZERO 1
+#define HAVE_MEMSET 1
+
+/* If neither of these functions exists, you should add memcmp.o to
+ lib/Makefile. */
+#define HAVE_MEMCMP 1
+#define HAVE_BCMP 1
+
+/* If neither of these functions exists, you should add memcpy.o to
+ lib/Makefile. */
+#define HAVE_MEMCPY 1
+#define HAVE_BCOPY 1
+
+/* If neither of these functions exists, you should add strcas.o to
+ lib/Makefile. */
+#define HAVE_STRCASECMP 1
+#define HAVE_STRICMP 0
+
+/* If neither of these functions exists, you should add strncs.o to
+ lib/Makefile. */
+#define HAVE_STRNCASECMP 1
+#define HAVE_STRNICMP 0
+
+/* If neither of these functions exists, you should add strchr.o to
+ lib/Makefile. */
+#define HAVE_STRCHR 1
+#define HAVE_INDEX 1
+
+/* If neither of these functions exists, you should add strrch.o to
+ lib/Makefile. */
+#define HAVE_STRRCHR 1
+#define HAVE_RINDEX 1
+
+/* There are also Unix specific functions which are replaced in the
+ subdirectory unix. If they are missing, the configure script will
+ automatically add them to unix/Makefile to force them to be
+ recompiled. If you are configuring by hand, you will have to do
+ this yourself. The string @UNIXOBJS@ in unix/Makefile.in should be
+ replaced by a list of object files in unix/Makefile. The following
+ comments tell you which object file names to add. */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to unix/Makefile. */
+#define HAVE_OPENDIR 1 /* dirent.o */
+#define HAVE_DUP2 1 /* dup2.o */
+#define HAVE_FTW 0 /* ftw.o */
+#define HAVE_REMOVE 1 /* remove.o */
+#define HAVE_RENAME 1 /* rename.o */
+#define HAVE_STRERROR 1 /* strerr.o */
+
+/* The code needs to know how to create directories. If you have the
+ mkdir function, set HAVE_MKDIR to 1 and replace @UUDIR@ in
+ Makefile.in with '# ' (the configure script will set @UUDIR@
+ according to the variable UUDIR). Otherwise, set HAVE_MKDIR to 0,
+ remove @UUDIR@ from Makefile.in, set MKDIR_PROGRAM to the name of
+ the program which will create a directory named on the command line
+ (e.g., "/bin/mkdir"), and add mkdir.o to the @UNIXOBJS@ string in
+ unix/Makefile.in. */
+#define HAVE_MKDIR 1
+#define MKDIR_PROGRAM unused
+
+/* The code also needs to know how to remove directories. If you have
+ the rmdir function, set HAVE_RMDIR to 1. Otherwise, set
+ RMDIR_PROGRAM to the name of the program which will remove a
+ directory named on the command line (e.g., "/bin/rmdir") and add
+ rmdir.o to the @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_RMDIR 1
+#define RMDIR_PROGRAM unused
+
+/* The code needs to know to how to get the name of the current
+ directory. If getcwd is available it will be used, otherwise if
+ getwd is available it will be used. Otherwise, set PWD_PROGRAM to
+ the name of the program which will print the name of the current
+ working directory (e.g., "/bin/pwd") and add getcwd.o to the
+ @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_GETCWD 1
+#define HAVE_GETWD 1
+#define PWD_PROGRAM unused
+
+/* If you have either sigsetjmp or setret, it will be used instead of
+ setjmp. These functions will only be used if your system restarts
+ system calls after interrupts (see HAVE_RESTARTABLE_SYSCALLS,
+ below). */
+#define HAVE_SIGSETJMP 0
+#define HAVE_SETRET 0
+
+/* The code needs to know what function to use to set a signal
+ handler. If will try to use each of the following functions in
+ turn. If none are available, it will use signal, which is assumed
+ to always exist. */
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIGSET 0
+
+/* If the code is going to use sigvec (HAVE_SIGACTION is 0 and
+ HAVE_SIGVEC is 1), then HAVE_SIGVEC_SV_FLAGS must be set to 1 if
+ the sigvec structure contains the sv_flags field, or 0 if the
+ sigvec structure contains the sv_onstack field. If the code is not
+ going to use sigvec, it doesn't matter what this is set to. */
+#define HAVE_SIGVEC_SV_FLAGS 1
+
+/* The code will try to use each of the following functions in turn
+ when blocking signals from delivery. If none are available, a
+ relatively unimportant race condition will exist. */
+#define HAVE_SIGPROCMASK 1
+#define HAVE_SIGBLOCK 1
+#define HAVE_SIGHOLD 0
+
+/* If you have either of the following functions, it will be used to
+ determine the number of file descriptors which may be open.
+ Otherwise, the code will use OPEN_MAX if defined, then NOFILE if
+ defined, then 20. */
+#define HAVE_GETDTABLESIZE 1
+#define HAVE_SYSCONF 0
+
+/* The code will use one of the following functions when detaching
+ from a terminal. One of these must exist. */
+#define HAVE_SETPGRP 1
+#define HAVE_SETSID 1
+
+/* If you do not specify the local node name in the main configuration
+ file, Taylor UUCP will try to use each of the following functions
+ in turn. If neither is available, you must specify the local node
+ name in the configuration file. */
+#define HAVE_GETHOSTNAME 1
+#define HAVE_UNAME 0
+
+/* The code will try to use each of the following functions in turn to
+ determine the current time. If none are available, it will use
+ time, which is assumed to always exist. */
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_FTIME 0
+
+/* If neither gettimeofday nor ftime is available, the code will use
+ times (if available) to measure a span of time. See also the
+ discussion of TIMES_TICK in policy.h. */
+#define HAVE_TIMES 1
+
+/* When a chat script requests a pause of less than a second with \p,
+ Taylor UUCP will try to use each of the following functions in
+ turn. If none are available, it will sleep for a full second.
+ Also, the (non-portable) tstuu program requires either select or
+ poll. */
+#define HAVE_NAPMS 0
+#define HAVE_NAP 0
+#define HAVE_USLEEP 1
+#define HAVE_POLL 0
+#define HAVE_SELECT 1
+
+/* If the getgrent function is available, it will be used to determine
+ all the groups a user belongs to when checking file access
+ permissions. */
+#define HAVE_GETGRENT 1
+
+/* If the socket function is available, TCP support code will be
+ compiled in. */
+#define HAVE_SOCKET 1
+
+/* If the t_open function is available, TLI support code will be
+ compiled in. This may require adding a library, such as -lnsl or
+ -lxti, to the Makefile variables LIBS. */
+#define HAVE_T_OPEN 0
+
+/* That's the end of the list of the functions. Now there are a few
+ last miscellaneous items. */
+
+/* On some systems the following functions are declared in such a way
+ that the code cannot make a simple extern. On other systems, these
+ functions are not declared at all, and the extern is required. If
+ a declaration of the function, as shown, compiles on your system,
+ set the value to 1. Not all functions declared externally are
+ listed here, only the ones with which I have had trouble. */
+/* extern long times (); */
+#define TIMES_DECLARATION_OK 0
+/* extern struct passwd *getpwnam (); */
+#define GETPWNAM_DECLARATION_OK 1
+/* extern struct passwd *getpwuid (); */
+#define GETPWUID_DECLARATION_OK 0
+/* extern struct group *getgrent (); */
+#define GETGRENT_DECLARATION_OK 1
+
+/* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and
+ your setpgrp calls takes 2 arguments (on System V they generally
+ take no arguments). You can safely set this to 1 on System V,
+ provided the call will compile without any errors. */
+#define HAVE_BSD_PGRP 0
+
+/* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header
+ file <sys/wait.h>. */
+#define HAVE_UNION_WAIT 1
+
+/* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names
+ longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* If slow system calls are restarted after interrupts, set
+ HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION
+ is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and
+ SV_INTERRUPT is defined in <signal.h>. In both of these cases
+ system calls can be prevented from restarting. */
+#define HAVE_RESTARTABLE_SYSCALLS 1
+
+/* Some systems supposedly need the following macros to be defined.
+ These are handled by the configure script (it will turn #undef into
+ #define when appropriate, which is why the peculiar #ifndef #undef
+ construction is used). If you are configuring by hand, you may add
+ appropriate definitions here, or just add them to CFLAGS when
+ running make. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+#ifndef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+#ifndef _MINIX
+#undef _MINIX
+#endif
+#ifndef _POSIX_1_SOURCE
+#undef _POSIX_1_SOURCE
+#endif
diff --git a/gnu/libexec/uucp/common_sources/conn.c b/gnu/libexec/uucp/common_sources/conn.c
new file mode 100644
index 00000000000..df35e8297f6
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/conn.c
@@ -0,0 +1,552 @@
+/* conn.c
+ Connection routines for the Taylor UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/04 19:30:39 jtc Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+
+static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ const char *zphone, boolean ftranslate));
+
+/* Create a new connection. This relies on system dependent functions
+ to set the qcmds and psysdep fields. If qport is NULL, it opens a
+ standard input port. */
+
+boolean
+fconn_init (qport, qconn)
+ struct uuconf_port *qport;
+ struct sconnection *qconn;
+{
+ qconn->qport = qport;
+ switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype)
+ {
+ case UUCONF_PORTTYPE_STDIN:
+ return fsysdep_stdin_init (qconn);
+ case UUCONF_PORTTYPE_MODEM:
+ return fsysdep_modem_init (qconn);
+ case UUCONF_PORTTYPE_DIRECT:
+ return fsysdep_direct_init (qconn);
+#if HAVE_TCP
+ case UUCONF_PORTTYPE_TCP:
+ return fsysdep_tcp_init (qconn);
+#endif
+#if HAVE_TLI
+ case UUCONF_PORTTYPE_TLI:
+ return fsysdep_tli_init (qconn);
+#endif
+ default:
+ ulog (LOG_ERROR, "Unknown port type");
+ return FALSE;
+ }
+}
+
+/* Connection dispatch routines. */
+
+/* Free a connection. */
+
+void
+uconn_free (qconn)
+ struct sconnection *qconn;
+{
+ (*qconn->qcmds->pufree) (qconn);
+}
+
+/* Lock a connection. */
+
+boolean
+fconn_lock (qconn, fin)
+ struct sconnection *qconn;
+ boolean fin;
+{
+ boolean (*pflock) P((struct sconnection *, boolean));
+
+ pflock = qconn->qcmds->pflock;
+ if (pflock == NULL)
+ return TRUE;
+ return (*pflock) (qconn, fin);
+}
+
+/* Unlock a connection. */
+
+boolean
+fconn_unlock (qconn)
+ struct sconnection *qconn;
+{
+ boolean (*pfunlock) P((struct sconnection *));
+
+ pfunlock = qconn->qcmds->pfunlock;
+ if (pfunlock == NULL)
+ return TRUE;
+ return (*pfunlock) (qconn);
+}
+
+/* Open a connection. */
+
+boolean
+fconn_open (qconn, ibaud, ihighbaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ long ihighbaud;
+ boolean fwait;
+{
+ boolean fret;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_PORT))
+ {
+ char abspeed[20];
+
+ if (ibaud == (long) 0)
+ strcpy (abspeed, "default speed");
+ else
+ sprintf (abspeed, "speed %ld", ibaud);
+
+ if (qconn->qport == NULL)
+ ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)",
+ abspeed);
+ else if (qconn->qport->uuconf_zname == NULL)
+ ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)",
+ abspeed);
+ else
+ ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)",
+ qconn->qport->uuconf_zname, abspeed);
+ }
+#endif
+
+ /* If the system provides a range of baud rates, we select the
+ highest baud rate supported by the port. */
+ if (ihighbaud != 0 && qconn->qport != NULL)
+ {
+ struct uuconf_port *qport;
+
+ qport = qconn->qport;
+ ibaud = ihighbaud;
+ if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
+ {
+ if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0)
+ {
+ if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud)
+ ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud;
+ }
+ else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0)
+ ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
+ }
+ else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
+ {
+ if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0)
+ ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
+ }
+ }
+
+ /* This will normally be overridden by the port specific open
+ routine. */
+ if (qconn->qport == NULL)
+ ulog_device ("stdin");
+ else
+ ulog_device (qconn->qport->uuconf_zname);
+
+ fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait);
+
+ if (! fret)
+ ulog_device ((const char *) NULL);
+
+ return fret;
+}
+
+/* Close a connection. */
+
+boolean
+fconn_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ boolean fret;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection");
+
+ /* Don't report hangup signals while we're closing. */
+ fLog_sighup = FALSE;
+
+ fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess);
+
+ /* Make sure any signal reporting has been done before we set
+ fLog_sighup back to TRUE. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ fLog_sighup = TRUE;
+
+ ulog_device ((const char *) NULL);
+
+ return fret;
+}
+
+/* Reset the connection. */
+
+boolean
+fconn_reset (qconn)
+ struct sconnection *qconn;
+{
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection");
+
+ return (*qconn->qcmds->pfreset) (qconn);
+}
+
+/* Dial out on the connection. */
+
+boolean
+fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ struct uuconf_dialer sdialer;
+ enum tdialerfound tfound;
+ boolean (*pfdial) P((struct sconnection *, pointer,
+ const struct uuconf_system *, const char *,
+ struct uuconf_dialer *, enum tdialerfound *));
+
+ if (qdialer == NULL)
+ qdialer = &sdialer;
+ if (ptdialerfound == NULL)
+ ptdialerfound = &tfound;
+
+ qdialer->uuconf_zname = NULL;
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ pfdial = qconn->qcmds->pfdial;
+ if (pfdial == NULL)
+ return TRUE;
+ return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound);
+}
+
+/* Read data from the connection. */
+
+boolean
+fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ boolean fret;
+
+ fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout,
+ freport);
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_INCOMING))
+ udebug_buffer ("fconn_read: Read", zbuf, *pclen);
+ else if (FDEBUGGING (DEBUG_PORT))
+ ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen);
+#endif
+
+ return fret;
+}
+
+/* Write data to the connection. */
+
+boolean
+fconn_write (qconn, zbuf, clen)
+ struct sconnection *qconn;
+ const char *zbuf;
+ size_t clen;
+{
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_OUTGOING))
+ udebug_buffer ("fconn_write: Writing", zbuf, clen);
+ else if (FDEBUGGING (DEBUG_PORT))
+ ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen);
+#endif
+
+ return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen);
+}
+
+/* Read and write data. */
+
+boolean
+fconn_io (qconn, zwrite, pcwrite, zread, pcread)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t *pcwrite;
+ char *zread;
+ size_t *pcread;
+{
+ boolean fret;
+#if DEBUG > 1
+ size_t cwrite = *pcwrite;
+ size_t cread = *pcread;
+
+ if (cread == 0 || cwrite == 0)
+ ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu",
+ (unsigned long) cread, (unsigned long) cwrite);
+#endif
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_OUTGOING))
+ udebug_buffer ("fconn_io: Writing", zwrite, cwrite);
+#endif
+
+ fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread);
+
+ DEBUG_MESSAGE4 (DEBUG_PORT,
+ "fconn_io: Wrote %lu of %lu, read %lu of %lu",
+ (unsigned long) *pcwrite, (unsigned long) cwrite,
+ (unsigned long) *pcread, (unsigned long) cread);
+
+#if DEBUG > 1
+ if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
+ udebug_buffer ("fconn_io: Read", zread, *pcread);
+#endif
+
+ return fret;
+}
+
+/* Send a break character to a connection. Some port types may not
+ support break characters, in which case we just return TRUE. */
+
+boolean
+fconn_break (qconn)
+ struct sconnection *qconn;
+{
+ boolean (*pfbreak) P((struct sconnection *));
+
+ pfbreak = *qconn->qcmds->pfbreak;
+ if (pfbreak == NULL)
+ return TRUE;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character");
+
+ return (*pfbreak) (qconn);
+}
+
+/* Change the setting of a connection. Some port types may not
+ support this, in which case we just return TRUE. */
+
+boolean
+fconn_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ boolean (*pfset) P((struct sconnection *, enum tparitysetting,
+ enum tstripsetting, enum txonxoffsetting));
+
+ pfset = qconn->qcmds->pfset;
+ if (pfset == NULL)
+ return TRUE;
+
+ DEBUG_MESSAGE3 (DEBUG_PORT,
+ "fconn_set: Changing setting to %d, %d, %d",
+ (int) tparity, (int) tstrip, (int) txonxoff);
+
+ return (*pfset) (qconn, tparity, tstrip, txonxoff);
+}
+
+/* Require or ignore carrier on a connection. */
+
+boolean
+fconn_carrier (qconn, fcarrier)
+ struct sconnection *qconn;
+ boolean fcarrier;
+{
+ boolean (*pfcarrier) P((struct sconnection *, boolean));
+
+ pfcarrier = qconn->qcmds->pfcarrier;
+ if (pfcarrier == NULL)
+ return TRUE;
+ return (*pfcarrier) (qconn, fcarrier);
+}
+
+/* Run a chat program on a connection. */
+
+boolean
+fconn_run_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ return (*qconn->qcmds->pfchat) (qconn, pzprog);
+}
+
+/* Get the baud rate of a connection. */
+
+long
+iconn_baud (qconn)
+ struct sconnection *qconn;
+{
+ long (*pibaud) P((struct sconnection *));
+
+ pibaud = qconn->qcmds->pibaud;
+ if (pibaud == NULL)
+ return 0;
+ return (*pibaud) (qconn);
+}
+
+/* Modem dialing routines. */
+
+/*ARGSUSED*/
+boolean
+fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ {
+ char **pz;
+ boolean ffirst;
+
+ /* The pzdialer field is a sequence of dialer/token pairs. The
+ dialer portion names a dialer to use. The token portion is
+ what \D and \T in the chat script expand to. If there is no
+ token for the last dialer, the phone number for the system is
+ used. */
+ ffirst = TRUE;
+ pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
+ while (*pz != NULL)
+ {
+ int iuuconf;
+ struct uuconf_dialer *q;
+ struct uuconf_dialer s;
+ const char *ztoken;
+ boolean ftranslate;
+
+ if (! ffirst)
+ q = &s;
+ else
+ q = qdialer;
+
+ iuuconf = uuconf_dialer_info (puuconf, *pz, q);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ulog (LOG_ERROR, "%s: Dialer not found", *pz);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+
+ ++pz;
+ ztoken = *pz;
+
+ ftranslate = FALSE;
+ if (ztoken == NULL
+ || strcmp (ztoken, "\\D") == 0)
+ ztoken = zphone;
+ else if (strcmp (ztoken, "\\T") == 0)
+ {
+ ztoken = zphone;
+ ftranslate = TRUE;
+ }
+
+ if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate))
+ {
+ (void) uuconf_dialer_free (puuconf, q);
+ if (! ffirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+ return FALSE;
+ }
+
+ if (ffirst)
+ {
+ *ptdialerfound = DIALERFOUND_FREE;
+ ffirst = FALSE;
+ }
+ else
+ (void) uuconf_dialer_free (puuconf, q);
+
+ if (*pz != NULL)
+ ++pz;
+ }
+
+ return TRUE;
+ }
+ else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL)
+ {
+ struct uuconf_dialer *q;
+
+ q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
+ *qdialer = *q;
+ *ptdialerfound = DIALERFOUND_TRUE;
+ return fcdo_dial (qconn, puuconf, q, zphone, FALSE);
+ }
+ else
+ {
+ ulog (LOG_ERROR, "No dialer information");
+ return FALSE;
+ }
+}
+
+/* Actually use a dialer. We set up the modem (which may include
+ opening the dialer device), run the chat script, and finish dealing
+ with the modem. */
+
+static boolean
+fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+{
+ const char *zname;
+
+ if (! fsysdep_modem_begin_dial (qconn, qdial))
+ return FALSE;
+
+ if (qconn->qport == NULL)
+ zname = NULL;
+ else
+ zname = qconn->qport->uuconf_zname;
+
+ if (! fchat (qconn, puuconf, &qdial->uuconf_schat,
+ (const struct uuconf_system *) NULL, qdial,
+ zphone, ftranslate, zname, iconn_baud (qconn)))
+ return FALSE;
+
+ return fsysdep_modem_end_dial (qconn, qdial);
+}
diff --git a/gnu/libexec/uucp/common_sources/conn.h b/gnu/libexec/uucp/common_sources/conn.h
new file mode 100644
index 00000000000..59d4881b07f
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/conn.h
@@ -0,0 +1,312 @@
+/* conn.h
+ Header file for routines which manipulate connections.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef CONN_H
+
+#define CONN_H
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct uuconf_system;
+struct uuconf_dialer;
+struct uuconf_chat;
+#endif
+
+/* This structure represents a connection. */
+
+struct sconnection
+{
+ /* Pointer to command table for this type of connection. */
+ const struct sconncmds *qcmds;
+ /* Pointer to system dependent information. */
+ pointer psysdep;
+ /* Pointer to system independent information. */
+ struct uuconf_port *qport;
+};
+
+/* Whether fconn_dial got a dialer. */
+
+enum tdialerfound
+{
+ /* Did not find a dialer. */
+ DIALERFOUND_FALSE,
+ /* Found a dialer which does not need to be freed. */
+ DIALERFOUND_TRUE,
+ /* Found a dialer which does need to be freed. */
+ DIALERFOUND_FREE
+};
+
+/* Parity settings to pass to fconn_set. */
+
+enum tparitysetting
+{
+ /* Do not change output parity generation. */
+ PARITYSETTING_DEFAULT,
+ /* No parity (all eight output bits used). */
+ PARITYSETTING_NONE,
+ /* Even parity. */
+ PARITYSETTING_EVEN,
+ /* Odd parity. */
+ PARITYSETTING_ODD,
+ /* Mark parity. */
+ PARITYSETTING_MARK,
+ /* Space parity. */
+ PARITYSETTING_SPACE
+};
+
+/* Type of strip control argument to fconn_set. */
+
+enum tstripsetting
+{
+ /* Do not change the stripping of input characters. */
+ STRIPSETTING_DEFAULT,
+ /* Do not strip input characters to seven bits. */
+ STRIPSETTING_EIGHTBITS,
+ /* Strip input characters to seven bits. */
+ STRIPSETTING_SEVENBITS
+};
+
+/* Type of XON/XOFF control argument to fconn_set. */
+
+enum txonxoffsetting
+{
+ /* Do not change XON/XOFF handshake setting. */
+ XONXOFF_DEFAULT,
+ /* Do not do XON/XOFF handshaking. */
+ XONXOFF_OFF,
+ /* Do XON/XOFF handshaking. */
+ XONXOFF_ON
+};
+
+/* A command table holds the functions which implement actions for
+ each different kind of connection. */
+
+struct sconncmds
+{
+ /* Free up a connection. */
+ void (*pufree) P((struct sconnection *qconn));
+ /* Lock the connection. The fin argument is TRUE if the connection
+ is to be used for an incoming call. May be NULL. */
+ boolean (*pflock) P((struct sconnection *qconn, boolean fin));
+ /* Unlock the connection. May be NULL. */
+ boolean (*pfunlock) P((struct sconnection *qconn));
+ /* Open the connection. */
+ boolean (*pfopen) P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+ /* Close the connection. */
+ boolean (*pfclose) P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+ /* Reset the connection so that another call may be accepted. */
+ boolean (*pfreset) P((struct sconnection *qconn));
+ /* Dial a number on a connection. This set *qdialer to the dialer
+ used, if any, and sets *ptdialerfound appropriately. The qsys
+ and zphone arguments are for the chat script. This field may be
+ NULL. */
+ boolean (*pfdial) P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialerfound));
+ /* Read data from a connection, with a timeout in seconds. When
+ called *pclen is the length of the buffer; on successful return
+ *pclen is the number of bytes read into the buffer. The cmin
+ argument is the minimum number of bytes to read before returning
+ ahead of a timeout. */
+ boolean (*pfread) P((struct sconnection *qconn, char *zbuf, size_t *pclen,
+ size_t cmin, int ctimeout, boolean freport));
+ /* Write data to the connection. */
+ boolean (*pfwrite) P((struct sconnection *qconn, const char *zbuf,
+ size_t clen));
+ /* Read and write data to the connection. This reads and writes
+ data until either all passed in data has been written or the read
+ buffer has been filled. When called *pcread is the size of the
+ read buffer and *pcwrite is the number of bytes to write; on
+ successful return *pcread is the number of bytes read and
+ *pcwrite is the number of bytes written. */
+ boolean (*pfio) P((struct sconnection *qconn, const char *zwrite,
+ size_t *pcwrite, char *zread, size_t *pcread));
+ /* Send a break character. This field may be NULL. */
+ boolean (*pfbreak) P((struct sconnection *qconn));
+ /* Change the connection setting. This field may be NULL. */
+ boolean (*pfset) P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+ /* Require or ignore carrer. This field may be NULL. */
+ boolean (*pfcarrier) P((struct sconnection *qconn,
+ boolean fcarrier));
+ /* Run a chat program on a connection. */
+ boolean (*pfchat) P((struct sconnection *qconn, char **pzprog));
+ /* Get the baud rate of a connection. This field may be NULL. */
+ long (*pibaud) P((struct sconnection *qconn));
+};
+
+/* Connection functions. */
+
+/* Initialize a connection. This must be called before any of the
+ other connection functions are called. It initializes the fields
+ of qconn. It returns FALSE on error. */
+extern boolean fconn_init P((struct uuconf_port *qport,
+ struct sconnection *qconn));
+
+/* Free up connection data. */
+extern void uconn_free P((struct sconnection *qconn));
+
+/* Lock a connection. The fin argument is TRUE if the port is to be
+ used for an incoming call; certains type of Unix locking need this
+ information because they need to open the port. */
+extern boolean fconn_lock P((struct sconnection *qconn, boolean fin));
+
+/* Unlock a connection. */
+extern boolean fconn_unlock P((struct sconnection *qconn));
+
+/* Open a connection. If ibaud is 0, the natural baud rate of the
+ port is used. If ihighbaud is not 0, fconn_open chooses the
+ highest supported baud rate between ibaud and ihighbaud. If fwait
+ is TRUE, this should wait for an incoming call. */
+extern boolean fconn_open P((struct sconnection *qconn, long ibaud,
+ long ihighbaud, boolean fwait));
+
+/* Close a connection. The fsuccess argument is TRUE if the
+ conversation completed normally, FALSE if it is being aborted. */
+extern boolean fconn_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+
+/* Reset a connection such that another call may be accepted. */
+extern boolean fconn_reset P((struct sconnection *q));
+
+/* Dial out on a connection. The qsys and zphone arguments are for
+ the chat scripts; zphone is the phone number to dial. If qdialer
+ is not NULL, *qdialer will be set to the dialer information used if
+ any; *ptdialerfound will be set appropriately. */
+extern boolean fconn_dial P((struct sconnection *q, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialerfound));
+
+/* Read from a connection.
+ zbuf -- buffer to read bytes into
+ *pclen on call -- length of zbuf
+ *pclen on successful return -- number of bytes read
+ cmin -- minimum number of bytes to read before returning ahead of timeout
+ ctimeout -- timeout in seconds, 0 if none
+ freport -- whether to report errors. */
+extern boolean fconn_read P((struct sconnection *qconn, char *zbuf,
+ size_t *pclen, size_t cmin,
+ int ctimeout, boolean freport));
+
+/* Write to a connection. */
+extern boolean fconn_write P((struct sconnection *qconn, const char *zbuf,
+ size_t cbytes));
+
+/* Read and write to a connection. This reads and writes data until
+ either all passed-in data has been written or the read buffer is
+ full.
+ zwrite -- buffer to write bytes from
+ *pcwrite on call -- number of bytes to write
+ *pcwrite on successful return -- number of bytes written
+ zread -- buffer to read bytes into
+ *pcread on call -- size of read buffer
+ *pcread on successful return -- number of bytes read. */
+extern boolean fconn_io P((struct sconnection *qconn, const char *zwrite,
+ size_t *pcwrite, char *zread, size_t *pcread));
+
+/* Send a break character to a connection. */
+extern boolean fconn_break P((struct sconnection *qconn));
+
+/* Change the settings of a connection. This allows independent
+ control over the parity of output characters, whether to strip
+ input characters, and whether to do XON/XOFF handshaking. There is
+ no explicit control over parity checking of input characters. This
+ function returns FALSE on error. Attempts to set values not
+ supported by the hardware are silently ignored. */
+extern boolean fconn_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+
+/* Get the baud rate of a connection. */
+extern long iconn_baud P((struct sconnection *qconn));
+
+/* Do a chat script with a system. */
+extern boolean fchat P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_chat *qchat,
+ const struct uuconf_system *qsys,
+ const struct uuconf_dialer *qdialer,
+ const char *zphone, boolean ftranslate,
+ const char *zport, long ibaud));
+
+/* Tell the connection to either require or ignore carrier as fcarrier
+ is TRUE or FALSE respectively. This is called with fcarrier TRUE
+ when \m is encountered in a chat script, and with fcarrier FALSE
+ when \M is encountered. */
+extern boolean fconn_carrier P((struct sconnection *qconn,
+ boolean fcarrier));
+
+/* Run a chat program on a connection. */
+extern boolean fconn_run_chat P((struct sconnection *qconn,
+ char **pzprog));
+
+/* Dialing out on a modem is partially system independent. This is
+ the modem dialing routine. */
+extern boolean fmodem_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialerfound));
+
+/* Begin dialing out. This should open the dialer device if there is
+ one, toggle DTR if requested and possible, and tell the port to
+ ignore carrier. It should return FALSE on error. */
+extern boolean fsysdep_modem_begin_dial P((struct sconnection *qconn,
+ struct uuconf_dialer *qdial));
+
+/* Finish dialing out on a modem. This should close the dialer device
+ if there is one. If the dialer and the port both support carrier,
+ the connection should be told to pay attention to carrier. If it
+ is possible to wait for carrier to come on, and the dialer and the
+ port both the port support carrier, it should wait until carrier
+ comes on. */
+extern boolean fsysdep_modem_end_dial P((struct sconnection *qconn,
+ struct uuconf_dialer *qdial));
+
+/* System dependent initialization routines. */
+extern boolean fsysdep_stdin_init P((struct sconnection *qconn));
+extern boolean fsysdep_modem_init P((struct sconnection *qconn));
+extern boolean fsysdep_direct_init P((struct sconnection *qconn));
+#if HAVE_TCP
+extern boolean fsysdep_tcp_init P((struct sconnection *qconn));
+#endif
+#if HAVE_TLI
+extern boolean fsysdep_tli_init P((struct sconnection *qconn));
+#endif
+
+#endif /* ! defined (CONN_H) */
diff --git a/gnu/libexec/uucp/common_sources/copy.c b/gnu/libexec/uucp/common_sources/copy.c
new file mode 100644
index 00000000000..6956bb3d7cf
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/copy.c
@@ -0,0 +1,202 @@
+/* copy.c
+ Copy one file to another for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char copy_rcsid[] = "$Id: copy.c,v 1.1 1993/08/04 19:30:44 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+/* Copy one file to another. */
+
+#if USE_STDIO
+
+boolean
+fcopy_file (zfrom, zto, fpublic, fmkdirs)
+ const char *zfrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ FILE *efrom;
+ boolean fret;
+
+ efrom = fopen (zfrom, BINREAD);
+ if (efrom == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zfrom, strerror (errno));
+ return FALSE;
+ }
+
+ fret = fcopy_open_file (efrom, zto, fpublic, fmkdirs);
+ (void) fclose (efrom);
+ return fret;
+}
+
+boolean
+fcopy_open_file (efrom, zto, fpublic, fmkdirs)
+ FILE *efrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ FILE *eto;
+ char ab[8192];
+ int c;
+
+ eto = esysdep_fopen (zto, fpublic, FALSE, fmkdirs);
+ if (eto == NULL)
+ return FALSE;
+
+ while ((c = fread (ab, sizeof (char), sizeof ab, efrom)) != 0)
+ {
+ if (fwrite (ab, sizeof (char), (size_t) c, eto) != c)
+ {
+ ulog (LOG_ERROR, "fwrite: %s", strerror (errno));
+ (void) fclose (eto);
+ (void) remove (zto);
+ return FALSE;
+ }
+ }
+
+ if (fclose (eto) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#else /* ! USE_STDIO */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+boolean
+fcopy_file (zfrom, zto, fpublic, fmkdirs)
+ const char *zfrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ int ofrom;
+ boolean fret;
+
+ ofrom = open (zfrom, O_RDONLY | O_NOCTTY, 0);
+ if (ofrom < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfrom, strerror (errno));
+ return FALSE;
+ }
+
+ fret = fcopy_open_file (ofrom, zto, fpublic, fmkdirs);
+ (void) close (ofrom);
+ return fret;
+}
+
+boolean
+fcopy_open_file (ofrom, zto, fpublic, fmkdirs)
+ int ofrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ int oto;
+ char ab[8192];
+ int c;
+
+ /* These file mode arguments are from the UNIX version of sysdep.h;
+ each system dependent header file will need their own
+ definitions. */
+ oto = creat (zto, fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE);
+ if (oto < 0)
+ {
+ if (errno == ENOENT && fmkdirs)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ return FALSE;
+ oto = creat (zto,
+ fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE);
+ }
+ if (oto < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zto, strerror (errno));
+ return FALSE;
+ }
+ }
+
+ while ((c = read (ofrom, ab, sizeof ab)) > 0)
+ {
+ if (write (oto, ab, (size_t) c) != c)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ (void) close (oto);
+ (void) remove (zto);
+ return FALSE;
+ }
+ }
+
+ if (close (oto) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ if (c < 0)
+ {
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* ! USE_STDIO */
diff --git a/gnu/libexec/uucp/common_sources/cu.h b/gnu/libexec/uucp/common_sources/cu.h
new file mode 100644
index 00000000000..5a514ee3bfe
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/cu.h
@@ -0,0 +1,80 @@
+/* cu.h
+ Header file for cu.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* The user settable variables supported by cu. */
+
+/* The escape character used to introduce a special command. The
+ escape character is the first character of this string. */
+extern const char *zCuvar_escape;
+
+/* Whether to delay for a second before printing the host name after
+ seeing an escape character. */
+extern boolean fCuvar_delay;
+
+/* The input characters which finish a line. The escape character is
+ only recognized following one of these characters. */
+extern const char *zCuvar_eol;
+
+/* Whether to transfer binary data (nonprintable characters other than
+ newline and tab) when sending a file. If this is FALSE, then
+ newline is changed to carriage return. */
+extern boolean fCuvar_binary;
+
+/* A prefix string to use before sending a binary character from a
+ file; this is only used if fCuvar_binary is TRUE. */
+extern const char *zCuvar_binary_prefix;
+
+/* Whether to check for echoes of characters sent when sending a file.
+ This is ignored if fCuvar_binary is TRUE. */
+extern boolean fCuvar_echocheck;
+
+/* A character to look for after each newline is sent when sending a
+ file. The character is the first character in this string, except
+ that a '\0' means that no echo check is done. */
+extern const char *zCuvar_echonl;
+
+/* The timeout to use when looking for an character. */
+extern int cCuvar_timeout;
+
+/* The character to use to kill a line if an echo check fails. The
+ first character in this string is sent. */
+extern const char *zCuvar_kill;
+
+/* The number of times to try resending a line if the echo check keeps
+ failing. */
+extern int cCuvar_resend;
+
+/* The string to send at the end of a file sent with ~>. */
+extern const char *zCuvar_eofwrite;
+
+/* The string to look for to finish a file received with ~<. For tip
+ this is a collection of single characters, but I don't want to do
+ that because it means that there are characters which cannot be
+ received. */
+extern const char *zCuvar_eofread;
+
+/* Whether to provide verbose information when sending or receiving a
+ file. */
+extern boolean fCuvar_verbose;
diff --git a/gnu/libexec/uucp/common_sources/getopt.h b/gnu/libexec/uucp/common_sources/getopt.h
new file mode 100644
index 00000000000..1a70e027714
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/getopt.h
@@ -0,0 +1,120 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file was modified slightly by Ian Lance Taylor, November 1992,
+ for Taylor UUCP. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ian Lance Taylor <ian@airs.com> added the following defines for
+ Taylor UUCP. This avoids reported conflicts with system getopt
+ definitions. */
+#define getopt gnu_getopt
+#define optarg gnu_optarg
+#define optind gnu_optind
+#define opterr gnu_opterr
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+ const char *name;
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+enum _argtype
+{
+ no_argument,
+ required_argument,
+ optional_argument
+};
+
+extern int getopt P((int argc, char *const *argv, const char *shortopts));
+extern int getopt_long P((int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind));
+extern int getopt_long_only P((int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind));
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal P((int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/libexec/uucp/common_sources/log.c b/gnu/libexec/uucp/common_sources/log.c
new file mode 100644
index 00000000000..b55ca8b10b9
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/log.c
@@ -0,0 +1,699 @@
+/* log.c
+ Routines to add entries to the log files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char log_rcsid[] = "$Id: log.c,v 1.1 1993/08/04 19:30:50 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+#if ANSI_C
+#include <stdarg.h>
+#endif
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+
+/* Local functions. */
+
+static const char *zldate_and_time P((void));
+
+/* Log file name. */
+static const char *zLogfile;
+
+/* The function to call when a LOG_FATAL error occurs. */
+static void (*pfLfatal) P((void));
+
+/* Whether to go to a file. */
+static boolean fLfile;
+
+/* ID number. */
+static int iLid;
+
+/* The current user name. */
+static char *zLuser;
+
+/* The current system name. */
+static char *zLsystem;
+
+/* The current device name. */
+char *zLdevice;
+
+/* The open log file. */
+static FILE *eLlog;
+
+/* Whether we have tried to open the log file. We need this because
+ we don't want to keep trying to open the log file if we failed the
+ first time. It can't be static because under HAVE_HDB_LOGGING we
+ may have to write to various different log files. */
+static boolean fLlog_tried;
+
+#if DEBUG > 1
+/* Debugging file name. */
+static const char *zLdebugfile;
+
+/* The open debugging file. */
+static FILE *eLdebug;
+
+/* Whether we've tried to open the debugging file. */
+static boolean fLdebug_tried;
+
+/* Whether we've written out any debugging information. */
+static boolean fLdebugging;
+#endif
+
+/* Statistics file name. */
+static const char *zLstatsfile;
+
+/* The open statistics file. */
+static FILE *eLstats;
+
+/* Whether we've tried to open the statistics file. */
+static boolean fLstats_tried;
+
+/* The array of signals. The elements are only set to TRUE by the
+ default signal handler. They are only set to FALSE if we don't
+ care whether we got the signal or not. */
+volatile sig_atomic_t afSignal[INDEXSIG_COUNT];
+
+/* The array of signals to log. The elements are only set to TRUE by
+ the default signal handler. They are set to FALSE when the signal
+ is logged in ulog. This means that if a signal comes in at just
+ the right time we won't log it (or, rather, we'll log it once
+ instead of twice), but that is not a catatrophe. */
+volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
+
+/* Flag that indicates SIGHUP is worth logging. */
+boolean fLog_sighup = TRUE;
+
+/* Signal names to use when logging signals. */
+static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES;
+
+/* If not NULL, ulog calls this function before outputting anything.
+ This is used to support cu. */
+void (*pfLstart) P((void));
+
+/* If not NULL, ulog calls this function after outputting everything.
+ This is used to support cu. */
+void (*pfLend) P((void));
+
+/* Set the function to call on a LOG_FATAL error. */
+
+void
+ulog_fatal_fn (pfn)
+ void (*pfn) P((void));
+{
+ pfLfatal = pfn;
+}
+
+/* Decide whether to send log message to the file or not. */
+
+void
+ulog_to_file (puuconf, ffile)
+ pointer puuconf;
+ boolean ffile;
+{
+ int iuuconf;
+
+ iuuconf = uuconf_logfile (puuconf, &zLogfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+#if DEBUG > 1
+ iuuconf = uuconf_debugfile (puuconf, &zLdebugfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+#endif
+
+ iuuconf = uuconf_statsfile (puuconf, &zLstatsfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ fLfile = ffile;
+}
+
+/* Set the ID number. This will be called by the usysdep_initialize
+ if there is something sensible to set it to. */
+
+void
+ulog_id (i)
+ int i;
+{
+ iLid = i;
+}
+
+/* Set the user we are making log entries for. The arguments will be
+ copied into memory. */
+
+void
+ulog_user (zuser)
+ const char *zuser;
+{
+ ubuffree (zLuser);
+ zLuser = zbufcpy (zuser);
+}
+
+/* Set the system name we are making log entries for. The name is copied
+ into memory. */
+
+void
+ulog_system (zsystem)
+ const char *zsystem;
+{
+ if (zsystem == NULL
+ || zLsystem == NULL
+ || strcmp (zsystem, zLsystem) != 0)
+ {
+ ubuffree (zLsystem);
+ zLsystem = zbufcpy (zsystem);
+#if HAVE_HDB_LOGGING
+ /* Under HDB logging we now must write to a different log file. */
+ ulog_close ();
+#endif /* HAVE_HDB_LOGGING */
+ }
+}
+
+/* Set the device name. This is copied into memory. */
+
+void
+ulog_device (zdevice)
+ const char *zdevice;
+{
+ ubuffree (zLdevice);
+ zLdevice = zbufcpy (zdevice);
+}
+
+/* Make a log entry. We make a token concession to non ANSI_C systems,
+ but it clearly won't always work. */
+
+#if ! ANSI_C
+#undef HAVE_VFPRINTF
+#endif
+
+/*VARARGS2*/
+#if HAVE_VFPRINTF
+void
+ulog (enum tlog ttype, const char *zmsg, ...)
+#else
+void
+ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
+ enum tlog ttype;
+ const char *zmsg;
+#endif
+{
+#if HAVE_VFPRINTF
+ va_list parg;
+#endif
+ FILE *e, *edebug;
+ boolean fstart, fend;
+ const char *zhdr, *zstr;
+
+ /* Log any received signal. We do it this way to avoid calling ulog
+ from the signal handler. A few routines call ulog to get this
+ message out with zmsg == NULL. */
+ {
+ static boolean fdoing_sigs;
+
+ if (! fdoing_sigs)
+ {
+ int isig;
+
+ fdoing_sigs = TRUE;
+ for (isig = 0; isig < INDEXSIG_COUNT; isig++)
+ {
+ if (afLog_signal[isig])
+ {
+ afLog_signal[isig] = FALSE;
+
+ /* Apparently SunOS sends SIGINT rather than SIGHUP
+ when hanging up, so we don't log either signal if
+ fLog_sighup is FALSE. */
+ if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT)
+ || fLog_sighup)
+ ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]);
+ }
+ }
+ fdoing_sigs = FALSE;
+ }
+ }
+
+ if (zmsg == NULL)
+ return;
+
+#if DEBUG > 1
+ /* If we've had a debugging file open in the past, then we want to
+ write all log file entries to the debugging file even if it's
+ currently closed. */
+ if (fLfile
+ && eLdebug == NULL
+ && ! fLdebug_tried
+ && (fLdebugging || (int) ttype >= (int) LOG_DEBUG))
+ {
+ fLdebug_tried = TRUE;
+ eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE);
+ fLdebugging = TRUE;
+ }
+#endif /* DEBUG > 1 */
+
+ if (! fLfile)
+ e = stderr;
+#if DEBUG > 1
+ else if ((int) ttype >= (int) LOG_DEBUG)
+ {
+ e = eLdebug;
+
+ /* If we can't open the debugging file, don't output any
+ debugging messages. */
+ if (e == NULL)
+ return;
+ }
+#endif /* DEBUG > 1 */
+ else
+ {
+ if (eLlog == NULL && ! fLlog_tried)
+ {
+ fLlog_tried = TRUE;
+#if ! HAVE_HDB_LOGGING
+ eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE);
+#else /* HAVE_HDB_LOGGING */
+ {
+ const char *zsys;
+ char *zfile;
+
+ /* We want to write to .Log/program/system, e.g.
+ .Log/uucico/uunet. The system name may not be set. */
+ if (zLsystem == NULL)
+ zsys = "ANY";
+ else
+ zsys = zLsystem;
+
+ zfile = zbufalc (strlen (zLogfile)
+ + strlen (abProgram)
+ + strlen (zsys)
+ + 1);
+ sprintf (zfile, zLogfile, abProgram, zsys);
+ eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE);
+ ubuffree (zfile);
+ }
+#endif /* HAVE_HDB_LOGGING */
+
+ if (eLlog == NULL)
+ {
+ /* We can't open the log file. We don't even have a
+ safe way to report this problem, since we may not be
+ able to write to stderr (it may, for example, be
+ attached to the incoming call). */
+ if (pfLfatal != NULL)
+ (*pfLfatal) ();
+ usysdep_exit (FALSE);
+ }
+ }
+
+ e = eLlog;
+
+ /* eLlog might be NULL here because we might try to open the log
+ file recursively via esysdep_fopen. */
+ if (e == NULL)
+ return;
+ }
+
+ if (pfLstart != NULL)
+ (*pfLstart) ();
+
+ edebug = NULL;
+#if DEBUG > 1
+ if ((int) ttype < (int) LOG_DEBUG)
+ edebug = eLdebug;
+#endif
+
+ fstart = TRUE;
+ fend = TRUE;
+
+ switch (ttype)
+ {
+ case LOG_NORMAL:
+ zhdr = "";
+ break;
+ case LOG_ERROR:
+ zhdr = "ERROR: ";
+ break;
+ case LOG_FATAL:
+ zhdr = "FATAL: ";
+ break;
+#if DEBUG > 1
+ case LOG_DEBUG:
+ zhdr = "DEBUG: ";
+ break;
+ case LOG_DEBUG_START:
+ zhdr = "DEBUG: ";
+ fend = FALSE;
+ break;
+ case LOG_DEBUG_CONTINUE:
+ zhdr = NULL;
+ fstart = FALSE;
+ fend = FALSE;
+ break;
+ case LOG_DEBUG_END:
+ zhdr = NULL;
+ fstart = FALSE;
+ break;
+#endif
+ default:
+ zhdr = "???: ";
+ break;
+ }
+
+ if (fstart)
+ {
+ if (! fLfile)
+ {
+ fprintf (e, "%s: ", abProgram);
+ if (edebug != NULL)
+ fprintf (edebug, "%s: ", abProgram);
+ }
+ else
+ {
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, "%s ", abProgram);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", abProgram);
+#else /* ! HAVE_TAYLOR_LOGGING */
+ fprintf (e, "%s ", zLuser == NULL ? "uucp" : zLuser);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLuser == NULL ? "uucp" : zLuser);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+ fprintf (e, "%s ", zLsystem == NULL ? "-" : zLsystem);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLsystem == NULL ? "-" : zLsystem);
+
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, "%s ", zLuser == NULL ? "-" : zLuser);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLuser == NULL ? "-" : zLuser);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+ zstr = zldate_and_time ();
+ fprintf (e, "(%s", zstr);
+ if (edebug != NULL)
+ fprintf (edebug, "(%s", zstr);
+
+ if (iLid != 0)
+ {
+#if ! HAVE_HDB_LOGGING
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, " %d", iLid);
+ if (edebug != NULL)
+ fprintf (edebug, " %d", iLid);
+#else /* ! HAVE_TAYLOR_LOGGING */
+ fprintf (e, "-%d", iLid);
+ if (edebug != NULL)
+ fprintf (edebug, "-%d", iLid);
+#endif /* ! HAVE_TAYLOR_LOGGING */
+#else /* HAVE_HDB_LOGGING */
+
+ /* I assume that the second number here is meant to be
+ some sort of file sequence number, and that it should
+ correspond to the sequence number in the statistics
+ file. I don't have any really convenient way to do
+ this, so I won't unless somebody thinks it's very
+ important. */
+ fprintf (e, ",%d,%d", iLid, 0);
+ if (edebug != NULL)
+ fprintf (edebug, ",%d,%d", iLid, 0);
+#endif /* HAVE_HDB_LOGGING */
+ }
+
+ fprintf (e, ") ");
+ if (edebug != NULL)
+ fprintf (edebug, ") ");
+
+ fprintf (e, "%s", zhdr);
+ if (edebug != NULL)
+ fprintf (edebug, "%s", zhdr);
+ }
+ }
+
+#if HAVE_VFPRINTF
+ va_start (parg, zmsg);
+ vfprintf (e, zmsg, parg);
+ va_end (parg);
+ if (edebug != NULL)
+ {
+ va_start (parg, zmsg);
+ vfprintf (edebug, zmsg, parg);
+ va_end (parg);
+ }
+#else /* ! HAVE_VFPRINTF */
+ fprintf (e, zmsg, a, b, c, d, f, g, h, i, j);
+ if (edebug != NULL)
+ fprintf (edebug, zmsg, a, b, c, d, f, g, h, i, j);
+#endif /* ! HAVE_VFPRINTF */
+
+ if (fend)
+ {
+ fprintf (e, "\n");
+ if (edebug != NULL)
+ fprintf (edebug, "\n");
+ }
+
+ (void) fflush (e);
+ if (edebug != NULL)
+ (void) fflush (edebug);
+
+ if (pfLend != NULL)
+ (*pfLend) ();
+
+ if (ttype == LOG_FATAL)
+ {
+ if (pfLfatal != NULL)
+ (*pfLfatal) ();
+ usysdep_exit (FALSE);
+ }
+
+#if CLOSE_LOGFILES
+ ulog_close ();
+#endif
+}
+
+/* Log a uuconf error. */
+
+void
+ulog_uuconf (ttype, puuconf, iuuconf)
+ enum tlog ttype;
+ pointer puuconf;
+ int iuuconf;
+{
+ char ab[512];
+
+ (void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab);
+ ulog (ttype, "%s", ab);
+}
+
+/* Close the log file. There's nothing useful we can do with errors,
+ so we don't check for them. */
+
+void
+ulog_close ()
+{
+ /* Make sure we logged any signal we received. */
+ ulog (LOG_ERROR, (const char *) NULL);
+
+ if (eLlog != NULL)
+ {
+ (void) fclose (eLlog);
+ eLlog = NULL;
+ fLlog_tried = FALSE;
+ }
+
+#if DEBUG > 1
+ if (eLdebug != NULL)
+ {
+ (void) fclose (eLdebug);
+ eLdebug = NULL;
+ fLdebug_tried = FALSE;
+ }
+#endif
+}
+
+/* Add an entry to the statistics file. We may eventually want to put
+ failed file transfers in here, but we currently do not. */
+
+/*ARGSUSED*/
+void
+ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster)
+ boolean fsucceeded;
+ const char *zuser;
+ const char *zsystem;
+ boolean fsent;
+ long cbytes;
+ long csecs;
+ long cmicros;
+ boolean fmaster;
+{
+ long cbps;
+
+ /* The seconds and microseconds are now counted independently, so
+ they may be out of synch. */
+ if (cmicros < 0)
+ {
+ csecs -= ((- cmicros) / 1000000L) + 1;
+ cmicros = 1000000L - ((- cmicros) % 1000000L);
+ }
+ if (cmicros >= 1000000L)
+ {
+ csecs += cmicros / 10000000L;
+ cmicros = cmicros % 1000000L;
+ }
+
+ /* On a system which can determine microseconds we might very well
+ have both csecs == 0 and cmicros == 0. */
+ if (csecs == 0 && cmicros < 1000)
+ cbps = 0;
+ else
+ {
+ long cmillis;
+
+ /* This computation will not overflow provided csecs < 2147483
+ and cbytes and cbps both fit in a long. */
+ cmillis = csecs * 1000 + cmicros / 1000;
+ cbps = ((cbytes / cmillis) * 1000
+ + ((cbytes % cmillis) * 1000) / cmillis);
+ }
+
+ if (eLstats == NULL)
+ {
+ if (fLstats_tried)
+ return;
+ fLstats_tried = TRUE;
+ eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE);
+ if (eLstats == NULL)
+ return;
+ }
+
+#if HAVE_TAYLOR_LOGGING
+ fprintf (eLstats,
+ "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec)\n",
+ zuser, zsystem, zldate_and_time (),
+ fsucceeded ? "" : "failed after ",
+ fsent ? "sent" : "received",
+ cbytes, csecs, cmicros / 1000, cbps);
+#endif /* HAVE_TAYLOR_LOGGING */
+#if HAVE_V2_LOGGING
+ fprintf (eLstats,
+ "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n",
+ zuser, zsystem, zldate_and_time (),
+ (long) time ((time_t *) NULL),
+ fsent ? "sent" : "received",
+ fsucceeded ? "data" : "failed after",
+ cbytes, csecs + cmicros / 500000);
+#endif /* HAVE_V2_LOGGING */
+#if HAVE_HDB_LOGGING
+ {
+ static int iseq;
+
+ /* I don't know what the 'C' means. The sequence number should
+ probably correspond to the sequence number in the log file, but
+ that is currently always 0; using this fake sequence number
+ will still at least reveal which transfers are from different
+ calls. We don't report a failed data transfer with this
+ format. */
+ if (! fsucceeded)
+ return;
+ ++iseq;
+ fprintf (eLstats,
+ "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld %s\n",
+ zsystem, zuser, fmaster ? 'M' : 'S', zldate_and_time (),
+ iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
+ fsent ? "->" : "<-",
+ cbytes, csecs, cmicros / 1000, cbps,
+ "bytes/sec");
+ }
+#endif /* HAVE_HDB_LOGGING */
+
+ (void) fflush (eLstats);
+
+#if CLOSE_LOGFILES
+ ustats_close ();
+#endif
+}
+
+/* Close the statistics file. */
+
+void
+ustats_close ()
+{
+ if (eLstats != NULL)
+ {
+ if (fclose (eLstats) != 0)
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ eLstats = NULL;
+ fLstats_tried = FALSE;
+ }
+}
+
+/* Return the date and time in a form used for a log entry. */
+
+static const char *
+zldate_and_time ()
+{
+ long isecs, imicros;
+ struct tm s;
+#if HAVE_TAYLOR_LOGGING
+ static char ab[sizeof "1991-12-31 12:00:00.00"];
+#endif
+#if HAVE_V2_LOGGING
+ static char ab[sizeof "12/31-12:00"];
+#endif
+#if HAVE_HDB_LOGGING
+ static char ab[sizeof "12/31-12:00:00"];
+#endif
+
+ isecs = ixsysdep_time (&imicros);
+ usysdep_localtime (isecs, &s);
+
+#if HAVE_TAYLOR_LOGGING
+ sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d",
+ s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour,
+ s.tm_min, s.tm_sec, (int) (imicros / 10000));
+#endif
+#if HAVE_V2_LOGGING
+ sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday,
+ s.tm_hour, s.tm_min);
+#endif
+#if HAVE_HDB_LOGGING
+ sprintf (ab, "%d/%d-%02d:%02d:%02d", s.tm_mon + 1, s.tm_mday,
+ s.tm_hour, s.tm_min, s.tm_sec);
+#endif
+
+ return ab;
+}
diff --git a/gnu/libexec/uucp/common_sources/policy.h b/gnu/libexec/uucp/common_sources/policy.h
new file mode 100644
index 00000000000..f79942915de
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/policy.h
@@ -0,0 +1,521 @@
+/* policy.h
+ Configuration file for policy decisions. To be edited on site.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* This header file contains macro definitions which must be set by
+ each site before compilation. The first few are system
+ characteristics that can not be easily discovered by the
+ configuration script. Most are configuration decisions that must
+ be made by the local administrator. */
+
+/* System characteristics. */
+
+/* This code tries to use several ANSI C features, including
+ prototypes, stdarg.h, the const qualifier and the types void
+ (including void * pointers) and unsigned char. By default it will
+ use these features if the compiler defines __STDC__. If your
+ compiler supports these features but does not define __STDC__, you
+ should set ANSI_C to 1. If your compiler does not support these
+ features but defines __STDC__ (no compiler should do this, in my
+ opinion), you should set ANSI_C to 0. In most cases (or if you're
+ not sure) just leave the line below commented out. */
+/* #define ANSI_C 1 */
+
+/* Set USE_STDIO to 1 if data files should be read using the stdio
+ routines (fopen, fread, etc.) rather than the UNIX unbuffered I/O
+ calls (open, read, etc.). Unless you know your stdio is really
+ rotten, you should leave this as 1. */
+#define USE_STDIO 1
+
+/* Exactly one of the following macros must be set to 1. Many modern
+ systems support more than one of these choices through some form of
+ compilation environment, in which case the setting will depend on
+ the compilation environment you use. If you have a reasonable
+ choice between options, I suspect that TERMIO or TERMIOS will be
+ more efficient than TTY, but I have not done any head to head
+ comparisons.
+
+ If you don't set any of these macros, the code below will guess.
+ It will doubtless be wrong on some systems.
+
+ HAVE_BSD_TTY -- Use the 4.2BSD tty routines
+ HAVE_SYSV_TERMIO -- Use the System V termio routines
+ HAVE_POSIX_TERMIOS -- Use the POSIX termios routines
+ */
+#define HAVE_BSD_TTY 0
+#define HAVE_SYSV_TERMIO 0
+#define HAVE_POSIX_TERMIOS 1
+
+/* This code tries to guess which terminal driver to use if you did
+ not make a choice above. It is in this file to make it easy to
+ figure out what's happening if something goes wrong. */
+
+#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS == 0
+#if HAVE_CBREAK
+#undef HAVE_BSD_TTY
+#define HAVE_BSD_TTY 1
+#else
+#undef HAVE_SYSV_TERMIO
+#define HAVE_SYSV_TERMIO 1
+#endif
+#endif
+
+/* On some systems a write to a serial port will block even if the
+ file descriptor has been set to not block. File transfer can be
+ more efficient if the package knows that a write to the serial port
+ will not block; however, if the write does block unexpectedly then
+ data loss is possible at high speeds.
+
+ If writes to a serial port always block even when requested not to,
+ you should set HAVE_UNBLOCKED_WRITES to 0; otherwise you should set
+ it to 1. In general on System V releases without STREAMS-based
+ ttys (e.g., before SVR4) HAVE_UNBLOCKED_WRITES should be 0 and on
+ BSD or SVR4 it should be 1.
+
+ If HAVE_UNBLOCKED_WRITES is set to 1 when it should be 0 you may
+ see an unexpectedly large number of transmission errors, or, if you
+ have hardware handshaking, transfer times may be lower than
+ expected (but then, they always are). If HAVE_UNBLOCKED_WRITES is
+ set to 0 when it should be 1, file transfer will use more CPU time
+ than necessary. If you are unsure, setting HAVE_UNBLOCKED_WRITES
+ to 0 should always be safe. */
+#define HAVE_UNBLOCKED_WRITES 1
+
+/* When the code does do a blocking write, it wants to write the
+ largest amount of data which the kernel will accept as a single
+ unit. On BSD this is typically the value of OBUFSIZ in
+ <sys/tty.h>, usually 100. On System V before SVR4 this is
+ typically the size of a clist, CLSIZE in <sys/tty.h>, which is
+ usually 64. On SVR4, which uses STREAMS-based ttys, 2048 is
+ reasonable. Define SINGLE_WRITE to the correct value for your
+ system. If SINGLE_WRITE is too large, data loss may occur. If
+ SINGLE_WRITE is too small, file transfer will use more CPU time
+ than necessary. If you have no idea, 64 should work on most modern
+ systems. */
+#define SINGLE_WRITE 100
+
+/* Some tty drivers, such as those from SCO and AT&T's Unix PC, have a
+ bug in the implementation of ioctl() that causes CLOCAL to be
+ ineffective until the port is opened a second time. If
+ HAVE_CLOCAL_BUG is set to 1, code will be added to do this second
+ open on the port. Set this if you are getting messages that say
+ "Line disconnected" while in the dial chat script after only
+ writing the first few characters to the port. This bug causes the
+ resetting of CLOCAL to have no effect, so the "\m" (require
+ carrier) escape sequence won't function properly in dialer chat
+ scripts. */
+#define HAVE_CLOCAL_BUG 0
+
+/* On some systems, such as SCO Xenix, resetting DTR on a port
+ apparently prevents getty from working on the port, and thus
+ prevents anybody from dialing in. If HAVE_RESET_BUG is set to 1,
+ DTR will not be reset when a serial port is closed. */
+#define HAVE_RESET_BUG 0
+
+/* The Sony NEWS reportedly handles no parity by clearing both the odd
+ and even parity bits in the sgtty structure, unlike most BSD based
+ systems in which no parity is indicated by setting both the odd and
+ even parity bits. Setting HAVE_PARITY_BUG to 1 will handle this
+ correctly. */
+#define HAVE_PARITY_BUG 0
+
+#if HAVE_BSD_TTY
+#ifdef sony
+#undef HAVE_PARITY_BUG
+#define HAVE_PARITY_BUG 1
+#endif
+#endif
+
+/* On Ultrix 4.0, at least, setting CBREAK causes input characters to
+ be stripped, regardless of the setting of LPASS8 and LLITOUT. This
+ can be worked around by using the termio call to reset ISTRIP.
+ This probably does not apply to any other operating system.
+ Setting HAVE_STRIP_BUG to 1 will use this workaround. */
+#define HAVE_STRIP_BUG 0
+
+#if HAVE_BSD_TTY
+#ifdef ultrix
+#undef HAVE_STRIP_BUG
+#define HAVE_STRIP_BUG 1
+#endif
+#endif
+
+/* TIMES_TICK is the fraction of a second which times(2) returns (for
+ example, if times returns 100ths of a second TIMES_TICK should be
+ set to 100). On a true POSIX system (one which has the sysconf
+ function and also has _SC_CLK_TCK defined in <unistd.h>) TIMES_TICK
+ may simply be left as 0. On some systems the environment variable
+ HZ is what you want for TIMES_TICK, but on some other systems HZ
+ has the wrong value; check the man page. If you leave this set to
+ 0, the code will try to guess; it will doubtless be wrong on some
+ non-POSIX systems. If TIMES_TICK is wrong the code may report
+ incorrect file transfer times in the statistics file, but on many
+ systems times(2) will actually not be used and this value will not
+ matter at all. */
+#define TIMES_TICK 0
+
+/* If your system does not support saved set user ID, set
+ HAVE_SAVED_SETUID to 0. However, this is ignored if your system
+ has the setreuid function. Most modern Unixes have one or the
+ other. If your system has the setreuid function, don't worry about
+ this define, or about the following discussion.
+
+ If you set HAVE_SAVED_SETUID to 0, you will not be able to use uucp
+ to transfer files that the uucp user can not read. Basically, you
+ will only be able to use uucp on world-readable files. If you set
+ HAVE_SAVED_SETUID to 1, but your system does not have saved set
+ user ID, uucp will fail with an error message whenever anybody
+ other than the uucp user uses it. */
+#define HAVE_SAVED_SETUID 1
+
+/* On some systems, such as the DG Aviion and, possibly, the RS/6000,
+ the setreuid function is broken. It should be possible to use
+ setreuid to swap the real and effective user ID's, but on some
+ systems it will not change the real user ID (I believe this is due
+ to a misreading of the POSIX standard). On such a system you must
+ set HAVE_BROKEN_SETREUID to 1; if you do not, you will get error
+ messages from setreuid. Systems on which setreuid exists but is
+ broken pretty much always have saved setuid. */
+#define HAVE_BROKEN_SETREUID 0
+
+/* On the 3B2, and possibly other systems, nap takes an argument in
+ hundredths of a second rather than milliseconds. I don't know of
+ any way to test for this. Set HAVE_HUNDREDTHS_NAP to 1 if this is
+ true on your system. This does not matter if your system does not
+ have the nap function. */
+#define HAVE_HUNDREDTHS_NAP 0
+
+/* Set PS_PROGRAM to the program to run to get a process status,
+ including the arguments to pass it. This is used by ``uustat -p''.
+ Set HAVE_PS_MULTIPLE to 1 if a comma separated list of process
+ numbers may be appended (e.g. ``ps -flp1,10,100''). Otherwise ps
+ will be invoked several times, with a single process number append
+ each time. The default definitions should work on most systems,
+ although some (such as the NeXT) will complain about the 'p'
+ option; for those, use the second set of definitions. The third
+ set of definitions are appropriate for System V. To use the second
+ or third set of definitions, change the ``#if 1'' to ``#if 0'' and
+ change the appropriate ``#if 0'' to ``#if 1''. */
+#if 1
+#define PS_PROGRAM "/bin/ps -lp"
+#define HAVE_PS_MULTIPLE 0
+#endif
+#if 0
+#define PS_PROGRAM "/bin/ps -l"
+#define HAVE_PS_MULTIPLE 0
+#endif
+#if 0
+#define PS_PROGRAM "/bin/ps -flp"
+#define HAVE_PS_MULTIPLE 1
+#endif
+
+/* If you use other programs that also lock devices, such as cu or
+ uugetty, the other programs and UUCP must agree on whether a device
+ is locked. This is typically done by creating a lock file in a
+ specific directory; the lock files are generally named
+ LCK..something or LK.something. If the LOCKDIR macro is defined,
+ these lock files will be placed in the named directory; otherwise
+ they will be placed in the default spool directory. On some HDB
+ systems the lock files are placed in /etc/locks. On some they are
+ placed in /usr/spool/locks. On the NeXT they are placed in
+ /usr/spool/uucp/LCK. */
+/* #define LOCKDIR "/usr/spool/uucp" */
+/* #define LOCKDIR "/etc/locks" */
+/* #define LOCKDIR "/usr/spool/locks" */
+/* #define LOCKDIR "/usr/spool/uucp/LCK" */
+#define LOCKDIR "/var/spool/lock"
+
+/* You must also specify the format of the lock files by setting
+ exactly one of the following macros to 1. Check an existing lock
+ file to decide which of these choices is more appropriate.
+
+ The HDB style is to write the locking process ID in ASCII, passed
+ to ten characters, followed by a newline.
+
+ The V2 style is to write the locking process ID as four binary
+ bytes in the host byte order. Many BSD derived systems use this
+ type of lock file, including the NeXT.
+
+ SCO lock files are similar to HDB lock files, but always lock the
+ lowercase version of the tty (i.e., LCK..tty2a is created if you
+ are locking tty2A). They are appropriate if you are using Taylor
+ UUCP on an SCO Unix, SCO Xenix, or SCO Open Desktop system.
+
+ SVR4 lock files are also similar to HDB lock files, but they use a
+ different naming convention. The filenames are LK.xxx.yyy.zzz,
+ where xxx is the major device number of the device holding the
+ special device file, yyy is the major device number of the port
+ device itself, and zzz is the minor device number of the port
+ device.
+
+ Coherent use a completely different method of terminal locking.
+ See unix/cohtty for details. For locks other than for terminals,
+ HDB type lock files are used. */
+#define HAVE_V2_LOCKFILES 0
+#define HAVE_HDB_LOCKFILES 1
+#define HAVE_SCO_LOCKFILES 0
+#define HAVE_SVR4_LOCKFILES 0
+#define HAVE_COHERENT_LOCKFILES 0
+
+/* If your system supports Internet mail addresses (which look like
+ user@host.domain rather than system!user), HAVE_INTERNET_MAIL
+ should be set to 1. This is checked by uuxqt when sending error
+ (or success, if requested) notifications to the person who
+ submitted the job. */
+#define HAVE_INTERNET_MAIL 1
+
+/* Adminstrative decisions. */
+
+/* Set USE_RCS_ID to 1 if you want the RCS ID strings compiled into
+ the executable. Leaving them out will decrease the executable
+ size. Leaving them in will make it easier to determine which
+ version you are running. */
+#define USE_RCS_ID 1
+
+/* DEBUG controls how much debugging information is compiled into the
+ code. If DEBUG is defined as 0, no sanity checks will be done and
+ no debugging messages will be compiled in. If DEBUG is defined as
+ 1 sanity checks will be done but there will still be no debugging
+ messages. If DEBUG is 2 than debugging messages will be compiled
+ in. When initially testing, DEBUG should be 2, and you should
+ probably leave it at 2 unless a small reduction in the executable
+ file size will be very helpful. */
+#define DEBUG 2
+
+/* Set the default grade to use for a uucp command if the -g option is
+ not used. The grades, from highest to lowest, are 0 to 9, A to Z,
+ a to z. */
+#define BDEFAULT_UUCP_GRADE ('N')
+
+/* Set the default grade to use for a uux command if the -g option is
+ not used. */
+#define BDEFAULT_UUX_GRADE ('N')
+
+/* To compile in use of the new style of configuration files described
+ in the documentation, set HAVE_TAYLOR_CONFIG to 1. */
+#define HAVE_TAYLOR_CONFIG 1
+
+/* To compile in use of V2 style configuration files (L.sys, L-devices
+ and so on), set HAVE_V2_CONFIG to 1. To compile in use of HDB
+ style configuration files (Systems, Devices and so on) set
+ HAVE_HDB_CONFIG to 1. The files will be looked up in the
+ oldconfigdir directory as defined in the Makefile.
+
+ You may set any or all of HAVE_TAYLOR_CONFIG, HAVE_V2_CONFIG and
+ HAVE_HDB_CONFIG to 1 (you must set at least one of the macros).
+ When looking something up (a system, a port, etc.) the new style
+ configuration files will be read first, followed by the V2
+ configuration files, followed by the HDB configuration files. */
+#define HAVE_V2_CONFIG 0
+#define HAVE_HDB_CONFIG 0
+
+/* Exactly one of the following macros must be set to 1. The exact
+ format of the spool directories is explained in unix/spool.c.
+
+ SPOOLDIR_V2 -- Use a Version 2 (original UUCP) style spool directory
+ SPOOLDIR_BSD42 -- Use a BSD 4.2 style spool directory
+ SPOOLDIR_BSD43 -- Use a BSD 4.3 style spool directory
+ SPOOLDIR_HDB -- Use a HDB (BNU) style spool directory
+ SPOOLDIR_ULTRIX -- Use an Ultrix style spool directory
+ SPOOLDIR_SVR4 -- Use a System V Release 4 spool directory
+ SPOOLDIR_TAYLOR -- Use a new style spool directory
+
+ If you are not worried about compatibility with a currently running
+ UUCP, use SPOOLDIR_TAYLOR. */
+#define SPOOLDIR_V2 0
+#define SPOOLDIR_BSD42 0
+#define SPOOLDIR_BSD43 0
+#define SPOOLDIR_HDB 0
+#define SPOOLDIR_ULTRIX 0
+#define SPOOLDIR_SVR4 0
+#define SPOOLDIR_TAYLOR 1
+
+/* You must select which type of logging you want by setting exactly
+ one of the following to 1. These control output to the log file
+ and to the statistics file.
+
+ If you define HAVE_TAYLOR_LOGGING, each line in the log file will
+ look something like this:
+
+ uucico uunet uucp (1991-12-10 09:04:34.45 16390) Receiving uunet/D./D.uunetSwJ72
+
+ and each line in the statistics file will look something like this:
+
+ uucp uunet (1991-12-10 09:04:40.20) received 2371 bytes in 5 seconds (474 bytes/sec)
+
+ If you define HAVE_V2_LOGGING, each line in the log file will look
+ something like this:
+
+ uucico uunet uucp (12/10-09:04 16390) Receiving uunet/D./D.uunetSwJ72
+
+ and each line in the statistics file will look something like this:
+
+ uucp uunet (12/10-09:04 16390) (692373862) received data 2371 bytes 5 seconds
+
+ If you define HAVE_HDB_LOGGING, each program will by default use a
+ separate log file. For uucico talking to uunet, for example, it
+ will be /usr/spool/uucp/.Log/uucico/uunet. Each line will look
+ something like this:
+
+ uucp uunet (12/10-09:04:22,16390,1) Receiving uunet/D./D.uunetSwJ72
+
+ and each line in the statistics file will look something like this:
+
+ uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, 474 bytes/sec
+
+ The main reason to prefer one format over another is that you may
+ have shell scripts which expect the files to have a particular
+ format. If you have none, choose whichever format you find more
+ appealing. */
+#define HAVE_TAYLOR_LOGGING 1
+#define HAVE_V2_LOGGING 0
+#define HAVE_HDB_LOGGING 0
+
+/* If you would like the log, debugging and statistics files to be
+ closed after each message, set CLOSE_LOGFILES to 1. This will
+ permit the log files to be easily moved. If a log file does not
+ exist when a new message is written out, it will be created.
+ Setting CLOSE_LOGFILES to 1 will obviously require slightly more
+ processing time. */
+#define CLOSE_LOGFILES 0
+
+/* The name of the default spool directory. If HAVE_TAYLOR_CONFIG is
+ set to 1, this may be overridden by the ``spool'' command in the
+ configuration file. */
+#define SPOOLDIR "/var/spool/uucp"
+
+/* The name of the default public directory. If HAVE_TAYLOR_CONFIG is
+ set to 1, this may be overridden by the ``pubdir'' command in the
+ configuration file. Also, a particular system may be given a
+ specific public directory by using the ``pubdir'' command in the
+ system file. */
+#define PUBDIR "/var/spool/uucppublic"
+
+/* The default command path. This is a space separated list of
+ directories. Remote command executions requested by uux are looked
+ up using this path. If you are using HAVE_TAYLOR_CONFIG, the
+ command path may be overridden for a particular system. For most
+ systems, you should just make sure that the programs rmail and
+ rnews can be found using this path. */
+#define CMDPATH "/bin /usr/bin /usr/local/bin"
+
+/* The default amount of free space to require for systems that do not
+ specify an amount with the ``free-space'' command. This is only
+ used when talking to another instance of Taylor UUCP; if accepting
+ a file would not leave at least this many bytes free on the disk,
+ it will be refused. */
+#define DEFAULT_FREE_SPACE (50000)
+
+/* While a file is being received, Taylor UUCP will periodically check
+ to see if there is enough free space remaining on the disk. If
+ there is not enough space available on the disk (as determined by
+ DEFAULT_FREE_SPACE, above, or the ``free-space'' command for the
+ system) the communication will be aborted. The disk will be
+ checked each time FREE_SPACE_DELTA bytes are received. Lower
+ values of FREE_SPACE_DELTA are less likely to fill up the disk, but
+ will also waste more time checking the amount of free space. To
+ avoid checking the disk while the file is being received, set
+ FREE_SPACE_DELTA to 0. */
+#define FREE_SPACE_DELTA (10240)
+
+/* It is possible for an execute job to request to be executed using
+ sh(1), rather than execve(2). This is such a security risk, it is
+ being disabled by default; to allow such jobs, set the following
+ macro to 1. */
+#define ALLOW_SH_EXECUTION 0
+
+/* If a command executed on behalf of a remote system takes a filename
+ as an argument, a security breach may be possible (note that on my
+ system neither of the default commands, rmail and rnews, take
+ filename arguments). If you set ALLOW_FILENAME_ARGUMENTS to 0, all
+ arguments to a command will be checked; if any argument
+ 1) starts with ../
+ 2) contains the string /../
+ 3) begins with a / but does not name a file that may be sent or
+ received (according to the specified ``remote-send'' and
+ ``remote-receive'')
+ the command will be rejected. By default, any argument is
+ permitted. */
+#define ALLOW_FILENAME_ARGUMENTS 1
+
+#if HAVE_TAYLOR_LOGGING
+
+/* The default log file when using HAVE_TAYLOR_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile''
+ command in the configuration file. */
+#define LOGFILE "/var/spool/uucp/Log"
+
+/* The default statistics file when using HAVE_TAYLOR_LOGGING. When
+ using HAVE_TAYLOR_CONFIG, this may be overridden by the
+ ``statfile'' command in the configuration file. */
+#define STATFILE "/var/spool/uucp/Stats"
+
+/* The default debugging file when using HAVE_TAYLOR_LOGGING. When
+ using HAVE_TAYLOR_CONFIG, this may be overridden by the
+ ``debugfile'' command in the configuration file. */
+#define DEBUGFILE "/var/spool/uucp/Debug"
+
+#endif /* HAVE_TAYLOR_LOGGING */
+
+#if HAVE_V2_LOGGING
+
+/* The default log file when using HAVE_V2_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile''
+ command in the configuration file. */
+#define LOGFILE "/var/spool/uucp/LOGFILE"
+
+/* The default statistics file when using HAVE_V2_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile''
+ command in the configuration file. */
+#define STATFILE "/var/spool/uucp/SYSLOG"
+
+/* The default debugging file when using HAVE_V2_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile''
+ command in the configuration file. */
+#define DEBUGFILE "/var/spool/uucp/DEBUG"
+
+#endif /* HAVE_V2_LOGGING */
+
+#if HAVE_HDB_LOGGING
+
+/* The default log file when using HAVE_HDB_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``logfile''
+ command in the configuration file. The first %s in the string will
+ be replaced by the program name (e.g. uucico); the second %s will
+ be replaced by the system name (if there is no appropriate system,
+ "ANY" will be used). No other '%' character may appear in the
+ string. */
+#define LOGFILE "/var/spool/uucp/.Log/%s/%s"
+
+/* The default statistics file when using HAVE_HDB_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``statfile''
+ command in the configuration file. */
+#define STATFILE "/var/spool/uucp/.Admin/xferstats"
+
+/* The default debugging file when using HAVE_HDB_LOGGING. When using
+ HAVE_TAYLOR_CONFIG, this may be overridden by the ``debugfile''
+ command in the configuration file. */
+#define DEBUGFILE "/var/spool/uucp/.Admin/audit.local"
+
+#endif /* HAVE_HDB_LOGGING */
diff --git a/gnu/libexec/uucp/common_sources/prot.c b/gnu/libexec/uucp/common_sources/prot.c
new file mode 100644
index 00000000000..4cc224ef0f9
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/prot.c
@@ -0,0 +1,237 @@
+/* prot.c
+ Protocol support routines to move commands and data around.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char prot_rcsid[] = "$Id: prot.c,v 1.1 1993/08/04 19:30:55 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+#include "uudefs.h"
+#include "system.h"
+#include "conn.h"
+#include "prot.h"
+
+/* Variables visible to the protocol-specific routines. */
+
+/* Buffer to hold received data. */
+char abPrecbuf[CRECBUFLEN];
+
+/* Index of start of data in abPrecbuf. */
+int iPrecstart;
+
+/* Index of end of data (first byte not included in data) in abPrecbuf. */
+int iPrecend;
+
+/* We want to output and input at the same time, if supported on this
+ machine. If we have something to send, we send it all while
+ accepting a large amount of data. Once we have sent everything we
+ look at whatever we have received. If data comes in faster than we
+ can send it, we may run out of buffer space. */
+
+boolean
+fsend_data (qconn, zsend, csend, fdoread)
+ struct sconnection *qconn;
+ const char *zsend;
+ size_t csend;
+ boolean fdoread;
+{
+ if (! fdoread)
+ return fconn_write (qconn, zsend, csend);
+
+ while (csend > 0)
+ {
+ size_t crec, csent;
+
+ if (iPrecend < iPrecstart)
+ crec = iPrecstart - iPrecend - 1;
+ else
+ {
+ crec = CRECBUFLEN - iPrecend;
+ if (iPrecstart == 0)
+ --crec;
+ }
+
+ csent = csend;
+
+ if (! fconn_io (qconn, zsend, &csent, abPrecbuf + iPrecend, &crec))
+ return FALSE;
+
+ csend -= csent;
+ zsend += csent;
+
+ iPrecend = (iPrecend + crec) % CRECBUFLEN;
+ }
+
+ return TRUE;
+}
+
+/* Read data from the other system when we have nothing to send. The
+ argument cneed is the amount of data the caller wants, and ctimeout
+ is the timeout in seconds. The function sets *pcrec to the amount
+ of data which was actually received, which may be less than cneed
+ if there isn't enough room in the receive buffer. If no data is
+ received before the timeout expires, *pcrec will be returned as 0.
+ If an error occurs, the function returns FALSE. If the freport
+ argument is FALSE, no error should be reported. */
+
+boolean
+freceive_data (qconn, cneed, pcrec, ctimeout, freport)
+ struct sconnection *qconn;
+ size_t cneed;
+ size_t *pcrec;
+ int ctimeout;
+ boolean freport;
+{
+ /* Set *pcrec to the maximum amount of data we can read. fconn_read
+ expects *pcrec to be the buffer size, and sets it to the amount
+ actually received. */
+ if (iPrecend < iPrecstart)
+ *pcrec = iPrecstart - iPrecend - 1;
+ else
+ {
+ *pcrec = CRECBUFLEN - iPrecend;
+ if (iPrecstart == 0)
+ --(*pcrec);
+ }
+
+#if DEBUG > 0
+ /* If we have no room in the buffer, we're in trouble. The
+ protocols must be written to ensure that this can't happen. */
+ if (*pcrec == 0)
+ ulog (LOG_FATAL, "freceive_data: No room in buffer");
+#endif
+
+ /* If we don't have room for all the data the caller wants, we
+ simply have to expect less. We'll get the rest later. */
+ if (*pcrec < cneed)
+ cneed = *pcrec;
+
+ if (! fconn_read (qconn, abPrecbuf + iPrecend, pcrec, cneed, ctimeout,
+ freport))
+ return FALSE;
+
+ iPrecend = (iPrecend + *pcrec) % CRECBUFLEN;
+
+ return TRUE;
+}
+
+/* Read a single character. Get it out of the receive buffer if it's
+ there, otherwise ask freceive_data for at least one character.
+ This is used because as a protocol is shutting down freceive_data
+ may read ahead and eat characters that should be read outside the
+ protocol routines. We call freceive_data rather than fconn_read
+ with an argument of 1 so that we can get all the available data in
+ a single system call. The ctimeout argument is the timeout in
+ seconds; the freport argument is FALSE if no error should be
+ reported. This returns a character, or -1 on timeout or -2 on
+ error. */
+
+int
+breceive_char (qconn, ctimeout, freport)
+ struct sconnection *qconn;
+ int ctimeout;
+ boolean freport;
+{
+ char b;
+
+ if (iPrecstart == iPrecend)
+ {
+ size_t crec;
+
+ if (! freceive_data (qconn, sizeof (char), &crec, ctimeout, freport))
+ return -2;
+ if (crec == 0)
+ return -1;
+ }
+
+ b = abPrecbuf[iPrecstart];
+ iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
+ return BUCHAR (b);
+}
+
+/* Send mail about a file transfer. We send to the given mailing
+ address if there is one, otherwise to the user. */
+
+boolean
+fmail_transfer (fsuccess, zuser, zmail, zwhy, zfromfile, zfromsys,
+ ztofile, ztosys, zsaved)
+ boolean fsuccess;
+ const char *zuser;
+ const char *zmail;
+ const char *zwhy;
+ const char *zfromfile;
+ const char *zfromsys;
+ const char *ztofile;
+ const char *ztosys;
+ const char *zsaved;
+{
+ const char *zsendto;
+ const char *az[20];
+ int i;
+
+ if (zmail != NULL && *zmail != '\0')
+ zsendto = zmail;
+ else
+ zsendto = zuser;
+
+ i = 0;
+ az[i++] = "The file\n\t";
+ if (zfromsys != NULL)
+ {
+ az[i++] = zfromsys;
+ az[i++] = "!";
+ }
+ az[i++] = zfromfile;
+ if (fsuccess)
+ az[i++] = "\nwas successfully transferred to\n\t";
+ else
+ az[i++] = "\ncould not be transferred to\n\t";
+ if (ztosys != NULL)
+ {
+ az[i++] = ztosys;
+ az[i++] = "!";
+ }
+ az[i++] = ztofile;
+ az[i++] = "\nas requested by\n\t";
+ az[i++] = zuser;
+ if (! fsuccess)
+ {
+ az[i++] = "\nfor the following reason:\n\t";
+ az[i++] = zwhy;
+ az[i++] = "\n";
+ }
+ if (zsaved != NULL)
+ {
+ az[i++] = zsaved;
+ az[i++] = "\n";
+ }
+
+ return fsysdep_mail (zsendto,
+ fsuccess ? "UUCP succeeded" : "UUCP failed",
+ i, az);
+}
diff --git a/gnu/libexec/uucp/common_sources/prot.h b/gnu/libexec/uucp/common_sources/prot.h
new file mode 100644
index 00000000000..4e2bb584d84
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/prot.h
@@ -0,0 +1,250 @@
+/* prot.h
+ Protocol header file.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* We need the definition of uuconf_cmdtab to declare the protocol
+ parameter arrays. */
+#ifndef UUCONF_H
+#include "uuconf.h"
+#endif
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct sdaemon;
+struct sconnection;
+struct stransfer;
+#endif
+
+/* The sprotocol structure holds information and functions for a specific
+ protocol (e.g. the 'g' protocol). */
+
+struct sprotocol
+{
+ /* The name of the protocol (e.g. 'g'). */
+ char bname;
+ /* Reliability requirements, an or of UUCONF_RELIABLE_xxx defines
+ from uuconf.h. */
+ int ireliable;
+ /* The maximum number of channels this protocol can support. */
+ int cchans;
+ /* Protocol parameter commands. */
+ struct uuconf_cmdtab *qcmds;
+ /* A routine to start the protocol. If *pzlog is set to be
+ non-NULL, it is an informative message to be logged; it should
+ then be passed to ubuffree. */
+ boolean (*pfstart) P((struct sdaemon *qdaemon, char **pzlog));
+ /* Shutdown the protocol. */
+ boolean (*pfshutdown) P((struct sdaemon *qdaemon));
+ /* Send a command to the other side. */
+ boolean (*pfsendcmd) P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+ /* Get buffer to space to fill with data. This should set *pcdata
+ to the amount of data desired. */
+ char *(*pzgetspace) P((struct sdaemon *qdaemon, size_t *pcdata));
+ /* Send data to the other side. The argument z must be a return
+ value of pzgetspace. The ipos argument is the file position, and
+ is ignored by most protocols. */
+ boolean (*pfsenddata) P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+ /* Wait for data to come in and call fgot_data with it until
+ fgot_data sets *pfexit. */
+ boolean (*pfwait) P((struct sdaemon *qdaemon));
+ /* Handle any file level actions that need to be taken. If a file
+ transfer is starting rather than ending, fstart is TRUE. If the
+ file is being sent rather than received, fsend is TRUE. If
+ fstart and fsend are both TRUE, cbytes holds the size of the
+ file. If *pfhandled is set to TRUE, then the protocol routine
+ has taken care of queueing up qtrans for the next action. */
+ boolean (*pffile) P((struct sdaemon *qdaemon, struct stransfer *qtrans,
+ boolean fstart, boolean fsend, long cbytes,
+ boolean *pfhandled));
+};
+
+/* Send data to the other system. If the fread argument is TRUE, this
+ will also receive data into the receive buffer abPrecbuf; fread is
+ passed as TRUE if the protocol expects data to be coming back, to
+ make sure the input buffer does not fill up. Returns FALSE on
+ error. */
+extern boolean fsend_data P((struct sconnection *qconn,
+ const char *zsend, size_t csend,
+ boolean fdoread));
+
+/* Receive data from the other system when there is no data to send.
+ The cneed argument is the amount of data desired and the ctimeout
+ argument is the timeout in seconds. This will set *pcrec to the
+ amount of data received. It will return FALSE on error. If a
+ timeout occurs, it will return TRUE with *pcrec set to zero. */
+extern boolean freceive_data P((struct sconnection *qconn, size_t cneed,
+ size_t *pcrec, int ctimeout,
+ boolean freport));
+
+/* Get one character from the remote system, going through the
+ procotol buffering. The ctimeout argument is the timeout in
+ seconds, and the freport argument is TRUE if errors should be
+ reported (when closing a connection it is pointless to report
+ errors). This returns a character or -1 on a timeout or -2 on an
+ error. */
+extern int breceive_char P((struct sconnection *qconn,
+ int ctimeout, boolean freport));
+
+/* Compute a 32 bit CRC of a data buffer, given an initial CRC. */
+extern unsigned long icrc P((const char *z, size_t c, unsigned long ick));
+
+/* The initial CRC value to use for a new buffer. */
+#if ANSI_C
+#define ICRCINIT (0xffffffffUL)
+#else
+#define ICRCINIT ((unsigned long) 0xffffffffL)
+#endif
+
+/* The size of the receive buffer. */
+#define CRECBUFLEN (16384)
+
+/* Buffer to hold received data. */
+extern char abPrecbuf[CRECBUFLEN];
+
+/* Index of start of data in abPrecbuf. */
+extern int iPrecstart;
+
+/* Index of end of data (first byte not included in data) in abPrecbuf. */
+extern int iPrecend;
+
+/* There are a couple of variables and functions that are shared by
+ the 'i' and 'j' protocols (the 'j' protocol is just a wrapper
+ around the 'i' protocol). These belong in a separate header file,
+ protij.h, but I don't want to create one for just a couple of
+ things. */
+
+/* An escape sequence of characters for the 'j' protocol to avoid
+ (protocol parameter ``avoid''). */
+extern const char *zJavoid_parameter;
+
+/* Timeout to use when sending the 'i' protocol SYNC packet (protocol
+ parameter ``sync-timeout''). */
+extern int cIsync_timeout;
+
+/* Shared startup routine for the 'i' and 'j' protocols. */
+extern boolean fijstart P((struct sdaemon *qdaemon, char **pzlog,
+ int imaxpacksize,
+ boolean (*pfsend) P((struct sconnection *qconn,
+ const char *zsend,
+ size_t csend,
+ boolean fdoread)),
+ boolean (*pfreceive) P((struct sconnection *qconn,
+ size_t cneed,
+ size_t *pcrec,
+ int ctimeout,
+ boolean freport))));
+
+/* Prototypes for 'g' protocol functions. */
+
+extern struct uuconf_cmdtab asGproto_params[];
+extern boolean fgstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fbiggstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fgshutdown P((struct sdaemon *qdaemon));
+extern boolean fgsendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *zggetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean fgsenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean fgwait P((struct sdaemon *qdaemon));
+
+/* Prototypes for 'f' protocol functions. */
+
+extern struct uuconf_cmdtab asFproto_params[];
+extern boolean ffstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean ffshutdown P((struct sdaemon *qdaemon));
+extern boolean ffsendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *zfgetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean ffsenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean ffwait P((struct sdaemon *qdaemon));
+extern boolean fffile P((struct sdaemon *qdaemon, struct stransfer *qtrans,
+ boolean fstart, boolean fsend, long cbytes,
+ boolean *pfhandled));
+
+/* Prototypes for 't' protocol functions. */
+
+extern struct uuconf_cmdtab asTproto_params[];
+extern boolean ftstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean ftshutdown P((struct sdaemon *qdaemon));
+extern boolean ftsendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *ztgetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean ftsenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean ftwait P((struct sdaemon *qdaemon));
+extern boolean ftfile P((struct sdaemon *qdaemon, struct stransfer *qtrans,
+ boolean fstart, boolean fsend, long cbytes,
+ boolean *pfhandled));
+
+/* Prototypes for 'e' protocol functions. */
+
+extern struct uuconf_cmdtab asEproto_params[];
+extern boolean festart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean feshutdown P((struct sdaemon *qdaemon));
+extern boolean fesendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *zegetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean fesenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean fewait P((struct sdaemon *qdaemon));
+extern boolean fefile P((struct sdaemon *qdaemon, struct stransfer *qtrans,
+ boolean fstart, boolean fsend, long cbytes,
+ boolean *pfhandled));
+
+/* Prototypes for 'i' protocol functions. */
+
+extern struct uuconf_cmdtab asIproto_params[];
+extern boolean fistart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fishutdown P((struct sdaemon *qdaemon));
+extern boolean fisendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *zigetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean fisenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean fiwait P((struct sdaemon *qdaemon));
+
+/* Prototypes for 'j' protocol functions. The 'j' protocol mostly
+ uses the 'i' protocol functions, but it has a couple of functions
+ of its own. */
+extern boolean fjstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fjshutdown P((struct sdaemon *qdaemon));
+
+/* Prototypes for 'a' protocol functions (these use 'z' as the second
+ character because 'a' is a modified Zmodem protocol). */
+extern struct uuconf_cmdtab asZproto_params[];
+extern boolean fzstart P((struct sdaemon *qdaemon, char **pzlog));
+extern boolean fzshutdown P((struct sdaemon *qdaemon));
+extern boolean fzsendcmd P((struct sdaemon *qdaemon, const char *z,
+ int ilocal, int iremote));
+extern char *zzgetspace P((struct sdaemon *qdaemon, size_t *pcdata));
+extern boolean fzsenddata P((struct sdaemon *qdaemon, char *z, size_t c,
+ int ilocal, int iremote, long ipos));
+extern boolean fzwait P((struct sdaemon *qdaemon));
+extern boolean fzfile P((struct sdaemon *qdaemon, struct stransfer *qtrans,
+ boolean fstart, boolean fsend, long cbytes,
+ boolean *pfhandled));
diff --git a/gnu/libexec/uucp/common_sources/sysdep.h b/gnu/libexec/uucp/common_sources/sysdep.h
new file mode 100644
index 00000000000..47675ac2385
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/sysdep.h
@@ -0,0 +1,530 @@
+/* sysh.unx -*- C -*-
+ The header file for the UNIX system dependent routines.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef SYSH_UNX_H
+
+#define SYSH_UNX_H
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct uuconf_system;
+struct sconnection;
+#endif
+
+/* Make sure the defines do not conflict. These are in this file
+ because they are Unix dependent. */
+#if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_COHERENT_LOCKFILES != 1
+ #error LOCKFILES define not set or duplicated
+#endif
+
+/* SCO and SVR4 lockfiles are basically just like HDB lockfiles. */
+#if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES
+#undef HAVE_HDB_LOCKFILES
+#define HAVE_HDB_LOCKFILES 1
+#endif
+
+#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS != 1
+ #error Terminal driver define not set or duplicated
+#endif
+
+#if SPOOLDIR_V2 + SPOOLDIR_BSD42 + SPOOLDIR_BSD43 + SPOOLDIR_HDB + SPOOLDIR_ULTRIX + SPOOLDIR_SVR4 + SPOOLDIR_TAYLOR != 1
+ #error Spool directory define not set or duplicated
+#endif
+
+/* If setreuid is broken, don't use it. */
+#if HAVE_BROKEN_SETREUID
+#undef HAVE_SETREUID
+#define HAVE_SETREUID 0
+#endif
+
+/* Get some standard types from the configuration header file. */
+#ifdef PID_T
+typedef PID_T pid_t;
+#endif
+
+#ifdef UID_T
+typedef UID_T uid_t;
+#endif
+
+#ifdef GID_T
+typedef GID_T gid_t;
+#endif
+
+#ifdef OFF_T
+typedef OFF_T off_t;
+#endif
+
+/* On Unix, binary files are the same as text files. */
+#define BINREAD "r"
+#define BINWRITE "w"
+
+/* If we have sigaction, we can force system calls to not be
+ restarted. */
+#if HAVE_SIGACTION
+#undef HAVE_RESTARTABLE_SYSCALLS
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+
+/* If we have sigvec, and we have HAVE_SIGVEC_SV_FLAGS, and
+ SV_INTERRUPT is defined, we can force system calls to not be
+ restarted (signal.h is included by uucp.h before this point, so
+ SV_INTERRUPT will be defined by now if it it ever is). */
+#if HAVE_SIGVEC && HAVE_SIGVEC_SV_FLAGS
+#ifdef SV_INTERRUPT
+#undef HAVE_RESTARTABLE_SYSCALLS
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+#endif
+
+/* If we were cross-configured, we will have a value of -1 for
+ HAVE_RESTARTABLE_SYSCALLS. In this case, we try to guess what the
+ correct value should be. Yuck. If we have sigvec, but neither of
+ the above cases applied (which we know because they would have
+ changed HAVE_RESTARTABLE_SYSCALLS) then we are probably on 4.2BSD
+ and system calls are automatically restarted. Otherwise, assume
+ that they are not. */
+#if HAVE_RESTARTABLE_SYSCALLS == -1
+#undef HAVE_RESTARTABLE_SYSCALLS
+#if HAVE_SIGVEC
+#define HAVE_RESTARTABLE_SYSCALLS 1
+#else
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+#endif /* HAVE_RESTARTABLE_SYSCALLS == -1 */
+
+/* We don't handle sigset in combination with restartable system
+ calls, so we check for it although this combination will never
+ happen. */
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && HAVE_SIGSET
+#if HAVE_RESTARTABLE_SYSCALLS
+#undef HAVE_SIGSET
+#define HAVE_SIGSET 0
+#endif
+#endif
+
+/* If we don't have restartable system calls, we can ignore
+ fsysdep_catch, usysdep_start_catch and usysdep_end_catch.
+ Otherwise fsysdep_catch has to do a setjmp. */
+
+#if ! HAVE_RESTARTABLE_SYSCALLS
+
+#define fsysdep_catch() (TRUE)
+#define usysdep_start_catch()
+#define usysdep_end_catch()
+#define CATCH_PROTECT
+
+#else /* HAVE_RESTARTABLE_SYSCALLS */
+
+#if HAVE_SETRET && ! HAVE_SIGSETJMP
+#include <setret.h>
+#define setjmp setret
+#define longjmp longret
+#define jmp_buf ret_buf
+#else /* ! HAVE_SETRET || HAVE_SIGSETJMP */
+#include <setjmp.h>
+#if HAVE_SIGSETJMP
+#undef setjmp
+#undef longjmp
+#undef jmp_buf
+#define setjmp(s) sigsetjmp ((s), TRUE)
+#define longjmp siglongjmp
+#define jmp_buf sigjmp_buf
+#endif /* HAVE_SIGSETJMP */
+#endif /* ! HAVE_SETRET || HAVE_SIGSETJMP */
+
+extern volatile sig_atomic_t fSjmp;
+extern volatile jmp_buf sSjmp_buf;
+
+#define fsysdep_catch() (setjmp (sSjmp_buf) == 0)
+
+#define usysdep_start_catch() (fSjmp = TRUE)
+
+#define usysdep_end_catch() (fSjmp = FALSE)
+
+#define CATCH_PROTECT volatile
+
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+
+/* Get definitions for the terminal driver. */
+
+#if HAVE_BSD_TTY
+#include <sgtty.h>
+struct sbsd_terminal
+{
+ struct sgttyb stty;
+ struct tchars stchars;
+ struct ltchars sltchars;
+};
+typedef struct sbsd_terminal sterminal;
+#define fgetterminfo(o, q) \
+ (ioctl ((o), TIOCGETP, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCGETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCGLTC, &(q)->sltchars) == 0)
+#define fsetterminfo(o, q) \
+ (ioctl ((o), TIOCSETN, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0)
+#define fsetterminfodrain(o, q) \
+ (ioctl ((o), TIOCSETP, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0)
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+#include <termio.h>
+typedef struct termio sterminal;
+#define fgetterminfo(o, q) (ioctl ((o), TCGETA, (q)) == 0)
+#define fsetterminfo(o, q) (ioctl ((o), TCSETA, (q)) == 0)
+#define fsetterminfodrain(o, q) (ioctl ((o), TCSETAW, (q)) == 0)
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+#include <termios.h>
+typedef struct termios sterminal;
+#define fgetterminfo(o, q) (tcgetattr ((o), (q)) == 0)
+#define fsetterminfo(o, q) (tcsetattr ((o), TCSANOW, (q)) == 0)
+#define fsetterminfodrain(o, q) (tcsetattr ((o), TCSADRAIN, (q)) == 0)
+
+/* On some systems it is not possible to include both <sys/ioctl.h>
+ and <termios.h> in the same source files; I don't really know why.
+ On such systems, we pretend that we don't have <sys/ioctl.h>. */
+#if ! HAVE_TERMIOS_AND_SYS_IOCTL_H
+#undef HAVE_SYS_IOCTL_H
+#define HAVE_SYS_IOCTL_H 0
+#endif
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+/* The root directory (this is needed by the system independent stuff
+ as the default for local-send). */
+#define ZROOTDIR "/"
+
+/* The name of the execution directory within the spool directory
+ (this is need by the system independent uuxqt.c). */
+#define XQTDIR ".Xqtdir"
+
+/* The name of the directory in which we preserve file transfers that
+ failed. */
+#define PRESERVEDIR ".Preserve"
+
+/* The length of the sequence number used in a file name. */
+#define CSEQLEN (4)
+
+/* Get some standard definitions. Avoid including the files more than
+ once--some might have been included by uucp.h. */
+#if USE_STDIO && HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if ! USE_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+
+/* Get definitions for the file permission bits. */
+
+#ifndef S_IRWXU
+#define S_IRWXU 0700
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 0200
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+
+#ifndef S_IRWXG
+#define S_IRWXG 0070
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0020
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+
+#ifndef S_IRWXO
+#define S_IRWXO 0007
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0002
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+#ifndef S_ISDIR
+#ifdef S_IFDIR
+#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
+#else /* ! defined (S_IFDIR) */
+#define S_ISDIR(i) (((i) & 0170000) == 040000)
+#endif /* ! defined (S_IFDIR) */
+#endif /* ! defined (S_ISDIR) */
+
+/* We need the access macros. */
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define F_OK 0
+#endif /* ! defined (R_OK) */
+
+/* We create files with these modes (should this be configurable?). */
+#define IPRIVATE_FILE_MODE (S_IRUSR | S_IWUSR)
+#define IPUBLIC_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+
+/* We create directories with this mode (should this be configurable?). */
+#define IDIRECTORY_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+#define IPUBLIC_DIRECTORY_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
+
+#if ! HAVE_OPENDIR
+
+/* Define some structures to use if we don't have opendir, etc. These
+ will only work if we have the old Unix filesystem, with a 2 byte
+ inode and a 14 byte filename. */
+
+#include <sys/dir.h>
+
+struct dirent
+{
+ char d_name[DIRSIZ + 1];
+};
+
+typedef struct
+{
+ int o;
+ struct dirent s;
+} DIR;
+
+extern DIR *opendir P((const char *zdir));
+extern struct dirent *readdir P((DIR *));
+extern int closedir P((DIR *));
+
+#endif /* ! HAVE_OPENDIR */
+
+#if ! HAVE_FTW_H
+
+/* If there is no <ftw.h>, define the ftw constants. */
+
+#define FTW_F (0)
+#define FTW_D (1)
+#define FTW_DNR (2)
+#define FTW_NS (3)
+
+#endif /* ! HAVE_FTW_H */
+
+/* This structure holds the system dependent information we keep for a
+ connection. This is used by the TCP and TLI code. */
+
+struct ssysdep_conn
+{
+ /* File descriptor. */
+ int o;
+ /* Device name. */
+ char *zdevice;
+ /* File status flags. */
+ int iflags;
+ /* File status flags for descriptor 1 (-1 if not standard input). */
+ int istdout_flags;
+ /* Hold the real descriptor when using a dialer device. */
+ int ohold;
+ /* TRUE if this is a terminal and the remaining fields are valid. */
+ boolean fterminal;
+ /* TRUE if this is a TLI descriptor. */
+ boolean ftli;
+ /* Baud rate. */
+ long ibaud;
+ /* Original terminal settings. */
+ sterminal sorig;
+ /* Current terminal settings. */
+ sterminal snew;
+#if HAVE_COHERENT_LOCKFILES
+ /* On Coherent we need to hold on to the real port name which will
+ be used to enable the port. Ick. */
+ char *zenable;
+#endif
+};
+
+/* These functions do I/O and chat scripts to a port. They are called
+ by the TCP and TLI routines. */
+extern boolean fsysdep_conn_read P((struct sconnection *qconn,
+ char *zbuf, size_t *pclen,
+ size_t cmin, int ctimeout,
+ boolean freport));
+extern boolean fsysdep_conn_write P((struct sconnection *qconn,
+ const char *zbuf, size_t clen));
+extern boolean fsysdep_conn_io P((struct sconnection *qconn,
+ const char *zwrite, size_t *pcwrite,
+ char *zread, size_t *pcread));
+extern boolean fsysdep_conn_chat P((struct sconnection *qconn,
+ char **pzprog));
+
+/* Set a signal handler. */
+extern void usset_signal P((int isig, RETSIGTYPE (*pfn) P((int)),
+ boolean fforce, boolean *pfignored));
+
+/* Default signal handler. This sets the appropriate element of the
+ afSignal array. If system calls are automatically restarted, it
+ may do a longjmp to an fsysdep_catch. */
+extern RETSIGTYPE ussignal P((int isig));
+
+/* Try to fork, repeating several times. */
+extern pid_t ixsfork P((void));
+
+/* Spawn a job. Returns the process ID of the spawned job or -1 on
+ error. The following macros may be passed in aidescs. */
+
+/* Set descriptor to /dev/null. */
+#define SPAWN_NULL (-1)
+/* Set element of aidescs to a pipe for caller to read from. */
+#define SPAWN_READ_PIPE (-2)
+/* Set element of aidescs to a pipe for caller to write to. */
+#define SPAWN_WRITE_PIPE (-3)
+
+extern pid_t ixsspawn P((const char **pazargs, int *aidescs,
+ boolean fkeepuid, boolean fkeepenv,
+ const char *zchdir, boolean fnosigs,
+ boolean fshell, const char *zpath,
+ const char *zuu_machine,
+ const char *zuu_user));
+
+/* Do a form of popen using ixsspawn. */
+extern FILE *espopen P((const char **pazargs, boolean frd,
+ pid_t *pipid));
+
+/* Wait for a particular process to finish, returning the exit status.
+ The process ID should be pid_t, but we can't put that in a
+ prototype. */
+extern int ixswait P((unsigned long ipid, const char *zreport));
+
+/* Find a spool file in the spool directory. For a local file, the
+ bgrade argument is the grade of the file. This is needed for
+ SPOOLDIR_SVR4. */
+extern char *zsfind_file P((const char *zsimple, const char *zsystem,
+ int bgrade));
+
+/* Return the grade given a sequence number. */
+extern char bsgrade P((pointer pseq));
+
+/* Lock a string. */
+extern boolean fsdo_lock P((const char *, boolean fspooldir,
+ boolean *pferr));
+
+/* Unlock a string. */
+extern boolean fsdo_unlock P((const char *, boolean fspooldir));
+
+/* Check access for a particular user name, or NULL to check access
+ for any user. */
+extern boolean fsuser_access P((const struct stat *, int imode,
+ const char *zuser));
+
+/* Stick two directories and a file name together. */
+extern char *zsappend3 P((const char *zdir1, const char *zdir2,
+ const char *zfile));
+
+/* Stick three directories and a file name together. */
+extern char *zsappend4 P((const char *zdir1, const char *zdir2,
+ const char *zdir3, const char *zfile));
+
+/* Get a temporary file name. */
+extern char *zstemp_file P((const struct uuconf_system *qsys));
+
+/* Get a command file name. */
+extern char *zscmd_file P((const struct uuconf_system *qsys, int bgrade));
+
+/* Get a jobid from a system, a file name, and a grade. */
+extern char *zsfile_to_jobid P((const struct uuconf_system *qsys,
+ const char *zfile,
+ int bgrade));
+
+/* Get a file name from a jobid. This also returns the associated system
+ in *pzsystem and the grade in *pbgrade. */
+extern char *zsjobid_to_file P((const char *zid, char **pzsystem,
+ char *pbgrade));
+
+/* See whether there is a spool directory for a system when using
+ SPOOLDIR_ULTRIX. */
+extern boolean fsultrix_has_spool P((const char *zsystem));
+
+#if HAVE_COHERENT_LOCKFILES
+/* Lock a coherent tty. */
+extern boolean lockttyexist P((const char *z));
+extern boolean fscoherent_disable_tty P((const char *zdevice,
+ char **pzenable));
+#endif
+
+/* Some replacements for standard Unix functions. */
+
+#if ! HAVE_DUP2
+extern int dup2 P((int oold, int onew));
+#endif
+
+#if ! HAVE_FTW
+extern int ftw P((const char *zdir,
+ int (*pfn) P((const char *zfile,
+ const struct stat *qstat,
+ int iflag)),
+ int cdescriptors));
+#endif
+
+#if ! HAVE_GETCWD && ! HAVE_GETWD
+extern char *getcwd P((char *zbuf, size_t cbuf));
+#endif
+
+#if ! HAVE_MKDIR
+extern int mkdir P((const char *zdir, int imode));
+#endif
+
+#if ! HAVE_RENAME
+extern int rename P((const char *zold, const char *znew));
+#endif
+
+#if ! HAVE_RMDIR
+extern int rmdir P((const char *zdir));
+#endif
+
+/* The working directory from which the program was run (this is set
+ by usysdep_initialize if called with INIT_GETCWD). */
+extern char *zScwd;
+
+/* The spool directory name. */
+extern const char *zSspooldir;
+
+/* The lock directory name. */
+extern const char *zSlockdir;
+
+/* The local UUCP name (needed for some spool directory stuff). */
+extern const char *zSlocalname;
+
+#endif /* ! defined (SYSH_UNX_H) */
diff --git a/gnu/libexec/uucp/common_sources/system.h b/gnu/libexec/uucp/common_sources/system.h
new file mode 100644
index 00000000000..aa9d2a41a45
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/system.h
@@ -0,0 +1,950 @@
+/* system.h
+ Header file for system dependent stuff in the Taylor UUCP package.
+ This file is not itself system dependent.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef SYSTEM_H
+
+#define SYSTEM_H
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct tm;
+struct uuconf_system;
+struct uuconf_port;
+struct sconnection;
+struct sstatus;
+struct scmd;
+#endif
+
+/* Any function which returns an error should also report an error
+ message, unless otherwise indicated.
+
+ Any function that returns a char *, rather than a const char *, is
+ returning a pointer to a buffer allocated by zbufalc which must be
+ freed using ubuffree, unless otherwise indicated. */
+
+/* The maximum length of a remote system name. */
+extern size_t cSysdep_max_name_len;
+
+/* Initialize. If something goes wrong, this routine should just
+ exit. The flag argument is 0, or a combination of any of the
+ following flags. */
+
+/* This program needs to know the current working directory. This is
+ used because on Unix it can be expensive to determine the current
+ working directory (some versions of getcwd fork a process), but in
+ most cases we don't need to know it. However, we are going to
+ chdir to the spool directory (unless INIT_CHDIR is set), so we have
+ to get the cwd now if we are ever going to get it. Both uucp and
+ uux use the function fsysdep_needs_cwd to determine whether they
+ will need the current working directory, and pass the argument to
+ usysdep_initialize appropriately. There's probably a cleaner way
+ to handle this, but this will suffice for now. */
+#define INIT_GETCWD (01)
+
+/* This program should not chdir to the spool directory. This may
+ only make sense on Unix. It is set by cu. */
+#define INIT_NOCHDIR (02)
+
+/* This program needs special access to the spool directories. That
+ means, on Unix, this program is normally installed setuid. */
+#define INIT_SUID (04)
+
+extern void usysdep_initialize P((pointer puuconf, int iflags));
+
+/* Exit the program. The fsuccess argument indicates whether to
+ return an indication of success or failure to the outer
+ environment. This routine should not return. */
+extern void usysdep_exit P((boolean fsuccess));
+
+/* Called when a non-standard configuration file is being used, to
+ avoid handing out privileged access. If it returns FALSE, default
+ configuration file will be used. This is called before the
+ usysdep_initialize function is called. */
+extern boolean fsysdep_other_config P((const char *));
+
+/* Detach from the controlling terminal. This probably only makes
+ sense on Unix. It is called by uucico to try to get the modem port
+ as a controlling terminal. It is also called by uucico before it
+ starts up uuxqt, so that uuxqt will be a complete daemon. */
+extern void usysdep_detach P((void));
+
+/* Get the local node name if it is not specified in the configuration
+ files. Returns NULL on error; otherwise the return value should
+ point to a static buffer. */
+extern const char *zsysdep_localname P((void));
+
+/* Get the login name. This is used when uucico is started up with no
+ arguments in slave mode, which causes it to assume that somebody
+ has logged in. It also used by uucp and uux for recording the user
+ name. This may not return NULL. The return value should point to
+ a static buffer. */
+extern const char *zsysdep_login_name P((void));
+
+/* Set a signal handler for a signal. If the signal occurs, the
+ appropriate element of afSignal should be set to the signal number
+ (see the declaration of afSignal in uucp.h). This routine might be
+ able to just use signal, but Unix requires more complex handling.
+ This is called before usysdep_initialize. */
+extern void usysdep_signal P((int isig));
+
+/* Catch a signal. This is actually defined as a macro in the system
+ dependent header file, and the prototype here just indicates how it
+ should be called. It is called before a routine which must exit if
+ a signal occurs, and is expected to set do a setjmp (which is why
+ it must be a macro). It is actually only called in one place in
+ the system independent code, before the call to read stdin in uux.
+ This is needed to handle 4.2 BSD restartable system calls, which
+ require a longjmp. On systems which don't need to do
+ setjmp/longjmp around system calls, this can be redefined in
+ sysdep.h to TRUE. It should return TRUE if the routine should
+ proceed, or FALSE if a signal occurred. After having this return
+ TRUE, usysdep_start_catch should be used to start catching the
+ signal; this basically tells the signal handler that it's OK to do
+ the longjmp, if fsysdep_catch did not already do so. */
+#ifndef fsysdep_catch
+extern boolean fsysdep_catch P((void));
+#endif
+
+/* Start catching a signal. This is called after fsysdep_catch to
+ tell the signal handler to go ahead and do the longjmp. This may
+ be implemented as a macro in sysdep.h. */
+#ifndef usysdep_start_catch
+extern void usysdep_start_catch P((void));
+#endif
+
+/* Stop catching a signal. This is called when it is no longer
+ necessary for fsysdep_catch to handle signals. This may be
+ implemented as a macro in sysdep.h. */
+#ifndef usysdep_end_catch
+extern void usysdep_end_catch P((void));
+#endif
+
+/* Link two files. On Unix this should attempt the link. If it
+ succeeds it should return TRUE with *pfworked set to TRUE. If the
+ link fails because it must go across a device, it should return
+ TRUE with *pfworked set to FALSE. If the link fails for some other
+ reason, it should log an error message and return FALSE. On a
+ system which does not support links to files, this should just
+ return TRUE with *pfworked set to FALSE. */
+extern boolean fsysdep_link P((const char *zfrom, const char *zto,
+ boolean *pfworked));
+
+/* Get the port name. This is used when uucico is started up in slave
+ mode to figure out which port was used to call in so that it can
+ determine any appropriate protocol parameters. This may return
+ NULL if the port cannot be determined, which will just mean that no
+ protocol parameters are applied. The name returned should be the
+ sort of name that would appear in the port file. This should set
+ *pftcp_port to TRUE if it can determine that the port is a TCP
+ connection rather than a normal serial port. The return value (if
+ not NULL) should point to a static buffer. */
+extern const char *zsysdep_port_name P((boolean *pftcp_port));
+
+/* Expand a file name on the local system. On Unix, if the zfile
+ argument begins with ~user/ it goes in that users home directory,
+ and if it begins with ~/ it goes in the public directory (the
+ public directory is passed to this routine, since each system may
+ have its own public directory). Similar conventions may be
+ desirable on other systems. This should always return an absolute
+ path name, probably in the public directory. It should return NULL
+ on error; otherwise the return value should be allocated using
+ zbufcpy or zbufalc. */
+extern char *zsysdep_local_file P((const char *zname,
+ const char *zpubdir));
+
+/* Return whether a file name is in a directory, and check for read or
+ write access. This should check whether zfile is within zdir (or
+ is zdir itself). If it is not, it should return FALSE. If zfile
+ is in zdir, then fcheck indicates whether further checking should
+ be done. If fcheck is FALSE, no further checking is done.
+ Otherwise, if freadable is TRUE the user zuser should have search
+ access to all directories from zdir down to zfile and should have
+ read access on zfile itself (if zfile does not exist, or is not a
+ regular file, this function may return FALSE but does not have to).
+ If freadable is FALSE, the user zuser should have search access to
+ all directories from zdir down to zfile and should have write
+ access on zfile (which may be a directory, or may not actually
+ exist, which is acceptable). The zuser argument may be NULL, in
+ which case the check should be made for any user, not just zuser.
+ There is no way for this function to return error. */
+extern boolean fsysdep_in_directory P((const char *zfile,
+ const char *zdir,
+ boolean fcheck,
+ boolean freadable,
+ const char *zuser));
+
+/* Return TRUE if a file exists, FALSE otherwise. There is no way to
+ return error. */
+extern boolean fsysdep_file_exists P((const char *zfile));
+
+/* Start up a program. The code expects fsysdep_run to return after
+ doing a fork, but at least for now everything will work fine if it
+ does not (on a system which does not support forking). The three
+ string arguments may be catenated together to form the program to
+ execute; I did it this way to make it easy to call execl(2), and
+ because I never needed more than two arguments. The program will
+ always be "uucico" or "uuxqt". The return value will be passed
+ directly to usysdep_exit, and should be TRUE on success, FALSE on
+ error. */
+extern boolean fsysdep_run P((const char *zprogram, const char *zarg1,
+ const char *zarg2));
+
+/* Send a mail message. This function will be passed an array of
+ strings. All necessary newlines are already included; the strings
+ should simply be concatenated together to form the mail message.
+ It should return FALSE on error, although the return value is often
+ ignored. */
+extern boolean fsysdep_mail P((const char *zto, const char *zsubject,
+ int cstrs, const char **paz));
+
+/* Get the time in seconds since some epoch. The actual epoch is
+ unimportant, so long as the time values are consistent across
+ program executions and the value is never negative. If the
+ pimicros argument is not NULL, it should be set to the number of
+ microseconds (if this is not available, *pimicros should be set to
+ zero). */
+extern long ixsysdep_time P((long *pimicros));
+
+/* Get the time in seconds and microseconds (millionths of a second)
+ since some epoch. The actual epoch is not important, and it may
+ change in between program invocations; this is provided because on
+ Unix the times function may be used. If microseconds can not be
+ determined, *pimicros can just be set to zero. */
+extern long ixsysdep_process_time P((long *pimicros));
+
+/* Parse the value returned by ixsysdep_time into a struct tm. I
+ assume that this structure is defined in <time.h>. This is
+ basically just localtime, except that the ANSI function takes a
+ time_t which may not be what is returned by ixsysdep_time. */
+extern void usysdep_localtime P((long itime, struct tm *q));
+
+/* Sleep for a number of seconds. */
+extern void usysdep_sleep P((int cseconds));
+
+/* Pause for half a second, or 1 second if subsecond sleeps are not
+ possible. */
+extern void usysdep_pause P((void));
+
+/* Lock a remote system. This should return FALSE if the system is
+ already locked (no error should be reported). */
+extern boolean fsysdep_lock_system P((const struct uuconf_system *qsys));
+
+/* Unlock a remote system. This should return FALSE on error
+ (although the return value is generally ignored). */
+extern boolean fsysdep_unlock_system P((const struct uuconf_system *qsys));
+
+/* Get the conversation sequence number for a remote system, and
+ increment it for next time. This should return -1 on error. */
+extern long ixsysdep_get_sequence P((const struct uuconf_system *qsys));
+
+/* Get the status of a remote system. This should return FALSE on
+ error. Otherwise it should set *qret to the status. If no status
+ information is available, this should set *qret to sensible values
+ and return TRUE. If pfnone is not NULL, then it should be set to
+ TRUE if no status information was available or FALSE otherwise. */
+extern boolean fsysdep_get_status P((const struct uuconf_system *qsys,
+ struct sstatus *qret,
+ boolean *pfnone));
+
+/* Set the status of a remote system. This should return FALSE on
+ error. The system will be locked before this call is made. */
+extern boolean fsysdep_set_status P((const struct uuconf_system *qsys,
+ const struct sstatus *qset));
+
+/* See whether a remote system is permitted to log in. This is just
+ to support the remote.unknown shell script for HDB. The zscript
+ argument is the script name, as return by uuconf_remote_unknown.
+ The zsystem argument is the name given by the remote system. If
+ the system is not permitted to log in, this function should log an
+ error and return FALSE. */
+extern boolean fsysdep_unknown_caller P((const char *zscript,
+ const char *zsystem));
+
+/* Check whether there is work for a remote system. It should return
+ TRUE if there is work, FALSE otherwise; there is no way to indicate
+ an error. */
+extern boolean fsysdep_has_work P((const struct uuconf_system *qsys));
+
+/* Initialize the work scan. This will be called before
+ fsysdep_get_work. The bgrade argument is the minimum grade of
+ execution files that should be considered (e.g. a bgrade of 'd'
+ will allow all grades from 'A' to 'Z' and 'a' to 'd'). This
+ function should return FALSE on error. */
+extern boolean fsysdep_get_work_init P((const struct uuconf_system *qsys,
+ int bgrade));
+
+/* Get the next command to be executed for a remote system. The
+ bgrade argument will be the same as for fsysdep_get_work_init;
+ probably only one of these functions will use it, namely the
+ function for which it is more convenient. This should return FALSE
+ on error. The structure pointed to by qcmd should be filled in.
+ The strings may point into a static buffer; they will be copied out
+ if necessary. If there is no more work, this should set qcmd->bcmd
+ to 'H' and return TRUE. This should set qcmd->pseq to something
+ which can be passed to fsysdep_did_work to remove the job from the
+ queue when it has been completed. This may set qcmd->bcmd to 'P'
+ to represent a poll file; the main code will just pass the pseq
+ element of such a structure to fsysdep_did_work if the system is
+ called. */
+extern boolean fsysdep_get_work P((const struct uuconf_system *qsys,
+ int bgrade, struct scmd *qcmd));
+
+/* Remove a job from the work queue. This must also remove the
+ temporary file used for a send command, if there is one. It should
+ return FALSE on error. */
+extern boolean fsysdep_did_work P((pointer pseq));
+
+/* Save the temporary file for a send command. This function should
+ return a string that will be put into a mail message. On success
+ this string should say something like ``The file has been saved as
+ ...''. On failure it could say something like ``The file could not
+ be saved because ...''. If there is no temporary file, or for some
+ reason it's not appropriate to include a message, this function
+ should just return NULL. This function is used when a file send
+ fails for some reason, to make sure that we don't completely lost
+ the file. */
+extern const char *zsysdep_save_temp_file P((pointer pseq));
+
+/* Cleanup anything left over by fsysdep_get_work_init and
+ fsysdep_get_work. This may be called even though
+ fsysdep_get_work_init has not been. */
+extern void usysdep_get_work_free P((const struct uuconf_system *qsys));
+
+/* Add a base name to a file if it is a directory. If zfile names a
+ directory, then return a string naming a file within the directory
+ with the base file name of zname. This should return NULL on
+ error. */
+extern char *zsysdep_add_base P((const char *zfile,
+ const char *zname));
+
+/* Get a file name from the spool directory. This should return NULL
+ on error. The pseq argument is TRUE if the file was found from
+ searching the work directory; this is, unfortunately, needed to
+ support SVR4 spool directories. */
+extern char *zsysdep_spool_file_name P((const struct uuconf_system *qsys,
+ const char *zfile,
+ pointer pseq));
+
+/* Make necessary directories. This should create all non-existent
+ directories for a file. If the fpublic argument is TRUE, anybody
+ should be permitted to create and remove files in the directory;
+ otherwise anybody can list the directory, but only the UUCP system
+ can create and remove files. It should return FALSE on error. */
+extern boolean fsysdep_make_dirs P((const char *zfile, boolean fpublic));
+
+/* Create a stdio file, setting appropriate protection. If the
+ fpublic argument is TRUE, the file is made publically accessible;
+ otherwise it is treated as a private data file. If the fappend
+ argument is TRUE, the file is opened in append mode; otherwise any
+ previously existing file of the same name is removed. If the
+ fmkdirs argument is TRUE, then any necessary directories should
+ also be created. On a system in which file protections are
+ unimportant and the necessary directories exist, this may be
+ implemented as
+
+ fopen (zfile, fappend ? "a" : "w");
+
+ */
+extern FILE *esysdep_fopen P((const char *zfile, boolean fpublic,
+ boolean fappend, boolean fmkdirs));
+
+/* Open a file, using the access permission of the user who invoked
+ the program. The frd argument is TRUE if the file should be opened
+ for reading, and the fbinary argument is TRUE if the file should be
+ opened as a binary file (this is ignored on Unix, since there all
+ files are binary files). This returns an openfile_t, not a FILE *.
+ This is supposed to be able to open a file even if it can not be
+ read by the uucp user. This is not possible on some older Unix
+ systems. */
+extern openfile_t esysdep_user_fopen P((const char *zfile,
+ boolean frd, boolean fbinary));
+
+/* Open a file to send to another system; the qsys argument is the
+ system the file is being sent to. If fcheck is TRUE, it should
+ make sure that the file is readable by zuser (if zuser is NULL the
+ file must be readable by anybody). This is to eliminate a window
+ between fsysdep_in_directory and esysdep_open_send. If an error
+ occurs, it should return EFILECLOSED. */
+extern openfile_t esysdep_open_send P((const struct uuconf_system *qsys,
+ const char *zname,
+ boolean fcheck,
+ const char *zuser));
+
+/* Return a temporary file name to receive into. This file will be
+ opened by esysdep_open_receive. The qsys argument is the system
+ the file is coming from, the zto argument is the name the file will
+ have after it has been fully received, and the ztemp argument, if
+ it is not NULL, is from the command sent by the remote system. The
+ return value must be freed using ubuffree. The function should
+ return NULL on error. */
+extern char *zsysdep_receive_temp P((const struct uuconf_system *qsys,
+ const char *zfile,
+ const char *ztemp));
+
+/* Open a file to receive from another system. The zreceive argument
+ is the return value of zsysdep_receive_temp with the same qsys,
+ zfile and ztemp arguments. If the function can determine that this
+ file has already been partially received, it should set *pcrestart
+ to the number of bytes that have been received. If the file has
+ not been partially received, *pcrestart should be set to -1. The
+ function should return EFILECLOSED on error. After the file is
+ written, fsysdep_move_file will be called to move the file to its
+ final destination, and to set the correct file mode. */
+extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp,
+ const char *zreceive,
+ long *pcrestart));
+
+/* Move a file. This is used to move a received file to its final
+ location. The zto argument is the file to create. The zorig
+ argument is the name of the file to move. If fmkdirs is TRUE, then
+ any necessary directories are created; fpublic indicates whether
+ they should be publically writeable or not. If fcheck is TRUE,
+ this should make sure the directory is writeable by the user zuser
+ (if zuser is NULL, then it must be writeable by any user); this is
+ to avoid a window of vulnerability between fsysdep_in_directory and
+ fsysdep_move_file. This function should return FALSE on error; the
+ zorig file should be removed even if an error occurs. */
+extern boolean fsysdep_move_file P((const char *zorig, const char *zto,
+ boolean fmkdirs, boolean fpublic,
+ boolean fcheck, const char *zuser));
+
+/* Change the mode of a file. The imode argument is a Unix mode.
+ This should return FALSE on error. */
+extern boolean fsysdep_change_mode P((const char *zfile,
+ unsigned int imode));
+
+/* Truncate a file which we are receiving into. This may be done by
+ closing the original file, removing it and reopening it. This
+ should return FALSE on error. */
+extern openfile_t esysdep_truncate P((openfile_t e, const char *zname));
+
+/* It is possible for the acknowledgement of a received file to be
+ lost. The sending system will then now know that the file was
+ correctly received, and will send it again. This can be a problem
+ particularly with protocols which support channels, since they may
+ send several small files in a single window, all of which may be
+ received correctly although the sending system never sees the
+ acknowledgement. If these files involve an execution, the
+ execution will happen twice, which will be bad.
+
+ This function is called when a file is completely received. It is
+ supposed to try and remember the reception, in case the connection
+ is lost. It is passed the system, the file name to receive to, and
+ the temporary file name from the sending system. It should return
+ FALSE on error. */
+extern boolean fsysdep_remember_reception P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* This function is called to see if a file has already been received
+ successfully. It gets the same arguments as
+ fsysdep_remember_reception. It should return TRUE if the file was
+ already received, FALSE otherwise. There is no way to report
+ error. */
+extern boolean fsysdep_already_received P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* This function is called when it is no longer necessary to remember
+ that a file has been received. This will be called when the
+ protocol knows that the receive message has been acknowledged. It
+ gets the same arguments as fsysdep_remember_reception. it should
+ return FALSE on error. */
+extern boolean fsysdep_forget_reception P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* Start expanding a wildcarded file name. This should return FALSE
+ on error; otherwise subsequent calls to zsysdep_wildcard should
+ return file names. */
+extern boolean fsysdep_wildcard_start P((const char *zfile));
+
+/* Get the next wildcard name. This should return NULL when there are
+ no more names to return. The return value should be freed using
+ ubuffree. The argument should be the same as that to
+ fsysdep_wildcard_start. There is no way to return error. */
+extern char *zsysdep_wildcard P((const char *zfile));
+
+/* Finish getting wildcard names. This may be called before or after
+ zsysdep_wildcard has returned NULL. It should return FALSE on
+ error. */
+extern boolean fsysdep_wildcard_end P((void));
+
+/* Prepare to execute a bunch of file transfer requests. This should
+ make an entry in the spool directory so that the next time uucico
+ is started up it will transfer these files. The bgrade argument
+ specifies the grade of the commands. The commands themselves are
+ in the pascmds array, which has ccmds entries. The function should
+ return NULL on error, or the jobid on success. The jobid is a
+ string that may be printed or passed to fsysdep_kill_job and
+ related functions, but is otherwise uninterpreted. */
+extern char *zsysdep_spool_commands P((const struct uuconf_system *qsys,
+ int bgrade, int ccmds,
+ const struct scmd *pascmds));
+
+/* Get a file name to use for a data file to be copied to another
+ system. The ztname, zdname and zxname arguments will all either be
+ NULL or point to an array of CFILE_NAME_LEN characters in length.
+ The ztname array should be set to a temporary file name that could
+ be passed to zsysdep_spool_file_name to retrieve the return value
+ of this function; this will be appropriate for the temporary name
+ in a send request. The zdname array should be set to a data file
+ name that is appropriate for the spool directory of the other
+ system; this will be appropriate for the name of the destination
+ file in a send request of a data file for an execution of some
+ sort. The zxname array should be set to an execute file name that
+ is appropriate for the other system. The zlocalname argument is
+ the name of the local system as seen by the remote system, the
+ bgrade argument is the grade, and fxqt is TRUE if this file is
+ going to become an execution file. This should return NULL on
+ error. */
+#define CFILE_NAME_LEN (15)
+
+extern char *zsysdep_data_file_name P((const struct uuconf_system *qsys,
+ const char *zlocalname,
+ int bgrade, boolean fxqt,
+ char *ztname, char *zdname,
+ char *zxname));
+
+/* Get a name for a local execute file. This is used by uux for a
+ local command with remote files. Returns NULL on error. */
+extern char *zsysdep_xqt_file_name P((void));
+
+/* Beginning getting execute files. To get a list of execute files,
+ first fsysdep_get_xqt_init is called, then zsysdep_get_xqt is
+ called several times until it returns NULL, then finally
+ usysdep_get_xqt_free is called. */
+extern boolean fsysdep_get_xqt_init P((void));
+
+/* Get the next execute file. This should return NULL when finished
+ (with *pferr set to FALSE). On an error this should return NULL
+ with *pferr set to TRUE. This should set *pzsystem to the name of
+ the system for which the execute file was created. Both the return
+ value and *pzsystem should be freed using ubuffree. */
+extern char *zsysdep_get_xqt P((char **pzsystem,
+ boolean *pferr));
+
+/* Clean up after getting execute files. */
+extern void usysdep_get_xqt_free P((void));
+
+/* Get the absolute pathname of a command to execute. This is given
+ the legal list of commands (which may be the special case "ALL")
+ and the path. It must return an absolute pathname to the command.
+ If it gets an error it should set *pferr to TRUE and return NULL;
+ if the command is not found it should set *pferr to FALSE and
+ return NULL. */
+extern char *zsysdep_find_command P((const char *zcmd, char **pzcmds,
+ char **pzpath, boolean *pferr));
+
+/* Expand file names for uuxqt. This exists because uuxqt on Unix has
+ to expand file names which begin with a ~. It does not want to
+ expand any other type of file name, and it turns a double ~ into a
+ single one without expanding. If this returns NULL, the file does
+ not need to be changed; otherwise it returns a zbufalc'ed string.
+ There is no way to report error. */
+extern char *zsysdep_xqt_local_file P((const struct uuconf_system *qsys,
+ const char *zfile));
+
+#if ! ALLOW_FILENAME_ARGUMENTS
+/* Check an argument to an execution command to make sure that it
+ doesn't refer to a file name that may not be accessed. This should
+ check the argument to see if it is a filename. If it is, it should
+ either reject it out of hand or it should call fin_directory_list
+ on the file with both qsys->zremote_receive and qsys->zremote_send.
+ If the file is rejected, it should log an error and return FALSE.
+ Otherwise it should return TRUE. */
+extern boolean fsysdep_xqt_check_file P((const struct uuconf_system *qsys,
+ const char *zfile));
+#endif /* ! ALLOW_FILENAME_ARGUMENTS */
+
+/* Run an execute file. The arguments are:
+
+ qsys -- system for which execute file was created
+ zuser -- user who requested execution
+ pazargs -- list of arguments to command (element 0 is command)
+ zfullcmd -- command and arguments stuck together in one string
+ zinput -- file name for standard input (may be NULL)
+ zoutput -- file name for standard output (may be NULL)
+ fshell -- if TRUE, use /bin/sh to execute file
+ ilock -- return value of ixsysdep_lock_uuxqt
+ pzerror -- set to name of standard error file
+ pftemp -- set to TRUE if error is temporary, FALSE otherwise
+
+ If fshell is TRUE, the command should be executed with /bin/sh
+ (obviously, this can only really be done on Unix systems). If an
+ error occurs this should return FALSE and set *pftemp
+ appropriately. *pzerror should be freed using ubuffree. */
+extern boolean fsysdep_execute P((const struct uuconf_system *qsys,
+ const char *zuser,
+ const char **pazargs,
+ const char *zfullcmd,
+ const char *zinput,
+ const char *zoutput,
+ boolean fshell,
+ int ilock,
+ char **pzerror,
+ boolean *pftemp));
+
+/* Lock for uuxqt execution. If the cmaxuuxqts argument is not zero,
+ this should make sure that no more than cmaxuuxqts uuxqt processes
+ are running at once. Also, only one uuxqt may execute a particular
+ command (specified by the -c option) at a time. If zcmd is not
+ NULL, it is a command that must be locked. This should return a
+ nonnegative number which will be passed to other routines,
+ including fsysdep_unlock_uuxqt, or -1 on error. */
+extern int ixsysdep_lock_uuxqt P((const char *zcmd,
+ int cmaxuuxqts));
+
+/* Unlock a uuxqt process. This is passed the return value of
+ ixsysdep_lock_uuxqt, as well as the arguments passed to
+ ixsysdep_lock_uuxqt. It may return FALSE on error, but at present
+ the return value is ignored. */
+extern boolean fsysdep_unlock_uuxqt P((int iseq, const char *zcmd,
+ int cmaxuuxqts));
+
+/* See whether a particular uuxqt command is locked. This should
+ return TRUE if the command is locked (because ixsysdep_lock_uuxqt
+ was called with it as an argument), FALSE otherwise. There is no
+ way to return error. */
+extern boolean fsysdep_uuxqt_locked P((const char *zcmd));
+
+/* Lock an execute file in order to execute it. This should return
+ FALSE if the execute file is already locked. There is no way to
+ return error. */
+extern boolean fsysdep_lock_uuxqt_file P((const char *zfile));
+
+/* Unlock an execute file. This should return FALSE on error. */
+extern boolean fsysdep_unlock_uuxqt_file P((const char *zfile));
+
+/* Lock the execution directory. The ilock argument is the return
+ value of ixsysdep_lock_uuxqt. This should return FALSE if the
+ directory is already locked. There is no way to return error. */
+extern boolean fsysdep_lock_uuxqt_dir P((int ilock));
+
+/* Remove all files in the execution directory, and unlock it. This
+ should return FALSE on error. */
+extern boolean fsysdep_unlock_uuxqt_dir P((int ilock));
+
+/* Move files into or out of the execution directory. The code will
+ already have checked that all the files exist. The elements in the
+ pzfrom array will be complete filenames, and the elements in the
+ pzto array will be either NULL (in which case the file should not
+ be moved) or simple base names. If fto is TRUE, the files in
+ pzfrom should be moved to pzto; otherwise, the files in pzto should
+ be moved to pzfrom (this is used if a temporary failure occurs, in
+ which case the execution will be retried later). If pzinput and
+ *pzinput are not NULL, then it is the name of the standard input
+ file; if it is the same as any element of pzfrom, then *pzinput
+ should be set to the zbufcpy of the corresponding pzto value, if
+ any. */
+extern boolean fsysdep_move_uuxqt_files P((int cfiles,
+ const char *const *pzfrom,
+ const char *const *pzto,
+ boolean fto, int ilock,
+ char **pzinput));
+
+/* Expand a file name on the local system, defaulting to the current
+ directory. This is just like zsysdep_local_file, except that
+ relative files are placed in the working directory the program
+ started in rather than in the public directory. This should return
+ NULL on error. */
+extern char *zsysdep_local_file_cwd P((const char *zname,
+ const char *zpubdir));
+
+/* Add the working directory to a file name. The named file is
+ actually on a remote system. If the file already has a directory,
+ it should not be changed. This should return NULL on error. */
+extern char *zsysdep_add_cwd P((const char *zfile));
+
+/* See whether a file name will need the current working directory
+ when zsysdep_local_file_cwd or zsysdep_add_cwd is called on it.
+ This will be called before usysdep_initialize. It should just
+ check whether the argument is an absolute path. See the comment
+ above usysdep_initialize in this file for an explanation of why
+ things are done this way. */
+extern boolean fsysdep_needs_cwd P((const char *zfile));
+
+/* Get the base name of a file. The file will be a local file name,
+ and this function should return the base file name, ideally in a
+ form which will make sense on most systems; it will be used if the
+ destination of a uucp is a directory. */
+extern char *zsysdep_base_name P((const char *zfile));
+
+/* Return a filename within a directory. */
+extern char *zsysdep_in_dir P((const char *zdir, const char *zfile));
+
+/* Get the mode of a file. This should return a Unix style file mode.
+ It should return 0 on error. */
+extern unsigned int ixsysdep_file_mode P((const char *zfile));
+
+/* See whether the user has access to a file. This is called by uucp
+ and uux to prevent copying of a file which uucp can read but the
+ user cannot. If access is denied, this should log an error message
+ and return FALSE. */
+extern boolean fsysdep_access P((const char *zfile));
+
+/* See whether the daemon has access to a file. This is called by
+ uucp and uux when a file is queued up for transfer without being
+ copied into the spool directory. It is merely an early error
+ check, as the daemon would of course discover the error itself when
+ it tried the transfer. If access would be denied, this should log
+ an error message and return FALSE. */
+extern boolean fsysdep_daemon_access P((const char *zfile));
+
+/* Translate a destination from system!user to a place in the public
+ directory where uupick will get the file. On Unix this produces
+ system!~/receive/user/localname, and that's probably what it has to
+ produce on any other system as well. Returns NULL on a usage
+ error, or otherwise returns string allocated by zbufcpy. */
+extern char *zsysdep_uuto P((const char *zdest,
+ const char *zlocalname));
+
+/* Return TRUE if a pathname exists and is a directory. */
+extern boolean fsysdep_directory P((const char *zpath));
+
+/* Walk a directory tree. The zdir argument is the directory to walk.
+ The pufn argument is a function to call on each regular file in the
+ tree. The first argument to pufn should be the full filename; the
+ second argument to pufn should be the filename relative to zdir;
+ the third argument to pufn should be the pinfo argument to
+ usysdep_walk_tree. The usysdep_walk_tree function should return
+ FALSE on error. */
+extern boolean usysdep_walk_tree P((const char *zdir,
+ void (*pufn) P((const char *zfull,
+ const char *zrelative,
+ pointer pinfo)),
+ pointer pinfo));
+
+/* Return the jobid of a work file, given the sequence value. On
+ error this should log an error and return NULL. The jobid is a
+ string which may be printed out and read in and passed to
+ fsysdep_kill_job, etc., but is not otherwise interpreted. */
+extern char *zsysdep_jobid P((const struct uuconf_system *qsys,
+ pointer pseq));
+
+/* See whether the current user is permitted to kill jobs submitted by
+ another user. This should return TRUE if permission is granted,
+ FALSE otherwise. */
+extern boolean fsysdep_privileged P((void));
+
+/* Kill a job, given the jobid. This should remove all associated
+ files and in general eliminate the job completely. On error it
+ should log an error message and return FALSE. */
+extern boolean fsysdep_kill_job P((pointer puuconf,
+ const char *zjobid));
+
+/* Rejuvenate a job, given the jobid. If possible, this should update
+ the time associated with the job such that it will not be
+ eliminated by uustat -K or similar programs that check the creation
+ time. This should affect the return value of ixsysdep_work_time.
+ On error it should log an error message and return FALSE. */
+extern boolean fsysdep_rejuvenate_job P((pointer puuconf,
+ const char *zjobid));
+
+/* Get the time a job was queued, given the sequence number. There is
+ no way to indicate error. The return value must use the same epoch
+ as ixsysdep_time. */
+extern long ixsysdep_work_time P((const struct uuconf_system *qsys,
+ pointer pseq));
+
+/* Get the time a file was created. This is called by uustat on
+ execution files. There is no way to indicate error. The return
+ value must use the same epoch as ixsysdep_time. */
+extern long ixsysdep_file_time P((const char *zfile));
+
+/* Get the size in bytes of a file. If this file does not exist, this
+ should not give an error message, but should return -1. If some
+ other error occurs, this should return -2. */
+extern long csysdep_size P((const char *zfile));
+
+/* Return the amount of free space on the containing the given file
+ name (the file may or may not exist). If the amount of free space
+ cannot be determined, the function should return -1. */
+extern long csysdep_bytes_free P((const char *zfile));
+
+/* Start getting status information for all systems with available
+ status information. There may be status information for unknown
+ systems, which is why this series of functions is used. The phold
+ argument is used to pass information around, to possibly avoid the
+ use of static variables. On error this should log an error and
+ return FALSE. */
+extern boolean fsysdep_all_status_init P((pointer *phold));
+
+/* Get status information for the next system. This should return the
+ system name and fill in the qstat argument. The phold argument
+ will be that set by fsysdep_all_status_init. On error this should
+ log an error, set *pferr to TRUE, and return NULL. */
+extern char *zsysdep_all_status P((pointer phold, boolean *pferr,
+ struct sstatus *qstat));
+
+/* Free up anything allocated by fsysdep_all_status_init and
+ zsysdep_all_status. The phold argument is that set by
+ fsysdep_all_status_init. */
+extern void usysdep_all_status_free P((pointer phold));
+
+/* Display the process status of all processes holding lock files.
+ This is uustat -p. The return value is passed to usysdep_exit. */
+extern boolean fsysdep_lock_status P((void));
+
+/* Return TRUE if the user has legitimate access to the port. This is
+ used by cu to control whether the user can open a port directly,
+ rather than merely being able to dial out on it. Opening a port
+ directly allows the modem to be reprogrammed. */
+extern boolean fsysdep_port_access P((struct uuconf_port *qport));
+
+/* Return whether the given port could be named by the given line. On
+ Unix, the line argument would be something like "ttyd0", and this
+ function should return TRUE if the named port is "/dev/ttyd0". */
+extern boolean fsysdep_port_is_line P((struct uuconf_port *qport,
+ const char *zline));
+
+/* Set the terminal into raw mode. In this mode no input characters
+ should be treated specially, and characters should be made
+ available as they are typed. The original terminal mode should be
+ saved, so that it can be restored by fsysdep_terminal_restore. If
+ flocalecho is TRUE, then local echoing should still be done;
+ otherwise echoing should be disabled. This function returns FALSE
+ on error. */
+extern boolean fsysdep_terminal_raw P((boolean flocalecho));
+
+/* Restore the terminal back to the original setting, before
+ fsysdep_terminal_raw was called. Returns FALSE on error. */
+extern boolean fsysdep_terminal_restore P((void));
+
+/* Read a line from the terminal. The fsysdep_terminal_raw function
+ will have been called. This should print the zprompt argument
+ (unless it is NULL) and return the line, allocated by zbufcpy, or
+ NULL on error. */
+extern char *zsysdep_terminal_line P((const char *zprompt));
+
+/* Write a line to the terminal, ending with a newline. This is
+ basically just puts (zline, stdout), except that the terminal will
+ be in raw mode, so on ASCII Unix systems the line needs to end with
+ \r\n. */
+extern boolean fsysdep_terminal_puts P((const char *zline));
+
+/* If faccept is TRUE, permit the user to generate signals from the
+ terminal. If faccept is FALSE, turn signals off again. After
+ fsysdep_terminal_raw is called, signals should be off. Return
+ FALSE on error. */
+extern boolean fsysdep_terminal_signals P((boolean faccept));
+
+/* The cu program expects the system dependent code to handle the
+ details of copying data from the communications port to the
+ terminal. This should be set up by fsysdep_cu_init, and done while
+ fsysdep_cu is called. It is permissible to do it on a continual
+ basis (on Unix a subprocess handles it) so long as the copying can
+ be stopped by the fsysdep_cu_copy function.
+
+ The fsysdep_cu_init function does any system dependent
+ initialization needed for this. */
+extern boolean fsysdep_cu_init P((struct sconnection *qconn));
+
+/* Copy all data from the communications port to the terminal, and all
+ data from the terminal to the communications port. Keep this up
+ until the escape character *zCuvar_escape is seen. Set *pbcmd to
+ the character following the escape character; after the escape
+ character, zlocalname should be printed, possibly after a delay.
+ If two escape characters are entered in sequence, this function
+ should send a single escape character to the port, and not return.
+ Returns FALSE on error. */
+extern boolean fsysdep_cu P((struct sconnection *qconn,
+ char *pbcmd,
+ const char *zlocalname));
+
+/* If fcopy is TRUE, start copying data from the communications port
+ to the terminal. If fcopy is FALSE, stop copying data. This
+ function may be called several times during a cu session. It
+ should return FALSE on error. */
+extern boolean fsysdep_cu_copy P((boolean fcopy));
+
+/* Stop copying data from the communications port to the terminal, and
+ generally clean up after fsysdep_cu_init and fsysdep_cu. Returns
+ FALSE on error. */
+extern boolean fsysdep_cu_finish P((void));
+
+/* Run a shell command. If zcmd is NULL, or *zcmd == '\0', just
+ start up a shell. The second argument is one of the following
+ values. This should return FALSE on error. */
+enum tshell_cmd
+{
+ /* Attach stdin and stdout to the terminal. */
+ SHELL_NORMAL,
+ /* Attach stdout to the communications port, stdin to the terminal. */
+ SHELL_STDOUT_TO_PORT,
+ /* Attach stdin to the communications port, stdout to the terminal. */
+ SHELL_STDIN_FROM_PORT,
+ /* Attach both stdin and stdout to the communications port. */
+ SHELL_STDIO_ON_PORT
+};
+
+extern boolean fsysdep_shell P((struct sconnection *qconn,
+ const char *zcmd,
+ enum tshell_cmd tcmd));
+
+/* Change directory. If zdir is NULL, or *zdir == '\0', change to the
+ user's home directory. Return FALSE on error. */
+extern boolean fsysdep_chdir P((const char *zdir));
+
+/* Suspend the current process. This is only expected to work on Unix
+ versions that support SIGTSTP. In general, people can just shell
+ out. */
+extern boolean fsysdep_suspend P((void));
+
+/* Start getting files for uupick. The zsystem argument may be NULL
+ to get files from all systems, or it may specify a particular
+ system. The zpubdir argument is the public directory to use. This
+ returns FALSE on error. */
+extern boolean fsysdep_uupick_init P((const char *zsystem,
+ const char *zpubdir));
+
+/* Get the next file for uupick. This returns the basic file name.
+ It sets *pzfull to the full name, and *pzfrom to the name of the
+ system which sent this file over; both should be freed using
+ ubuffree. *pzfull should be passed to ubuffree after it is no
+ longer needed. The zsystem and zpubdir arguments should be the
+ same as the arguments to fsysdep_uupick_init. This returns NULL
+ when all files been returned. */
+extern char *zsysdep_uupick P((const char *zsystem, const char *zpubdir,
+ char **pzfrom, char **pzfull));
+
+/* Clean up after getting files for uupick. */
+extern boolean fsysdep_uupick_free P((const char *zsystem,
+ const char *zpubdir));
+
+/* Translate a local file name for uupick. On Unix this is just like
+ zsysdep_local_file_cwd except that a file beginning with ~/ is
+ placed in the user's home directory rather than in the public
+ directory. */
+extern char *zsysdep_uupick_local_file P((const char *zfile));
+
+/* Remove a directory and all the files in it. */
+extern boolean fsysdep_rmdir P((const char *zdir));
+
+#endif /* ! defined (SYSTEM_H) */
diff --git a/gnu/libexec/uucp/common_sources/tcp.c b/gnu/libexec/uucp/common_sources/tcp.c
new file mode 100644
index 00000000000..c38760da85c
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/tcp.c
@@ -0,0 +1,470 @@
+/* tcp.c
+ Code to handle TCP connections.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char tcp_rcsid[] = "$Id: tcp.c,v 1.1 1993/08/04 19:31:06 jtc Exp $";
+#endif
+
+#if HAVE_TCP
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "conn.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_TYPES_TCP_H
+#include <sys/types.tcp.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* This code handles TCP connections. It assumes a Berkeley socket
+ interface. */
+
+/* The normal "uucp" port number. */
+#define IUUCP_PORT (540)
+
+/* Local functions. */
+static void utcp_free P((struct sconnection *qconn));
+static boolean ftcp_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean ftcp_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean ftcp_reset P((struct sconnection *qconn));
+static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialer));
+static int itcp_port_number P((const char *zport));
+
+/* The command table for a TCP connection. */
+static const struct sconncmds stcpcmds =
+{
+ utcp_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ ftcp_open,
+ ftcp_close,
+ ftcp_reset,
+ ftcp_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ NULL, /* pfbreak */
+ NULL, /* pfset */
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ NULL /* pibaud */
+};
+
+/* Initialize a TCP connection. */
+
+boolean
+fsysdep_tcp_init (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ q->o = -1;
+ q->zdevice = NULL;
+ q->iflags = -1;
+ q->istdout_flags = -1;
+ q->fterminal = FALSE;
+ q->ftli = FALSE;
+ q->ibaud = 0;
+
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = &stcpcmds;
+ return TRUE;
+}
+
+/* Free a TCP connection. */
+
+static void
+utcp_free (qconn)
+ struct sconnection *qconn;
+{
+ xfree (qconn->psysdep);
+}
+
+/* Open a TCP connection. If the fwait argument is TRUE, we are
+ running as a server. Otherwise we are just trying to reach another
+ system. */
+
+static boolean
+ftcp_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *qsysdep;
+ struct sockaddr_in s;
+ const char *zport;
+ uid_t iuid, ieuid;
+
+ ulog_device ("TCP");
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ qsysdep->o = socket (AF_INET, SOCK_STREAM, 0);
+ if (qsysdep->o < 0)
+ {
+ ulog (LOG_ERROR, "socket: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
+ if (qsysdep->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ /* If we aren't waiting for a connection, we're done. */
+ if (! fwait)
+ return TRUE;
+
+ /* Run as a server and wait for a new connection. The code in
+ uucico.c has already detached us from our controlling terminal.
+ From this point on if the server gets an error we exit; we only
+ return if we have received a connection. It would be more robust
+ to respawn the server if it fails; someday. */
+ bzero ((pointer) &s, sizeof s);
+ s.sin_family = AF_INET;
+ zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
+ s.sin_port = itcp_port_number (zport);
+ s.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ /* Swap to our real user ID when doing the bind call. This will
+ permit the server to use privileged TCP ports when invoked by
+ root. We only swap if our effective user ID is not root, so that
+ the program can also be made suid root in order to get privileged
+ ports when invoked by anybody. */
+ iuid = getuid ();
+ ieuid = geteuid ();
+ if (ieuid != 0)
+ {
+#if HAVE_SETREUID
+ /* Swap the effective user id and the real user id. We can then
+ swap them back again when we want to return to the uucp
+ user's permissions. */
+ if (setreuid (ieuid, iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) ieuid, (long) iuid, strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set the effective user id to the real user id. Since the
+ effective user id is the saved setuid we will able to set
+ back to it later. If the real user id is root we will not be
+ able to switch back and forth, but that doesn't matter since
+ we only want to switch once. */
+ if (setuid (iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid,
+ strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* There's no way to switch between real permissions and
+ effective permissions. Just try the bind with the uucp
+ permissions. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+ }
+
+ if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
+ ulog (LOG_FATAL, "bind: %s", strerror (errno));
+
+ /* Now swap back to the uucp user ID. */
+ if (ieuid != 0)
+ {
+#if HAVE_SETREUID
+ if (setreuid (iuid, ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) iuid, (long) ieuid, strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set ourselves back to our original effective user id. */
+ if (setuid ((uid_t) ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid,
+ strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* We didn't switch, no need to switch back. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+ }
+
+ if (listen (qsysdep->o, 5) < 0)
+ ulog (LOG_FATAL, "listen: %s", strerror (errno));
+
+ while (! FGOT_SIGNAL ())
+ {
+ size_t clen;
+ int onew;
+ pid_t ipid;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftcp_open: Waiting for connections");
+
+ clen = sizeof s;
+ onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen);
+ if (onew < 0)
+ ulog (LOG_FATAL, "accept: %s", strerror (errno));
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftcp_open: Got connection; forking");
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+ if (ipid == 0)
+ {
+ (void) close (qsysdep->o);
+ qsysdep->o = onew;
+
+ /* Now we fork and let our parent die, so that we become
+ a child of init. This lets the main server code wait
+ for its child and then continue without accumulating
+ zombie children. */
+ ipid = ixsfork ();
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ ulog_id (getpid ());
+
+ return TRUE;
+ }
+
+ (void) close (onew);
+
+ /* Now wait for the child. */
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ }
+
+ /* We got a signal. */
+ usysdep_exit (FALSE);
+
+ /* Avoid compiler warnings. */
+ return FALSE;
+}
+
+/* Close the port. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ fret = TRUE;
+ if (qsysdep->o >= 0 && close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->o = -1;
+ return fret;
+}
+
+/* Reset the port. This will be called by a child which was forked
+ off in ftcp_open, above. We don't want uucico to continue looping
+ and giving login prompts, so we pretend that we received a SIGINT
+ signal. This should probably be handled more cleanly. The signal
+ will not be recorded in the log file because we don't set
+ afLog_signal[INDEXSIG_SIGINT]. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_reset (qconn)
+ struct sconnection *qconn;
+{
+ afSignal[INDEXSIG_SIGINT] = TRUE;
+ return TRUE;
+}
+
+/* Dial out on a TCP port, so to speak: connect to a remote computer. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialer;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *zhost;
+ struct hostent *q;
+ struct sockaddr_in s;
+ const char *zport;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ *ptdialer = DIALERFOUND_FALSE;
+
+ zhost = zphone;
+ if (zhost == NULL)
+ {
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "No address for TCP connection");
+ return FALSE;
+ }
+ zhost = qsys->uuconf_zname;
+ }
+
+ errno = 0;
+ q = gethostbyname ((char *) zhost);
+ if (q == NULL)
+ {
+ if (errno == 0)
+ ulog (LOG_ERROR, "%s: unknown host name", zhost);
+ else
+ ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno));
+ return FALSE;
+ }
+
+ s.sin_family = q->h_addrtype;
+ zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
+ s.sin_port = itcp_port_number (zport);
+ memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length);
+
+ if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
+ {
+ ulog (LOG_ERROR, "connect: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Get the port number given a name. The argument will almost always
+ be "uucp" so we cache that value. The return value is always in
+ network byte order. This returns -1 on error. */
+
+static int
+itcp_port_number (zname)
+ const char *zname;
+{
+ boolean fuucp;
+ static int iuucp;
+ int i;
+ char *zend;
+ struct servent *q;
+
+ fuucp = strcmp (zname, "uucp") == 0;
+ if (fuucp && iuucp != 0)
+ return iuucp;
+
+ /* Try it as a number first. */
+ i = strtol ((char *) zname, &zend, 10);
+ if (i != 0 && *zend == '\0')
+ return htons (i);
+
+ q = getservbyname ((char *) zname, (char *) "tcp");
+ if (q == NULL)
+ {
+ /* We know that the "uucp" service should be 540, even if isn't
+ in /etc/services. */
+ if (fuucp)
+ {
+ iuucp = htons (IUUCP_PORT);
+ return iuucp;
+ }
+ ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno));
+ return -1;
+ }
+
+ if (fuucp)
+ iuucp = q->s_port;
+
+ return q->s_port;
+}
+
+#endif /* HAVE_TCP */
diff --git a/gnu/libexec/uucp/common_sources/tli.c b/gnu/libexec/uucp/common_sources/tli.c
new file mode 100644
index 00000000000..6958b80b470
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/tli.c
@@ -0,0 +1,644 @@
+/* tli.c
+ Code to handle TLI connections.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char tli_rcsid[] = "$Id: tli.c,v 1.1 1993/08/04 19:31:09 jtc Exp $";
+#endif
+
+#if HAVE_TLI
+
+#include "sysdep.h"
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_TIUSER_H
+#include <tiuser.h>
+#else
+#if HAVE_XTI_H
+#include <xti.h>
+#else
+#if HAVE_SYS_TLI_H
+#include <sys/tli.h>
+#endif
+#endif
+#endif
+
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* The arguments to t_alloca have two different names. I want the
+ SVID ones, not the XPG3 ones. */
+#ifndef T_BIND
+#define T_BIND T_BIND_STR
+#endif
+#ifndef T_CALL
+#define T_CALL T_CALL_STR
+#endif
+
+/* Hopefully these externs will not cause any trouble. This is how
+ they are shown in the SVID. */
+extern int t_errno;
+extern char *t_errlist[];
+extern int t_nerr;
+
+#ifndef t_alloc
+extern pointer t_alloc ();
+#endif
+
+/* This code handles TLI connections. It's Unix specific. It's
+ largely based on code from Unix Network Programming, by W. Richard
+ Stevens. */
+
+/* Local functions. */
+static const char *ztlierror P((void));
+static void utli_free P((struct sconnection *qconn));
+static boolean ftli_push P((struct sconnection *qconn));
+static boolean ftli_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean ftli_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean ftli_reset P((struct sconnection *qconn));
+static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialer));
+
+/* The command table for a TLI connection. */
+static const struct sconncmds stlicmds =
+{
+ utli_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ ftli_open,
+ ftli_close,
+ ftli_reset,
+ ftli_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ NULL, /* pfbreak */
+ NULL, /* pfset */
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ NULL /* pibaud */
+};
+
+/* Get a TLI error string. */
+
+static const char *
+ztlierror ()
+{
+ if (t_errno == TSYSERR)
+ return strerror (errno);
+ if (t_errno < 0 || t_errno >= t_nerr)
+ return "Unknown TLI error";
+ return t_errlist[t_errno];
+}
+
+/* Initialize a TLI connection. */
+
+boolean
+fsysdep_tli_init (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ q->o = -1;
+ q->zdevice = NULL;
+ q->iflags = -1;
+ q->istdout_flags = -1;
+ q->fterminal = FALSE;
+ q->ftli = TRUE;
+ q->ibaud = 0;
+
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = &stlicmds;
+ return TRUE;
+}
+
+/* Free a TLI connection. */
+
+static void
+utli_free (qconn)
+ struct sconnection *qconn;
+{
+ xfree (qconn->psysdep);
+}
+
+/* Push all desired modules onto a TLI stream. If the user requests a
+ STREAMS connection without giving a list of modules, we just push
+ tirdwr. If the I_PUSH ioctl is not defined on this system, we just
+ ignore any list of modules. */
+
+static boolean
+ftli_push (qconn)
+ struct sconnection *qconn;
+{
+#ifdef I_PUSH
+
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL)
+ {
+ char **pz;
+
+ for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush;
+ *pz != NULL;
+ pz++)
+ {
+ if (ioctl (qsysdep->o, I_PUSH, *pz) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz,
+ strerror (errno));
+ return FALSE;
+ }
+ }
+ }
+ else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
+ {
+ if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+ /* If we have just put the connection into stream mode, we must turn
+ off the TLI flag to avoid using TLI calls on it. */
+ if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
+ qsysdep->ftli = FALSE;
+
+#endif /* defined (I_PUSH) */
+
+ return TRUE;
+}
+
+/* Open a TLI connection. If the fwait argument is TRUE, we are
+ running as a server. Otherwise we are just trying to reach another
+ system. */
+
+static boolean
+ftli_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *zdevice;
+ char *zfreedev;
+ const char *zservaddr;
+ char *zfreeaddr;
+ struct t_bind *qtbind;
+ struct t_call *qtcall;
+
+ /* Unlike most other device types, we don't bother to call
+ ulog_device here, because fconn_open calls it with the name of
+ the port anyhow. */
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice;
+ if (zdevice == NULL)
+ zdevice = qconn->qport->uuconf_zname;
+
+ zfreedev = NULL;
+ if (*zdevice != '/')
+ {
+ zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice));
+ sprintf (zfreedev, "/dev/%s", zdevice);
+ zdevice = zfreedev;
+ }
+
+ qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
+ if (qsysdep->o < 0)
+ {
+ ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ());
+ ubuffree (zfreedev);
+ return FALSE;
+ }
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ubuffree (zfreedev);
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
+ if (qsysdep->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ ubuffree (zfreedev);
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ /* If we aren't waiting for a connection, we can bind to any local
+ address, and then we're finished. */
+ if (! fwait)
+ {
+ ubuffree (zfreedev);
+ if (t_bind (qsysdep->o, (struct t_bind *) NULL,
+ (struct t_bind *) NULL) < 0)
+ {
+ ulog (LOG_ERROR, "t_bind: %s", ztlierror ());
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ /* Run as a server and wait for a new connection. The code in
+ uucico.c has already detached us from our controlling terminal.
+ From this point on if the server gets an error we exit; we only
+ return if we have received a connection. It would be more robust
+ to respawn the server if it fails; someday. */
+ qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL);
+ if (qtbind == NULL)
+ ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ());
+
+ zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr;
+ if (zservaddr == NULL)
+ ulog (LOG_FATAL, "Can't run as TLI server; no server address");
+
+ zfreeaddr = zbufcpy (zservaddr);
+ qtbind->addr.len = cescape (zfreeaddr);
+ if (qtbind->addr.len > qtbind->addr.maxlen)
+ ulog (LOG_FATAL, "%s: TLI server address too long (max %d)",
+ zservaddr, qtbind->addr.maxlen);
+ memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len);
+ ubuffree (zfreeaddr);
+
+ qtbind->qlen = 5;
+
+ if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0)
+ ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ());
+
+ (void) t_free ((pointer) qtbind, T_BIND);
+
+ qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL);
+ if (qtcall == NULL)
+ ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ());
+
+ while (! FGOT_SIGNAL ())
+ {
+ int onew;
+ pid_t ipid;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftli_open: Waiting for connections");
+
+ if (t_listen (qsysdep->o, qtcall) < 0)
+ ulog (LOG_FATAL, "t_listen: %s", ztlierror ());
+
+ onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
+ if (onew < 0)
+ ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ());
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+
+ if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0)
+ ulog (LOG_FATAL, "t_bind: %s", ztlierror ());
+
+ if (t_accept (qsysdep->o, onew, qtcall) < 0)
+ {
+ /* We may have received a disconnect. */
+ if (t_errno != TLOOK)
+ ulog (LOG_FATAL, "t_accept: %s", ztlierror ());
+ if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
+ ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ());
+ (void) t_close (onew);
+ continue;
+ }
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftli_open: Got connection; forking");
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+ if (ipid == 0)
+ {
+ ulog_close ();
+
+ (void) t_close (qsysdep->o);
+ qsysdep->o = onew;
+
+ /* Push any desired modules. */
+ if (! ftli_push (qconn))
+ _exit (EXIT_FAILURE);
+
+ /* Now we fork and let our parent die, so that we become
+ a child of init. This lets the main server code wait
+ for its child and then continue without accumulating
+ zombie children. */
+ ipid = ixsfork ();
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ ulog_id (getpid ());
+
+ return TRUE;
+ }
+
+ (void) t_close (onew);
+
+ /* Now wait for the child. */
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ }
+
+ /* We got a signal. */
+ usysdep_exit (FALSE);
+
+ /* Avoid compiler warnings. */
+ return FALSE;
+}
+
+/* Close the port. */
+
+/*ARGSUSED*/
+static boolean
+ftli_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ fret = TRUE;
+ if (qsysdep->o >= 0)
+ {
+ if (qsysdep->ftli)
+ {
+ if (t_close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "t_close: %s", ztlierror ());
+ fret = FALSE;
+ }
+ }
+ else
+ {
+ if (close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ }
+
+ qsysdep->o = -1;
+ }
+
+ return fret;
+}
+
+/* Reset the port. This will be called by a child which was forked
+ off in ftli_open, above. We don't want uucico to continue looping
+ and giving login prompts, so we pretend that we received a SIGINT
+ signal. This should probably be handled more cleanly. The signal
+ will not be recorded in the log file because we don't set
+ afLog_signal[INDEXSIG_SIGINT]. */
+
+/*ARGSUSED*/
+static boolean
+ftli_reset (qconn)
+ struct sconnection *qconn;
+{
+ afSignal[INDEXSIG_SIGINT] = TRUE;
+ return TRUE;
+}
+
+/* Dial out on a TLI port, so to speak: connect to a remote computer. */
+
+/*ARGSUSED*/
+static boolean
+ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ struct ssysdep_conn *qsysdep;
+ char **pzdialer;
+ const char *zaddr;
+ struct t_call *qtcall;
+ char *zescape;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
+ if (*pzdialer == NULL)
+ pzdialer = NULL;
+
+ /* If the first dialer is "TLI" or "TLIS", we use the first token
+ (pzdialer[1]) as the address to connect to. */
+ zaddr = zphone;
+ if (pzdialer != NULL
+ && (strcmp (pzdialer[0], "TLI") == 0
+ || strcmp (pzdialer[0], "TLIS") == 0))
+ {
+ if (pzdialer[1] == NULL)
+ ++pzdialer;
+ else
+ {
+ if (strcmp (pzdialer[1], "\\D") != 0
+ && strcmp (pzdialer[1], "\\T") != 0)
+ zaddr = pzdialer[1];
+ pzdialer += 2;
+ }
+ }
+
+ if (zaddr == NULL)
+ {
+ ulog (LOG_ERROR, "No address for TLI connection");
+ return FALSE;
+ }
+
+ qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR);
+ if (qtcall == NULL)
+ {
+ ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ());
+ return FALSE;
+ }
+
+ zescape = zbufcpy (zaddr);
+ qtcall->addr.len = cescape (zescape);
+ if (qtcall->addr.len > qtcall->addr.maxlen)
+ {
+ ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr,
+ qtcall->addr.maxlen);
+ ubuffree (zescape);
+ return FALSE;
+ }
+ memcpy (qtcall->addr.buf, zescape, qtcall->addr.len);
+ ubuffree (zescape);
+
+ if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0)
+ {
+ if (t_errno != TLOOK)
+ ulog (LOG_ERROR, "t_connect: %s", ztlierror ());
+ else
+ {
+ if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
+ ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ());
+ else
+ ulog (LOG_ERROR, "Connection refused");
+ }
+ return FALSE;
+ }
+
+ /* We've connected to the remote. Push any desired modules. */
+ if (! ftli_push (qconn))
+ return FALSE;
+
+ /* Handle the rest of the dialer sequence. This is similar to
+ fmodem_dial, and they should, perhaps, be combined somehow. */
+ if (pzdialer != NULL)
+ {
+ boolean ffirst;
+
+ ffirst = TRUE;
+ while (*pzdialer != NULL)
+ {
+ int iuuconf;
+ struct uuconf_dialer *q;
+ struct uuconf_dialer s;
+ const char *ztoken;
+ boolean ftranslate;
+
+ if (! ffirst)
+ q = &s;
+ else
+ q = qdialer;
+
+ iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+
+ ++pzdialer;
+ ztoken = *pzdialer;
+
+ ftranslate = FALSE;
+ if (ztoken == NULL
+ || strcmp (ztoken, "\\D") == 0)
+ ztoken = zphone;
+ else if (strcmp (ztoken, "\\T") == 0)
+ {
+ ztoken = zphone;
+ ftranslate = TRUE;
+ }
+
+ if (! fchat (qconn, puuconf, &q->uuconf_schat,
+ (const struct uuconf_system *) NULL, q,
+ zphone, ftranslate, qconn->qport->uuconf_zname,
+ (long) 0))
+ {
+ (void) uuconf_dialer_free (puuconf, q);
+ if (! ffirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+ return FALSE;
+ }
+
+ if (ffirst)
+ {
+ *ptdialerfound = DIALERFOUND_FREE;
+ ffirst = FALSE;
+ }
+ else
+ (void) uuconf_dialer_free (puuconf, q);
+
+ if (*pzdialer != NULL)
+ ++pzdialer;
+ }
+ }
+
+ return TRUE;
+}
+
+#endif /* HAVE_TLI */
diff --git a/gnu/libexec/uucp/common_sources/trans.h b/gnu/libexec/uucp/common_sources/trans.h
new file mode 100644
index 00000000000..79c380ea48d
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/trans.h
@@ -0,0 +1,268 @@
+/* trans.h
+ Header file for file and command transfer routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* The maximum possible number of channels. */
+#define IMAX_CHAN (16)
+
+/* The ifeatures field of the sdaemon structure is an or of the
+ following values. These values are sent during the uucico
+ handshake, and MUST NOT CHANGE. */
+
+/* File size negotiation. */
+#define FEATURE_SIZES (01)
+
+/* File transfer restart. */
+#define FEATURE_RESTART (02)
+
+/* The E (execute) command. */
+#define FEATURE_EXEC (04)
+
+/* Version 1.03: requires decimal size in S and R command. Needless
+ to say, this should not be used by any new programs. */
+#define FEATURE_V103 (010)
+
+/* SVR4 UUCP: expects dummy string between notify field and size field
+ in send command. There is probably some meaning to this string,
+ but I don't know what it is. If I ever find out, this flag will
+ still be used to indicate it. */
+#define FEATURE_SVR4 (020)
+
+/* This structure is used to hold information concerning the
+ communication link established with the remote system. */
+
+struct sdaemon
+{
+ /* Global uuconf pointer. */
+ pointer puuconf;
+ /* Remote system information. */
+ const struct uuconf_system *qsys;
+ /* Local name being used. */
+ const char *zlocalname;
+ /* Connection structure. */
+ struct sconnection *qconn;
+ /* Protocol being used. */
+ const struct sprotocol *qproto;
+ /* The largest file size permitted for a local request. */
+ long clocal_size;
+ /* The largest file size permitted for a remote request. */
+ long cremote_size;
+ /* The largest file size that may ever be transferred. */
+ long cmax_ever;
+ /* The remote system ulimit. */
+ long cmax_receive;
+ /* Features supported by the remote side. */
+ int ifeatures;
+ /* TRUE if we should request the remote side to hang up. */
+ boolean frequest_hangup;
+ /* TRUE if the remote side requested a hangup. */
+ boolean fhangup_requested;
+ /* TRUE if we are hanging up. */
+ boolean fhangup;
+ /* TRUE if the local system is currently the master. */
+ boolean fmaster;
+ /* TRUE if the local system placed the call. */
+ boolean fcaller;
+ /* UUCONF_RELIABLE_* flags for the connection. */
+ int ireliable;
+ /* If fcaller is FALSE, the lowest grade which may be transferred
+ during this call. */
+ char bgrade;
+};
+
+/* This structure is used to hold a file or command transfer which is
+ in progress. */
+
+struct stransfer
+{
+ /* Next file transfer in queue. */
+ struct stransfer *qnext;
+ /* Previous file transfer in queue. */
+ struct stransfer *qprev;
+ /* Points to the queue this structure is on. */
+ struct stransfer **pqqueue;
+ /* The function to call to send some data. */
+ boolean (*psendfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon));
+ /* The function to call when data is received. */
+ boolean (*precfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon,
+ const char *zdata, size_t cdata));
+ /* Type specific information. */
+ pointer pinfo;
+ /* TRUE if we are sending the file e (this is used to avoid a call
+ to psendfn). */
+ boolean fsendfile;
+ /* TRUE if we are receiving the file e (this is used to avoid a call
+ to precfn). */
+ boolean frecfile;
+ /* The file to read or write. */
+ openfile_t e;
+ /* The position we are at in the file. */
+ long ipos;
+ /* TRUE if we are waiting for a command string. */
+ boolean fcmd;
+ /* The command string we have so far. */
+ char *zcmd;
+ /* The length of the command string we have so far. */
+ size_t ccmd;
+ /* Local destination number. */
+ int ilocal;
+ /* Remote destination number. */
+ int iremote;
+ /* The command. */
+ struct scmd s;
+ /* A message to log when work starts. */
+ char *zlog;
+ /* The process time; imicros can be negative. */
+ long isecs;
+ long imicros;
+ /* Number of bytes sent or received. */
+ long cbytes;
+};
+
+/* Reasons that a file transfer might fail. */
+
+enum tfailure
+{
+ /* No failure. */
+ FAILURE_NONE,
+ /* No permission for operation. */
+ FAILURE_PERM,
+ /* Can't open necessary file. */
+ FAILURE_OPEN,
+ /* Not enough space to receive file. */
+ FAILURE_SIZE,
+ /* File was received in a previous conversation. */
+ FAILURE_RECEIVED
+};
+
+/* The main loop which talks to the remote system, passing transfer
+ requests and file back and forth. */
+extern boolean floop P((struct sdaemon *qdaemon));
+
+/* Allocate a new transfer structure. */
+extern struct stransfer *qtransalc P((struct scmd *qcmd));
+
+/* Free a transfer structure. */
+extern void utransfree P((struct stransfer *qtrans));
+
+/* Queue up local requests. If pfany is not NULL, this sets *pfany to
+ TRUE if there are, in fact, any local requests which can be done at
+ this point. */
+extern boolean fqueue P((struct sdaemon *qdaemon, boolean *pfany));
+
+/* Clear away any queued requests. This may be called more than once
+ at the end of a call. */
+extern void uclear_queue P((struct sdaemon *qdaemon));
+
+/* Queue a new transfer request made by the local system. */
+extern boolean fqueue_local P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* Queue a new transfer request made by the remote system. */
+extern boolean fqueue_remote P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* Queue a transfer request which wants to send something. */
+extern boolean fqueue_send P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* Queue a transfer request which wants to receiving something. */
+extern boolean fqueue_receive P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* Prepare to send a file by local or remote request. */
+extern boolean flocal_send_file_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd));
+extern boolean fremote_send_file_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd,
+ int iremote));
+
+/* Prepare to receive a file by local or remote request. */
+extern boolean flocal_rec_file_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd));
+extern boolean fremote_rec_file_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd,
+ int iremote));
+
+/* Prepare to request work by local or remote request. */
+extern boolean flocal_xcmd_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd));
+extern boolean fremote_xcmd_init P((struct sdaemon *qdaemon,
+ struct scmd *qcmd,
+ int iremote));
+
+/* We have lost the connection; record any in progress file transfers
+ in the statistics file and discard any temporary files. */
+extern void ufailed P((struct sdaemon *qdaemon));
+
+/* Check that there is enough disk space for a file receive. Return
+ FALSE if there is not. */
+extern boolean frec_check_free P((struct stransfer *qtrans,
+ long cfree_space));
+
+/* Discard the temporary file being used to receive a file, if
+ appropriate. */
+extern boolean frec_discard_temp P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* Handle data received by a protocol. This is called by the protocol
+ specific routines as data comes in. The data is passed as two
+ buffers because that is convenient for packet based protocols, but
+ normally csecond will be 0. The ilocal argument is the local
+ channel number, and the iremote argument is the remote channel
+ number. Either may be -1, if the protocol does not have channels.
+ The ipos argument is the position in the file, if the protocol
+ knows it; for most protocols, this will be -1. The fallacked
+ argument should be set to TRUE if the remote has acknowledged all
+ outstanding data; see uwindow_acked, below, for details. This will
+ set *pfexit to TRUE if there is something for the main loop to do.
+ A file is complete is when a zero length buffer is passed (cfirst
+ == 0). A command is complete when data containing a null byte is
+ passed. This will return FALSE on error. If the protocol pfwait
+ entry point should exit and let the top level loop continue,
+ *pfexit will be set to TRUE (if pfexit is not NULL). This will not
+ set *pfexit to FALSE, so the caller must do that. */
+extern boolean fgot_data P((struct sdaemon *qdaemon,
+ const char *zfirst, size_t cfirst,
+ const char *zsecond, size_t csecond,
+ int ilocal, int iremote,
+ long ipos, boolean fallacked,
+ boolean *pfexit));
+
+/* This routine is called when an ack is sent for a file receive. */
+extern void usent_receive_ack P((struct sdaemon *qdaemon,
+ struct stransfer *qtrans));
+
+/* A protocol may call this routine to indicate the packets have been
+ acknowledged by the remote system. If the fallacked argument is
+ TRUE, then all outstanding packets have been acknowledged; for
+ convenience, this may also be indicated by passing fallacked as
+ TRUE to fgot_data, above. Otherwise this routine should be called
+ each time a complete window is acked by the remote system. The
+ transfer code uses this information to keep track of when an
+ acknowledgement of a file receive has been seen by the other side,
+ so that file receives may be handled cleanly if the connection is
+ lost. */
+extern void uwindow_acked P((struct sdaemon *qdaemon,
+ boolean fallacked));
diff --git a/gnu/libexec/uucp/common_sources/util.c b/gnu/libexec/uucp/common_sources/util.c
new file mode 100644
index 00000000000..2ddc2608ddc
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/util.c
@@ -0,0 +1,144 @@
+/* util.c
+ A couple of UUCP utility functions.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char util_rcsid[] = "$Id: util.c,v 1.1 1993/08/04 19:31:13 jtc Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+
+/* Get information for an unknown system. This will leave the name
+ allocated on the heap. We could fix this by breaking the
+ abstraction and adding the name to qsys->palloc. It makes sure the
+ name is not too long, but takes no other useful action. */
+
+boolean
+funknown_system (puuconf, zsystem, qsys)
+ pointer puuconf;
+ const char *zsystem;
+ struct uuconf_system *qsys;
+{
+ char *z;
+ int iuuconf;
+
+ if (strlen (zsystem) <= cSysdep_max_name_len)
+ z = zbufcpy (zsystem);
+ else
+ {
+ char **pznames, **pz;
+ boolean ffound;
+
+ z = zbufalc (cSysdep_max_name_len + 1);
+ memcpy (z, zsystem, cSysdep_max_name_len);
+ z[cSysdep_max_name_len] = '\0';
+
+ iuuconf = uuconf_system_names (puuconf, &pznames, TRUE);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ ffound = FALSE;
+ for (pz = pznames; *pz != NULL; pz++)
+ {
+ if (strcmp (*pz, z) == 0)
+ ffound = TRUE;
+ xfree ((pointer) *pz);
+ }
+ xfree ((pointer) pznames);
+
+ if (ffound)
+ {
+ ubuffree (z);
+ return FALSE;
+ }
+ }
+
+ iuuconf = uuconf_system_unknown (puuconf, qsys);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ubuffree (z);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
+ qsys->uuconf_zname = z;
+
+ return TRUE;
+}
+
+/* See whether a file is in a directory list, and make sure the user
+ has appropriate access. */
+
+boolean
+fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser)
+ const char *zfile;
+ char **pzdirs;
+ const char *zpubdir;
+ boolean fcheck;
+ boolean freadable;
+ const char *zuser;
+{
+ boolean fmatch;
+ char **pz;
+
+ fmatch = FALSE;
+
+ for (pz = pzdirs; *pz != NULL; pz++)
+ {
+ char *zuse;
+
+ if (pz[0][0] == '!')
+ {
+ zuse = zsysdep_local_file (*pz + 1, zpubdir);
+ if (zuse == NULL)
+ return FALSE;
+
+ if (fsysdep_in_directory (zfile, zuse, FALSE,
+ FALSE, (const char *) NULL))
+ fmatch = FALSE;
+ }
+ else
+ {
+ zuse = zsysdep_local_file (*pz, zpubdir);
+ if (zuse == NULL)
+ return FALSE;
+
+ if (fsysdep_in_directory (zfile, zuse, fcheck,
+ freadable, zuser))
+ fmatch = TRUE;
+ }
+
+ ubuffree (zuse);
+ }
+
+ return fmatch;
+}
diff --git a/gnu/libexec/uucp/common_sources/uuconf.h b/gnu/libexec/uucp/common_sources/uuconf.h
new file mode 100644
index 00000000000..4bf6bccbf3f
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/uuconf.h
@@ -0,0 +1,1496 @@
+/* uuconf.h
+ Header file for UUCP configuration routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The use of an object file which uses material from this header
+ file, and from no other portion of the uuconf library, is
+ unrestricted, as described in paragraph 4 of section 5 of version 2
+ of the GNU Library General Public License (this sentence is merely
+ informative, and does not modify the License in any way).
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef UUCONF_H
+
+#define UUCONF_H
+
+#include <stdio.h>
+
+/* The macro UUCONF_ANSI_C may be used to override __STDC__. */
+#ifndef UUCONF_ANSI_C
+#ifdef __STDC__
+#define UUCONF_ANSI_C 1
+#else /* ! defined (__STDC__) */
+#define UUCONF_ANSI_C 0
+#endif /* ! defined (__STDC__) */
+#endif /* ! defined (UUCONF_ANSI_C) */
+
+#if UUCONF_ANSI_C
+#define UUCONF_CONST const
+typedef void *UUCONF_POINTER;
+#include <stddef.h>
+typedef size_t UUCONF_SIZE_T;
+#else
+#define UUCONF_CONST
+typedef char *UUCONF_POINTER;
+typedef unsigned int UUCONF_SIZE_T;
+#endif
+
+/* The field names of each of the following structures begin with
+ "uuconf_". This is to avoid any conflicts with user defined
+ macros. The first character following the "uuconf_" string
+ indicates the type of the field.
+
+ z -- a string (char *)
+ c -- a count (normally int)
+ i -- an integer value (normally int)
+ f -- a boolean value (normally int)
+ b -- a single character value (char or int)
+ t -- an enum (enum XX)
+ s -- a structure (struct XX)
+ u -- a union (union XX)
+ q -- a pointer to a structure (struct XX *)
+ p -- a pointer to something other than a string
+ */
+
+/* The information which is kept for a chat script. */
+
+struct uuconf_chat
+{
+ /* The script itself. This is a NULL terminated list of expect/send
+ pairs. The first string is an expect string. A string starting
+ with a '-' indicates subsend string; the following strings which
+ start with '-' are subexpect/subsend strings. This field may be
+ NULL, in which case there is no chat script (but pzprogram may
+ hold a program to run). */
+ char **uuconf_pzchat;
+ /* The chat program to run. This is a NULL terminated list of
+ arguments; element 0 if the program. May be NULL, in which case
+ there is no program. */
+ char **uuconf_pzprogram;
+ /* The timeout in seconds to use for expect strings in the chat
+ script. */
+ int uuconf_ctimeout;
+ /* The NULL terminated list of failure strings. If any of these
+ strings appear, the chat script is aborted. May be NULL, in
+ which case there are no failure strings. */
+ char **uuconf_pzfail;
+ /* Non-zero if incoming characters should be stripped to seven bits
+ (by anding with 0x7f). */
+ int uuconf_fstrip;
+};
+
+/* The information which is kept for a time specification. This is a
+ linked list of structures. Each element of the list represents a
+ span of time, giving a starting time and an ending time. The time
+ only depends on the day of the week, not on the day of the month or
+ of the year. The time is only specified down to the minute, not
+ down to the second or below. The list is sorted by starting time.
+
+ The starting and ending time are expressed in minutes since the
+ beginning of the week, which is considered to be 12 midnight on
+ Sunday. Thus 60 is 1 am on Sunday, 1440 (== 60 * 24) is 12
+ midnight on Monday, and the largest possible value is 10080 (== 60
+ * 24 * 7) which is 12 midnight on the following Sunday.
+
+ Each span of time has a value associated with it. This is the
+ lowest grade or the largest file size that may be transferred
+ during that time, depending on the source of the time span. When
+ time specifications overlap, the value used for the overlap is the
+ higher grade or the smaller file size. Thus specifying
+ ``call-timegrade z Any'' and ``call-timegrade Z Mo'' means that
+ only grade Z or higher may be sent on Monday, since Z is the higer
+ grade of the overlapping spans. The final array wil have no
+ overlaps.
+
+ Each span also has a retry time associated with it. This permits
+ different retry times to be used at different times of day. The
+ retry time is only relevant if the span came from a ``time'' or
+ ``timegrade'' command for a system. */
+
+struct uuconf_timespan
+{
+ /* Next element in list. */
+ struct uuconf_timespan *uuconf_qnext;
+ /* Starting minute (-1 at the end of the array). */
+ int uuconf_istart;
+ /* Ending minute. */
+ int uuconf_iend;
+ /* Value for this span (lowest grade or largest file that may be
+ transferred at this time). */
+ long uuconf_ival;
+ /* Retry time. */
+ int uuconf_cretry;
+};
+
+/* The information which is kept for protocol parameters. Protocol
+ parameter information is stored as an array of the following
+ structures. */
+
+struct uuconf_proto_param
+{
+ /* The name of the protocol to which this entry applies. This is
+ '\0' for the last element of the array. */
+ int uuconf_bproto;
+ /* Specific entries for this protocol. This points to an array
+ ending in an element with a uuconf_cargs field of 0. */
+ struct uuconf_proto_param_entry *uuconf_qentries;
+};
+
+/* Each particular protocol parameter entry is one of the following
+ structures. */
+
+struct uuconf_proto_param_entry
+{
+ /* The number of arguments to the ``protocol-parameter'' command
+ (not counting ``protocol-parameter'' itself). This is 0 for the
+ last element of the array. */
+ int uuconf_cargs;
+ /* The actual arguments to the ``protocol-parameter'' command; this
+ is an array with cargs entries. */
+ char **uuconf_pzargs;
+};
+
+/* The information which is kept for a system. The zname and zalias
+ fields will be the same for all alternates. Every other fields is
+ specific to the particular alternate in which it appears (although
+ most will be the same for all alternates). */
+
+struct uuconf_system
+{
+ /* The name of the system. */
+ char *uuconf_zname;
+ /* A list of aliases for the system. This is a NULL terminated list
+ of strings. May be NULL, in which case there are no aliases. */
+ char **uuconf_pzalias;
+ /* A linked list of alternate call in or call out information. Each
+ alternative way to call this system occupies an element of this
+ list. May be NULL, in which case there are no alternates. */
+ struct uuconf_system *uuconf_qalternate;
+ /* The name for this particular alternate. May be NULL, in which
+ case this alternate does not have a name. */
+ char *uuconf_zalternate;
+ /* If non-zero, this alternate may be used for calling out. */
+ int uuconf_fcall;
+ /* If non-zero, this alternate may be used for accepting a call. */
+ int uuconf_fcalled;
+ /* The times at which this system may be called. The ival field of
+ each uuconf_timespan structure is the lowest grade which may be
+ transferred at that time. The cretry field is the number of
+ minutes to wait before retrying the call, or 0 if it was not
+ specified. May be NULL, in which case the system may never be
+ called. */
+ struct uuconf_timespan *uuconf_qtimegrade;
+ /* The times at which to request a particular grade of the system
+ when calling it, and the grades to request. The ival field of
+ each uuconf_timespan structure is the lowest grade which the
+ other system should transfer at that time. May be NULL, in which
+ case there are no grade restrictions. */
+ struct uuconf_timespan *uuconf_qcalltimegrade;
+ /* The maximum number of times to retry calling this system. If
+ this is 0, there is no limit. */
+ int uuconf_cmax_retries;
+ /* The number of minutes to wait between successful calls to a
+ system. */
+ int uuconf_csuccess_wait;
+ /* The size restrictions by time for local requests during a locally
+ placed call. The ival field of each uuconf_timespan structure is
+ the size in bytes of the largest file which may be transferred at
+ that time. May be NULL, in which case there are no size
+ restrictions. */
+ struct uuconf_timespan *uuconf_qcall_local_size;
+ /* The size restrictions by time for remote requests during a
+ locally placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcall_remote_size;
+ /* The size restrictions by time for local requests during a
+ remotely placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcalled_local_size;
+ /* The size restrictions by time for remote requests during a
+ remotely placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcalled_remote_size;
+ /* Baud rate, or speed. Zero means any baud rate. If ihighbaud is
+ non-zero, this is the low baud rate of a range. */
+ long uuconf_ibaud;
+ /* If non-zero, ibaud is the low baud rate of a range and ihighbaud
+ is the high baud rate. */
+ long uuconf_ihighbaud;
+ /* Port name to use. May be NULL. If an HDB configuration file
+ contains a modem class (alphabetic characters preceeding the baud
+ rate), the class is appended to the port name. */
+ char *uuconf_zport;
+ /* Specific port information, if the system entry includes port
+ information. May be NULL. */
+ struct uuconf_port *uuconf_qport;
+ /* Phone number to call, or address to use for a TCP connection.
+ May be NULL, in which case a dialer script may not use \D or \T
+ for this system, and a TCP port will use the system name. */
+ char *uuconf_zphone;
+ /* Chat script to use when logging in to the system. */
+ struct uuconf_chat uuconf_schat;
+ /* Login name to use for \L in the login chat script. This should
+ normally be accessed via uuconf_callout. If it is "*",
+ uuconf_callout will look it up in the call out file. This may be
+ NULL, in which case the login script may not use \L. */
+ char *uuconf_zcall_login;
+ /* Password to use for \P in the login chat script. This should
+ normally be accessed via uuconf_callout. If it is "*",
+ uuconf_callout will look it up in the call out file. This may be
+ NULL, in which case the login script may not use \P. */
+ char *uuconf_zcall_password;
+ /* The login name this system must use when calling in. This may be
+ different for different alternates. This should only be examined
+ if uuconf_fcalled is TRUE. If this is NULL or "ANY" then
+ uuconf_validate must be called to make sure that whatever login
+ name was used is permitted for this machine. */
+ char *uuconf_zcalled_login;
+ /* If non-zero, then when this system calls in the call should not
+ be allowed to proceed and the system should be called back. */
+ int uuconf_fcallback;
+ /* If non-zero, then conversation sequence numbers should be used
+ with this system. */
+ int uuconf_fsequence;
+ /* A list of protocols to use with this system. Each protocol has a
+ single character name. May be NULL, in which case any known
+ protocol may be used. */
+ char *uuconf_zprotocols;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* Chat script to run when called by this system. */
+ struct uuconf_chat uuconf_scalled_chat;
+ /* Debugging level to set during a conversation. May be NULL. */
+ char *uuconf_zdebug;
+ /* Maximum remote debugging level this system may request. May be
+ NULL. */
+ char *uuconf_zmax_remote_debug;
+ /* Non-zero if the remote system may request us to send files from
+ the local system to the remote. */
+ int uuconf_fsend_request;
+ /* Non-zero if the remote system may request us to receive files
+ from the remote system to the local. */
+ int uuconf_frec_request;
+ /* Non-zero if local requests are permitted when calling this
+ system. */
+ int uuconf_fcall_transfer;
+ /* Non-zero if local requests are permitted when this system calls
+ in. */
+ int uuconf_fcalled_transfer;
+ /* NULL terminated list of directories from which files may be sent
+ by local request. */
+ char **uuconf_pzlocal_send;
+ /* NULL terminated list of directories from which files may be sent
+ by remote request. */
+ char **uuconf_pzremote_send;
+ /* NULL terminated list of directories into which files may be
+ received by local request. */
+ char **uuconf_pzlocal_receive;
+ /* NULL terminated list of directories into which files may be
+ received by remote request. */
+ char **uuconf_pzremote_receive;
+ /* Path to use for command execution. This is a NULL terminated
+ list of directories. */
+ char **uuconf_pzpath;
+ /* NULL terminated List of commands that may be executed. */
+ char **uuconf_pzcmds;
+ /* Amount of free space to leave when accepting a file from this
+ system, in bytes. */
+ long uuconf_cfree_space;
+ /* NULL terminated list of systems that this system may forward
+ from. May be NULL if there are no systems from which files may
+ be forwarded. The list may include "ANY". */
+ char **uuconf_pzforward_from;
+ /* NULL terminated list of systems that this system may forward to.
+ May be NULL if there are no systems to which files may be
+ forwarded. The list may include "ANY". */
+ char **uuconf_pzforward_to;
+ /* The public directory to use for this sytem. */
+ const char *uuconf_zpubdir;
+ /* The local name to use for this remote system. May be NULL if the
+ usual local name should be used. */
+ char *uuconf_zlocalname;
+ /* Memory allocation block for the system. */
+ UUCONF_POINTER uuconf_palloc;
+};
+
+/* Types of ports. */
+
+enum uuconf_porttype
+{
+ /* Unknown port type. A port of this type should never be returned
+ by the uuconf functions. */
+ UUCONF_PORTTYPE_UNKNOWN,
+ /* Read from standard input and write to standard output. Not
+ normally used. */
+ UUCONF_PORTTYPE_STDIN,
+ /* A modem port. */
+ UUCONF_PORTTYPE_MODEM,
+ /* A direct connect port. */
+ UUCONF_PORTTYPE_DIRECT,
+ /* A TCP port. Not supported on all systems. */
+ UUCONF_PORTTYPE_TCP,
+ /* A TLI port. Not supported on all systems. */
+ UUCONF_PORTTYPE_TLI
+};
+
+/* Additional information for a stdin port (there is none). */
+
+struct uuconf_stdin_port
+{
+ int uuconf_idummy;
+};
+
+/* Additional information for a modem port. */
+
+struct uuconf_modem_port
+{
+ /* The device name. May be NULL, in which case the port name is
+ used instead. */
+ char *uuconf_zdevice;
+ /* The device name to send the dialer chat script to. May be NULL,
+ in which case the chat script is sent to the usual device. */
+ char *uuconf_zdial_device;
+ /* The default baud rate (speed). If zero, there is no default. */
+ long uuconf_ibaud;
+ /* The low baud rate, if a range is used. If zero, a range is not
+ used and ihighbaud should be ignored. */
+ long uuconf_ilowbaud;
+ /* The high baud rate, if ilowbaud is non-zero. */
+ long uuconf_ihighbaud;
+ /* Non-zero if the port supports carrier detect. */
+ int uuconf_fcarrier;
+ /* A NULL terminated sequence of dialer/token pairs (element 0 is a
+ dialer name, element 1 is a token, etc.) May be NULL, in which
+ case qdialer should not be NULL. */
+ char **uuconf_pzdialer;
+ /* Specific dialer information. Only used if pzdialer is NULL. */
+ struct uuconf_dialer *uuconf_qdialer;
+};
+
+/* Additional information for a direct connect port. */
+
+struct uuconf_direct_port
+{
+ /* The device name. May be NULL, in which case the port name is
+ used instead. */
+ char *uuconf_zdevice;
+ /* The baud rate (speed). */
+ long uuconf_ibaud;
+};
+
+/* Additional information for a TCP port. */
+
+struct uuconf_tcp_port
+{
+ /* The TCP port number to use. May be a name or a number. May be
+ NULL, in which case "uucp" is looked up using getservbyname. */
+ char *uuconf_zport;
+};
+
+/* Additional information for a TLI port. */
+
+struct uuconf_tli_port
+{
+ /* Device name to open. May be NULL, in which case the port name is
+ used. */
+ char *uuconf_zdevice;
+ /* Whether this port should be turned into a stream, permitting the
+ read and write calls instead of the t_rcv and t_send calls. */
+ int uuconf_fstream;
+ /* A NULL terminated list of modules to push after making the
+ connection. May be NULL, in which case if fstream is non-zero,
+ then "tirdwr" is pushed onto the stream, and otherwise nothing is
+ pushed. */
+ char **uuconf_pzpush;
+ /* A NULL terminated sequence of dialer/token pairs (element 0 is a
+ dialer name, element 1 is a token, etc.) May be NULL. If
+ element 0 is TLI or TLIS, element 1 is used as the address to
+ connect to; otherwise uuconf_zphone from the system information
+ is used. */
+ char **uuconf_pzdialer;
+ /* Address to use when operating as a server. This may contain
+ escape sequences. */
+ char *uuconf_zservaddr;
+};
+
+/* Information kept for a port. */
+
+struct uuconf_port
+{
+ /* The name of the port. */
+ char *uuconf_zname;
+ /* The type of the port. */
+ enum uuconf_porttype uuconf_ttype;
+ /* The list of protocols supported by the port. The name of each
+ protocol is a single character. May be NULL, in which case any
+ protocol is permitted. */
+ char *uuconf_zprotocols;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* The set of reliability bits. */
+ int uuconf_ireliable;
+ /* The lock file name to use. */
+ char *uuconf_zlockname;
+ /* Memory allocation block for the port. */
+ UUCONF_POINTER uuconf_palloc;
+ /* The type specific information. */
+ union
+ {
+ struct uuconf_stdin_port uuconf_sstdin;
+ struct uuconf_modem_port uuconf_smodem;
+ struct uuconf_direct_port uuconf_sdirect;
+ struct uuconf_tcp_port uuconf_stcp;
+ struct uuconf_tli_port uuconf_stli;
+ } uuconf_u;
+};
+
+/* Information kept about a dialer. */
+
+struct uuconf_dialer
+{
+ /* The name of the dialer. */
+ char *uuconf_zname;
+ /* The chat script to use when dialing out. */
+ struct uuconf_chat uuconf_schat;
+ /* The string to send when a `=' appears in the phone number. */
+ char *uuconf_zdialtone;
+ /* The string to send when a `-' appears in the phone number. */
+ char *uuconf_zpause;
+ /* Non-zero if the dialer supports carrier detect. */
+ int uuconf_fcarrier;
+ /* The number of seconds to wait for carrier after the chat script
+ is complete. Only used if fcarrier is non-zero. Only supported
+ on some systems. */
+ int uuconf_ccarrier_wait;
+ /* If non-zero, DTR should be toggled before dialing. Only
+ supported on some systems. */
+ int uuconf_fdtr_toggle;
+ /* If non-zero, sleep for 1 second after toggling DTR. Ignored if
+ fdtr_toggle is zero. */
+ int uuconf_fdtr_toggle_wait;
+ /* The chat script to use when a call is complete. */
+ struct uuconf_chat uuconf_scomplete;
+ /* The chat script to use when a call is aborted. */
+ struct uuconf_chat uuconf_sabort;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* The set of reliability bits. */
+ int uuconf_ireliable;
+ /* Memory allocation block for the dialer. */
+ UUCONF_POINTER uuconf_palloc;
+};
+
+/* Reliability bits for the ireliable field of ports and dialers.
+ These bits are used to decide which protocol to run. A given
+ protocol will have a set of these bits, and each of them must be
+ turned on for the port before we will permit that protocol to be
+ used. This will be overridden by the zprotocols field. */
+
+/* Whether a set of reliability bits is given. If this bit is not
+ set, then there is no reliability information. */
+#define UUCONF_RELIABLE_SPECIFIED (01)
+
+/* Set if the connection is eight bit transparent. */
+#define UUCONF_RELIABLE_EIGHT (02)
+
+/* Set if the connection is error-free. */
+#define UUCONF_RELIABLE_RELIABLE (04)
+
+/* Set if the connection is end-to-end reliable (e.g. TCP). */
+#define UUCONF_RELIABLE_ENDTOEND (010)
+
+/* Set if the connection is full-duplex; that is, no time consuming
+ line turnaround is required before sending data in the reverse
+ direction. If the connection is truly half-duplex, in the sense
+ that communication can only flow in one direction, UUCP can not be
+ used. */
+#define UUCONF_RELIABLE_FULLDUPLEX (020)
+
+/* UUCP grades range from 0 to 9, A to Z, a to z in order from highest
+ to lowest (work of higher grades is done before work of lower
+ grades). */
+
+/* The highest grade. */
+#define UUCONF_GRADE_HIGH ('0')
+
+/* The lowest grade. */
+#define UUCONF_GRADE_LOW ('z')
+
+/* Whether a character is a legal grade (requires <ctype.h>). */
+#define UUCONF_GRADE_LEGAL(b) (isalnum ((unsigned) (b)))
+
+/* Return < 0 if the first grade should be done before the second
+ grade, == 0 if they are the same, or > 0 if the first grade should
+ be done after the second grade. On an ASCII system, this can just
+ be b1 - b2. */
+#define UUCONF_GRADE_CMP(b1, b2) (uuconf_grade_cmp ((b1), (b2)))
+
+/* Most of the uuconf functions returns an error code. A value of
+ zero (UUCONF_SUCCESS) indicates success. */
+
+/* If this bit is set in the returned error code, then the
+ uuconf_errno function may be used to obtain the errno value as set
+ by the function which caused the failure. */
+#define UUCONF_ERROR_ERRNO (0x100)
+
+/* If this bit is set in the returned error code, then the
+ uuconf_filename function may be used to get the name of a file
+ associated with the error. */
+#define UUCONF_ERROR_FILENAME (0x200)
+
+/* If this bit is set in the returned error code, then the
+ uuconf_lineno function may be used to get a line number associated
+ with the error; normally if this is set UUCONF_ERROR_FILENAME will
+ also be set. */
+#define UUCONF_ERROR_LINENO (0x400)
+
+/* There are two UUCONF_CMDTABRET bits that may be set in the return
+ value of uuconf_cmd_line or uuconf_cmd_args, described below. They
+ do not indicate an error, but instead give instructions to the
+ calling function, often uuconf_cmd_file. They may also be set in
+ the return value of a user function listed in a uuconf_cmdtab
+ table, in which case they will be honored by uuconf_cmd_file. */
+
+/* This bit means that the memory occupied by the arguments passed to
+ the function should be preserved, and not overwritten or freed. It
+ refers only to the contents of the arguments; the contents of the
+ argv array itself may always be destroyed. If this bit is set in
+ the return value of uuconf_cmd_line or uuconf_cmd_args, it must be
+ honored. It will be honored by uuconf_cmd_file. This may be
+ combined with an error code or with UUCONF_CMDTABRET_EXIT, although
+ neither uuconf_cmd_file or uuconf_cmd_line will do so. */
+#define UUCONF_CMDTABRET_KEEP (0x800)
+
+/* This bit means that uuconf_cmd_file should exit, rather than go on
+ to read and process the next line. If uuconf_cmd_line or
+ uuconf_cmd_args encounter an error, the return value will have this
+ bit set along with the error code. A user function may set this
+ bit with or without an error; the return value of the user function
+ will be returned by uuconf_cmd_file, except that the
+ UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT bits will be
+ cleared. */
+#define UUCONF_CMDTABRET_EXIT (0x1000)
+
+/* This macro may be used to extract the specific error value. */
+#define UUCONF_ERROR_VALUE(i) ((i) & 0xff)
+
+/* UUCONF_ERROR_VALUE will return one of the following values. */
+
+/* Function succeeded. */
+#define UUCONF_SUCCESS (0)
+/* Named item not found. */
+#define UUCONF_NOT_FOUND (1)
+/* A call to fopen failed. */
+#define UUCONF_FOPEN_FAILED (2)
+/* A call to fseek failed. */
+#define UUCONF_FSEEK_FAILED (3)
+/* A call to malloc or realloc failed. */
+#define UUCONF_MALLOC_FAILED (4)
+/* Syntax error in file. */
+#define UUCONF_SYNTAX_ERROR (5)
+/* Unknown command. */
+#define UUCONF_UNKNOWN_COMMAND (6)
+
+#if UUCONF_ANSI_C
+
+/* For each type of configuration file (Taylor, V2, HDB), there are
+ separate routines to read various sorts of information. There are
+ also generic routines, which call on the appropriate type specific
+ routines. The library can be compiled to read any desired
+ combination of the configuration file types. This affects only the
+ generic routines, as it determines which type specific routines
+ they call. Thus, on a system which, for example, does not have any
+ V2 configuration files, there is no need to include the overhead of
+ the code to parse the files and the time to look for them.
+ However, a program which specifically wants to be able to parse
+ them can call the V2 specific routines.
+
+ The uuconf functions all take as an argument a pointer to uuconf
+ global information. This must be initialized by any the
+ initialization routines (the generic one and the three file type
+ specific ones) before any of the other uuconf functions may be
+ called. */
+
+/* Initialize the configuration file reading routines. The ppglobal
+ argument should point to a generic pointer (a void *, or, on older
+ compilers, a char *) which will be initialized and may then be
+ passed to the other uuconf routines. The zprogram argument is the
+ name of the program for which files should be read. A NULL is
+ taken as "uucp", and reads the standard UUCP configuration files.
+ The only other common argument is "cu", but any string is
+ permitted. The zname argument is the name of the Taylor UUCP
+ config file; if it is NULL, the default config file will be read.
+ If not reading Taylor UUCP configuration information, the argument
+ is ignored. This function must be called before any of the other
+ uuconf functions.
+
+ Note that if the zname argument is obtained from the user running
+ the program, the program should be careful to revoke any special
+ privileges it may have (e.g. on Unix call setuid (getuid ()) and
+ setgid (getgid ())). Otherwise various sorts of spoofing become
+ possible. */
+extern int uuconf_init (void **uuconf_ppglobal,
+ const char *uuconf_zprogram,
+ const char *uuconf_zname);
+
+/* Adjust the configuration file global pointer for a new thread. The
+ library is fully reentrant (with the exception of the function
+ uuconf_error_string, which calls strerror, which on some systems is
+ not reentrant), provided that each new thread that wishes to call
+ the library calls this function and uses the new global pointer
+ value. The ppglobal argument should be set to the address of the
+ global pointer set by any of the init functions; it will be
+ modified to become a new global pointer. */
+extern int uuconf_init_thread (void **uuconf_ppglobal);
+
+/* Get the names of all known systems. This sets sets *ppzsystems to
+ point to an array of system names. The list of names is NULL
+ terminated. The array is allocated using malloc, as is each
+ element of the array, and they may all be passed to free when they
+ are no longer needed. If the falias argument is 0, the list will
+ not include any aliases; otherwise, it will. */
+extern int uuconf_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for the system zsystem. This sets the fields
+ in *qsys. This will work whether zsystem is the official name of
+ the system or merely an alias. */
+extern int uuconf_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for an unknown (anonymous) system. The
+ uuconf_zname field of the returned system information will be NULL.
+ If no information is available for unknown systems, this will
+ return UUCONF_NOT_FOUND. This does not run the HDB remote.unknown
+ shell script. */
+extern int uuconf_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for the local system. Normally the local system
+ name should first be looked up using uuconf_system_info. If that
+ returns UUCONF_NOT_FOUND, this function may be used to get an
+ appropriate set of defaults. The uuconf_zname field of the
+ returned system information may be NULL. */
+extern int uuconf_system_local (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Free the memory occupied by system information returned by
+ uuconf_system_info, uuconf_system_unknown, uuconf_system_local, or
+ any of the configuration file type specific routines described
+ below. After this is called, the contents of the structure shall
+ not be referred to. */
+extern int uuconf_system_free (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+#ifdef __OPTIMIZE__
+#define uuconf_system_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Find a matching port. This will consider each port in turn.
+
+ If the zname argument is not NULL, the port's uuconf_zname field
+ must match it.
+
+ If the ibaud argument is not zero and the ihighbaud argument is
+ zero, the port's baud rate, if defined, must be the same (if the
+ port has a range of baud rates, ibaud must be within the range).
+ If ibaud and ihighbaud are both not zero, the port's baud rate, if
+ defined, must be between ibaud and ihighbaud inclusive (if the port
+ has a range of baud rates, the ranges must intersect). If the port
+ has no baud rate, either because it is a type of port for which
+ baud rate is not defined (e.g. a TCP port) or because the
+ uuconf_ibaud field is 0, the ibaud and ihighbaud arguments are
+ ignored.
+
+ If the pifn argument is not NULL, the port is passed to pifn, along
+ with the pinfo argument (which is otherwise ignored). If pifn
+ returns UUCONF_SUCCESS, the port matches. If pifn returns
+ UUCONF_NOT_FOUND, a new port is sought. Otherwise the return value
+ of pifn is returned from uuconf_find_port. The pifn function may
+ be used to further restrict the port, such as by modem class or
+ device name. It may also be used to lock the port, if appropriate;
+ in this case, if the lock fails, pifn may return UUCONF_NOT_FOUND
+ to force uuconf_find_port to continue searching for a port.
+
+ If the port matches, the information is set into uuconf_qport, and
+ uuconf_find_port returns UUCONF_SUCCESS. */
+extern int uuconf_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Free the memory occupied by system information returned by
+ uuconf_find_port (or any of the configuration file specific
+ routines described below). After this is called, the contents of
+ the structure shall not be referred to. */
+extern int uuconf_port_free (void *uuconf_pglobal,
+ struct uuconf_port *uuconf_qport);
+
+#ifdef __OPTIMIZE__
+#define uuconf_port_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Get the names of all known dialers. This sets sets *ppzdialers to
+ point to an array of dialer names. The list of names is NULL
+ terminated. The array is allocated using malloc, as is each
+ element of the array, and they may all be passed to free when they
+ are no longer needed. */
+extern int uuconf_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer. This sets the fields
+ in *qdialer. */
+extern int uuconf_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Free the memory occupied by system information returned by
+ uuconf_dialer_info (or any of the configuration file specific
+ routines described below). After this is called, the contents of
+ the structure shall not be referred to. */
+extern int uuconf_dialer_free (void *uuconf_pglobal,
+ struct uuconf_dialer *uuconf_qsys);
+
+#ifdef __OPTIMIZE__
+#define uuconf_dialer_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Get the local node name. If the node name is not specified
+ (because no ``nodename'' command appeared in the config file) this
+ will return UUCONF_NOT_FOUND, and some system dependent function
+ must be used to determine the node name. Otherwise it will return
+ a pointer to a constant string, which should not be freed. */
+extern int uuconf_localname (void *uuconf_pglobal,
+ const char **pzname);
+
+/* Get the local node name that should be used, given a login name.
+ This function will check for any special local name that may be
+ associated with the login name zlogin (as set by the ``myname''
+ command in a Taylor configuration file, or the MYNAME field in a
+ Permissions entry). This will set *pzname to the node name. If no
+ node name can be determined, *pzname will be set to NULL and the
+ function will return UUCONF_NOT_FOUND; in this case some system
+ dependent function must be used to determine the node name. If the
+ function returns UUCONF_SUCCESS, *pzname will be point to an
+ malloced buffer. */
+extern int uuconf_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the name of the UUCP spool directory. This will set *pzspool
+ to a constant string, which should not be freed. */
+extern int uuconf_spooldir (void *uuconf_pglobal,
+ const char **uuconf_pzspool);
+
+/* Get the name of the default UUCP public directory. This will set
+ *pzpub to a constant string, which should not be freed. Note that
+ particular systems may use a different public directory. */
+extern int uuconf_pubdir (void *uuconf_pglobal,
+ const char **uuconf_pzpub);
+
+/* Get the name of the UUCP lock directory. This will set *pzlock to
+ a constant string, which should not be freed. */
+extern int uuconf_lockdir (void *uuconf_pglobal,
+ const char **uuconf_pzlock);
+
+/* Get the name of the UUCP log file. This will set *pzlog to a
+ constant string, which should not be freed. */
+extern int uuconf_logfile (void *uuconf_pglobal,
+ const char **uuconf_pzlog);
+
+/* Get the name of the UUCP statistics file. This will set *pzstats
+ to a constant string, which should not be freed. */
+extern int uuconf_statsfile (void *uuconf_pglobal,
+ const char **uuconf_pzstats);
+
+/* Get the name of the UUCP debugging file. This will set *pzdebug to
+ a constant string, which should not be freed. */
+extern int uuconf_debugfile (void *uuconf_pglobal,
+ const char **uuconf_pzdebug);
+
+/* Get the default debugging level to use. This basically gets the
+ argument of the ``debug'' command from the Taylor UUCP config file.
+ It will set *pzdebug to a constant string, which should not be
+ freed. */
+extern int uuconf_debuglevel (void *uuconf_pglobal,
+ const char **uuconf_pzdebug);
+
+/* Get the maximum number of simultaneous uuxqt executions. This will
+ set *pcmaxuuxqt to the number. Zero indicates no maximum. */
+extern int uuconf_maxuuxqts (void *uuconf_pglobal,
+ int *uuconf_pcmaxuuxqt);
+
+/* Check a login name and password. This checks the Taylor UUCP
+ password file (not /etc/passwd). It will work even if
+ uuconf_taylor_init was not called. If the login name exists and
+ the password is correct, this returns UUCONF_SUCCESS. If the login
+ does not exist, or the password is wrong, this returns
+ UUCONF_NOT_FOUND. Other errors are also possible. */
+extern int uuconf_callin (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ const char *uuconf_zpassword);
+
+/* Get the callout login name and password for a system. This will
+ set both *pzlog and *pzpass to a string allocated by malloc, or to
+ NULL if the value is not found. If neither value is found, the
+ function will return UUCONF_NOT_FOUND. */
+extern int uuconf_callout (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ char **uuconf_pzlog,
+ char **uuconf_pzpass);
+
+/* See if a login name is permitted for a system. This will return
+ UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is
+ invalid. This simply calls uuconf_taylor_validate or returns
+ UUCONF_SUCCESS, depending on the value of HAVE_TAYLOR_CONFIG. */
+extern int uuconf_validate (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ const char *uuconf_zlogin);
+
+/* Get the name of the HDB remote.unknown shell script, if using
+ HAVE_HDB_CONFIG. This does not actually run the shell script. If
+ the function returns UUCONF_SUCCESS, the name will be in *pzname,
+ which will point to an malloced buffer. If it returns
+ UUCONF_NOT_FOUND, then there is no script to run. */
+extern int uuconf_remote_unknown (void *uuconf_pglobal,
+ char **pzname);
+
+/* Translate a dial code. This sets *pznum to an malloced string.
+ This will look up the entire zdial string in the dialcode file, so
+ for normal use the alphabetic prefix should be separated. */
+extern int uuconf_dialcode (void *uuconf_pglobal,
+ const char *uuconf_zdial,
+ char **uuconf_pznum);
+
+/* Compare two grades, returning < 0 if b1 should be executed before
+ b2, == 0 if they are the same, or > 0 if b1 should be executed
+ after b2. This can not fail, and does not return a standard uuconf
+ error code; it is normally called via the macro UUCONF_GRADE_CMP,
+ defined above. */
+extern int uuconf_grade_cmp (int uuconf_b1, int uuconf_b2);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_init ();
+extern int uuconf_init_thread ();
+extern int uuconf_system_names ();
+extern int uuconf_system_info ();
+extern int uuconf_system_unknown ();
+extern int uuconf_system_local ();
+extern int uuconf_system_free ();
+extern int uuconf_find_port ();
+extern int uuconf_port_free ();
+extern int uuconf_dialer_names ();
+extern int uuconf_dialer_info ();
+extern int uuconf_dialer_free ();
+extern int uuconf_localname ();
+extern int uuconf_login_localname ();
+extern int uuconf_spooldir ();
+extern int uuconf_lockdir ();
+extern int uuconf_pubdir ();
+extern int uuconf_logfile ();
+extern int uuconf_statsfile ();
+extern int uuconf_debugfile ();
+extern int uuconf_debuglevel ();
+extern int uuconf_maxuuxqts ();
+extern int uuconf_callin ();
+extern int uuconf_callout ();
+extern int uuconf_remote_unknown ();
+extern int uuconf_validate ();
+extern int uuconf_grade_cmp ();
+
+#ifdef __OPTIMIZE__
+#define uuconf_system_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#define uuconf_port_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#define uuconf_dialer_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the Taylor UUCP configuration file reading routines.
+ This must be called before calling any of the Taylor UUCP
+ configuration file specific routines. The ppglobal argument should
+ point to a generic pointer. Moreover, before calling this function
+ the pointer either must be set to NULL, or must have been passed to
+ one of the other uuconf init routines. The zprogram argument is
+ the name of the program for which files should be read. If NULL,
+ it is taken as "uucp", which means to read the standard UUCP files.
+ The zname argument is the name of the config file. If it is NULL,
+ the default config file will be used.
+
+ Note that if the zname argument is obtained from the user running
+ the program, the program should be careful to revoke any special
+ privileges it may have (e.g. on Unix call setuid (getuid ()) and
+ setgid (getgid ())). Otherwise various sorts of spoofing become
+ possible. */
+extern int uuconf_taylor_init (void **uuconf_pglobal,
+ const char *uuconf_zprogram,
+ const char *uuconf_zname);
+
+/* Get the names of all systems listed in the Taylor UUCP
+ configuration files. This sets *ppzsystems to point to an array of
+ system names. The list of names is NULL terminated. The array is
+ allocated using malloc, as is each element of the array. If the
+ falias argument is 0, the list will not include any aliases;
+ otherwise, it will. */
+extern int uuconf_taylor_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the Taylor UUCP
+ configuration files. This will set *qsys. */
+extern int uuconf_taylor_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for an unknown (anonymous) system. This returns
+ the values set by the ``unknown'' command in the main configuration
+ file. If the ``unknown'' command was not used, this will return
+ UUCONF_NOT_FOUND. */
+extern int uuconf_taylor_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the Taylor UUCP configuration files. The
+ arguments and return values are identical to those of
+ uuconf_find_port. */
+extern int uuconf_taylor_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Get the names of all dialers listed in the Taylor UUCP
+ configuration files. This sets *ppzdialers to point to an array of
+ dialer names. The list of names is NULL terminated. The array is
+ allocated using malloc, as is each element of the array. */
+extern int uuconf_taylor_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer from the Taylor UUCP
+ configuration files. This sets the fields in *qdialer. */
+extern int uuconf_taylor_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Get the local node name that should be used, given a login name,
+ considering only the ``myname'' command in the Taylor UUCP
+ configuration files. If the function returns UUCONF_SUCCESS,
+ *pzname will point to an malloced buffer. */
+extern int uuconf_taylor_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the callout login name and password for a system from the
+ Taylor UUCP configuration files. This will set both *pzlog and
+ *pzpass to a string allocated by malloc, or to NULL if the value is
+ not found. If neither value is found, the function will return
+ UUCONF_NOT_FOUND. */
+extern int uuconf_taylor_callout (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ char **uuconf_pzlog,
+ char **uuconf_pzpass);
+
+/* See if a login name is permitted for a system. This will return
+ UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is
+ invalid. This checks whether the login name appears in a
+ called-login command with a list of system which does not include
+ the system qsys. */
+extern int uuconf_taylor_validate (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ const char *uuconf_zlogin);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_taylor_init ();
+extern int uuconf_taylor_system_names ();
+extern int uuconf_taylor_system_info ();
+extern int uuconf_taylor_system_unknown ();
+extern int uuconf_taylor_find_port ();
+extern int uuconf_taylor_dialer_names ();
+extern int uuconf_taylor_dialer_info ();
+extern int uuconf_taylor_login_localname ();
+extern int uuconf_taylor_callout ();
+extern int uuconf_taylor_validate ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the V2 configuration file reading routines. This must
+ be called before any of the other V2 routines are called. The
+ ppglobal argument should point to a generic pointer. Moreover,
+ before calling this function the pointer either must be set to
+ NULL, or must have been passed to one of the other uuconf init
+ routines. */
+extern int uuconf_v2_init (void **uuconf_ppglobal);
+
+/* Get the names of all systems listed in the V2 configuration files.
+ This sets *ppzsystems to point to an array of system names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. If the falias argument is
+ 0, the list will not include any aliases; otherwise, it will. */
+extern int uuconf_v2_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the V2 configuration
+ files. This will set *qsys. */
+extern int uuconf_v2_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the V2 configuration files. The arguments and
+ return values are identical to those of uuconf_find_port. */
+extern int uuconf_v2_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_v2_init ();
+extern int uuconf_v2_system_names ();
+extern int uuconf_v2_system_info ();
+extern int uuconf_v2_find_port ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the HDB configuration file reading routines. This
+ should be called before any of the other HDB routines are called.
+ The ppglobal argument should point to a generic pointer. Moreover,
+ before calling this function the pointer either must be set to
+ NULL, or must have been passed to one of the other uuconf init
+ routines. The zprogram argument is used to match against a
+ "services" string in Sysfiles. A NULL or "uucp" argument is taken
+ as "uucico". */
+extern int uuconf_hdb_init (void **uuconf_ppglobal,
+ const char *uuconf_zprogram);
+
+/* Get the names of all systems listed in the HDB configuration files.
+ This sets *ppzsystems to point to an array of system names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. If the falias argument is
+ 0, the list will not include any aliases; otherwise, it will (an
+ alias is created by using the ALIAS= keyword in the Permissions
+ file). */
+extern int uuconf_hdb_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the HDB configuration
+ files. This will set *qsys. */
+extern int uuconf_hdb_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+
+/* Get information for an unknown (anonymous) system. If no
+ information is available for unknown systems, this will return
+ UUCONF_NOT_FOUND. This does not run the remote.unknown shell
+ script. */
+extern int uuconf_hdb_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the HDB configuration files. The arguments and
+ return values are identical to those of uuconf_find_port. */
+extern int uuconf_hdb_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Get the names of all dialers listed in the HDB configuration files.
+ This sets *ppzdialers to point to an array of dialer names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. */
+extern int uuconf_hdb_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer from the HDB
+ configuration files. This sets the fields in *qdialer. */
+extern int uuconf_hdb_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Get the local node name that should be used, given a login name,
+ considering only the MYNAME field in the HDB Permissions file. If
+ the function returns UUCONF_SUCCESS, *pzname will point to an
+ malloced buffer. */
+extern int uuconf_hdb_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the name of the HDB remote.unknown shell script. This does not
+ actually run the shell script. If the function returns
+ UUCONF_SUCCESS, the name will be in *pzname, which will point to an
+ malloced buffer. */
+extern int uuconf_hdb_remote_unknown (void *uuconf_pglobal,
+ char **pzname);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_hdb_init ();
+extern int uuconf_hdb_system_names ();
+extern int uuconf_hdb_system_info ();
+extern int uuconf_hdb_system_unknown ();
+extern int uuconf_hdb_find_port ();
+extern int uuconf_hdb_dialer_names ();
+extern int uuconf_hdb_dialer_info ();
+extern int uuconf_hdb_localname ();
+extern int uuconf_hdb_remote_unknown ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* This function will set an appropriate error message into the buffer
+ zbuf, given a uuconf error code. The buffer will always be null
+ terminated, and will never be accessed beyond the length cbuf.
+ This function will return the number of characters needed for the
+ complete message, including the null byte. If this is less than
+ the cbytes argument, the buffer holds a truncated string. */
+extern int uuconf_error_string (void *uuconf_pglobal, int ierror,
+ char *zbuf, UUCONF_SIZE_T cbuf);
+
+/* If UUCONF_ERROR_ERRNO is set in a return value, this function may
+ be used to retrieve the errno value. This will be the value of
+ errno as set by the system function which failed. However, some
+ system functions, notably some stdio routines, may not set errno,
+ in which case the value will be meaningless. This function does
+ not return a uuconf error code, and it cannot fail. */
+extern int uuconf_error_errno (void *uuconf_pglobal);
+
+/* If UUCONF_ERROR_FILENAME is set in a return value, this function
+ may be used to retrieve the file name. This function does not
+ return a uuconf error code, and it cannot fail. The string that it
+ returns a pointer to is not guaranteed to remain allocated across
+ the next call to a uuconf function (other than one of the three
+ error retrieving functions). */
+extern const char *uuconf_error_filename (void *uuconf_pglobal);
+
+/* If UUCONF_ERROR_LINENO is set in a return value, this function may
+ be used to retrieve the line number. This function does not return
+ a uuconf error code, and it cannot fail. */
+extern int uuconf_error_lineno (void *uuconf_pglobal);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_error_string ();
+extern int uuconf_error_errno ();
+extern UUCONF_CONST char *uuconf_error_filename ();
+extern int uuconf_error_lineno ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+/* The uuconf package also provides a few functions which can accept
+ commands and parcel them out according to a table. These are
+ publically visible, partially in the hopes that they will be
+ useful, but mostly because the rest of the Taylor UUCP package uses
+ them. */
+
+/* The types of entries allowed in a command table (struct
+ uuconf_cmdtab). Each type defines how a particular command is
+ interpreted. Each type will either assign a value to a variable or
+ call a function. In all cases, a line of input is parsed into
+ separate fields, separated by whitespace; comments beginning with
+ '#' are discarded, except that a '#' preceeded by a backslash is
+ retained. The first field is taken as the command to execute, and
+ the remaining fields are its arguments. */
+
+/* A boolean value. Used for a command which accepts a single
+ argument, which must begin with 'y', 'Y', 't', or 'T' for true (1)
+ or 'n', 'N', 'f', or 'F' for false (0). The corresponding variable
+ must be an int. */
+#define UUCONF_CMDTABTYPE_BOOLEAN (0x12)
+
+/* An integer value. Used for a command which accepts a single
+ argument, which must be an integer. The corresponding variable
+ must be an int. */
+#define UUCONF_CMDTABTYPE_INT (0x22)
+
+/* A long value. Used for a command which accepts a single value,
+ which must be an integer. The corresponding variable must be a
+ long. */
+#define UUCONF_CMDTABTYPE_LONG (0x32)
+
+/* A string value. Used for a command which accepts a string
+ argument. If there is no argument, the variable will be set to
+ point to a zero byte. Otherwise the variable will be set to point
+ to the string. The corresponding variable must be a char *. The
+ memory pointed to by the variable after it is set must not be
+ modified. */
+#define UUCONF_CMDTABTYPE_STRING (0x40)
+
+/* A full string value. Used for a command which accepts a series of
+ string arguments separated by whitespace. The corresponding
+ variable must be a char **. It will be set to an NULL terminated
+ array of the arguments. The memory occupied by the array itself,
+ and by the strings within it, must not be modified. */
+#define UUCONF_CMDTABTYPE_FULLSTRING (0x50)
+
+/* A function. If this command is encountered, the command and its
+ arguments are passed to the corresponding function. They are
+ passed as an array of strings, in which the first string is the
+ command itself, along with a count of strings. This value may be
+ or'red with a specific number of required arguments;
+ UUCONF_CMDTABTYPE_FN | 1 accepts no additional arguments besides
+ the command itself, UUCONF_CMDTABTYPE_FN | 2 accepts 1 argument,
+ etc. UUCONF_CMDTABTYPE_FN | 0, accepts any number of additional
+ arguments. */
+#define UUCONF_CMDTABTYPE_FN (0x60)
+
+/* A prefix function. The string in the table is a prefix; if a
+ command is encountered with the same prefix, the corresponding
+ function will be called as for UUCONF_CMDTABTYPE_FN. The number of
+ arguments may be or'red in as with UUCONF_CMDTABTYPE_FN. */
+#define UUCONF_CMDTABTYPE_PREFIX (0x70)
+
+/* This macro will return the particular type of a CMDTABTYPE. */
+#define UUCONF_TTYPE_CMDTABTYPE(i) ((i) & 0x70)
+
+/* This macro will return the required number of arguments of a
+ CMDTABTYPE. If it is zero, there is no restriction. */
+#define UUCONF_CARGS_CMDTABTYPE(i) ((i) & 0x0f)
+
+/* When a function is called via UUCONF_CMDTABTYPE_FN or
+ UUCONF_CMDTABTYPE_PREFIX, it may return any uuconf error code (see
+ above). However, it will normally return one of the following:
+
+ UUCONF_CMDTABRET_CONTINUE: Take no special action. In particular,
+ the arguments passed to the function may be overwritten or freed.
+
+ UUCONF_CMDTABRET_KEEP: The memory occupied by the arguments passed
+ to the function must be preserved. Continue processing commands.
+
+ UUCONF_CMDTABRET_EXIT: If reading commands from a file, stop
+ processing. The arguments passed to the function may be
+ overwritten or freed.
+
+ UUCONF_CMDTABRET_KEEP_AND_EXIT: Stop processing any file. The
+ memory occupied by the arguments passed to the function must be
+ preserved.
+
+ These values are interpreted by uuconf_cmd_file. The
+ uuconf_cmd_line and uuconf_cmd_args functions may return
+ UUCONF_CMDTABRET_KEEP. It they get an error, they will return an
+ error code with UUCONF_CMDTABRET_EXIT set. Also, of course, they
+ may return any value that is returned by one of the user functions
+ in the uuconf_cmdtab table. */
+
+/* UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT are defined above,
+ with the error codes. */
+
+#define UUCONF_CMDTABRET_CONTINUE UUCONF_SUCCESS
+#define UUCONF_CMDTABRET_KEEP_AND_EXIT \
+ (UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT)
+
+/* When a function is called via CMDTABTYPE_FN or CMDTABTYPE_PREFIX,
+ it is passed five arguments. This is the type of a pointer to such
+ a function. The uuconf global information structure is passed in
+ for convenience in calling another uuconf function. The arguments
+ to the command are passed in (the command itself is the first
+ argument) along with a count and the value of the pvar field from
+ the uuconf_cmdtab structure in which the function pointer was
+ found. The pinfo argument to the function is taken from the
+ argument to uuconf_cmd_*. */
+
+#if UUCONF_ANSI_C
+typedef int (*uuconf_cmdtabfn) (void *uuconf_pglobal,
+ int uuconf_argc,
+ char **uuconf_argv,
+ void *uuconf_pvar,
+ void *uuconf_pinfo);
+#else
+typedef int (*uuconf_cmdtabfn) ();
+#endif
+
+/* A table of commands is an array of the following structures. The
+ final element of the table should have uuconf_zcmd == NULL. */
+
+struct uuconf_cmdtab
+{
+ /* Command name. */
+ UUCONF_CONST char *uuconf_zcmd;
+ /* Command type (one of CMDTABTYPE_*). */
+ int uuconf_itype;
+ /* If not CMDTABTYPE_FN or CMDTABTYPE_PREFIX, the address of the
+ associated variable. Otherwise, a pointer value to pass to the
+ function pifn. */
+ UUCONF_POINTER uuconf_pvar;
+ /* The function to call if CMDTABTYPE_FN or CMDTABTYPE_PREFIX. */
+ uuconf_cmdtabfn uuconf_pifn;
+};
+
+/* Bit flags to pass to uuconf_processcmds. */
+
+/* If set, case is significant when checking commands. Normally case
+ is ignored. */
+#define UUCONF_CMDTABFLAG_CASE (0x1)
+
+/* If set, a backslash at the end of a line may be used to include the
+ next physical line in the logical line. */
+#define UUCONF_CMDTABFLAG_BACKSLASH (0x2)
+
+#if UUCONF_ANSI_C
+
+/* Read commands from a file, look them up in a table, and take the
+ appropriate action. This continues reading lines from the file
+ until EOF, or until a function returns with UUCONF_CMDTABRET_EXIT
+ set, or until an error occurs. The qtab argument must point to a
+ table of struct uuconf_cmdtab; the last element in the table should
+ have uuconf_zcmd == NULL. When a UUCONF_CMDTABTYPE_FN or
+ UUCONF_CMDTABTYPE_PREFIX command is found, the pinfo argument will
+ be passed to the called function. If an a command is found that is
+ not in the table, then if pfiunknownfn is NULL the unknown command
+ is ignored; otherwise it is passed to pfiunknownfn, which should
+ return a uuconf return code which is handled as for any other
+ function (the pvar argument to pfiunknownfn will always be NULL).
+ The iflags argument is any combination of the above
+ UUCONF_CMDTABFLAG bits. The pblock argument may also be a memory
+ block, as returned by uuconf_malloc_block (described below), in
+ which case all memory preserved because of UUCONF_CMDTABRET_KEEP
+ will be added to the block so that it may be freed later; it may
+ also be NULL, in which case any such memory is permanently lost.
+
+ This function initially sets the internal line number to 0, and
+ then increments it as each line is read. It is permitted for any
+ called function to use the uuconf_lineno function to obtain it. If
+ this function is called when not at the start of a file, the value
+ returned by uuconf_lineno (which is, in any case, only valid if an
+ error code with UUCONF_ERROR_LINENO set is returned) must be
+ adjusted by the caller.
+
+ This returns a normal uuconf return value, as described above. */
+extern int uuconf_cmd_file (void *uuconf_pglobal,
+ FILE *uuconf_e,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+/* This utility function is just like uuconf_cmd_file, except that it
+ only operates on a single string. If a function is called via
+ qtab, its return value will be the return value of this function.
+ UUCONF_CMDTABFLAG_BACKSLASH is ignored in iflags. The string z is
+ modified in place. The return value may include the
+ UUCONF_CMDTABRET_KEEP and, on error, the UUCONF_CMDTABRET_EXIT
+ bits, which should be honored by the calling code. */
+extern int uuconf_cmd_line (void *uuconf_pglobal,
+ char *uuconf_z,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+/* This utility function is just like uuconf_cmd_line, except it is
+ given a list of already parsed arguments. */
+extern int uuconf_cmd_args (void *uuconf_pglobal,
+ int uuconf_cargs,
+ char **uuconf_pzargs,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_cmd_file ();
+extern int uuconf_cmd_line ();
+extern int uuconf_cmd_args ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* The uuconf_cmd_file function may allocate memory permanently, as
+ for setting a UUCONF_CMDTABTYPE_STRING value, in ways which are
+ difficult to free up. A memory block may be used to record all
+ allocated memory, so that it can all be freed up at once at some
+ later time. These functions do not take a uuconf global pointer,
+ and are independent of the rest of the uuconf library. */
+
+/* Allocate a block of memory. If this returns NULL, then malloc
+ returned NULL, and errno is whatever malloc set it to. */
+extern void *uuconf_malloc_block (void);
+
+/* Allocate memory within a memory block. If this returns NULL, then
+ malloc returned NULL, and errno is whatever malloc set it to. */
+extern void *uuconf_malloc (void *uuconf_pblock,
+ UUCONF_SIZE_T uuconf_cbytes);
+
+/* Add a block returned by the generic malloc routine to a memory
+ block. This returns zero on success, non-zero on failure. If this
+ fails (returns non-zero), then malloc returned NULL, and errno is
+ whatever malloc set it to. */
+extern int uuconf_add_block (void *uuconf_pblock, void *uuconf_padd);
+
+/* Free a value returned by uuconf_malloc from a memory block. In the
+ current implementation, this will normally not do anything, but it
+ doesn't hurt. No errors can occur. */
+extern void uuconf_free (void *uuconf_pblock, void *uuconf_pfree);
+
+/* Free an entire memory block, including all values returned by
+ uuconf_malloc from it and all values added to it with
+ uuconf_add_block. No errors can occur. */
+extern void uuconf_free_block (void *uuconf_pblock);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern UUCONF_POINTER uuconf_malloc_block ();
+extern UUCONF_POINTER uuconf_malloc ();
+extern int uuconf_add_block ();
+extern /* void */ uuconf_free ();
+extern /* void */ uuconf_free_block ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#endif /* ! defined (UUCONF_H) */
diff --git a/gnu/libexec/uucp/common_sources/uucp.h b/gnu/libexec/uucp/common_sources/uucp.h
new file mode 100644
index 00000000000..8df3ec4c3e7
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/uucp.h
@@ -0,0 +1,367 @@
+/* uucp.h
+ Header file for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* Get the system configuration parameters. */
+#include "conf.h"
+#include "policy.h"
+
+/* Get a definition for ANSI_C if we weren't given one. */
+#ifndef ANSI_C
+#ifdef __STDC__
+#define ANSI_C 1
+#else /* ! defined (__STDC__) */
+#define ANSI_C 0
+#endif /* ! defined (__STDC__) */
+#endif /* ! defined (ANSI_C) */
+
+/* Pass this definition into uuconf.h. */
+#define UUCONF_ANSI_C ANSI_C
+
+/* We always include some standard header files. We need <signal.h>
+ to define sig_atomic_t. */
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+/* On some systems we need <sys/types.h> to get sig_atomic_t or
+ size_t or time_t. */
+#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && HAVE_SIG_ATOMIC_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#else
+#if ! HAVE_SIZE_T_IN_STDDEF_H && HAVE_SIZE_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#else
+#if ! HAVE_TIME_T_IN_TIME_H && HAVE_TIME_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#endif
+#endif
+#endif
+
+#ifndef USE_TYPES_H
+#define USE_TYPES_H 0
+#endif
+
+#if USE_TYPES_H
+#include <sys/types.h>
+#endif
+
+/* Make sure we have sig_atomic_t. */
+#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H
+#ifndef SIG_ATOMIC_T
+/* There is no portable definition for sig_atomic_t. */
+#define SIG_ATOMIC_T char
+#endif /* ! defined (SIG_ATOMIC_T) */
+typedef SIG_ATOMIC_T sig_atomic_t;
+#endif /* ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H */
+
+/* Make sure we have size_t. We use int as the default because the
+ main use of this type is to provide an argument to malloc and
+ realloc. On a system which does not define size_t, int is
+ certainly the correct type to use. */
+#if ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H
+#ifndef SIZE_T
+#define SIZE_T unsigned
+#endif /* ! defined (SIZE_T) */
+typedef SIZE_T size_t;
+#endif /* ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H */
+
+/* Make sure we have time_t. We use long as the default. We don't
+ bother to let conf.h override this, since on a system which doesn't
+ define time_t long must be correct. */
+#if ! HAVE_TIME_T_IN_TIME_H && ! HAVE_TIME_T_IN_TYPES_H
+typedef long time_t;
+#endif
+
+/* Set up some definitions for both ANSI C and Classic C.
+
+ P() -- for function prototypes (e.g. extern int foo P((int)) ).
+ pointer -- for a generic pointer (i.e. void *).
+ constpointer -- for a generic pointer to constant data.
+ BUCHAR -- to convert a character to unsigned. */
+#if ANSI_C
+#if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR
+ #error ANSI C compiler without void or unsigned char
+#endif
+#define P(x) x
+typedef void *pointer;
+typedef const void *constpointer;
+#define BUCHAR(b) ((unsigned char) (b))
+#else /* ! ANSI_C */
+/* Handle uses of const, volatile and void in Classic C. */
+#define const
+#define volatile
+#if ! HAVE_VOID
+#define void int
+#endif
+#define P(x) ()
+typedef char *pointer;
+typedef const char *constpointer;
+#if HAVE_UNSIGNED_CHAR
+#define BUCHAR(b) ((unsigned char) (b))
+#else /* ! HAVE_UNSIGNED_CHAR */
+/* This should work on most systems, but not necessarily all. */
+#define BUCHAR(b) ((b) & 0xff)
+#endif /* ! HAVE_UNSIGNED_CHAR */
+#endif /* ! ANSI_C */
+
+/* Make sure we have a definition for offsetof. */
+#ifndef offsetof
+#define offsetof(type, field) \
+ ((size_t) ((char *) &(((type *) 0)->field) - (char *) (type *) 0))
+#endif
+
+/* Only use inline with gcc. */
+#ifndef __GNUC__
+#define __inline__
+#endif
+
+/* Get the string functions, which are used throughout the code. */
+#if HAVE_MEMORY_H
+#include <memory.h>
+#else
+/* We really need a definition for memchr, and this should not
+ conflict with anything in <string.h>. I hope. */
+extern pointer memchr ();
+#endif
+
+#if HAVE_STRING_H
+#include <string.h>
+#else /* ! HAVE_STRING_H */
+#if HAVE_STRINGS_H
+#include <strings.h>
+#else /* ! HAVE_STRINGS_H */
+extern char *strcpy (), *strncpy (), *strchr (), *strrchr (), *strtok ();
+extern char *strcat (), *strerror (), *strstr ();
+extern size_t strlen (), strspn (), strcspn ();
+#if ! HAVE_MEMORY_H
+extern pointer memcpy (), memchr ();
+#endif /* ! HAVE_MEMORY_H */
+#endif /* ! HAVE_STRINGS_H */
+#endif /* ! HAVE_STRING_H */
+
+/* Get what we need from <stdlib.h>. */
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#else /* ! HAVE_STDLIB_H */
+extern pointer malloc (), realloc (), bsearch ();
+extern long strtol ();
+extern char *getenv ();
+#endif /* ! HAVE_STDLIB_H */
+
+/* NeXT uses <libc.h> to declare a bunch of functions. */
+#if HAVE_LIBC_H
+#include <libc.h>
+#endif
+
+/* Make sure we have the EXIT_ macros. */
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS (0)
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE (1)
+#endif
+
+/* If we need to declare errno, do so. I don't want to always do
+ this, because some system might theoretically have a different
+ declaration for errno. On a POSIX system this is sure to work. */
+#if ! HAVE_ERRNO_DECLARATION
+extern int errno;
+#endif
+
+/* If the system has the socket call, guess that we can compile the
+ TCP code. */
+#define HAVE_TCP HAVE_SOCKET
+
+/* If the system has the t_open call, guess that we can compile the
+ TLI code. */
+#define HAVE_TLI HAVE_T_OPEN
+
+/* The boolean type holds boolean values. */
+typedef int boolean;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+
+/* The openfile_t type holds an open file. This depends on whether we
+ are using stdio or not. */
+#if USE_STDIO
+
+typedef FILE *openfile_t;
+#define EFILECLOSED ((FILE *) NULL)
+#define ffileisopen(e) ((e) != NULL)
+#define ffileeof(e) feof (e)
+#define cfileread(e, z, c) fread ((z), 1, (c), (e))
+#define ffilereaderror(e, c) ferror (e)
+#define cfilewrite(e, z, c) fwrite ((z), 1, (c), (e))
+#ifdef SEEK_SET
+#define ffileseek(e, i) (fseek ((e), (long) (i), SEEK_SET) == 0)
+#define ffilerewind(e) (fseek ((e), (long) 0, SEEK_SET) == 0)
+#else
+#define ffileseek(e, i) (fseek ((e), (long) (i), 0) == 0)
+#define ffilerewind(e) (fseek ((e), (long) 0, 0) == 0)
+#endif
+#define ffileclose(e) (fclose (e) == 0)
+
+#else /* ! USE_STDIO */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef int openfile_t;
+#define EFILECLOSED (-1)
+#define ffileisopen(e) ((e) >= 0)
+#define ffileeof(e) (FALSE)
+#define cfileread(e, z, c) read ((e), (z), (c))
+#define ffilereaderror(e, c) ((c) < 0)
+#define cfilewrite(e, z, c) write ((e), (z), (c))
+#ifdef SEEK_SET
+#define ffileseek(e, i) (lseek ((e), (long) i, SEEK_SET) >= 0)
+#define ffilerewind(e) (lseek ((e), (long) 0, SEEK_SET) >= 0)
+#else
+#define ffileseek(e, i) (lseek ((e), (long) i, 0) >= 0)
+#define ffilerewind(e) (lseek ((e), (long) 0, 0) >= 0)
+#endif
+#define ffileclose(e) (close (e) >= 0)
+
+#endif /* ! USE_STDIO */
+
+/* A prototype for main to avoid warnings from gcc 2.0
+ -Wmissing-prototype option. */
+extern int main P((int argc, char **argv));
+
+/* Some standard routines which we only define if they are not present
+ on the system we are compiling on. */
+
+#if ! HAVE_GETLINE
+/* Read a line from a file. */
+extern int getline P((char **pz, size_t *pc, FILE *e));
+#endif
+
+#if ! HAVE_REMOVE
+/* Erase a file. */
+#undef remove
+extern int remove P((const char *zfile));
+#endif
+
+#if ! HAVE_STRDUP
+/* Copy a string into memory. */
+extern char *strdup P((const char *z));
+#endif
+
+#if ! HAVE_STRSTR
+/* Look for one string within another. */
+extern char *strstr P((const char *zouter, const char *zinner));
+#endif
+
+#if ! HAVE_STRCASECMP
+#if HAVE_STRICMP
+#define strcasecmp stricmp
+#else /* ! HAVE_STRICMP */
+/* Rename strcasecmp to avoid ANSI C name space. */
+#define strcasecmp xstrcasecmp
+extern int strcasecmp P((const char *z1, const char *z2));
+#endif /* ! HAVE_STRICMP */
+#endif /* ! HAVE_STRCASECMP */
+
+#if ! HAVE_STRNCASECMP
+#if HAVE_STRNICMP
+#define strncasecmp strnicmp
+#else /* ! HAVE_STRNICMP */
+/* Rename strncasecmp to avoid ANSI C name space. */
+#define strncasecmp xstrncasecmp
+extern int strncasecmp P((const char *z1, const char *z2, size_t clen));
+#endif /* ! HAVE_STRNICMP */
+#endif /* ! HAVE_STRNCASECMP */
+
+#if ! HAVE_STRERROR
+/* Get a string corresponding to an error message. */
+#undef strerror
+extern char *strerror P((int ierr));
+#endif
+
+/* Get the appropriate definitions for memcmp, memcpy, memchr and
+ bzero. */
+#if ! HAVE_MEMCMP
+#if HAVE_BCMP
+#define memcmp(p1, p2, c) bcmp ((p1), (p2), (c))
+#else /* ! HAVE_BCMP */
+extern int memcmp P((constpointer p1, constpointer p2, size_t c));
+#endif /* ! HAVE_BCMP */
+#endif /* ! HAVE_MEMCMP */
+
+#if ! HAVE_MEMCPY
+#if HAVE_BCOPY
+#define memcpy(pto, pfrom, c) bcopy ((pfrom), (pto), (c))
+#else /* ! HAVE_BCOPY */
+extern pointer memcpy P((pointer pto, constpointer pfrom, size_t c));
+#endif /* ! HAVE_BCOPY */
+#endif /* ! HAVE_MEMCPY */
+
+#if ! HAVE_MEMCHR
+extern pointer memchr P((constpointer p, int b, size_t c));
+#endif
+
+#if ! HAVE_BZERO
+#if HAVE_MEMSET
+#define bzero(p, c) memset ((p), 0, (c))
+#else /* ! HAVE_MEMSET */
+extern void bzero P((pointer p, int c));
+#endif /* ! HAVE_MEMSET */
+#endif /* ! HAVE_BZERO */
+
+/* Look up a character in a string. */
+#if ! HAVE_STRCHR
+#if HAVE_INDEX
+#define strchr index
+extern char *index ();
+#else /* ! HAVE_INDEX */
+extern char *strchr P((const char *z, int b));
+#endif /* ! HAVE_INDEX */
+#endif /* ! HAVE_STRCHR */
+
+#if ! HAVE_STRRCHR
+#if HAVE_RINDEX
+#define strrchr rindex
+extern char *rindex ();
+#else /* ! HAVE_RINDEX */
+extern char *strrchr P((const char *z, int b));
+#endif /* ! HAVE_RINDEX */
+#endif /* ! HAVE_STRRCHR */
+
+/* Turn a string into a long integer. */
+#if ! HAVE_STRTOL
+extern long strtol P((const char *, char **, int));
+#endif
+
+/* Lookup a key in a sorted array. */
+#if ! HAVE_BSEARCH
+extern pointer bsearch P((constpointer pkey, constpointer parray,
+ size_t celes, size_t cbytes,
+ int (*pficmp) P((constpointer, constpointer))));
+#endif
diff --git a/gnu/libexec/uucp/common_sources/uudefs.h b/gnu/libexec/uucp/common_sources/uudefs.h
new file mode 100644
index 00000000000..47d2c89896e
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/uudefs.h
@@ -0,0 +1,445 @@
+/* uudefs.h
+ Miscellaneous definitions for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct uuconf_system;
+struct uuconf_timespan;
+#endif
+
+/* The tlog enumeration holds the different types of logging. */
+enum tlog
+{
+ /* Normal log entry. */
+ LOG_NORMAL,
+ /* Error log entry. */
+ LOG_ERROR,
+ /* Fatal log entry. */
+ LOG_FATAL
+#if DEBUG > 1
+ ,
+ /* Debugging log entry. */
+ LOG_DEBUG,
+ /* Start debugging log entry. */
+ LOG_DEBUG_START,
+ /* Continue debugging log entry. */
+ LOG_DEBUG_CONTINUE,
+ /* End debugging log entry. */
+ LOG_DEBUG_END
+#endif
+};
+
+/* The tstatus_type enumeration holds the kinds of status information
+ we put in the status file. The order of entries here corresponds
+ to the order of entries in the azStatus array. */
+enum tstatus_type
+{
+ /* Conversation complete. */
+ STATUS_COMPLETE,
+ /* Port unavailable. */
+ STATUS_PORT_FAILED,
+ /* Dial failed. */
+ STATUS_DIAL_FAILED,
+ /* Login failed. */
+ STATUS_LOGIN_FAILED,
+ /* Handshake failed. */
+ STATUS_HANDSHAKE_FAILED,
+ /* Failed after logging in. */
+ STATUS_FAILED,
+ /* Talking to remote system. */
+ STATUS_TALKING,
+ /* Wrong time to call. */
+ STATUS_WRONG_TIME,
+ /* Number of status values. */
+ STATUS_VALUES
+};
+
+/* An array to convert status entries to strings. If more status entries
+ are added, this array must be extended. */
+extern const char *azStatus[];
+
+/* The sstatus structure holds the contents of a system status file. */
+struct sstatus
+{
+ /* Current status of conversation. */
+ enum tstatus_type ttype;
+ /* Number of failed retries. */
+ int cretries;
+ /* Time of last call in seconds since epoch (determined by
+ ixsysdep_time). */
+ long ilast;
+ /* Number of seconds until a retry is permitted. */
+ int cwait;
+};
+
+/* How long we have to wait for the next call, given the number of retries
+ we have already made. This should probably be configurable. */
+#define CRETRY_WAIT(c) ((c) * 10 * 60)
+
+/* The scmd structure holds a complete UUCP command. */
+struct scmd
+{
+ /* Command ('S' for send, 'R' for receive, 'X' for execute, 'E' for
+ simple execution, 'H' for hangup, 'Y' for hangup confirm, 'N' for
+ hangup deny). */
+ char bcmd;
+ /* At least one compiler needs an explicit padding byte here. */
+ char bdummy;
+ /* Sequence handle for fsysdep_did_work. */
+ pointer pseq;
+ /* File name to transfer from. */
+ const char *zfrom;
+ /* File name to transfer to. */
+ const char *zto;
+ /* User who requested transfer. */
+ const char *zuser;
+ /* Options. */
+ const char *zoptions;
+ /* Temporary file name ('S' and 'E'). */
+ const char *ztemp;
+ /* Mode to give newly created file ('S' and 'E'). */
+ unsigned int imode;
+ /* User to notify on remote system (optional; 'S' and 'E'). */
+ const char *znotify;
+ /* File size (-1 if not supplied) ('S', 'E' and 'R'). */
+ long cbytes;
+ /* Command to execute ('E'). */
+ const char *zcmd;
+ /* Position to restart from ('R'). */
+ long ipos;
+};
+
+#if DEBUG > 1
+
+/* We allow independent control over several different types of
+ debugging output, using a bit string with individual bits dedicated
+ to particular debugging types. */
+
+/* The bit string is stored in iDebug. */
+extern int iDebug;
+
+/* Debug abnormal events. */
+#define DEBUG_ABNORMAL (01)
+/* Debug chat scripts. */
+#define DEBUG_CHAT (02)
+/* Debug initial handshake. */
+#define DEBUG_HANDSHAKE (04)
+/* Debug UUCP protocol. */
+#define DEBUG_UUCP_PROTO (010)
+/* Debug protocols. */
+#define DEBUG_PROTO (020)
+/* Debug port actions. */
+#define DEBUG_PORT (040)
+/* Debug configuration files. */
+#define DEBUG_CONFIG (0100)
+/* Debug spool directory actions. */
+#define DEBUG_SPOOLDIR (0200)
+/* Debug executions. */
+#define DEBUG_EXECUTE (0400)
+/* Debug incoming data. */
+#define DEBUG_INCOMING (01000)
+/* Debug outgoing data. */
+#define DEBUG_OUTGOING (02000)
+
+/* Maximum possible value for iDebug. */
+#define DEBUG_MAX (03777)
+
+/* Intializer for array of debug names. The index of the name in the
+ array is the corresponding bit position in iDebug. We only check
+ for prefixes, so these names only need to be long enough to
+ distinguish each name from every other. The last entry must be
+ NULL. The string "all" is also recognized to turn on all
+ debugging. */
+#define DEBUG_NAMES \
+ { "a", "ch", "h", "u", "pr", "po", "co", "s", "e", "i", "o", NULL }
+
+/* The prefix to use to turn off all debugging. */
+#define DEBUG_NONE "n"
+
+/* Check whether a particular type of debugging is being done. */
+#define FDEBUGGING(i) ((iDebug & (i)) != 0)
+
+/* These macros are used to output debugging information. I use
+ several different macros depending on the number of arguments
+ because no macro can take a variable number of arguments and I
+ don't want to use double parentheses. */
+#define DEBUG_MESSAGE0(i, z) \
+ do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z)); } while (0)
+#define DEBUG_MESSAGE1(i, z, a1) \
+ do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z), (a1)); } while (0)
+#define DEBUG_MESSAGE2(i, z, a1, a2) \
+ do { if (FDEBUGGING (i)) ulog (LOG_DEBUG, (z), (a1), (a2)); } while (0)
+#define DEBUG_MESSAGE3(i, z, a1, a2, a3) \
+ do \
+ { \
+ if (FDEBUGGING (i)) \
+ ulog (LOG_DEBUG, (z), (a1), (a2), (a3)); \
+ } \
+ while (0)
+#define DEBUG_MESSAGE4(i, z, a1, a2, a3, a4) \
+ do \
+ { \
+ if (FDEBUGGING (i)) \
+ ulog (LOG_DEBUG, (z), (a1), (a2), (a3), (a4)); \
+ } \
+ while (0)
+
+#else /* DEBUG <= 1 */
+
+/* If debugging information is not being compiled, provide versions of
+ the debugging macros which just disappear. */
+#define DEBUG_MESSAGE0(i, z)
+#define DEBUG_MESSAGE1(i, z, a1)
+#define DEBUG_MESSAGE2(i, z, a1, a2)
+#define DEBUG_MESSAGE3(i, z, a1, a2, a3)
+#define DEBUG_MESSAGE4(i, z, a1, a2, a3, a4)
+
+#endif /* DEBUG <= 1 */
+
+/* Functions. */
+
+/* Given an unknown system name, return information for an unknown
+ system. If unknown systems are not permitted, this returns FALSE.
+ Otherwise, it translates the name as necessary for the spool
+ directory, and fills in *qsys. */
+extern boolean funknown_system P((pointer puuconf, const char *zsystem,
+ struct uuconf_system *qsys));
+
+/* See whether a file belongs in the spool directory. */
+extern boolean fspool_file P((const char *zfile));
+
+/* See if the current time matches a time span. If not, return FALSE.
+ Otherwise, return TRUE and set *pival and *pcretry to the values
+ from the matching element of the span. */
+extern boolean ftimespan_match P((const struct uuconf_timespan *qspan,
+ long *pival, int *pcretry));
+
+/* Determine the maximum size that may ever be transferred, given a
+ timesize span. If there are any time gaps larger than 1 hour not
+ described by the timesize span, this returns -1. Otherwise it
+ returns the largest size that may be transferred at some time. */
+extern long cmax_size_ever P((const struct uuconf_timespan *qtimesize));
+
+/* Send mail about a file transfer. */
+extern boolean fmail_transfer P((boolean fok, const char *zuser,
+ const char *zmail, const char *zwhy,
+ const char *zfrom, const char *zfromsys,
+ const char *zto, const char *ztosys,
+ const char *zsaved));
+
+/* See whether a file is in one of a list of directories. The zpubdir
+ argument is used to pass the directory names to zsysdep_local_file.
+ If fcheck is FALSE, this does not check accessibility. Otherwise,
+ if freadable is TRUE, the user zuser must have read access to the
+ file and all appropriate directories; if freadable is FALSE zuser
+ must have write access to the appropriate directories. The zuser
+ argument may be NULL, in which case all users must have the
+ appropriate access (this is used for a remote request). */
+extern boolean fin_directory_list P((const char *zfile,
+ char **pzdirs,
+ const char *zpubdir,
+ boolean fcheck,
+ boolean freadable,
+ const char *zuser));
+
+/* Parse a command string. */
+extern boolean fparse_cmd P((char *zcmd, struct scmd *qcmd));
+
+/* Make a log entry. */
+#ifdef __GNUC__
+#define GNUC_VERSION __GNUC__
+#else
+#define GNUC_VERSION 0
+#endif
+
+#if ANSI_C && HAVE_VFPRINTF
+extern void ulog P((enum tlog ttype, const char *zfmt, ...))
+#if GNUC_VERSION > 1
+ __attribute__ ((format (printf, 2, 3)))
+#endif
+ ;
+#else
+extern void ulog ();
+#endif
+
+#undef GNUC_VERSION
+
+/* Report an error returned by one of the uuconf routines. */
+extern void ulog_uuconf P((enum tlog ttype, pointer puuconf,
+ int iuuconf));
+
+/* Set the function to call if a fatal error occurs. */
+extern void ulog_fatal_fn P((void (*pfn) P((void))));
+
+/* If ffile is TRUE, send log entries to the log file rather than to
+ stderr. */
+extern void ulog_to_file P((pointer puuconf, boolean ffile));
+
+/* Set the ID number used by the logging functions. */
+extern void ulog_id P((int iid));
+
+/* Set the system name used by the logging functions. */
+extern void ulog_system P((const char *zsystem));
+
+/* Set the system and user name used by the logging functions. */
+extern void ulog_user P((const char *zuser));
+
+/* Set the device name used by the logging functions. */
+extern void ulog_device P((const char *zdevice));
+
+/* Close the log file. */
+extern void ulog_close P((void));
+
+/* Make an entry in the statistics file. */
+extern void ustats P((boolean fsucceeded, const char *zuser,
+ const char *zsystem, boolean fsent,
+ long cbytes, long csecs, long cmicros,
+ boolean fmaster));
+
+/* Close the statistics file. */
+extern void ustats_close P((void));
+
+#if DEBUG > 1
+/* A debugging routine to output a buffer. This outputs zhdr, the
+ buffer length clen, and the contents of the buffer in quotation
+ marks. */
+extern void udebug_buffer P((const char *zhdr, const char *zbuf,
+ size_t clen));
+
+/* A debugging routine to make a readable version of a character.
+ This takes a buffer at least 5 bytes long, and returns the length
+ of the string it put into it (not counting the null byte). */
+extern size_t cdebug_char P((char *z, int ichar));
+
+/* Parse a debugging option string. This can either be a number or a
+ comma separated list of debugging names. This returns a value for
+ iDebug. */
+extern int idebug_parse P((const char *));
+
+#endif /* DEBUG <= 1 */
+
+/* Copy one file to another. */
+extern boolean fcopy_file P((const char *zfrom, const char *zto,
+ boolean fpublic, boolean fmkdirs));
+
+/* Copy an open file to another. */
+extern boolean fcopy_open_file P((openfile_t efrom, const char *zto,
+ boolean fpublic, boolean fmkdirs));
+
+/* Translate escape sequences in a buffer, leaving the result in the
+ same buffer and returning the length. */
+extern size_t cescape P((char *zbuf));
+
+/* Get a buffer to hold a string of a given size. The buffer should
+ be freed with ubuffree. */
+extern char *zbufalc P((size_t csize));
+
+/* Call zbufalc to allocate a buffer and copy a string into it. */
+extern char *zbufcpy P((const char *z));
+
+/* Free up a buffer returned by zbufalc or zbufcpy. */
+extern void ubuffree P((char *z));
+
+/* Allocate memory without fail. */
+extern pointer xmalloc P((size_t));
+
+/* Realloc memory without fail. */
+extern pointer xrealloc P((pointer, size_t));
+
+/* Free memory (accepts NULL pointers, which some libraries erroneously
+ do not). */
+extern void xfree P((pointer));
+
+/* Global variables. */
+
+/* The name of the program being run. This is statically initialized,
+ although it should perhaps be set from argv[0]. */
+extern char abProgram[];
+
+/* When a signal occurs, the signal handlers sets the appropriate
+ element of the arrays afSignal and afLog_signal to TRUE. The
+ afSignal array is used to check whether a signal occurred. The
+ afLog_signal array tells ulog to log the signal; ulog will clear
+ the element after logging it, which means that if a signal comes in
+ at just the right moment it will not be logged. It will always be
+ recorded in afSignal, though. At the moment we handle 5 signals:
+ SIGHUP, SIGINT, SIGQUIT, SIGTERM and SIGPIPE (the Unix code also
+ handles SIGALRM). If we want to handle more, the afSignal array
+ must be extended; I see little point to handling any of the other
+ ANSI C or POSIX signals, as they are either unlikely to occur
+ (SIGABRT, SIGUSR1) or nearly impossible to handle cleanly (SIGILL,
+ SIGSEGV). SIGHUP is only logged if fLog_sighup is TRUE. */
+#define INDEXSIG_SIGHUP (0)
+#define INDEXSIG_SIGINT (1)
+#define INDEXSIG_SIGQUIT (2)
+#define INDEXSIG_SIGTERM (3)
+#define INDEXSIG_SIGPIPE (4)
+#define INDEXSIG_COUNT (5)
+
+extern volatile sig_atomic_t afSignal[INDEXSIG_COUNT];
+extern volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
+extern boolean fLog_sighup;
+
+/* The names of the signals to use in error messages, as an
+ initializer for an array. */
+#define INDEXSIG_NAMES \
+ { "hangup", "interrupt", "quit", "termination", "SIGPIPE" }
+
+/* Check to see whether we've received a signal. It would be nice if
+ we could use a single variable for this, but we sometimes want to
+ clear our knowledge of a signal and that would cause race
+ conditions (clearing a single element of the array is not a race
+ assuming that we don't care about a particular signal, even if it
+ occurs after we've examined the array). */
+#define FGOT_SIGNAL() \
+ (afSignal[INDEXSIG_SIGHUP] || afSignal[INDEXSIG_SIGINT] \
+ || afSignal[INDEXSIG_SIGQUIT] || afSignal[INDEXSIG_SIGTERM] \
+ || afSignal[INDEXSIG_SIGPIPE])
+
+/* If we get a SIGINT in uucico, we continue the current communication
+ session but don't start any new ones. This macros checks for any
+ signal other than SIGINT, which means we should get out
+ immediately. */
+#define FGOT_QUIT_SIGNAL() \
+ (afSignal[INDEXSIG_SIGHUP] || afSignal[INDEXSIG_SIGQUIT] \
+ || afSignal[INDEXSIG_SIGTERM] || afSignal[INDEXSIG_SIGPIPE])
+
+/* File being sent. */
+extern openfile_t eSendfile;
+
+/* File being received. */
+extern openfile_t eRecfile;
+
+/* Device name to log. This is set by fconn_open. It may be NULL. */
+extern char *zLdevice;
+
+/* If not NULL, ulog calls this function before outputting anything.
+ This is used to support cu. */
+extern void (*pfLstart) P((void));
+
+/* If not NULL, ulog calls this function after outputting everything.
+ This is used to support cu. */
+extern void (*pfLend) P((void));
diff --git a/gnu/libexec/uucp/contrib/Dial.Hayes b/gnu/libexec/uucp/contrib/Dial.Hayes
new file mode 100644
index 00000000000..32eef82d347
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Dial.Hayes
@@ -0,0 +1,108 @@
+#!xchat
+# @(#) dial.hayes V1.1 Tue Sep 1 13:59:58 1992 (Bob Denny)
+#
+# xchat script for dialing a vanilla Hayes modem
+#
+# Usage:
+# xchat dial.hayes telno
+#
+# where telno is the telephone number, subject to pause and wait
+# character modification.
+#
+# Uncomment the first two lines after "start:" to get debugging
+# in file "Dial.Log"
+#
+# Flush input, zero counter, set telephone number if supplied,
+# else fail if no telephone number given.
+#
+start:
+### dbgfile Dial.Log
+### dbgset 15
+ zero
+ flush
+ ifnstr notelno 0
+ telno 0
+ goto initmodem
+#
+# Missing telephone number.
+#
+notelno:
+ logerr No telephone number given
+ failed
+#
+# Reset the modem to nonvolatile profile.
+# Allow 3 sec. for response, as some modems are slow to reset.
+#
+initmodem:
+ count
+ ifgtr cantinit 4
+ send ATZ\r
+ timeout initmodem 3000
+ expect setupmodem OK
+#
+# No response from modem
+#
+cantinit:
+ logerr Can't wake modem
+ failed
+#
+# Send the stuff needed to initialize the modem to the modes
+# needed for the particular modem flavor. The string below
+# is provided as a vanilla example. Allow 2 sec. for the
+# modem to respond to this command.
+#
+setupmodem:
+ sleep 1000
+ send ATM0S7=90S11=120\r
+ timeout setupfail 2000
+ expect setupfail ERROR
+ expect dialnumber OK
+#
+# Modem barfed or died on setup command.
+#
+setupfail:
+ logerr Error in modem setup string
+ failed
+#
+# Dial the supplied number. Handle the various errors that
+# can come back from the modem by logging the error.
+#
+dialnumber:
+ sleep 1000
+ send ATDT
+ dial
+ send \r
+ flush
+ timeout timeout 90000
+ expect connected CONNECT
+ expect busy BUSY
+ expect nocarrier NO CARRIER
+ expect noanswer NO ANSWER
+ expect nodialtone NO DIALTONE
+#
+# Success!
+#
+connected:
+ success
+#
+# Handle modem dial failures
+#
+timeout:
+ logerr Modem or carrier timeout.
+ failed
+busy:
+ logerr BUSY
+ failed
+nocarrier:
+ logerr NO CARRIER
+ failed
+noanswer:
+ logerr NO ANSWER
+ failed
+nodialtone:
+ logerr NO DIALTONE
+ failed
+#
+# end
+#
+
diff --git a/gnu/libexec/uucp/contrib/Hangup.Hayes b/gnu/libexec/uucp/contrib/Hangup.Hayes
new file mode 100644
index 00000000000..c111c00fcae
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Hangup.Hayes
@@ -0,0 +1,57 @@
+#!xchat
+# @(#) Hangup.Hayes V1.1 Tue Sep 1 14:04:25 1992 (Bob Denny)
+#
+# xchat script for hanging up a Hayes-type modem. When used with Taylor
+# UUCP, this script should be run as the dialer-complete and dialer-abort
+# script with xchat.
+#
+# Usage:
+# xchat Hangup.Hayes [ x ]
+#
+# where 'x' is any string. If it is present, this script will log the
+# modem reset as an ABORT reset, otherwise it will not log anything.
+#
+# Uncomment the lines starting with '###' to get debugging log.
+#
+start:
+### dbgfile Hangup.Log
+### dbgset 15
+ zero
+ sleep 2000 # Wait for trailing garbage
+ flush # Toss it out
+ ifnstr wakemodem 0 # No abort indicator
+ log Hangup on abort
+#
+# Get modem's attention via Hayes 'escape' protocol.
+#
+wakemodem:
+ sleep 4000
+ send +++
+ sleep 4000
+ send \r
+ timeout reset 2000
+ expect reset OK
+#
+# We're (probably) in command mode. Use ATZ (reset) to hang up
+# as some modems don't behave well with ATH0 command.
+#
+reset:
+ send ATZ\r
+ timeout silent 5000
+ expect done OK
+#
+# Finished, modem is back in initial state.
+#
+done:
+ success
+#
+# No response to escape protocol. Log the error and force DTR low
+# in an attempt to get control of the modem. Then send ATZ just to
+# make sure.
+#
+silent:
+ logerr Hangup: no response from modem
+ hangup # Force DTR low as last gasp
+ send ATZ\r
+ sleep 5000
+ failed
diff --git a/gnu/libexec/uucp/contrib/Login.LAT b/gnu/libexec/uucp/contrib/Login.LAT
new file mode 100644
index 00000000000..d557f97e219
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.LAT
@@ -0,0 +1,137 @@
+#!xchat
+# @(#) login.LAT V1.2 Tue Sep 1 13:25:28 1992
+#
+# xchat script for logging into a VMS system through a LAT
+# terminal server port. If no VMS password parameter supplied,
+# skips password phase of VMS login. If LAT-password supplied,
+# will log into LAT server using that password. NOTE: does not
+# handle the situation where a LAT password is needed but no
+# VMS password is needed.
+#
+# Usage:
+# xchat login.LAT sysname username [ password [ LAT-password ] ]
+#
+# History:
+# rbd Fri Aug 14 13:37:06 1992
+# Changes for Lantronix ETS-16. It says "type help at the Local>
+# prompt..." then it gives the prompt for real! Prompt may need
+# to be something other than "Local>". We match the real Local>
+# prompt by matching the leading newline!
+#
+# rbd Tue Sep 1 13:04:32 1992
+# Remove absolute path name from log file. Now defaults per config.
+#
+start:
+ dbgfile Login.Log
+ dbgset 15
+ sleep 2000 # Wait 2 seconds
+ flush # Flush typeahead
+ ifnstr svrstart 3 # Skip server password if not given
+#
+# Starting point if server password supplied. Handle situation
+# where the server line may have been left waiting for username
+# or at local> prompt.
+#
+getsvrpwp:
+ zero
+l0:
+ count # Get server's password prompt
+ ifgtr deadmux 5 # die if 5 cr's don't do it
+ send \r
+ timeout l0 1000 # Wait and try again
+ expect dosvrpw ssword>
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Send server's password. Fail if don't get Username
+# or Local> prompt.
+#
+dosvrpw:
+ zero
+l2:
+ sendstr 3
+ send \r
+ timeout badsvrpw 5000 # Die if invalid
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Starting point if NO server password supplied. Handle situation
+# where the server line may have been left at local> prompt.
+#
+svrstart:
+ zero
+l1:
+ count # Get username> or local> prompt
+ ifgtr deadmux 5 # Die if 5 cr's don't do it
+ send \r
+ timeout l1 1000 # Wait and try again
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Server asked for a username. Just give 'uucp'.
+#
+svrlogin:
+ send uucp\r
+ timeout deadmux 2000
+ expect connect \nLocal>
+#
+# At this point, we have the Local> prompt. Send the connect
+# command for the specified LAT host service name, and wait for
+# VMS "Username:" prompt. Die after 10 seconds.
+#
+connect:
+ send c\s
+ sendstr 0
+ send \r
+ timeout nologin 10000
+ expect gotlogin ername:
+#
+# Got VMS "Username:" prompt. Send the username. If a password
+# was given, wait for the "Password:" prompt. Die after 10 seconds.
+# if no password was given, we're done!
+#
+gotlogin:
+ sendstr 1
+ send \r
+ ifnstr done 2
+ timeout nopasswd 10000
+ expect gotpasswd ssword:
+#
+# Got VMS "Password:" prompt. Send the password and we're done!
+#
+gotpasswd:
+ sendstr 2
+ send \r
+#
+# Success!
+#
+done:
+ success
+#
+# ERROR HANDLERS
+#
+#
+# LAT server appears dead. Fail.
+#
+deadmux:
+ logerr No response from LAT server
+ failed
+#
+# The server password was bad. Fail.
+#
+badsvrpw:
+ logerr Invalid LAT server password
+ failed
+#
+# VMS system appears to be dead. Fail.
+#
+nologin:
+ logerr No VMS Username: prompt
+ failed
+#
+# Failed to get "Password:" prompt. Fail.
+#
+nopasswd:
+ logerr No VMS Password: prompt. Invalid password?
+ failed
+
diff --git a/gnu/libexec/uucp/contrib/Login.PortSel b/gnu/libexec/uucp/contrib/Login.PortSel
new file mode 100644
index 00000000000..d8c3a6643a6
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.PortSel
@@ -0,0 +1,133 @@
+#!xchat
+# @(#) Login.PortSelUnix V1.0 Tue Sep 1 14:57:05 1992 (Bob Denny)
+#
+# NOTE: Untested with xchat V1.1. Taken from DECUS UUCP.
+#
+# From: "Kent C. Brodie" <moocow!brodie@CSD4.MILW.WISC.EDU>
+# uucp: {uunet!marque,csd4.milw.wisc.edu}!moocow!brodie
+# special script for "uwmcsd4", have to go through a port selector (and then
+# log in via standard Unix procedures).
+#
+# Also included is the ability to wait in the port selector queue.
+# Be forwarned that the debug log can get pretty big depending on
+# how many times you "wait" in the queue.
+# (C) 1989 Kent C. Brodie - Medical College of Wisconsin
+
+# P0 is systemname , P1 is username, P2 is password.
+
+ zero
+
+# send a CR to get the selector's attention. Sleep a little bit
+# due to large login text of selector. It sends "Which System?"
+# when it's ready.
+
+getprtslct:
+ count
+ ifgtr noprtslct 6
+ break
+ send \r
+ sleep 2000
+ flush
+ expect prtslctok ystem?
+ timeout getprtslct 15000
+
+noprtslct:
+ logerr Sent cr, no "Which System?" from port selector
+ failed
+
+# Send the system name. We either get "OK" (connected), or we
+# get "No ports available, would you like to wait?" (wait in queue)
+
+prtslctok:
+ zero
+ sendstr 0
+ send \r
+ expect connected OK
+ expect prtslctwait wait?
+ timeout noconnect 10000
+
+# Usually we get "nn Your place in queue" messages. JUST in case we
+# get a free port right away, check for 'Are you ready?' as well.
+
+prtslctwait:
+ zero
+ send Y\r
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout prtwaitbad 70000
+
+prtwaitbad:
+ logerr Sent "Y" to wait in queue, did not get valid response.
+ failed
+
+# Here's where we wait in the queue. The port selector sends us a status
+# message about once a minute. We either get "nn Your place in queue"
+# or we get "System Available. Are you Ready?".
+# If something goes wrong, we time out waiting for either response.
+# The reason we don't sleep for 40-50 seconds is because as SOON as the
+# port is ready, it informs us. If we wait too long, it drops us.
+# This setup is laid out for a maximum of 20 "tries" which is ABOUT
+# 20 minutes. Note: This constant retrying can make log files
+# kind of big....
+
+prtslctque:
+ count
+ ifgtr prtslcttry 20
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout noportwait 70000
+
+prtslcttry:
+ logerr Too many (20) wait/retries -- queue too busy.
+ failed
+
+prtslctrdy:
+ send Y\r
+ expect connected OK
+ timeout noconnect 20000
+
+
+noportwait:
+ logerr Timed out awaiting place in port queue
+ failed
+
+noconnect:
+ logerr Sent system name, no "OK" from selector
+ failed
+
+# standard Unix login stuff. Send cr, expect "ogin:", if no, send a break
+# (which tells Unix to try the next bit rate) and try again.
+
+connected:
+ send \r
+ zero
+ goto waitlogin
+
+sendbreak:
+ count
+ ifgtr nolgi 6
+ flush
+ break
+
+waitlogin:
+ expect gotlogin ogin:
+ timeout sendbreak 5000
+
+nolgi:
+ logerr No login: prompt
+ failed
+
+gotlogin:
+ sendstr 1
+ send \r
+ expect gotword word:
+ timeout nopwd 10000
+
+nopwd:
+ logerr No password: prompt
+ failed
+
+gotword:
+ sendstr 2
+ send \r
+ success
diff --git a/gnu/libexec/uucp/contrib/Login.VMS b/gnu/libexec/uucp/contrib/Login.VMS
new file mode 100644
index 00000000000..d6196cb2aa6
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.VMS
@@ -0,0 +1,96 @@
+#!xchat
+# @(#) Login.VMS V1.1 Tue Sep 1 13:24:54 1992 (Bob Denny)
+#
+#
+# xchat script for logging into a VMS system. If no VMS password
+# parameter supplied, skips password phase of VMS login. If syspass
+# parameter given, will go through steps needed to log into a VMS
+# system where a "system password" was set on the port.
+#
+# Cannot handle situation where system password is required but
+# no password needed.
+#
+#
+# Usage:
+# xchat Login.VMS username [ password [ syspass ] ]
+#
+# Uncomment the lines starting with "###" to get debug logging.
+#
+start:
+### dbgfile Login.Log
+### dbgset 15
+ sleep 2000 # Wait 2 seconds
+ zero
+ flush # Flush typeahead
+ ifnstr login 2 # Skip sys passwd if not given
+#
+# Need system password. Send <CR> to get bell.
+# Try 5 times at 2 sec. intervals. Skip to do
+# username if we see "Username:".
+#
+syspass:
+ count
+ ifgtr nobell 5 # Fail after 5 tries
+ send \r
+ timeout syspass 2000 # Wait 2 sec. and try again
+ expect gotbell \007
+ expect gotlogin Username:
+#
+# Got the bell. Send the system password. Repeat 5 times
+# at 2 sec. intervals. Fail if we don't get Username:
+#
+gotbell:
+ zero
+ sleep 2000
+l1:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ sendstr 2
+ send \r
+ timeout l1 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Start here if no system password supplied.
+# Send <CR> until we get Username: Try 5 times at 2 sec. intervals.
+#
+login:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ send \r
+ timeout login 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Got VMS "Username:" prompt. Send the username. If a password
+# was given, wait for the "Password:" prompt. Die after 10 seconds.
+# if no password was given, we're done!
+#
+gotlogin:
+ sendstr 0
+ send \r
+ ifnstr done 1
+ timeout nopasswd 10000
+ expect gotpasswd Password:
+#
+# Got VMS "Password:" prompt. Send the password and we're done!
+#
+gotpasswd:
+ sendstr 1
+ send \r
+#
+# Success!
+#
+done:
+ success
+#
+# ERROR HANDLERS
+#
+nobell:
+ logerr No VMS system password prompt (bell)
+ failed
+nologin:
+ logerr No VMS Username: prompt
+ failed
+nopasswd:
+ logerr No VMS Password: prompt.
+ failed
+
diff --git a/gnu/libexec/uucp/contrib/Makefile.uurt b/gnu/libexec/uucp/contrib/Makefile.uurt
new file mode 100644
index 00000000000..235fcca889f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Makefile.uurt
@@ -0,0 +1,30 @@
+#
+# Makefile for uurate 1.0
+#
+
+# Where uurate is installed
+BIN=/usr/local/bin
+
+# Flags to use when compiling uurate
+CFLAGS=-I..
+
+CC=cc
+SHELL=/bin/sh
+PROGS=uurate
+
+#-----------
+
+all: $(PROGS)
+
+install: $(PROGS)
+ @for i in $(PROGS) ; do \
+ echo "Install $$i into $(BIN)..." ; \
+ cp $$i $(BIN) ; \
+ echo "Set ownership and protection..." ; \
+ /bin/chmod 0555 $(BIN)/$$i ; \
+ /bin/chown bin $(BIN)/$$i ; \
+ /bin/chgrp bin $(BIN)/$$i ; \
+ done
+
+clean:
+ rm -f $(PROGS) core
diff --git a/gnu/libexec/uucp/contrib/Makefile.xchat b/gnu/libexec/uucp/contrib/Makefile.xchat
new file mode 100644
index 00000000000..5e9aaa8ffed
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Makefile.xchat
@@ -0,0 +1,31 @@
+#
+# Makefile for xchat 1.1
+#
+# Bob Denny - Tue Sep 1 15:58:22 1992
+#
+CC=cc
+SHELL=/bin/sh
+BIN=/usr/local/lib/uucp
+PROGS=xchat
+
+#-----------
+
+all: $(PROGS)
+
+install: $(PROGS)
+ @for i in $(PROGS) ; do \
+ echo "Install $$i into $(BIN)..." ; \
+ cp $$i $(BIN) ; \
+ echo "Set ownership and protection..." ; \
+ /bin/chmod 0555 $(BIN)/$$i ; \
+ /bin/chown bin $(BIN)/$$i ; \
+ /bin/chgrp bin $(BIN)/$$i ; \
+ done
+
+clean:
+ rm -f $(PROGS) core
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/README b/gnu/libexec/uucp/contrib/README
new file mode 100644
index 00000000000..c4105ed0386
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README
@@ -0,0 +1,46 @@
+This is the README file for the Taylor UUCP contrib directory.
+
+This directory contains contributed shell scripts and programs that
+you may find useful.
+
+xchat.c, xchat.man, README-XCHAT, xc-conf.h-dist, Makefile.xchat:
+ A program by Bob Denny that may be invoked by the ``chat-program''
+ command for any of the various types of chat scripts. It is
+ driven by scripts which are written in its own little language.
+ It is a powerful program that can add a lot of flexibility to your
+ chat scripts.
+
+Dial.Hayes, Hangup.Hayes, Login.LAT, Login.PortSel, Login.VMS:
+ Sample scripts for xchat.
+
+uurate.c, uurate.man, README-UURATE, Makefile.uurt:
+ A nifty little program by Bob Denny which analyzes the Log and
+ Stats file and prints various sorts of reports.
+
+uutraf:
+ Another program to produce neat reports from your log files, this
+ one a perl script by Johan Vromans.
+
+savelog.sh, savelog.man:
+ A handy shell script to rename a log file and cycle old versions
+ through a set of names, throwing away the oldest one. It will
+ also optionally compress the old log files. I believe that this
+ is originally from smail. It was written by Ronald S. Karr and
+ Landon Curt Noll, and was given to me by Bob Denny.
+
+uureroute:
+ A perl script reroute all mail queued up for one host to another.
+ Written by Bill Campbell and contributed by Francois Pinard.
+
+stats.sh:
+ A gawk script by Zacharias Beckman which reads the Stats file and
+ prints the last 80 lines as a nicely formatted table.
+
+uuq.sh:
+ A uuq workalike shell script by Zacharias Beckman.
+
+tstout.c:
+ A program to remove a user from utmp and wtmp, essentially logging
+ them out. I put this together from BSD code. I need it to use
+ tstuu with the system UUCP on Ultrix 4.0, for reasons that escape
+ me. Most people will have little use for this.
diff --git a/gnu/libexec/uucp/contrib/README-UURATE b/gnu/libexec/uucp/contrib/README-UURATE
new file mode 100644
index 00000000000..2cc361ce26f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README-UURATE
@@ -0,0 +1,20 @@
+uurate V1.2 - Gather and display Taylor UUCP traffic statistics
+
+Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992
+
+See the man page for documentation.
+
+Installation:
+------------
+
+(1) Copy Makefile.uurt to Makefile.
+
+(2) Edit Makefile: set BIN where you want uurate to be installed, and
+ set CFLAGS to point to the directory containing the UUCP sources
+ (this is .. by default).
+
+(3) Type ``make'' to compile the program.
+
+(4) Type ``make install'' to install the program.
+
+(5) Install the man page if you want. I didn't put that into the Makefile.
diff --git a/gnu/libexec/uucp/contrib/README-XCHAT b/gnu/libexec/uucp/contrib/README-XCHAT
new file mode 100644
index 00000000000..5f93a284bda
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README-XCHAT
@@ -0,0 +1,42 @@
+This is xchat V1.1 (Tue Sep 1 15:50:56 1992)
+
+Introduction:
+------------
+
+Xchat is a general-purpose dialing and login program designed for use
+with Taylor UUCP as a "chat-program", taking the place (or augmenting)
+the built-in chat scripting facility. It provides the ability to
+closely control timeouts, multiple simultaneous expect strings with
+separate actions, extended terminal control, modem command character
+pacing, and more.
+
+When used in conjunction with Taylor UUCP's configuration features,
+xchat can provide you the ability to manage the most intricate login,
+dial and hangup needs. The scripts are written in a shell-like (well,
+sort-of) style with labels, commands, and parameters, easing the task
+of writing procedures for complex terminal communications situations.
+
+Installation:
+------------
+
+(1) Copy xc-conf.h-dist to xc-conf.h, then edit xc-conf.h to reflect
+ your condifuration. A description of the settings is in that file.
+
+(2) Copy Makefile.xchat to Makefile and edit it to set BIN to where
+ you want xchat installed.
+
+(2) Do a 'make' to build xchat.
+
+(3) Do a 'make install' to install it.
+
+(4) Format and print xchat.8, and install it if you want.
+
+(5) Print out copies of the scripts in the ./scripts subdirectory.
+
+(6) Read xchat.8 and the scripts together.
+
+
+Author:
+------
+
+Robert B. Denny (denny@alisa.com)
diff --git a/gnu/libexec/uucp/contrib/savelog.man b/gnu/libexec/uucp/contrib/savelog.man
new file mode 100644
index 00000000000..919b94f4ec1
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.man
@@ -0,0 +1,130 @@
+.\" @(#)man/man8/savelog.an 1.2 24 Oct 1990 05:18:46
+.de pP
+.if n .sp 1
+.if t .sp .4
+..
+.de tP
+.pP
+.ta \\n(pDu
+.ti -\\n(pDu
+..
+.TH SAVELOG X_MAN8_EXT_X "31 January 1988" "Local"
+.SH NAME
+savelog \- cycle and truncate log files
+.SH SYNOPSIS
+.na
+.B X_UTIL_BIN_DIR_X/savelog
+[
+.B \-m
+.I mode
+] [
+.B \-u
+.I user
+] [
+.B \-g
+.I group
+] [
+.B \-c
+.I cycle
+] [
+.B \-t
+] [
+.B \-l
+]
+.I logfile
+.br
+.ad
+.SH DESCRIPTION
+The
+.I savelog
+command renames and optionally compresses a log file and cycles it
+through a set of names based on the original log file, removing the
+last name in the cycle.
+.SH OPTIONS
+The
+.I savelog
+command accepts the following options:
+.TP
+\fB\-m\fP \fImode\fP
+Change the permissions mode for renamed log files to
+.IR mode .
+By default the mode is unchanged.
+.TP
+\fB\-u\fP \fIuser\fP
+Change the owner for renamed log files to
+.IR user .
+By default the owner is unchanged.
+.TP
+\fB\-g\fP \fIgroup\fP
+Change the group for renamed log files to
+.IR group .
+By default the group is unchanged.
+.TP
+\fB\-c\fP \fIcycle\fP
+Save
+.I cycle
+versions of the logfile, where
+.I cycle
+is a decimal number. The default value is 7.
+.TP
+.B \-l
+Do not compress log files. By default, a compression program is used,
+if one is available.
+.TP
+.B \-t
+Ensure that a new logfile exists when the savelog operation is
+complete. Use of
+.BR \-m ,
+.BR \-u
+or
+.BR \-g
+imply this, ensuring that the logfile will have the designated mode.
+.SH "OPERATION"
+The given logfile is cycled through files named:
+.RS
+
+OLD/\fIfile\fP.\fInumber\fP
+
+.RE
+where
+.I file
+is the basename for the logfile and where
+.I number
+ranges from 0 to one less then the
+.I cycle
+count specified for the command.
+The
+.I OLD
+dirctory is created, as necessary, and is under the same directory as
+the logfile itself.
+.PP
+This cycle operation is accomplished by renaming the file numbered
+.IR cycle -2
+to a file numbered
+.IR cycle -1
+and so on until the file numbered 0 is renamed to the file numbered 1.
+If compression is being used, the first cycle file is compressed after
+being renamed to cycle 1. After the cycle files are moved through the
+various names, the filefile itself is moved to the cycle 0 file.
+This cycle normally occurs once every time
+.I savelog
+is executed.
+If the log file does not exist, savelog ignores it and does
+not cycle the OLD files.
+.PP
+If compression is being used, then compressed log files will have an
+additional suffix appropriate for the compression program that is
+used.
+.SH "SEE ALSO"
+.IR smail (X_MAN5_EXT_X)
+and
+.IR smail (X_MAN8_EXT_X).
+.SH COPYRIGHT
+Copyright(C)1987, 1988 Ronald S. Karr and Landon Curt Noll
+.br
+See a file COPYING,
+distributed with the source code,
+or type
+.I "smail \-bc"
+for distribution rights and restrictions
+associated with this software.
diff --git a/gnu/libexec/uucp/contrib/savelog.sh b/gnu/libexec/uucp/contrib/savelog.sh
new file mode 100755
index 00000000000..64c989f292b
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.sh
@@ -0,0 +1,247 @@
+#! /bin/sh
+# @(#)util/savelog.sh 1.4 26 Oct 1991 22:49:39
+#
+# savelog - save a log file
+#
+# Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
+#
+# See the file COPYING, distributed with smail, for restriction
+# and warranty information.
+#
+# usage: savelog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-l] file...
+#
+# -m mode - chmod log files to mode
+# -u user - chown log files to user
+# -g group - chgrp log files to group
+# -c cycle - save cycle versions of the logfile (default: 7)
+# -t - touch file
+# -l - don't compress any log files (default: compress)
+# file - log file names
+#
+# The savelog command saves and optionally compresses old copies of files
+# into an 'dir'/OLD sub-directory. The 'dir' directory is determined from
+# the directory of each 'file'.
+#
+# Older version of 'file' are named:
+#
+# OLD/'file'.<number><compress_suffix>
+#
+# where <number> is the version number, 0 being the newest. By default,
+# version numbers > 0 are compressed (unless -l prevents it). The
+# version number 0 is never compressed on the off chance that a process
+# still has 'file' opened for I/O.
+#
+# If the 'file' does not exist or if it is zero length, no further processing
+# is performed. However if -t was also given, it will be created.
+#
+# For files that do exist and have lengths greater than zero, the following
+# actions are performed.
+#
+# 1) Version numered files are cycled. That is version 6 is moved to
+# version 7, version is moved to becomes version 6, ... and finally
+# version 0 is moved to version 1. Both compressed names and
+# uncompressed names are cycled, regardless of -t. Missing version
+# files are ignored.
+#
+# 2) The new OLD/file.1 is compressed and is changed subject to
+# the -m, -u and -g flags. This step is skipped if the -t flag
+# was given.
+#
+# 3) The main file is moved to OLD/file.0.
+#
+# 4) If the -m, -u, -g or -t flags are given, then file is created
+# (as an empty file) subject to the given flags.
+#
+# 5) The new OLD/file.0 is chanegd subject to the -m, -u and -g flags.
+#
+# Note: If the OLD sub-directory does not exist, it will be created
+# with mode 0755.
+#
+# Note: If no -m, -u or -g flag is given, then the primary log file is
+# not created.
+#
+# Note: Since the version numbers start with 0, version number <cycle>
+# is never formed. The <cycle> count must be at least 2.
+#
+# Bugs: If a process is still writing to the file.0 and savelog
+# moved it to file.1 and compresses it, data could be lost.
+# Smail does not have this problem in general because it
+# restats files often.
+
+# common location
+PATH="X_UTIL_PATH_X:X_SECURE_PATH_X"; export PATH
+COMPRESS="X_COMPRESS_X"
+COMP_FLAG="X_COMP_FLAG_X"
+DOT_Z="X_DOT_Z_X"
+CHOWN="X_CHOWN_X"
+GETOPT="X_UTIL_BIN_DIR_X/getopt"
+
+# parse args
+exitcode=0 # no problems to far
+prog=$0
+mode=
+user=
+group=
+touch=
+count=7
+set -- `$GETOPT m:u:g:c:lt $*`
+if [ $# -eq 0 -o $? -ne 0 ]; then
+ echo "usage: $prog [-m mode][-u user][-g group][-t][-c cycle][-l] file ..." 1>&2
+ exit 1
+fi
+for i in $*; do
+ case $i in
+ -m) mode=$2; shift 2;;
+ -u) user=$2; shift 2;;
+ -g) group=$2; shift 2;;
+ -c) count=$2; shift 2;;
+ -t) touch=1; shift;;
+ -l) COMPRESS=""; shift;;
+ --) shift; break;;
+ esac
+done
+if [ "$count" -lt 2 ]; then
+ echo "$prog: count must be at least 2" 1>&2
+ exit 2
+fi
+
+# cycle thru filenames
+while [ $# -gt 0 ]; do
+
+ # get the filename
+ filename=$1
+ shift
+
+ # catch bogus files
+ if [ -b "$filename" -o -c "$filename" -o -d "$filename" ]; then
+ echo "$prog: $filename is not a regular file" 1>&2
+ exitcode=3
+ continue
+ fi
+
+ # if not a file or empty, do nothing major
+ if [ ! -s $filename ]; then
+ # if -t was given and it does not exist, create it
+ if [ ! -z "$touch" -a ! -f $filename ]; then
+ touch $filename
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not touch $filename" 1>&2
+ exitcode=4
+ continue
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+ fi
+ continue
+ fi
+
+ # be sure that the savedir exists and is writable
+ savedir=`expr "$filename" : '\(.*\)/'`
+ if [ -z "$savedir" ]; then
+ savedir=./OLD
+ else
+ savedir=$savedir/OLD
+ fi
+ if [ ! -s $savedir ]; then
+ mkdir $savedir
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not mkdir $savedir" 1>&2
+ exitcode=5
+ continue
+ fi
+ chmod 0755 $savedir
+ fi
+ if [ ! -d $savedir ]; then
+ echo "$prog: $savedir is not a directory" 1>&2
+ exitcode=6
+ continue
+ fi
+ if [ ! -w $savedir ]; then
+ echo "$prog: directory $savedir is not writable" 1>&2
+ exitcode=7
+ continue
+ fi
+
+ # deterine our uncompressed file names
+ newname=`expr "$filename" : '.*/\(.*\)'`
+ if [ -z "$newname" ]; then
+ newname=$savedir/$filename
+ else
+ newname=$savedir/$newname
+ fi
+
+ # cycle the old compressed log files
+ cycle=`expr $count - 1`
+ rm -f $newname.$cycle $newname.$cycle$DOT_Z
+ while [ "$cycle" -gt 1 ]; do
+ # --cycle
+ oldcycle=$cycle
+ cycle=`expr $cycle - 1`
+ # cycle log
+ if [ -f $newname.$cycle$DOT_Z ]; then
+ mv -f $newname.$cycle$DOT_Z $newname.$oldcycle$DOT_Z
+ fi
+ if [ -f $newname.$cycle ]; then
+ # file was not compressed for some reason move it anyway
+ mv -f $newname.$cycle $newname.$oldcycle
+ fi
+ done
+
+ # compress the old uncompressed log if needed
+ if [ -f $newname.0 ]; then
+ if [ -z "$COMPRESS" ]; then
+ newfile=$newname.1
+ mv $newname.0 $newfile
+ else
+ newfile=$newname.1$DOT_Z
+ $COMPRESS $COMP_FLAG < $newname.0 > $newfile
+ rm -f $newname.0
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newfile
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newfile
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newfile
+ fi
+ fi
+
+ # move the file into the file.0 holding place
+ mv -f $filename $newname.0
+
+ # replace file if needed
+ if [ ! -z "$touch" -o ! -z "$user" -o \
+ ! -z "$group" -o ! -z "$mode" ]; then
+ touch $filename
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+
+ # fix the permissions on the holding place file.0 file
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newname.0
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newname.0
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newname.0
+ fi
+done
+exit $exitcode
diff --git a/gnu/libexec/uucp/contrib/stats.sh b/gnu/libexec/uucp/contrib/stats.sh
new file mode 100755
index 00000000000..ac1d0f556ee
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/stats.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# uuspeed - a script to parse a Taylor UUCP Stats file into pretty results.
+# Zacharias J. Beckman.
+
+grep bytes /usr/spool/uucp/Stats | grep -v 'bytes 0.00 secs' | grep -v 'failed after' | tail -80 | \
+gawk '
+ BEGIN {
+ printf(" UUCP transmission history:\n");
+ format=" %8d bytes %8s(%8s) in %7.2f sec = %5.0f baud, %4.1fK / min\n";
+ average=0.01;
+ samples=0;
+ }
+
+ {
+ if ($6 > 100) {
+ printf (format, $6, $5, $2, $9, $6/$9*10, ($6/$9*60)/1000);
+
+ average += ($6/$9*10);
+ samples += 1;
+ }
+ }
+
+ END {
+ printf (" average speed %d baud\n", average/samples);
+ }
+'
diff --git a/gnu/libexec/uucp/contrib/tstout.c b/gnu/libexec/uucp/contrib/tstout.c
new file mode 100644
index 00000000000..dd82633c7a0
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/tstout.c
@@ -0,0 +1,158 @@
+/* tstout.c
+ Put together by Ian Lance Taylor <ian@airs.com>
+
+ This program is used to logout a program run by the tstuu program.
+ I needed this because on Ultrix 4.0 I can't get the uucp program
+ to run without invoking it via /bin/login and having it start up
+ as a shell. If I don't do it this way, it gets a SIGSEGV trap
+ for some reason. Most systems probably don't need to do things
+ this way. It will only work on BSD systems anyhow, I suspect.
+
+ The code for this comes from "UNIX Network Programming" by W.
+ Richard Stevens, Prentice-Hall 1990. Most of it is from 4.3BSD, as
+ noted in the comments.
+
+ This program must run suid to root.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <utmp.h>
+
+static int logout P((const char *zdev));
+static void logwtmp P((const char *zdev, const char *zname,
+ const char *zhost));
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *z;
+
+ if (argc != 2
+ || strncmp (argv[1], "/dev/", sizeof "/dev/" - 1) != 0)
+ {
+ fprintf (stderr, "Usage: tstout device\n");
+ exit (EXIT_FAILURE);
+ }
+
+ z = argv[1] + 5;
+
+ if (logout (z))
+ logwtmp (z, "", "");
+
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ *z = 'p';
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ exit (EXIT_SUCCESS);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logout.c 5.2 (Berkeley) 2/17/89";
+#endif /* LIBC_SCCS and not lint */
+
+#define UTMPFILE "/etc/utmp"
+
+/* 0 on failure, 1 on success */
+
+static int
+logout(line)
+ register const char *line;
+{
+ register FILE *fp;
+ struct utmp ut;
+ int rval;
+ time_t time();
+
+ if (!(fp = fopen(UTMPFILE, "r+")))
+ return(0);
+ rval = 0;
+ while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) {
+ if (!ut.ut_name[0] ||
+ strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
+ continue;
+ bzero(ut.ut_name, sizeof(ut.ut_name));
+ bzero(ut.ut_host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR);
+ (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp);
+ (void)fseek(fp, (long)0, L_INCR);
+ rval = 1;
+ }
+ (void)fclose(fp);
+ return(rval);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88";
+#endif /* LIBC_SCCS and not lint */
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+static void
+logwtmp(line, name, host)
+ const char *line, *name, *host;
+{
+ struct utmp ut;
+ struct stat buf;
+ int fd;
+ time_t time();
+ char *strncpy();
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ (void)close(fd);
+}
diff --git a/gnu/libexec/uucp/contrib/uuclean b/gnu/libexec/uucp/contrib/uuclean
new file mode 100644
index 00000000000..e9c631c86c3
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuclean
@@ -0,0 +1,23 @@
+# This is a sample uuclean shell script
+# Copyright (C) 1992 Ian Lance Taylor
+# Do whatever you like with this script.
+#
+# Set some variables
+bindir=/usr/local/bin
+spooldir=/usr/spool/uucp
+#
+# Warn about all mail over two days old
+$(bindir)/uustat -c rmail -o 48 -N -Q -W"Unable to deliver; will try up to one week"
+# Return all mail over a week old
+$(bindir)/uustat -c rmail -o 168 -K -M -N -Q -W"Could not be delivered for over one week"
+# Throw away other requests over a week old
+$(bindir)/uustat -o 168 -K -M -N -Q -W"Over one week old"
+# Throw away any executions over three days old
+$(bindir)/uustat -o 72 -M -N -Q -W"Unable to execute for three days"
+#
+# Now delete any old spool files
+find $(spooldir) -ctime +8 -name '[CDX].*' -print -exec rm -f \{\} \;
+# Delete any old temporary files
+find $(spooldir) -atime +1 -ctime +1 -name 'TM.*' -print -exec rm -f \{\} \;
+# Delete any old preserved files
+find $(spooldir)/.Preserve -atime +14 -ctime +14 -print -exec rm -f \{\} \;
diff --git a/gnu/libexec/uucp/contrib/uuq.sh b/gnu/libexec/uucp/contrib/uuq.sh
new file mode 100755
index 00000000000..a5d88e95223
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuq.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# uuq - a script to examine and display the Taylor spool directory contents.
+# note - uses the uuname script or similar functionality.
+# Zacharias Beckman
+
+SPOOLDIR="/usr/spool/uucp"
+SYSTEMS=`uuname`
+TMPFILE="/tmp/uuq.tmp"
+FORSYSTEM=""
+DELETE=""
+LONG=0
+SINGLE=0
+
+while [ "$1" != "" ]
+do
+ case $1 in
+ -l) LONG=1
+ shift
+ ;;
+ -s) shift
+ SYSTEMS=$argv[1]
+ SINGLE=1
+ shift
+ ;;
+ -d) shift
+ DELETE=$argv[1]
+ shift
+ ;;
+ -h) echo "uuq: usage uuq [options]"
+ echo " -l long listing (may take a while)"
+ echo " -s n run uuq only for system n"
+ echo " -d n delete item n from the queue (required -s)"
+ exit 1
+ ;;
+ *) echo "uuq: invalid option"
+ exit 1
+ ;;
+ esac
+done
+
+if [ "${DELETE}" != "" ] && [ ${SINGLE} != 1 ] ; then
+ echo "uuq: you must specify a system to delete the job from:"
+ echo " uuq -s wizard -d D.0004"
+ exit 1
+fi
+
+cd ${SPOOLDIR}
+
+# if we are deleting a job, then do that first and exit without showing
+# any other queue information
+
+if [ "${DELETE}" != "" ] ; then
+ if [ -d ${SYSTEMS}/D. ] ; then
+ cd ${SYSTEMS}/C.
+ PACKET=${DELETE}
+ if [ -f ${PACKET} ] ; then
+ EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}`
+ DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}`
+ echo "deleting job ${PACKET}"
+ rm ${PACKET}
+ rm ${EXFILE}
+ rm ${DFILE}
+ else
+ echo "uuq: job ${PACKET} not found"
+ exit 1
+ fi
+ else
+ echo "uuq: system ${SYSTEMS} not found"
+ fi
+
+ exit 1
+fi
+
+# use the 'uuname' script to obtain a list of systems for the 'sys' file,
+# then step through each directory looking for appropriate information.
+
+if [ ${LONG} -gt 0 ] ; then
+ echo "system"
+ echo -n "job# act size command"
+fi
+
+for DESTSYSTEM in ${SYSTEMS} ; do
+ # if there is an existing directory for the named system, cd into it and
+ # "do the right thing."
+
+ if [ -d ${DESTSYSTEM} ] ; then
+ cd ${DESTSYSTEM}/C.
+
+ PACKET=`ls`
+
+ if [ "${PACKET}" != "" ] ; then
+ # if a long listing has been required, extra information is printed
+
+ echo ""
+ echo "${DESTSYSTEM}:"
+
+ # now each packet must be examined and appropriate information is
+ # printed for this system
+
+ if [ ${LONG} -gt 0 ] ; then
+ for PACKET in * ; do
+ EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}`
+ DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}`
+ echo -n "${PACKET} " > ${TMPFILE}
+ gawk '{if (NR == 2) printf(" %s ", $1);}' ${PACKET} >> ${TMPFILE}
+ ls -l ${DFILE}|awk '{printf("%-10d ", $4)}' >> ${TMPFILE}
+ if [ -f ${EXFILE} ] ; then
+ gawk '/U / {printf("(%s)", $2);}\
+ /C / {print substr($0,2,length($0));}' ${EXFILE} >> ${TMPFILE}
+ else
+ echo "---" >> ${TMPFILE}
+ fi
+
+ cat ${TMPFILE}
+ done
+ cat ${SPOOLDIR}/.Status/${DESTSYSTEM}
+ else
+ ls
+ fi
+ fi
+ fi
+
+ cd ${SPOOLDIR}
+done
diff --git a/gnu/libexec/uucp/contrib/uurate.c b/gnu/libexec/uucp/contrib/uurate.c
new file mode 100644
index 00000000000..ceab41c53bf
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.c
@@ -0,0 +1,657 @@
+/*
+ * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992
+ *
+ * This program digests log and stats files in the "Taylor" format
+ * and outputs various statistical data to standard out.
+ *
+ * Author:
+ * Bob Denny (denny@alisa.com)
+ * Fri Feb 7 13:38:36 1992
+ *
+ * Original author:
+ * Mark Pizzolato mark@infopiz.UUCP
+ *
+ * Edits:
+ * Bob Denny - Fri Feb 7 15:04:54 1992
+ * Heavy rework for Taylor UUCP. This was the (very old) uurate from
+ * DECUS UUCP, which had a single logfile for activity and stats.
+ * Personally, I would have done things differently, with tables
+ * and case statements, but in the interest of time, I preserved
+ * Mark Pizzolato's techniques and style.
+ *
+ * Bob Denny - Sun Aug 30 14:18:50 1992
+ * Changes to report format suggested by Francois Pinard and others.
+ * Add summary report, format from uutraf.pl (perl script), again
+ * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
+ */
+
+char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2";
+
+#include <ctype.h> /* Character Classification */
+#include <string.h>
+#include <math.h>
+
+#include "uucp.h"
+
+
+#define _DEBUG_ 0
+
+/*
+ * Direction of Calling and Data Transmission
+ */
+#define IN 0 /* Inbound */
+#define OUT 1 /* Outbound */
+
+/*
+ * Data structures used to collect information
+ */
+struct File_Stats
+ {
+ int files; /* Files Transferred */
+ unsigned long bytes; /* Data Size Transferred*/
+ double time; /* Transmission Time */
+ };
+
+struct Phone_Call
+ {
+ int calls; /* Call Count */
+ int succs; /* Successful calls */
+ double connect_time; /* Connect Time Spent */
+ struct File_Stats flow[2]; /* Rcvd & Sent Data */
+ };
+
+struct Execution_Command
+ {
+ struct Execution_Command *next;
+ char Commandname[64];
+ int count;
+ };
+
+struct Host_entry
+ {
+ struct Host_entry *next;
+ char Hostname[32];
+ struct Execution_Command *cmds; /* Local Activities */
+ struct Phone_Call call[2]; /* In & Out Activities */
+ };
+
+/*
+ * Stuff for getopt()
+ */
+extern int optind; /* GETOPT : Option Index */
+extern char *optarg; /* GETOPT : Option Value */
+extern void *calloc();
+
+static void fmtime();
+static void fmbytes();
+
+/*
+ * Default files to read. Taken from Taylor compile-time configuration.
+ * Must look like an argvec, hence the dummy argv[0].
+ */
+static char *(def_logs[3]) = { "", LOGFILE, STATFILE };
+
+/*
+ * Misc. strings for reports
+ */
+static char *(file_hdr[2]) = { "\nReceived file statistics:\n",
+ "\nSent file statistics\n" };
+
+/*
+ * BEGIN EXECUTION
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char c;
+ char *p, *s;
+ struct Host_entry *hosts = NULL;
+ struct Host_entry *cur = NULL;
+ struct Host_entry *e;
+ struct Execution_Command *cmd;
+ struct Execution_Command *ec;
+ char Hostname[64];
+ FILE *Log = NULL;
+ char logline[1024];
+ char *logmsg;
+ int sent;
+ int called;
+ int show_files = 0; /* I prefer boolean, but... */
+ int show_calls = 0;
+ int show_commands = 0;
+ int show_efficiency = 0;
+ int show_summary = 0;
+ int have_files = 0;
+ int have_calls = 0;
+ int have_commands = 0;
+ int use_stdin = 0;
+ Hostname[0] = '\0';
+
+ /*
+ * I wish the compiler had the #error directive!
+ */
+#if !HAVE_TAYLOR_LOGGING
+ fprintf(stderr, "uurate cannot be used with your configuration of\n");
+ fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n");
+ fprintf(stderr, "TAYLOR_LOGGING configuration.\n");
+ exit(1);
+#endif
+
+ /*
+ * Process the command line arguments
+ */
+ while((c = getopt(argc, argv, "h:cfexai")) != EOF)
+ {
+ switch(c)
+ {
+ case 'h':
+ strcpy(Hostname, optarg);
+ break;
+ case 'c':
+ show_calls = 1;
+ break;
+ case 'f':
+ show_files = 1;
+ break;
+ case 'x':
+ show_commands = 1;
+ break;
+ case 'e':
+ show_efficiency = 1;
+ break;
+ case 'a':
+ show_calls = show_files = show_commands = show_efficiency = 1;
+ break;
+ case 'i':
+ use_stdin = 1;
+ break;
+ default :
+ goto usage;
+ }
+ }
+
+ /*
+ * If no report switches given, show summary report.
+ */
+ if (show_calls == 0 && show_files == 0
+ && show_efficiency == 0 && show_commands == 0)
+ show_summary = 1;
+
+ /*
+ * Adjust argv and argc to account for the args processed above.
+ */
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * If further args present, Assume rest are logfiles for us to process,
+ * otherwise, take input from Log and Stat files provided in the
+ * compilation environment of Taylor UUCP. If -i was given, Log already
+ * points to stdin and no file args are accepted.
+ */
+ if(argc == 1) /* No file arguments */
+ {
+ if (use_stdin) /* If -i, read from stdin */
+ {
+ argc = 2;
+ Log = stdin;
+ }
+ else /* Read from current logs */
+ {
+ argc = 3; /* Bash argvec to default log/stat files */
+ argv = &def_logs[0];
+ }
+ }
+ else if (use_stdin) /* File args with -i is an error */
+ {
+ fprintf(stderr, "uurate (error): file args given with '-i'\n");
+ goto usage;
+ }
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * MAIN LOGFILE PROCESSING LOOP
+ */
+ while (argc > 1)
+ {
+
+ if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ return;
+ }
+
+#if _DEBUG_
+ printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1]));
+#endif
+
+ /*
+ * Read each line of the logfile and collect information
+ */
+ while (fgets(logline, sizeof(logline), Log))
+ {
+ /*
+ * The host name of the other end of the connection is
+ * always the second field of the log line, whether we
+ * are reading a Log file or a Stats file. Set 'p' to
+ * point to the second field, null-terminated. Skip
+ * the line if something is funny.
+ */
+ if (NULL == (p = strchr(logline, ' ')))
+ continue;
+ ++p;
+ if (NULL != (s = strchr(p, ' ')))
+ *s = '\0';
+ for (s = p; *s; ++s)
+ if (isupper(*s))
+ *s = tolower(*s);
+ /*
+ * Skip this line if we got -h <host> and
+ * this line does not contain that host name.
+ */
+ if (Hostname[0] != '\0')
+ if (0 != strcmp(p, Hostname))
+ continue;
+ /*
+ * We are within a call block now. If this line is a file
+ * transfer record, determine the direction. If not then
+ * skip the line if it is not interesting.
+ */
+ if ((s = strchr(++s, ')')) == NULL)
+ continue;
+ logmsg = s + 2; /* Message is 2 characters after ')' */
+ if (0 == strncmp(logmsg, "sent", 4))
+ sent = OUT;
+ else
+ if (0 == strncmp(logmsg, "received", 8))
+ sent = IN;
+ else
+ if ((0 != strncmp(logmsg, "Call complete", 13)) &&
+ (0 != strncmp(logmsg, "Calling system", 14)) &&
+ (0 != strncmp(logmsg, "Incoming call", 13)) &&
+ (0 != strncmp(logmsg, "Executing", 9)))
+ continue;
+ /*
+ * Find the Host_entry for this host, or create a new
+ * one and link it on to the list.
+ */
+ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
+ {
+ for (cur = hosts; cur != NULL ; cur = cur->next)
+ if (0 == strcmp(cur->Hostname, p))
+ break;
+ if (cur == NULL)
+ {
+ cur = (struct Host_entry *)calloc(1, sizeof(*hosts));
+ strcpy(cur->Hostname, p);
+ if (hosts == NULL)
+ hosts = cur;
+ else
+ {
+ for (e = hosts; e->next != NULL; e = e->next);
+ e->next = cur;
+ }
+ }
+ }
+ /*
+ * OK, if this is a uuxqt record, find the Execution_Command
+ * structure for the command being executed, or create a new
+ * one. Then count an execution of this command.
+ */
+ if (0 == strncmp(logmsg, "Executing", 9))
+ {
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if ((s = strpbrk(++p, " )")) == NULL)
+ continue;
+ *s = '\0';
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ if (0 == strcmp(cmd->Commandname, p))
+ break;
+ if (cmd == NULL)
+ {
+ cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd));
+ strcpy(cmd->Commandname, p);
+ if (cur->cmds == NULL)
+ cur->cmds = cmd;
+ else
+ {
+ for (ec = cur->cmds; ec->next != NULL; ec = ec->next);
+ ec->next = cmd;
+ }
+ }
+ ++cmd->count;
+ have_commands = 1;
+ continue;
+ }
+ /*
+ * Count start of outgoing call.
+ */
+ if (0 == strncmp(logmsg, "Calling system", 14))
+ {
+ called = OUT;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Count start of incoming call.
+ */
+ if (0 == strncmp(logmsg, "Incoming call", 13))
+ {
+ called = IN;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Handle end of call. Pick up the connect time.
+ */
+ if (0 == strncmp(logmsg, "Call complete", 13))
+ {
+ cur->call[called].succs += 1;
+ if (NULL == (s = strchr(logmsg, '(')))
+ continue;
+ cur->call[called].connect_time += atof(s+1);
+ continue;
+ }
+ /*
+ * If we reached here, this must have been a file transfer
+ * record. Count it in the field corresponding to the
+ * direction of the transfer. Count bytes transferred and
+ * the time to transfer as well.
+ */
+ have_files = 1;
+ cur->call[called].flow[sent].files += 1;
+ if (NULL == (s = strchr(logmsg, ' ')))
+ continue;
+ cur->call[called].flow[sent].bytes += atol(++s);
+ if (NULL == (s = strchr(s, ' ')))
+ continue;
+ if (NULL == (s = strpbrk(s, "0123456789")))
+ continue;
+ cur->call[called].flow[sent].time += atof(s);
+ }
+ argc -= 1;
+ argv += 1;
+ if(Log != stdin)
+ fclose(Log);
+ }
+
+ /*
+ * ***********
+ * * REPORTS *
+ * ***********
+ */
+
+ /*
+ * Truncate the Hostnames to 8 characters at most.
+ */
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ cur->Hostname[8] = '\0';
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * Summary report
+ *
+ * I know, this code could be tightened (rbd)...
+ */
+ if(show_summary)
+ {
+ char t1[32], t2[32], t3[32], t4[32], t5[32];
+ long ib, ob, b, rf, sf;
+ long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0;
+ double it, ot, ir, or;
+ double t_it=0.0, t_ot=0.0;
+ int nhosts = 0;
+
+ printf("\n\
+ Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n");
+ printf("\
+ Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n");
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ ib = (cur->call[IN].flow[IN].bytes +
+ cur->call[OUT].flow[IN].bytes);
+ fmbytes(ib, t1);
+ t_ib += ib;
+
+ ob = (cur->call[IN].flow[OUT].bytes +
+ cur->call[OUT].flow[OUT].bytes);
+ fmbytes(ob, t2);
+ t_ob += ob;
+
+ b = ib + ob;
+ fmbytes(b, t3);
+ t_b += b;
+
+ it = cur->call[IN].flow[IN].time +
+ cur->call[OUT].flow[IN].time;
+ fmtime(it, t4);
+ t_it += it;
+
+ ot = cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(ot, t5);
+ t_ot += ot;
+
+ rf = cur->call[IN].flow[IN].files +
+ cur->call[OUT].flow[IN].files;
+ t_rf += rf;
+
+ sf = cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[OUT].files;
+ t_sf += sf;
+
+ ir = (it == 0.0) ? 0.0 : (ib / it);
+ or = (ot == 0.0) ? 0.0 : (ob / ot);
+
+ printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ cur->Hostname,
+ t1, t2, t3, t4, t5,
+ ir, or, rf, sf);
+ }
+
+ if(nhosts > 1)
+ {
+ fmbytes(t_ib, t1);
+ fmbytes(t_ob, t2);
+ fmbytes(t_b, t3);
+ fmtime(t_it, t4);
+ fmtime(t_ot, t5);
+ ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it);
+ or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot);
+
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ printf("\
+Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ t1, t2, t3, t4, t5,
+ ir, or, t_rf, t_sf);
+ }
+ }
+
+
+ /*
+ * Call statistics report
+ */
+ if(show_calls && have_calls)
+ {
+ char t1[32], t2[32];
+
+ printf("\nCall statistics:\n");
+ printf("\
+ sysname callto failto totime callfm failfm fmtime\n");
+ printf("\
+ -------- ------ ------ -------- ------ ------ --------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ fmtime(cur->call[OUT].connect_time, t1);
+ fmtime(cur->call[IN].connect_time, t2),
+ printf(" %-8s %6d %6d %8s %6d %6d %8s\n",
+ cur->Hostname,
+ cur->call[OUT].calls,
+ cur->call[OUT].calls - cur->call[OUT].succs,
+ t1,
+ cur->call[IN].calls,
+ cur->call[IN].calls - cur->call[IN].succs,
+ t2);
+ }
+ }
+
+ /*
+ * File statistics report
+ */
+ if(show_files && have_files)
+ {
+ char t1[32], t2[32];
+
+ for (sent = IN; sent <= OUT; ++sent)
+ {
+ printf(file_hdr[sent]);
+ printf(" sysname files bytes xfr time byte/s\n");
+ printf(" -------- ------ -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ double rate;
+ double time;
+
+ time = cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time;
+ if (time == 0.0)
+ continue;
+ rate = (cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes) / time;
+ fmbytes((cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes), t1);
+ fmtime((cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time), t2);
+ printf(" %-8s %6d %8s %8s %6.1f\n",
+ cur->Hostname,
+ cur->call[IN].flow[sent].files +
+ cur->call[OUT].flow[sent].files,
+ t1, t2, rate);
+ }
+ }
+ }
+
+ /*
+ * Efficiency report
+ */
+ if (show_efficiency && have_files)
+ {
+ char t1[32], t2[32], t3[32];
+ double total, flow;
+
+ printf("\nEfficiency:\n");
+ printf(" sysname conntime flowtime ovhdtime eff. %%\n");
+ printf(" -------- -------- -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ total = cur->call[IN].connect_time + cur->call[OUT].connect_time;
+ flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time;
+ fmtime(total, t1);
+ fmtime(flow, t2);
+ fmtime((total-flow), t3);
+ printf(" %-8s %8s %8s %8s %5.1f%%\n",
+ cur->Hostname, t1, t2, t3, ((flow / total) * 100.0));
+ }
+ }
+
+ /*
+ * Command execution report
+ */
+ if (show_commands & have_commands)
+ {
+ printf("\nCommand executions:\n");
+ printf(" sysname rmail rnews other\n");
+ printf(" -------- ------ ------ ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ int rmail, rnews, other;
+
+ if (cur->cmds == NULL)
+ continue;
+ rmail = rnews = other = 0;
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ {
+ if (strcmp(cmd->Commandname, "rmail") == 0)
+ rmail += cmd->count;
+ else if (strcmp(cmd->Commandname, "rnews") == 0)
+ rnews += cmd->count;
+ else
+ other += cmd->count;
+ }
+ printf(" %-8s %6d %6d %6d\n", cur->Hostname,
+ rmail, rnews, other);
+ }
+ }
+ return;
+
+ usage:
+ fprintf(stderr,
+ "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n");
+ fprintf(stderr,"where:\t-c\tReport call statistics\n");
+ fprintf(stderr, "\t-f\tReport file transfer statistics\n");
+ fprintf(stderr, "\t-e\tReport efficiency statistics\n");
+ fprintf(stderr, "\t-x\tReport command execution statistics\n");
+ fprintf(stderr, "\t-a\tAll of the above reports\n");
+ fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n");
+ fprintf(stderr, "\t-i\tRead log info from standard input\n");
+ fprintf(stderr,
+ "If no report options given, a compact summary report is given.\n");
+ fprintf(stderr,
+ "If neither -i nor logfiles given, defaults to reading from\n");
+ fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE);
+}
+
+/*
+ * fmtime() - Format time in hours & minutes;
+ */
+static void fmtime(dsec, buf)
+ double dsec;
+ char *buf;
+{
+ long hrs, min, lsec;
+
+ lsec = dsec;
+ hrs = lsec / 3600L;
+ min = (lsec - (hrs * 3600L)) / 60L;
+
+ sprintf(buf, "%02ld:%02ld", hrs, min);
+}
+
+/*
+ * fmbytes - Format size in bytes
+ */
+static void fmbytes(n, buf)
+ unsigned long n;
+ char *buf;
+{
+ char t;
+ double s = n;
+
+ if(s >= 10239897.6) /* More than 9999.9K ? */
+ {
+ s = (double)n / 1048576.0; /* Yes, display in Megabytes */
+ t = 'M';
+ }
+ else
+ {
+ s = (double)n / 1024.0; /* Display in Kilobytes */
+ t = 'K';
+ }
+
+ sprintf(buf, "%.1f%c", s, t);
+}
+
diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man
new file mode 100644
index 00000000000..9f33ef30386
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.man
@@ -0,0 +1,217 @@
+.TH uurate 1
+.SH NAME
+uurate \- Report Taylor UUCP statistics
+.SH SYNOPSIS
+.BR uurate " [ " "\-cfexai" " ] [ " "\-h "
+.I host
+.RI " ] [ " "logfile..." " ] "
+.PP
+or simply,
+.PP
+.B uurate
+.PP
+for a traffic summary report.
+.SH DESCRIPTION
+The
+.I uurate
+command provides tabular summary reports on the operation of the
+Taylor UUCP system. Data is taken from the currently active log
+files, standard input, or from a list of log files given on the
+command line. Output is in the form of tabular reports summarizing
+call, file transfer, and command execution
+.RI "(" "uuxqt" ")"
+activity.
+.PP
+The log files given to
+.I uurate
+must be in the ``Taylor'' format. Also, note that call and file
+transfer activities are logged in separate files, nominally called
+.I Log
+and
+.I Stats,
+respectively. For reports to be meaningful, the
+.I Log
+and
+.I Stats
+files should be given to
+.I uurate
+together, and cover the same time period.
+.PP
+If neither the
+.B \-i
+option nor any
+.I logfile
+options are given,
+.I uurate
+defaults to taking its input from the current Taylor
+.I Log
+and
+.I Stats
+files, as defined at compilation time.
+This is the normal mode of operation.
+.PP
+The reporting options described below can be used to select
+the set of reports desired. If no options are given, the
+.B call
+and
+.B file
+reports are displayed. If there is no relevant data for a particular
+report or host, that report or host will be supressed.
+.SH OPTIONS
+The following options may be given to
+.I uurate:
+.TP 5
+.B \-c
+Report on call statistics. Requires data from a
+.I Log
+file.
+.TP 5
+.B \-f
+Report on file transfer statistics. Requires data from a
+.I Stats
+file.
+.TP 5
+.B \-e
+Report on efficiency (total connect time versus time spent transferring
+files). Requires data from both a
+.I Log
+and a
+.I Stats
+file, and they must span the same time period.
+.TP 5
+.B \-x
+Report on remote execution requests (e.g.,
+.IR rmail ")."
+Requires data from a
+.I Log
+file.
+.TP 5
+.B \-a
+All reports. Identical to
+.B \-cfex.
+.TP 5
+.BI "\-h " "host"
+Restrict report output to
+.I host.
+.SH "DESCRIPTION OF REPORTS"
+There are four reports available: the call, file transfer, efficiency,
+and remote execution reports. Each may be selected by a command line
+option. All reports may be selected via the option
+.B \-a.
+If no report selection options are given,
+.I uurate
+displays a compact traffic summary report (see below).
+.SS "Summary report"
+If no report options are given,
+.I uurate
+displays a traffic summary report. This is particularly useful in daily
+.I cron
+jobs which report on errors and the like. Traffic statistics for each
+active system is reported on a single line. If more than one system was
+active, a 'totals' line is included at the end of the report.
+.SS "Call report"
+The call report gives statistics on inbound and outbound calls for
+each active host system. The fields are described below:
+.br
+.nf
+.in +.5i
+.ta 1.0i
+.BR "sysname " "UUCP node name of neighbor host system"
+.BR "callto " "Outbound calls attempted to that system"
+.BR "failto " "Failed outbound calls to that system"
+.BR "totime " "Connect time (sec.) on outbound calls"
+.BR "callfm " "Inbound calls attempted by that system"
+.BR "failfm " "Failed inbound calls from that system"
+.BR "fmtime " "Connect time (sec.) on inbound calls"
+.in -.5
+.SS "File transfer reports"
+The file transfer reports give statistics on inbound and
+outbound file transfers (regardless of which end initiated the transfer)
+for each active host system. There are two reports, one for files
+sent to the remote system and one for files received from the remote
+system. The fields in each report are described below:
+.br
+.nf
+.in +.5i
+.ta 1.0i
+.BR "sysname " "UUCP node name of neighbor host system"
+.BR "files " "Number of files transferred"
+.BR "bytes " "Total size (bytes) of files transferred"
+.BR "seconds " "Total time (sec.) to transfer files"
+.BR "byte/sec " "Average transfer rate (bytes/sec)"
+.in -.5
+.SS "Efficiency report"
+The efficiency report describes the utilization of the links
+to each active remote system, giving the ratio of total connect time
+to the time spent actually transferring files.
+The fields are described below:
+.br
+.nf
+.in +.5i
+.ta 1.0i
+.BR "sysname " "UUCP node name of neighbor host system"
+.BR "conntime " "Total connect time for that system"
+.BR "flowtime " "Total file transfer time for that system"
+.BR "ovhdtime " "Connect time not used to transfer files"
+.BR "effcy (%) " "Ratio of connect time to transfer time"
+.in -.5
+.SS "Remote execution report"
+The remote execution report describes remotely
+requested command executions from each active host system.
+Executions of
+.I rmail
+and
+.I rnews
+are the most common, and are detailed separately. The fields
+are described below:
+.br
+.nf
+.in +.5i
+.ta 1.0i
+.BR "sysname " "UUCP node name of neighbor host system"
+.BR "rmail " "Number of rmail requests from that system"
+.BR "rnews " "Number of rnews requests from that system"
+.BR "other " "Number of other requests from that system"
+.in -.5i
+.SS FILES
+The file names below may be changed at compilation time or by the
+configuration file, so these are only approximations.
+.br
+.nf
+.in +.5in
+.ta 2.0i
+.IR "/usr/spool/uucp/Log " "Taylor format call/execution log"
+.IR "/usr/spool/uucp/Stats " "Taylor format file transfer log"
+.SS "SEE ALSO"
+.IR uucico "(8)"
+.SS BUGS
+Does not understand older (V2, BNU) logging formats. Anyone care to
+volunteer to add this? I don't use the stuff myself.
+.PP
+The entries that Taylor UUCP makes in the log file for incoming calls
+don't have a host name. This confuses
+.I uurate
+into thinking that the calls came in for system "-". This may require
+a change to Taylor logging.
+.PP
+Should check the configuration file to locate the currently active
+.I Log
+and
+.I Stats
+files when using them for default inputs. Instead, it uses the
+compile-time settings only.
+.PP
+Should report packet protocol error statistics by host and
+protocol type.
+.SS AUTHOR
+Robert B. Denny (denny@alisa.com)
+.br
+Loosely based on the DECUS UUCP program
+.I uurate
+by Mark Pizzolato.
+
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/uureroute b/gnu/libexec/uucp/contrib/uureroute
new file mode 100644
index 00000000000..3eeb654e1e2
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uureroute
@@ -0,0 +1,91 @@
+#!/usr/local/bin/perl
+eval ' exec /usr/local/bin/perl $0 "$@" '
+ if $running_under_some_shell;
+
+# From a script by <Bill.Campbell@celestial.com>
+# Newsgroups: comp.sources.misc
+# Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01
+# Date: 26 Feb 92 02:28:37 GMT
+#
+# This is a Honey DanBer specific routine written in perl to reroute all
+# mail queued up for a specific host. It needs to be run as "root" since
+# uucp will not allow itself to remove others requests.
+#
+# Revision *** 92/21/09: Francois Pinard <pinard@iro.umontreal.ca>
+# 1. adapted for Taylor UUCP
+#
+# Revision 1.3 91/10/08 09:01:21 src
+# 1. Rewritten in perl
+# 2. Add -v option for debugging.
+#
+# Revision 1.2 91/10/07 23:57:42 root
+# 1. Fix mail program path.
+# 2. Truncate directory name to 7 characters
+
+($progname = $0) =~ s!.*/!!; # save this very early
+
+$USAGE = "
+# Reroute uucp mail
+#
+# Usage: $progname [-v] host [host...]
+#
+# Options Argument Description
+# -v Verbose (doesn't execute /bin/sh)
+#
+";
+
+$UUSTAT = "/usr/local/bin/uustat";
+$SHELL = "/bin/sh";
+$SMAIL = "/bin/smail";
+
+sub usage
+{
+ die join ("\n", @_) . "\n$USAGE\n";
+}
+
+do "getopts.pl";
+
+&usage ("Invalid Option") unless do Getopts ("vV");
+
+$verbose = ($opt_v ? '-v' : ());
+$suffix = ($verbose ? '' : $$);
+
+&usage ("No system specified") if $#ARGV < 0;
+
+if (!$verbose)
+{
+ open (SHELL, "| $SHELL");
+ select SHELL;
+}
+
+while ($system = shift)
+{
+ $sysprefix = substr ($system, 0, 7);
+ $directory = "/usr/spool/uucp/$sysprefix";
+ open (UUSTAT, "$UUSTAT -s $system -c rmail |");
+ print "set -ex\n";
+ while (<UUSTAT>)
+ {
+ ($jobid, ) = split;
+ ($cfile) = substr ($jobid, length ($jobid) - 5);
+ $cfilename = "$directory/C./C.$cfile";
+ open (CFILE, $cfilename) || die "Cannot open $cfilename\n";
+ $_ = <CFILE>;
+ close CFILE;
+ if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/)
+ {
+ $datafile = "$directory/D./D.$1";
+ $address = $2;
+ }
+ else
+ {
+ print STDERR;
+ die "Cannot parse previous line from $cfilename\n";
+ }
+ print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n";
+ }
+ close UUSTAT;
+}
+close SHELL unless $verbose;
+
+exit 0;
diff --git a/gnu/libexec/uucp/contrib/uusnap.c b/gnu/libexec/uucp/contrib/uusnap.c
new file mode 100644
index 00000000000..0f878c1e054
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uusnap.c
@@ -0,0 +1,321 @@
+/* uusnap.c
+ (c) 1992 Heiko W.Rupp hwr@pilhuhn.ka.sub.org
+ uusnap is a tool to display the activities of the connected
+ systems.
+
+ Put a file uusnap.systems in NEWCONFIGDIR (see Makefile), in which
+ the systems, you want to monitor are listed, one on a single line.
+ The sequence of the files there determine the sequence of the
+ listing.
+
+ At the moment it only works with taylor config and taylor dirs
+
+ compile it form the Makefile or:
+ cc -c -g -pipe -O -I. -I. -DNEWCONFIGLIB=\"/usr/local/lib/uucp\" uusnap.c
+ cc -o uusnap uusnap.o
+ For this, uusnap.[ch] must be in the same directory as uucp.h and so.
+
+ uusnap must have read access to SPOOLDIR/.Status in order to work.
+*/
+
+#define MAXSYS 30 /* maximum number of systems */
+#define WAIT_NORMAL 10 /* wait period if noone is talking */
+#define WAIT_TALKING 2 /* refresh display every second if */
+ /* someone is talking with us */
+
+#include "uucp.h"
+#if USE_RCS_ID
+char uusnap_rcsid[] = "$Id: uusnap.c,v 1.1 1993/08/04 19:31:43 jtc Exp $";
+#endif
+
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+extern char *ctime(time_t*);
+
+struct sysInfo {
+ char sysname[10]; /* name of the system to watch */
+ char *statfile; /* name of its status file */
+ char *spooldir; /* root of its spooldir */
+ int in; /* number of unprocessed in-files */
+ int out; /* number of files to send them */
+ time_t last; /* last poll time */
+ time_t next; /* time of next poll */
+ time_t lastidir; /* time of last in-spooldir access */
+ time_t lastodir; /* time of last outgoing spd acc */
+ time_t laststat; /* time of last status file access */
+ int status; /* status of the system */
+ int num_retries; /* number of retries */
+};
+
+struct sysInfo Systems[MAXSYS];
+
+
+/* I have extend the system status. If time for the specified system
+ is Never, I say so. To get this to work, one also should extend
+ uucico.c. It is not important to do this. With the normal uucico,
+ one only gets no status.
+*/
+
+const char *azStatus[] = /* Status codes as defined by uucico */
+{ /* listing them here instead of */
+ "Conversation complete", /* including the appropriate file */
+ "Port unavailable", /* reduces the size of the executable */
+ "Dial failed",
+ "Login failed",
+ "Handshake failed",
+ "Call failed",
+ "Talking",
+ "Wrong time to call",
+ "Time to call = Never !"
+};
+
+main()
+{
+ int i;
+ i=get_systems();
+ display_info(i);
+
+ exit(0);
+}
+
+int
+get_systems()
+{
+ char filename[1024];
+ char fn[1024];
+ char line[80];
+ FILE *fp;
+ int i=0;
+ int j;
+ struct stat stbuf;
+ struct sysInfo sys;
+
+ strcpy(filename,NEWCONFIGLIB);
+ strcat(filename,"/uusnap.systems");
+ if ((fp=fopen(filename,"r"))!=NULL) {
+ while (fgets(line,80,fp)!=NULL) {
+ *(rindex(line,'\n'))='\0';
+ strcpy(sys.sysname,line); /* get the name of the system */
+ strcpy(fn,SPOOLDIR); /* get the name of the statusfile */
+ strcat(fn,"/.Status/");
+ strcat(fn,line);
+ sys.statfile=malloc(strlen(fn)+1);
+ strcpy(sys.statfile,fn);
+ strcpy(fn,SPOOLDIR); /* get the name of the spooldir */
+ strcat(fn,"/");
+ strcat(fn,line);
+ sys.spooldir=malloc(strlen(fn)+1);
+ strcpy(sys.spooldir,fn);
+ sys.laststat=0;
+ sys.lastidir=sys.lastodir=0;
+ Systems[i]=sys; /* get_stat_for_system needs it */
+ get_stat_for_system(i); /* now get the system status */
+ get_inq_num(i,TRUE); /* number of unprocessed files */
+ get_outq_num(i,TRUE); /* number of files to send */
+ i++;
+ }
+ fclose(fp);
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ return i;
+}
+
+
+
+display_info(int numSys)
+{
+ char *filename;
+ int sysnum;
+ FILE *fp;
+ char contentline[80];
+ char isTalking=FALSE;
+ struct stat stbuf;
+ struct sysInfo sys;
+ time_t time;
+
+ filename = (char*)malloc(1024);
+ if (filename == NULL) {
+ fprintf(stderr, "Can't malloc 1024 bytes");
+ exit(1);
+ }
+
+ while(TRUE) {
+ display_headline();
+ for (sysnum=0;sysnum<numSys;sysnum++) {
+ sys = Systems[sysnum];
+ stat(sys.statfile,&stbuf);
+ if ((time=stbuf.st_atime) > sys.laststat) {
+ get_stat_for_system(sysnum);
+ }
+ if(display_status_line(sysnum)==1)
+ isTalking=TRUE;
+ }
+ if (isTalking) {
+ sleep(WAIT_TALKING);
+ isTalking = FALSE;
+ }
+ else
+ sleep(WAIT_NORMAL); /* wait a bit */
+ }
+ return 0;
+}
+
+int
+display_status_line(int sn)
+{
+ char *time_s;
+
+ int sys_stat,num_retries,wait;
+ int i;
+ time_t last_time;
+ time_t next_time;
+
+ struct sysInfo sys;
+
+ sys = Systems[sn];
+
+ printf("%10s ",sys.sysname);
+ get_inq_num(sn);
+ if (sys.in==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.in);
+ get_outq_num(sn);
+ if (sys.out==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.out);
+ time_s = ctime(&sys.last);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ printf("%8s ",time_s); /* time of last poll */
+ time_s = ctime(&sys.next);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ if (sys.last == sys.next)
+ printf(" ");
+ else
+ printf("%8s ",time_s); /* time of next poll */
+ if (sys.num_retries==0)
+ printf(" ");
+ else
+ printf("%2d ",sys.num_retries);
+ if (sys_stat==6) /* system is talking */
+ printf("\E[7m"); /* reverse video on */
+ printf("%s",azStatus[sys.status]);
+ if (sys.status==6) {
+ printf("\E[m\n"); /* reverse video off */
+ return 1;
+ }
+ else {
+ printf("\n");
+ return 0;
+ }
+}
+
+
+display_headline()
+{
+ printf("\E[;H\E[2J"); /* clear screen */
+ printf("\E[7muusnap (press CTRL-C to escape)\E[m \n\n");
+ printf(" System #in #out last next #ret Status\n");
+ return 0;
+}
+
+get_inq_num(int num,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[num].spooldir);
+ strcat(filename,"/X./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[num].lastidir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[num].lastidir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[num].in=i;
+ }
+ return 0;
+}
+
+get_outq_num(int sys,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[sys].spooldir);
+ strcat(filename,"/C./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[sys].lastodir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[sys].lastodir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[sys].out=i;
+ }
+ return 0;
+}
+
+get_stat_for_system(int i)
+{
+ char fn[80];
+ struct sysInfo sys;
+ struct stat stbuf;
+ FILE *fp;
+ time_t wait;
+
+ sys = Systems[i];
+ stat(sys.statfile,&stbuf);
+ if (stbuf.st_atime > sys.laststat) {
+ if ((fp=fopen(sys.statfile,"r"))!=NULL) {
+ fgets(fn,80,fp);
+ fclose(fp);
+ sscanf(fn,"%d %d %ld %d",
+ &sys.status,
+ &sys.num_retries,
+ &sys.last,
+ &wait);
+ sys.next=sys.last+wait;
+ }
+ else {
+ sys.status=0;
+ sys.num_retries=0;
+ sys.last=0;
+ sys.next=0;
+ }
+ stat(sys.statfile,&stbuf);
+ sys.laststat=stbuf.st_atime;
+ }
+ Systems[i] = sys;
+ return 0;
+}
diff --git a/gnu/libexec/uucp/contrib/uutraf b/gnu/libexec/uucp/contrib/uutraf
new file mode 100644
index 00000000000..8b56d0f6b4f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uutraf
@@ -0,0 +1,203 @@
+#!/usr/local/bin/perl
+# uutraf.pl -- UUCP Traffic Analyzer
+# SCCS Status : @(#)@ uutraf 1.7
+# Author : Johan Vromans
+# Created On : ***
+# Last Modified By: Johan Vromans
+# Last Modified On: Wed Feb 26 08:52:56 1992
+# Update Count : 4
+# Status : OK
+# Requires: : Perl V4 or later
+
+# Reads UUCP syslog, and generates a report from it.
+#
+# Created by Johan Vromans <jv@mh.nl>
+# Loosely based on an idea by Greg Hackney (hack@texbell.swbt.com)
+
+# Usage: uutraf [-taylor|-hdb|-bnu|-bsd] [syslog]
+
+# Logfile formats:
+#
+# BSD:
+#
+# jv mhres (2/23-5:18) (698818735) received 135 b 2 secs
+# root mhres (2/23-5:19) (698818742) sent 2365 b 3 secs, Pk: 38, Rxmt: 0
+#
+# HDB:
+#
+# uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, \
+# 474 bytes/sec
+#
+# Taylor:
+#
+# jv mhres (1992-02-24 20:49:04.06) sent 16234 bytes in 148.780 seconds \
+# (109 bytes/sec)
+# jv mhres (1992-02-24 21:04:05.76) received 449 bytes in 6.550 seconds \
+# (68 bytes/sec)
+
+$uucp_type = "gnu";
+
+%hosts = (); # hosts seen
+%bytes_in = (); # of bytes received from host
+%bytes_out = (); # of bytes sent to host
+%secs_in = (); # of seconds connect for recving
+%secs_out = (); # of seconds connect for sending
+%files_in = (); # of input requests
+%files_out = (); # of output requests
+
+# read info, break the lines and tally
+
+if ( $ARGV[0] =~ /^-/ ) {
+ ($uucp_type = substr (shift (@ARGV), 1)) =~ tr/A-Z/a-z/;
+}
+
+if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) {
+ @ARGV = ("/usr/spool/uucp/Stats") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " .
+ "(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds";
+ $uucp_type = 0;
+ $recv = "received";
+}
+elsif ( $uucp_type eq "hdb" || $uucp_type eq "bnu" ) {
+ @ARGV = ("/usr/spool/uucp/.Admin/xferstats") unless $#ARGV >= 0;
+ $pat = "^([^!]+)![^(]+\\(([-0-9:\\/]+)\\).+([<>])-? " .
+ "(\\d+) \\/ (\\d+)\\.(\\d+) secs";
+ $uucp_type = 1;
+ $recv = "<";
+}
+elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) {
+ @ARGV = ("/usr/spool/uucp/SYSLOG") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/]+)\\) \\([^)]+\\) " .
+ "(sent|received) (\\d+) b (\\d+) secs";
+ $uucp_type = 2;
+ $recv = "received";
+}
+else {
+ die ("Unknown UUCP type: $uucp_type\n");
+}
+
+$garbage = 0;
+
+while ( <> ) {
+ unless ( /$pat/o ) {
+ print STDERR "Possible garbage: $_";
+ if ( $garbage++ > 10 ) {
+ die ("Too much garbage; wrong UUCP type?\n");
+ }
+ next;
+ }
+
+ # gather timestamps
+ $last_date = $2;
+ $first_date = $last_date unless defined $first_date;
+
+ # initialize new hosts
+ unless ( defined $hosts{$1} ) {
+ $hosts{$1} = $files_in{$1} = $files_out{$1} =
+ $bytes_in{$1} = $bytes_out{$1} =
+ $secs_in{$1} = $secs_out{$1} = 0;
+ }
+
+ # Taylor and HDB have milliseconds, BSD has not.
+ $secs = ($uucp_type == 2) ? ($5 + ($5 == 0 ? 0.5 : 0)) : ($5 + $6/1000);
+
+ # tally
+ if ( $3 eq $recv ) { # recv
+ $bytes_in{$1} += $4;
+ $files_in{$1}++;
+ $secs_in{$1} += $secs;
+ }
+ else { # xmit
+ $bytes_out{$1} += $4;
+ $files_out{$1}++;
+ $secs_out{$1} += $secs;
+ }
+ $garbage = 0;
+}
+
+@hosts = keys (%hosts);
+die ("No info found, stopped\n") if $#hosts < 0;
+
+################ report section ################
+
+$thishost = &gethostname();
+$thishost = (defined $thishost) ? "on node $thishost" : "report";
+
+if ( $uucp_type eq 0 ) { # Taylor UUCP
+ substr ($first_date, 16) = "";
+ substr ($last_date, 16) = "";
+}
+
+format std_head =
+@|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+"UUCP traffic $thishost from $first_date to $last_date"
+
+Remote -----------K-Bytes----------- ----Hours---- --Avg CPS-- --Files--
+ Host Recv Sent Total Recv Sent Recv Sent Recv Sent
+.
+format std_out =
+@<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>> @>>>>> @>>>> @>>>> @>>> @>>>
+$Zhost, $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs, $Zi_acps, $Zo_acps, $Zi_count, $Zo_count
+.
+
+$^ = "std_head";
+$~ = "std_out";
+
+&print_dashes ();
+
+reset "T"; # reset totals
+
+foreach $host (@hosts) {
+ &print_line ($host, $bytes_in{$host}, $bytes_out{$host},
+ $secs_in{$host}, $secs_out{$host},
+ $files_in{$host}, $files_out{$host});
+
+}
+
+&print_dashes ();
+&print_line ("Total", $Ti_bytes, $To_bytes,
+ $Ti_secs, $To_secs, $Ti_count, $To_count);
+
+################ that's it ################
+
+sub print_line {
+ reset "Z"; # reset print fields
+ local ($Zhost,
+ $Zi_bytes, $Zo_bytes,
+ $Zi_secs, $Zo_secs,
+ $Zi_count, $Zo_count) = @_;
+ $Ti_bytes += $Zi_bytes;
+ $To_bytes += $Zo_bytes;
+ $Zt_bytes = $Zi_bytes + $Zo_bytes;
+ $Tt_bytes += $Zt_bytes;
+ $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) : "0";
+ $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) : "0";
+ $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000);
+ $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000);
+ $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000);
+ $Zi_hrs = sprintf ("%.1f", $Zi_secs/3600);
+ $Zo_hrs = sprintf ("%.1f", $Zo_secs/3600);
+ $Ti_secs += $Zi_secs;
+ $To_secs += $Zo_secs;
+ $Ti_count += $Zi_count;
+ $To_count += $Zo_count;
+ write;
+}
+
+sub print_dashes {
+ $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes =
+ $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
+ "------------";
+ write;
+ # easy, isn't it?
+}
+
+################ missing ################
+
+sub gethostname {
+ $ENV{"SHELL"} = "/bin/sh";
+ $try = `uuname -l 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ return undef;
+}
diff --git a/gnu/libexec/uucp/contrib/uutry b/gnu/libexec/uucp/contrib/uutry
new file mode 100644
index 00000000000..bc0cf299e99
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uutry
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# This script was hacked together by Marc Evans (marc@Synergytics.Com)
+# I claim no copyright to it and don't really care what people do
+# with it, hence, it is public domain. I take no responsibility for
+# for happens if you use this script, providing no warentee. This
+# section of the comments may be removed if you so desire.
+#
+# Usage:
+# uutry [-x#] systemname
+# where '-x#' has the value [0-9], higher values providing more detail
+
+#
+# The following variables should be gropped from the configuration
+# files rather then being hard coded here.
+#
+Spool=/usr/spool/uucp
+Lib=/usr/lib/uucp
+Status=$Spool/.Status
+Debug=$Spool/Debug
+Uucico=$lib/uucico
+#
+# Default option values
+#
+x="-x5"
+s=""
+
+for i in $* ; do
+ case $i in
+ -x*) x="$i" ;;
+ *) s="$i" ;;
+ esac
+done
+
+if [ $s != "" ]; then
+ rm -f $Status/$s
+ $Uucico -r1 $x -s$s &
+ >$Debug
+ tail -f $Debug
+else
+ echo "Usage: uutry systemname"
+ exit 1
+fi
diff --git a/gnu/libexec/uucp/contrib/xc-conf.h-dist b/gnu/libexec/uucp/contrib/xc-conf.h-dist
new file mode 100644
index 00000000000..8810dd78d92
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xc-conf.h-dist
@@ -0,0 +1,38 @@
+/*
+ * *************
+ * * XC-CONF.H *
+ * *************
+ *
+ * Configuration file for xchat 1.1. Edit this file prior to make-ing
+ * xchat.
+ *
+ * History:
+ * Bob Denny - Tue Sep 1 11:42:54 1992
+ */
+
+/*
+ * Edit this to reflect the relative location of xchat sources to
+ * the main Taylor UUCP source directory. As distributed, xchat
+ * is in the ./contrib sub-directory under the main Taylor UUCP
+ * directory. Therefore, Taylor's conf.h is in our parent directory.
+ */
+#include "../conf.h"
+
+/*
+ * The following definition establishes the default path to the
+ * scripts used by xchat. You may lleave this blank (""), but
+ * the command line given to xchat (e.g., in the 'sys' file entry)
+ * must specify a full (absolute) path name to the script to be
+ * executed. Normally, this is the same place you put your config
+ * and system files for UUCP.
+ */
+#define SCRIPT_DIR "/usr/local/conf/uucp/" /* MUST HAVE TRAILING "/" */
+
+/*
+ * The following definition establishes the default path to the
+ * log files that are produced by the 'dbgfile' statement. Normally
+ * this is the same location you configured Taylor UUCP to put its
+ * log files.
+ */
+#define LOG_DIR "/usr/spool/uucp/" /* MUST HAVE TRAILING "/" */
+
diff --git a/gnu/libexec/uucp/contrib/xchat.c b/gnu/libexec/uucp/contrib/xchat.c
new file mode 100644
index 00000000000..cfb4d359662
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xchat.c
@@ -0,0 +1,1444 @@
+/*
+ * ***********
+ * * XCHAT.C *
+ * ***********
+ *
+ * Extended chat processor for Taylor UUCP. See accompanying documentation.
+ *
+ * Written by:
+ * Bob Denny (denny@alisa.com)
+ * Based on code in DECUS UUCP (for VAX/VMS)
+ *
+ * History:
+ * Version 1.0 shipped with Taylor 1.03. No configuration info inside.
+ *
+ * Bob Denny - Sun Aug 30 18:41:30 1992
+ * V1.1 - long overdue changes for other systems. Rip out interval
+ * timer code, use timer code from Taylor UUCP, use select()
+ * for timed reads. Use Taylor UUCP "conf.h" file to set
+ * configuration for this program. Add defaulting of script
+ * and log file paths.
+ *
+ * Bugs:
+ * Does not support BSD terminal I/O. Anyone care to add it?
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/termio.h>
+
+#include "xc-conf.h"
+
+/*
+ * Pick a timing routine to use, as done in Taylor UUCP.
+ */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#define USE_SELECT_TIMER 0
+#else
+#define USE_SELECT_TIMER HAVE_SELECT
+#if USE_SELECT_TIMER
+#include <sys/time.h>
+#endif
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+static int ttblind();
+static int ttcd();
+
+/* script entry -- "compiled" form of dial, hangup, or login script */
+
+struct script {
+ struct script *next; /* pointer to next entry, or null */
+ int opcode; /* numeric opcode */
+ char *strprm; /* pointer to string param */
+ long intprm; /* integer parameter */
+ char *newstate; /* new state name */
+};
+
+/* opcode definition array element -- one for each possible opcode */
+
+struct script_opdef {
+ char *opname;
+ int opcode; /* numeric opcode -- same as array index */
+ int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */
+ int newstate; /* one of SC_NONE, SC_NWST */
+};
+
+ /* values for opcode */
+
+#define SC_LABEL 0 /* "label" (state name) */
+#define SC_CDLY 1 /* set char output delay in msec */
+#define SC_PCHR 2 /* pause char for dial string (from P in input) */
+#define SC_PTIM 3 /* seconds to allow for pause char */
+#define SC_WCHR 4 /* wait char for dial string (from W in input) */
+#define SC_WTIM 5 /* seconds to allow for wait char */
+#define SC_ZERO 6 /* zero counter */
+#define SC_INCR 7 /* increment counter */
+#define SC_IFGT 8 /* change state if counter > int param */
+#define SC_WAIT 9 /* wait for int param seconds */
+#define SC_GOTO 10 /* unconditional change to new state */
+#define SC_SEND 11 /* send strparam (after sprintf substitutions) */
+#define SC_BRK 12 /* send a break */
+#define SC_HANG 13 /* drop DTR */
+#define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */
+#define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */
+ /* default = 100 (one tenth second) */
+#define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */
+ /* default = 45 seconds */
+#define SC_EXIT 17 /* script done, success */
+#define SC_FAIL 18 /* script done, failure */
+#define SC_LOG 19 /* write strparam to uucp.log */
+#define SC_LOGE 20 /* write strparam to uucp.log w/error ind */
+#define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */
+#define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */
+#define SC_DBST 23 /* 'or' intparam into debug mask */
+#define SC_DBCL 24 /* 'bicl' intparam into debug mask */
+#define SC_TIMO 25 /* newstate if no match in intparam secs */
+ /* (uses calculated dial time if intparam is 0) */
+#define SC_XPCT 26 /* wait for strparam, goto _newstate if found */
+#define SC_CARR 27 /* goto _newstate if carrier detected */
+#define SC_FLSH 28 /* flush typeahead buffer */
+#define SC_IFBL 29 /* change state if controller is blind w/o CD */
+#define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */
+#define SC_SNDP 31 /* send parameter n */
+#define SC_IF1P 32 /* if parameter n present */
+#define SC_IF0P 33 /* if parameter n absent */
+#define SC_DBOF 34 /* open debugging file */
+#define SC_TELN 35 /* Set telno from parameter n */
+#define SC_7BIT 36 /* Set port to 7-bit stripping */
+#define SC_8BIT 37 /* Set port for 8-bit characters */
+#define SC_PNON 38 /* Set port for 8-bit, no parity */
+#define SC_PEVN 39 /* Set port for 7-bit, even parity */
+#define SC_PODD 40 /* Set port for 7-bit, odd parity */
+#define SC_HUPS 41 /* Change state on HUP signal */
+#define SC_END 42 /* end of array */
+
+ /* values for prmtype, prm2type */
+
+#define SC_NONE 0 /* no parameter */
+#define SC_STR 1 /* simple string */
+#define SC_INT 2 /* integer */
+#define SC_NWST 3 /* new state name */
+#define SC_XSTR 4 /* translated string */
+
+/* opcode definition table for dial/login/hangup scripts */
+
+static struct script_opdef sc_opdef[] =
+ {
+ {"label", SC_LABEL, SC_NONE, SC_NONE},
+ {"chrdly", SC_CDLY, SC_INT, SC_NONE},
+ {"pchar", SC_PCHR, SC_STR, SC_NONE},
+ {"ptime", SC_PTIM, SC_INT, SC_NONE},
+ {"wchar", SC_WCHR, SC_STR, SC_NONE},
+ {"wtime", SC_WTIM, SC_INT, SC_NONE},
+ {"zero", SC_ZERO, SC_NONE, SC_NONE},
+ {"count", SC_INCR, SC_NONE, SC_NONE},
+ {"ifgtr", SC_IFGT, SC_INT, SC_NWST},
+ {"sleep", SC_WAIT, SC_INT, SC_NONE},
+ {"goto", SC_GOTO, SC_NONE, SC_NWST},
+ {"send", SC_SEND, SC_XSTR, SC_NONE},
+ {"break", SC_BRK, SC_NONE, SC_NONE},
+ {"hangup", SC_HANG, SC_NONE, SC_NONE},
+ {"7bit", SC_7BIT, SC_NONE, SC_NONE},
+ {"8bit", SC_8BIT, SC_NONE, SC_NONE},
+ {"nopar", SC_PNON, SC_NONE, SC_NONE},
+ {"evenpar", SC_PEVN, SC_NONE, SC_NONE},
+ {"oddpar", SC_PODD, SC_NONE, SC_NONE},
+ {"telno", SC_TELN, SC_INT, SC_NONE},
+ {"dial", SC_DIAL, SC_NONE, SC_NONE},
+ {"dgttime", SC_DTIM, SC_INT, SC_NONE},
+ {"ctime", SC_CTIM, SC_INT, SC_NONE},
+ {"success", SC_EXIT, SC_NONE, SC_NONE},
+ {"failed", SC_FAIL, SC_NONE, SC_NONE},
+ {"log", SC_LOG, SC_XSTR, SC_NONE},
+ {"logerr", SC_LOGE, SC_XSTR, SC_NONE},
+ {"debug", SC_DBG, SC_XSTR, SC_NONE},
+ {"debuge", SC_DBGE, SC_XSTR, SC_NONE},
+ {"dbgset", SC_DBST, SC_INT, SC_NONE},
+ {"dbgclr", SC_DBCL, SC_INT, SC_NONE},
+ {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE},
+ {"timeout", SC_TIMO, SC_INT, SC_NWST},
+ {"expect", SC_XPCT, SC_XSTR, SC_NWST},
+ {"ifcarr", SC_CARR, SC_NONE, SC_NWST},
+ {"ifhang", SC_HUPS, SC_NONE, SC_NWST},
+ {"flush", SC_FLSH, SC_NONE, SC_NONE},
+ {"ifblind", SC_IFBL, SC_NONE, SC_NWST},
+ {"ifblgtr", SC_IFBG, SC_INT, SC_NWST},
+ {"sendstr", SC_SNDP, SC_INT, SC_NONE},
+ {"ifstr", SC_IF1P, SC_INT, SC_NWST},
+ {"ifnstr", SC_IF0P, SC_INT, SC_NWST},
+ {"table end", SC_END, SC_NONE, SC_NONE}
+ };
+
+#define SUCCESS 0
+#define FAIL 1
+#define ERROR -1
+#define MAX_SCLINE 255 /* max length of a line in a script file */
+#define MAX_EXPCT 127 /* max length of an expect string */
+#define CTL_DELIM " \t\n\r" /* Delimiters for tokens */
+#define SAME 0 /* if (strcmp(a,b) == SAME) ... */
+#define SLOP 10 /* Slop space on arrays */
+#define MAX_STRING 200 /* Max length string to send/expect */
+
+#define DEBUG_LEVEL(level) \
+ (Debug & (1 << level))
+
+#define DB_LOG 0 /* error messages and a copy of the LOGFILE output */
+#define DB_LGIE 1 /* dial,login,init trace -- errors only */
+#define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */
+#define DB_LGII 3 /* script processing internals */
+
+#define TRUE 1
+#define FALSE 0
+
+#define NONE 0
+#define EVEN 1
+#define ODD 2
+
+#define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1)
+
+static char **paramv; /* Parameter vector */
+static int paramc; /* Parameter count */
+static char telno[64]; /* Telephone number w/meta-chars */
+static int Debug;
+static int fShangup = FALSE; /* TRUE if HUP signal received */
+static FILE *dbf = NULL;
+static struct termio old, new;
+
+extern int usignal();
+extern int uhup();
+
+static struct siglist
+{
+ int signal;
+ int (*o_catcher) ();
+ int (*n_catcher) ();
+} sigtbl[] = {
+ { SIGHUP, NULL, uhup },
+ { SIGINT, NULL, usignal },
+ { SIGIOT, NULL, usignal },
+ { SIGQUIT, NULL, usignal },
+ { SIGTERM, NULL, usignal },
+ { SIGALRM, NULL, usignal },
+ { 0, NULL, NULL } /* Table end */
+ };
+
+extern struct script *read_script();
+extern void msleep();
+extern char xgetc();
+extern void charlog();
+extern void setup_tty();
+extern void restore_tty();
+extern void ttoslow();
+extern void ttflui();
+extern void tthang();
+extern void ttbreak();
+extern void tt7bit();
+extern void ttpar();
+extern void DEBUG();
+
+extern void *malloc();
+
+
+/*
+ * **********************************
+ * * BEGIN EXECUTION - MAIN PROGRAM *
+ * **********************************
+ *
+ * This program is called by Taylor UUCP with a list of
+ * arguments in argc/argv, and stdin/stdout mapped to the
+ * tty device, and stderr mapped to the Taylor logfile, where
+ * anything written to stdout will be logged as an error.
+ *
+ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, stat;
+ FILE *sf;
+ char sfname[256];
+ struct script *script;
+ struct siglist *sigs;
+
+ /*
+ * The following is needed because my cpp does not have the
+ * #error directive...
+ */
+#if ! HAVE_SELECT
+ no_select_sorry(); /* Sad way to fail make */
+#endif
+
+ paramv = &argv[2]; /* Parameters start at 2nd arg */
+ paramc = argc - 2; /* Number of live parameters */
+
+ telno[0] = '\0';
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "%s: no script file supplied\n", argv[0]);
+ exit(FAIL);
+ }
+
+ /*
+ * If the script file argument begins with '/', then we assume
+ * it is an absolute pathname, otherwise, we prepend the
+ * SCRIPT_DIR path.
+ */
+ *sfname = '\0'; /* Empty name string */
+ if(argv[1][0] != '/') /* If relative path */
+ strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */
+ strcat(sfname, argv[1]); /* Add the script file name */
+
+ /*
+ * Now open the script file.
+ */
+ if ((sf = fopen(sfname, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname);
+ perror(" ");
+ exit(FAIL);
+ }
+
+ /*
+ * COMPILE SCRIPT
+ */
+ if ((script = read_script(sf)) == NULL)
+ {
+ fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]);
+ exit(FAIL);
+ }
+
+ /*
+ * Set up a signal catcher so the line can be returned to
+ * it's current state if something nasty happens.
+ */
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ {
+ sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher);
+ sigs += 1;
+ }
+
+ /*
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+ setup_tty();
+
+ /*
+ * EXECUTE SCRIPT
+ */
+ if ((stat = do_script(script)) != SUCCESS)
+ fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]);
+
+ /*
+ * Clean up and exit.
+ */
+ restore_tty();
+#ifdef FIXSIGS
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ if(sigs->o_catcher != -1)
+ signal(sigs->signal, sigs->o_catcher);
+#endif
+ exit(stat);
+}
+
+/*
+ * deal_script - deallocate a script and all strings it points to
+ */
+int deal_script(loc)
+struct script *loc;
+{
+ /*
+ * If pointer is null, just exit
+ */
+ if (loc == (struct script *)NULL)
+ return SUCCESS;
+
+ /*
+ * Deallocate the rest of the script
+ */
+ deal_script(loc->next);
+
+ /*
+ * Deallocate the string parameter, if any
+ */
+ if (loc->strprm != (char *)NULL)
+ free(loc->strprm);
+
+ /*
+ * Deallocate the new state name parameter, if any
+ */
+ if (loc->newstate != (char *)NULL)
+ free(loc->newstate);
+
+ /*
+ * Deallocate this entry
+ */
+ free(loc);
+
+ return SUCCESS;
+}
+
+
+/*
+ * read_script
+ *
+ * Read & compile a script, return pointer to first entry, or null if bad
+ */
+struct script *read_script(fd)
+ FILE *fd;
+{
+ struct script *this = NULL;
+ struct script *prev = NULL;
+ struct script *first = NULL;
+ long len, i;
+ char inpline[MAX_SCLINE];
+ char inpcopy[MAX_SCLINE];
+ char *c, *cln, *opc, *cp;
+
+ /*
+ * MAIN COMPILATION LOOP
+ */
+ while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL)
+ {
+ /*
+ * Skip comments and blank lines
+ */
+ if (*c == '#' || *c == '\n')
+ continue;
+
+ /*
+ * Get rid of the trailing newline, and copy the string
+ */
+ inpline[strlen(inpline)-1] = '\0';
+ strcpy(inpcopy, inpline);
+
+ /*
+ * Look for text starting in the first col (a label)
+ */
+ if ((!isspace(inpline[0])) &&
+ (cln = strchr (inpline, ':')) != (char *)NULL) {
+ this = (struct script *)malloc (sizeof (struct script));
+ if (prev != (struct script *)NULL)
+ prev->next = this;
+ prev = this;
+ if (first == (struct script *)NULL)
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ len = cln - c;
+ this->strprm = (char *)malloc(len+1);
+ strncpy(this->strprm, c, len);
+ (this->strprm)[len] = '\0';
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ c = cln + 1;
+ }
+
+ /*
+ * Now handle the opcode. Fold it to lower case.
+ */
+ opc = strtok(c, CTL_DELIM);
+ if (opc == (char *)NULL) /* If no opcode... */
+ continue; /* ...read the next line */
+ cp = opc;
+ while(*cp)
+ tolower(*cp++);
+
+ /*
+ * If we have an opcode but we haven't seen anything
+ * else (like a label) yet, i.e., this is the first
+ * entry, and there was no label. We need to
+ * cobble up a label so that read_script is happy
+ */
+ if (first == (struct script *)NULL)
+ {
+ this = (struct script *)malloc (sizeof (struct script));
+ prev = this;
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ this->strprm = (char *)malloc(2);
+ strcpy(this->strprm, ":");
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ }
+
+ /*
+ * Find opcode - ndex through the opcode definition table
+ */
+ for (i=1; sc_opdef[i].opcode != SC_END; i++)
+ if (strcmp(opc, sc_opdef[i].opname) == SAME)
+ break;
+ if ((sc_opdef[i].opcode) == SC_END)
+ {
+ logit ("Bad opcode in script", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+
+ /*
+ * Found opcode. Allocate a new command node and initialize
+ */
+ this = (struct script *)malloc(sizeof (struct script));
+ prev->next = this;
+ prev = this;
+ this->next = (struct script *)NULL;
+ this->opcode = sc_opdef[i].opcode;
+ this->strprm = (char *)NULL;
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+
+ /*
+ * Pick up new state parameter, if any
+ */
+ if (sc_opdef[i].newstate == SC_NWST)
+ {
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing new state", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ else
+ {
+ this->newstate = (char *)malloc(strlen(c)+1);
+ strcpy(this->newstate, c);
+ }
+ }
+
+ /*
+ * Pick up the string or integer parameter. Handle missing
+ * parameter gracefully.
+ */
+ switch (sc_opdef[i].prmtype)
+ {
+ /*
+ * INT parameter - convert and store in node
+ */
+ case SC_INT:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * If this is the parameter to DBST or DBCL, force
+ * base-10 conversion, else convert per parameter.
+ */
+ if (sc_opdef[i].opcode == SC_DBST ||
+ sc_opdef[i].opcode == SC_DBCL)
+ this->intprm = strtol(c, (char **)NULL, 0);
+ else
+ this->intprm = strtol(c, (char **)NULL, 10);
+ break;
+
+ /*
+ * STR/XSTR strings.
+ */
+ case SC_STR:
+ case SC_XSTR:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * For XSTR opcode, use c to find out where
+ * the string param begins in the copy of the
+ * input line, and pick up all that's left of
+ * the line (to allow imbedded blanks, etc.).
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ c = &inpcopy[0] + (c - &inpline[0]);
+
+ /*
+ * Allocate a buffer for the string parameter
+ */
+ this->strprm = (char *)malloc(strlen(c)+1);
+
+ /*
+ * For XSTR, Translate the string and store its
+ * length. Note that, after escape sequences are
+ * compressed, the resulting string may well be a
+ * few bytes shorter than the input string (whose
+ * length was the basis for the malloc above),
+ * but it will never be longer.
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ {
+ this->intprm = xlat_str(this->strprm, c);
+ this->strprm[this->intprm] = '\0';
+ }
+ else
+ strcpy(this->strprm, c);
+ break;
+
+ }
+ }
+
+ /*
+ * EOF
+ */
+ return first;
+}
+
+
+/*
+ * xlat_str
+ *
+ * Translate embedded escape characters in a "send" or "expect" string.
+ *
+ * Called by read_script(), above.
+ *
+ * Returns the actual length of the resulting string. Note that imbedded
+ * nulls (specified by \000 in the input) ARE allowed in the result.
+ */
+xlat_str(out, in)
+ char *out, *in;
+{
+ register int i = 0, j = 0;
+ int byte, k;
+
+ while (in[i])
+ {
+ if (in[i] != '\\')
+ {
+ out[j++] = in[i++];
+ }
+ else
+ {
+ switch (in[++i])
+ {
+ case 'd': /* EOT */
+ out[j++] = 0x04;
+ break;
+ case 'N': /* null */
+ out[j++] = 0x00;
+ break;
+ case 'n': /* line feed */
+ out[j++] = 0x0a;
+ break;
+ case 'r': /* carriage return */
+ out[j++] = 0x0d;
+ break;
+ case 's': /* space */
+ out[j++] = ' ';
+ break;
+ case 't': /* tab */
+ out[j++] = '\t';
+ break;
+ case '-': /* hyphen */
+ out[j++] = '-';
+ break;
+ case '\\': /* back slash */
+ out[j++] = '\\';
+ break;
+ case '0': /* '\nnn' format */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ byte = in[i] - '0';
+ k = 0;
+
+ while (3 > ++k)
+ if ((in[i+1] < '0') || (in[i+1] > '7'))
+ break;
+ else
+ {
+ byte = (byte<<3) + in[i+1] - '0';
+ ++i;
+ }
+ out[j++] = byte;
+ break;
+ default: /* don't know so skip it */
+ break;
+ }
+ ++i;
+ }
+ }
+ return j;
+}
+
+
+/* find a state within a script */
+
+struct script *
+ find_state(begin, newstate)
+struct script *begin;
+char *newstate;
+{
+ struct script *here;
+
+ for (here=begin; here != (struct script *)NULL; here=here->next) {
+ if (here->opcode == SC_LABEL &&
+ strcmp(here->strprm, newstate) == SAME)
+ return here;
+ }
+ return (struct script *)NULL;
+}
+
+
+/*
+ * do_script() - execute a script
+ */
+int do_script(begin)
+ struct script *begin;
+{
+ struct script *curstate, *newstate, *curscr;
+ int dbgsave;
+ char tempstr[MAX_SCLINE];
+ char dfname[256];
+ char *c, chr;
+ int prmlen;
+ int dbfd;
+
+ time_t sc_carrtime = 45000; /* time to wf carr after dial */
+ time_t sc_chrdly = 100; /* delay time for ttoslow */
+ time_t sc_ptime = 2000; /* time to allow for pause char */
+ time_t sc_wtime = 10000; /* time to allow for wait char */
+ time_t sc_dtime = 100; /* time to allow for each digit */
+ time_t sc_dtmo; /* total time to dial number */
+ int sc_counter; /* random counter */
+ char sc_pchar = ','; /* modem pause character */
+ char sc_wchar = 'W'; /* modem wait-for-dialtone character */
+ time_t sc_begwait; /* time at beg of wait */
+ time_t sc_secs; /* timeout period */
+
+ int expcnt;
+ int expin;
+ static char expbuf[MAX_EXPCT];
+
+ dbgsave = Debug;
+ curstate = begin;
+
+ if (curstate == (struct script *)NULL)
+ return SUCCESS;
+
+ _newstate:
+ /*
+ * do all of curstate's actions. Enter with curstate pointing
+ * to a label entry
+ */
+ expin = 0;
+
+ for (curscr = curstate->next; /* point to 1st scr after label */
+ (curscr != (struct script *)NULL) && /* do until end of scr */
+ (curscr->opcode != SC_LABEL); /* or next label */
+ curscr = curscr->next)
+ {
+ expcnt = 0;
+ switch (curscr->opcode)
+ {
+ case SC_LABEL:
+ logit("Script proc err", curstate->strprm);
+ return FAIL;
+
+ case SC_FLSH:
+ DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0);
+ ttflui();
+ break;
+
+ case SC_CDLY:
+ sc_chrdly = curscr->intprm;
+ DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly);
+ break;
+
+ case SC_PCHR:
+ sc_pchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar);
+ break;
+
+ case SC_PTIM:
+ sc_ptime = curscr->intprm;
+ DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime);
+ break;
+
+ case SC_WCHR:
+ sc_wchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar);
+ break;
+
+ case SC_WTIM:
+ sc_wtime = curscr->intprm;
+ DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime);
+ break;
+
+ case SC_ZERO:
+ sc_counter = 0;
+ DEBUG(DB_LGII, "Set counter to %d\n", sc_counter);
+ break;
+
+ case SC_INCR:
+ sc_counter++;
+ DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter);
+ break;
+
+ case SC_WAIT:
+ DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm);
+ msleep(curscr->intprm);
+ break;
+
+ case SC_DTIM:
+ sc_dtime = curscr->intprm;
+ DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime);
+ break;
+
+ case SC_CTIM:
+ sc_carrtime = curscr->intprm;
+ DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime);
+ break;
+
+ case SC_EXIT:
+ Debug = dbgsave;
+ DEBUG(DB_LGI, "Script ended successfully\n", 0);
+ return SUCCESS;
+
+ case SC_FAIL:
+ Debug = dbgsave;
+ if (DEBUG_LEVEL(DB_LGI) && dbf != NULL)
+ fprintf(dbf, "Script failed\n");
+ else if (expin)
+ charlog(expbuf, expin, DB_LOG,
+ "Script failed. Last received data");
+ return FAIL;
+
+ case SC_LOG:
+ logit(curscr->strprm, "");
+ break;
+
+ case SC_LOGE:
+ logit("ERROR: ", curscr->strprm);
+ break;
+
+ case SC_DBOF:
+ /*
+ * If the debug file name does not begin with "/", then
+ * we prepend the LOG_DIR to the string. Then CREATE the
+ * file. This WIPES OUT previous logs.
+ */
+ *dfname = '\0'; /* Zero name string */
+ if(curscr->strprm[0] != '/')
+ strcat(dfname, LOG_DIR); /* Prepend default directory */
+ strcat(dfname, curscr->strprm); /* Add given string */
+ DEBUG(DB_LGII, "Open debug file %s\n", dfname);
+ if ((dbfd = creat (dfname, 0600)) <= 0)
+ {
+ logit("Failed to create debug log %s", dfname);
+ perror("");
+ return FAIL;
+ }
+ if ((dbf = fdopen(dbfd, "w")) == NULL)
+ {
+ logit("Failed to open debug log fildes.", "");
+ perror("");
+ return FAIL;
+ }
+ break;
+
+ case SC_DBG:
+ DEBUG(DB_LGI, "<%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBGE:
+ DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBST:
+ Debug |= curscr->intprm;
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_DBCL:
+ Debug &= ~(curscr->intprm);
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_BRK:
+ DEBUG(DB_LGI, "Sending break\n", 0);
+ ttbreak();
+ break;
+
+ case SC_HANG:
+ DEBUG(DB_LGI, "Dropping DTR\n", 0);
+ tthang();
+ break;
+
+ case SC_7BIT:
+ DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0);
+ tt7bit(TRUE);
+ break;
+
+ case SC_8BIT:
+ DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0);
+ tt7bit(FALSE);
+ break;
+
+ case SC_PNON:
+ DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0);
+ ttpar(NONE);
+ break;
+
+ case SC_PEVN:
+ DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0);
+ ttpar(EVEN);
+ break;
+
+ case SC_PODD:
+ DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0);
+ ttpar(ODD);
+ break;
+
+ case SC_IFBL:
+ if (ttblind())
+ {
+ DEBUG(DB_LGI, "Blind mux,\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFBG:
+ if (ttblind() && sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Blind mux & ctr > %d\n",
+ curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFGT:
+ if (sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_GOTO:
+ _chgstate:
+ DEBUG(DB_LGI, "Changing to state %s\n",
+ curscr->newstate);
+ curstate = find_state(begin, curscr->newstate);
+ if (curstate == NULL)
+ {
+ logit("New state not found",
+ curscr->newstate);
+ return FAIL;
+ }
+ goto _newstate;
+
+ case SC_SEND:
+ ttoslow(curscr->strprm, curscr->intprm, sc_chrdly);
+ break;
+
+ case SC_TELN:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "telno - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ strcpy(telno, paramv[curscr->intprm]);
+ DEBUG(DB_LGII, "telno set to %s\n", telno);
+ break;
+
+ case SC_SNDP:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "sendstr - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ prmlen = xlat_str(tempstr, paramv[curscr->intprm]);
+ ttoslow(tempstr, prmlen, sc_chrdly);
+ break;
+
+ case SC_IF1P:
+ if (curscr->intprm < paramc)
+ goto _chgstate;
+ break;
+
+ case SC_IF0P:
+ if (curscr->intprm >= paramc)
+ goto _chgstate;
+ break;
+
+ case SC_DIAL:
+ if(telno[0] == '\0')
+ {
+ logit("telno not set", "");
+ return(FAIL);
+ }
+ /*
+ * Compute and set a default timeout for the 'timeout'
+ * command. Some parameters in this computation may be
+ * changed by the script. See the man page xchat(8) for
+ * details.
+ */
+ sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno)
+ + sc_carrtime;
+ c=strcpy(tempstr, telno);
+ for (; *c!='\0'; c++)
+ {
+ if (*c == 'W')
+ {
+ *c = sc_wchar;
+ sc_dtmo += sc_wtime;
+ }
+ else if (*c == 'P')
+ {
+ *c = sc_pchar;
+ sc_dtmo += sc_ptime;
+ }
+ }
+ DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo);
+ ttoslow(tempstr, 0, sc_chrdly);
+ break;
+
+ case SC_TIMO: /* these are "expects", don't bother */
+ case SC_XPCT: /* with them yet, other than noting that */
+ case SC_CARR: /* they exist */
+ expcnt++;
+ break;
+ }
+
+ }
+
+ /* we've done the current state's actions, now do its expects, if any */
+
+ if (expcnt == 0)
+ {
+ if (curscr != (struct script *)NULL &&
+ (curscr->opcode == SC_LABEL))
+ {
+ curstate = curscr;
+ DEBUG(DB_LGI, "Fell through to state %s\n",
+ curstate->strprm);
+ goto _newstate;
+ }
+ else
+ {
+ logit("No way out of state", curstate->strprm);
+ return FAIL;
+ }
+ }
+
+ time(&sc_begwait); /* log time at beg of expect */
+ DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm);
+ charlog((char *)NULL, 0, DB_LGI, "Received");
+
+ while (1)
+ {
+ chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */
+
+ charlog(&chr, 1, DB_LGI, (char *)NULL);
+
+ if (chr != EOF)
+ {
+ if (expin < MAX_EXPCT)
+ {
+ expbuf[expin++] = chr & 0x7f;
+ }
+ else
+ {
+ strncpy(expbuf, &expbuf[1], MAX_EXPCT-1);
+ expbuf[MAX_EXPCT-1] = chr & 0x7f;
+ }
+ }
+
+ /* for each entry in the current state... */
+
+ for (curscr = curstate->next;
+ (curscr != (struct script *)NULL) &&
+ (curscr->opcode != SC_LABEL);
+ curscr = curscr->next)
+ {
+
+ switch (curscr->opcode)
+ {
+ case SC_TIMO:
+ sc_secs = curscr->intprm;
+ if (sc_secs == 0)
+ sc_secs = sc_dtmo;
+ sc_secs /= 1000;
+ if (time(NULL)-sc_begwait > sc_secs)
+ {
+ DEBUG(DB_LGI,
+ "\nTimed out (%d secs)\n", sc_secs);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_CARR:
+ if (ttcd())
+ {
+ DEBUG(DB_LGI, "\nGot carrier\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_HUPS:
+ if (fShangup)
+ {
+ DEBUG(DB_LGI, "\nGot data set hangup\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_XPCT:
+ if ((expin >= curscr->intprm) &&
+ (strncmp(curscr->strprm,
+ &expbuf[expin - curscr->intprm],
+ curscr->intprm) == SAME))
+ {
+ charlog(curscr->strprm, curscr->intprm,
+ DB_LGI, "Matched");
+ goto _chgstate;
+ }
+ break;
+
+ }
+ }
+ }
+}
+
+/*
+ * SIGNAL HANDLERS
+ */
+
+/*
+ * usignal - generic signal catcher
+ */
+static int usignal(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig);
+ restore_tty();
+ exit(FAIL);
+}
+
+/*
+ * uhup - HUP catcher
+ */
+static int uhup(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Data set hangup.\n");
+ fShangup = TRUE;
+}
+
+/*
+ * TERMINAL I/O ROUTINES
+ */
+
+/*
+ * xgetc - get a character with timeout
+ *
+ * Assumes that stdin is opened on a terminal or TCP socket
+ * with O_NONBLOCK.
+ */
+static char xgetc(tmo)
+int tmo; /* Timeout, seconds */
+{
+ char c;
+ struct timeval s;
+ int f = 1; /* Select on stdin */
+ int result;
+
+ if(read(0, &c, 1) <= 0) /* If no data available */
+ {
+ s.tv_sec = (long)tmo;
+ s.tv_usec = 0L;
+ if(select (1, &f, (int *) NULL, &f, &s) == 1)
+ read(0, &c, 1);
+ else
+ c = '\377';
+ }
+
+ return(c);
+}
+
+/*
+ * Pause for an interval in milliseconds
+ */
+void msleep(msec)
+long msec;
+{
+
+#if HAVE_USLEEP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ usleep (msec * (long)1000);
+#endif /* HAVE_USLEEP */
+
+#if HAVE_NAPMS
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ napms (msec);
+#endif /* HAVE_NAPMS */
+
+#if HAVE_NAP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ nap (msec);
+#endif /* HAVE_NAP */
+
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ if(msec == 0)
+ return;
+ /*
+ * We need to pass an unused pollfd structure because poll checks
+ * the address before checking the number of elements.
+ */
+ poll (&sdummy, 0, msec);
+#endif /* HAVE_POLL */
+
+#if USE_SELECT_TIMER
+ struct timeval s;
+
+ if(msec == 0)
+ return;
+ s.tv_sec = msec / 1000L;
+ s.tv_usec = (msec % 1000L) * 1000L;
+ select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \
+ ! HAVE_POLL && ! USE_SELECT_TIMER
+ if(msec == 0)
+ return;
+ sleep (1); /* Sleep for a whole second (UGH!) */
+#endif /* HAVE_ and USE_ nothing */
+}
+
+/*
+ * Debugging output
+ */
+static void DEBUG(level, msg1, msg2)
+int level;
+char *msg1, *msg2;
+{
+ if ((dbf != NULL) && DEBUG_LEVEL(level))
+ fprintf(dbf, msg1, msg2);
+}
+
+/*
+ * charlog - log a string of characters
+ *
+ * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged
+ * when read does its 1 sec. timeout. Log "<1 sec.>"
+ * so user can see elapsed time
+ */
+static void charlog(buf, len, mask, msg)
+char *buf;
+int len, mask;
+char *msg;
+{
+ char tbuf[256];
+
+ if (DEBUG_LEVEL(mask) && dbf != NULL)
+ {
+ if(msg == (char *)NULL)
+ msg = "";
+ strncpy(tbuf, buf, len);
+ tbuf[len] = '\0';
+ if(len == 1 && tbuf[0] == '\377')
+ strcpy(tbuf, "<1 sec.>");
+ fprintf(dbf, "%s %s\n", msg, tbuf);
+ }
+}
+
+/*
+ * setup_tty()
+ *
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+static void setup_tty()
+{
+ register int i;
+
+ ioctl(0, TCGETA, &old);
+
+ new = old;
+
+ for(i = 0; i < 7; i++)
+ new.c_cc[i] = '\0';
+ new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */
+ new.c_cc[VTIME] = 10; /* TIME = 1 sec. */
+ new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */
+ new.c_lflag = 0; /* No special line discipline */
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * restore_tty() - restore signal handlers and tty modes on exit.
+ */
+static void restore_tty(sig)
+int sig;
+{
+ ioctl(0, TCSETA, &old);
+ return;
+}
+
+/*
+ * ttoslow() - Send characters with pacing delays
+ */
+static void ttoslow(s, len, delay)
+ char *s;
+ int len;
+ time_t delay;
+{
+ int i;
+
+ if (len == 0)
+ len = strlen(s);
+
+ charlog (s, len, DB_LGI, "Sending slowly");
+
+ for (i = 0; i < len; i++, s++)
+ {
+ write(1, s, 1);
+ msleep(delay);
+ }
+}
+
+/*
+ * ttflui - flush input buffer
+ */
+static void ttflui()
+{
+ if(isatty(0))
+ (void) ioctl ( 0, TCFLSH, 0);
+}
+
+/*
+ * ttcd - Test if carrier is present
+ *
+ * NOT IMPLEMENTED. I don't know how!!!
+ */
+static int ttcd()
+{
+ return TRUE;
+}
+
+/*
+ * tthang - Force DTR low for 1-2 sec.
+ */
+static void tthang()
+{
+ if(!isatty())
+ return;
+
+#ifdef TCCLRDTR
+ (void) ioctl (1, TCCLRDTR, 0);
+ sleep (2);
+ (void) ioctl (1, TCSETDTR, 0);
+#endif
+
+ return;
+}
+
+/*
+ * ttbreak - Send a "break" on the line
+ */
+static void ttbreak()
+{
+ (void) ioctl (1, TCSBRK, 0);
+}
+
+/*
+ * ttblind - return TRUE if tty is "blind"
+ *
+ * NOT IMPLEMENTED - Don't know how!!!
+ */
+static int ttblind()
+{
+ return FALSE;
+}
+
+/*
+ * tt7bit - enable/disable 7-bit stripping on line
+ */
+static void tt7bit(enable)
+ int enable;
+{
+ if(enable)
+ new.c_iflag |= ISTRIP;
+ else
+ new.c_iflag &= ~ISTRIP;
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * ttpar - Set parity mode on line. Ignore parity errors on input.
+ */
+static void ttpar(mode)
+ int mode;
+{
+ switch(mode)
+ {
+ case NONE:
+ new.c_iflag &= ~(INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARENB | PARODD);
+ new.c_cflag |= CS8;
+ break;
+
+ case EVEN:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARODD);
+ new.c_cflag |= (CS7 | PARENB);
+
+ break;
+
+ case ODD:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE);
+ new.c_cflag |= (CS7 | PARENB | PARODD);
+ break;
+ }
+
+ ioctl(0, TCSETA, &new);
+}
+
+
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/xchat.man b/gnu/libexec/uucp/contrib/xchat.man
new file mode 100644
index 00000000000..c980e202fcb
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xchat.man
@@ -0,0 +1,614 @@
+.TH xchat 8
+.SH NAME
+xchat - Extended chat processor
+.SH SYNOPSIS
+.BI "xchat " "scriptfile"
+.RI " [ " parameter... " ] "
+.PP
+where
+.I scriptfile
+is the name of a file containing an
+.I xchat
+script. If
+.I scriptfile
+begins with ``/'', then it is assumed to be a full path name for the
+script file. If not, a configuration-dependent default directory path
+(usually
+.B "/usr/local/conf/uucp/"
+) is prepended to the script file name. Normally, the default path
+is the same as that for the Taylor UUCP configuration files.
+.SH DESCRIPTION
+.I Xchat
+is a general-purpose dialing and login program designed for use
+with Taylor UUCP as a ``chat-program'', taking the place (or
+augmenting) the built-in chat scripting facility. It provides the
+ability to closely control timeouts, multiple simultaneous ``expect''
+strings with separate actions, extended terminal control, modem
+command character pacing, and more.
+.PP
+When used in conjunction with Taylor UUCP's
+configuration features,
+.I xchat
+can provide you the ability to manage the most intricate login,
+dial and hangup needs. The scripts are written in a shell-like (well,
+sort-of) style with labels, commands, and parameters, easing the task
+of writing procedures for complex terminal communications situations.
+.PP
+Because
+.I xchat
+assumes that it is connected to the terminal device via stdin/stdout,
+you can easily debug scripts by invoking it from the shell and
+responding to the script from the keyboard. A debug logging facility
+is included, with the debug output going to a separate user-specified
+file. This makes it easy to debug connection problems without wading
+through large
+.I uucico
+log and debug files.
+.PP
+Formally, a script describes a state machine;
+.I xchat
+interprets the script and does what the state machine
+tells it to. This section will be much easier to understand
+if you obtain listings of the script files supplied with
+.I xchat.
+.SH "SCRIPT FILE FORMAT"
+Script files are ordinary text files containing comments, labels,
+and statements. Blank lines are ignored.
+Comments are denoted by leading ``#''
+characters. Some statements (those which do not end with an
+``extended string'' argument; see below) can also have trailing
+comments.
+.PP
+.I Labels
+begin in column one and are ended by colons (:). A label
+specifies a state name. All lines between a pair of labels are
+the statements for a single state.
+.PP
+Processing always begins at the head of the script (no leading
+state name is necessary).
+.PP
+.I Statements
+are divided into two categories, ``action'' and ``expect''.
+When a state is entered, all of its actions are performed in the
+order in which they appear in the file.
+.PP
+A
+.I transition
+to another state may occur for any of three reasons:
+.IP (1) 5
+One of the actions may cause a transition to
+another state, in which case the rest of the
+current state's actions are skipped.
+Processing resumes with the first action
+statement of the new state.
+.IP (2) 5
+If none of the actions cause a state
+transition, and there are no expects in the
+state, processing ``falls through'' to the next
+state in the file.
+.IP (3) 5
+If none of the actions cause a state
+transition, but there are expects in the
+state, the state machine pauses until one of
+the expects is ``satisfied''. It then transitions
+to the state named in the expect
+statement.
+.PP
+Finally, there are two action statements which, when executed,
+cause the script to exit.
+.SH "SCRIPT FILE STATEMENTS"
+This section describes all of the statements that may appear in script
+files, except for a few special action statements. Those are described
+in a later section, ``Overriding Defaults''.
+.PP
+Some statements accept one or two arguments, referred to in the
+following descriptions as
+.IR int ", " ns ", " str ", or "
+.IR xstr ", to"
+indicate whether the argument is an integer, a new state name, a
+string, or an ``extended string'' (described in a later section).
+.PP
+For all statements that accept two arguments, the first is the
+name of a new state, and the second specifies a condition or
+reason for changing to the new state.
+.SS "Termination And Informational Statements"
+These statements are used to place entries into the Taylor UUCP
+.I Log
+file, and to cause
+.I xchat
+to exit with successful or failure status. It is also possible to open a
+separate
+.I debug
+log file and control the level of tracing and error reporting that will go
+into that log file. This is very useful in debugging
+.I xchat
+scripts.
+.br
+.ta 1.0i 1.5i 2.0i
+.TP 2.0i
+.B failed
+Exit script with ``failed'' status. This causes
+.I xchat
+to exit with status 0.
+.TP 2.0i
+.B success
+Exit script with ``success'' status. This causes
+.I xchat
+to exit with status 1.
+.TP 2.0i
+.BI "log " xstr
+Send informational message
+.I xstr
+to standard error. When used with Taylor UUCP, this is the
+.I Log
+file for the
+.I uucico
+program.
+.TP 2.0i
+.BI "logerr " xstr
+Send message
+.I xstr
+to standard error, with ``ERROR:'' indicator. When used
+with Taylor UUCP, this is the
+.I Log
+file for the
+.I uucico
+program.
+.TP 2.0i
+.BI "dbgfile " xstr
+Open script debugging file
+.I xstr.
+If
+.I xstr
+begins with ``/'', it is assumed to be an absolute path name for the
+debugging file. If not, then a configuration-dependent default directory
+path (usually
+.B "/usr/spool/uucp"
+) is prepended to
+.I xstr.
+Normally the default path is that of the directory where Taylor UUCP
+puts its log files.
+The debugging file is used to capture a detailed log of the data sent
+and received, errors encountered, and a trace of script execution.
+The various types of logging are controlled by the
+.I "debug mask,"
+described next.
+.B Note:
+A new log file is created each time
+.I xchat
+runs. Use the
+.B log
+and
+.B loge
+commands to log
+continuous information onto standard out, which is connected
+to the Taylor UUCP
+.I Log
+file when
+.I xchat
+is run by the Taylor
+.I uucico.
+.TP 2.0i
+.BI "dbgset " int
+Set the bits specified in
+.I int
+in the debugging mask. The value in
+.I int
+is ``or''ed into the mask. Set bit 0 (value \= 1) for error messages,
+bit 1 (value \= 2) for dial, login and init errors, bit 2 (value \= 4)
+for dial, login and init trace with character I/O, and bit 3 (value \= 8)
+for script processing internals. Normally, you will just turn it all on
+with a value of 15.
+.TP 2.0i
+.BI "dbgclr " int
+Clear the bits specified in
+.I int
+from the debugging mask.
+.TP 2.0i
+.BI "debug " xstr
+Write
+.I
+xstr
+into the debug log. The entry will be enclosed in angle brackets.
+.TP 2.0i
+.BI "debuge " xstr
+Write
+.I xstr
+into the debug log with ``ERROR: '' prepended. The entry will be enclosed
+in angle brackets.
+.SS "Sending Data"
+These statements are used to transmit data to standard out (the tty or TCP
+port when used with Taylor UUCP).
+.I
+No implied carriage returns are sent.
+You must include a \\r if you want a carriage return in the string
+sent by the
+.B send
+command. If you want a return sent after
+.B dial
+or
+.B sendstr,
+you must send it with a separate
+.B send
+command.
+.TP 2.0i
+.B dial
+Send the string previously set by the
+.B telno
+command to the serial port.
+.B W
+and
+.B P
+characters in the phone number are
+converted as described under
+.B
+Dial Strings,
+below. This statement also sets a default
+timeout value, as described under the
+.B timeout
+statement.
+.TP 2.0i
+.BI "send " xstr
+Send the string
+.I xstr
+to the serial port.
+.TP 2.0i
+.BI "sendstr " int
+The argument of this statement is a digit from 0
+through 7. Send the corresponding string
+parameter as passed to
+.I xchat
+following the script file name. The parameter is interpreted
+as an extended string.
+.SS "Special Terminal Control Statements"
+These statements are used to cause the terminal port to perform some special action, or to change the mode of the port.
+.I
+The modes of the port are restored to their original settings
+.I
+by xchat before it exits.
+.TP 2.0i
+.B flush
+Flush the terminal port's input buffer.
+.TP 2.0i
+.B break
+Send a break signal.
+.TP 2.0i
+.B hangup
+Momentarily drop Data Terminal Ready (DTR) on the
+serial port, causing the modem to hang up. (Not
+usually needed, since
+.I uucico
+does this at the end of each call.)
+.TP 2.0i
+.B 7bit
+Change the port to strip incoming characters to 7 bits.
+.I
+This is the default mode.
+This mode
+is implied when the port has parity enabled, since parity characters
+are 7-bits wide.
+.TP 2.0i
+.B 8bit
+Change the port to allow incoming 8-bit characters to be passed
+to the script processor. This mode has no effect if parity is
+enabled, since parity characters are 7-bits wide.
+.TP 2.0i
+.B nopar
+Change the port to 8-bits, no parity.
+.I
+This is the default mode.
+.TP 2.0i
+.B evenpar
+Change the port to 7-bits, even parity.
+.I
+Incoming characters with parity errors are discarded.
+.TP 2.0i
+.B oddpar
+Change the port to 7-bits, odd parity.
+.I
+Incoming characters with parity errors are discarded.
+.SS "Counting, Branching, Timing and Testing Statements"
+These statements are used to control the flow of the
+.I xchat
+script itself, including branching, delays, and counter manipulation.
+.TP 2.0i
+.BI "sleep " int
+Delay for
+.I int
+milliseconds.
+.TP 2.0i
+.B zero
+Clear the counter.
+.TP 2.0i
+.B count
+Add one to the counter.
+.TP 2.0i
+.BI "ifgtr " "ns int"
+Go to state
+.I ns
+if counter greater than
+.I int.
+.TP 2.0i
+.BI "goto " ns
+Go to state
+.I ns
+unconditionally.
+.TP 2.0i
+.BI "ifstr " "ns int"
+Go to state
+.I ns
+if string parameter
+.I int
+is nonempty.
+.TP 2.0i
+.BI "ifnstr " "ns int"
+Go to state
+.I ns
+if string parameter
+.I int
+is empty.
+.TP 2.0i
+.BI "ifblind " ns
+Change to state
+.I ns
+if the port is ``blind'' without carrier (CD) asserted.
+.I
+This is not yet implemented, the test always fails.
+.TP 2.0i
+.BI "ifblgtr " "ns int"
+Change to state
+.I ns
+if the port is ``blind'' without carrier (CD) asserted, and counter
+is greater then
+.I int.
+.I
+This is not yet implemented, the test always fails.
+.SS "Expect Statements"
+Expect statements are usually the last statements that appear in a
+given state, though in fact they can appear anywhere within the
+state. Even if they appear at the beginning, the script processor
+always does all of the action statements first. As a practical
+matter, the order of these statements is not significant; they are
+all interpreted ``in parallel''.
+.TP 2.0i
+.BI "expect " "ns xstr"
+Change to state
+.I ns
+if the string specified by
+.I xstr
+is received from standard input (usually the serial port).
+Case is significant, but high-order bits are not
+checked.
+.TP 2.0i
+.BI "ifcarr " ns
+Change to state
+.I ns
+if Carrier Detect (CD) is true.
+.I
+Not currently implemented. Always changes state.
+.TP 2.0i
+.BI "ifhang " ns
+Change to state
+.I ns
+if a data set hangup occurs (SIGHUP signal received).
+.TP 2.0i
+.BI "timeout " "ns int"
+Change to state
+.I ns
+if the time (in milliseconds)
+given by
+.I int
+has elapsed without satisfying any
+expects. If the time specified is 0, a default
+timeout value (calculated from the length and
+other characteristics of the most recent dial
+string) is used.
+.SH "SCRIPT PROCESSING DETAILS"
+.SS "Extended Strings"
+In the statements that accept string arguments, the strings are
+interpreted as
+.I
+extended strings.
+Extended strings begin with
+the first nonblank character and continue, including all imbedded
+and trailing blanks and other whitespace, until (but not
+including) the end of the line in the script file. (There is no
+provision for line continuation.) No trailing spaces should be
+present between the last ``desired'' character of the string and the
+end of the line, as they will be included in the stored string and
+sent or expected, just as they appear in the script file. And,
+obviously, no trailing comments are permitted! They will just be
+stored as part of the string.
+.PP
+Within an extended string, the following ``escape sequences'' will
+be converted as indicated before being sent or expected:
+.br
+.nf
+.in +0.5i
+\fB\\d\fR EOT character (control-D)
+\fB\\N\fR null character
+\fB\\n\fR line feed
+\fB\\r\fR carriage return
+\fB\\s\fR space
+\fB\\t\fR tab
+\fB\\\-\fR hyphen
+\fB\\\\\fR backslash
+\fB\\ooo\fR character with value ooo (in octal)
+.in -0.5i
+.fi
+.PP
+Since extended strings in scripts can include embedded spaces,
+tabs, etc., these escape sequences are only required in strings
+appearing in systems entries, though they may be used in script
+files to improve readability.
+.PP
+The octal-character specification (\\ooo) may have from one to
+three octal digits; it is terminated either after the third digit
+or when a non-octal character is encountered. But if you want to
+specify one of these followed by something that happens to be a
+valid octal character (for example, a control-A followed by a 7)
+make sure to include all three digits after the \\ . So \\0017
+would become a control-A followed by the Ascii character ``7'', but
+\\17 or \\017 would become a control-Y (decimal value 25). \\1S
+would convert to a control-A followed by an ``S''.
+.PP
+Extended strings are stored without a trailing carriage return
+unless one is explicitly present in the string (via \\r).
+.SS "String Parameters"
+The
+.B sendstr
+statement sends (after conversion from extended string
+format) one of the parameters given on the
+.I xchat
+command line following the script file name.
+The parameter is selected by the integer
+argument of the statement.
+.PP
+This allows ``generic'' script files to serve
+for many different systems; the string parameters
+provide the phone number, username, password, etc. Character
+substitutions described under ``extended strings'' above are
+performed on these strings.
+.PP
+The ifstr and ifnstr statements allow further generality in script
+files, by testing whether a particular parameter is present in the
+systems entry. For example, a single script can be
+used both for those systems that require a password and
+those that do not. The password is specified as the last argument
+in the
+.xchat
+command; the script can test for this
+parameter's existence and skip the password sequence if
+the parameter is empty.
+.SS "``Wait'' And ``Pause'' Characters In Dial Strings"
+An additional conversion is performed on dial strings. Dial strings
+are interpreted as extended strings. Then the characters
+.B W
+and
+.B P
+within a dial string are interpreted as ``wait for dial
+tone'' and ``pause'', and may be converted to other characters. By
+default,
+.B W
+is left alone, and
+.B P
+is converted to a comma (,);
+these are appropriate for Hayes-type modems. The script may
+specify other substitutions (see below).
+.PP
+.B NOTE:
+The Taylor UUCP documentation states that the ``wait'' and ``pause''
+characters are ``='' and ``-'', respectively. These are actual characters
+understood by some modems. When using
+.I xchat
+you should put
+.B W
+and
+.B P
+in the dial strings you specify in the Taylor configuration files.
+This way, the
+.I xchat
+processor can make the substitution appropriate for the particular
+modem in use. Make a separate
+.I xchat
+script for each modem type, e.g.,
+.I "dial.hayes"
+and specify the translation there. This way, the phone number strings
+in the Taylor configuration files can be used with a variety of modems.
+.SS "Default Timeouts For Dial Strings"
+When a
+.B dial
+statement is executed, a default timeout value is set.
+This is the timeout value used by a subsequent timeout statement
+if the statement specifies a timeout value of 0.
+.PP
+The default timeout is given by:
+.br
+.nf
+.in +2
+\fIctime\fR + (\fIndigits\fR * \fIdgttime\fR) + (\fInwchar\fR * \fIwtime\fR) + (\fInpchar\fR * \fI ptime\fR)
+.in -2
+.fi
+.PP
+where
+.I
+ndigits, nwchar,
+and
+.I npchar
+are the number of digits, wait characters, and pause characters in
+the dial string, and
+.I ctime, dgttime, wtime,
+and
+.I ptime
+are 45 seconds, 0.1 seconds, 10 seconds, and 2 seconds,
+respectively.
+All of these times may be changed as specified below under
+``Overriding Defaults.''
+.SS "Trailing Carriage Returns Not Assumed"
+In the
+.B dial
+and
+.B sendstr
+statements, the dial string or
+parameter is sent with no trailing carriage return;
+if a carriage return must be sent after one of these, a separate
+send statement must provide it.
+.SH "OVERRIDING DEFAULTS"
+The script processor sets several default values. The following
+statements, which override these defaults, may be useful in
+certain circumstances.
+.TP 2.0i
+.BI "chrdly " int
+Since many modems cannot accept dialing commands
+at full ``computer speed'', the script processor
+sends all strings with a brief inter-character
+delay. This statement specifies the delay time,
+in milliseconds. The default is 100 (0.1 second).
+.TP 2.0i
+.BI "pchar " str
+Specifies the character to which
+.BR P s
+in the
+dial string should be converted. Default is
+``,'', for use with Hayes-type modems.
+.TP 2.0i
+.BI "ptime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each pause character in
+the dial string. Default is 2000 (2 seconds).
+.TP 2.0i
+.BI "wchar " str
+Specifies the character to which
+.BR W s
+in the
+dial string should be converted. Default is
+``W'', for Hayes modems.
+.TP 2.0i
+.BI "wtime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each wait-for-dialtone
+character in the dial string. Default is 10000
+(10 seconds).
+.TP 2.0i
+.BI "dgttime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each digit character in
+the dial string. Default is 100 (0.1 second).
+.TP 2.0i
+.BI "ctime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for carrier to appear after
+the dial string is sent. Default is 45000 (45
+seconds).
+.SH "SEE ALSO"
+uucico(8) for Taylor UUCP, and documentation for Taylor UUCP.
+.SH AUTHOR
+Robert B. Denny (denny@alisa.com)
+.SH HISTORY
+This program is an adaptation of the dial/login script processing
+code that is a part of DECUS UUCP for VAX/VMS, written by Jamie
+Hanrahan, et. al.
+.SH BUGS
+This version (1.1) does not support BSD terminal facilities. Anyone
+volunteer to add this?
+
diff --git a/gnu/libexec/uucp/cu/Makefile b/gnu/libexec/uucp/cu/Makefile
new file mode 100644
index 00000000000..be03d0ba8e4
--- /dev/null
+++ b/gnu/libexec/uucp/cu/Makefile
@@ -0,0 +1,15 @@
+# Makefile for cu
+
+BINDIR= $(bindir)
+BINOWN= $(owner)
+BINMODE= 4555
+
+PROG= cu
+SRCS= cu.c prot.c log.c chat.c conn.c tcp.c tli.c copy.c
+LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
+DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP)
+CFLAGS+= -I$(.CURDIR)/../common_sources\
+ -DVERSION=\"$(VERSION)\"
+
+.include <bsd.prog.mk>
+.PATH: $(.CURDIR)/../common_sources
diff --git a/gnu/libexec/uucp/cu/cu.1 b/gnu/libexec/uucp/cu/cu.1
new file mode 100644
index 00000000000..56409a00427
--- /dev/null
+++ b/gnu/libexec/uucp/cu/cu.1
@@ -0,0 +1,286 @@
+''' $Id: cu.1,v 1.1 1993/08/04 19:31:53 jtc Exp $
+.TH cu 1 "Taylor UUCP 1.04"
+.SH NAME
+cu \- Call up another system
+.SH SYNOPSIS
+.B cu
+[ options ] [ system | phone | "dir" ]
+.SH DESCRIPTION
+The
+.I cu
+command is used to call up another system and act as a dial in
+terminal. It can also do simple file transfers with no error
+checking.
+
+.I cu
+takes a single argument, besides the options. If the argument is the
+string "dir" cu will make a direct connection to the port. This may
+only be used by users with write access to the port, as it permits
+reprogramming the modem.
+
+Otherwise, if the argument begins with a digit, it is taken to be a
+phone number to call. Otherwise, it is taken to be the name of a
+system to call. The
+.B \-z
+option may be used to name a system beginning with a digit, and the
+.B \-c
+option may be used to name a phone number that does not begin with a
+digit.
+
+.I cu
+locates a port to use in the UUCP configuration files. If a simple
+system name is given, it will select a port appropriate for that
+system. The
+.B \-p, \-l
+and
+.B \-s
+options may be used to control the port selection.
+
+When a connection is made to the remote system,
+.I cu
+forks into two processes. One reads from the port and writes to the
+terminal, while the other reads from the terminal and writes to the
+port.
+
+.I cu
+provides several commands that may be used during the conversation.
+The commands all begin with an escape character, initially
+.B ~
+(tilde). The escape character is only recognized at the beginning of
+a line. To send an escape character to the remote system at the start
+of a line, it must be entered twice. All commands are either a single
+character or a word beginning with
+.B %
+(percent sign).
+
+.I cu
+recognizes the following commands:
+
+.TP 5
+.B ~.
+Terminate the conversation.
+.TP 5
+.B ~! command
+Run command in a shell. If command is empty, starts up a shell.
+.TP 5
+.B ~$ command
+Run command, sending the standard output to the remote system.
+.TP 5
+.B ~| command
+Run command, taking the standard input from the remote system.
+.TP 5
+.B ~+ command
+Run command, taking the standard input from the remote system and
+sending the standard output to the remote system.
+.TP 5
+.B ~#, ~%break
+Send a break signal, if possible.
+.TP 5
+.B ~c directory, ~%cd directory
+Change the local directory.
+.TP 5
+.B ~> file
+Send a file to the remote system. This just dumps the file over the
+communication line. It is assumed that the remote system is expecting
+it.
+.TP 5
+.B ~<
+Receive a file from the remote system. This prompts for the local
+file name and for the remote command to execute to begin the file
+transfer. It continues accepting data until the contents of the
+.B eofread
+variable are seen.
+.TP 5
+.B ~p from to, ~%put from to
+Send a file to a remote Unix system. This runs the appropriate
+commands on the remote system.
+.TP 5
+.B ~t from to, ~%take from to
+Retrieve a file from a remote Unix system. This runs the appropriate
+commands on the remote system.
+.TP 5
+.B ~s variable value
+Set a
+.I cu
+variable to the given value. If value is not given, the variable is
+set to
+.B true.
+.TP 5
+.B ~! variable
+Set a
+.I cu
+variable to
+.B false.
+.TP 5
+.B ~z
+Suspend the cu session. This is only supported on some systems. On
+systems for which ^Z may be used to suspend a job,
+.B ~^Z
+will also suspend the session.
+.TP 5
+.B ~%nostop
+Turn off XON/XOFF handling.
+.TP 5
+.B ~%stop
+Turn on XON/XOFF handling.
+.TP 5
+.B ~v
+List all the variables and their values.
+.TP 5
+.B ~?
+List all commands.
+
+.I cu
+also supports several variables. They may be listed with the
+.B ~v
+command, and set with the
+.B ~s
+or
+.B ~!
+commands.
+
+.TP 5
+.B escape
+The escape character. Initially
+.B ~
+(tilde).
+.TP 5
+.B delay
+If this variable is true,
+.I cu
+will delay for a second after recognizing the escape character before
+printing the name of the local system. The default is true.
+.TP 5
+.B eol
+The list of characters which are considered to finish a line. The
+escape character is only recognized after one of these is seen. The
+default is carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R.
+.TP 5
+.B binary
+Whether to transfer binary data when sending a file. If this is
+false, then newlines in the file being sent are converted to carriage
+returns. The default is false.
+.TP 5
+.B binary-prefix
+A string used before sending a binary character in a file transfer, if
+the
+.B binary
+variable is true. The default is ^Z.
+.TP 5
+.B echo-check
+Whether to check file transfers by examining what the remote system
+echoes back. This probably doesn't work very well. The default is
+false.
+.TP 5
+.B echonl
+The character to look for after sending each line in a file. The
+default is carriage return.
+.TP 5
+.B timeout
+The timeout to use, in seconds, when looking for a character, either
+when doing echo checking or when looking for the
+.B echonl
+character. The default is 30.
+.TP 5
+.B kill
+The character to use delete a line if the echo check fails. The
+default is ^U.
+.TP 5
+.B resend
+The number of times to resend a line if the echo check continues to
+fail. The default is 10.
+.TP 5
+.B eofwrite
+The string to write after sending a file with the
+.B ~>
+command. The default is ^D.
+.TP 5
+.B eofread
+The string to look for when receiving a file with the
+.B ~<
+command. The default is $, which is intended to be a typical shell
+prompt.
+.TP 5
+.B verbose
+Whether to print accumulated information during a file transfer. The
+default is true.
+.SH OPTIONS
+The following options may be given to
+.I cu.
+.TP 5
+.B \-e
+Use even parity.
+.TP 5
+.B \-o
+Use odd parity. If both
+.B \-e
+and
+.B \-o
+are used, no parity is used. Otherwise the default parity of the line
+is used.
+.TP 5
+.B \-h
+Echo characters locally (half-duplex mode).
+.TP 5
+.B \-z system
+The system to call.
+.TP 5
+.B \-c phone-number
+The phone number to call.
+.TP 5
+.B \-p port
+Name the port to use.
+.TP 5
+.B \-a port
+Equivalent to
+.B \-p port.
+.TP 5
+.B \-l line
+Name the line to use by giving a device name. This may be used to
+dial out on ports that are not listed in the UUCP configuration files.
+Write access to the device is required.
+.TP 5
+.B \-s speed
+The speed (baud rate) to use.
+.TP 5
+.B \-#
+Where # is a number, equivalent to
+.B \-s #.
+.TP 5
+.B \-n
+Prompt for the phone number to use.
+.TP 5
+.B \-d
+Enter debugging mode. Equivalent to
+.B \-x all.
+.TP 5
+.B \-x type
+Turn on particular debugging types. The following types are
+recognized: abnormal, chat, handshake, uucp-proto, proto, port,
+config, spooldir, execute, incoming, outgoing. Only abnormal, chat,
+handshake, port, config, incoming and outgoing are meaningful for
+.I cu.
+
+Multiple types may be given, separated by commas, and the
+.B \-x
+option may appear multiple times. A number may also be given, which
+will turn on that many types from the foregoing list; for example,
+.B \-x 2
+is equivalent to
+.B \-x abnormal,chat.
+.B \-x all
+may be used to turn on all debugging options.
+.TP 5
+.B \-I file
+Set configuration file to use. This option may not be available,
+depending upon how
+.I cu
+was compiled.
+.SH BUGS
+This program does not work very well.
+.SH FILES
+The file name may be changed at compilation time, so this is only an
+approximation.
+
+.br
+/usr/lib/uucp/config - Configuration file.
diff --git a/gnu/libexec/uucp/cu/cu.c b/gnu/libexec/uucp/cu/cu.c
new file mode 100644
index 00000000000..72d60a62ecc
--- /dev/null
+++ b/gnu/libexec/uucp/cu/cu.c
@@ -0,0 +1,2068 @@
+/* cu.c
+ Call up a remote system.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cu_rcsid[] = "$Id: cu.c,v 1.1 1993/08/04 19:31:54 jtc Exp $";
+#endif
+
+#include "cu.h"
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "prot.h"
+#include "system.h"
+#include "sysdep.h"
+#include "getopt.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* Here are the user settable variables. The user is permitted to
+ change these while running the program, using ~s. */
+
+/* The escape character used to introduce a special command. The
+ escape character is the first character of this string. */
+const char *zCuvar_escape = "~";
+
+/* Whether to delay for a second before printing the host name after
+ seeing an escape character. */
+boolean fCuvar_delay = TRUE;
+
+/* The input characters which finish a line. The escape character is
+ only recognized following one of these characters. The default is
+ carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the
+ Ultrix /etc/remote file. */
+const char *zCuvar_eol = "\r\025\003\017\004\023\021\022";
+
+/* Whether to transfer binary data (nonprintable characters other than
+ newline and tab) when sending a file. If this is FALSE, then
+ newline is changed to carriage return. */
+boolean fCuvar_binary = FALSE;
+
+/* A prefix string to use before sending a binary character from a
+ file; this is only used if fCuvar_binary is TRUE. The default is
+ ^Z. */
+const char *zCuvar_binary_prefix = "\026";
+
+/* Whether to check for echoes of characters sent when sending a file.
+ This is ignored if fCuvar_binary is TRUE. */
+boolean fCuvar_echocheck = FALSE;
+
+/* A character to look for after each newline is sent when sending a
+ file. The character is the first character in this string, except
+ that a '\0' means that no echo check is done. */
+const char *zCuvar_echonl = "\r";
+
+/* The timeout to use when looking for an character. */
+int cCuvar_timeout = 30;
+
+/* The character to use to kill a line if an echo check fails. The
+ first character in this string is sent. The default is ^U. */
+const char *zCuvar_kill = "\025";
+
+/* The number of times to try resending a line if the echo check keeps
+ failing. */
+int cCuvar_resend = 10;
+
+/* The string to send at the end of a file sent with ~>. The default
+ is ^D. */
+const char *zCuvar_eofwrite = "\004";
+
+/* The string to look for to finish a file received with ~<. For tip
+ this is a collection of single characters, but I don't want to do
+ that because it means that there are characters which cannot be
+ received. The default is a guess at a typical shell prompt. */
+const char *zCuvar_eofread = "$";
+
+/* Whether to provide verbose information when sending or receiving a
+ file. */
+boolean fCuvar_verbose = TRUE;
+
+/* The table used to give a value to a variable, and to print all the
+ variable values. */
+
+static const struct uuconf_cmdtab asCuvars[] =
+{
+ { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL },
+ { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL },
+ { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL },
+ { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL },
+ { "binary-prefix", UUCONF_CMDTABTYPE_STRING,
+ (pointer) &zCuvar_binary_prefix, NULL },
+ { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN,
+ (pointer) &fCuvar_echocheck, NULL },
+ { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL },
+ { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL },
+ { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL },
+ { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL },
+ { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL },
+ { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL },
+ { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL },
+ { NULL, 0, NULL, NULL}
+};
+
+/* The program name. */
+char abProgram[] = "cu";
+
+/* The string printed at the initial connect. */
+#if ANSI_C
+#define ZCONNMSG "\aConnected."
+#else
+#define ZCONNMSG "Connected."
+#endif
+
+/* The string printed when disconnecting. */
+#if ANSI_C
+#define ZDISMSG "\aDisconnected."
+#else
+#define ZDISMSG "Disconnected."
+#endif
+
+/* Local variables. */
+
+/* The string we print when the user is once again connected to the
+ port after transferring a file or taking some other action. */
+static const char abCuconnected[]
+#if ANSI_C
+ = "\a[connected]";
+#else
+ = "[connected]";
+#endif
+
+/* Global uuconf pointer. */
+static pointer pCuuuconf;
+
+/* Connection. */
+static struct sconnection *qCuconn;
+
+/* Whether to close the connection. */
+static boolean fCuclose_conn;
+
+/* Dialer used to dial out. */
+static struct uuconf_dialer *qCudialer;
+
+/* Whether we need to restore the terminal. */
+static boolean fCurestore_terminal;
+
+/* Whether we are doing local echoing. */
+static boolean fCulocalecho;
+
+/* Whether we need to call fsysdep_cu_finish. */
+static boolean fCustarted;
+
+/* A structure used to pass information to icuport_lock. */
+struct sconninfo
+{
+ boolean fmatched;
+ boolean flocked;
+ struct sconnection *qconn;
+ const char *zline;
+};
+
+/* Local functions. */
+
+static void ucuusage P((void));
+static void ucuabort P((void));
+static void uculog_start P((void));
+static void uculog_end P((void));
+static int icuport_lock P((struct uuconf_port *qport, pointer pinfo));
+static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn,
+ int bcmd));
+static boolean fcuset_var P((pointer puuconf, char *zline));
+static int icuunrecogvar P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static int icuunrecogfn P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static void uculist_vars P((void));
+static void uculist_fns P((const char *zescape));
+static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn,
+ char *zline));
+static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
+ size_t cbuf));
+
+#define ucuputs(zline) \
+ do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
+
+/* Long getopt options. */
+static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } };
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ /* -c: phone number. */
+ char *zphone = NULL;
+ /* -e: even parity. */
+ boolean feven = FALSE;
+ /* -l: line. */
+ char *zline = NULL;
+ /* -n: prompt for phone number. */
+ boolean fprompt = FALSE;
+ /* -o: odd parity. */
+ boolean fodd = FALSE;
+ /* -p: port name. */
+ const char *zport = NULL;
+ /* -s: speed. */
+ long ibaud = 0L;
+ /* -t: map cr to crlf. */
+ boolean fmapcr = FALSE;
+ /* -z: system. */
+ const char *zsystem = NULL;
+ /* -I: configuration file name. */
+ const char *zconfig = NULL;
+ int iopt;
+ pointer puuconf;
+ int iuuconf;
+ const char *zlocalname;
+ int i;
+ struct uuconf_system ssys;
+ const struct uuconf_system *qsys = NULL;
+ boolean flooped;
+ struct uuconf_port sport;
+ struct sconnection sconn;
+ struct sconninfo sinfo;
+ long ihighbaud;
+ struct uuconf_dialer sdialer;
+ struct uuconf_dialer *qdialer;
+ char bcmd;
+
+ /* We want to accept -# as a speed. It's easiest to look through
+ the arguments, replace -# with -s#, and let getopt handle it. */
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-'
+ && isdigit (BUCHAR (argv[i][1])))
+ {
+ size_t clen;
+ char *z;
+
+ clen = strlen (argv[i]);
+ z = zbufalc (clen + 2);
+ z[0] = '-';
+ z[1] = 's';
+ memcpy (z + 2, argv[i] + 1, clen);
+ argv[i] = z;
+ }
+ }
+
+ while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:",
+ asCulongopts, (int *) NULL)) != EOF)
+ {
+ switch (iopt)
+ {
+ case 'c':
+ /* Phone number. */
+ zphone = optarg;
+ break;
+
+ case 'd':
+ /* Set debugging level to maximum. */
+#if DEBUG > 1
+ iDebug = DEBUG_MAX;
+#endif
+ break;
+
+ case 'e':
+ /* Even parity. */
+ feven = TRUE;
+ break;
+
+ case 'h':
+ /* Local echo. */
+ fCulocalecho = TRUE;
+ break;
+
+ case 'n':
+ /* Prompt for phone number. */
+ fprompt = TRUE;
+ break;
+
+ case 'l':
+ /* Line name. */
+ zline = optarg;
+ break;
+
+ case 'o':
+ /* Odd parity. */
+ fodd = TRUE;
+ break;
+
+ case 'p':
+ case 'a':
+ /* Port name (-a is for compatibility). */
+ zport = optarg;
+ break;
+
+ case 's':
+ /* Speed. */
+ ibaud = strtol (optarg, (char **) NULL, 10);
+ break;
+
+ case 't':
+ /* Map cr to crlf. */
+ fmapcr = TRUE;
+ break;
+
+ case 'z':
+ /* System name. */
+ zsystem = optarg;
+ break;
+
+ case 'I':
+ /* Configuration file name. */
+ if (fsysdep_other_config (optarg))
+ zconfig = optarg;
+ break;
+
+ case 'x':
+#if DEBUG > 1
+ /* Set debugging level. */
+ iDebug |= idebug_parse (optarg);
+#endif
+ break;
+
+ case 0:
+ /* Long option found and flag set. */
+ break;
+
+ default:
+ ucuusage ();
+ break;
+ }
+ }
+
+ /* There can be one more argument, which is either a system name, a
+ phone number, or "dir". We decide which it is based on the first
+ character. To call a UUCP system whose name begins with a digit,
+ or one which is named "dir", you must use -z. */
+ if (optind != argc)
+ {
+ if (optind != argc - 1
+ || zsystem != NULL
+ || zphone != NULL)
+ ucuusage ();
+ if (strcmp (argv[optind], "dir") != 0)
+ {
+ if (isdigit (BUCHAR (argv[optind][0])))
+ zphone = argv[optind];
+ else
+ zsystem = argv[optind];
+ }
+ }
+
+ /* If the user doesn't give a system, port, line or speed, then
+ there's no basis on which to select a port. */
+ if (zsystem == NULL
+ && zport == NULL
+ && zline == NULL
+ && ibaud == 0L)
+ ucuusage ();
+
+ if (fprompt)
+ {
+ size_t cphone;
+
+ printf ("Phone number: ");
+ (void) fflush (stdout);
+ zphone = NULL;
+ cphone = 0;
+ if (getline (&zphone, &cphone, stdin) <= 0
+ || *zphone == '\0')
+ {
+ fprintf (stderr, "%s: No phone number entered\n", abProgram);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ iuuconf = uuconf_init (&puuconf, "cu", zconfig);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ pCuuuconf = puuconf;
+
+#if DEBUG > 1
+ {
+ const char *zdebug;
+
+ iuuconf = uuconf_debuglevel (puuconf, &zdebug);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ if (zdebug != NULL)
+ iDebug |= idebug_parse (zdebug);
+ }
+#endif
+
+ usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID);
+
+ iuuconf = uuconf_localname (puuconf, &zlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ zlocalname = zsysdep_localname ();
+ if (zlocalname == NULL)
+ exit (EXIT_FAILURE);
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ ulog_fatal_fn (ucuabort);
+ pfLstart = uculog_start;
+ pfLend = uculog_end;
+
+#ifdef SIGINT
+ usysdep_signal (SIGINT);
+#endif
+#ifdef SIGHUP
+ usysdep_signal (SIGHUP);
+#endif
+#ifdef SIGQUIT
+ usysdep_signal (SIGQUIT);
+#endif
+#ifdef SIGTERM
+ usysdep_signal (SIGTERM);
+#endif
+#ifdef SIGPIPE
+ usysdep_signal (SIGPIPE);
+#endif
+
+ if (zsystem != NULL)
+ {
+ iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ ulog (LOG_FATAL, "%s: System not found", zsystem);
+ }
+ qsys = &ssys;
+ }
+
+ /* This loop is used if a system is specified. It loops over the
+ various alternates until it finds one for which the dial
+ succeeds. This is an ugly spaghetti construction, and it should
+ be broken up into different functions someday. */
+ flooped = FALSE;
+ while (TRUE)
+ {
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+
+ /* The uuconf_find_port function only selects directly on a port
+ name and a speed. To select based on the line name, we use a
+ function. If we can't find any defined port, and the user
+ specified a line name but did not specify a port name or a
+ system or a phone number, then we fake a direct port with
+ that line name (we don't fake a port if a system or phone
+ number were given because if we fake a port we have no way to
+ place a call; perhaps we should automatically look up a
+ particular dialer). This permits users to say cu -lttyd0
+ without having to put ttyd0 in the ports file, provided they
+ have read and write access to the port. */
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ sinfo.zline = zline;
+ if (zport != NULL || zline != NULL || ibaud != 0L)
+ {
+ iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L,
+ icuport_lock, (pointer) &sinfo,
+ &sport);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ if (zline == NULL
+ || zport != NULL
+ || zphone != NULL
+ || qsys != NULL)
+ {
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "All matching ports in use");
+ else
+ ulog (LOG_FATAL, "No matching ports");
+ }
+
+ sport.uuconf_zname = zline;
+ sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
+ sport.uuconf_zprotocols = NULL;
+ sport.uuconf_qproto_params = NULL;
+ sport.uuconf_ireliable = 0;
+ sport.uuconf_zlockname = NULL;
+ sport.uuconf_palloc = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
+
+ if (! fsysdep_port_access (&sport))
+ ulog (LOG_FATAL, "%s: Permission denied", zline);
+
+ if (! fconn_init (&sport, &sconn))
+ ucuabort ();
+
+ if (! fconn_lock (&sconn, FALSE))
+ ulog (LOG_FATAL, "%s: Line in use", zline);
+
+ qCuconn = &sconn;
+ }
+ ihighbaud = 0L;
+ }
+ else
+ {
+ for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
+ {
+ if (! qsys->uuconf_fcall)
+ continue;
+ if (qsys->uuconf_qport != NULL)
+ {
+ if (fconn_init (qsys->uuconf_qport, &sconn))
+ {
+ if (fconn_lock (&sconn, FALSE))
+ {
+ qCuconn = &sconn;
+ break;
+ }
+ uconn_free (&sconn);
+ }
+ }
+ else
+ {
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
+ qsys->uuconf_ibaud,
+ qsys->uuconf_ihighbaud,
+ icuport_lock,
+ (pointer) &sinfo,
+ &sport);
+ if (iuuconf == UUCONF_SUCCESS)
+ break;
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ }
+ }
+
+ if (qsys == NULL)
+ {
+ const char *zrem;
+
+ if (flooped)
+ zrem = "remaining ";
+ else
+ zrem = "";
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "%s: All %smatching ports in use",
+ zsystem, zrem);
+ else
+ ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem);
+ }
+
+ ibaud = qsys->uuconf_ibaud;
+ ihighbaud = qsys->uuconf_ihighbaud;
+ }
+
+ /* Here we have locked a connection to use. */
+ if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE))
+ ucuabort ();
+
+ fCuclose_conn = TRUE;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Set up the connection. */
+ if (fodd && feven)
+ {
+ tparity = PARITYSETTING_NONE;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (fodd)
+ {
+ tparity = PARITYSETTING_ODD;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (feven)
+ {
+ tparity = PARITYSETTING_EVEN;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else
+ {
+ tparity = PARITYSETTING_DEFAULT;
+ tstrip = STRIPSETTING_DEFAULT;
+ }
+
+ if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON))
+ ucuabort ();
+
+ if (qsys != NULL)
+ zphone = qsys->uuconf_zphone;
+
+ if (qsys != NULL || zphone != NULL)
+ {
+ enum tdialerfound tdialer;
+
+ if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer,
+ &tdialer))
+ {
+ if (zport != NULL
+ || zline != NULL
+ || ibaud != 0L
+ || qsys == NULL)
+ ucuabort ();
+
+ if (qsys->uuconf_qalternate == NULL)
+ ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
+
+ fCuclose_conn = FALSE;
+ (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE);
+ qCuconn = NULL;
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ /* Loop around and try another alternate. */
+ flooped = TRUE;
+ continue;
+ }
+ if (tdialer == DIALERFOUND_FALSE)
+ qdialer = NULL;
+ else
+ qdialer = &sdialer;
+ }
+ else
+ {
+ /* If no system or phone number was specified, we connect
+ directly to the modem. We only permit this if the user
+ has access to the port, since it permits various
+ shenanigans such as reprogramming the automatic
+ callbacks. */
+ if (! fsysdep_port_access (sconn.qport))
+ ulog (LOG_FATAL, "Access to port denied");
+ qdialer = NULL;
+ if (! fconn_carrier (&sconn, FALSE))
+ ulog (LOG_FATAL, "Can't turn off carrier");
+ }
+
+ break;
+ }
+
+ qCudialer = qdialer;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Here we have connected, and can start the main cu protocol. The
+ program spends most of its time in system dependent code, and
+ only comes out when a special command is received from the
+ terminal. */
+ printf ("%s\n", ZCONNMSG);
+
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+
+ fCurestore_terminal = TRUE;
+
+ if (! fsysdep_cu_init (&sconn))
+ ucuabort ();
+
+ fCustarted = TRUE;
+
+ while (fsysdep_cu (&sconn, &bcmd, zlocalname))
+ if (! fcudo_cmd (puuconf, &sconn, bcmd))
+ break;
+
+ fCustarted = FALSE;
+ if (! fsysdep_cu_finish ())
+ ucuabort ();
+
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+
+ (void) fconn_close (&sconn, puuconf, qdialer, TRUE);
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ printf ("\n%s\n", ZDISMSG);
+
+ ulog_close ();
+
+ usysdep_exit (TRUE);
+
+ /* Avoid errors about not returning a value. */
+ return 0;
+}
+
+/* Print a usage message and die. */
+
+static void
+ucuusage ()
+{
+ fprintf (stderr,
+ "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ VERSION);
+ fprintf (stderr,
+ "Usage: cu [options] [system or phone-number]\n");
+ fprintf (stderr,
+ " -a port, -p port: Use named port\n");
+ fprintf (stderr,
+ " -l line: Use named device (e.g. tty0)\n");
+ fprintf (stderr,
+ " -s speed, -#: Use given speed\n");
+ fprintf (stderr,
+ " -c phone: Phone number to call\n");
+ fprintf (stderr,
+ " -z system: System to call\n");
+ fprintf (stderr,
+ " -e: Set even parity\n");
+ fprintf (stderr,
+ " -o: Set odd parity\n");
+ fprintf (stderr,
+ " -h: Echo locally\n");
+ fprintf (stderr,
+ " -t: Map carriage return to carriage return/linefeed\n");
+ fprintf (stderr,
+ " -n: Prompt for phone number\n");
+ fprintf (stderr,
+ " -d: Set maximum debugging level\n");
+ fprintf (stderr,
+ " -x debug: Set debugging type\n");
+#if HAVE_TAYLOR_CONFIG
+ fprintf (stderr,
+ " -I file: Set configuration file to use\n");
+#endif /* HAVE_TAYLOR_CONFIG */
+
+ exit (EXIT_FAILURE);
+}
+
+/* This function is called when a fatal error occurs. */
+
+static void
+ucuabort ()
+{
+ if (fCustarted)
+ {
+ fCustarted = FALSE;
+ (void) fsysdep_cu_finish ();
+ }
+
+ if (fCurestore_terminal)
+ {
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+ }
+
+ if (qCuconn != NULL)
+ {
+ struct sconnection *qconn;
+
+ if (fCuclose_conn)
+ {
+ fCuclose_conn = FALSE;
+ (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE);
+ }
+ qconn = qCuconn;
+ qCuconn = NULL;
+ (void) fconn_unlock (qconn);
+ uconn_free (qconn);
+ }
+
+ ulog_close ();
+
+ printf ("\n%s\n", ZDISMSG);
+
+ usysdep_exit (FALSE);
+}
+
+/* This variable is just used to communicate between uculog_start and
+ uculog_end. */
+static boolean fCulog_restore;
+
+/* This function is called by ulog before it output anything. We use
+ it to restore the terminal, if necessary. ulog is only called for
+ errors or debugging in cu, so it's not too costly to do this. If
+ we didn't do it, then at least on Unix each line would leave the
+ cursor in the same column rather than wrapping back to the start,
+ since CRMOD will not be on. */
+
+static void
+uculog_start ()
+{
+ if (! fCurestore_terminal)
+ fCulog_restore = FALSE;
+ else
+ {
+ fCulog_restore = TRUE;
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_terminal_restore ())
+ ucuabort ();
+ }
+}
+
+/* This function is called by ulog after everything is output. It
+ sets the terminal back, if necessary. */
+
+static void
+uculog_end ()
+{
+ if (fCulog_restore)
+ {
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ }
+}
+
+/* Check to see if this port has the desired line, to handle the -l
+ option. If it does, or if no line was specified, set up a
+ connection and lock it. */
+
+static int
+icuport_lock (qport, pinfo)
+ struct uuconf_port *qport;
+ pointer pinfo;
+{
+ struct sconninfo *q = (struct sconninfo *) pinfo;
+
+ if (q->zline != NULL
+ && ! fsysdep_port_is_line (qport, q->zline))
+ return UUCONF_NOT_FOUND;
+
+ q->fmatched = TRUE;
+
+ if (! fconn_init (qport, q->qconn))
+ return UUCONF_NOT_FOUND;
+ else if (! fconn_lock (q->qconn, FALSE))
+ {
+ uconn_free (q->qconn);
+ return UUCONF_NOT_FOUND;
+ }
+ else
+ {
+ qCuconn = q->qconn;
+ q->flocked = TRUE;
+ return UUCONF_SUCCESS;
+ }
+}
+
+/* Execute a cu escape command. Return TRUE if the connection should
+ continue, or FALSE if the connection should be terminated. */
+
+static boolean
+fcudo_cmd (puuconf, qconn, bcmd)
+ pointer puuconf;
+ struct sconnection *qconn;
+ int bcmd;
+{
+ char *zline;
+ char *z;
+ char abescape[5];
+ boolean fret;
+ size_t clen;
+ char abbuf[100];
+
+ /* Some commands take a string up to the next newline character. */
+ switch (bcmd)
+ {
+ default:
+ zline = NULL;
+ break;
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ case '%':
+ case 'c':
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ case 's':
+ {
+ zline = zsysdep_terminal_line ((const char *) NULL);
+ if (zline == NULL)
+ ucuabort ();
+ zline[strcspn (zline, "\n")] = '\0';
+ }
+ break;
+ }
+
+ switch (bcmd)
+ {
+ default:
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]",
+ abescape, abescape, abescape);
+ ucuputs (abbuf);
+ return TRUE;
+
+ case '.':
+ /* Hangup. */
+ return FALSE;
+
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ /* Shell out. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ {
+ enum tshell_cmd t;
+
+ switch (bcmd)
+ {
+ default:
+ case '!': t = SHELL_NORMAL; break;
+ case '$': t = SHELL_STDOUT_TO_PORT; break;
+ case '|': t = SHELL_STDIN_FROM_PORT; break;
+ case '+': t = SHELL_STDIO_ON_PORT; break;
+ }
+
+ (void) fsysdep_shell (qconn, zline, t);
+ }
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ ubuffree (zline);
+ return TRUE;
+
+ case '%':
+ fret = fcudo_subcmd (puuconf, qconn, zline);
+ ubuffree (zline);
+ return fret;
+
+ case '#':
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return TRUE;
+
+ case 'c':
+ (void) fsysdep_chdir (zline);
+ ubuffree (zline);
+ return TRUE;
+
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ clen = strlen (zline);
+ z = zbufalc (clen + 3);
+ z[0] = bcmd;
+ z[1] = ' ';
+ memcpy (z + 2, zline, clen + 1);
+ ubuffree (zline);
+ fret = fcudo_subcmd (puuconf, qconn, z);
+ ubuffree (z);
+ return fret;
+
+ case 'z':
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_suspend ())
+ ucuabort ();
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ return TRUE;
+
+ case 's':
+ fret = fcuset_var (puuconf, zline);
+ ubuffree (zline);
+ return fret;
+
+ case 'v':
+ uculist_vars ();
+ return TRUE;
+
+ case '?':
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ucuputs ("");
+ ucuputs ("[Escape sequences]");
+ sprintf (abbuf,
+ "[%s. hangup] [%s!CMD run shell]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s$CMD stdout to remote] [%s|CMD stdin from remote]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s+CMD stdin and stdout to remote]",
+ abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s# send break] [%scDIR change directory]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s> send file] [%s< receive file]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ssVAR VAL set variable] [%ssVAR set boolean]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ss!VAR unset boolean] [%sv list variables]",
+ abescape, abescape);
+ ucuputs (abbuf);
+#ifdef SIGTSTP
+ sprintf (abbuf,
+ "[%sz suspend]",
+ abescape);
+ ucuputs (abbuf);
+#endif
+ uculist_fns (abescape);
+ return TRUE;
+ }
+}
+
+/* List ~% functions. */
+
+static void
+uculist_fns (zescape)
+ const char *zescape;
+{
+ char abbuf[100];
+
+ sprintf (abbuf,
+ "[%s%%break send break] [%s%%cd DIR change directory]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]",
+ zescape, zescape);
+ ucuputs (abbuf);
+}
+
+/* Set a variable. */
+
+static boolean
+fcuset_var (puuconf, zline)
+ pointer puuconf;
+ char *zline;
+{
+ char *zvar, *zval;
+ char *azargs[2];
+ char azbool[2];
+ int iuuconf;
+
+ zvar = strtok (zline, "= \t");
+ if (zvar == NULL)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ zval = strtok ((char *) NULL, " \t");
+
+ if (zval == NULL)
+ {
+ azargs[0] = zvar;
+ if (azargs[0][0] != '!')
+ azbool[0] = 't';
+ else
+ {
+ ++azargs[0];
+ azbool[0] = 'f';
+ }
+ azbool[1] = '\0';
+ azargs[1] = azbool;
+ }
+ else
+ {
+ azargs[0] = zvar;
+ azargs[1] = zval;
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars,
+ (pointer) NULL, icuunrecogvar, 0,
+ (pointer) NULL);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown variable. */
+
+/*ARGSUSED*/
+static int
+icuunrecogvar (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* List all the variables with their values. */
+
+static void
+uculist_vars ()
+{
+ const struct uuconf_cmdtab *q;
+ char abbuf[100];
+
+ ucuputs ("");
+ for (q = asCuvars; q->uuconf_zcmd != NULL; q++)
+ {
+ switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype))
+ {
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN):
+ if (*(boolean *) q->uuconf_pvar)
+ sprintf (abbuf, "%s true", q->uuconf_zcmd);
+ else
+ sprintf (abbuf, "%s false", q->uuconf_zcmd);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT):
+ sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG):
+ sprintf (abbuf, "%s %ld", q->uuconf_zcmd,
+ *(long *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING):
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING):
+ {
+ const char *z;
+ char abchar[5];
+ size_t clen;
+
+ sprintf (abbuf, "%s ", q->uuconf_zcmd);
+ clen = strlen (abbuf);
+ for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++)
+ {
+ int cchar;
+
+ if (! isprint (*z))
+ {
+ sprintf (abchar, "\\%03o", (unsigned int) *z);
+ cchar = 4;
+ }
+ else
+ {
+ abchar[0] = *z;
+ abchar[1] = '\0';
+ cchar = 1;
+ }
+ if (clen + cchar < sizeof (abbuf))
+ strcat (abbuf, abchar);
+ clen += cchar;
+ }
+ }
+ break;
+
+ default:
+ sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd);
+ break;
+ }
+
+ ucuputs (abbuf);
+ }
+}
+
+/* Subcommands. These are commands that begin with ~%. */
+
+/* This variable is only used so that we can pass a non-NULL address
+ in pvar. It is never assigned to or examined. */
+
+static char bCutype;
+
+/* The command table for the subcommands. */
+
+static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+
+static const struct uuconf_cmdtab asCucmds[] =
+{
+ { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir },
+ { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug },
+ { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop },
+ { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop },
+ { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput },
+ { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake },
+ { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { NULL, 0, NULL, NULL }
+};
+
+/* Do a subcommand. This is called by commands beginning with ~%. */
+
+static boolean
+fcudo_subcmd (puuconf, qconn, zline)
+ pointer puuconf;
+ struct sconnection *qconn;
+ char *zline;
+{
+ char *azargs[3];
+ int iarg;
+ int iuuconf;
+
+ for (iarg = 0; iarg < 3; iarg++)
+ {
+ azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n");
+ if (azargs[iarg] == NULL)
+ break;
+ }
+
+ if (iarg == 0)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds,
+ (pointer) qconn, icuunrecogfn,
+ 0, (pointer) NULL);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown function. */
+
+/*ARGSUSED*/
+static int
+icuunrecogfn (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ if (argv[0][0] == '?')
+ uculist_fns (abescape);
+ else
+ ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a break. */
+
+/*ARGSUSED*/
+static int
+icubreak (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Change directories. */
+
+/*ARGSUSED*/
+static int
+icuchdir (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ const char *zarg;
+
+ if (argc <= 1)
+ zarg = NULL;
+ else
+ zarg = argv[1];
+ (void) fsysdep_chdir (zarg);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Toggle debugging. */
+
+/*ARGSUSED*/
+static int
+icudebug (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+#if DEBUG > 1
+ if (iDebug != 0)
+ iDebug = 0;
+ else
+ iDebug = DEBUG_MAX;
+#else
+ ucuputs ("[compiled without debugging]");
+#endif
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Control whether the port does xon/xoff handshaking. If pvar is not
+ NULL, this is "stop"; otherwise it is "nostop". */
+
+/*ARGSUSED*/
+static int
+icunostop (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT,
+ pvar == NULL ? XONXOFF_OFF : XONXOFF_ON))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a file to the remote system. The first argument is the file
+ to send. If that argument is not present, it is prompted for. The
+ second argument is to file name to use on the remote system. If
+ that argument is not present, the basename of the local filename is
+ used. If pvar is not NULL, then this is ~>, which is used to send
+ a command to a non-Unix system. We treat is the same as ~%put,
+ except that we assume the user has already entered the appropriate
+ command (for ~%put, we force ``cat >to'' to the other side). */
+
+/*ARGSUSED*/
+static int
+icuput (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ char *zfrom;
+ char *zto = NULL;
+ char *zalc;
+ openfile_t e;
+ int cline;
+ char *zbuf;
+ size_t cbuf;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("File to send: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (pvar == NULL)
+ {
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Remote file name []: " +
+ strlen (zbase));
+ sprintf (zprompt, "Remote file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+ }
+
+ e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ if (pvar == NULL)
+ ubuffree (zto);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s", zfrom, zerrstr);
+ ubuffree (zfrom);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ ubuffree (zfrom);
+
+ /* Tell the system dependent layer to stop copying data from the
+ port to the terminal. We want to read the echoes ourself. Also
+ permit the local user to generate signals. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ /* If pvar is NULL, then we are sending a file to a Unix system. We
+ send over the command "cat > TO" to prepare it to receive. If
+ pvar is not NULL, the user is assumed to have set up whatever
+ action was needed to receive the file. */
+ if (pvar == NULL)
+ {
+ boolean fret;
+
+ zalc = zbufalc (sizeof "cat > \n" + strlen (zto));
+ sprintf (zalc, "cat > %s\n", zto);
+ ubuffree (zto);
+ fret = fcusend_buf (qconn, zalc, strlen (zalc));
+ ubuffree (zalc);
+ if (! fret)
+ {
+ (void) ffileclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ cline = 0;
+
+ zbuf = NULL;
+ cbuf = 0;
+
+ while (TRUE)
+ {
+ char abbuf[512];
+ size_t c;
+
+#if USE_STDIO
+ if (fCuvar_binary)
+#endif
+ {
+ if (ffileeof (e))
+ break;
+ c = cfileread (e, abbuf, sizeof abbuf);
+ if (ffilereaderror (e, c))
+ {
+ ucuputs ("[file read error]");
+ break;
+ }
+ if (c == 0)
+ break;
+ zbuf = abbuf;
+ }
+#if USE_STDIO
+ else
+ {
+ if (getline (&zbuf, &cbuf, e) <= 0)
+ {
+ xfree ((pointer) zbuf);
+ break;
+ }
+ c = strlen (zbuf);
+ }
+#endif
+
+ if (fCuvar_verbose)
+ {
+ ++cline;
+ printf ("%d ", cline);
+ (void) fflush (stdout);
+ }
+
+ if (! fcusend_buf (qconn, zbuf, c))
+ {
+ if (! fCuvar_binary)
+ xfree ((pointer) zbuf);
+ (void) fclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ (void) ffileclose (e);
+
+ if (pvar == NULL)
+ {
+ char beof;
+
+ beof = '\004';
+ if (! fconn_write (qconn, &beof, 1))
+ ucuabort ();
+ }
+ else
+ {
+ if (*zCuvar_eofwrite != '\0')
+ {
+ if (! fconn_write (qconn, zCuvar_eofwrite,
+ strlen (zCuvar_eofwrite)))
+ ucuabort ();
+ }
+ }
+
+ if (fCuvar_verbose)
+ ucuputs ("");
+
+ ucuputs ("[file transfer complete]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Get a file from the remote side. This is ~%take, or ~t, or ~<.
+ The first two are assumed to be taking the file from a Unix system,
+ so we force the command "cat FROM; echo */
+
+/*ARGSUSED*/
+static int
+icutake (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ const char *zeof;
+ char *zfrom, *zto, *zcmd;
+ char *zalc;
+ openfile_t e;
+ char bcr;
+ size_t ceoflen;
+ char *zlook = NULL;
+ size_t ceofhave;
+ boolean ferr;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("Remote file to retreive: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase));
+ sprintf (zprompt, "Local file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+
+ if (pvar != NULL)
+ {
+ zcmd = zsysdep_terminal_line ("Remote command to execute: ");
+ if (zcmd == NULL)
+ ucuabort ();
+ zcmd[strcspn (zcmd, "\n")] = '\0';
+ zeof = zCuvar_eofread;
+ }
+ else
+ {
+ zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////"
+ + strlen (zfrom));
+ sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom);
+ zeof = "\n////cuend////\n";
+ }
+
+ ubuffree (zfrom);
+
+ e = esysdep_user_fopen (zto, FALSE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ ubuffree (zcmd);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s\n", zto, zerrstr);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ ubuffree (zto);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ ubuffree (zto);
+
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ if (! fconn_write (qconn, zcmd, strlen (zcmd)))
+ ucuabort ();
+ bcr = '\r';
+ if (! fconn_write (qconn, &bcr, 1))
+ ucuabort ();
+
+ ubuffree (zcmd);
+
+ /* Eliminated any previously echoed data to avoid confusion. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* If we're dealing with a Unix system, we can reliably discard the
+ command. Otherwise, the command will probably wind up in the
+ file; too bad. */
+ if (pvar == NULL)
+ {
+ int b;
+
+ while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n')
+ {
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ ucuputs ("[timed out waiting for newline]");
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+ }
+
+ ceoflen = strlen (zeof);
+ zlook = zbufalc (ceoflen);
+ ceofhave = 0;
+ ferr = FALSE;
+
+ while (TRUE)
+ {
+ int b;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file receive aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ break;
+ }
+
+ b = breceive_char (qconn, cCuvar_timeout, TRUE);
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ if (ceofhave > 0)
+ (void) fwrite (zlook, sizeof (char), ceofhave, e);
+ ucuputs ("[timed out]");
+ break;
+ }
+
+ if (ceoflen == 0)
+ {
+ if (cfilewrite (e, &b, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ zlook[ceofhave] = b;
+ ++ceofhave;
+ if (ceofhave == ceoflen)
+ {
+ size_t cmove;
+ char *zmove;
+
+ if (memcmp (zeof, zlook, ceoflen) == 0)
+ {
+ ucuputs ("[file transfer complete]");
+ break;
+ }
+
+ if (cfilewrite (e, zlook, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+
+ zmove = zlook;
+ for (cmove = ceoflen - 1, zmove = zlook;
+ cmove > 0;
+ cmove--, zmove++)
+ zmove[0] = zmove[1];
+
+ --ceofhave;
+ }
+ }
+ }
+
+ ubuffree (zlook);
+
+ if (! ffileclose (e))
+ ferr = TRUE;
+ if (ferr)
+ ucuputs ("[file write error]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a buffer to the remote system. If fCuvar_binary is FALSE,
+ each buffer passed in will be a single line; in this case we can
+ check the echoed characters and kill the line if they do not match.
+ This returns FALSE if an echo check fails. If a port error
+ occurrs, it calls ucuabort. */
+
+static boolean
+fcusend_buf (qconn, zbufarg, cbufarg)
+ struct sconnection *qconn;
+ const char *zbufarg;
+ size_t cbufarg;
+{
+ const char *zbuf;
+ size_t cbuf;
+ int ctries;
+ size_t cbplen;
+ char *zsendbuf;
+
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ ctries = 0;
+
+ if (fCuvar_binary)
+ cbplen = strlen (zCuvar_binary_prefix);
+ else
+ cbplen = 1;
+ zsendbuf = zbufalc (64 * (cbplen + 1));
+
+ /* Loop while we still have characters to send. The value of cbuf
+ will be reset to cbufarg if an echo failure occurs while sending
+ a line in non-binary mode. */
+ while (cbuf > 0)
+ {
+ int csend;
+ char *zput;
+ const char *zget;
+ boolean fnl;
+ int i;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ /* Discard anything we've read from the port up to now, to avoid
+ confusing the echo checking. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* Send all characters up to a newline before actually sending
+ the newline. This makes it easier to handle the special
+ newline echo checking. Send up to 64 characters at a time
+ before doing echo checking. */
+ if (*zbuf == '\n')
+ csend = 1;
+ else
+ {
+ const char *znl;
+
+ znl = memchr (zbuf, '\n', cbuf);
+ if (znl == NULL)
+ csend = cbuf;
+ else
+ csend = znl - zbuf;
+ if (csend > 64)
+ csend = 64;
+ }
+
+ /* Translate this part of the buffer. If we are not in binary
+ mode, we translate \n to \r, and ignore any nonprintable
+ characters. */
+ zput = zsendbuf;
+ fnl = FALSE;
+ for (i = 0, zget = zbuf; i < csend; i++, zget++)
+ {
+ if (isprint (*zget)
+ || *zget == '\t')
+ *zput++ = *zget;
+ else if (*zget == '\n')
+ {
+ if (fCuvar_binary)
+ *zput++ = '\n';
+ else
+ *zput++ = '\r';
+ fnl = TRUE;
+ }
+ else if (fCuvar_binary)
+ {
+ strcpy (zput, zCuvar_binary_prefix);
+ zput += cbplen;
+ *zput++ = *zget;
+ }
+ }
+
+ zbuf += csend;
+ cbuf -= csend;
+
+ if (zput == zsendbuf)
+ continue;
+
+ /* Send the data over the port. */
+ if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE))
+ ucuabort ();
+
+ /* We do echo checking if requested, unless we are in binary
+ mode. Echo checking of a newline is different from checking
+ of normal characters; when we send a newline we look for
+ *zCuvar_echonl. */
+ if ((fCuvar_echocheck && ! fCuvar_binary)
+ || (fnl && *zCuvar_echonl != '\0'))
+ {
+ long iend;
+
+ iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout;
+ for (zget = zsendbuf; zget < zput; zget++)
+ {
+ int bread;
+ int bwant;
+
+ if (fCuvar_binary ? *zget == '\n' : *zget == '\r')
+ {
+ bwant = *zCuvar_echonl;
+ if (bwant == '\0')
+ continue;
+ }
+ else
+ {
+ if (! fCuvar_echocheck || ! isprint (*zget))
+ continue;
+ bwant = *zget;
+ }
+
+ do
+ {
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not
+ confuse us in the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ bread = breceive_char (qconn,
+ iend - ixsysdep_time ((long *) NULL),
+ TRUE);
+ if (bread < 0)
+ {
+ if (bread == -2)
+ ucuabort ();
+
+ /* If we timed out, and we're not in binary
+ mode, we kill the line and try sending it
+ again from the beginning. */
+ if (! fCuvar_binary && *zCuvar_kill != '\0')
+ {
+ ++ctries;
+ if (ctries < cCuvar_resend)
+ {
+ if (fCuvar_verbose)
+ {
+ printf ("R ");
+ (void) fflush (stdout);
+ }
+ if (! fsend_data (qconn, zCuvar_kill, 1,
+ TRUE))
+ ucuabort ();
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ break;
+ }
+ }
+ ubuffree (zsendbuf);
+ ucuputs ("[timed out looking for echo]");
+ return FALSE;
+ }
+ }
+ while (bread != *zget);
+
+ if (bread < 0)
+ break;
+ }
+ }
+ }
+
+ ubuffree (zsendbuf);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/MANIFEST b/gnu/libexec/uucp/libunix/MANIFEST
new file mode 100644
index 00000000000..d64e7992204
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/MANIFEST
@@ -0,0 +1,76 @@
+Makefile.in
+MANIFEST
+access.c
+addbas.c
+app3.c
+app4.c
+basnam.c
+bytfre.c
+chmod.c
+cohtty.c
+cwd.c
+cusub.c
+detach.c
+dirent.c
+dup2.c
+efopen.c
+epopen.c
+exists.c
+filnam.c
+fsusg.c
+fsusg.h
+ftw.c
+getcwd.c
+indir.c
+init.c
+isdir.c
+isfork.c
+iswait.c
+jobid.c
+lcksys.c
+link.c
+locfil.c
+lock.c
+loctim.c
+mail.c
+mkdir.c
+mkdirs.c
+mode.c
+move.c
+opensr.c
+pause.c
+picksb.c
+portnm.c
+proctm.c
+recep.c
+remove.c
+rename.c
+rmdir.c
+run.c
+seq.c
+serial.c
+signal.c
+sindir.c
+size.c
+sleep.c
+splcmd.c
+splnam.c
+spool.c
+spawn.c
+srmdir.c
+statsb.c
+status.c
+strerr.c
+time.c
+tmpfil.c
+trunc.c
+uacces.c
+ufopen.c
+ultspl.c
+unknwn.c
+uuto.c
+walk.c
+wldcrd.c
+work.c
+xqtfil.c
+xqtsub.c
diff --git a/gnu/libexec/uucp/libunix/Makefile b/gnu/libexec/uucp/libunix/Makefile
new file mode 100644
index 00000000000..a9401e66dc0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/Makefile
@@ -0,0 +1,21 @@
+# This subdirectory contains Unix specific support functions.
+
+LIB= unix
+SRCS= access.c addbas.c app3.c app4.c basnam.c bytfre.c cwd.c \
+ chmod.c cohtty.c cusub.c detach.c efopen.c epopen.c exists.c \
+ filnam.c fsusg.c indir.c init.c isdir.c isfork.c iswait.c \
+ jobid.c lcksys.c link.c locfil.c lock.c loctim.c mail.c \
+ mkdirs.c mode.c move.c opensr.c pause.c picksb.c portnm.c \
+ proctm.c recep.c run.c seq.c serial.c signal.c sindir.c size.c \
+ sleep.c spawn.c splcmd.c splnam.c spool.c srmdir.c statsb.c \
+ status.c time.c tmpfil.c trunc.c uacces.c ufopen.c ultspl.c \
+ unknwn.c uuto.c walk.c wldcrd.c work.c xqtfil.c xqtsub.c ftw.c
+CFLAGS+= -I$(.CURDIR)/../common_sources \
+ -DOWNER=\"$(owner)\" -DSBINDIR=\"$(sbindir)\"
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libunix/access.c b/gnu/libexec/uucp/libunix/access.c
new file mode 100644
index 00000000000..c2c0eef2108
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/access.c
@@ -0,0 +1,83 @@
+/* access.c
+ Check access to files by the user and by the daemon. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See if the user has access to a file, to prevent the setuid uucp
+ and uux programs handing out unauthorized access. */
+
+boolean
+fsysdep_access (zfile)
+ const char *zfile;
+{
+ if (access (zfile, R_OK) == 0)
+ return TRUE;
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (errno));
+ return FALSE;
+}
+
+/* See if the daemon has access to a file. This is called if a file
+ is not being transferred to the spool directory, since if the
+ daemon does not have access the later transfer will fail. We
+ assume that the daemon will have the same euid (or egid) as the one
+ we are running under. If our uid (gid) and euid (egid) are the
+ same, we assume that we have access. Note that is not important
+ for security, since the check will be (implicitly) done again when
+ the daemon tries to transfer the file. This routine should work
+ whether the UUCP programs are installed setuid or setgid. */
+
+boolean
+fsysdep_daemon_access (zfile)
+ const char *zfile;
+{
+ struct stat s;
+ uid_t ieuid, iuid, iegid, igid;
+ boolean fok;
+
+ ieuid = geteuid ();
+ if (ieuid == 0)
+ return TRUE;
+ iuid = getuid ();
+ iegid = getegid ();
+ igid = getgid ();
+
+ /* If our effective uid and gid are the same as our real uid and
+ gid, we assume the daemon will have access to the file. */
+ if (ieuid == iuid && iegid == igid)
+ return TRUE;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+
+ /* If our euid is not our uid, but it is the file's uid, see if the
+ owner has read access. Otherwise, if our egid is not our gid,
+ but it is the file's gid, see if the group has read access.
+ Otherwise, see if the world has read access. We know from the
+ above check that at least one of our euid and egid are different,
+ so that is the only one we want to check. This check could fail
+ if the UUCP programs were both setuid and setgid, but why would
+ they be? */
+ if (ieuid != iuid && ieuid == s.st_uid)
+ fok = (s.st_mode & S_IRUSR) != 0;
+ else if (iegid != igid && iegid == s.st_gid)
+ fok = (s.st_mode & S_IRGRP) != 0;
+ else
+ fok = (s.st_mode & S_IROTH) != 0;
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "%s: cannot be read by daemon", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/addbas.c b/gnu/libexec/uucp/libunix/addbas.c
new file mode 100644
index 00000000000..8597918a3c9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/addbas.c
@@ -0,0 +1,50 @@
+/* addbas.c
+ If we have a directory, add in a base name. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* If we have a directory, add a base name. */
+
+char *
+zsysdep_add_base (zfile, zname)
+ const char *zfile;
+ const char *zname;
+{
+ size_t clen;
+ const char *zlook;
+ char *zfree;
+ char *zret;
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "zsysdep_add_base: %s: Can't happen", zfile);
+#endif
+
+ clen = strlen (zfile);
+
+ if (zfile[clen - 1] != '/')
+ {
+ if (! fsysdep_directory (zfile))
+ return zbufcpy (zfile);
+ zfree = NULL;
+ }
+ else
+ {
+ /* Trim out the trailing '/'. */
+ zfree = zbufcpy (zfile);
+ zfree[clen - 1] = '\0';
+ zfile = zfree;
+ }
+
+ zlook = strrchr (zname, '/');
+ if (zlook != NULL)
+ zname = zlook + 1;
+
+ zret = zsysdep_in_dir (zfile, zname);
+ ubuffree (zfree);
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/app3.c b/gnu/libexec/uucp/libunix/app3.c
new file mode 100644
index 00000000000..5c0b5893851
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/app3.c
@@ -0,0 +1,29 @@
+/* app3.c
+ Stick two directories and a file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+char *
+zsappend3 (zdir1, zdir2, zfile)
+ const char *zdir1;
+ const char *zdir2;
+ const char *zfile;
+{
+ size_t cdir1, cdir2, cfile;
+ char *zret;
+
+ cdir1 = strlen (zdir1);
+ cdir2 = strlen (zdir2);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir1 + cdir2 + cfile + 3);
+ memcpy (zret, zdir1, cdir1);
+ memcpy (zret + cdir1 + 1, zdir2, cdir2);
+ memcpy (zret + cdir1 + cdir2 + 2, zfile, cfile);
+ zret[cdir1] = '/';
+ zret[cdir1 + cdir2 + 1] = '/';
+ zret[cdir1 + cdir2 + cfile + 2] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/app4.c b/gnu/libexec/uucp/libunix/app4.c
new file mode 100644
index 00000000000..a3b3787f68f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/app4.c
@@ -0,0 +1,33 @@
+/* app4.c
+ Stick three directories and a file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+char *
+zsappend4 (zdir1, zdir2, zdir3, zfile)
+ const char *zdir1;
+ const char *zdir2;
+ const char *zdir3;
+ const char *zfile;
+{
+ size_t cdir1, cdir2, cdir3, cfile;
+ char *zret;
+
+ cdir1 = strlen (zdir1);
+ cdir2 = strlen (zdir2);
+ cdir3 = strlen (zdir3);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir1 + cdir2 + cdir3 + cfile + 4);
+ memcpy (zret, zdir1, cdir1);
+ memcpy (zret + cdir1 + 1, zdir2, cdir2);
+ memcpy (zret + cdir1 + cdir2 + 2, zdir3, cdir3);
+ memcpy (zret + cdir1 + cdir2 + cdir3 + 3, zfile, cfile);
+ zret[cdir1] = '/';
+ zret[cdir1 + cdir2 + 1] = '/';
+ zret[cdir1 + cdir2 + cdir3 + 2] = '/';
+ zret[cdir1 + cdir2 + cdir3 + cfile + 3] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/basnam.c b/gnu/libexec/uucp/libunix/basnam.c
new file mode 100644
index 00000000000..c61fcaa8de6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/basnam.c
@@ -0,0 +1,22 @@
+/* basnam.c
+ Get the base name of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Get the base name of a file name. */
+
+char *
+zsysdep_base_name (zfile)
+ const char *zfile;
+{
+ const char *z;
+
+ z = strrchr (zfile, '/');
+ if (z != NULL)
+ return zbufcpy (z + 1);
+ return zbufcpy (zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/bytfre.c b/gnu/libexec/uucp/libunix/bytfre.c
new file mode 100644
index 00000000000..568eebe0307
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/bytfre.c
@@ -0,0 +1,19 @@
+/* bytfre.c
+ Get the number of bytes free on a file system. */
+
+#include "uucp.h"
+
+#include "system.h"
+#include "sysdep.h"
+#include "fsusg.h"
+
+long
+csysdep_bytes_free (zfile)
+ const char *zfile;
+{
+ struct fs_usage s;
+
+ if (get_fs_usage ((char *) zfile, (char *) NULL, &s) < 0)
+ return -1;
+ return s.fsu_bavail * (long) 512;
+}
diff --git a/gnu/libexec/uucp/libunix/chmod.c b/gnu/libexec/uucp/libunix/chmod.c
new file mode 100644
index 00000000000..cf69f3eb014
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/chmod.c
@@ -0,0 +1,25 @@
+/* chmod.c
+ Change the mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Change the mode of a file. */
+
+boolean
+fsysdep_change_mode (zfile, imode)
+ const char *zfile;
+ unsigned int imode;
+{
+ if (chmod ((char *) zfile, imode) < 0)
+ {
+ ulog (LOG_ERROR, "chmod (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/cohtty.c b/gnu/libexec/uucp/libunix/cohtty.c
new file mode 100644
index 00000000000..a7aec1cae33
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cohtty.c
@@ -0,0 +1,244 @@
+/* Coherent tty locking support. This file was contributed by Bob
+ Hemedinger <bob@dalek.mwc.com> of Mark Williams Corporation and
+ lightly edited by Ian Lance Taylor. */
+
+/* The bottom part of this file is lock.c.
+ * This is a hacked lock.c. A full lock.c can be found in the libmisc sources
+ * under /usr/src/misc.tar.Z.
+ *
+ * These are for checking for the existence of locks:
+ * lockexist(resource)
+ * lockttyexist(ttyname)
+ */
+
+#include "uucp.h"
+
+#if HAVE_COHERENT_LOCKFILES
+
+/* cohtty.c: Given a serial device name, read /etc/ttys and determine if
+ * the device is already enabled. If it is, disable the
+ * device and return a string so that it can be re-enabled
+ * at the completion of the uucico session as part of the
+ * function that resets the serial device before uucico
+ * terminates.
+ *
+ */
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <access.h>
+
+/* fscoherent_disable_tty() is a COHERENT specific function. It takes the name
+ * of a serial device and then scans /etc/ttys for a match. If it finds one,
+ * it checks the first field of the entry. If it is a '1', then it will disable
+ * the port and set a flag. The flag will be checked later when uucico wants to
+ * reset the serial device to see if the device needs to be re-enabled.
+ */
+
+boolean
+fscoherent_disable_tty (zdevice, pzenable)
+ const char *zdevice;
+ char **pzenable;
+{
+
+
+struct ttyentry{ /* this is an /etc/ttys entry */
+ char enable_disable[1];
+ char remote_local[1];
+ char baud_rate[1];
+ char tty_device[16];
+};
+
+struct ttyentry sought_tty;
+
+int x,y,z; /* dummy */
+FILE * infp; /* this will point to /etc/ttys */
+char disable_command[66]; /* this will be the disable command
+ * passed to the system.
+ */
+char enable_device[16]; /* this will hold our device name
+ * to enable.
+ */
+
+ *pzenable = NULL;
+
+ strcpy(enable_device,""); /* initialize our strings */
+ strcpy(sought_tty.tty_device,"");
+
+ if( (infp = fopen("/etc/ttys","r")) == NULL){
+ ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n");
+ return FALSE;
+ }
+
+ while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){
+ sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0';
+ strcpy(enable_device,sought_tty.tty_device);
+
+ /* we must strip away the suffix to the com port name or
+ * we will never find a match. For example, if we are passed
+ * /dev/com4l to call out with and the port is already enabled,
+ * 9/10 the port enabled will be com4r. After we strip away the
+ * suffix of the port found in /etc/ttys, then we can test
+ * if the base port name appears in the device name string
+ * passed to us.
+ */
+
+ for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){
+ if(isdigit(sought_tty.tty_device[z])){
+ break;
+ }
+ }
+ y = strlen(sought_tty.tty_device);
+ for(x = z+1 ; x <= y; x++){
+ sought_tty.tty_device[x] = '\0';
+ }
+
+
+/* ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */
+ if(strstr(zdevice, sought_tty.tty_device)){
+ if(sought_tty.enable_disable[0] == '1'){
+ ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n",
+ zdevice, sought_tty.tty_device);
+ sprintf(disable_command, "/etc/disable %s",enable_device);
+ {
+ pid_t ipid;
+ const char *azargs[3];
+ int aidescs[3];
+
+ azargs[0] = "/etc/disable";
+ azargs[1] = enable_device;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+ ipid = ixsspawn (azargs, aidescs, TRUE,
+ FALSE,
+ (const char *) NULL, TRUE,
+ TRUE,
+ (const char *) NULL,
+ (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ x = 1;
+ else
+ x = ixswait ((unsigned long) ipid,
+ (const char *) NULL);
+ }
+ *pzenable = zbufalc (sizeof "/dev/"
+ + strlen (enable_device));
+ sprintf(*pzenable,"/dev/%s", enable_device);
+/* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */
+ return(x==0? TRUE : FALSE); /* disable either failed
+ or succeded */
+ }else{
+ return FALSE; /* device in tty entry not enabled */
+ }
+ }
+ }
+ return FALSE; /* no ttys entry found */
+}
+
+/* The following is COHERENT 4.0 specific. It is used to test for any
+ * existing lockfiles on a port which would have been created by init
+ * when a user logs into a port.
+ */
+
+#define LOCKSIG 9 /* Significant Chars of Lockable Resources. */
+#define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */
+
+#define LOCKPRE "LCK.."
+#define PIDLEN 6 /* Maximum length of string representing a pid. */
+
+#ifndef LOCKDIR
+#define LOCKDIR SPOOLDIR
+#endif
+
+/* There is a special version of DEVMASK for the PE multiport driver
+ * because of the peculiar way it uses the minor device number. For
+ * all other drivers, the lower 5 bits describe the physical port--
+ * the upper 3 bits give attributes for the port.
+ */
+
+#define PE_DRIVER 21 /* Major device number for the PE driver. */
+#define PE_DEVMASK 0x3f /* PE driver minor device mask. */
+#define DEVMASK 0x1f /* Minor device mask. */
+
+/*
+ * Generates a resource name for locking, based on the major number
+ * and the lower 4 bits of the minor number of the tty device.
+ *
+ * Builds the name in buff as two "." separated decimal numbers.
+ * Returns NULL on failure, buff on success.
+ */
+static char *
+gen_res_name(path, buff)
+char *path;
+char *buff;
+{
+ struct stat sbuf;
+ int status;
+
+ if (0 != (status = stat(path, &sbuf))) {
+ /* Can't stat the file. */
+ return (NULL);
+ }
+
+ if (PE_DRIVER == major(sbuf.st_rdev)) {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ PE_DEVMASK & minor(sbuf.st_rdev));
+ } else {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ DEVMASK & minor(sbuf.st_rdev));
+ }
+
+ return(buff);
+} /* gen_res_name */
+
+/*
+ * lockexist(resource) char *resource;
+ *
+ * Test for existance of a lock on the given resource.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+
+static boolean
+lockexist(resource)
+const char *resource;
+{
+ char lockfn[LOKFLEN];
+
+ if ( resource == NULL )
+ return(0);
+ sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
+
+ return (!access(lockfn, AEXISTS));
+} /* lockexist() */
+
+/*
+ * lockttyexist(ttyname) char *ttyname;
+ *
+ * Test for existance of a lock on the given tty.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+boolean
+lockttyexist(ttyn)
+const char *ttyn;
+{
+ char resource[LOKFLEN];
+ char filename[LOKFLEN];
+
+ sprintf(filename, "/dev/%s", ttyn);
+ if (NULL == gen_res_name(filename, resource)){
+ return(0); /* Non-existent tty can not be locked :-) */
+ }
+
+ return(lockexist(resource));
+} /* lockttyexist() */
+
+#endif /* HAVE_COHERENT_LOCKFILES */
diff --git a/gnu/libexec/uucp/libunix/cusub.c b/gnu/libexec/uucp/libunix/cusub.c
new file mode 100644
index 00000000000..4cee888d716
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cusub.c
@@ -0,0 +1,1163 @@
+/* cusub.c
+ System dependent routines for cu.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/04 19:32:09 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+#include "cu.h"
+#include "conn.h"
+#include "prot.h"
+
+#include <errno.h>
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Local variables. */
+
+/* The EOF character, as set by fsysdep_terminal_raw. */
+static char bSeof;
+
+/* The SUSP character, as set by fsysdep_terminal_raw. */
+static char bStstp;
+
+/* Local functions. */
+
+static const char *zsport_line P((const struct uuconf_port *qport));
+static void uscu_child P((struct sconnection *qconn, int opipe));
+static RETSIGTYPE uscu_alarm P((int isig));
+static int cscu_escape P((char *pbcmd, const char *zlocalname));
+static RETSIGTYPE uscu_alarm_kill P((int isig));
+
+/* Return the device name for a port, or NULL if none. */
+
+static const char *
+zsport_line (qport)
+ const struct uuconf_port *qport;
+{
+ const char *zline;
+
+ if (qport == NULL)
+ return NULL;
+
+ switch (qport->uuconf_ttype)
+ {
+ default:
+ case UUCONF_PORTTYPE_STDIN:
+ return NULL;
+ case UUCONF_PORTTYPE_MODEM:
+ zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_DIRECT:
+ zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ return NULL;
+ }
+
+ if (zline == NULL)
+ zline = qport->uuconf_zname;
+ return zline;
+}
+
+/* Check whether the user has legitimate access to a port. */
+
+boolean
+fsysdep_port_access (qport)
+ struct uuconf_port *qport;
+{
+ const char *zline;
+ char *zfree;
+ boolean fret;
+
+ zline = zsport_line (qport);
+ if (zline == NULL)
+ return TRUE;
+
+ zfree = NULL;
+ if (*zline != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree, "/dev/%s", zline);
+ zline = zfree;
+ }
+
+ fret = access (zline, R_OK | W_OK) == 0;
+ ubuffree (zfree);
+ return fret;
+}
+
+/* Return whether the given port is named by the given line. */
+
+boolean
+fsysdep_port_is_line (qport, zline)
+ struct uuconf_port *qport;
+ const char *zline;
+{
+ const char *zpline;
+ char *zfree1, *zfree2;
+ boolean fret;
+
+ zpline = zsport_line (qport);
+ if (zpline == NULL)
+ return FALSE;
+
+ if (strcmp (zline, zpline) == 0)
+ return TRUE;
+
+ zfree1 = NULL;
+ zfree2 = NULL;
+ if (*zline != '/')
+ {
+ zfree1 = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree1, "/dev/%s", zline);
+ zline = zfree1;
+ }
+ if (*zpline != '/')
+ {
+ zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline));
+ sprintf (zfree2, "/dev/%s", zpline);
+ zpline = zfree2;
+ }
+
+ fret = strcmp (zline, zpline) == 0;
+ ubuffree (zfree1);
+ ubuffree (zfree2);
+ return fret;
+}
+
+/* The cu program wants the system dependent layer to handle the
+ details of copying data from the communications port to the
+ terminal. This copying need only be done while executing
+ fsysdep_cu. On Unix, however, we set up a subprocess to do it all
+ the time. This subprocess must be controllable via the
+ fsysdep_cu_copy function.
+
+ We keep a pipe open to the subprocess. When we want it to stop we
+ send it a signal, and then wait for it to write a byte to us over
+ the pipe. */
+
+/* The subprocess pid. */
+static volatile pid_t iSchild;
+
+/* The pipe from the subprocess. */
+static int oSpipe;
+
+/* When we tell the child to stop, it sends this. */
+#define CHILD_STOPPED ('S')
+
+/* When we tell the child to start, it sends this. */
+#define CHILD_STARTED ('G')
+
+/* Initialize the subprocess, and have it start copying data. */
+
+boolean
+fsysdep_cu_init (qconn)
+ struct sconnection *qconn;
+{
+ int ai[2];
+
+ /* Write out anything we may have buffered up during the chat
+ script. We do this before forking the child only to make it easy
+ to move the child into a separate executable. */
+ while (iPrecend != iPrecstart)
+ {
+ char *z;
+ int c;
+
+ z = abPrecbuf + iPrecstart;
+ if (iPrecend > iPrecstart)
+ c = iPrecend - iPrecstart;
+ else
+ c = CRECBUFLEN - iPrecstart;
+
+ iPrecstart = (iPrecstart + c) % CRECBUFLEN;
+
+ while (c > 0)
+ {
+ int cwrote;
+
+ cwrote = write (1, z, c);
+ if (cwrote <= 0)
+ {
+ if (cwrote < 0)
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ c -= cwrote;
+ z += cwrote;
+ }
+ }
+
+ if (pipe (ai) < 0)
+ {
+ ulog (LOG_ERROR, "pipe: %s", strerror (errno));
+ return FALSE;
+ }
+
+ iSchild = ixsfork ();
+ if (iSchild < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (iSchild == 0)
+ {
+ (void) close (ai[0]);
+ uscu_child (qconn, ai[1]);
+ /*NOTREACHED*/
+ }
+
+ (void) close (ai[1]);
+
+ oSpipe = ai[0];
+
+ return TRUE;
+}
+
+/* Copy all data from the terminal to the communications port. If we
+ see an escape character following a newline character, read the
+ next character and return it. */
+
+boolean
+fsysdep_cu (qconn, pbcmd, zlocalname)
+ struct sconnection *qconn;
+ char *pbcmd;
+ const char *zlocalname;
+{
+ boolean fstart;
+ char b;
+ int c;
+
+ fstart = TRUE;
+
+ while (TRUE)
+ {
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+ else
+ {
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ c = read (0, &b, 1);
+
+ usysdep_end_catch ();
+
+ if (c <= 0)
+ break;
+
+ if (fstart && b == *zCuvar_escape)
+ {
+ c = cscu_escape (pbcmd, zlocalname);
+ if (c <= 0)
+ break;
+ if (*pbcmd != b)
+ {
+ write (1, pbcmd, 1);
+
+ /* For Unix, we let the eof character be the same as
+ '.', and we let the suspend character (if any) be the
+ same as 'z'. */
+ if (*pbcmd == bSeof)
+ *pbcmd = '.';
+ if (*pbcmd == bStstp)
+ *pbcmd = 'z';
+ return TRUE;
+ }
+ }
+ if (! fconn_write (qconn, &b, (size_t) 1))
+ return FALSE;
+ fstart = strchr (zCuvar_eol, b) != NULL;
+ }
+
+ if (c < 0)
+ {
+ if (errno != EINTR)
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* I'm not sure what's best in this case. */
+ ulog (LOG_ERROR, "End of file on terminal");
+ return FALSE;
+}
+
+/* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */
+
+volatile sig_atomic_t fScu_alarm;
+
+static RETSIGTYPE
+uscu_alarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm);
+#endif
+
+ fScu_alarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif
+}
+
+/* We've just seen an escape character. We print the host name,
+ optionally after a 1 second delay. We read the next character from
+ the terminal and return it. The 1 second delay on the host name is
+ mostly to be fancy; it lets ~~ look smoother. */
+
+static int
+cscu_escape (pbcmd, zlocalname)
+ char *pbcmd;
+ const char *zlocalname;
+{
+ CATCH_PROTECT int c;
+
+ write (1, zCuvar_escape, 1);
+
+ fScu_alarm = FALSE;
+ usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL);
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ alarm (1);
+ }
+
+ c = 0;
+
+ while (TRUE)
+ {
+ if (fScu_alarm)
+ {
+ char b;
+
+ fScu_alarm = FALSE;
+ b = '[';
+ write (1, &b, 1);
+ write (1, zlocalname, strlen (zlocalname));
+ b = ']';
+ write (1, &b, 1);
+ }
+
+ if (c <= 0)
+ c = read (0, pbcmd, 1);
+ if (c >= 0 || errno != EINTR)
+ {
+ usysdep_end_catch ();
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ return c;
+ }
+ }
+}
+
+/* A SIGALRM handler which does nothing but send a signal to the child
+ process and schedule another alarm. POSIX.1 permits kill and alarm
+ from a signal handler. The reference to static data may or may not
+ be permissible. */
+
+static volatile sig_atomic_t iSsend_sig;
+
+static RETSIGTYPE
+uscu_alarm_kill (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm_kill);
+#endif
+
+ (void) kill (iSchild, iSsend_sig);
+
+ alarm (1);
+}
+
+/* Start or stop copying data from the communications port to the
+ terminal. We send a signal to the child process to tell it what to
+ do. Unfortunately, there are race conditions in the child, so we
+ keep sending it a signal once a second until it responds. We send
+ SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */
+
+boolean
+fsysdep_cu_copy (fcopy)
+ boolean fcopy;
+{
+ int ierr;
+ int c;
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ if (fcopy)
+ iSsend_sig = SIGUSR1;
+ else
+ iSsend_sig = SIGUSR2;
+
+ uscu_alarm_kill (SIGALRM);
+
+ alarm (1);
+
+ while (TRUE)
+ {
+ char b;
+
+ c = read (oSpipe, &b, 1);
+
+#if DEBUG > 1
+ if (c > 0)
+ DEBUG_MESSAGE1 (DEBUG_INCOMING,
+ "fsysdep_cu_copy: Got '%d'", b);
+#endif
+
+ if ((c < 0 && errno != EINTR)
+ || c == 0
+ || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED)))
+ break;
+
+ /* If none of the above conditions were true, then we either got
+ an EINTR error, in which case we probably timed out and the
+ SIGALRM handler resent the signal, or we read the wrong
+ character, in which case we will just read again from the
+ pipe. */
+ }
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ if (c > 0)
+ return TRUE;
+
+ if (c == 0)
+ ulog (LOG_ERROR, "EOF on child pipe");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+
+ return FALSE;
+}
+
+/* Shut down cu by killing the child process. */
+
+boolean
+fsysdep_cu_finish ()
+{
+ (void) close (oSpipe);
+
+ /* We hit the child with SIGTERM, give it two seconds to die, and
+ then send a SIGKILL. */
+ if (kill (iSchild, SIGTERM) < 0)
+ {
+ /* Don't give an error if the child has already died. */
+ if (errno != ESRCH)
+ ulog (LOG_ERROR, "kill: %s", strerror (errno));
+ }
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ iSsend_sig = SIGKILL;
+ alarm (2);
+
+ (void) ixswait ((unsigned long) iSchild, "child");
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ return TRUE;
+}
+
+/* Code for the child process. */
+
+/* This signal handler just records the signal. In this case we only
+ care about which signal we received most recently. */
+
+static volatile sig_atomic_t iSchild_sig;
+
+static RETSIGTYPE
+uscu_child_handler (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_child_handler);
+#endif
+
+ iSchild_sig = isig;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* The child process. This copies the port to the terminal, except
+ when it is stopped by a signal. It would be reasonable to write a
+ separate program for this, probably passing it the port on stdin.
+ This would reduce the memory requirements, since we wouldn't need a
+ second process holding all the configuration stuff, and also let it
+ work reasonably on 680x0 versions of MINIX. */
+
+static void
+uscu_child (qconn, opipe)
+ struct sconnection *qconn;
+ int opipe;
+{
+ CATCH_PROTECT int oport;
+ CATCH_PROTECT boolean fstopped, fgot;
+ CATCH_PROTECT int cwrite;
+ CATCH_PROTECT char abbuf[1024];
+
+ /* It would be nice if we could just use fsserial_read, but that
+ will log signals that we don't want logged. There should be a
+ generic way to extract the file descriptor from the port. */
+ if (qconn->qport == NULL)
+ oport = 0;
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+#if DEBUG > 0
+ default:
+ ulog (LOG_FATAL, "uscu_child: Can't happen");
+ oport = -1;
+ break;
+#endif
+ case UUCONF_PORTTYPE_STDIN:
+ oport = 0;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oport = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL);
+ usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL);
+
+ fstopped = FALSE;
+ fgot = FALSE;
+ iSchild_sig = 0;
+ cwrite = 0;
+
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+
+ while (TRUE)
+ {
+ int isig;
+ int c;
+
+ /* There is a race condition here between checking the signal
+ and receiving a new and possibly different one. This is
+ solved by having the parent resend the signal until it gets a
+ response. */
+ isig = iSchild_sig;
+ iSchild_sig = 0;
+ if (isig != 0)
+ {
+ char b;
+
+ if (isig == SIGTERM)
+ exit (EXIT_SUCCESS);
+
+ if (isig == SIGUSR1)
+ {
+ fstopped = FALSE;
+ b = CHILD_STARTED;
+ }
+ else
+ {
+ fstopped = TRUE;
+ b = CHILD_STOPPED;
+ cwrite = 0;
+ }
+
+ c = write (opipe, &b, 1);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (fstopped)
+ pause ();
+ else if (cwrite > 0)
+ {
+ char *zbuf;
+
+ zbuf = abbuf;
+ while (cwrite > 0)
+ {
+ c = write (1, zbuf, cwrite);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN
+ || errno == EWOULDBLOCK
+ || errno == ENODATA))
+ c = 0;
+
+ if (c < 0 && errno == EINTR)
+ break;
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ cwrite -= c;
+ zbuf += c;
+ }
+ }
+ else
+ {
+ /* On some systems apparently read will return 0 until
+ something has been written to the port. We therefore
+ accept a 0 return until after we have managed to read
+ something. Setting errno to 0 apparently avoids a
+ problem on Coherent. */
+ errno = 0;
+ c = read (oport, abbuf, sizeof abbuf);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if ((c == 0 && fgot)
+ || (c < 0 && errno != EINTR))
+ {
+ /* This can be a normal way to exit, depending on just
+ how the connection is dropped. */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_SUCCESS);
+ }
+ if (c > 0)
+ {
+ fgot = TRUE;
+ cwrite = c;
+ }
+ }
+ }
+}
+
+/* Terminal control routines. */
+
+/* Whether file descriptor 0 is attached to a terminal or not. */
+static boolean fSterm;
+
+/* Whether we are doing local echoing. */
+static boolean fSlocalecho;
+
+/* The original state of the terminal. */
+static sterminal sSterm_orig;
+
+/* The new state of the terminal. */
+static sterminal sSterm_new;
+
+#if ! HAVE_BSD_TTY
+#ifdef SIGTSTP
+/* Whether SIGTSTP is being ignored. */
+static boolean fStstp_ignored;
+#endif
+#endif
+
+/* Set the terminal into raw mode. */
+
+boolean
+fsysdep_terminal_raw (flocalecho)
+ boolean flocalecho;
+{
+ fSlocalecho = flocalecho;
+
+ /* This defaults may be overriden below. */
+ bSeof = '\004';
+ bStstp = '\032';
+
+ if (! fgetterminfo (0, &sSterm_orig))
+ {
+ fSterm = FALSE;
+ return TRUE;
+ }
+
+ fSterm = TRUE;
+
+ sSterm_new = sSterm_orig;
+
+#if HAVE_BSD_TTY
+
+ /* We use CBREAK mode rather than RAW mode, because RAW mode turns
+ off all output processing, which we don't want to do. This means
+ that we have to disable the interrupt characters, which we do by
+ setting them to -1. */
+ bSeof = sSterm_orig.stchars.t_eofc;
+
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ sSterm_new.stchars.t_startc = -1;
+ sSterm_new.stchars.t_stopc = -1;
+ sSterm_new.stchars.t_eofc = -1;
+ sSterm_new.stchars.t_brkc = -1;
+
+ bStstp = sSterm_orig.sltchars.t_suspc;
+
+ sSterm_new.sltchars.t_suspc = -1;
+ sSterm_new.sltchars.t_dsuspc = -1;
+ sSterm_new.sltchars.t_rprntc = -1;
+ sSterm_new.sltchars.t_flushc = -1;
+ sSterm_new.sltchars.t_werasc = -1;
+ sSterm_new.sltchars.t_lnextc = -1;
+
+ if (! flocalecho)
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP);
+ sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM);
+ }
+ else
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO);
+ sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM);
+ }
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ bStstp = sSterm_new.c_cc[VSUSP];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~
+ (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Restore the terminal to its original setting. */
+
+boolean
+fsysdep_terminal_restore ()
+{
+ if (! fSterm)
+ return TRUE;
+
+ if (! fsetterminfo (0, &sSterm_orig))
+ {
+ ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Read a line from the terminal. This will be called after
+ fsysdep_terminal_raw has been called. */
+
+char *
+zsysdep_terminal_line (zprompt)
+ const char *zprompt;
+{
+ CATCH_PROTECT size_t cbuf = 0;
+ CATCH_PROTECT char *zbuf = NULL;
+ CATCH_PROTECT size_t cgot = 0;
+
+ if (zprompt != NULL && *zprompt != '\0')
+ (void) write (1, zprompt, strlen (zprompt));
+
+ /* Forgot about any previous SIGINT or SIGQUIT signals we may have
+ received. We don't worry about the race condition here, since we
+ can't get these signals from the terminal at the moment and it's
+ not too likely that somebody else will be sending them to us. */
+ afSignal[INDEXSIG_SIGINT] = 0;
+ afSignal[INDEXSIG_SIGQUIT] = 0;
+
+ if (! fsysdep_terminal_restore ())
+ return NULL;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ cbuf = 0;
+ zbuf = NULL;
+ cgot = 0;
+ }
+
+ while (TRUE)
+ {
+ char b;
+ int c;
+
+ if (afSignal[INDEXSIG_SIGINT]
+ || afSignal[INDEXSIG_SIGQUIT])
+ {
+ usysdep_end_catch ();
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ /* Return an empty string. */
+ cgot = 0;
+ break;
+ }
+
+ /* There's a race here between checking the signals and calling
+ read. It just means that the user will have to hit ^C more
+ than once. */
+
+ c = read (0, &b, 1);
+ if (c < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+ if (c == 0)
+ {
+ /* I'm not quite sure what to do here. */
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "EOF on terminal");
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ cbuf += 64;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = b;
+
+ ++cgot;
+
+ if (b == '\n')
+ {
+ usysdep_end_catch ();
+ break;
+ }
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ ++cbuf;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = '\0';
+
+ if (! fsysdep_terminal_raw (fSlocalecho))
+ return NULL;
+
+ return zbuf;
+}
+
+/* Write a line to the terminal with a trailing newline. */
+
+boolean
+fsysdep_terminal_puts (zline)
+ const char *zline;
+{
+ char *zalc, *zprint;
+ size_t clen;
+
+ if (zline == NULL)
+ {
+ zalc = zbufalc (2);
+ clen = 0;
+ }
+ else
+ {
+ clen = strlen (zline);
+ zalc = zbufalc (clen + 2);
+ memcpy (zalc, zline, clen);
+ }
+
+ if (fSterm)
+ {
+ zalc[clen] = '\r';
+ ++clen;
+ }
+ zalc[clen] = '\n';
+ ++clen;
+
+ zprint = zalc;
+ while (clen > 0)
+ {
+ int c;
+
+ c = write (1, zprint, clen);
+ if (c <= 0)
+ {
+ ubuffree (zalc);
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ clen -= c;
+ zprint += c;
+ }
+
+ ubuffree (zalc);
+
+ return TRUE;
+}
+
+/* Allow or disallow signals from the terminal. */
+
+boolean
+fsysdep_terminal_signals (faccept)
+ boolean faccept;
+{
+#if HAVE_BSD_TTY
+
+ if (faccept)
+ {
+ sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc;
+ sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc;
+ }
+ else
+ {
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ if (faccept)
+ sSterm_new.c_lflag |= ISIG;
+ else
+ sSterm_new.c_lflag &=~ ISIG;
+
+#ifdef SIGTSTP
+ /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This
+ function will be called with faccept TRUE before it is called
+ with faccept FALSE, so fStstp_ignored will be correctly
+ initialized. */
+ if (faccept)
+ usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored);
+ else if (! fStstp_ignored)
+ usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL);
+#endif
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Start up a command, or possibly just a shell. Optionally attach
+ stdin or stdout to the port. We attach directly to the port,
+ rather than copying the data ourselves. */
+
+boolean
+fsysdep_shell (qconn, zcmd, tcmd)
+ struct sconnection *qconn;
+ const char *zcmd;
+ enum tshell_cmd tcmd;
+{
+ const char *azargs[4];
+ int oread, owrite;
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/bin/sh";
+ if (zcmd == NULL || *zcmd == '\0')
+ azargs[1] = NULL;
+ else
+ {
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+ }
+
+ if (qconn->qport == NULL)
+ {
+ oread = 0;
+ owrite = 1;
+ }
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+ default:
+ oread = owrite = -1;
+ break;
+ case UUCONF_PORTTYPE_STDIN:
+ oread = 0;
+ owrite = 1;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ aidescs[0] = 0;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[0] = oread;
+ if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[1] = owrite;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL,
+ FALSE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, "shell") == 0;
+}
+
+/* Change directories. */
+
+boolean
+fsysdep_chdir (zdir)
+ const char *zdir;
+{
+ if (zdir == NULL || *zdir == '\0')
+ {
+ zdir = getenv ("HOME");
+ if (zdir == NULL)
+ {
+ ulog (LOG_ERROR, "HOME not defined");
+ return FALSE;
+ }
+ }
+ if (chdir (zdir) < 0)
+ {
+ ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Suspend the current process. */
+
+boolean
+fsysdep_suspend ()
+{
+#ifndef SIGTSTP
+ return fsysdep_terminal_puts ("[process suspension not supported]");
+#else
+ return kill (getpid (), SIGTSTP) == 0;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/cwd.c b/gnu/libexec/uucp/libunix/cwd.c
new file mode 100644
index 00000000000..433025db6c3
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cwd.c
@@ -0,0 +1,55 @@
+/* cwd.c
+ Routines dealing with the current working directory. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* See whether running this file through zsysdep_add_cwd would require
+ knowing the current working directory. This is used to avoid
+ determining the cwd if it will not be needed. */
+
+boolean
+fsysdep_needs_cwd (zfile)
+ const char *zfile;
+{
+ return *zfile != '/' && *zfile != '~';
+}
+
+/* Expand a local file, putting relative pathnames in the current
+ working directory. Note that ~/file is placed in the public
+ directory, rather than in the user's home directory. This is
+ consistent with other UUCP packages. */
+
+char *
+zsysdep_local_file_cwd (zfile, zpubdir)
+ const char *zfile;
+ const char *zpubdir;
+{
+ if (*zfile == '/')
+ return zbufcpy (zfile);
+ else if (*zfile == '~')
+ return zsysdep_local_file (zfile, zpubdir);
+ else
+ return zsysdep_add_cwd (zfile);
+}
+
+/* Add the current working directory to a remote file name. */
+
+char *
+zsysdep_add_cwd (zfile)
+ const char *zfile;
+{
+ if (*zfile == '/' || *zfile == '~')
+ return zbufcpy (zfile);
+
+ if (zScwd == NULL)
+ {
+ ulog (LOG_ERROR, "Can't determine current directory");
+ return NULL;
+ }
+
+ return zsysdep_in_dir (zScwd, zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/detach.c b/gnu/libexec/uucp/libunix/detach.c
new file mode 100644
index 00000000000..41e1969b5ef
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/detach.c
@@ -0,0 +1,186 @@
+/* detach.c
+ Detach from the controlling terminal.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef TIOCNOTTY
+#define HAVE_TIOCNOTTY 1
+#else
+#define HAVE_TIOCNOTTY 0
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+/* Detach from the controlling terminal. This is called by uucico if
+ it is calling out to another system, so that it can receive SIGHUP
+ signals from the port it calls out on. It is also called by uucico
+ just before it starts uuxqt, so that uuxqt is completely
+ independent of the terminal. */
+
+void
+usysdep_detach ()
+{
+#if ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY
+
+ pid_t igrp;
+
+ /* First make sure we are not a process group leader. If we have
+ TIOCNOTTY, this doesn't matter, since TIOCNOTTY sets our process
+ group to 0 anyhow. */
+
+#if HAVE_BSD_PGRP
+ igrp = getpgrp (0);
+#else
+ igrp = getpgrp ();
+#endif
+
+ if (igrp == getpid ())
+ {
+ boolean fignored;
+ pid_t ipid;
+
+ /* Ignore SIGHUP, since our process group leader is about to
+ die. */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored);
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ /* We'll always wind up as a child of process number 1, right?
+ Right? We have to wait for our parent to die before
+ reenabling SIGHUP. */
+ while (getppid () != 1)
+ sleep (1);
+
+ ulog_id (getpid ());
+
+ /* Restore SIGHUP catcher if it wasn't being ignored. */
+ if (! fignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+#endif /* ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY */
+
+#if HAVE_TIOCNOTTY
+ /* Lose the original controlling terminal. If standard input has
+ been reopened to /dev/null, this will do no harm. If another
+ port has been opened to become the controlling terminal, it
+ should have been detached when it was closed. */
+ (void) ioctl (0, TIOCNOTTY, (char *) NULL);
+#endif
+
+ /* Close stdin, stdout and stderr and reopen them on /dev/null, to
+ make sure we have no connection at all to the terminal. */
+ (void) close (0);
+ (void) close (1);
+ (void) close (2);
+ if (open ((char *) "/dev/null", O_RDONLY) != 0
+ || open ((char *) "/dev/null", O_WRONLY) != 1
+ || open ((char *) "/dev/null", O_WRONLY) != 2)
+ ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno));
+
+#if HAVE_BSD_PGRP
+
+ /* Make sure our process group ID is set to 0. On BSD TIOCNOTTY
+ should already have set it 0, so this will do no harm. On System
+ V we presumably did not execute the TIOCNOTTY call, but the
+ System V setpgrp will detach the controlling terminal anyhow.
+ This lets us use the same code on both BSD and System V, provided
+ it compiles correctly, which life easier for the configure
+ script. We don't output an error if we got EPERM because some
+ BSD variants don't permit this usage of setpgrp (which means they
+ don't provide any way to pick up a new controlling terminal). */
+
+ if (setpgrp (0, 0) < 0)
+ {
+ if (errno != EPERM)
+ ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
+ }
+
+#else /* ! HAVE_BSD_PGRP */
+
+#if HAVE_SETSID
+
+ /* Under POSIX the setsid call creates a new session for which we
+ are the process group leader. It also detaches us from our
+ controlling terminal. I'm using the BSD setpgrp call first
+ because they should be equivalent for my purposes, but it turns
+ out that on Ultrix 4.0 setsid prevents us from ever acquiring
+ another controlling terminal (it does not change our process
+ group, and Ultrix 4.0 prevents us from setting our process group
+ to 0). */
+ (void) setsid ();
+
+#else /* ! HAVE_SETSID */
+
+#if HAVE_SETPGRP
+
+ /* Now we assume we have the System V setpgrp, which takes no
+ arguments, and we couldn't compile the HAVE_BSD_PGRP code above
+ because there was a prototype somewhere in scope. On System V
+ setpgrp makes us the leader of a new process group and also
+ detaches the controlling terminal. */
+
+ if (setpgrp () < 0)
+ ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
+
+#else /* ! HAVE_SETPGRP */
+
+ #error Must detach from controlling terminal
+
+#endif /* HAVE_SETPGRP */
+#endif /* ! HAVE_SETSID */
+#endif /* ! HAVE_BSD_PGRP */
+
+ /* At this point we have completely detached from our controlling
+ terminal. The next terminal device we open will probably become
+ our controlling terminal. */
+}
diff --git a/gnu/libexec/uucp/libunix/dirent.c b/gnu/libexec/uucp/libunix/dirent.c
new file mode 100644
index 00000000000..83db496cabb
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dirent.c
@@ -0,0 +1,123 @@
+/* dirent.c
+ Replacements for opendir, readdir and closedir for the original
+ Unix filesystem only.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Simple emulations of opendir/readdir/closedir for systems which
+ have the original format of Unix directories. It's probably better
+ to get Doug Gwyn's public domain set of emulation functions. */
+
+DIR *
+opendir (zdir)
+ const char *zdir;
+{
+ int o;
+ struct stat s;
+ DIR *qret;
+
+ o = open ((char *) zdir, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ return NULL;
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0
+ || fstat (o, &s) < 0)
+ {
+ int isave;
+
+ isave = errno;
+ (void) close (o);
+ errno = isave;
+ return NULL;
+ }
+ if (! S_ISDIR (s.st_mode))
+ {
+ (void) close (o);
+ errno = ENOTDIR;
+ return NULL;
+ }
+ qret = (DIR *) xmalloc (sizeof (DIR));
+ qret->o = o;
+ return qret;
+}
+
+struct dirent *
+readdir (q)
+ DIR *q;
+{
+ struct direct sdir;
+ int cgot;
+
+ do
+ {
+ cgot = read (q->o, &sdir, sizeof (struct direct));
+ if (cgot <= 0)
+ return NULL;
+ if (cgot != sizeof (struct direct))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ while (sdir.d_ino == 0);
+
+ strncpy (q->s.d_name, sdir.d_name, DIRSIZ);
+ q->s.d_name[DIRSIZ] = '\0';
+ return &q->s;
+}
+
+int
+closedir (q)
+ DIR *q;
+{
+ int o;
+
+ o = q->o;
+ xfree (q);
+ return close (o);
+}
diff --git a/gnu/libexec/uucp/libunix/dup2.c b/gnu/libexec/uucp/libunix/dup2.c
new file mode 100644
index 00000000000..6a7359fe92e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dup2.c
@@ -0,0 +1,69 @@
+/* dup2.c
+ The Unix dup2 function, for systems which only have dup.
+
+ Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* I basically took this from the emacs 18.57 distribution, although I
+ cleaned it up a bit and made it POSIX compliant. */
+
+int
+dup2 (oold, onew)
+ int oold;
+ int onew;
+{
+ if (oold == onew)
+ return onew;
+ (void) close (onew);
+
+#ifdef F_DUPFD
+ return fcntl (oold, F_DUPFD, onew);
+#else
+ {
+ int onext, oret, isave;
+
+ onext = dup (oold);
+ if (onext == onew)
+ return onext;
+ if (onext < 0)
+ return -1;
+ oret = dup2 (oold, onew);
+ isave = errno;
+ (void) close (onext);
+ errno = isave;
+ return oret;
+ }
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/efopen.c b/gnu/libexec/uucp/libunix/efopen.c
new file mode 100644
index 00000000000..7e360b61687
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/efopen.c
@@ -0,0 +1,132 @@
+/* efopen.c
+ Open a stdio file with appropriate permissions. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_APPEND
+#ifdef FAPPEND
+#define O_APPEND FAPPEND
+#endif
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+FILE *
+esysdep_fopen (zfile, fpublic, fappend, fmkdirs)
+ const char *zfile;
+ boolean fpublic;
+ boolean fappend;
+ boolean fmkdirs;
+{
+ int imode;
+ int o;
+ FILE *e;
+
+ if (fpublic)
+ imode = IPUBLIC_FILE_MODE;
+ else
+ imode = IPRIVATE_FILE_MODE;
+
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = open ((char *) zfile, O_WRONLY | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ o = creat ((char *) zfile, imode);
+#endif /* ! defined (O_CREAT) */
+ }
+
+ if (o < 0)
+ {
+ if (errno == ENOENT && fmkdirs)
+ {
+ if (! fsysdep_make_dirs (zfile, fpublic))
+ return NULL;
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = creat ((char *) zfile, imode);
+#endif
+ }
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ }
+
+#ifndef O_CREAT
+#ifdef O_APPEND
+ if (fappend)
+ {
+ if (fcntl (o, F_SETFL, O_APPEND) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+ }
+#endif /* defined (O_APPEND) */
+#endif /* ! defined (O_CREAT) */
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+
+ if (fappend)
+ e = fdopen (o, (char *) "a");
+ else
+ e = fdopen (o, (char *) "w");
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (o);
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/epopen.c b/gnu/libexec/uucp/libunix/epopen.c
new file mode 100644
index 00000000000..dec1b3999d6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/epopen.c
@@ -0,0 +1,85 @@
+/* epopen.c
+ A version of popen that goes through ixsspawn.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* A version of popen that goes through ixsspawn. This actually takes
+ an array of arguments rather than a string, and takes a boolean
+ read/write value rather than a string. It sets *pipid to the
+ process ID of the child. */
+
+FILE *
+espopen (pazargs, frd, pipid)
+ const char **pazargs;
+ boolean frd;
+ pid_t *pipid;
+{
+ int aidescs[3];
+ pid_t ipid;
+ FILE *eret;
+
+ if (frd)
+ {
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_READ_PIPE;
+ }
+ else
+ {
+ aidescs[0] = SPAWN_WRITE_PIPE;
+ aidescs[1] = SPAWN_NULL;
+ }
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ return NULL;
+
+ if (frd)
+ eret = fdopen (aidescs[1], (char *) "r");
+ else
+ eret = fdopen (aidescs[0], (char *) "w");
+ if (eret == NULL)
+ {
+ int ierr;
+
+ ierr = errno;
+ (void) close (frd ? aidescs[1] : aidescs[0]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ errno = ierr;
+ return NULL;
+ }
+
+ *pipid = ipid;
+
+ return eret;
+}
diff --git a/gnu/libexec/uucp/libunix/exists.c b/gnu/libexec/uucp/libunix/exists.c
new file mode 100644
index 00000000000..9473922f0d5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/exists.c
@@ -0,0 +1,16 @@
+/* exists.c
+ Check whether a file exists. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+boolean
+fsysdep_file_exists (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ return stat ((char *) zfile, &s) == 0;
+}
diff --git a/gnu/libexec/uucp/libunix/filnam.c b/gnu/libexec/uucp/libunix/filnam.c
new file mode 100644
index 00000000000..62054767b89
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/filnam.c
@@ -0,0 +1,376 @@
+/* filnam.c
+ Get names to use for UUCP files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+/* We need a definition for SEEK_SET. */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+#define ZCHARS \
+ "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+/* Local functions. */
+
+static boolean fscmd_seq P((const char *zsystem, char *zseq));
+static char *zsfile_name P((int btype, const char *zsystem,
+ const char *zlocalname, int bgrade,
+ boolean fxqt, char *ztname, char *zdname,
+ char *zxname));
+
+/* Get a new command sequence number (this is not a sequence number to
+ be used for communicating with another system, but a sequence
+ number to be used when generating the name of a command file).
+ The sequence number is placed into zseq, which should be five
+ characters long. */
+
+static boolean
+fscmd_seq (zsystem, zseq)
+ const char *zsystem;
+ char *zseq;
+{
+ boolean ferr;
+ char *zfree;
+ const char *zfile;
+ int o;
+ int i;
+
+ /* Lock the sequence file. This may not be correct for all systems,
+ but it only matters if the system UUCP and this UUCP are running
+ at the same time. */
+ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr))
+ {
+ if (ferr || FGOT_SIGNAL ())
+ return FALSE;
+ sleep (5);
+ }
+
+ zfree = NULL;
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ zfile = "SEQF";
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zfree = zsysdep_in_dir (".Sequence", zsystem);
+ zfile = zfree;
+#endif
+#if SPOOLDIR_ULTRIX
+ if (! fsultrix_has_spool (zsystem))
+ zfile = "sys/DEFAULT/.SEQF";
+ else
+ {
+ zfree = zsappend3 ("sys", zsystem, ".SEQF");
+ zfile = zfree;
+ }
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ zfree = zsysdep_in_dir (zsystem, "SEQF");
+ zfile = zfree;
+#endif /* SPOOLDIR_TAYLOR */
+
+#ifdef O_CREAT
+ o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE);
+#else
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ {
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+ }
+#endif
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zfile, FALSE))
+ {
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_RDWR | O_CREAT | O_NOCTTY,
+ IPUBLIC_FILE_MODE);
+#else
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+#endif
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+ }
+
+ if (read (o, zseq, CSEQLEN) != CSEQLEN)
+ strcpy (zseq, "0000");
+ zseq[CSEQLEN] = '\0';
+
+ /* We must add one to the sequence number and return the new value.
+ On Ultrix, arbitrary characters are allowed in the sequence
+ number. On other systems, the sequence number apparently must be
+ in hex. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_HDB || SPOOLDIR_SVR4
+ i = (int) strtol (zseq, (char **) NULL, 16);
+ ++i;
+ if (i > 0xffff)
+ i = 0;
+ /* The sprintf argument has CSEQLEN built into it. */
+ sprintf (zseq, "%04x", (unsigned int) i);
+#endif
+#if SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ for (i = CSEQLEN - 1; i >= 0; i--)
+ {
+ const char *zdig;
+
+ zdig = strchr (ZCHARS, zseq[i]);
+ if (zdig == NULL || zdig[0] == '\0' || zdig[1] == '\0')
+ zseq[i] = '0';
+ else
+ {
+ zseq[i] = zdig[1];
+ break;
+ }
+ }
+#endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */
+
+ if (lseek (o, (off_t) 0, SEEK_SET) < 0
+ || write (o, zseq, CSEQLEN) != CSEQLEN
+ || close (o) < 0)
+ {
+ ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno));
+ (void) close (o);
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+
+ return TRUE;
+}
+
+/* Get the name of a command or data file for a remote system. The
+ btype argument should be C for a command file or D for a data file.
+ If the grade of a data file is X, it is assumed that this is going
+ to become an execute file on some other system. The zsystem
+ argument is the system that the file will be transferred to. The
+ ztname argument will be set to a file name that could be passed to
+ zsysdep_spool_file_name. The zdname argument, if not NULL, will be
+ set to a data file name appropriate for the remote system. The
+ zxname argument, if not NULL, will be set to the name of an execute
+ file on the remote system. None of the names will be more than 14
+ characters long. */
+
+/*ARGSUSED*/
+static char *
+zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname)
+ int btype;
+ const char *zsystem;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ char abseq[CSEQLEN + 1];
+ char absimple[11 + CSEQLEN];
+ char *zname;
+
+ if (zlocalname == NULL)
+ zlocalname = zSlocalname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zsystem, abseq))
+ return NULL;
+
+ if (btype == 'C')
+ {
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq);
+#else
+ sprintf (absimple, "C.%c%s", bgrade, abseq);
+#endif
+ }
+ else if (btype == 'D')
+ {
+ /* This name doesn't really matter that much; it's just the
+ name we use on the local system. The name we use on the
+ remote system, which we return in zdname, should contain
+ our system name so that remote UUCP's running SPOOLDIR_V2
+ and the like can distinguish while files come from which
+ systems. */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq);
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+#else /* SPOOLDIR_TAYLOR */
+ if (fxqt)
+ sprintf (absimple, "D.X%s", abseq);
+ else
+ sprintf (absimple, "D.%s", abseq);
+#endif /* SPOOLDIR_TAYLOR */
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+ }
+#if DEBUG > 0
+ else
+ ulog (LOG_FATAL, "zsfile_name: Can't happen");
+#endif
+
+ zname = zsfind_file (absimple, zsystem, bgrade);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ if (ztname != NULL)
+ strcpy (ztname, absimple);
+
+ if (zdname != NULL)
+ sprintf (zdname, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ if (zxname != NULL)
+ sprintf (zxname, "X.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ return zname;
+}
+
+/* Return a name to use for a data file to be copied to another
+ system. The name returned will be for a real file. The zlocalname
+ argument is the local name as seen by the remote system, the bgrade
+ argument is the file grade, and the fxqt argument is TRUE if this
+ file will become an execution file. The ztname argument, if not
+ NULL, will be set to a name that could be passed to
+ zsysdep_spool_file_name to get back the return value of this
+ function. The zdname argument, if not NULL, will be set to a name
+ that the file could be given on another system. The zxname
+ argument, if not NULL, will be set to a name for an execute file on
+ another system. */
+
+char *
+zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname,
+ zxname)
+ const struct uuconf_system *qsys;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt,
+ ztname, zdname, zxname);
+}
+
+/* Get a command file name. */
+
+char *
+zscmd_file (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL,
+ bgrade, FALSE, (char *) NULL, (char *) NULL,
+ (char *) NULL);
+}
+
+/* Return a name for an execute file to be created locally. This is
+ used by uux to execute a command locally with remote files. */
+
+char *
+zsysdep_xqt_file_name ()
+{
+ char abseq[CSEQLEN + 1];
+ char absx[11 + CSEQLEN];
+ char *zname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zSlocalname, abseq))
+ return NULL;
+
+ sprintf (absx, "X.%.7sX%s", zSlocalname, abseq);
+
+ zname = zsfind_file (absx, zSlocalname, -1);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ return zname;
+}
diff --git a/gnu/libexec/uucp/libunix/fsusg.c b/gnu/libexec/uucp/libunix/fsusg.c
new file mode 100644
index 00000000000..e2b40a8ad5a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/fsusg.c
@@ -0,0 +1,231 @@
+/* fsusage.c -- return space usage of mounted filesystems
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file was modified slightly by Ian Lance Taylor, December 1992,
+ for use with Taylor UUCP. */
+
+#include "uucp.h"
+#include "sysdep.h"
+#include "fsusg.h"
+
+int statfs ();
+
+#if STAT_STATFS2_BSIZE
+#ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */
+#include <sys/vfs.h>
+#endif
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+#include <sys/mount.h>
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if STAT_USTAT /* SVR2 and others. */
+#include <ustat.h>
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+#include <sys/statfs.h>
+#endif
+#ifdef _AIX
+#ifdef _IBMR2 /* AIX RS6000. */
+#include <sys/statfs.h>
+#endif
+#endif
+
+#ifdef _AIX
+#ifdef _I386 /* AIX PS/2. */
+#include <sys/stat.h>
+#include <sys/dustat.h>
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+#include <sys/statvfs.h>
+int statvfs ();
+#endif
+
+#define STAT_NONE 0
+
+#if ! STAT_STATVFS
+#if ! STAT_STATFS2_BSIZE
+#if ! STAT_STATFS2_FSIZE
+#if ! STAT_STATFS2_FS_DATA
+#if ! STAT_STATFS4
+#if ! STAT_USTAT
+#undef STAT_NONE
+#define STAT_NONE 1
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+#if ! STAT_NONE
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding up. */
+
+static long
+adjust_blocks (blocks, fromsize, tosize)
+ long blocks;
+ int fromsize, tosize;
+{
+ if (fromsize == tosize) /* E.g., from 512 to 512. */
+ return blocks;
+ else if (fromsize > tosize) /* E.g., from 2048 to 512. */
+ return blocks * (fromsize / tosize);
+ else /* E.g., from 256 to 512. */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+#endif
+
+/* Fill in the fields of FSP with information about space usage for
+ the filesystem on which PATH resides.
+ DISK is the device on which PATH is mounted, for space-getting
+ methods that need to know it.
+ Return 0 if successful, -1 if not. */
+
+int
+get_fs_usage (path, disk, fsp)
+ char *path, *disk;
+ struct fs_usage *fsp;
+{
+#if STAT_NONE
+ return -1;
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
+ fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
+ fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
+ fsp->fsu_files = fsd.fd_req.gtot;
+ fsp->fsu_ffree = fsd.fd_req.gfree;
+#endif
+
+#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+#define convert_blocks(b) (b)
+#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
+#define f_bavail f_bfree
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+ struct statvfs fsd;
+
+ if (statvfs (path, &fsd) < 0)
+ return -1;
+ /* f_frsize isn't guaranteed to be supported. */
+#define convert_blocks(b) \
+ adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+#endif
+
+#if STAT_USTAT
+ {
+ struct stat sstat;
+ struct ustat s;
+
+ if (stat (path, &sstat) < 0
+ || ustat (sstat.st_dev, &s) < 0)
+ return -1;
+ fsp->fsu_blocks = -1;
+ fsp->fsu_bfree = f_tfree;
+ fsp->fsu_bavail = f_tfree;
+ fsp->fsu_files = -1;
+ fsp->fsu_ffree = -1;
+ }
+#endif
+
+#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */
+#if ! STAT_USTAT
+#if ! STAT_NONE
+ fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
+ fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
+ fsp->fsu_files = fsd.f_files;
+ fsp->fsu_ffree = fsd.f_ffree;
+#endif
+#endif
+#endif
+
+ return 0;
+}
+
+#ifdef _AIX
+#ifdef _I386
+/* AIX PS/2 does not supply statfs. */
+
+int
+statfs (path, fsb)
+ char *path;
+ struct statfs *fsb;
+{
+ struct stat stats;
+ struct dustat fsd;
+
+ if (stat (path, &stats))
+ return -1;
+ if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+ return -1;
+ fsb->f_type = 0;
+ fsb->f_bsize = fsd.du_bsize;
+ fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+ fsb->f_bfree = fsd.du_tfree;
+ fsb->f_bavail = fsd.du_tfree;
+ fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
+ fsb->f_ffree = fsd.du_tinode;
+ fsb->f_fsid.val[0] = fsd.du_site;
+ fsb->f_fsid.val[1] = fsd.du_pckno;
+ return 0;
+}
+#endif
+#endif /* _AIX && _I386 */
diff --git a/gnu/libexec/uucp/libunix/fsusg.h b/gnu/libexec/uucp/libunix/fsusg.h
new file mode 100644
index 00000000000..8d4d054cb5a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/fsusg.h
@@ -0,0 +1,31 @@
+/* fsusage.h -- declarations for filesystem space usage info
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This files was modified slightly by Ian Lance Taylor for use with
+ Taylor UUCP. */
+
+/* Space usage statistics for a filesystem. Blocks are 512-byte. */
+struct fs_usage
+{
+ long fsu_blocks; /* Total blocks. */
+ long fsu_bfree; /* Free blocks available to superuser. */
+ long fsu_bavail; /* Free blocks available to non-superuser. */
+ long fsu_files; /* Total file nodes. */
+ long fsu_ffree; /* Free file nodes. */
+};
+
+extern int get_fs_usage P((char *path, char *disk, struct fs_usage *fsp));
diff --git a/gnu/libexec/uucp/libunix/ftw.c b/gnu/libexec/uucp/libunix/ftw.c
new file mode 100644
index 00000000000..c3372b53ca4
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ftw.c
@@ -0,0 +1,250 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ian Lance Taylor (ian@airs.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/* Traverse one level of a directory tree. */
+
+static int
+ftw_dir (dirs, level, descriptors, dir, len, func)
+ DIR **dirs;
+ int level;
+ int descriptors;
+ char *dir;
+ size_t len;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+{
+ int got;
+ struct dirent *entry;
+
+ got = 0;
+
+ errno = 0;
+
+ while ((entry = readdir (dirs[level])) != NULL)
+ {
+ size_t namlen;
+ struct stat s;
+ int flag, ret, newlev;
+
+ ++got;
+
+ namlen = strlen (entry->d_name);
+ if (entry->d_name[0] == '.'
+ && (namlen == 1 ||
+ (namlen == 2 && entry->d_name[1] == '.')))
+ {
+ errno = 0;
+ continue;
+ }
+
+ if (namlen + len + 1 > PATH_MAX)
+ {
+#ifdef ENAMETOOLONG
+ errno = ENAMETOOLONG;
+#else
+ errno = ENOMEM;
+#endif
+ return -1;
+ }
+
+ dir[len] = '/';
+ memcpy ((dir + len + 1), entry->d_name, namlen + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ newlev = (level + 1) % descriptors;
+
+ if (dirs[newlev] != NULL)
+ closedir (dirs[newlev]);
+
+ dirs[newlev] = opendir (dir);
+ if (dirs[newlev] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (dir, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, newlev, descriptors, dir,
+ namlen + len + 1, func);
+ if (dirs[newlev] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[newlev]);
+ errno = save;
+ dirs[newlev] = NULL;
+ }
+ }
+
+ if (ret != 0)
+ return ret;
+
+ if (dirs[level] == NULL)
+ {
+ int skip;
+
+ dir[len] = '\0';
+ dirs[level] = opendir (dir);
+ if (dirs[level] == NULL)
+ return -1;
+ skip = got;
+ while (skip-- != 0)
+ {
+ errno = 0;
+ if (readdir (dirs[level]) == NULL)
+ return errno == 0 ? 0 : -1;
+ }
+ }
+
+ errno = 0;
+ }
+
+ return errno == 0 ? 0 : -1;
+}
+
+/* Call a function on every element in a directory tree. */
+
+int
+ftw (dir, func, descriptors)
+ const char *dir;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+ int descriptors;
+{
+ DIR **dirs;
+ int c;
+ DIR **p;
+ size_t len;
+ char buf[PATH_MAX + 1];
+ struct stat s;
+ int flag, ret;
+
+ if (descriptors <= 0)
+ descriptors = 1;
+
+ dirs = (DIR **) malloc (descriptors * sizeof (DIR *));
+ if (dirs == NULL)
+ return -1;
+ c = descriptors;
+ p = dirs;
+ while (c-- != 0)
+ *p++ = NULL;
+
+ len = strlen (dir);
+ memcpy (buf, dir, len + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ dirs[0] = opendir (dir);
+ if (dirs[0] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (buf, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
+ if (dirs[0] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[0]);
+ errno = save;
+ }
+ }
+
+ free ((pointer) dirs);
+ return ret;
+}
diff --git a/gnu/libexec/uucp/libunix/getcwd.c b/gnu/libexec/uucp/libunix/getcwd.c
new file mode 100644
index 00000000000..d3623bd2cd8
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/getcwd.c
@@ -0,0 +1,59 @@
+/* getcwd.c
+ Replacement for the getcwd function that just calls /bin/pwd. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+char *
+getcwd (zbuf, cbuf)
+ char *zbuf;
+ size_t cbuf;
+{
+ const char *azargs[2];
+ FILE *e;
+ pid_t ipid;
+ int cread;
+ int ierr;
+
+ azargs[0] = PWD_PROGRAM;
+ azargs[1] = NULL;
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ return NULL;
+
+ ierr = 0;
+
+ cread = fread (zbuf, sizeof (char), cbuf, e);
+ if (cread == 0)
+ ierr = errno;
+
+ (void) fclose (e);
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ ierr = EACCES;
+ cread = 0;
+ }
+
+ if (cread != 0)
+ {
+ if (zbuf[cread - 1] == '\n')
+ zbuf[cread - 1] = '\0';
+ else
+ {
+ ierr = ERANGE;
+ cread = 0;
+ }
+ }
+
+ if (cread == 0)
+ {
+ errno = ierr;
+ return NULL;
+ }
+
+ return zbuf;
+}
diff --git a/gnu/libexec/uucp/libunix/indir.c b/gnu/libexec/uucp/libunix/indir.c
new file mode 100644
index 00000000000..2484ec23f85
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/indir.c
@@ -0,0 +1,133 @@
+/* indir.c
+ See if a file is in a directory.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See whether a file is in a directory, and optionally check access. */
+
+boolean
+fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser)
+ const char *zfile;
+ const char *zdir;
+ boolean fcheck;
+ boolean freadable;
+ const char *zuser;
+{
+ size_t c;
+ char *zcopy, *zslash;
+ struct stat s;
+
+ if (*zfile != '/')
+ return FALSE;
+ c = strlen (zdir);
+ if (c > 0 && zdir[c - 1] == '/')
+ c--;
+ if (strncmp (zfile, zdir, c) != 0
+ || (zfile[c] != '/' && zfile[c] != '\0'))
+ return FALSE;
+ if (strstr (zfile + c, "/../") != NULL)
+ return FALSE;
+
+ /* If we're not checking access, get out now. */
+ if (! fcheck)
+ return TRUE;
+
+ zcopy = zbufcpy (zfile);
+
+ /* Start checking directories after zdir. Otherwise, we would
+ require that all directories down to /usr/spool/uucppublic be
+ publically searchable; they probably are but it should not be a
+ requirement. */
+ zslash = zcopy + c;
+ do
+ {
+ char b;
+ struct stat shold;
+
+ b = *zslash;
+ *zslash = '\0';
+
+ shold = s;
+ if (stat (zcopy, &s) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If this is the top directory, any problems will be caught
+ later when we try to open it. */
+ if (zslash == zcopy + c)
+ {
+ ubuffree (zcopy);
+ return TRUE;
+ }
+
+ /* Go back and check the last directory for read or write
+ access. */
+ s = shold;
+ break;
+ }
+
+ /* If this is not a directory, get out of the loop. */
+ if (! S_ISDIR (s.st_mode))
+ break;
+
+ /* Make sure the directory is searchable. */
+ if (! fsuser_access (&s, X_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If we've reached the end of the string, get out. */
+ if (b == '\0')
+ break;
+
+ *zslash = b;
+ }
+ while ((zslash = strchr (zslash + 1, '/')) != NULL);
+
+ /* At this point s holds a stat on the last component of the path.
+ We must check it for readability or writeability. */
+ if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ ubuffree (zcopy);
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/init.c b/gnu/libexec/uucp/libunix/init.c
new file mode 100644
index 00000000000..d4a13776281
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/init.c
@@ -0,0 +1,394 @@
+/* init.c
+ Initialize the system dependent routines.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#if ! HAVE_GETHOSTNAME && HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+/* Use getcwd in preference to getwd; if we have neither, we will be
+ using a getcwd replacement. */
+#if HAVE_GETCWD
+#undef HAVE_GETWD
+#define HAVE_GETWD 0
+#else /* ! HAVE_GETCWD */
+#if ! HAVE_GETWD
+#undef HAVE_GETCWD
+#define HAVE_GETCWD 1
+#endif /* ! HAVE_GETWD */
+#endif /* ! HAVE_GETCWD */
+
+#if HAVE_GETWD
+/* Get a value for MAXPATHLEN. */
+#if HAVE_SYS_PARAMS_H
+#include <sys/params.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else /* ! defined (PATH_MAX) */
+#define MAXPATHLEN 1024
+#endif /* ! defined (PATH_MAX) */
+#endif /* ! defined (MAXPATHLEN) */
+#endif /* HAVE_GETWD */
+
+/* External functions. */
+#ifndef getlogin
+extern char *getlogin ();
+#endif
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+#if HAVE_GETCWD
+#ifndef getcwd
+extern char *getcwd ();
+#endif
+#endif
+#if HAVE_GETWD
+#ifndef getwd
+extern char *getwd ();
+#endif
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Initialize the system dependent routines. We will probably be running
+ suid to uucp, so we make sure that nothing is obviously wrong. We
+ save the login name since we will be losing the real uid. */
+static char *zSlogin;
+
+/* The UUCP spool directory. */
+const char *zSspooldir;
+
+/* The UUCP lock directory. */
+const char *zSlockdir;
+
+/* The local UUCP name. */
+const char *zSlocalname;
+
+/* We save the current directory since we will do a chdir to the
+ spool directory. */
+char *zScwd;
+
+/* The maximum length of a system name is controlled by the type of spool
+ directory we use. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+size_t cSysdep_max_name_len = 7;
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+size_t cSysdep_max_name_len = 14;
+#endif
+#if SPOOLDIR_TAYLOR
+#if HAVE_LONG_FILE_NAMES
+size_t cSysdep_max_name_len = 255;
+#else /* ! HAVE_LONG_FILE_NAMES */
+size_t cSysdep_max_name_len = 14;
+#endif /* ! HAVE_LONG_FILE_NAMES */
+#endif /* SPOOLDIR_TAYLOR */
+
+/* Initialize the system dependent routines. */
+
+void
+usysdep_initialize (puuconf,iflags)
+ pointer puuconf;
+ int iflags;
+{
+ int cdescs;
+ int o;
+ int iuuconf;
+ char *z;
+ struct passwd *q;
+
+ ulog_id (getpid ());
+
+ /* Close everything but stdin, stdout and stderr. */
+#if HAVE_GETDTABLESIZE
+ cdescs = getdtablesize ();
+#else
+#if HAVE_SYSCONF
+ cdescs = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ cdescs = OPEN_MAX;
+#else
+#ifdef NOFILE
+ cdescs = NOFILE;
+#else
+ cdescs = 20;
+#endif /* ! defined (NOFILE) */
+#endif /* ! defined (OPEN_MAX) */
+#endif /* ! HAVE_SYSCONF */
+#endif /* ! HAVE_GETDTABLESIZE */
+
+ for (o = 3; o < cdescs; o++)
+ (void) close (o);
+
+ /* Make sure stdin, stdout and stderr are open. */
+ if (fcntl (0, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_RDONLY, 0) != 0)
+ exit (EXIT_FAILURE);
+ if (fcntl (1, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 1)
+ exit (EXIT_FAILURE);
+ if (fcntl (2, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 2)
+ exit (EXIT_FAILURE);
+
+ iuuconf = uuconf_spooldir (puuconf, &zSspooldir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_lockdir (puuconf, &zSlockdir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_localname (puuconf, &zSlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+#if HAVE_GETHOSTNAME
+ char ab[256];
+
+ if (gethostname (ab, sizeof ab - 1) < 0)
+ ulog (LOG_FATAL, "gethostname: %s", strerror (errno));
+ ab[sizeof ab - 1] = '\0';
+ ab[strcspn (ab, ".")] = '\0';
+ zSlocalname = zbufcpy (ab);
+#else /* ! HAVE_GETHOSTNAME */
+#if HAVE_UNAME
+ struct utsname s;
+
+ if (uname (&s) < 0)
+ ulog (LOG_FATAL, "uname: %s", strerror (errno));
+ zSlocalname = zbufcpy (s.nodename);
+#else /* ! HAVE_UNAME */
+ ulog (LOG_FATAL, "Don't know how to get local node name");
+#endif /* ! HAVE_UNAME */
+#endif /* ! HAVE_GETHOSTNAME */
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ /* We always set our file modes to exactly what we want. */
+ umask (0);
+
+ /* Get the login name, making sure that it matches the uid. Many
+ systems truncate the getlogin return value to 8 characters, but
+ keep the full name in the password file, so we prefer the name in
+ the password file. */
+ z = getenv ("LOGNAME");
+ if (z == NULL)
+ z = getenv ("USER");
+ if (z == NULL)
+ z = getlogin ();
+ if (z == NULL)
+ q = NULL;
+ else
+ {
+ q = getpwnam (z);
+ if (q != NULL)
+ z = q->pw_name;
+ }
+ if (q == NULL || q->pw_uid != getuid ())
+ {
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ z = NULL;
+ else
+ z = q->pw_name;
+ }
+ if (z != NULL)
+ zSlogin = zbufcpy (z);
+
+ /* On some old systems, an suid program run by root is started with
+ an euid of 0. If this happens, we look up the uid we should have
+ and set ourselves to it manually. This means that on such a
+ system root will not be able to uucp or uux files that are not
+ readable by uucp. */
+ if ((iflags & INIT_SUID) != 0
+ && geteuid () == 0)
+ {
+ q = getpwnam (OWNER);
+ if (q != NULL)
+ setuid (q->pw_uid);
+ }
+
+ if ((iflags & INIT_GETCWD) != 0)
+ {
+ const char *zenv;
+ struct stat senv, sdot;
+
+ /* Get the current working directory. We have to get it now,
+ since we're about to do a chdir. We use PWD if it's defined
+ and if it really names the working directory, since if it's
+ not the same as whatever getcwd returns it's probably more
+ appropriate. */
+ zenv = getenv ("PWD");
+ if (zenv != NULL
+ && stat ((char *) zenv, &senv) == 0
+ && stat ((char *) ".", &sdot) == 0
+ && senv.st_ino == sdot.st_ino
+ && senv.st_dev == sdot.st_dev)
+ zScwd = zbufcpy (zenv);
+ else
+ {
+
+#if HAVE_GETCWD
+ {
+ size_t c;
+
+ c = 128;
+ while (TRUE)
+ {
+ zScwd = (char *) xmalloc (c);
+ if (getcwd (zScwd, c) != NULL)
+ break;
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ if (errno != ERANGE)
+ break;
+ c <<= 1;
+ }
+ }
+#endif /* HAVE_GETCWD */
+
+#if HAVE_GETWD
+ zScwd = (char *) xmalloc (MAXPATHLEN);
+ if (getwd (zScwd) == NULL)
+ {
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ }
+#endif /* HAVE_GETWD */
+
+ if (zScwd != NULL)
+ zScwd = (char *) xrealloc ((pointer) zScwd,
+ strlen (zScwd) + 1);
+ }
+ }
+
+ if ((iflags & INIT_NOCHDIR) == 0)
+ {
+ /* Connect to the spool directory, and create it if it doesn't
+ exist. */
+ if (chdir (zSspooldir) < 0)
+ {
+ if (errno == ENOENT
+ && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0)
+ ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir,
+ strerror (errno));
+ if (chdir (zSspooldir) < 0)
+ ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir,
+ strerror (errno));
+ }
+ }
+}
+
+/* Exit the program. */
+
+void
+usysdep_exit (fsuccess)
+ boolean fsuccess;
+{
+ exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/* This is called when a non-standard configuration file is used, to
+ make sure the program doesn't hand out privileged file access.
+ This means that to test non-standard configuration files, you
+ should be logged in as uucp. This is called before
+ usysdep_initialize. It ensures that someone can't simply use an
+ alternate configuration file to steal UUCP transfers from other
+ systems. This will still permit people to set up their own
+ configuration file and pretend to be whatever system they choose.
+ The only real security is to use a high level of protection on the
+ modem ports. */
+
+/*ARGSUSED*/
+boolean fsysdep_other_config (z)
+ const char *z;
+{
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ return TRUE;
+}
+
+/* Get the node name to use if it was not specified in the configuration
+ file. */
+
+const char *
+zsysdep_localname ()
+{
+ return zSlocalname;
+}
+
+/* Get the login name. We actually get the login name in
+ usysdep_initialize, because after that we may switch away from the
+ real uid. */
+
+const char *
+zsysdep_login_name ()
+{
+ if (zSlogin == NULL)
+ ulog (LOG_FATAL, "Can't get login name");
+ return zSlogin;
+}
diff --git a/gnu/libexec/uucp/libunix/isdir.c b/gnu/libexec/uucp/libunix/isdir.c
new file mode 100644
index 00000000000..fc95e5275a8
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/isdir.c
@@ -0,0 +1,18 @@
+/* isdir.c
+ See whether a file exists and is a directory. */
+
+#include "uucp.h"
+
+#include "system.h"
+#include "sysdep.h"
+
+boolean
+fsysdep_directory (z)
+ const char *z;
+{
+ struct stat s;
+
+ if (stat ((char *) z, &s) < 0)
+ return FALSE;
+ return S_ISDIR (s.st_mode);
+}
diff --git a/gnu/libexec/uucp/libunix/isfork.c b/gnu/libexec/uucp/libunix/isfork.c
new file mode 100644
index 00000000000..f067d07552c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/isfork.c
@@ -0,0 +1,25 @@
+/* isfork.c
+ Retry fork several times before giving up. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+pid_t
+ixsfork ()
+{
+ int i;
+ pid_t iret;
+
+ for (i = 0; i < 10; i++)
+ {
+ iret = fork ();
+ if (iret >= 0 || errno != EAGAIN)
+ return iret;
+ sleep (5);
+ }
+
+ return iret;
+}
diff --git a/gnu/libexec/uucp/libunix/iswait.c b/gnu/libexec/uucp/libunix/iswait.c
new file mode 100644
index 00000000000..d2610aa1f8b
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/iswait.c
@@ -0,0 +1,159 @@
+/* iswait.c
+ Wait for a process to finish.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/* We use a typedef wait_status for wait (waitpid, wait4) to put
+ results into. We define the POSIX examination functions we need if
+ they are not already defined (if they aren't defined, I assume that
+ we have a standard wait status). */
+
+#if HAVE_UNION_WAIT
+typedef union wait wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(u) ((u).w_termsig == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(u) ((u).w_retcode)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(u) ((u).w_termsig)
+#endif
+#else /* ! HAVE_UNION_WAIT */
+typedef int wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(i) (((i) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(i) ((i) & 0x7f)
+#endif
+#endif /* ! HAVE_UNION_WAIT */
+
+/* Wait for a particular process to finish. The ipid argument should
+ be pid_t, but then we couldn't have a prototype. If the zreport
+ argument is not NULL, then a wait error will be logged, and if the
+ exit status is non-zero it will be logged with zreport as the
+ header of the log message. If the zreport argument is NULL, no
+ errors will be logged. This function returns the exit status if
+ the process exited normally, or -1 on error or if the process was
+ killed by a signal (I don't just always return the exit status
+ because then the calling code would have to prepared to handle
+ union wait status vs. int status, and none of the callers care
+ which signal killed the program anyhow).
+
+ This functions keeps waiting until the process finished, even if it
+ is interrupted by a signal. I think this is right for all uses.
+ The controversial one would be when called from uuxqt to wait for a
+ requested process. Hitting uuxqt with SIGKILL will approximate the
+ actions taken if we return from here with an error anyhow. If we
+ do get a signal, we call ulog with a NULL argument to get it in the
+ log file at about the right time. */
+
+int
+ixswait (ipid, zreport)
+ unsigned long ipid;
+ const char *zreport;
+{
+ wait_status istat;
+
+#if HAVE_WAITPID
+ while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "waitpid: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAITPID */
+#if HAVE_WAIT4
+ while (wait4 ((pid_t) ipid, (pointer) &istat, 0,
+ (struct rusage *) NULL) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait4: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAIT4 */
+ pid_t igot;
+
+ /* We could theoretically get the wrong child here if we're in some
+ kind of weird pipeline, so we don't give any error messages for
+ it. */
+ while ((igot = wait ((pointer) &istat)) != (pid_t) ipid)
+ {
+ if (igot < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ }
+#endif /* ! HAVE_WAIT4 */
+#endif /* ! HAVE_WAITPID */
+
+ DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d",
+ WIFEXITED (istat) ? "Exit status" : "Signal",
+ WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat));
+
+ if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0)
+ return 0;
+
+ if (zreport != NULL)
+ {
+ if (! WIFEXITED (istat))
+ ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat));
+ else
+ ulog (LOG_ERROR, "%s: Exit status %d", zreport,
+ WEXITSTATUS (istat));
+ }
+
+ if (WIFEXITED (istat))
+ return WEXITSTATUS (istat);
+ else
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/jobid.c b/gnu/libexec/uucp/libunix/jobid.c
new file mode 100644
index 00000000000..7f22f1d37d7
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/jobid.c
@@ -0,0 +1,101 @@
+/* jobid.c
+ Convert file names to jobids and vice versa.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Translate a file name and an associated system into a job id.
+ These job ids are used by uustat. We use the system name attached
+ to the grade and sequence number. This won't work correctly if the
+ file name was actually created by some other version of uucp that
+ uses a different length for the sequence number. Too bad. */
+
+char *
+zsfile_to_jobid (qsys, zfile, bgrade)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ int bgrade;
+{
+ size_t clen;
+ char *zret;
+
+ clen = strlen (qsys->uuconf_zname);
+ zret = zbufalc (clen + CSEQLEN + 2);
+ memcpy (zret, qsys->uuconf_zname, clen);
+ zret[clen] = bgrade;
+ memcpy (zret + clen + 1, zfile + strlen (zfile) - CSEQLEN, CSEQLEN + 1);
+ return zret;
+}
+
+/* Turn a job id back into a file name. */
+
+char *
+zsjobid_to_file (zid, pzsystem, pbgrade)
+ const char *zid;
+ char **pzsystem;
+ char *pbgrade;
+{
+ size_t clen;
+ const char *zend;
+ char *zsys;
+ char abname[CSEQLEN + 11];
+ char *zret;
+
+ clen = strlen (zid);
+ if (clen <= CSEQLEN)
+ {
+ ulog (LOG_ERROR, "%s: Bad job id", zid);
+ return NULL;
+ }
+
+ zend = zid + clen - CSEQLEN - 1;
+
+ zsys = zbufalc (clen - CSEQLEN);
+ memcpy (zsys, zid, clen - CSEQLEN - 1);
+ zsys[clen - CSEQLEN - 1] = '\0';
+
+ /* This must correspond to zsfile_name. */
+#if ! SPOOLDIR_TAYLOR
+ sprintf (abname, "C.%.7s%s", zsys, zend);
+#else
+ sprintf (abname, "C.%s", zend);
+#endif
+
+ zret = zsfind_file (abname, zsys, *zend);
+
+ if (zret != NULL && pzsystem != NULL)
+ *pzsystem = zsys;
+ else
+ ubuffree (zsys);
+
+ if (pbgrade != NULL)
+ *pbgrade = *zend;
+
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/lcksys.c b/gnu/libexec/uucp/libunix/lcksys.c
new file mode 100644
index 00000000000..4ece16afe7b
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/lcksys.c
@@ -0,0 +1,41 @@
+/* lcksys.c
+ Lock and unlock a remote system. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Lock a remote system. */
+
+boolean
+fsysdep_lock_system (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *z;
+ boolean fret;
+
+ z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
+ sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
+ fret = fsdo_lock (z, FALSE, (boolean *) NULL);
+ ubuffree (z);
+ return fret;
+}
+
+/* Unlock a remote system. */
+
+boolean
+fsysdep_unlock_system (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *z;
+ boolean fret;
+
+ z = zbufalc (strlen (qsys->uuconf_zname) + sizeof "LCK..");
+ sprintf (z, "LCK..%.8s", qsys->uuconf_zname);
+ fret = fsdo_unlock (z, FALSE);
+ ubuffree (z);
+ return fret;
+}
diff --git a/gnu/libexec/uucp/libunix/link.c b/gnu/libexec/uucp/libunix/link.c
new file mode 100644
index 00000000000..4550c76c94d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/link.c
@@ -0,0 +1,38 @@
+/* link.c
+ Link two files. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_link (zfrom, zto, pfworked)
+ const char *zfrom;
+ const char *zto;
+ boolean *pfworked;
+{
+ *pfworked = FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, TRUE))
+ return FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ }
+ if (errno == EXDEV)
+ return TRUE;
+ ulog (LOG_ERROR, "link (%s, %s): %s", zfrom, zto, strerror (errno));
+ return FALSE;
+}
diff --git a/gnu/libexec/uucp/libunix/locfil.c b/gnu/libexec/uucp/libunix/locfil.c
new file mode 100644
index 00000000000..0e05af9bcee
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/locfil.c
@@ -0,0 +1,95 @@
+/* locfil.c
+ Expand a file name on the local system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <pwd.h>
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Turn a file name into an absolute path, by doing tilde expansion
+ and moving any other type of file into the public directory. */
+
+char *
+zsysdep_local_file (zfile, zpubdir)
+ const char *zfile;
+ const char *zpubdir;
+{
+ const char *zdir;
+
+ if (*zfile == '/')
+ return zbufcpy (zfile);
+
+ if (*zfile != '~')
+ zdir = zpubdir;
+ else
+ {
+ if (zfile[1] == '\0')
+ return zbufcpy (zpubdir);
+
+ if (zfile[1] == '/')
+ {
+ zdir = zpubdir;
+ zfile += 2;
+ }
+ else
+ {
+ size_t cuserlen;
+ char *zcopy;
+ struct passwd *q;
+
+ ++zfile;
+ cuserlen = strcspn ((char *) zfile, "/");
+ zcopy = zbufalc (cuserlen + 1);
+ memcpy (zcopy, zfile, cuserlen);
+ zcopy[cuserlen] = '\0';
+
+ q = getpwnam (zcopy);
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "User %s not found", zcopy);
+ ubuffree (zcopy);
+ return NULL;
+ }
+ ubuffree (zcopy);
+
+ if (zfile[cuserlen] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ zdir = q->pw_dir;
+ zfile += cuserlen + 1;
+ }
+ }
+
+ return zsysdep_in_dir (zdir, zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/lock.c b/gnu/libexec/uucp/libunix/lock.c
new file mode 100644
index 00000000000..c43e31dfd00
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/lock.c
@@ -0,0 +1,477 @@
+/* lock.c
+ Lock and unlock a file name.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/04 19:32:33 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* Lock something. If the fspooldir argument is TRUE, the argument is
+ a file name relative to the spool directory; otherwise the argument
+ is a simple file name which should be created in the system lock
+ directory (under HDB this is /etc/locks). */
+
+boolean
+fsdo_lock (zlock, fspooldir, pferr)
+ const char *zlock;
+ boolean fspooldir;
+ boolean *pferr;
+{
+ char *zfree;
+ const char *zpath, *zslash;
+ size_t cslash;
+ pid_t ime;
+ char *ztempfile;
+ char abtempfile[sizeof "TMP1234567890"];
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cwrote;
+ const char *zerr;
+ boolean fret;
+
+ if (pferr != NULL)
+ *pferr = TRUE;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ ime = getpid ();
+
+ /* We do the actual lock by creating a file and then linking it to
+ the final file name we want. This avoids race conditions due to
+ one process checking the file before we have finished writing it,
+ and also works even if we are somehow running as root.
+
+ First, create the file in the right directory (we must create the
+ file in the same directory since otherwise we might attempt a
+ cross-device link). */
+ zslash = strrchr (zpath, '/');
+ if (zslash == NULL)
+ cslash = 0;
+ else
+ cslash = zslash - zpath + 1;
+
+ sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
+ ztempfile = zbufalc (cslash + sizeof abtempfile);
+ memcpy (ztempfile, zpath, cslash);
+ memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
+
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (ztempfile, FALSE))
+ {
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno));
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ zerr = NULL;
+ if (cwrote < 0)
+ zerr = "write";
+ if (close (o) < 0)
+ zerr = "close";
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno));
+ (void) remove (ztempfile);
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+
+ /* Now try to link the file we just created to the lock file that we
+ want. If it fails, try reading the existing file to make sure
+ the process that created it still exists. We do this in a loop
+ to make it easy to retry if the old locking process no longer
+ exists. */
+ fret = TRUE;
+ if (pferr != NULL)
+ *pferr = FALSE;
+ o = -1;
+ zerr = NULL;
+
+ while (link (ztempfile, zpath) != 0)
+ {
+ int cgot;
+ int ipid;
+ boolean freadonly;
+
+ fret = FALSE;
+
+ if (errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath,
+ strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ break;
+ }
+
+ freadonly = FALSE;
+ o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno == EACCES)
+ {
+ freadonly = TRUE;
+ o = open ((char *) zpath, O_RDONLY, 0);
+ }
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /* The file was presumably removed between the link
+ and the open. Try the link again. */
+ fret = TRUE;
+ continue;
+ }
+ zerr = "open";
+ break;
+ }
+ }
+
+ /* The race starts here. See below for a discussion. */
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ /* On NFS, the link might have actually succeeded even though we
+ got a failure return. This can happen if the original
+ acknowledgement was lost or delayed and the operation was
+ retried. In this case the pid will be our own. This
+ introduces a rather improbable race condition: if a stale
+ lock was left with our process ID in it, and another process
+ just did the kill, below, but has not yet changed the lock
+ file to hold its own process ID, we could start up and make
+ it all the way to here and think we have the lock. I'm not
+ going to worry about this possibility. */
+ if (ipid == ime)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* If the process still exists, we will get EPERM rather than
+ ESRCH. We then return FALSE to indicate that we cannot make
+ the lock. */
+ if (kill (ipid, 0) == 0 || errno == EPERM)
+ break;
+
+ ulog (LOG_ERROR, "Found stale lock %s held by process %d",
+ zpath, ipid);
+
+ /* This is a stale lock, created by a process that no longer
+ exists.
+
+ Now we could remove the file (and, if the file mode disallows
+ writing, that's what we have to do), but we try to avoid
+ doing so since it causes a race condition. If we remove the
+ file, and are interrupted any time after we do the read until
+ we do the remove, another process could get in, open the
+ file, find that it was a stale lock, remove the file and
+ create a new one. When we regained control we would remove
+ the file the other process just created.
+
+ These files are being generated partially for the benefit of
+ cu, and it would be nice to avoid the race however cu avoids
+ it, so that the programs remain compatible. Unfortunately,
+ nobody seems to know how cu avoids the race, or even if it
+ tries to avoid it at all.
+
+ There are a few ways to avoid the race. We could use kernel
+ locking primitives, but they may not be available. We could
+ link to a special file name, but if that file were left lying
+ around then no stale lock could ever be broken (Henry Spencer
+ would think this was a good thing).
+
+ Instead I've implemented the following procedure: seek to the
+ start of the file, write our pid into it, sleep for five
+ seconds, and then make sure our pid is still there. Anybody
+ who checks the file while we're asleep will find our pid
+ there and fail the lock. The only race will come from
+ another process which has done the read by the time we do our
+ write. That process will then have five seconds to do its
+ own write. When we wake up, we'll notice that our pid is no
+ longer in the file, and retry the lock from the beginning.
+
+ This relies on the atomicity of write(2). If it possible for
+ the writes of two processes to be interleaved, the two
+ processes could livelock. POSIX unfortunately leaves this
+ case explicitly undefined; however, given that the write is
+ of less than a disk block, it's difficult to imagine an
+ interleave occurring.
+
+ Note that this is still a race. If it takes the second
+ process more than five seconds to do the kill, the lseek, and
+ the write, both processes will think they have the lock.
+ Perhaps the length of time to sleep should be configurable.
+ Even better, perhaps I should add a configuration option to
+ use a permanent lock file, which eliminates any race and
+ forces the installer to be aware of the existence of the
+ permanent lock file.
+
+ We stat the file after the sleep, to make sure some other
+ program hasn't deleted it for us. */
+ if (freadonly)
+ {
+ (void) close (o);
+ o = -1;
+ (void) remove (zpath);
+ continue;
+ }
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ if (cwrote < 0)
+ {
+ zerr = "write";
+ break;
+ }
+
+ (void) sleep (5);
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ if (ipid == ime)
+ {
+ struct stat sfile, sdescriptor;
+
+ /* It looks like we have the lock. Do the final stat
+ check. */
+ if (stat ((char *) zpath, &sfile) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ zerr = "stat";
+ break;
+ }
+ /* Loop around and try again. */
+ }
+ else
+ {
+ if (fstat (o, &sdescriptor) < 0)
+ {
+ zerr = "fstat";
+ break;
+ }
+
+ if (sfile.st_ino == sdescriptor.st_ino
+ && sfile.st_dev == sdescriptor.st_dev)
+ {
+ /* Close the file before assuming we've succeeded to
+ pick up any trailing errors. */
+ if (close (o) < 0)
+ {
+ zerr = "close";
+ break;
+ }
+
+ o = -1;
+
+ /* We have the lock. */
+ fret = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Loop around and try the lock again. We keep doing this until
+ the lock file holds a pid that exists. */
+ (void) close (o);
+ o = -1;
+ fret = TRUE;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ }
+
+ if (o >= 0)
+ (void) close (o);
+
+ ubuffree (zfree);
+
+ /* It would be nice if we could leave the temporary file around for
+ future calls, but considering that we create lock files in
+ various different directories it's probably more trouble than
+ it's worth. */
+ if (remove (ztempfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
+
+ ubuffree (ztempfile);
+
+ return fret;
+}
+
+/* Unlock something. The fspooldir argument is as in fsdo_lock. */
+
+boolean
+fsdo_unlock (zlock, fspooldir)
+ const char *zlock;
+ boolean fspooldir;
+{
+ char *zfree;
+ const char *zpath;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ if (remove (zpath) == 0
+ || errno == ENOENT)
+ {
+ ubuffree (zfree);
+ return TRUE;
+ }
+ else
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+}
diff --git a/gnu/libexec/uucp/libunix/loctim.c b/gnu/libexec/uucp/libunix/loctim.c
new file mode 100644
index 00000000000..da5f32e2d27
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/loctim.c
@@ -0,0 +1,25 @@
+/* loctim.c
+ Turn a time epoch into a struct tm. This is trivial on Unix. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef localtime
+extern struct tm *localtime ();
+#endif
+
+void
+usysdep_localtime (itime, q)
+ long itime;
+ struct tm *q;
+{
+ time_t i;
+
+ i = (time_t) itime;
+ *q = *localtime (&i);
+}
diff --git a/gnu/libexec/uucp/libunix/mail.c b/gnu/libexec/uucp/libunix/mail.c
new file mode 100644
index 00000000000..74c1aa95adc
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mail.c
@@ -0,0 +1,85 @@
+/* mail.c
+ Send mail to a user.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifndef ctime
+extern char *ctime ();
+#endif
+
+/* Mail a message to a user. */
+
+boolean
+fsysdep_mail (zto, zsubject, cstrs, paz)
+ const char *zto;
+ const char *zsubject;
+ int cstrs;
+ const char **paz;
+{
+ const char *az[3];
+ FILE *e;
+ pid_t ipid;
+ time_t itime;
+ int i;
+
+ az[0] = MAIL_PROGRAM;
+ az[1] = zto;
+ az[2] = NULL;
+
+ e = espopen (az, FALSE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM,
+ strerror (errno));
+ return FALSE;
+ }
+
+ fprintf (e, "Subject: %s\n", zsubject);
+ fprintf (e, "To: %s\n", zto);
+
+ fprintf (e, "\n");
+
+ (void) time (&itime);
+ /* Remember that ctime includes a \n, so this skips a line. */
+ fprintf (e, "Message from UUCP on %s %s\n", zSlocalname,
+ ctime (&itime));
+
+ for (i = 0; i < cstrs; i++)
+ fputs (paz[i], e);
+
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, MAIL_PROGRAM) == 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdir.c b/gnu/libexec/uucp/libunix/mkdir.c
new file mode 100644
index 00000000000..f59ad5dfd6e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdir.c
@@ -0,0 +1,58 @@
+/* mkdir.c
+ Create a directory. We must go through a subsidiary program to
+ force our real uid to be the uucp owner before invoking the setuid
+ /bin/mkdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+mkdir (zdir, imode)
+ const char *zdir;
+ int imode;
+{
+ struct stat s;
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ /* Make sure the directory does not exist, since we will otherwise
+ get the wrong errno value. */
+ if (stat (zdir, &s) == 0)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ /* /bin/mkdir will create the directory with mode 777, so we set our
+ umask to get the mode we want. */
+ (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO));
+
+ azargs[0] = UUDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
+ TRUE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ (void) umask (0);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdirs.c b/gnu/libexec/uucp/libunix/mkdirs.c
new file mode 100644
index 00000000000..a4e0b67bb8c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdirs.c
@@ -0,0 +1,49 @@
+/* mkdirs.c
+ Create any directories needed for a file name. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_make_dirs (zfile, fpublic)
+ const char *zfile;
+ boolean fpublic;
+{
+ char *zcopy, *z;
+ int imode;
+
+ zcopy = zbufcpy (zfile);
+
+ if (fpublic)
+ imode = IPUBLIC_DIRECTORY_MODE;
+ else
+ imode = IDIRECTORY_MODE;
+
+ for (z = zcopy; *z != '\0'; z++)
+ {
+ if (*z == '/' && z != zcopy)
+ {
+ *z = '\0';
+ if (! fsysdep_directory (zcopy))
+ {
+ if (mkdir (zcopy, imode) != 0)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
+ strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ }
+ *z = '/';
+ }
+ }
+
+ ubuffree (zcopy);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/mode.c b/gnu/libexec/uucp/libunix/mode.c
new file mode 100644
index 00000000000..53f74ec81c3
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mode.c
@@ -0,0 +1,33 @@
+/* mode.c
+ Get the Unix file mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+unsigned int
+ixsysdep_file_mode (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return 0;
+ }
+
+#if S_IRWXU != 0700
+ #error Files modes need to be translated
+#endif
+
+ /* We can't return 0, since that indicate an error. */
+ if ((s.st_mode & 0777) == 0)
+ return 0400;
+
+ return s.st_mode & 0777;
+}
diff --git a/gnu/libexec/uucp/libunix/move.c b/gnu/libexec/uucp/libunix/move.c
new file mode 100644
index 00000000000..ccfe6d4d728
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/move.c
@@ -0,0 +1,176 @@
+/* move.c
+ Move a file.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* Move (rename) a file from one name to another. This routine will
+ optionally create necessary directories, and fpublic indicates
+ whether the new directories should be publically accessible or not.
+ If fcheck is true, it will try to determine whether the named user
+ has write access to the new file. */
+
+boolean
+fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
+ const char *zorig;
+ const char *zto;
+ boolean fmkdirs;
+ boolean fpublic;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ int o;
+
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "fsysdep_move_file: Moving %s to %s", zorig, zto);
+
+ /* Optionally make sure that zuser has write access on the
+ directory. */
+ if (fcheck)
+ {
+ char *zcopy;
+ char *zslash;
+
+ zcopy = zbufcpy (zto);
+ zslash = strrchr (zcopy, '/');
+ if (zslash == zcopy)
+ zslash[1] = '\0';
+ else
+ *zslash = '\0';
+
+ if (stat (zcopy, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ if (! fsuser_access (&s, W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ ubuffree (zcopy);
+
+ /* A malicious user now has a few milliseconds to change a
+ symbolic link to a directory uucp has write permission on but
+ the user does not (the obvious choice being /usr/lib/uucp).
+ The only certain method I can come up with to close this race
+ is to fork an suid process which takes on the users identity
+ and does the actual copy. This is sufficiently high overhead
+ that I'm not going to do it. */
+ }
+
+ /* We try to use rename to move the file. */
+
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+ }
+
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to copy the
+ file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ /* If we can't link across devices, we must copy the file by hand. */
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto,
+ strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Copy the file. */
+ if (stat ((char *) zorig, &s) < 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Make sure the file gets the right mode by creating it before we
+ call fcopy_file. */
+ (void) remove (zto);
+ o = creat ((char *) zto, s.st_mode);
+ if (o < 0)
+ {
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ o = creat ((char *) zto, s.st_mode);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+ }
+ (void) close (o);
+
+ if (! fcopy_file (zorig, zto, fpublic, fmkdirs))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ if (remove (zorig) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno));
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/opensr.c b/gnu/libexec/uucp/libunix/opensr.c
new file mode 100644
index 00000000000..3a8ca7a8b8a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/opensr.c
@@ -0,0 +1,244 @@
+/* opensr.c
+ Open files for sending and receiving.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Open a file to send to another system, and return the mode and
+ the size. */
+
+openfile_t
+esysdep_open_send (qsys, zfile, fcheck, zuser)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ openfile_t e;
+ int o;
+
+ if (fsysdep_directory (zfile))
+ {
+ ulog (LOG_ERROR, "%s: is a directory", zfile);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fopen (zfile, BINREAD);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ o = fileno (e);
+#else
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ if (e == -1)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return -1;
+ }
+ o = e;
+#endif
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (fstat (o, &s) == -1)
+ {
+ ulog (LOG_ERROR, "fstat: %s", strerror (errno));
+ s.st_mode = 0666;
+ }
+
+ /* We have to recheck the file permission, although we probably
+ checked it already, because otherwise there would be a window in
+ which somebody could change the contents of a symbolic link to
+ point to some file which was only readable by uucp. */
+ if (fcheck)
+ {
+ if (! fsuser_access (&s, R_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+ }
+
+ return e;
+}
+
+/* Get a temporary file name to receive into. We use the ztemp
+ argument to pick the file name, so that we relocate the file if the
+ transmission is aborted. */
+
+char *
+zsysdep_receive_temp (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Temp", qsys->uuconf_zname, ztemp);
+ else
+ return zstemp_file (qsys);
+}
+
+/* Open a temporary file to receive into. This should, perhaps, check
+ that we have write permission on the receiving directory, but it
+ doesn't. */
+
+openfile_t
+esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+ const char *zreceive;
+ long *pcrestart;
+{
+ int o;
+ openfile_t e;
+
+ /* If we used the ztemp argument in zsysdep_receive_temp, above,
+ then we will have a name consistent across conversations. In
+ that case, we may have already received some portion of this
+ file. */
+ o = -1;
+ *pcrestart = -1;
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ {
+ o = open ((char *) zreceive, O_WRONLY);
+ if (o >= 0)
+ {
+ struct stat s;
+
+ /* For safety, we insist on the file being less than 1 week
+ old. This can still catch people, unfortunately. I
+ don't know of any good solution to the problem of old
+ files hanging around. If anybody has a file they want
+ restarted, and they know about this issue, they can touch
+ it to bring it up to date. */
+ if (fstat (o, &s) < 0
+ || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL))
+ {
+ (void) close (o);
+ o = -1;
+ }
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "esysdep_open_receive: Reusing %s",
+ zreceive);
+ *pcrestart = (long) s.st_size;
+ }
+ }
+ }
+
+ if (o < 0)
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zreceive, FALSE))
+ return EFILECLOSED;
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zreceive, strerror (errno));
+ return EFILECLOSED;
+ }
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+#else
+ e = o;
+#endif
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/pause.c b/gnu/libexec/uucp/libunix/pause.c
new file mode 100644
index 00000000000..e774e0897bf
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/pause.c
@@ -0,0 +1,96 @@
+/* pause.c
+ Pause for half a second. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+/* Pick a timing routine to use. I somewhat arbitrarily picked usleep
+ above nap above napms above poll above select. */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#undef HAVE_SELECT
+#define HAVE_SELECT 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+#if HAVE_SELECT
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_POLL
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#if ! HAVE_STROPTS_H && ! HAVE_POLL_H
+/* We need a definition for struct pollfd, although it doesn't matter
+ what it contains. */
+struct pollfd
+{
+ int idummy;
+};
+#endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */
+#endif /* HAVE_POLL */
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER
+#include <time.h>
+#endif
+#endif
+
+void
+usysdep_pause ()
+{
+#if HAVE_NAPMS
+ napms (500);
+#endif /* HAVE_NAPMS */
+#if HAVE_NAP
+#if HAVE_HUNDREDTHS_NAP
+ nap (50L);
+#else
+ nap (500L);
+#endif /* ! HAVE_HUNDREDTHS_NAP */
+#endif /* HAVE_NAP */
+#if HAVE_USLEEP
+ usleep (500 * (long) 1000);
+#endif /* HAVE_USLEEP */
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ /* We need to pass an unused pollfd structure because poll checks
+ the address before checking the number of elements. */
+ poll (&sdummy, 0, 500);
+#endif /* HAVE_POLL */
+#if HAVE_SELECT
+ struct timeval s;
+
+ s.tv_sec = 0;
+ s.tv_usec = 500 * (long) 1000;
+ select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
+#if ! USE_SELECT_TIMER && ! HAVE_POLL
+ sleep (1);
+#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
+#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
+}
diff --git a/gnu/libexec/uucp/libunix/picksb.c b/gnu/libexec/uucp/libunix/picksb.c
new file mode 100644
index 00000000000..3fe5c6f585f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/picksb.c
@@ -0,0 +1,230 @@
+/* picksb.c
+ System dependent routines for uupick.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char picksb_rcsid[] = "$Id: picksb.c,v 1.1 1993/08/04 19:32:42 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+
+/* Local variables. */
+
+/* Directory of ~/receive/USER. */
+static DIR *qStopdir;
+
+/* Name of ~/receive/USER. */
+static char *zStopdir;
+
+/* Directory of ~/receive/USER/SYSTEM. */
+static DIR *qSsysdir;
+
+/* Name of system. */
+static char *zSsysdir;
+
+/* Prepare to get a list of all the file to uupick for this user. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_init (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ const char *zuser;
+
+ zuser = zsysdep_login_name ();
+
+ zStopdir = (char *) xmalloc (strlen (zpubdir)
+ + sizeof "/receive/"
+ + strlen (zuser));
+ sprintf (zStopdir, "%s/receive/%s", zpubdir, zuser);
+
+ qStopdir = opendir (zStopdir);
+ if (qStopdir == NULL && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zStopdir,
+ strerror (errno));
+ return FALSE;
+ }
+
+ qSsysdir = NULL;
+
+ return TRUE;
+}
+
+/* Return the next file from the uupick directories. */
+
+/*ARGSUSED*/
+char *
+zsysdep_uupick (zsysarg, zpubdir, pzfrom, pzfull)
+ const char *zsysarg;
+ const char *zpubdir;
+ char **pzfrom;
+ char **pzfull;
+{
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ while (qSsysdir == NULL)
+ {
+ const char *zsystem;
+ char *zdir;
+
+ if (qStopdir == NULL)
+ return NULL;
+
+ if (zsysarg != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ zsystem = zsysarg;
+ }
+ else
+ {
+ do
+ {
+ qentry = readdir (qStopdir);
+ if (qentry == NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ return NULL;
+ }
+ }
+ while (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0);
+
+ zsystem = qentry->d_name;
+ }
+
+ zdir = zbufalc (strlen (zStopdir) + strlen (zsystem) + sizeof "/");
+ sprintf (zdir, "%s/%s", zStopdir, zsystem);
+
+ qSsysdir = opendir (zdir);
+ if (qSsysdir == NULL)
+ {
+ if (errno != ENOENT && errno != ENOTDIR)
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ }
+ else
+ {
+ ubuffree (zSsysdir);
+ zSsysdir = zbufcpy (zsystem);
+ }
+
+ ubuffree (zdir);
+ }
+
+ qentry = readdir (qSsysdir);
+ if (qentry == NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ continue;
+ }
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+
+ *pzfrom = zbufcpy (zSsysdir);
+ *pzfull = zsappend3 (zStopdir, zSsysdir, qentry->d_name);
+ return zbufcpy (qentry->d_name);
+ }
+}
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_free (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ xfree ((pointer) zStopdir);
+ if (qStopdir != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ }
+ ubuffree (zSsysdir);
+ zSsysdir = NULL;
+ if (qSsysdir != NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ }
+
+ return TRUE;
+}
+
+/* Expand a local file name for uupick. */
+
+char *
+zsysdep_uupick_local_file (zfile)
+ const char *zfile;
+{
+ struct passwd *q;
+
+ /* If this does not start with a simple ~, pass it to
+ zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd
+ only uses the zpubdir argument if the file starts with a simple
+ ~, so it doesn't really matter what we pass for zpubdir. */
+ if (zfile[0] != '~'
+ || (zfile[1] != '/' && zfile[1] != '\0'))
+ return zsysdep_local_file_cwd (zfile, (const char *) NULL);
+
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "Can't get home directory");
+ return NULL;
+ }
+
+ if (zfile[1] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ return zsysdep_in_dir (q->pw_dir, zfile + 2);
+}
diff --git a/gnu/libexec/uucp/libunix/portnm.c b/gnu/libexec/uucp/libunix/portnm.c
new file mode 100644
index 00000000000..9eda4ab012b
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/portnm.c
@@ -0,0 +1,51 @@
+/* portnm.c
+ Get the port name of stdin. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_TCP
+#if HAVE_SYS_TYPES_TCP_H
+#include <sys/types.tcp.h>
+#endif
+#include <sys/socket.h>
+#endif
+
+#ifndef ttyname
+extern char *ttyname ();
+#endif
+
+/* Get the port name of standard input. I assume that Unix systems
+ generally support ttyname. If they don't, this function can just
+ return NULL. It uses getsockname to see whether standard input is
+ a TCP connection. */
+
+const char *
+zsysdep_port_name (ftcp_port)
+ boolean *ftcp_port;
+{
+ const char *z;
+
+ *ftcp_port = FALSE;
+
+#if HAVE_TCP
+ {
+ size_t clen;
+ struct sockaddr s;
+
+ clen = sizeof (struct sockaddr);
+ if (getsockname (0, &s, &clen) == 0)
+ *ftcp_port = TRUE;
+ }
+#endif /* HAVE_TCP */
+
+ z = ttyname (0);
+ if (z == NULL)
+ return NULL;
+ if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
+ return z + sizeof "/dev/" - 1;
+ else
+ return z;
+}
diff --git a/gnu/libexec/uucp/libunix/proctm.c b/gnu/libexec/uucp/libunix/proctm.c
new file mode 100644
index 00000000000..55cf96f0c97
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/proctm.c
@@ -0,0 +1,197 @@
+/* proctm.c
+ Get the time spent in the process.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+/* Prefer gettimeofday to ftime to times. */
+
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+#undef HAVE_TIMES
+#define HAVE_TIMES 0
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#undef HAVE_FTIME
+#define HAVE_FTIME 0
+#endif
+
+#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY)
+#include <time.h>
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+
+#if HAVE_FTIME
+#include <sys/timeb.h>
+#endif
+
+#if HAVE_TIMES
+
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+
+#if TIMES_DECLARATION_OK
+/* We use a macro to protect this because times really returns clock_t
+ and on some systems, such as Ultrix 4.0, clock_t is int. We don't
+ leave it out entirely because on some systems, such as System III,
+ the declaration is necessary for correct compilation. */
+#ifndef times
+extern long times ();
+#endif
+#endif /* TIMES_DECLARATION_OK */
+
+#ifdef _SC_CLK_TCK
+#define HAVE_SC_CLK_TCK 1
+#else
+#define HAVE_SC_CLK_TCK 0
+#endif
+
+/* TIMES_TICK may have been set in policy.h, or we may be able to get
+ it using sysconf. If neither is the case, try to find a useful
+ definition from the system header files. */
+#if TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK)
+#ifdef CLK_TCK
+#undef TIMES_TICK
+#define TIMES_TICK CLK_TCK
+#else /* ! defined (CLK_TCK) */
+#ifdef HZ
+#undef TIMES_TICK
+#define TIMES_TICK HZ
+#endif /* defined (HZ) */
+#endif /* ! defined (CLK_TCK) */
+#endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */
+
+#endif /* HAVE_TIMES */
+
+#ifndef time
+extern time_t time ();
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Get the time in seconds and microseconds; this need only work
+ within the process when called from the system independent code.
+ It is also called by ixsysdep_time. */
+
+long
+ixsysdep_process_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY
+ struct timeval stime;
+ struct timezone stz;
+
+ (void) gettimeofday (&stime, &stz);
+ if (pimicros != NULL)
+ *pimicros = (long) stime.tv_usec;
+ return (long) stime.tv_sec;
+#endif /* HAVE_GETTIMEOFDAY */
+
+#if HAVE_FTIME
+ static boolean fbad;
+
+ if (! fbad)
+ {
+ struct timeb stime;
+ static struct timeb slast;
+
+ (void) ftime (&stime);
+
+ /* On some systems, such as SCO 3.2.2, ftime can go backwards in
+ time. If we detect this, we switch to using time. */
+ if (slast.time != 0
+ && (stime.time < slast.time
+ || (stime.time == slast.time &&
+ stime.millitm < slast.millitm)))
+ fbad = TRUE;
+ else
+ {
+ slast = stime;
+ if (pimicros != NULL)
+ *pimicros = (long) stime.millitm * (long) 1000;
+ return (long) stime.time;
+ }
+ }
+
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* HAVE_FTIME */
+
+#if HAVE_TIMES
+ struct tms s;
+ long i;
+ static int itick;
+
+ if (itick == 0)
+ {
+#if TIMES_TICK == 0
+#if HAVE_SYSCONF && HAVE_SC_CLK_TCK
+ itick = (int) sysconf (_SC_CLK_TCK);
+#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+ const char *z;
+
+ z = getenv ("HZ");
+ if (z != NULL)
+ itick = (int) strtol (z, (char **) NULL, 10);
+
+ /* If we really couldn't get anything, just use 60. */
+ if (itick == 0)
+ itick = 60;
+#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+#else /* TIMES_TICK != 0 */
+ itick = TIMES_TICK;
+#endif /* TIMES_TICK == 0 */
+ }
+
+ i = (long) times (&s);
+ if (pimicros != NULL)
+ *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick);
+ return i / (long) itick;
+#endif /* HAVE_TIMES */
+
+#if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */
+}
diff --git a/gnu/libexec/uucp/libunix/recep.c b/gnu/libexec/uucp/libunix/recep.c
new file mode 100644
index 00000000000..84a211a7a94
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/recep.c
@@ -0,0 +1,197 @@
+/* recep.c
+ See whether a file has already been received.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+static char *zsreceived_name P((const struct uuconf_system *qsys,
+ const char *ztemp));
+
+/* These routines are used to see whether we have already received a
+ file in a previous UUCP connection. It is possible for the
+ acknowledgement of a received file to be lost. The sending system
+ will then now know that the file was correctly received, and will
+ send it again. This can be a problem particularly with protocols
+ which support channels, since they may send several small files in
+ a single window, all of which may be received correctly although
+ the sending system never sees the acknowledgement. If these files
+ involve an execution, the execution will happen twice, which will
+ be bad.
+
+ We use a simple system. For each file we want to remember, we
+ create an empty file names .Received/SYS/TEMP, where SYS is the
+ name of the system and TEMP is the name of the temporary file used
+ by the sender. If no temporary file is used by the sender, we
+ don't remember that we received the file. This is not perfect, but
+ execution files will always have a temporary file, so the most
+ important case is handled. Also, any file received from Taylor
+ UUCP 1.04 or greater will always have a temporary file. */
+
+/* Return the name we are going use for the marker, or NULL if we have
+ no name. */
+
+static char *
+zsreceived_name (qsys, ztemp)
+ const struct uuconf_system *qsys;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Received", qsys->uuconf_zname, ztemp);
+ else
+ return NULL;
+}
+
+/* Remember that we have already received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_remember_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ int o;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (fsysdep_make_dirs (zfile, TRUE))
+ {
+ ubuffree (zfile);
+ return FALSE;
+ }
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ }
+
+ ubuffree (zfile);
+
+ /* We don't have to actually put anything in the file; we just use
+ the name. This is more convenient than keeping a file with a
+ list of names. */
+ if (close (o) < 0)
+ {
+ ulog (LOG_ERROR, "fsysdep_remember_reception: close: %s",
+ strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* See if we have already received a file. Note that don't delete the
+ marker file here, because we need to know that the sending system
+ has received our denial first. This function returns TRUE if the
+ file has already been received, FALSE if it has not. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_already_received (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ struct stat s;
+ boolean fret;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return FALSE;
+ if (stat (zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+
+ /* Ignore the file (return FALSE) if it is over one week old. */
+ fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL);
+
+ if (fret)
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s",
+ zfile);
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Forget that we have received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_forget_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ if (remove (zfile) < 0
+ && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/remove.c b/gnu/libexec/uucp/libunix/remove.c
new file mode 100644
index 00000000000..b695888ffaa
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/remove.c
@@ -0,0 +1,13 @@
+/* remove.c
+ Remove a file (Unix specific implementation). */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+int
+remove (z)
+ const char *z;
+{
+ return unlink (z);
+}
diff --git a/gnu/libexec/uucp/libunix/rename.c b/gnu/libexec/uucp/libunix/rename.c
new file mode 100644
index 00000000000..0947ef5cfae
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rename.c
@@ -0,0 +1,27 @@
+/* rename.c
+ Rename a file to a new name (Unix specific implementation). */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* This implementation will not work on directories, but fortunately
+ we never want to rename directories. */
+
+int
+rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
diff --git a/gnu/libexec/uucp/libunix/rmdir.c b/gnu/libexec/uucp/libunix/rmdir.c
new file mode 100644
index 00000000000..12a7b9e4507
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rmdir.c
@@ -0,0 +1,43 @@
+/* rmdir.c
+ Remove a directory on a system which doesn't have the rmdir system
+ call. This is only called by uupick, which is not setuid, so we
+ don't have to worry about the problems of invoking the setuid
+ /bin/rmdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+rmdir (zdir)
+ const char *zdir;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = RMDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ TRUE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EBUSY;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/run.c b/gnu/libexec/uucp/libunix/run.c
new file mode 100644
index 00000000000..e2191962837
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/run.c
@@ -0,0 +1,75 @@
+/* run.c
+ Run a program.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Start up a new program and end the current one. We don't have to
+ worry about SIGHUP because the current process is either not a
+ process group leader (uucp, uux) or it does not have a controlling
+ terminal (uucico). */
+
+boolean
+fsysdep_run (zprogram, zarg1, zarg2)
+ const char *zprogram;
+ const char *zarg1;
+ const char *zarg2;
+{
+ char *zlib;
+ const char *azargs[4];
+ int aidescs[3];
+ pid_t ipid;
+
+ zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram));
+ sprintf (zlib, "%s/%s", SBINDIR, zprogram);
+
+ azargs[0] = zlib;
+ azargs[1] = zarg1;
+ azargs[2] = zarg2;
+ azargs[3] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ /* We pass fsetuid and fshell as TRUE, which permits uucico and
+ uuxqt to be replaced by (non-setuid) shell scripts. */
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ ubuffree (zlib);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/seq.c b/gnu/libexec/uucp/libunix/seq.c
new file mode 100644
index 00000000000..2e01233022a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/seq.c
@@ -0,0 +1,126 @@
+/* seq.c
+ Get and increment the conversation sequence number for a system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Get the current conversation sequence number for a remote system,
+ and increment it for next time. The conversation sequence number
+ is kept in a file named for the system in the directory .Sequence
+ in the spool directory. This is not compatible with other versions
+ of UUCP, but it makes more sense to me. The sequence file is only
+ used if specified in the information for that system. */
+
+long
+ixsysdep_get_sequence (qsys)
+ const struct uuconf_system *qsys;
+{
+ FILE *e;
+ char *zname;
+ struct stat s;
+ long iseq;
+
+ /* This will only be called when the system is locked anyhow, so there
+ is no need to use a separate lock for the conversation sequence
+ file. */
+ zname = zsysdep_in_dir (".Sequence", qsys->uuconf_zname);
+
+ iseq = 0;
+ if (stat (zname, &s) == 0)
+ {
+ boolean fok;
+ char *zline;
+ size_t cline;
+
+ /* The file should only be readable and writable by uucp. */
+ if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ {
+ ulog (LOG_ERROR,
+ "Bad file protection for conversation sequence file");
+ ubuffree (zname);
+ return -1;
+ }
+
+ e = fopen (zname, "r+");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return -1;
+ }
+
+ ubuffree (zname);
+
+ fok = TRUE;
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ fok = FALSE;
+ else
+ {
+ char *zend;
+
+ iseq = strtol (zline, &zend, 10);
+ if (zend == zline)
+ fok = FALSE;
+ }
+
+ xfree ((pointer) zline);
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "Bad format for conversation sequence file");
+ (void) fclose (e);
+ return -1;
+ }
+
+ rewind (e);
+ }
+ else
+ {
+ e = esysdep_fopen (zname, FALSE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return -1;
+ }
+
+ ++iseq;
+
+ fprintf (e, "%ld", iseq);
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return -1;
+ }
+
+ return iseq;
+}
diff --git a/gnu/libexec/uucp/libunix/serial.c b/gnu/libexec/uucp/libunix/serial.c
new file mode 100644
index 00000000000..2b02cd5aaa5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/serial.c
@@ -0,0 +1,2977 @@
+/* serial.c
+ The serial port communication routines for Unix.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char serial_rcsid[] = "$Id: serial.c,v 1.1 1993/08/04 19:32:52 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "conn.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_TLI
+#if HAVE_TIUSER_H
+#include <tiuser.h>
+#else /* ! HAVE_TIUSER_H */
+#if HAVE_XTI_H
+#include <xti.h>
+#endif /* HAVE_XTI_H */
+#endif /* ! HAVE_TIUSER_H */
+#endif /* HAVE_TLI */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_BSD_TTY
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY
+#include <time.h>
+#endif
+#endif
+
+#if HAVE_STRIP_BUG && HAVE_BSD_TTY
+#include <termio.h>
+#endif
+
+#if HAVE_SVR4_LOCKFILES
+/* Get the right definitions for major and minor. */
+#if MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif /* MAJOR_IN_MKDEV */
+#if MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif /* MAJOR_IN_SYSMACROS */
+#if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS
+#ifndef major
+#define major(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef minor
+#define minor(i) ((i) & 0xff)
+#endif
+#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
+#endif /* HAVE_SVR4_LOCKFILES */
+
+/* Get definitions for both O_NONBLOCK and O_NDELAY. */
+#ifndef O_NDELAY
+#ifdef FNDELAY
+#define O_NDELAY FNDELAY
+#else /* ! defined (FNDELAY) */
+#define O_NDELAY 0
+#endif /* ! defined (FNDELAY) */
+#endif /* ! defined (O_NDELAY) */
+
+#ifndef O_NONBLOCK
+#ifdef FNBLOCK
+#define O_NONBLOCK FNBLOCK
+#else /* ! defined (FNBLOCK) */
+#define O_NONBLOCK 0
+#endif /* ! defined (FNBLOCK) */
+#endif /* ! defined (O_NONBLOCK) */
+
+#if O_NDELAY == 0 && O_NONBLOCK == 0
+ #error No way to do nonblocking I/O
+#endif
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Make sure we have a definition for MAX_INPUT. */
+#ifndef MAX_INPUT
+#define MAX_INPUT (256)
+#endif
+
+/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
+ Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
+ terminal before we know that it is unlocked. */
+#ifdef TIOCSINUSE
+#define HAVE_TIOCSINUSE 1
+#else
+#ifdef TIOCEXCL
+#define HAVE_TIOCEXCL 1
+#endif
+#endif
+
+#if HAVE_TLI
+extern int t_errno;
+extern char *t_errlist[];
+extern int t_nerr;
+#endif
+
+/* Determine bits to clear for the various terminal control fields for
+ HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */
+#if HAVE_SYSV_TERMIO
+#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
+ | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
+ | IXON | IXANY | IXOFF)
+#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
+ | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
+ | VTDLY | FFDLY)
+#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
+ | ECHONL | NOFLSH)
+#endif
+#if HAVE_POSIX_TERMIOS
+#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
+ | INLCR | INPCK | ISTRIP | IXOFF | IXON \
+ | PARMRK)
+#define ICLEAR_OFLAG (OPOST)
+#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
+ | ISIG | NOFLSH | TOSTOP)
+#endif
+
+/* Local functions. */
+
+static RETSIGTYPE usalarm P((int isig));
+static boolean fsserial_init P((struct sconnection *qconn,
+ const struct sconncmds *qcmds,
+ const char *zdevice));
+static void usserial_free P((struct sconnection *qconn));
+static boolean fsserial_lockfile P((boolean flok,
+ const struct sconnection *));
+static boolean fsserial_lock P((struct sconnection *qconn,
+ boolean fin));
+static boolean fsserial_unlock P((struct sconnection *qconn));
+static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsdirect_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsblock P((struct ssysdep_conn *q, boolean fblock));
+static boolean fsserial_close P((struct ssysdep_conn *q));
+static boolean fsstdin_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsmodem_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsdirect_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsserial_reset P((struct sconnection *qconn));
+static boolean fsstdin_reset P((struct sconnection *qconn));
+static boolean fsstdin_read P((struct sconnection *qconn,
+ char *zbuf, size_t *pclen, size_t cmin,
+ int ctimeout, boolean freport));
+static boolean fsstdin_write P((struct sconnection *qconn,
+ const char *zwrite, size_t cwrite));
+static boolean fsserial_break P((struct sconnection *qconn));
+static boolean fsstdin_break P((struct sconnection *qconn));
+static boolean fsserial_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsstdin_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsmodem_carrier P((struct sconnection *qconn,
+ boolean fcarrier));
+static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
+static boolean fsstdin_chat P((struct sconnection *qconn,
+ char **pzprog));
+static long isserial_baud P((struct sconnection *qconn));
+
+/* The command table for standard input ports. */
+
+static const struct sconncmds sstdincmds =
+{
+ usserial_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ fsstdin_open,
+ fsstdin_close,
+ fsstdin_reset,
+ NULL, /* pfdial */
+ fsstdin_read,
+ fsstdin_write,
+ fsysdep_conn_io,
+ fsstdin_break,
+ fsstdin_set,
+ NULL, /* pfcarrier */
+ fsstdin_chat,
+ isserial_baud
+};
+
+/* The command table for modem ports. */
+
+static const struct sconncmds smodemcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsmodem_open,
+ fsmodem_close,
+ fsserial_reset,
+ fmodem_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ fsmodem_carrier,
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* The command table for direct ports. */
+
+static const struct sconncmds sdirectcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsdirect_open,
+ fsdirect_close,
+ fsserial_reset,
+ NULL, /* pfdial */
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* If the system will let us set both O_NDELAY and O_NONBLOCK, we do
+ so. This is because some ancient drivers on some systems appear to
+ look for one but not the other. Some other systems will give an
+ EINVAL error if we attempt to set both, so we use a static global
+ to hold the value we want to set. If we get EINVAL, we change the
+ global and try again (if some system gives an error other than
+ EINVAL, the code will have to be modified). */
+static int iSunblock = O_NDELAY | O_NONBLOCK;
+
+/* This code handles SIGALRM. See the discussion above
+ fsysdep_conn_read. Normally we ignore SIGALRM, but the handler
+ will temporarily be set to this function, which should set fSalarm
+ and then either longjmp or schedule another SIGALRM. fSalarm is
+ never referred to outside of this file, but we don't make it static
+ to try to fool compilers which don't understand volatile. */
+
+volatile sig_atomic_t fSalarm;
+
+static RETSIGTYPE
+usalarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, usalarm);
+#endif
+
+ fSalarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ longjmp (sSjmp_buf, 1);
+#else
+ alarm (1);
+#endif
+}
+
+/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
+ SIGPIPE and another to restore the original state. When these
+ functions are called (in fsysdep_modem_close) SIGHUP is being
+ ignored. The routines are isblocksigs, which returns a value of
+ type HELD_SIG_MASK and usunblocksigs which takes a single argument
+ of type HELD_SIG_MASK. */
+
+#if HAVE_SIGPROCMASK
+
+/* Use the POSIX sigprocmask call. */
+
+#define HELD_SIG_MASK sigset_t
+
+static sigset_t isblocksigs P((void));
+
+static sigset_t
+isblocksigs ()
+{
+ sigset_t sblock, sold;
+
+ /* These expressions need an extra set of parentheses to avoid a bug
+ in SCO 3.2.2. */
+ (void) (sigemptyset (&sblock));
+ (void) (sigaddset (&sblock, SIGINT));
+ (void) (sigaddset (&sblock, SIGQUIT));
+ (void) (sigaddset (&sblock, SIGTERM));
+ (void) (sigaddset (&sblock, SIGPIPE));
+
+ (void) sigprocmask (SIG_BLOCK, &sblock, &sold);
+ return sold;
+}
+
+#define usunblocksigs(s) \
+ ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
+
+#else /* ! HAVE_SIGPROCMASK */
+#if HAVE_SIGBLOCK
+
+/* Use the BSD sigblock and sigsetmask calls. */
+
+#define HELD_SIG_MASK int
+
+#ifndef sigmask
+#define sigmask(i) (1 << ((i) - 1))
+#endif
+
+#define isblocksigs() \
+ sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
+ | sigmask (SIGTERM) | sigmask (SIGPIPE))
+
+#define usunblocksigs(i) ((void) sigsetmask (i))
+
+#else /* ! HAVE_SIGBLOCK */
+
+#if HAVE_SIGHOLD
+
+/* Use the SVR3 sighold and sigrelse calls. */
+
+#define HELD_SIG_MASK int
+
+static int isblocksigs P((void));
+
+static int
+isblocksigs ()
+{
+ sighold (SIGINT);
+ sighold (SIGQUIT);
+ sighold (SIGTERM);
+ sighold (SIGPIPE);
+ return 0;
+}
+
+static void usunblocksigs P((int));
+
+/*ARGSUSED*/
+static void
+usunblocksigs (i)
+ int i;
+{
+ sigrelse (SIGINT);
+ sigrelse (SIGQUIT);
+ sigrelse (SIGTERM);
+ sigrelse (SIGPIPE);
+}
+
+#else /* ! HAVE_SIGHOLD */
+
+/* We have no way to block signals. This system will suffer from a
+ race condition in fsysdep_modem_close. */
+
+#define HELD_SIG_MASK int
+
+#define isblocksigs() 0
+
+#define usunblocksigs(i)
+
+#endif /* ! HAVE_SIGHOLD */
+#endif /* ! HAVE_SIGBLOCK */
+#endif /* ! HAVE_SIGPROCMASK */
+
+/* Initialize a connection for use on a serial port. */
+
+static boolean
+fsserial_init (qconn, qcmds, zdevice)
+ struct sconnection *qconn;
+ const struct sconncmds *qcmds;
+ const char *zdevice;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ if (zdevice == NULL
+ && qconn->qport != NULL
+ && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ zdevice = qconn->qport->uuconf_zname;
+ if (zdevice == NULL)
+ q->zdevice = NULL;
+ else if (*zdevice == '/')
+ q->zdevice = zbufcpy (zdevice);
+ else
+ {
+ size_t clen;
+
+ clen = strlen (zdevice);
+ q->zdevice = zbufalc (sizeof "/dev/" + clen);
+ memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1);
+ memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen);
+ q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
+ }
+ q->o = -1;
+ q->ftli = FALSE;
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = qcmds;
+ return TRUE;
+}
+
+/* Initialize a connection for use on standard input. */
+
+boolean
+fsysdep_stdin_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sstdincmds, (const char *) NULL);
+}
+
+/* Initialize a connection for use on a modem port. */
+
+boolean
+fsysdep_modem_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &smodemcmds,
+ qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
+}
+
+/* Initialize a connection for use on a direct port. */
+
+boolean
+fsysdep_direct_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sdirectcmds,
+ qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
+}
+
+/* Free up a serial port. */
+
+static void
+usserial_free (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ ubuffree (qsysdep->zdevice);
+ xfree ((pointer) qsysdep);
+ qconn->psysdep = NULL;
+}
+
+/* This routine is used for both locking and unlocking. It is the
+ only routine which knows how to translate a device name into the
+ name of a lock file. If it can't figure out a name, it does
+ nothing and returns TRUE. */
+
+static boolean
+fsserial_lockfile (flok, qconn)
+ boolean flok;
+ const struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+ char *zalc;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qconn->qport == NULL)
+ z = NULL;
+ else
+ z = qconn->qport->uuconf_zlockname;
+ zalc = NULL;
+ if (z == NULL)
+ {
+#if ! HAVE_SVR4_LOCKFILES
+ {
+ const char *zbase;
+ size_t clen;
+
+ zbase = strrchr (qsysdep->zdevice, '/') + 1;
+ clen = strlen (zbase);
+ zalc = zbufalc (sizeof "LCK.." + clen);
+ memcpy (zalc, "LCK..", sizeof "LCK.." - 1);
+ memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1);
+#if HAVE_SCO_LOCKFILES
+ {
+ char *zl;
+
+ for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++)
+ if (isupper (*zl))
+ *zl = tolower (*zl);
+ }
+#endif
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+#if HAVE_SVR4_LOCKFILES
+ {
+ struct stat s;
+
+ if (stat (qsysdep->zdevice, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ zalc = zbufalc (sizeof "LK.123.123.123");
+ sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
+ major (s.st_rdev), minor (s.st_rdev));
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+ z = strrchr (qsysdep->zdevice, '/') + 1;
+#endif /* ! HAVE_SVR4_LOCKFILES */
+#endif /* ! HAVE_SVR4_LOCKFILES */
+ }
+
+ if (flok)
+ fret = fsdo_lock (z, FALSE, (boolean *) NULL);
+ else
+ fret = fsdo_unlock (z, FALSE);
+
+#if HAVE_COHERENT_LOCKFILES
+ if (fret)
+ {
+ if (flok)
+ {
+ if (lockttyexist (z))
+ {
+ ulog (LOG_NORMAL, "%s: port already locked");
+ fret = FALSE;
+ }
+ else
+ fret = fscoherent_disable_tty (z, &qsysdep->zenable);
+ }
+ else
+ {
+ fret = TRUE;
+ if (qsysdep->zenable != NULL)
+ {
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/etc/enable";
+ azargs[1] = qsysdep->zenable;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE,
+ (const char *) NULL, TRUE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s",
+ qsysdep->zenable, strerror (errno));
+ fret = FALSE;
+ }
+ else
+ {
+ if (ixswait ((unsigned long) ipid, (const char *) NULL)
+ == 0)
+ fret = TRUE;
+ else
+ fret = FALSE;
+ }
+ ubuffree (qsysdep->zenable);
+ qsysdep->zenable = NULL;
+ }
+ }
+ }
+#endif /* HAVE_COHERENT_LOCKFILES */
+
+ ubuffree (zalc);
+ return fret;
+}
+
+/* If we can mark a modem line in use, then when we lock a port we
+ must open it and mark it in use. We can't wait until the actual
+ open because we can't fail out if it is locked then. */
+
+static boolean
+fsserial_lock (qconn, fin)
+ struct sconnection *qconn;
+ boolean fin;
+{
+ if (! fsserial_lockfile (TRUE, qconn))
+ return FALSE;
+
+#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
+ /* Open the line and try to mark it in use. */
+ {
+ struct ssysdep_conn *qsysdep;
+ int iflag;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (fin)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag);
+ if (qsysdep->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ qsysdep->o = open (qsysdep->zdevice,
+ O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (qsysdep->o < 0)
+ {
+ if (errno != EBUSY)
+ ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+ }
+
+#if HAVE_TIOCSINUSE
+ /* If we can't mark it in use, return FALSE to indicate that the
+ lock failed. */
+ if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0)
+ {
+ if (errno != EALREADY)
+ ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+#endif
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (qsysdep->o, TIOCSCTTY, 0);
+#endif
+ }
+#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
+
+ return TRUE;
+}
+
+/* Unlock a modem or direct port. */
+
+static boolean
+fsserial_unlock (qconn)
+ struct sconnection *qconn;
+{
+ boolean fret;
+ struct ssysdep_conn *qsysdep;
+
+ fret = TRUE;
+
+ /* The file may have been opened by fsserial_lock, so close it here
+ if necessary. */
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qsysdep->o >= 0)
+ {
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ if (close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->o = -1;
+ }
+
+ if (! fsserial_lockfile (FALSE, qconn))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Open a serial line. This sets the terminal settings. We begin in
+ seven bit mode and let the protocol change if necessary. */
+
+#if HAVE_POSIX_TERMIOS
+typedef speed_t baud_code;
+#else
+typedef int baud_code;
+#endif
+
+static struct sbaud_table
+{
+ baud_code icode;
+ long ibaud;
+} asSbaud_table[] =
+{
+ { B50, 50 },
+ { B75, 75 },
+ { B110, 110 },
+ { B134, 134 },
+ { B150, 150 },
+ { B200, 200 },
+ { B300, 300 },
+ { B600, 600 },
+ { B1200, 1200 },
+ { B1800, 1800 },
+ { B2400, 2400 },
+ { B4800, 4800 },
+ { B9600, 9600 },
+#ifdef B19200
+ { B19200, 19200 },
+#else /* ! defined (B19200) */
+#ifdef EXTA
+ { EXTA, 19200 },
+#endif /* EXTA */
+#endif /* ! defined (B19200) */
+#ifdef B38400
+ { B38400, 38400 },
+#else /* ! defined (B38400) */
+#ifdef EXTB
+ { EXTB, 38400 },
+#endif /* EXTB */
+#endif /* ! defined (B38400) */
+#ifdef B57600
+ { B57600, 57600 },
+#endif
+#ifdef B76800
+ { B76800, 76800 },
+#endif
+#ifdef B115200
+ { B115200, 115200 },
+#endif
+ { B0, 0 }
+};
+
+#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+/* Hold the MIN value for the terminal to avoid setting it
+ unnecessarily. */
+static int cSmin;
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+static boolean
+fsserial_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+ baud_code ib;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (q->zdevice != NULL)
+ ulog_device (strrchr (q->zdevice, '/') + 1);
+ else
+ {
+ const char *zport;
+ boolean fdummy;
+
+#if DEBUG > 0
+ if (qconn->qport != NULL &&
+ qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ ulog (LOG_FATAL, "fsserial_open: Can't happen");
+#endif
+ zport = zsysdep_port_name (&fdummy);
+ if (zport != NULL)
+ ulog_device (zport);
+ }
+
+ ib = B0;
+ if (ibaud != 0)
+ {
+ int i;
+
+ for (i = 0; i < CBAUD_TABLE; i++)
+ if (asSbaud_table[i].ibaud == ibaud)
+ break;
+ if (i >= CBAUD_TABLE)
+ {
+ ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
+ return FALSE;
+ }
+ ib = asSbaud_table[i].icode;
+ }
+
+ /* The port may have already been opened by the locking routine. */
+ if (q->o < 0)
+ {
+ int iflag;
+
+ if (fwait)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ q->o = open (q->zdevice, O_RDWR | iflag);
+ if (q->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ q->o = open (q->zdevice, O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (q->o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (q->o, TIOCSCTTY, 0);
+#endif
+ }
+
+ /* Get the port flags, and make sure the ports are blocking. */
+
+ q->iflags = fcntl (q->o, F_GETFL, 0);
+ if (q->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ q->istdout_flags = -1;
+
+ if (! fgetterminfo (q->o, &q->sorig))
+ {
+ q->fterminal = FALSE;
+ return TRUE;
+ }
+
+ q->fterminal = TRUE;
+
+ q->snew = q->sorig;
+
+#if HAVE_BSD_TTY
+
+ q->snew.stty.sg_flags = RAW | ANYP;
+ if (ibaud == 0)
+ ib = q->snew.stty.sg_ospeed;
+ else
+ {
+ q->snew.stty.sg_ispeed = ib;
+ q->snew.stty.sg_ospeed = ib;
+ }
+
+ /* We don't want to receive any interrupt characters. */
+ q->snew.stchars.t_intrc = -1;
+ q->snew.stchars.t_quitc = -1;
+ q->snew.stchars.t_eofc = -1;
+ q->snew.stchars.t_brkc = -1;
+ q->snew.sltchars.t_suspc = -1;
+ q->snew.sltchars.t_rprntc = -1;
+ q->snew.sltchars.t_dsuspc = -1;
+ q->snew.sltchars.t_flushc = -1;
+ q->snew.sltchars.t_werasc = -1;
+ q->snew.sltchars.t_lnextc = -1;
+
+#ifdef NTTYDISC
+ /* We want to use the ``new'' terminal driver so that we can use the
+ local mode bits to control XON/XOFF. */
+ {
+ int iparam;
+
+ if (ioctl (q->o, TIOCGETD, &iparam) >= 0
+ && iparam != NTTYDISC)
+ {
+ iparam = NTTYDISC;
+ (void) ioctl (q->o, TIOCSETD, &iparam);
+ }
+ }
+#endif
+
+#ifdef TIOCHPCL
+ /* When the file is closed, hang up the line. This is a safety
+ measure in case the program crashes. */
+ (void) ioctl (q->o, TIOCHPCL, 0);
+#endif
+
+#ifdef TIOCFLUSH
+ {
+ int iparam;
+
+ /* Flush pending input. */
+#ifdef FREAD
+ iparam = FREAD;
+#else
+ iparam = 0;
+#endif
+ (void) ioctl (q->o, TIOCFLUSH, &iparam);
+ }
+#endif /* TIOCFLUSH */
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ if (ibaud == 0)
+ ib = q->snew.c_cflag & CBAUD;
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ q->snew.c_cflag |= (ib | ISET_CFLAG);
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+#ifdef TCFLSH
+ /* Flush pending input. */
+ (void) ioctl (q->o, TCFLSH, 0);
+#endif
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ if (ibaud == 0)
+ ib = cfgetospeed (&q->snew);
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ q->snew.c_cflag |= ISET_CFLAG;
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+ (void) cfsetospeed (&q->snew, ib);
+ (void) cfsetispeed (&q->snew, ib);
+
+ /* Flush pending input. */
+ (void) tcflush (q->o, TCIFLUSH);
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (ibaud != 0)
+ q->ibaud = ibaud;
+ else
+ {
+ int i;
+
+ q->ibaud = (long) 1200;
+ for (i = 0; i < CBAUD_TABLE; i++)
+ {
+ if (asSbaud_table[i].icode == ib)
+ {
+ q->ibaud = asSbaud_table[i].ibaud;
+ break;
+ }
+ }
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsserial_open: Baud rate is %ld", q->ibaud);
+ }
+
+ return TRUE;
+}
+
+/* Open a standard input port. The code alternates q->o between 0 and
+ 1 as appropriate. It is always 0 before any call to fsblock. */
+
+static boolean
+fsstdin_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+ q->o = 0;
+ if (! fsserial_open (qconn, ibaud, fwait))
+ return FALSE;
+ q->istdout_flags = fcntl (1, F_GETFL, 0);
+ if (q->istdout_flags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Open a modem port. */
+
+static boolean
+fsmodem_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Open a direct port. */
+
+static boolean
+fsdirect_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Change the blocking status of the port. We keep track of the
+ current blocking status to avoid calling fcntl unnecessarily; fcntl
+ turns out to be surprisingly expensive, at least on Ultrix. */
+
+static boolean
+fsblock (qs, fblock)
+ struct ssysdep_conn *qs;
+ boolean fblock;
+{
+ int iwant;
+ int isys;
+
+ if (fblock)
+ iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->iflags | iSunblock;
+
+ if (iwant == qs->iflags)
+ return TRUE;
+
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ if (isys < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ iwant = qs->iflags | O_NONBLOCK;
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ }
+#endif
+ if (isys < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ }
+
+ qs->iflags = iwant;
+
+ if (qs->istdout_flags >= 0)
+ {
+ if (fblock)
+ iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->istdout_flags | iSunblock;
+
+ if (fcntl (1, F_SETFL, iwant) < 0)
+ {
+ /* We don't bother to fix up iSunblock here, since we
+ succeeded above. */
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+
+ qs->istdout_flags = iwant;
+ }
+
+ return TRUE;
+}
+
+/* Close a serial port. */
+
+static boolean
+fsserial_close (q)
+ struct ssysdep_conn *q;
+{
+ if (q->o >= 0)
+ {
+ /* Use a 30 second timeout to avoid hanging while draining
+ output. */
+ if (q->fterminal)
+ {
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (q->o, &q->sorig);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we timed out, use the non draining call. Hopefully
+ this can't hang. */
+ if (fSalarm)
+ (void) fsetterminfo (q->o, &q->sorig);
+ }
+
+#ifdef TIOCNOTTY
+ /* We don't want this as our controlling terminal any more, so
+ get rid of it. This is necessary because we don't want to
+ open /dev/tty, since that can confuse the serial port locking
+ on some computers. */
+ (void) ioctl (q->o, TIOCNOTTY, (char *) NULL);
+#endif
+
+ (void) close (q->o);
+ q->o = -1;
+
+ /* Sleep to give the terminal a chance to settle, in case we are
+ about to call out again. */
+ sleep (2);
+ }
+
+ return TRUE;
+}
+
+/* Close a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ (void) close (1);
+ (void) close (2);
+ qsysdep->o = 0;
+ return fsserial_close (qsysdep);
+}
+
+/* Close a modem port. */
+
+static boolean
+fsmodem_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+ struct uuconf_dialer sdialer;
+ const struct uuconf_chat *qchat;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ fret = TRUE;
+
+ /* Figure out the dialer so that we can run the complete or abort
+ chat scripts. */
+ if (qdialer == NULL)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ {
+ const char *zdialer;
+ int iuuconf;
+
+ zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
+ iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
+ if (iuuconf == UUCONF_SUCCESS)
+ qdialer = &sdialer;
+ else
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ }
+ }
+ else
+ qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
+ }
+
+ /* Get the complete or abort chat script to use. */
+ qchat = NULL;
+ if (qdialer != NULL)
+ {
+ if (fsuccess)
+ qchat = &qdialer->uuconf_scomplete;
+ else
+ qchat = &qdialer->uuconf_sabort;
+ }
+
+ if (qchat != NULL
+ && (qchat->uuconf_pzprogram != NULL
+ || qchat->uuconf_pzchat != NULL))
+ {
+ boolean fsighup_ignored;
+ HELD_SIG_MASK smask;
+ int i;
+ sig_atomic_t afhold[INDEXSIG_COUNT];
+
+ /* We're no longer interested in carrier. */
+ (void) fsmodem_carrier (qconn, FALSE);
+
+ /* The port I/O routines check whether any signal has been
+ received, and abort if one has. While we are closing down
+ the modem, we don't care if we received a signal in the past,
+ but we do care if we receive a new signal (otherwise it would
+ be difficult to kill a uucico which was closing down a
+ modem). We never care if we get SIGHUP at this point. So we
+ turn off SIGHUP, remember what signals we've already seen,
+ and clear our notion of what signals we've seen. We have to
+ block the signals while we remember and clear the array,
+ since we might otherwise miss a signal which occurred between
+ the copy and the clear (old systems can't block signals; they
+ will just have to suffer the race). */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
+ smask = isblocksigs ();
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ {
+ afhold[i] = afSignal[i];
+ afSignal[i] = FALSE;
+ }
+ usunblocksigs (smask);
+
+ if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL,
+ (const struct uuconf_dialer *) NULL, (const char *) NULL,
+ FALSE, qconn->qport->uuconf_zname,
+ qsysdep->ibaud))
+ fret = FALSE;
+
+ /* Restore the old signal array and the SIGHUP handler. It is
+ not necessary to block signals here, since all we are doing
+ is exactly what the signal handler itself would do if the
+ signal occurred. */
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ if (afhold[i])
+ afSignal[i] = TRUE;
+ if (! fsighup_ignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+ if (qdialer != NULL
+ && qdialer == &sdialer)
+ (void) uuconf_dialer_free (puuconf, &sdialer);
+
+#if ! HAVE_RESET_BUG
+ /* Reset the terminal to make sure we drop DTR. It should be
+ dropped when we close the descriptor, but that doesn't seem to
+ happen on some systems. Use a 30 second timeout to avoid hanging
+ while draining output. */
+ if (qsysdep->fterminal)
+ {
+#if HAVE_BSD_TTY
+ qsysdep->snew.stty.sg_ispeed = B0;
+ qsysdep->snew.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ (void) cfsetospeed (&qsysdep->snew, B0);
+#endif
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* Let the port settle. */
+ sleep (2);
+ }
+#endif /* ! HAVE_RESET_BUG */
+
+ if (! fsserial_close (qsysdep))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Close a direct port. */
+
+/*ARGSUSED*/
+static boolean
+fsdirect_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
+}
+
+/* Reset a serial port by hanging up. */
+
+static boolean
+fsserial_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+ sterminal sbaud;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ sbaud = q->snew;
+
+#if HAVE_BSD_TTY
+ sbaud.stty.sg_ispeed = B0;
+ sbaud.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ if (cfsetospeed (&sbaud, B0) < 0)
+ {
+ ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno));
+ return FALSE;
+ }
+#endif
+
+ if (! fsetterminfodrain (q->o, &sbaud))
+ {
+ ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ /* Give the terminal a chance to settle. */
+ sleep (2);
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Reset a standard input port. */
+
+static boolean
+fsstdin_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_reset (qconn);
+}
+
+/* Begin dialing out on a modem port. This opens the dialer device if
+ there is one. */
+
+boolean
+fsysdep_modem_begin_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+#ifdef TIOCMODEM
+ /* If we can tell the modem to obey modem control, do so. */
+ {
+ int iperm;
+
+ iperm = 0;
+ (void) ioctl (qsysdep->o, TIOCMODEM, &iperm);
+ }
+#endif /* TIOCMODEM */
+
+ /* If we supposed to toggle DTR, do so. */
+
+ if (qdial->uuconf_fdtr_toggle)
+ {
+#ifdef TIOCCDTR
+ (void) ioctl (qsysdep->o, TIOCCDTR, 0);
+ sleep (2);
+ (void) ioctl (qsysdep->o, TIOCSDTR, 0);
+#else /* ! defined (TIOCCDTR) */
+ (void) fconn_reset (qconn);
+#endif /* ! defined (TIOCCDTR) */
+
+ if (qdial->uuconf_fdtr_toggle_wait)
+ sleep (2);
+ }
+
+ if (! fsmodem_carrier (qconn, FALSE))
+ return FALSE;
+
+ /* Open the dial device if there is one. */
+ z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device;
+ if (z != NULL)
+ {
+ char *zfree;
+ int o;
+
+ qsysdep->ohold = qsysdep->o;
+
+ zfree = NULL;
+ if (*z != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (z));
+ sprintf (zfree, "/dev/%s", z);
+ z = zfree;
+ }
+
+ o = open ((char *) z, O_RDWR | O_NOCTTY);
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+ ubuffree (zfree);
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return FALSE;
+ }
+
+ qsysdep->o = o;
+ }
+
+ return TRUE;
+}
+
+/* Tell the port to require or not require carrier. On BSD this uses
+ TIOCCAR and TIOCNCAR, which I assume are generally supported (it
+ can also use the LNOMDM bit supported by IS68K Unix). On System V
+ it resets or sets CLOCAL. We only require carrier if the port
+ supports it. This will only be called with fcarrier TRUE if the
+ dialer supports carrier. */
+
+static boolean
+fsmodem_carrier (qconn, fcarrier)
+ struct sconnection *qconn;
+ boolean fcarrier;
+{
+ register struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ if (fcarrier)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier)
+ {
+#ifdef TIOCCAR
+ /* Tell the modem to pay attention to carrier. */
+ if (ioctl (q->o, TIOCCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into nonlocal mode. */
+ q->snew.c_cflag &=~ CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+ }
+ else
+ {
+#ifdef TIOCNCAR
+ /* Tell the modem to ignore carrier. */
+ if (ioctl (q->o, TIOCNCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCNCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIS, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into local mode (ignore carrier) to start the chat
+ script. */
+ q->snew.c_cflag |= CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+
+#if HAVE_CLOCAL_BUG
+ /* On SCO and AT&T UNIX PC you have to reopen the port. */
+ {
+ int onew;
+
+ onew = open (q->zdevice, O_RDWR);
+ if (onew < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno));
+ return FALSE;
+ }
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (onew);
+ return FALSE;
+ }
+
+ (void) close (q->o);
+ q->o = onew;
+ }
+#endif /* HAVE_CLOCAL_BUG */
+
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+
+ return TRUE;
+}
+
+/* Finish dialing out on a modem by closing any dialer device and waiting
+ for carrier. */
+
+boolean
+fsysdep_modem_end_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
+ {
+ (void) close (q->o);
+ q->o = q->ohold;
+ }
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier
+ && qdial->uuconf_fcarrier)
+ {
+ /* Tell the port that we need carrier. */
+ if (! fsmodem_carrier (qconn, TRUE))
+ return FALSE;
+
+#ifdef TIOCWONLINE
+
+ /* We know how to wait for carrier, so do so. */
+
+ /* If we already got a signal, just quit now. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* This bit of code handles signals just like fsysdep_conn_read
+ does. See that function for a longer explanation. */
+
+ /* Use fsysdep_catch to handle a longjmp from the signal
+ handler. */
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ /* Start catching SIGALRM; normally we ignore it. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (qdial->uuconf_ccarrier_wait);
+
+ /* We really don't care if we get an error, since that will
+ probably just mean that TIOCWONLINE isn't supported in
+ which case there's nothing we can do anyhow. If we get
+ SIGINT we want to keep waiting for carrier, because
+ SIGINT just means don't start any new sessions. We don't
+ handle SIGINT correctly if we do a longjmp in the signal
+ handler; too bad. */
+ while (ioctl (q->o, TIOCWONLINE, 0) < 0
+ && errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ if (FGOT_QUIT_SIGNAL () || fSalarm)
+ break;
+ }
+ }
+
+ /* Turn off the pending SIGALRM and ignore SIGALARM again. */
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we got a random signal, just return FALSE. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* If we timed out, give an error. */
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR, "Timed out waiting for carrier");
+ return FALSE;
+ }
+
+#endif /* TIOCWONLINE */
+ }
+
+ return TRUE;
+}
+
+/* Read data from a connection, with a timeout. This routine handles
+ all types of connections, including TLI.
+
+ This function should return when we have read cmin characters or
+ the timeout has occurred. We have to work a bit to get Unix to do
+ this efficiently on a terminal. The simple implementation
+ schedules a SIGALRM signal and then calls read; if there is a
+ single character available, the call to read will return
+ immediately, so there must be a loop which terminates when the
+ SIGALRM is delivered or the correct number of characters has been
+ read. This can be very inefficient with a fast CPU or a low baud
+ rate (or both!), since each call to read may return only one or two
+ characters.
+
+ Under POSIX or System V, we can specify a minimum number of
+ characters to read, so there is no serious trouble.
+
+ Under BSD, we figure out how many characters we have left to read,
+ how long it will take for them to arrive at the current baud rate,
+ and sleep that long.
+
+ Doing this with a timeout and avoiding all possible race conditions
+ get very hairy, though. Basically, we're going to schedule a
+ SIGALRM for when the timeout expires. I don't really want to do a
+ longjmp in the SIGALRM handler, though, because that may lose data.
+ Therefore, I have the signal handler set a variable. However, this
+ means that there will be a span of time between the time the code
+ checks the variable and the time it calls the read system call; if
+ the SIGALRM occurs during that time, the read might hang forever.
+ To avoid this, the SIGALRM handler not only sets a global variable,
+ it also schedules another SIGALRM for one second in the future
+ (POSIX specifies that a signal handler is permitted to safely call
+ alarm). To avoid getting a continual sequence of SIGALRM
+ interrupts, we change the signal handler to ignore SIGALRM when
+ we're about to exit the function. This means that every time we
+ execute fsysdep_conn_read we make at least five system calls. It's
+ the best I've been able to come up with, though.
+
+ When fsysdep_conn_read finishes, there will be no SIGALRM scheduled
+ and SIGALRM will be ignored. */
+
+boolean
+fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ CATCH_PROTECT size_t cwant;
+ boolean fret;
+ register struct ssysdep_conn * const q
+ = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwant = *pclen;
+ *pclen = 0;
+
+ /* Guard against a bad timeout. We return TRUE when a timeout
+ expires. It is possible to get a negative timeout here because
+ the calling code does not check user supplied timeouts for
+ plausibility. */
+ if (ctimeout <= 0)
+ return TRUE;
+
+ /* We want to do a blocking read. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ fSalarm = FALSE;
+
+ /* We're going to set up an alarm signal to last for the entire
+ read. If the read system call cannot be interrupted, the signal
+ handler will do a longjmp causing fsysdep_catch (a macro) to
+ return FALSE. We handle that here. If read can be interrupted,
+ fsysdep_catch will be defined to TRUE. */
+ if (fsysdep_catch ())
+ {
+ /* Prepare to catch SIGALRM and schedule the signal. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ alarm (ctimeout);
+ }
+ else
+ {
+ /* We caught a signal. We don't actually have to do anything,
+ as all the appropriate checks are made at the start of the
+ following loop. */
+ }
+
+ fret = FALSE;
+
+ while (TRUE)
+ {
+ int cgot;
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* If we can tell the terminal not to return until we have a
+ certain number of characters, do so. */
+ if (q->fterminal)
+ {
+ int csetmin;
+
+ /* I'm not that confident about setting MIN to values larger
+ than 127, although up to 255 would probably work. */
+ if (cmin < 127)
+ csetmin = cmin;
+ else
+ csetmin = 127;
+
+ if (csetmin != cSmin)
+ {
+ q->snew.c_cc[VMIN] = csetmin;
+ while (! fsetterminfo (q->o, &q->snew))
+ {
+ if (errno != EINTR
+ || FGOT_QUIT_SIGNAL ())
+ {
+ int ierr;
+
+ /* We turn off the signal before reporting the
+ error to minimize any problems with
+ interrupted system calls. */
+ ierr = errno;
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
+ strerror (ierr));
+ return FALSE;
+ }
+
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR,
+ "Timed out when setting MIN to %d; retrying",
+ csetmin);
+ fSalarm = FALSE;
+ alarm (ctimeout);
+ }
+ }
+ cSmin = csetmin;
+ }
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+ /* If we've received a signal, get out now. */
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+
+ /* If we've already gotten a SIGALRM, get out with whatever
+ we've accumulated. */
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* Right here is the race condition which we avoid by having the
+ SIGALRM handler schedule another SIGALRM. */
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zbuf, cwant, &iflags);
+ if (cgot < 0 && t_errno != TSYSERR)
+ {
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zbuf, cwant);
+
+ /* If the read returned an error, check for signals. */
+ if (cgot < 0)
+ {
+ if (errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+ }
+
+ /* If read returned an error, get out. We just ignore EINTR
+ here, since it must be from some signal we don't care about.
+ If the read returned 0 then the line must have been hung up
+ (normally we would have received SIGHUP, but we can't count
+ on that). We turn off the signals before calling ulog to
+ reduce problems with interrupted system calls. */
+ if (cgot <= 0)
+ {
+ if (cgot < 0 && errno == EINTR)
+ cgot = 0;
+ else
+ {
+ int ierr;
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ {
+ if (cgot == 0)
+ ulog (LOG_ERROR, "Line disconnected");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+ }
+
+ return FALSE;
+ }
+ }
+
+ cwant -= cgot;
+ if (cgot >= cmin)
+ cmin = 0;
+ else
+ cmin -= cgot;
+ zbuf += cgot;
+ *pclen += cgot;
+
+ /* If we have enough data, get out now. */
+ if (cmin == 0)
+ {
+ fret = TRUE;
+ break;
+ }
+
+#if HAVE_BSD_TTY
+ /* We still want more data, so sleep long enough for the rest of
+ it to arrive. We don't this for System V or POSIX because
+ setting MIN is good enough (we can't sleep longer than it
+ takes to get MAX_INPUT characters anyhow).
+
+ The baud rate is approximately 10 times the number of
+ characters which will arrive in one second, so the number of
+ milliseconds to sleep ==
+ characters * (milliseconds / character) ==
+ characters * (1000 * (seconds / character)) ==
+ characters * (1000 * (1 / (baud / 10))) ==
+ characters * (10000 / baud)
+
+ We arbitrarily reduce the sleep amount by 10 milliseconds to
+ attempt to account for the amount of time it takes to set up
+ the sleep. This is how long it takes to get half a character
+ at 19200 baud. We then don't bother to sleep for less than
+ 10 milliseconds. We don't sleep if the read was interrupted.
+
+ We use select to sleep. It would be easy to use poll as
+ well, but it's unlikely that any system with BSD ttys would
+ have poll but not select. Using select avoids hassles with
+ the pending SIGALRM; if it hits the select will be
+ interrupted, and otherwise the select will not affect it. */
+
+#if ! HAVE_SELECT
+ #error This code requires select; feel free to extend it
+#endif
+
+ if (q->fterminal && cmin > 1 && cgot > 0)
+ {
+ int csleepchars;
+ int isleep;
+
+ /* We don't try to read all the way up to MAX_INPUT,
+ since that might drop a character. */
+ if (cmin <= MAX_INPUT - 10)
+ csleepchars = cmin;
+ else
+ csleepchars = MAX_INPUT - 10;
+
+ isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
+ isleep -= 10;
+
+ if (isleep > 10)
+ {
+ struct timeval s;
+
+ s.tv_sec = isleep / 1000;
+ s.tv_usec = (isleep % 1000) * 1000;
+
+ /* Some versions of select take a pointer to an int,
+ while some take a pointer to an fd_set. I just cast
+ the arguments to a generic pointer, and assume that
+ any machine which distinguishes int * from fd_set *
+ (I would be amazed if there are any such machines)
+ have an appropriate prototype somewhere or other. */
+ (void) select (0, (pointer) NULL, (pointer) NULL,
+ (pointer) NULL, &s);
+
+ /* Here either the select finished sleeping or we got a
+ SIGALRM. If the latter occurred, fSalarm was set to
+ TRUE; it will be checked at the top of the loop. */
+ }
+ }
+#endif /* HAVE_BSD_TTY */
+ }
+
+ /* Turn off the pending SIGALRM and return. */
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ return fret;
+}
+
+/* Read from a stdin port. */
+
+static boolean
+fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
+}
+
+/* Write data to a connection. This routine handles all types of
+ connections, including TLI. */
+
+boolean
+fsysdep_conn_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *q;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ /* We want blocking writes here. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ czero = 0;
+
+ while (cwrite > 0)
+ {
+ int cdid;
+
+ /* Loop until we don't get an interrupt. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cwrite, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cwrite);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We were interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is lost.
+ If we fail to write anything ten times in a row, we
+ assume that this has happened. This is hacked in like
+ this because there seems to be no reliable way to tell
+ exactly why the write returned 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ czero = 0;
+
+ cwrite -= cdid;
+ zwrite += cdid;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Write to a stdin port. */
+
+static boolean
+fsstdin_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ if (! fsblock (qsysdep, TRUE))
+ return FALSE;
+ qsysdep->o = 1;
+ return fsysdep_conn_write (qconn, zwrite, cwrite);
+}
+
+/* The fsysdep_conn_io routine is supposed to both read and write data
+ until it has either filled its read buffer or written out all the
+ data it was given. This lets us write out large packets without
+ losing incoming data. It handles all types of connections,
+ including TLI. */
+
+boolean
+fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t *pcwrite;
+ char *zread;
+ size_t *pcread;
+{
+ struct ssysdep_conn *q;
+ size_t cwrite, cread;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwrite = *pcwrite;
+ *pcwrite = 0;
+ cread = *pcread;
+ *pcread = 0;
+
+ czero = 0;
+
+ while (TRUE)
+ {
+ int cgot, cdid;
+ size_t cdo;
+
+ /* This used to always use nonblocking writes, but it turns out
+ that some systems don't support them on terminals.
+
+ The current algorithm is:
+ loop:
+ unblocked read
+ if read buffer full, return
+ if nothing to write, return
+ if HAVE_UNBLOCKED_WRITES
+ write all data
+ else
+ write up to SINGLE_WRITE bytes
+ if all data written, return
+ if no data written
+ blocked write of up to SINGLE_WRITE bytes
+
+ This algorithm should work whether the system supports
+ unblocked writes on terminals or not. If the system supports
+ unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
+ call write more often than it needs to. If the system does
+ not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
+ then the write may hang so long that incoming data is lost.
+ This is actually possible at high baud rates on any system
+ when a blocking write is done; there is no solution, except
+ hardware handshaking. */
+
+ /* If we are running on standard input, we switch the file
+ descriptors by hand. */
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ /* Do an unblocked read. */
+ if (! fsblock (q, FALSE))
+ return FALSE;
+
+ /* Loop until we get something (error or data) other than an
+ acceptable EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zread, cread, &iflags);
+ if (cgot < 0)
+ {
+ if (t_errno == TNODATA)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zread, cread);
+
+ if (cgot >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cgot < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ return FALSE;
+ }
+ cgot = 0;
+ }
+
+ cread -= cgot;
+ zread += cgot;
+ *pcread += cgot;
+
+ /* If we've filled the read buffer, or we have nothing left to
+ write, return out. */
+ if (cread == 0 || cwrite == 0)
+ return TRUE;
+
+ /* The port is currently unblocked. Do a write. */
+ cdo = cwrite;
+
+#if ! HAVE_UNBLOCKED_WRITES
+ if (q->fterminal && cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+#endif
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0)
+ {
+ if (t_errno == TFLOW)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid > 0)
+ {
+ /* We wrote some data. If we wrote everything, return out.
+ Otherwise loop around and do another read. */
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+
+ if (cwrite == 0)
+ return TRUE;
+
+ czero = 0;
+ }
+ else
+ {
+ /* We didn't write any data. Do a blocking write. */
+
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ cdo = cwrite;
+ if (cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsysdep_conn_io: Blocking write of %lud",
+ (unsigned long) cdo);
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is
+ lost. If we fail to write anything ten times in a
+ row, we assume that this has happened. This is
+ hacked in like this because there seems to be no
+ reliable way to tell exactly why the write returned
+ 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+ czero = 0;
+ }
+ }
+ }
+}
+
+/* Send a break character to a serial port. */
+
+static boolean
+fsserial_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+#if HAVE_BSD_TTY
+ (void) ioctl (q->o, TIOCSBRK, 0);
+ sleep (2);
+ (void) ioctl (q->o, TIOCCBRK, 0);
+ return TRUE;
+#endif /* HAVE_BSD_TTY */
+#if HAVE_SYSV_TERMIO
+ (void) ioctl (q->o, TCSBRK, 0);
+ return TRUE;
+#endif /* HAVE_SYSV_TERMIO */
+#if HAVE_POSIX_TERMIOS
+ return tcsendbreak (q->o, 0) == 0;
+#endif /* HAVE_POSIX_TERMIOS */
+}
+
+/* Send a break character to a stdin port. */
+
+static boolean
+fsstdin_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 1;
+ return fsserial_break (qconn);
+}
+
+/* Change the setting of a serial port. */
+
+/*ARGSUSED*/
+static boolean
+fsserial_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ register struct ssysdep_conn *q;
+ boolean fchanged, fdo;
+ int iset = 0;
+ int iclear = 0;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ fchanged = FALSE;
+
+ /* Set the parity for output characters. */
+
+#if HAVE_BSD_TTY
+
+ /* This will also cause parity detection on input characters. */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+#if HAVE_PARITY_BUG
+ /* The Sony NEWS mishandles this for some reason. */
+ iset = 0;
+ iclear = ANYP;
+#else
+ iset = ANYP;
+ iclear = 0;
+#endif
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = EVENP;
+ iclear = ODDP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = ODDP;
+ iclear = EVENP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+ iset = CS8;
+ iclear = PARENB | PARODD | (CSIZE &~ CS8);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = PARENB | CS7;
+ iclear = PARODD | (CSIZE &~ CS7);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = PARENB | PARODD | CS7;
+ iclear = CSIZE &~ CS7;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_cflag & iset) != iset
+ || (q->snew.c_cflag & iclear) != 0)
+ {
+ q->snew.c_cflag |= iset;
+ q->snew.c_cflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set whether input characters are stripped to seven bits. */
+
+#if HAVE_BSD_TTY
+
+#ifdef LPASS8
+ {
+ int i;
+
+ i = LPASS8;
+ if (tstrip == STRIPSETTING_EIGHTBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+ }
+ else if (tstrip == STRIPSETTING_SEVENBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIC, &i);
+ }
+ }
+#endif
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tstrip)
+ {
+ case STRIPSETTING_DEFAULT:
+ break;
+ case STRIPSETTING_EIGHTBITS:
+ iset = 0;
+ iclear = ISTRIP;
+ fdo = TRUE;
+ break;
+ case STRIPSETTING_SEVENBITS:
+ iset = ISTRIP;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set XON/XOFF handshaking. */
+
+#if HAVE_BSD_TTY
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = RAW;
+ iclear = TANDEM | CBREAK;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+ iset = CBREAK | TANDEM;
+ iclear = RAW;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = 0;
+ iclear = IXON | IXOFF;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+#ifdef CRTSCTS
+#if HAVE_POSIX_TERMIOS
+ /* This is system dependent, but I haven't figured out a good
+ way around it yet. If we are doing hardware flow control, we
+ don't send XON/XOFF characters but we do recognize them. */
+ if ((q->snew.c_cflag & CRTSCTS) != 0)
+ {
+ iset = IXON;
+ iclear = IXOFF;
+ fdo = TRUE;
+ break;
+ }
+#endif /* HAVE_POSIX_TERMIOS */
+#endif /* defined (CRTSCTS) */
+ iset = IXON | IXOFF;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (fchanged)
+ {
+ if (! fsetterminfodrain (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't change terminal settings: %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+#if HAVE_BSD_TTY
+ if (txonxoff == XONXOFF_ON
+ && (q->snew.stty.sg_flags & ANYP) == ANYP)
+ {
+ int i;
+
+ /* At least on Ultrix, we seem to have to set LLITOUT and
+ LPASS8. This shouldn't foul things up anywhere else. As far
+ as I can tell, this has to be done after setting the terminal
+ into cbreak mode, not before. */
+#ifndef LLITOUT
+#define LLITOUT 0
+#endif
+#ifndef LPASS8
+#define LPASS8 0
+#endif
+#ifndef LAUTOFLOW
+#define LAUTOFLOW 0
+#endif
+ i = LLITOUT | LPASS8 | LAUTOFLOW;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+
+#if HAVE_STRIP_BUG
+ /* Ultrix 4.0 has a peculiar problem: setting CBREAK always
+ causes input characters to be stripped. I hope this does not
+ apply to other BSD systems. It is possible to work around
+ this by using the termio call. I wish this sort of stuff was
+ not necessary!!! */
+ {
+ struct termio s;
+
+ if (ioctl (q->o, TCGETA, &s) >= 0)
+ {
+ s.c_iflag &=~ ISTRIP;
+ (void) ioctl (q->o, TCSETA, &s);
+ }
+ }
+#endif /* HAVE_STRIP_BUG */
+ }
+#endif /* HAVE_BSD_TTY */
+
+ return TRUE;
+}
+
+/* Change settings of a stdin port. */
+
+static boolean
+fsstdin_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_set (qconn, tparity, tstrip, txonxoff);
+}
+
+/* Run a chat program. */
+
+static boolean
+fsrun_chat (oread, owrite, pzprog)
+ int oread;
+ int owrite;
+ char **pzprog;
+{
+ int aidescs[3];
+ FILE *e;
+ pid_t ipid;
+ char *z;
+ size_t c;
+
+ aidescs[0] = oread;
+ aidescs[1] = owrite;
+ aidescs[2] = SPAWN_READ_PIPE;
+
+ /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the
+ responsibility of maintaing security on the chat program. */
+ ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE,
+ (const char *) NULL, FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
+ return FALSE;
+ }
+
+ e = fdopen (aidescs[2], (char *) "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (aidescs[2]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* The FILE e now is attached to stderr of the program. Forward
+ every line the program outputs to the log file. */
+ z = NULL;
+ c = 0;
+ while (getline (&z, &c, e) > 0)
+ {
+ size_t clen;
+
+ clen = strlen (z);
+ if (z[clen - 1] == '\n')
+ z[clen - 1] = '\0';
+ if (*z != '\0')
+ ulog (LOG_NORMAL, "chat: %s", z);
+ }
+
+ xfree ((pointer) z);
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, "Chat program") == 0;
+}
+
+/* Run a chat program on a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ return fsrun_chat (0, 1, pzprog);
+}
+
+/* Run a chat program on any general type of connection. */
+
+boolean
+fsysdep_conn_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
+}
+
+/* Return baud rate of a serial port. */
+
+static long
+isserial_baud (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return qsysdep->ibaud;
+}
diff --git a/gnu/libexec/uucp/libunix/signal.c b/gnu/libexec/uucp/libunix/signal.c
new file mode 100644
index 00000000000..33e24a72457
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/signal.c
@@ -0,0 +1,208 @@
+/* signal.c
+ Signal handling routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Signal handling routines. When we catch a signal, we want to set
+ the appropriate elements of afSignal and afLog_signal to TRUE. If
+ we are on a system which restarts system calls, we may also want to
+ longjmp out. On a system which does not restart system calls,
+ these signal handling routines are well-defined by ANSI C. */
+
+#if HAVE_RESTARTABLE_SYSCALLS
+volatile sig_atomic_t fSjmp;
+volatile jmp_buf sSjmp_buf;
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+
+/* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be
+ set in the sigaction structure to force system calls to be
+ interrupted. */
+#ifndef SA_INTERRUPT
+#define SA_INTERRUPT 0
+#endif
+
+/* The SVR3 sigset function can be called just like signal, unless
+ system calls are restarted which is extremely unlikely; we prevent
+ this case in sysh.unx. */
+#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC
+#define signal sigset
+#endif
+
+/* The sigvec structure changed from 4.2BSD to 4.3BSD. These macros
+ make the 4.3 code backward compatible. */
+#ifndef SV_INTERRUPT
+#define SV_INTERRUPT 0
+#endif
+#if ! HAVE_SIGVEC_SV_FLAGS
+#define sv_flags sv_onstack
+#endif
+
+/* Catch a signal. Reinstall the signal handler if necessary, set the
+ appropriate variables, and do a longjmp if necessary. */
+
+RETSIGTYPE
+ussignal (isig)
+ int isig;
+{
+ int iindex;
+
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, ussignal);
+#endif
+
+ switch (isig)
+ {
+ default: iindex = INDEXSIG_SIGHUP; break;
+#ifdef SIGINT
+ case SIGINT: iindex = INDEXSIG_SIGINT; break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM: iindex = INDEXSIG_SIGTERM; break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break;
+#endif
+ }
+
+ afSignal[iindex] = TRUE;
+ afLog_signal[iindex] = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* Prepare to catch a signal. This is basically the ANSI C routine
+ signal, but it uses sigaction or sigvec instead if they are
+ available. If fforce is FALSE, we do not set the signal if it is
+ currently being ignored. If pfignored is not NULL and fforce is
+ FALSE, then *pfignored will be set to TRUE if the signal was
+ previously being ignored (if fforce is TRUE the value returned in
+ *pfignored is meaningless). If we can't change the signal handler
+ we give a fatal error. */
+
+void
+usset_signal (isig, pfn, fforce, pfignored)
+ int isig;
+ RETSIGTYPE (*pfn) P((int));
+ boolean fforce;
+ boolean *pfignored;
+{
+#if HAVE_SIGACTION
+
+ struct sigaction s;
+
+ if (! fforce)
+ {
+ (void) (sigemptyset (&s.sa_mask));
+ if (sigaction (isig, (struct sigaction *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+ if (s.sa_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sa_handler = pfn;
+ (void) (sigemptyset (&s.sa_mask));
+ s.sa_flags = SA_INTERRUPT;
+
+ if (sigaction (isig, &s, (struct sigaction *) NULL) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGACTION */
+#if HAVE_SIGVEC
+
+ struct sigvec s;
+
+ if (! fforce)
+ {
+ if (sigvec (isig, (struct sigvec *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+ if (s.sv_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sv_handler = pfn;
+ s.sv_mask = 0;
+ s.sv_flags = SV_INTERRUPT;
+
+ if (sigvec (isig, &s, (struct sigvec *) NULL) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGVEC */
+
+ if (! fforce)
+ {
+ if (signal (isig, SIG_IGN) == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ (void) signal (isig, pfn);
+
+#endif /* ! HAVE_SIGVEC */
+#endif /* ! HAVE_SIGACTION */
+}
+
+/* The routine called by the system independent code, which always
+ uses the same signal handler. */
+
+void
+usysdep_signal (isig)
+ int isig;
+{
+ usset_signal (isig, ussignal, FALSE, (boolean *) NULL);
+}
diff --git a/gnu/libexec/uucp/libunix/sindir.c b/gnu/libexec/uucp/libunix/sindir.c
new file mode 100644
index 00000000000..d9875081891
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/sindir.c
@@ -0,0 +1,26 @@
+/* sindir.c
+ Stick a directory and file name together. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+char *
+zsysdep_in_dir (zdir, zfile)
+ const char *zdir;
+ const char *zfile;
+{
+ size_t cdir, cfile;
+ char *zret;
+
+ cdir = strlen (zdir);
+ cfile = strlen (zfile);
+ zret = zbufalc (cdir + cfile + 2);
+ memcpy (zret, zdir, cdir);
+ memcpy (zret + cdir + 1, zfile, cfile);
+ zret[cdir] = '/';
+ zret[cdir + cfile + 1] = '\0';
+ return zret;
+}
diff --git a/gnu/libexec/uucp/libunix/size.c b/gnu/libexec/uucp/libunix/size.c
new file mode 100644
index 00000000000..8d021db3cd5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/size.c
@@ -0,0 +1,27 @@
+/* size.c
+ Get the size in bytes of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+long
+csysdep_size (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno == ENOENT)
+ return -1;
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return -2;
+ }
+
+ return s.st_size;
+}
diff --git a/gnu/libexec/uucp/libunix/sleep.c b/gnu/libexec/uucp/libunix/sleep.c
new file mode 100644
index 00000000000..b232f9674ff
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/sleep.c
@@ -0,0 +1,14 @@
+/* sleep.c
+ Sleep for a number of seconds. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+void
+usysdep_sleep (c)
+ int c;
+{
+ (void) sleep (c);
+}
diff --git a/gnu/libexec/uucp/libunix/spawn.c b/gnu/libexec/uucp/libunix/spawn.c
new file mode 100644
index 00000000000..7ab080d1a9c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/spawn.c
@@ -0,0 +1,398 @@
+/* spawn.c
+ Spawn a program securely.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef environ
+extern char **environ;
+#endif
+
+/* Spawn a child in a fairly secure fashion. This returns the process
+ ID of the child or -1 on error. It takes far too many arguments:
+
+ pazargs -- arguments (element 0 is command)
+ aidescs -- file descriptors for stdin, stdout and stderr
+ fkeepuid -- TRUE if euid should be left unchanged
+ fkeepenv -- TRUE if environment should be left unmodified
+ zchdir -- directory to chdir to
+ fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT
+ fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC
+ zpath -- value for environment variable PATH
+ zuu_machine -- value for environment variable UU_MACHINE
+ zuu_user -- value for environment variable UU_USER
+
+ The aidescs array is three elements long. 0 is stdin, 1 is stdout
+ and 2 is stderr. The array may contain either file descriptor
+ numbers to dup appropriately, or one of the following:
+
+ SPAWN_NULL -- set descriptor to /dev/null
+ SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read
+ SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write
+
+ If fkeepenv is FALSE, a standard environment is created. The
+ environment arguments (zpath, zuu_machine and zuu_user) are only
+ used if fkeepenv is FALSE; any of them may be NULL.
+
+ This routine expects that all file descriptors have been set to
+ close-on-exec, so it doesn't have to worry about closing them
+ explicitly. It sets the close-on-exec flag for the new pipe
+ descriptors it returns. */
+
+pid_t
+ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
+ zpath, zuu_machine, zuu_user)
+ const char **pazargs;
+ int aidescs[3];
+ boolean fkeepuid;
+ boolean fkeepenv;
+ const char *zchdir;
+ boolean fnosigs;
+ boolean fshell;
+ const char *zpath;
+ const char *zuu_machine;
+ const char *zuu_user;
+{
+ char *zshcmd;
+ int i;
+ char *azenv[9];
+ char **pazenv;
+ boolean ferr;
+ int ierr = 0;
+ int onull;
+ int aichild_descs[3];
+ int cpar_close;
+ int aipar_close[4];
+ int cchild_close;
+ int aichild_close[3];
+ pid_t iret = 0;
+ const char *zcmd;
+
+ /* If we might have to use the shell, allocate enough space for the
+ quoted command before forking. Otherwise the allocation would
+ modify the data segment and we could not safely use vfork. */
+ zshcmd = NULL;
+ if (fshell)
+ {
+ size_t clen;
+
+ clen = 0;
+ for (i = 0; pazargs[i] != NULL; i++)
+ clen += strlen (pazargs[i]);
+ zshcmd = zbufalc (2 * clen + i);
+ }
+
+ /* Set up a standard environment. This is again done before forking
+ because it will modify the data segment. */
+ if (fkeepenv)
+ pazenv = environ;
+ else
+ {
+ const char *zterm, *ztz;
+ char *zspace;
+ int ienv;
+
+ if (zpath == NULL)
+ zpath = CMDPATH;
+
+ azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath));
+ sprintf (azenv[0], "PATH=%s", zpath);
+ zspace = azenv[0] + sizeof "PATH=" - 1;
+ while ((zspace = strchr (zspace, ' ')) != NULL)
+ *zspace = ':';
+
+ azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir));
+ sprintf (azenv[1], "HOME=%s", zSspooldir);
+
+ zterm = getenv ("TERM");
+ if (zterm == NULL)
+ zterm = "unknown";
+ azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm));
+ sprintf (azenv[2], "TERM=%s", zterm);
+
+ azenv[3] = zbufcpy ("SHELL=/bin/sh");
+
+ azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER));
+ sprintf (azenv[4], "USER=%s", OWNER);
+
+ ienv = 5;
+
+ ztz = getenv ("TZ");
+ if (ztz != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz));
+ sprintf (azenv[ienv], "TZ=%s", ztz);
+ ++ienv;
+ }
+
+ if (zuu_machine != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_MACHINE="
+ + strlen (zuu_machine));
+ sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine);
+ ++ienv;
+ }
+
+ if (zuu_user != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_USER="
+ + strlen (zuu_user));
+ sprintf (azenv[ienv], "UU_USER=%s", zuu_user);
+ ++ienv;
+ }
+
+ azenv[ienv] = NULL;
+ pazenv = azenv;
+ }
+
+ /* Set up any needed pipes. */
+
+ ferr = FALSE;
+ onull = -1;
+ cpar_close = 0;
+ cchild_close = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aidescs[i] == SPAWN_NULL)
+ {
+ if (onull < 0)
+ {
+ onull = open ((char *) "/dev/null", O_RDWR);
+ if (onull < 0
+ || fcntl (onull, F_SETFD,
+ fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ (void) close (onull);
+ ferr = TRUE;
+ break;
+ }
+ aipar_close[cpar_close] = onull;
+ ++cpar_close;
+ }
+ aichild_descs[i] = onull;
+ }
+ else if (aidescs[i] != SPAWN_READ_PIPE
+ && aidescs[i] != SPAWN_WRITE_PIPE)
+ aichild_descs[i] = aidescs[i];
+ else
+ {
+ int aipipe[2];
+
+ if (pipe (aipipe) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+
+ if (aidescs[i] == SPAWN_READ_PIPE)
+ {
+ aidescs[i] = aipipe[0];
+ aichild_close[cchild_close] = aipipe[0];
+ aichild_descs[i] = aipipe[1];
+ aipar_close[cpar_close] = aipipe[1];
+ }
+ else
+ {
+ aidescs[i] = aipipe[1];
+ aichild_close[cchild_close] = aipipe[1];
+ aichild_descs[i] = aipipe[0];
+ aipar_close[cpar_close] = aipipe[0];
+ }
+
+ ++cpar_close;
+ ++cchild_close;
+
+ if (fcntl (aidescs[i], F_SETFD,
+ fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+ }
+ }
+
+#if DEBUG > 1
+ if (! ferr && FDEBUGGING (DEBUG_EXECUTE))
+ {
+ ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]);
+ for (i = 1; pazargs[i] != NULL; i++)
+ ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]);
+ ulog (LOG_DEBUG_END, "%s", "");
+ }
+#endif
+
+ if (! ferr)
+ {
+ /* This should really be vfork if available. */
+ iret = ixsfork ();
+ if (iret < 0)
+ {
+ ferr = TRUE;
+ ierr = errno;
+ }
+ }
+
+ if (ferr)
+ {
+ for (i = 0; i < cchild_close; i++)
+ (void) close (aichild_close[i]);
+ iret = -1;
+ }
+
+ if (iret != 0)
+ {
+ /* The parent. Close the child's ends of the pipes and return
+ the process ID, or an error. */
+ for (i = 0; i < cpar_close; i++)
+ (void) close (aipar_close[i]);
+ ubuffree (zshcmd);
+ if (! fkeepenv)
+ {
+ char **pz;
+
+ for (pz = azenv; *pz != NULL; pz++)
+ ubuffree (*pz);
+ }
+ errno = ierr;
+ return iret;
+ }
+
+ /* The child. */
+
+#ifdef STDIN_FILENO
+#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2
+ #error The following code makes invalid assumptions
+#endif
+#endif
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aichild_descs[i] != i)
+ (void) dup2 (aichild_descs[i], i);
+ /* This should only be necessary if aichild_descs[i] == i, but
+ some systems copy the close-on-exec flag for a dupped
+ descriptor, which is wrong according to POSIX. */
+ (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC);
+ }
+
+ zcmd = pazargs[0];
+ pazargs[0] = strrchr (zcmd, '/');
+ if (pazargs[0] == NULL)
+ pazargs[0] = zcmd;
+ else
+ ++pazargs[0];
+
+ if (! fkeepuid)
+ {
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ }
+
+ if (zchdir != NULL)
+ (void) chdir (zchdir);
+
+ if (fnosigs)
+ {
+#ifdef SIGHUP
+ (void) signal (SIGHUP, SIG_IGN);
+#endif
+#ifdef SIGINT
+ (void) signal (SIGINT, SIG_IGN);
+#endif
+#ifdef SIGQUIT
+ (void) signal (SIGQUIT, SIG_IGN);
+#endif
+ }
+
+ (void) execve ((char *) zcmd, (char **) pazargs, pazenv);
+
+ /* The exec failed. If permitted, try using /bin/sh to execute a
+ shell script. */
+
+ if (errno == ENOEXEC && fshell)
+ {
+ char *zto;
+ const char *azshargs[4];
+
+ pazargs[0] = zcmd;
+ zto = zshcmd;
+ for (i = 0; pazargs[i] != NULL; i++)
+ {
+ const char *zfrom;
+
+ for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++)
+ {
+ /* Some versions of /bin/sh appear to have a bug such
+ that quoting a '/' sometimes causes an error. I
+ don't know exactly when this happens (I can recreate
+ it on Ultrix 4.0), but in any case it is harmless to
+ not quote a '/'. */
+ if (*zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom;
+ }
+ *zto++ = ' ';
+ }
+ *(zto - 1) = '\0';
+
+ azshargs[0] = "sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zshcmd;
+ azshargs[3] = NULL;
+
+ (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv);
+ }
+
+ _exit (EXIT_FAILURE);
+
+ /* Avoid compiler warning. */
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/splcmd.c b/gnu/libexec/uucp/libunix/splcmd.c
new file mode 100644
index 00000000000..9f6616a36dd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/splcmd.c
@@ -0,0 +1,115 @@
+/* splcmd.c
+ Spool a command.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+/* Given a set of commands to execute for a remote system, create a
+ command file holding them. This creates a single command file
+ holding all the commands passed in. It returns a jobid. */
+
+char *
+zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ int ccmds;
+ const struct scmd *pascmds;
+{
+ char *z;
+ FILE *e;
+ int i;
+ const struct scmd *q;
+ char *zjobid;
+
+#if DEBUG > 0
+ if (! UUCONF_GRADE_LEGAL (bgrade))
+ ulog (LOG_FATAL, "Bad grade %d", bgrade);
+#endif
+
+ z = zscmd_file (qsys, bgrade);
+ if (z == NULL)
+ return NULL;
+
+ e = esysdep_fopen (z, FALSE, FALSE, TRUE);
+ if (e == NULL)
+ {
+ ubuffree (z);
+ return NULL;
+ }
+
+ for (i = 0, q = pascmds; i < ccmds; i++, q++)
+ {
+ switch (q->bcmd)
+ {
+ case 'S':
+ fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify == NULL ? (const char *) "" : q->znotify);
+ break;
+ case 'R':
+ fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'X':
+ fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'E':
+ fprintf (e, "E %s %s %s -%s %s 0%o %s 0 %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify, q->zcmd);
+ break;
+ default:
+ ulog (LOG_ERROR,
+ "zsysdep_spool_commands: Unrecognized type %d",
+ q->bcmd);
+ (void) fclose (e);
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+ }
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+
+ zjobid = zsfile_to_jobid (qsys, z, bgrade);
+ if (zjobid == NULL)
+ (void) remove (z);
+ ubuffree (z);
+ return zjobid;
+}
diff --git a/gnu/libexec/uucp/libunix/splnam.c b/gnu/libexec/uucp/libunix/splnam.c
new file mode 100644
index 00000000000..06ce3605ce5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/splnam.c
@@ -0,0 +1,19 @@
+/* splnam.c
+ Get the full name of a file in the spool directory. */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Get the real name of a spool file. */
+
+char *
+zsysdep_spool_file_name (qsys, zfile, pseq)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ pointer pseq;
+{
+ return zsfind_file (zfile, qsys->uuconf_zname, bsgrade (pseq));
+}
diff --git a/gnu/libexec/uucp/libunix/spool.c b/gnu/libexec/uucp/libunix/spool.c
new file mode 100644
index 00000000000..f28229fe4e1
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/spool.c
@@ -0,0 +1,420 @@
+/* spool.c
+ Find a file in the spool directory.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/04 19:33:02 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* There are several types of files that go in the spool directory,
+ and they go into various different subdirectories. Whenever the
+ system name LOCAL appears below, it means whatever the local system
+ name is.
+
+ Command files
+ These contain instructions for uucico indicating what files to transfer
+ to and from what systems. Each line of a work file is a command
+ beginning with S, R or X.
+ #if ! SPOOLDIR_TAYLOR
+ They are named C.ssssssgqqqq, where ssssss is the system name to
+ transfer to or from, g is the grade and qqqq is the sequence number.
+ #if SPOOLDIR_V2
+ They are put in the spool directory.
+ #elif SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ They are put in the directory "C.".
+ #elif SPOOLDIR_HDB
+ They are put in a directory named for the system for which they were
+ created.
+ #elif SPOOLDIR_ULTRIX
+ If the directory sys/ssssss exists, they are put in the directory
+ sys/ssssss/C; otherwise, they are put in the directory sys/DEFAULT/C.
+ #endif
+ #elif SPOOLDIR_SVR4
+ They are put in the directory sys/g, where sys is the system name
+ and g is the grade.
+ #endif
+ #else SPOOLDIR_TAYLOR
+ They are named C.gqqqq, where g is the grade and qqqq is the sequence
+ number, and are placed in the directory ssssss/C. where ssssss is
+ the system name to transfer to or from.
+ #endif
+
+ Data files
+ There are files to be transferred to other systems. Some files to
+ be transferred may not be in the spool directory, depending on how
+ uucp was invoked. Data files are named in work files, so it is
+ never necessary to look at them directly (except to remove old ones);
+ it is only necessary to create them. These means that the many
+ variations in naming are inconsequential.
+ #if ! SPOOLDIR_TAYLOR
+ They are named D.ssssssgqqqq where ssssss is a system name (which
+ may be LOCAL for locally initiated transfers or a remote system for
+ remotely initiated transfers, except that HDB appears to use the
+ system the file is being transferred to), g is the grade and qqqq
+ is the sequence number. Some systems use a trailing subjob ID
+ number, but we currently do not. The grade is not important, and
+ some systems do not use it. If the data file is to become an
+ execution file on another system the grade (if present) will be
+ 'X'. Otherwise Ultrix appears to use 'b'; the uux included with
+ gnuucp 1.0 appears to use 'S'; SCO does not appear to use a grade,
+ although it does use a subjob ID number.
+ #if SPOOLDIR_V2
+ They are put in the spool directory.
+ #elif SPOOLDIR_BSD42
+ If the name begins with D.LOCAL, the file is put in the directory
+ D.LOCAL. Otherwise the file is put in the directory D..
+ #elif SPOOLDIR_BSD43
+ If the name begins with D.LOCALX, the file is put in the directory
+ D.LOCALX. Otherwise if the name begins with D.LOCAL, the file is
+ put in the directory D.LOCAL Otherwise the file is put in the
+ directory "D.".
+ #elif SPOOLDIR_HDB
+ They are put in a directory named for the system for which they
+ were created.
+ #elif SPOOLDIR_ULTRIX
+ Say the file is being transferred to system REMOTE. If the
+ directory sys/REMOTE exists, then if the file begins with D.LOCALX
+ it is put in sys/REMOTE/D.LOCALX, if the file begins with D.LOCAL
+ it is put in sys/REMOTE/D.LOCAL, and otherwise it is put in
+ "sys/REMOTE/D.". If the directory sys/REMOTE does not exist, the
+ same applies except that DEFAULT is used instead of REMOTE.
+ #elif SPOOLDIR_SVR4
+ They are put in the directory sys/g, where sys is the system name
+ and g is the grade.
+ #endif
+ #else SPOOLDIR_TAYLOR
+ If the file is to become an executable file on another system it is
+ named D.Xqqqq, otherwise it is named D.qqqq where in both cases
+ qqqq is a sequence number. If the corresponding C. file is in
+ directory ssssss/C., a D.X file is placed in ssssss/D.X and a D.
+ file is placed in "ssssss/D.".
+ #endif
+
+ Execute files
+ These are files that specify programs to be executed. They are
+ created by uux, perhaps as run on another system. These names are
+ important, because a file transfer done to an execute file name
+ causes an execution to occur. The name is X.ssssssgqqqq, where
+ ssssss is the requesting system, g is the grade, and qqqq is a
+ sequence number.
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ These files are placed in the spool directory.
+ #elif SPOOLDIR_BSD43
+ These files are placed in the directory X..
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ These files are put in a directory named for the system for which
+ the files were created.
+ #elif SPOOLDIR_ULTRIX
+ If there is a spool directory (sys/ssssss) for the requesting
+ system, the files are placed in sys/ssssss/X.; otherwise, the files
+ are placed in "sys/DEFAULT/X.".
+ #elif SPOOLDIR_TAYLOR
+ The system name is automatically truncated to seven characters when
+ a file is created. The files are placed in the subdirectory X. of
+ a directory named for the system for which the files were created.
+ #endif
+
+ Temporary receive files
+ These are used when receiving files from another system. They are
+ later renamed to the final name. The actual name is unimportant,
+ although it generally begins with TM..
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ These files are placed in the spool directory.
+ #elif SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ These files are placed in the directory .Temp.
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ These files are placed in a directory named for the system for
+ which they were created.
+ #endif
+
+ System status files
+ These are used to record when the last call was made to the system
+ and what the status is. They are used to prevent frequent recalls
+ to a system which is not responding. I will not attempt to
+ recreate the format of these exactly, since they are not all that
+ important. They will be put in the directory .Status, as in HDB,
+ and they use the system name as the name of the file.
+
+ Sequence file
+ This is used to generate a unique sequence number. It contains an
+ ASCII number.
+ #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ The file is named SEQF and is kept in the spool directory.
+ #elif SPOOLDIR_HDB || SPOOLDIR_SVR4
+ A separate sequence file is kept for each system in the directory
+ .Sequence with the name of the system.
+ #elif SPOOLDIR_ULTRIX
+ Each system with a file sys/ssssss has a sequence file in
+ sys/ssssss/.SEQF. Other systems use sys/DEFAULT/.SEQF.
+ #else SPOOLDIR_TAYLOR
+ A sequence file named SEQF is kept in the directory ssssss for each
+ system.
+ #endif
+ */
+
+/* Given the name of a file as specified in a UUCP command, and the
+ system for which this file has been created, return where to find
+ it in the spool directory. The file will begin with C. (a command
+ file), D. (a data file) or X. (an execution file). Under
+ SPOOLDIR_SVR4 we need to know the grade of the file created by the
+ local system; this is the bgrade argument, which is -1 for a file
+ from a remote system. */
+
+/*ARGSUSED*/
+char *
+zsfind_file (zsimple, zsystem, bgrade)
+ const char *zsimple;
+ const char *zsystem;
+ int bgrade;
+{
+ if (! fspool_file (zsimple))
+ {
+ ulog (LOG_ERROR, "Unrecognized file name %s", zsimple);
+ return NULL;
+ }
+
+#if ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR
+ if (*zsimple == 'X')
+ {
+ size_t clen;
+
+ /* Files beginning with X. are execute files. It is important
+ for security reasons that we know the system which created
+ the X. file. This is easy under SPOOLDIR_HDB or
+ SPOOLDIR_SVR4 SPOOLDIR_TAYLOR, because the file will be in a
+ directory named for the system. Under other schemes, we must
+ get the system name from the X. file name. To prevent
+ security violations, we set the system name directly here;
+ this will cause problems if the maximum file name length is
+ too short, but hopefully no problem will occur since any
+ System V systems will be using HDB or SVR4 or TAYLOR. */
+ clen = strlen (zsimple);
+ if (clen <= 7 || strncmp (zsimple + 2, zsystem, clen - 7) != 0)
+ {
+ static char *zbuf;
+ static size_t cbuf;
+ size_t cwant;
+
+ cwant = strlen (zsystem) + 8;
+ if (cwant > cbuf)
+ {
+ zbuf = (char *) xrealloc ((pointer) zbuf, cwant);
+ cbuf = cwant;
+ }
+ sprintf (zbuf, "X.%s%s", zsystem,
+ clen < 5 ? zsimple : zsimple + clen - 5);
+ zsimple = zbuf;
+ }
+ }
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 && ! SPOOLDIR_TAYLOR */
+
+#if SPOOLDIR_V2
+ /* V2 never uses subdirectories. */
+ return zbufcpy (zsimple);
+#endif /* SPOOLDIR_V2 */
+
+#if SPOOLDIR_HDB
+ /* HDB always uses the system name as a directory. */
+ return zsysdep_in_dir (zsystem, zsimple);
+#endif /* SPOOLDIR_HDB */
+
+#if SPOOLDIR_SVR4
+ /* SVR4 uses grade directories within the system directory for local
+ command and data files. */
+ if (bgrade < 0 || *zsimple == 'X')
+ return zsysdep_in_dir (zsystem, zsimple);
+ else
+ {
+ char abgrade[2];
+
+ abgrade[0] = bgrade;
+ abgrade[1] = '\0';
+ return zsappend3 (zsystem, abgrade, zsimple);
+ }
+#endif /* SPOOLDIR_SVR4 */
+
+#if ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4
+ switch (*zsimple)
+ {
+ case 'C':
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ return zsysdep_in_dir ("C.", zsimple);
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_ULTRIX
+ if (fsultrix_has_spool (zsystem))
+ return zsappend4 ("sys", zsystem, "C.", zsimple);
+ else
+ return zsappend4 ("sys", "DEFAULT", "C.", zsimple);
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ return zsappend3 (zsystem, "C.", zsimple);
+#endif /* SPOOLDIR_TAYLOR */
+
+ case 'D':
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ {
+ size_t c;
+ boolean ftruncated;
+
+ /* D.LOCAL in D.LOCAL/, others in D./. If BSD43, D.LOCALX in
+ D.LOCALX/. */
+ ftruncated = TRUE;
+ if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0)
+ {
+ c = strlen (zSlocalname);
+ ftruncated = FALSE;
+ }
+ else if (strncmp (zsimple + 2, zSlocalname, 7) == 0)
+ c = 7;
+ else if (strncmp (zsimple + 2, zSlocalname, 6) == 0)
+ c = 6;
+ else
+ c = 0;
+#if SPOOLDIR_BSD43
+ if (c > 0 && zsimple[c + 2] == 'X')
+ c++;
+#endif /* SPOOLDIR_BSD43 */
+ if (c > 0)
+ {
+ char *zalloc;
+
+ zalloc = zbufalc (c + 3);
+ memcpy (zalloc, zsimple, c + 2);
+ zalloc[c + 2] = '\0';
+
+ /* If we truncated the system name, and there is no existing
+ directory with the truncated name, then just use D.. */
+ if (! ftruncated || fsysdep_directory (zalloc))
+ {
+ char *zret;
+
+ zret = zsysdep_in_dir (zalloc, zsimple);
+ ubuffree (zalloc);
+ return zret;
+ }
+ ubuffree (zalloc);
+ }
+ return zsysdep_in_dir ("D.", zsimple);
+ }
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_ULTRIX
+ {
+ size_t c;
+ boolean ftruncated;
+ char *zfree;
+ const char *zdir;
+ char *zret;
+
+ /* D.LOCALX in D.LOCALX/, D.LOCAL in D.LOCAL/, others in D./. */
+ ftruncated = TRUE;
+ if (strncmp (zsimple + 2, zSlocalname, strlen (zSlocalname)) == 0)
+ {
+ c = strlen (zSlocalname);
+ ftruncated = FALSE;
+ }
+ else if (strncmp (zsimple + 2, zSlocalname, 7) == 0)
+ c = 7;
+ else if (strncmp (zsimple + 2, zSlocalname, 6) == 0)
+ c = 6;
+ else
+ c = 0;
+ if (c > 0 && zsimple[c + 2] == 'X')
+ ++c;
+ if (c > 0)
+ {
+ zfree = zbufalc (c + 3);
+ memcpy (zfree, zsimple, c + 2);
+ zfree[c + 2] = '\0';
+ zdir = zfree;
+
+ /* If we truncated the name, and there is no directory for
+ the truncated name, then don't use it. */
+ if (ftruncated)
+ {
+ char *zlook;
+
+ zlook = zsappend3 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ zdir);
+ if (! fsysdep_directory (zlook))
+ zdir = "D.";
+ ubuffree (zlook);
+ }
+ }
+ else
+ {
+ zfree = NULL;
+ zdir = "D.";
+ }
+
+ zret = zsappend4 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ zdir,
+ zsimple);
+ ubuffree (zfree);
+ return zret;
+ }
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ if (zsimple[2] == 'X')
+ return zsappend3 (zsystem, "D.X", zsimple);
+ else
+ return zsappend3 (zsystem, "D.", zsimple);
+#endif /* SPOOLDIR_TAYLOR */
+
+
+ case 'X':
+#if SPOOLDIR_BSD42
+ return zbufcpy (zsimple);
+#endif
+#if SPOOLDIR_BSD43
+ return zsysdep_in_dir ("X.", zsimple);
+#endif
+#if SPOOLDIR_ULTRIX
+ return zsappend4 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ "X.",
+ zsimple);
+#endif
+#if SPOOLDIR_TAYLOR
+ return zsappend3 (zsystem, "X.", zsimple);
+#endif
+ }
+
+ /* This is just to avoid warnings; it will never be executed. */
+ return NULL;
+#endif /* ! SPOOLDIR_V2 && ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+}
diff --git a/gnu/libexec/uucp/libunix/srmdir.c b/gnu/libexec/uucp/libunix/srmdir.c
new file mode 100644
index 00000000000..28487ef3097
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/srmdir.c
@@ -0,0 +1,112 @@
+/* srmdir.c
+ Remove a directory and all its contents.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int isremove_dir P((const char *, const struct stat *, int));
+
+/* Keep a list of directories to be removed. */
+
+struct sdirlist
+{
+ struct sdirlist *qnext;
+ char *zdir;
+};
+
+static struct sdirlist *qSdirlist;
+
+/* Remove a directory and all files in it. */
+
+boolean
+fsysdep_rmdir (zdir)
+ const char *zdir;
+{
+ boolean fret;
+ struct sdirlist *q;
+
+ qSdirlist = NULL;
+
+ fret = TRUE;
+ if (ftw ((char *) zdir, isremove_dir, 5) != 0)
+ {
+ ulog (LOG_ERROR, "ftw: %s", strerror (errno));
+ fret = FALSE;
+ }
+
+ q = qSdirlist;
+ while (q != NULL)
+ {
+ struct sdirlist *qnext;
+
+ if (rmdir (q->zdir) != 0)
+ {
+ ulog (LOG_ERROR, "rmdir (%s): %s", q->zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (q->zdir);
+ qnext = q->qnext;
+ xfree ((pointer) q);
+ q = qnext;
+ }
+
+ return fret;
+}
+
+/* Remove a file in a directory. */
+
+/*ARGSUSED*/
+static int
+isremove_dir (zfile, qstat, iflag)
+ const char *zfile;
+ const struct stat *qstat;
+ int iflag;
+{
+ if (iflag == FTW_D || iflag == FTW_DNR)
+ {
+ struct sdirlist *q;
+
+ q = (struct sdirlist *) xmalloc (sizeof (struct sdirlist));
+ q->qnext = qSdirlist;
+ q->zdir = zbufcpy (zfile);
+ qSdirlist = q;
+ }
+ else
+ {
+ if (remove (zfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/statsb.c b/gnu/libexec/uucp/libunix/statsb.c
new file mode 100644
index 00000000000..79a14c0e64c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/statsb.c
@@ -0,0 +1,572 @@
+/* statsb.c
+ System dependent routines for uustat.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/04 19:33:06 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+/* Local functions. */
+
+static int ussettime P((const char *z, time_t inow));
+static boolean fskill_or_rejuv P((pointer puuconf, const char *zid,
+ boolean fkill));
+
+/* See whether the user is permitted to kill arbitrary jobs. This is
+ true only for root and uucp. We check for uucp by seeing if the
+ real user ID and the effective user ID are the same; this works
+ because we should be suid to uucp, so our effective user ID will
+ always be uucp while our real user ID will be whoever ran the
+ program. */
+
+boolean
+fsysdep_privileged ()
+{
+ uid_t iuid;
+
+ iuid = getuid ();
+ return iuid == 0 || iuid == geteuid ();
+}
+
+/* Set file access time to the present. On many systems this could be
+ done by passing NULL to utime, but on some that doesn't work. This
+ routine is not time critical, so we never rely on NULL. */
+
+static int
+ussettime(z, inow)
+ const char *z;
+ time_t inow;
+{
+#if HAVE_UTIME_H
+ struct utimbuf s;
+
+ s.actime = inow;
+ s.modtime = inow;
+ return utime ((char *) z, &s);
+#else
+ time_t ai[2];
+
+ ai[0] = inow;
+ ai[1] = inow;
+ return utime ((char *) z, ai);
+#endif
+}
+
+/* Kill a job, given the jobid. */
+
+boolean
+fsysdep_kill_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, TRUE);
+}
+
+/* Rejuvenate a job, given the jobid. */
+
+boolean
+fsysdep_rejuvenate_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, FALSE);
+}
+
+/* Kill or rejuvenate a job, given the jobid. */
+
+static boolean
+fskill_or_rejuv (puuconf, zid, fkill)
+ pointer puuconf;
+ const char *zid;
+ boolean fkill;
+{
+ char *zfile;
+ char *zsys;
+ char bgrade;
+ time_t inow = 0;
+ int iuuconf;
+ struct uuconf_system ssys;
+ FILE *e;
+ boolean fret;
+ char *zline;
+ size_t cline;
+ int isys;
+
+ zfile = zsjobid_to_file (zid, &zsys, &bgrade);
+ if (zfile == NULL)
+ return FALSE;
+
+ if (! fkill)
+ inow = time ((time_t *) NULL);
+
+ iuuconf = uuconf_system_info (puuconf, zsys, &ssys);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ if (! funknown_system (puuconf, zsys, &ssys))
+ {
+ ulog (LOG_ERROR, "%s: Bad job id", zid);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ e = fopen (zfile, "r");
+ if (e == NULL)
+ {
+ if (errno == ENOENT)
+ ulog (LOG_ERROR, "%s: Job not found", zid);
+ else
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ /* Now we have to read through the file to identify any temporary
+ files. */
+ fret = TRUE;
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ struct scmd s;
+
+ if (! fparse_cmd (zline, &s))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s", zfile);
+ fret = FALSE;
+ continue;
+ }
+
+ /* You are only permitted to delete a job if you submitted it or
+ if you are root or uucp. */
+ if (strcmp (s.zuser, zsysdep_login_name ()) != 0
+ && ! fsysdep_privileged ())
+ {
+ ulog (LOG_ERROR, "%s: Not submitted by you", zid);
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ if (s.bcmd == 'S' || s.bcmd == 'E')
+ {
+ char *ztemp;
+
+ ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade);
+ if (ztemp == NULL)
+ fret = FALSE;
+ else
+ {
+ if (fkill)
+ isys = remove (ztemp);
+ else
+ isys = ussettime (ztemp, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s",
+ fkill ? "remove" : "utime", ztemp,
+ strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (ztemp);
+ }
+ }
+ }
+
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zsys);
+
+ if (fkill)
+ isys = remove (zfile);
+ else
+ isys = ussettime (zfile, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime",
+ zfile, strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Get the time a work job was queued. */
+
+long
+ixsysdep_work_time (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ char *zjobid, *zfile;
+ long iret;
+
+ zjobid = zsysdep_jobid (qsys, pseq);
+ zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL);
+ if (zfile == NULL)
+ return 0;
+ ubuffree (zjobid);
+ iret = ixsysdep_file_time (zfile);
+ ubuffree (zfile);
+ return iret;
+}
+
+/* Get the time a file was created (actually, the time it was last
+ modified). */
+
+long
+ixsysdep_file_time (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return ixsysdep_time ((long *) NULL);
+ }
+
+ return (long) s.st_mtime;
+}
+
+/* Start getting the status files. */
+
+boolean
+fsysdep_all_status_init (phold)
+ pointer *phold;
+{
+ DIR *qdir;
+
+ qdir = opendir ((char *) ".Status");
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno));
+ return FALSE;
+ }
+
+ *phold = (pointer) qdir;
+ return TRUE;
+}
+
+/* Get the next status file. */
+
+char *
+zsysdep_all_status (phold, pferr, qstat)
+ pointer phold;
+ boolean *pferr;
+ struct sstatus *qstat;
+{
+ DIR *qdir = (DIR *) phold;
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ errno = 0;
+ qentry = readdir (qdir);
+ if (qentry == NULL)
+ {
+ if (errno == 0)
+ *pferr = FALSE;
+ else
+ {
+ ulog (LOG_ERROR, "readdir: %s", strerror (errno));
+ *pferr = TRUE;
+ }
+ return NULL;
+ }
+
+ if (qentry->d_name[0] != '.')
+ {
+ struct uuconf_system ssys;
+
+ /* Hack seriously; fsysdep_get_status only looks at the
+ zname element of the qsys argument, so if we fake that we
+ can read the status file. This should really be done
+ differently. */
+ ssys.uuconf_zname = qentry->d_name;
+ if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL))
+ return zbufcpy (qentry->d_name);
+
+ /* If fsysdep_get_status fails, it will output an error
+ message. We just continue with the next entry, so that
+ most of the status files will be displayed. */
+ }
+ }
+}
+
+/* Finish getting the status file. */
+
+void
+usysdep_all_status_free (phold)
+ pointer phold;
+{
+ DIR *qdir = (DIR *) phold;
+
+ (void) closedir (qdir);
+}
+
+/* Get the status of all processes holding lock files. We do this by
+ invoking ps after we've figured out the process entries to use. */
+
+boolean
+fsysdep_lock_status ()
+{
+ DIR *qdir;
+ struct dirent *qentry;
+ int calc;
+ int *pai;
+ int cgot;
+ int aidescs[3];
+ char *zcopy, *ztok;
+ int cargs, iarg;
+ char **pazargs;
+
+ qdir = opendir ((char *) zSlockdir);
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno));
+ return FALSE;
+ }
+
+ /* We look for entries that start with "LCK.." and ignore everything
+ else. This won't find all possible lock files, but it should
+ find all the locks on terminals and systems. */
+
+ calc = 0;
+ pai = NULL;
+ cgot = 0;
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *zname;
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cread;
+ int ierr;
+ int ipid;
+
+ if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
+ continue;
+
+ zname = zsysdep_in_dir (zSlockdir, qentry->d_name);
+ o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ continue;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cread = read (o, &i, sizeof i);
+#else
+ cread = read (o, ab, sizeof ab - 1);
+#endif
+
+ ierr = errno;
+ (void) close (o);
+
+ if (cread < 0)
+ {
+ ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr));
+ ubuffree (zname);
+ continue;
+ }
+
+ ubuffree (zname);
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cread] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ printf ("%s: %d\n", qentry->d_name, ipid);
+
+ if (cgot >= calc)
+ {
+ calc += 10;
+ pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int));
+ }
+
+ pai[cgot] = ipid;
+ ++cgot;
+ }
+
+ if (cgot == 0)
+ return TRUE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ /* Parse PS_PROGRAM into an array of arguments. */
+ zcopy = zbufcpy (PS_PROGRAM);
+
+ cargs = 0;
+ for (ztok = strtok (zcopy, " \t");
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"))
+ ++cargs;
+
+ pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *));
+
+ memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM);
+ for (ztok = strtok (zcopy, " \t"), iarg = 0;
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"), ++iarg)
+ pazargs[iarg] = ztok;
+ pazargs[iarg] = NULL;
+
+#if ! HAVE_PS_MULTIPLE
+ /* We have to invoke ps multiple times. */
+ {
+ int i;
+ char *zlast, *zset;
+
+ zlast = pazargs[cargs - 1];
+ zset = zbufalc (strlen (zlast) + 20);
+ for (i = 0; i < cgot; i++)
+ {
+ pid_t ipid;
+
+ sprintf (zset, "%s%d", zlast, pai[i]);
+ pazargs[cargs - 1] = zset;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ }
+ ubuffree (zset);
+ }
+#else
+ {
+ char *zlast;
+ int i;
+ pid_t ipid;
+
+ zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1);
+ strcpy (zlast, pazargs[cargs - 1]);
+ for (i = 0; i < cgot; i++)
+ {
+ char ab[20];
+
+ sprintf (ab, "%d", pai[i]);
+ strcat (zlast, ab);
+ if (i + 1 < cgot)
+ strcat (zlast, ",");
+ }
+ pazargs[cargs - 1] = zlast;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ ubuffree (zlast);
+ }
+#endif
+
+ ubuffree (zcopy);
+ xfree ((pointer) pazargs);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/status.c b/gnu/libexec/uucp/libunix/status.c
new file mode 100644
index 00000000000..f403068a709
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/status.c
@@ -0,0 +1,212 @@
+/* status.c
+ Routines to get and set the status for a system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+
+/* If we are using HDB spool layout, store status using HDB status
+ values. SVR4 is a variant of HDB. */
+
+#define MAP_STATUS 1
+
+static const int aiMapstatus[] =
+{
+ 0, 13, 7, 6, 4, 20, 3, 2
+};
+#define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0]))
+
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+#define MAP_STATUS 0
+
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+/* Get the status of a system. This assumes that we are in the spool
+ directory. */
+
+boolean
+fsysdep_get_status (qsys, qret, pfnone)
+ const struct uuconf_system *qsys;
+ struct sstatus *qret;
+ boolean *pfnone;
+{
+ char *zname;
+ FILE *e;
+ char *zline;
+ char *zend, *znext;
+ boolean fbad;
+ int istat;
+
+ if (pfnone != NULL)
+ *pfnone = FALSE;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return FALSE;
+ }
+ zline = NULL;
+ }
+ else
+ {
+ size_t cline;
+
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ {
+ xfree ((pointer) zline);
+ zline = NULL;
+ }
+ (void) fclose (e);
+ }
+
+ if (zline == NULL)
+ {
+ /* There is either no status file for this system, or it's been
+ truncated, so fake a good status. */
+ qret->ttype = STATUS_COMPLETE;
+ qret->cretries = 0;
+ qret->ilast = 0;
+ qret->cwait = 0;
+ if (pfnone != NULL)
+ *pfnone = TRUE;
+ ubuffree (zname);
+ return TRUE;
+ }
+
+ /* It turns out that scanf is not used much in this program, so for
+ the benefit of small computers we avoid linking it in. This is
+ basically
+
+ sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries,
+ &qret->ilast, &qret->cwait);
+
+ except that it's done with strtol. */
+
+ fbad = FALSE;
+ istat = (int) strtol (zline, &zend, 10);
+ if (zend == zline)
+ fbad = TRUE;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map system dependent status
+ values on to our status values. */
+ {
+ int i;
+
+ for (i = 0; i < CMAPENTRIES; ++i)
+ {
+ if (aiMapstatus[i] == istat)
+ {
+ istat = i;
+ break;
+ }
+ }
+ }
+#endif /* MAP_STATUS */
+
+ if (istat < 0 || istat >= (int) STATUS_VALUES)
+ istat = (int) STATUS_COMPLETE;
+ qret->ttype = (enum tstatus_type) istat;
+ znext = zend;
+ qret->cretries = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->ilast = strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->cwait = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+
+ xfree ((pointer) zline);
+
+ if (fbad)
+ {
+ ulog (LOG_ERROR, "%s: Bad status file format", zname);
+ ubuffree (zname);
+ return FALSE;
+ }
+
+ ubuffree (zname);
+
+ return TRUE;
+}
+
+/* Set the status of a remote system. This assumes the system is
+ locked when this is called, and that the program is in the spool
+ directory. */
+
+boolean
+fsysdep_set_status (qsys, qset)
+ const struct uuconf_system *qsys;
+ const struct sstatus *qset;
+{
+ char *zname;
+ FILE *e;
+ int istat;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+
+ e = esysdep_fopen (zname, TRUE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return FALSE;
+ istat = (int) qset->ttype;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map istat onto a system
+ dependent number. */
+ if (istat >= 0 && istat < CMAPENTRIES)
+ istat = aiMapstatus[istat];
+#endif /* MAP_STATUS */
+
+ fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries,
+ qset->ilast, qset->cwait, azStatus[(int) qset->ttype],
+ qsys->uuconf_zname);
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/strerr.c b/gnu/libexec/uucp/libunix/strerr.c
new file mode 100644
index 00000000000..d2a6c2128d0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/strerr.c
@@ -0,0 +1,22 @@
+/* strerr.c
+ Return a string for a Unix errno value. */
+
+#include "uucp.h"
+
+#include <errno.h>
+
+#ifndef sys_nerr
+extern int sys_nerr;
+#endif
+#ifndef sys_errlist
+extern char *sys_errlist[];
+#endif
+
+char *
+strerror (ierr)
+ int ierr;
+{
+ if (ierr >= 0 && ierr < sys_nerr)
+ return sys_errlist[ierr];
+ return (char *) "unknown error";
+}
diff --git a/gnu/libexec/uucp/libunix/time.c b/gnu/libexec/uucp/libunix/time.c
new file mode 100644
index 00000000000..d0462433a7d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/time.c
@@ -0,0 +1,32 @@
+/* time.c
+ Get the current time. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Get the time in seconds since the epoch, with optional
+ microseconds. We use ixsysdep_process_time to get the microseconds
+ if it will work (it won't if it uses times, since that returns a
+ time based only on the process). */
+
+long
+ixsysdep_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+ return ixsysdep_process_time (pimicros);
+#else
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/tmpfil.c b/gnu/libexec/uucp/libunix/tmpfil.c
new file mode 100644
index 00000000000..2dac0024388
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/tmpfil.c
@@ -0,0 +1,83 @@
+/* tmpfil.c
+ Get a temporary file name.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#define ZDIGS \
+ "0123456789abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
+#define CDIGS (sizeof ZDIGS - 1)
+
+/*ARGSUSED*/
+char *
+zstemp_file (qsys)
+ const struct uuconf_system *qsys;
+{
+ static int icount;
+ const char *const zdigs = ZDIGS;
+ char ab[14];
+ pid_t ime;
+ int iset;
+
+ ab[0] = 'T';
+ ab[1] = 'M';
+ ab[2] = '.';
+
+ ime = getpid ();
+ iset = 3;
+ while (ime > 0 && iset < 10)
+ {
+ ab[iset] = zdigs[ime % CDIGS];
+ ime /= CDIGS;
+ ++iset;
+ }
+
+ ab[iset] = '.';
+ ++iset;
+
+ ab[iset] = zdigs[icount / CDIGS];
+ ++iset;
+ ab[iset] = zdigs[icount % CDIGS];
+ ++iset;
+
+ ab[iset] = '\0';
+
+ ++icount;
+ if (icount >= CDIGS * CDIGS)
+ icount = 0;
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42
+ return zbufcpy (ab);
+#endif
+#if SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ return zsysdep_in_dir (".Temp", ab);
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ return zsysdep_in_dir (qsys->uuconf_zname, ab);
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/trunc.c b/gnu/libexec/uucp/libunix/trunc.c
new file mode 100644
index 00000000000..c93e82e3940
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/trunc.c
@@ -0,0 +1,157 @@
+/* trunc.c
+ Truncate a file to zero length. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+/* Truncate a file to zero length. If this fails, it closes and
+ removes the file. We support a number of different means of
+ truncation, which is probably a waste of time since this function
+ is currently only called when the 'f' protocol resends a file. */
+
+#if HAVE_FTRUNCATE
+#undef HAVE_LTRUNC
+#define HAVE_LTRUNC 0
+#endif
+
+#if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC
+#ifdef F_CHSIZE
+#define HAVE_F_CHSIZE 1
+#else /* ! defined (F_CHSIZE) */
+#ifdef F_FREESP
+#define HAVE_F_FREESP 1
+#endif /* defined (F_FREESP) */
+#endif /* ! defined (F_CHSIZE) */
+#endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */
+
+openfile_t
+esysdep_truncate (e, zname)
+ openfile_t e;
+ const char *zname;
+{
+ int o;
+
+#if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP
+ int itrunc;
+
+ if (! ffilerewind (e))
+ {
+ ulog (LOG_ERROR, "rewind: %s", strerror (errno));
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ o = fileno (e);
+#else
+ o = e;
+#endif
+
+#if HAVE_FTRUNCATE
+ itrunc = ftruncate (o, 0);
+#endif
+#if HAVE_LTRUNC
+ itrunc = ltrunc (o, (long) 0, SEEK_SET);
+#endif
+#if HAVE_F_CHSIZE
+ itrunc = fcntl (o, F_CHSIZE, (off_t) 0);
+#endif
+#if HAVE_F_FREESP
+ /* This selection is based on an implementation of ftruncate by
+ kucharsk@Solbourne.com (William Kucharski). */
+ {
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = 0;
+ fl.l_type = F_WRLCK;
+
+ itrunc = fcntl (o, F_FREESP, &fl);
+ }
+#endif
+
+ if (itrunc != 0)
+ {
+#if HAVE_FTRUNCATE
+ ulog (LOG_ERROR, "ftruncate: %s", strerror (errno));
+#endif
+#ifdef HAVE_LTRUNC
+ ulog (LOG_ERROR, "ltrunc: %s", strerror (errno));
+#endif
+#ifdef HAVE_F_CHSIZE
+ ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno));
+#endif
+#ifdef HAVE_F_FREESP
+ ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno));
+#endif
+
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+ return e;
+#else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+ (void) ffileclose (e);
+ (void) remove (zname);
+
+ o = creat ((char *) zname, IPRIVATE_FILE_MODE);
+
+ if (o == -1)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zname, strerror (errno));
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno));
+ (void) close (o);
+ (void) remove (zname);
+ return NULL;
+ }
+#else /* ! USE_STDIO */
+ e = o;
+#endif /* ! USE_STDIO */
+
+ return e;
+#endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+}
diff --git a/gnu/libexec/uucp/libunix/uacces.c b/gnu/libexec/uucp/libunix/uacces.c
new file mode 100644
index 00000000000..c92c78eae35
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/uacces.c
@@ -0,0 +1,205 @@
+/* uacces.c
+ Check access to a file by user name.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#if HAVE_GETGRENT
+#include <grp.h>
+#if GETGRENT_DECLARATION_OK
+#ifndef getgrent
+extern struct group *getgrent ();
+#endif
+#endif
+#endif /* HAVE_GETGRENT */
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Do access(2) on a stat structure, except that the user name is
+ provided. If the user name in zuser is NULL, require the file to
+ be accessible to the world. Return TRUE if access is permitted,
+ FALSE otherwise. This does not log an error message. */
+
+boolean
+fsuser_access (q, imode, zuser)
+ const struct stat *q;
+ int imode;
+ const char *zuser;
+{
+ static char *zuser_hold;
+ static uid_t iuid_hold;
+ static gid_t igid_hold;
+ static int cgroups_hold;
+ static gid_t *paigroups_hold;
+ int ir, iw, ix, iand;
+
+ if (imode == F_OK)
+ return TRUE;
+
+ if (zuser != NULL)
+ {
+ /* We keep static variables around for the last user we did, to
+ avoid looking up a user multiple times. */
+ if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0)
+ {
+ struct passwd *qpwd;
+
+ if (zuser_hold != NULL)
+ {
+ ubuffree (zuser_hold);
+ zuser_hold = NULL;
+ cgroups_hold = 0;
+ xfree ((pointer) paigroups_hold);
+ paigroups_hold = NULL;
+ }
+
+ qpwd = getpwnam ((char *) zuser);
+ if (qpwd == NULL)
+ {
+ /* Check this as a remote request. */
+ zuser = NULL;
+ }
+ else
+ {
+#if HAVE_GETGRENT
+ struct group *qg;
+#endif
+
+ zuser_hold = zbufcpy (zuser);
+
+ iuid_hold = qpwd->pw_uid;
+ igid_hold = qpwd->pw_gid;
+
+#if HAVE_GETGRENT
+ /* Get the list of groups for this user. This is
+ definitely more appropriate for BSD than for System
+ V. It may just be a waste of time, and perhaps it
+ should be configurable. */
+ setgrent ();
+ while ((qg = getgrent ()) != NULL)
+ {
+ const char **pz;
+
+ if (qg->gr_gid == igid_hold)
+ continue;
+ for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++)
+ {
+ if ((*pz)[0] == *zuser
+ && strcmp (*pz, zuser) == 0)
+ {
+ paigroups_hold = ((gid_t *)
+ (xrealloc
+ ((pointer) paigroups_hold,
+ ((cgroups_hold + 1)
+ * sizeof (gid_t)))));
+ paigroups_hold[cgroups_hold] = qg->gr_gid;
+ ++cgroups_hold;
+ break;
+ }
+ }
+ }
+ endgrent ();
+#endif
+ }
+ }
+ }
+
+
+ /* Now do the actual access check. */
+
+ if (zuser != NULL)
+ {
+ /* The superuser can do anything. */
+ if (iuid_hold == 0)
+ return TRUE;
+
+ /* If this is the uid we're running under, there's no point to
+ checking access further, because when we actually try the
+ operation the system will do the checking for us. */
+ if (iuid_hold == geteuid ())
+ return TRUE;
+ }
+
+ ir = S_IROTH;
+ iw = S_IWOTH;
+ ix = S_IXOTH;
+
+ if (zuser != NULL)
+ {
+ if (iuid_hold == q->st_uid)
+ {
+ ir = S_IRUSR;
+ iw = S_IWUSR;
+ ix = S_IXUSR;
+ }
+ else
+ {
+ boolean fgroup;
+
+ fgroup = FALSE;
+ if (igid_hold == q->st_gid)
+ fgroup = TRUE;
+ else
+ {
+ int i;
+
+ for (i = 0; i < cgroups_hold; i++)
+ {
+ if (paigroups_hold[i] == q->st_gid)
+ {
+ fgroup = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fgroup)
+ {
+ ir = S_IRGRP;
+ iw = S_IWGRP;
+ ix = S_IXGRP;
+ }
+ }
+ }
+
+ iand = 0;
+ if ((imode & R_OK) != 0)
+ iand |= ir;
+ if ((imode & W_OK) != 0)
+ iand |= iw;
+ if ((imode & X_OK) != 0)
+ iand |= ix;
+
+ return (q->st_mode & iand) == iand;
+}
diff --git a/gnu/libexec/uucp/libunix/ufopen.c b/gnu/libexec/uucp/libunix/ufopen.c
new file mode 100644
index 00000000000..5a7b6f22b0d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ufopen.c
@@ -0,0 +1,218 @@
+/* ufopen.c
+ Open a file with the permissions of the invoking user.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Local functions. */
+
+static boolean fsuser_perms P((uid_t *pieuid));
+static boolean fsuucp_perms P((long ieuid));
+
+/* Switch to permissions of the invoking user. */
+
+static boolean
+fsuser_perms (pieuid)
+ uid_t *pieuid;
+{
+ uid_t ieuid, iuid;
+
+ ieuid = geteuid ();
+ iuid = getuid ();
+ if (pieuid != NULL)
+ *pieuid = ieuid;
+
+#if HAVE_SETREUID
+ /* Swap the effective user id and the real user id. We can then
+ swap them back again when we want to return to the uucp user's
+ permissions. */
+ if (setreuid (ieuid, iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) ieuid, (long) iuid, strerror (errno));
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set the effective user id to the real user id. Since the
+ effective user id is saved (it's the saved setuid) we will able
+ to set back to it later. If the real user id is root we will not
+ be able to switch back and forth, so don't even try. */
+ if (iuid != 0)
+ {
+ if (setuid (iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno));
+ return FALSE;
+ }
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* There's no way to switch between real permissions and effective
+ permissions. Just try to open the file with the uucp
+ permissions. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Restore the uucp permissions. */
+
+/*ARGSUSED*/
+static boolean
+fsuucp_perms (ieuid)
+ long ieuid;
+{
+#if HAVE_SETREUID
+ /* Swap effective and real user id's back to what they were. */
+ if (! fsuser_perms ((uid_t *) NULL))
+ return FALSE;
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set ourselves back to our original effective user id. */
+ if (setuid ((uid_t) ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno));
+ /* Is this error message helpful or confusing? */
+ if (errno == EPERM)
+ ulog (LOG_ERROR,
+ "Probably HAVE_SAVED_SETUID in policy.h should be set to 0");
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* We didn't switch, no need to switch back. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Open a file with the permissions of the invoking user. Ignore the
+ fbinary argument since Unix has no distinction between text and
+ binary files. */
+
+/*ARGSUSED*/
+openfile_t
+esysdep_user_fopen (zfile, frd, fbinary)
+ const char *zfile;
+ boolean frd;
+ boolean fbinary;
+{
+ uid_t ieuid;
+ openfile_t e;
+ const char *zerr;
+ int o = 0;
+
+ if (! fsuser_perms (&ieuid))
+ return EFILECLOSED;
+
+ zerr = NULL;
+
+#if USE_STDIO
+ e = fopen (zfile, frd ? "r" : "w");
+ if (e == NULL)
+ zerr = "fopen";
+ else
+ o = fileno (e);
+#else
+ if (frd)
+ {
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ zerr = "open";
+ }
+ else
+ {
+ e = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ zerr = "creat";
+ }
+ if (e >= 0)
+ {
+ o = e;
+ zerr = NULL;
+ }
+#endif
+
+ if (! fsuucp_perms ((long) ieuid))
+ {
+ if (ffileisopen (e))
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zfile, strerror (errno));
+#if ! HAVE_SETREUID
+ /* Are these error messages helpful or confusing? */
+#if HAVE_SAVED_SETUID
+ if (errno == EACCES && getuid () == 0)
+ ulog (LOG_ERROR,
+ "The superuser may only transfer files that are readable by %s",
+ OWNER);
+#else
+ if (errno == EACCES)
+ ulog (LOG_ERROR,
+ "You may only transfer files that are readable by %s", OWNER);
+#endif
+#endif /* ! HAVE_SETREUID */
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/ultspl.c b/gnu/libexec/uucp/libunix/ultspl.c
new file mode 100644
index 00000000000..34921d22804
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ultspl.c
@@ -0,0 +1,21 @@
+/* ultspl.c
+ See whether there is an Ultrix spool directory for a system. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+boolean
+fsultrix_has_spool (zsystem)
+ const char *zsystem;
+{
+ char *z;
+ boolean fret;
+
+ z = zsysdep_in_dir ("sys", zsystem);
+ fret = fsysdep_directory (z);
+ ubuffree (z);
+ return fret;
+}
diff --git a/gnu/libexec/uucp/libunix/unknwn.c b/gnu/libexec/uucp/libunix/unknwn.c
new file mode 100644
index 00000000000..76f53459475
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/unknwn.c
@@ -0,0 +1,43 @@
+/* unknwn.c
+ Check remote.unknown shell script. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Run the remote.unknown shell script. If it succeeds, we return
+ FALSE because that means that the system is not permitted to log
+ in. If the execution fails, we return TRUE. */
+
+boolean
+fsysdep_unknown_caller (zscript, zsystem)
+ const char *zscript;
+ const char *zsystem;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = zscript;
+ azargs[1] = zsystem;
+ azargs[2] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL, FALSE,
+ TRUE, (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, (const char *) NULL) != 0;
+}
diff --git a/gnu/libexec/uucp/libunix/uuto.c b/gnu/libexec/uucp/libunix/uuto.c
new file mode 100644
index 00000000000..debba9d6fd0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/uuto.c
@@ -0,0 +1,31 @@
+/* uuto.c
+ Translate a destination for uuto. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+/* Translate a uuto destination for Unix. */
+
+char *
+zsysdep_uuto (zdest, zlocalname)
+ const char *zdest;
+ const char *zlocalname;
+{
+ const char *zexclam;
+ char *zto;
+
+ zexclam = strrchr (zdest, '!');
+ if (zexclam == NULL)
+ return NULL;
+ zto = (char *) zbufalc (zexclam - zdest
+ + sizeof "!~/receive///"
+ + strlen (zexclam)
+ + strlen (zlocalname));
+ memcpy (zto, zdest, (size_t) (zexclam - zdest));
+ sprintf (zto + (zexclam - zdest), "!~/receive/%s/%s/",
+ zexclam + 1, zlocalname);
+ return zto;
+}
diff --git a/gnu/libexec/uucp/libunix/walk.c b/gnu/libexec/uucp/libunix/walk.c
new file mode 100644
index 00000000000..ab96123127d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/walk.c
@@ -0,0 +1,59 @@
+/* walk.c
+ Walk a directory tree. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int iswalk_dir P((const char *zname, const struct stat *qstat,
+ int iflag));
+
+/* Walk a directory tree. */
+
+static size_t cSlen;
+static void (*puSfn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+static pointer pSinfo;
+
+boolean
+usysdep_walk_tree (zdir, pufn, pinfo)
+ const char *zdir;
+ void (*pufn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+ pointer pinfo;
+{
+ cSlen = strlen (zdir) + 1;
+ puSfn = pufn;
+ pSinfo = pinfo;
+ return ftw ((char *) zdir, iswalk_dir, 5) == 0;
+}
+
+/* Pass a file found in the directory tree to the system independent
+ function. */
+
+/*ARGSUSED*/
+static int
+iswalk_dir (zname, qstat, iflag)
+ const char *zname;
+ const struct stat *qstat;
+ int iflag;
+{
+ char *zcopy;
+
+ if (iflag != FTW_F)
+ return 0;
+
+ zcopy = zbufcpy (zname + cSlen);
+
+ (*puSfn) (zname, zcopy, pSinfo);
+
+ ubuffree (zcopy);
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/wldcrd.c b/gnu/libexec/uucp/libunix/wldcrd.c
new file mode 100644
index 00000000000..cfbd15eb848
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/wldcrd.c
@@ -0,0 +1,212 @@
+/* wldcrd.c
+ Expand wildcards.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_GLOB && ! HAVE_GLOB_H
+#undef HAVE_GLOB
+#define HAVE_GLOB 0
+#endif
+
+#if HAVE_GLOB
+#include <glob.h>
+#endif
+
+/* Local variables to hold the wildcard in progress. */
+
+#if HAVE_GLOB
+static glob_t sSglob;
+static int iSglob;
+#else
+static char *zSwildcard_alloc;
+static char *zSwildcard;
+#endif
+
+/* Start getting a wildcarded file spec. Use the glob function if it
+ is available, and otherwise use the shell. */
+
+boolean
+fsysdep_wildcard_start (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ if (glob (zfile, 0, (int (*) ()) NULL, &sSglob) != 0)
+ sSglob.gl_pathc = 0;
+ iSglob = 0;
+ return TRUE;
+
+#else /* ! HAVE_GLOB */
+
+ char *zcmd, *zto;
+ const char *zfrom;
+ size_t c;
+ const char *azargs[4];
+ FILE *e;
+ pid_t ipid;
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+
+ zcmd = zbufalc (sizeof ECHO_PROGRAM + sizeof " " + 2 * strlen (zfile));
+ memcpy (zcmd, ECHO_PROGRAM, sizeof ECHO_PROGRAM - 1);
+ zto = zcmd + sizeof ECHO_PROGRAM - 1;
+ *zto++ = ' ';
+ zfrom = zfile;
+ while (*zfrom != '\0')
+ {
+ /* To avoid shell trickery, we quote all characters except
+ letters, digits, and wildcard specifiers. We don't quote '/'
+ to avoid an Ultrix sh bug. */
+ if (! isalnum (*zfrom)
+ && *zfrom != '*'
+ && *zfrom != '?'
+ && *zfrom != '['
+ && *zfrom != ']'
+ && *zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom++;
+ }
+ *zto = '\0';
+
+ azargs[0] = "/bin/sh";
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+
+ ubuffree (zcmd);
+
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen: %s", strerror (errno));
+ return FALSE;
+ }
+
+ zSwildcard_alloc = NULL;
+ c = 0;
+ if (getline (&zSwildcard_alloc, &c, e) <= 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ }
+
+ if (ixswait ((unsigned long) ipid, ECHO_PROGRAM) != 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ return FALSE;
+ }
+
+ if (zSwildcard_alloc == NULL)
+ return FALSE;
+
+ DEBUG_MESSAGE1 (DEBUG_EXECUTE,
+ "fsysdep_wildcard_start: got \"%s\"",
+ zSwildcard_alloc);
+
+ zSwildcard = zSwildcard_alloc;
+
+ return TRUE;
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Get the next wildcard spec. */
+
+/*ARGSUSED*/
+char *
+zsysdep_wildcard (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+ char *zret;
+
+ if (iSglob >= sSglob.gl_pathc)
+ return NULL;
+ zret = zbufcpy (sSglob.gl_pathv[iSglob]);
+ ++iSglob;
+ return zret;
+
+#else /* ! HAVE_GLOB */
+
+ char *zret;
+
+ if (zSwildcard_alloc == NULL || zSwildcard == NULL)
+ return NULL;
+
+ zret = zSwildcard;
+
+ while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+
+ if (*zSwildcard != '\0')
+ {
+ *zSwildcard = '\0';
+ ++zSwildcard;
+ while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+ }
+
+ if (*zSwildcard == '\0')
+ zSwildcard = NULL;
+
+ return zbufcpy (zret);
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Finish up getting wildcard specs. */
+
+boolean
+fsysdep_wildcard_end ()
+{
+#if HAVE_GLOB
+ globfree (&sSglob);
+ return TRUE;
+#else /* ! HAVE_GLOB */
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+ return TRUE;
+#endif /* ! HAVE_GLOB */
+}
diff --git a/gnu/libexec/uucp/libunix/work.c b/gnu/libexec/uucp/libunix/work.c
new file mode 100644
index 00000000000..3d055c282ed
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/work.c
@@ -0,0 +1,765 @@
+/* work.c
+ Routines to read command files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char work_rcsid[] = "$Id: work.c,v 1.1 1993/08/04 19:33:20 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Local functions. */
+
+static char *zswork_directory P((const char *zsystem));
+static boolean fswork_file P((const char *zsystem, const char *zfile,
+ char *pbgrade));
+static int iswork_cmp P((constpointer pkey, constpointer pdatum));
+
+/* These functions can support multiple actions going on at once.
+ This allows the UUCP package to send and receive multiple files at
+ the same time. This is a very flexible feature, but I'm not sure
+ it will actually be used all that much.
+
+ The ssfile structure holds a command file name and all the lines
+ read in from that command file. The union within the ssline
+ structure initially holds a line from the file and then holds a
+ pointer back to the ssfile structure; a pointer to this union is
+ used as a sequence pointer. The ztemp entry of the ssline
+ structure holds the name of a temporary file to delete, if any. */
+
+#define CFILELINES (10)
+
+struct ssline
+{
+ char *zline;
+ struct ssfile *qfile;
+ char *ztemp;
+};
+
+struct ssfile
+{
+ char *zfile;
+ int clines;
+ int cdid;
+ struct ssline aslines[CFILELINES];
+};
+
+/* Static variables for the work scan. */
+
+static char **azSwork_files;
+static size_t cSwork_files;
+static size_t iSwork_file;
+static struct ssfile *qSwork_file;
+
+/* Given a system name, return a directory to search for work. */
+
+static char *
+zswork_directory (zsystem)
+ const char *zsystem;
+{
+#if SPOOLDIR_V2
+ return zbufcpy (".");
+#endif /* SPOOLDIR_V2 */
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ return zbufcpy ("C.");
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ return zbufcpy (zsystem);
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_ULTRIX
+ return zsappend3 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ "C.");
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ return zsysdep_in_dir (zsystem, "C.");
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* See whether a file name from the directory returned by
+ zswork_directory is really a command for a particular system.
+ Return the command grade. */
+
+/*ARGSUSED*/
+static boolean
+fswork_file (zsystem, zfile, pbgrade)
+ const char *zsystem;
+ const char *zfile;
+ char *pbgrade;
+{
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+ int cfilesys, csys;
+
+ /* The file name should be C.ssssssgqqqq, where g is exactly one
+ letter and qqqq is exactly four numbers. The system name may be
+ truncated to six or seven characters. The system name of the
+ file must match the system name we're looking for, since there
+ could be work files for several systems in one directory. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ csys = strlen (zsystem);
+ cfilesys = strlen (zfile) - 7;
+ if (csys != cfilesys
+ && (csys < 6 || (cfilesys != 6 && cfilesys != 7)))
+ return FALSE;
+ *pbgrade = zfile[cfilesys + 2];
+ return strncmp (zfile + 2, zsystem, cfilesys) == 0;
+#endif /* V2 || BSD42 || BSD43 || ULTRIX */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ int clen;
+
+ /* The HDB file name should be C.ssssssgqqqq where g is exactly one
+ letter and qqqq is exactly four numbers or letters. We don't
+ check the system name, because it is guaranteed by the directory
+ we are looking in and some versions of uucp set it to the local
+ system rather than the remote one. I'm not sure of the exact
+ format of the SVR4 file name, but it does not include the grade
+ at all. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ clen = strlen (zfile);
+ if (clen < 7)
+ return FALSE;
+#if ! SPOOLDIR_SVR4
+ *pbgrade = zfile[clen - 5];
+#endif
+ return TRUE;
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_TAYLOR
+ /* We don't keep the system name in the file name, since that
+ forces truncation. Our file names are always C.gqqqq. */
+ *pbgrade = zfile[2];
+ return (zfile[0] == 'C'
+ && zfile[1] == '.'
+ && strlen (zfile) == 7);
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* A comparison function to look through the list of file names. */
+
+static int
+iswork_cmp (pkey, pdatum)
+ constpointer pkey;
+ constpointer pdatum;
+{
+ const char * const *pzkey = (const char * const *) pkey;
+ const char * const *pzdatum = (const char * const *) pdatum;
+
+ return strcmp (*pzkey, *pzdatum);
+}
+
+/* See whether there is any work to do for a particular system. */
+
+boolean
+fsysdep_has_work (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ qdir = opendir ((char *) zdir);
+ if (qdir == NULL)
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0')
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ ubuffree (zsub);
+ if (qdir == NULL)
+ continue;
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bgrade;
+
+ if (fswork_file (qsys->uuconf_zname, qentry->d_name, &bgrade))
+ {
+ closedir (qdir);
+#if SPOOLDIR_SVR4
+ closedir (qgdir);
+#endif
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+ return FALSE;
+}
+
+/* Initialize the work scan. We have to read all the files in the
+ work directory, so that we can sort them by work grade. The bgrade
+ argument is the minimum grade to consider. We don't want to return
+ files that we have already considered; usysdep_get_work_free will
+ clear the data out when we are done with the system. This returns
+ FALSE on error. */
+
+#define CWORKFILES (10)
+
+boolean
+fsysdep_get_work_init (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+ size_t chad;
+ size_t callocated;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+
+ qdir = opendir (zdir);
+ if (qdir == NULL)
+ {
+ boolean fret;
+
+ if (errno == ENOENT)
+ fret = TRUE;
+ else
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (zdir);
+ return fret;
+ }
+
+ chad = cSwork_files;
+ callocated = cSwork_files;
+
+ /* Sort the files we already know about so that we can check the new
+ ones with bsearch. It would be faster to use a hash table, and
+ the code should be probably be changed. The sort done at the end
+ of this function does not suffice because it only includes the
+ files added last time, and does not sort the entire array. Some
+ (bad) qsort implementations are very slow when given a sorted
+ array, which causes particularly bad effects here. */
+ if (chad > 0)
+ qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp);
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0'
+ || UUCONF_GRADE_CMP (bgrade, qgentry->d_name[0]) < 0)
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ if (qdir == NULL)
+ {
+ if (errno != ENOTDIR && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zsub,
+ strerror (errno));
+ ubuffree (zsub);
+ return FALSE;
+ }
+ ubuffree (zsub);
+ continue;
+ }
+ ubuffree (zsub);
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bfilegrade;
+ char *zname;
+
+#if ! SPOOLDIR_SVR4
+ zname = zbufcpy (qentry->d_name);
+#else
+ zname = zsysdep_in_dir (qgentry->d_name, qentry->d_name);
+ bfilegrade = qgentry->d_name[0];
+#endif
+
+ if (! fswork_file (qsys->uuconf_zname, qentry->d_name,
+ &bfilegrade)
+ || UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0
+ || (azSwork_files != NULL
+ && bsearch ((pointer) &zname,
+ (pointer) azSwork_files,
+ chad, sizeof (char *),
+ iswork_cmp) != NULL))
+ ubuffree (zname);
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "fsysdep_get_work_init: Found %s",
+ zname);
+
+ if (cSwork_files >= callocated)
+ {
+ callocated += CWORKFILES;
+ azSwork_files =
+ (char **) xrealloc ((pointer) azSwork_files,
+ callocated * sizeof (char *));
+ }
+
+ azSwork_files[cSwork_files] = zname;
+ ++cSwork_files;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+
+ /* Sorting the files alphabetically will get the grades in the
+ right order, since all the file prefixes are the same. */
+
+ if (cSwork_files > chad)
+ qsort ((pointer) (azSwork_files + chad), cSwork_files - chad,
+ sizeof (char *), iswork_cmp);
+
+ return TRUE;
+}
+
+/* Get the next work entry for a system. This must parse the next
+ line in the next work file. The type of command is set into
+ qcmd->bcmd; if there are no more commands we call
+ fsysdep_get_work_init to rescan, in case any came in since the last
+ call. If there are still no commands, qcmd->bcmd is set to 'H'.
+ Each field in the structure is set to point to a spot in an
+ malloced string. The only time we use the grade here is when
+ calling fsysdep_get_work_init to rescan. */
+
+boolean
+fsysdep_get_work (qsys, bgrade, qcmd)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ struct scmd *qcmd;
+{
+ char *zdir;
+
+ if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines)
+ qSwork_file = NULL;
+
+ if (azSwork_files == NULL)
+ {
+ qcmd->bcmd = 'H';
+ return TRUE;
+ }
+
+ zdir = NULL;
+
+ /* This loop continues until a line is returned. */
+ while (TRUE)
+ {
+ /* This loop continues until a file is opened and read in. */
+ while (qSwork_file == NULL)
+ {
+ FILE *e;
+ struct ssfile *qfile;
+ int iline, callocated;
+ char *zline;
+ size_t cline;
+ char *zname;
+
+ /* Read all the lines of a command file into memory. */
+ do
+ {
+ if (iSwork_file >= cSwork_files)
+ {
+ /* Rescan the work directory. */
+ if (! fsysdep_get_work_init (qsys, bgrade))
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+ if (iSwork_file >= cSwork_files)
+ {
+ qcmd->bcmd = 'H';
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+ if (zdir == NULL)
+ {
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ }
+
+ zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]);
+
+ ++iSwork_file;
+
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname,
+ strerror (errno));
+ ubuffree (zname);
+ }
+ }
+ while (e == NULL);
+
+ qfile = (struct ssfile *) xmalloc (sizeof (struct ssfile));
+ callocated = CFILELINES;
+ iline = 0;
+
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ if (iline >= callocated)
+ {
+ /* The sizeof (struct ssfile) includes CFILELINES
+ entries already, so using callocated * sizeof
+ (struct ssline) will give us callocated *
+ CFILELINES entries. */
+ qfile =
+ ((struct ssfile *)
+ xrealloc ((pointer) qfile,
+ (sizeof (struct ssfile) +
+ (callocated * sizeof (struct ssline)))));
+ callocated += CFILELINES;
+ }
+ qfile->aslines[iline].zline = zbufcpy (zline);
+ qfile->aslines[iline].qfile = NULL;
+ qfile->aslines[iline].ztemp = NULL;
+ iline++;
+ }
+
+ xfree ((pointer) zline);
+
+ if (fclose (e) != 0)
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+
+ if (iline == 0)
+ {
+ /* There were no lines in the file; this is a poll file,
+ for which we return a 'P' command. */
+ qfile->aslines[0].zline = zbufcpy ("P");
+ qfile->aslines[0].qfile = NULL;
+ qfile->aslines[0].ztemp = NULL;
+ iline = 1;
+ }
+
+ qfile->zfile = zname;
+ qfile->clines = iline;
+ qfile->cdid = 0;
+ qSwork_file = qfile;
+ }
+
+ /* This loop continues until all the lines from the current file
+ are used up, or a line is returned. */
+ while (TRUE)
+ {
+ int iline;
+
+ if (qSwork_file->cdid >= qSwork_file->clines)
+ {
+ /* We don't want to free qSwork_file here, since it must
+ remain until all the lines have been completed. It
+ is freed in fsysdep_did_work. */
+ qSwork_file = NULL;
+ /* Go back to the main loop which finds another file. */
+ break;
+ }
+
+ iline = qSwork_file->cdid;
+ ++qSwork_file->cdid;
+
+ /* Now parse the line into a command. */
+ if (! fparse_cmd (qSwork_file->aslines[iline].zline, qcmd))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s",
+ qSwork_file->zfile);
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ continue;
+ }
+
+ qSwork_file->aslines[iline].qfile = qSwork_file;
+ qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]);
+
+ if (qcmd->bcmd == 'S' || qcmd->bcmd == 'E')
+ {
+ char *zreal;
+
+ zreal = zsysdep_spool_file_name (qsys, qcmd->ztemp,
+ qcmd->pseq);
+ if (zreal == NULL)
+ {
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ ubuffree (zdir);
+ return FALSE;
+ }
+ qSwork_file->aslines[iline].ztemp = zreal;
+ }
+
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+}
+
+/* When a command has been complete, fsysdep_did_work is called. The
+ sequence entry was set above to be the address of an aslines
+ structure whose pfile entry points to the ssfile corresponding to
+ this file. We can then check whether all the lines have been
+ completed (they will have been if the pfile entry is NULL) and
+ remove the file if they have been. This means that we only remove
+ a command file if we manage to complete every transfer it specifies
+ in a single UUCP session. I don't know if this is how regular UUCP
+ works. */
+
+boolean
+fsysdep_did_work (pseq)
+ pointer pseq;
+{
+ struct ssfile *qfile;
+ struct ssline *qline;
+ int i;
+
+ qline = (struct ssline *) pseq;
+
+ ubuffree (qline->zline);
+ qline->zline = NULL;
+
+ qfile = qline->qfile;
+ qline->qfile = NULL;
+
+ /* Remove the temporary file, if there is one. It really doesn't
+ matter if this fails, and not checking the return value lets us
+ attempt to remove D.0 or whatever an unused temporary file is
+ called without complaining. */
+ if (qline->ztemp != NULL)
+ {
+ (void) remove (qline->ztemp);
+ ubuffree (qline->ztemp);
+ qline->ztemp = NULL;
+ }
+
+ /* If not all the lines have been returned from fsysdep_get_work,
+ we can't remove the file yet. */
+ if (qfile->cdid < qfile->clines)
+ return TRUE;
+
+ /* See whether all the commands have been completed. */
+ for (i = 0; i < qfile->clines; i++)
+ if (qfile->aslines[i].qfile != NULL)
+ return TRUE;
+
+ /* All commands have finished. */
+ if (remove (qfile->zfile) != 0)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", qfile->zfile,
+ strerror (errno));
+ return FALSE;
+ }
+
+ ubuffree (qfile->zfile);
+ xfree ((pointer) qfile);
+
+ if (qfile == qSwork_file)
+ qSwork_file = NULL;
+
+ return TRUE;
+}
+
+/* Free up the results of a work scan, when we're done with this
+ system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_work_free (qsys)
+ const struct uuconf_system *qsys;
+{
+ if (azSwork_files != NULL)
+ {
+ size_t i;
+
+ for (i = 0; i < cSwork_files; i++)
+ ubuffree ((pointer) azSwork_files[i]);
+ xfree ((pointer) azSwork_files);
+ azSwork_files = NULL;
+ cSwork_files = 0;
+ iSwork_file = 0;
+ }
+ if (qSwork_file != NULL)
+ {
+ int i;
+
+ ubuffree (qSwork_file->zfile);
+ for (i = 0; i < qSwork_file->cdid; i++)
+ {
+ ubuffree (qSwork_file->aslines[i].zline);
+ ubuffree (qSwork_file->aslines[i].ztemp);
+ }
+ for (i = qSwork_file->cdid; i < qSwork_file->clines; i++)
+ ubuffree (qSwork_file->aslines[i].zline);
+ xfree ((pointer) qSwork_file);
+ qSwork_file = NULL;
+ }
+}
+
+/* Save the temporary file used by a send command, and return an
+ informative message to mail to the requestor. This is called when
+ a file transfer failed, to make sure that the potentially valuable
+ file is not completely lost. */
+
+const char *
+zsysdep_save_temp_file (pseq)
+ pointer pseq;
+{
+ struct ssline *qline = (struct ssline *) pseq;
+ char *zto, *zslash;
+ size_t cwant;
+ static char *zbuf;
+ static int cbuf;
+
+ if (! fsysdep_file_exists (qline->ztemp))
+ return NULL;
+
+ zslash = strrchr (qline->ztemp, '/');
+ if (zslash == NULL)
+ zslash = qline->ztemp;
+ else
+ ++zslash;
+
+ zto = zbufalc (sizeof PRESERVEDIR + sizeof "/" + strlen (zslash));
+ sprintf (zto, "%s/%s", PRESERVEDIR, zslash);
+
+ if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE,
+ (const char *) NULL))
+ {
+ ubuffree (zto);
+ return "Could not move file to preservation directory";
+ }
+
+ cwant = sizeof "File saved as\n\t/" + strlen (zSspooldir) + strlen (zto);
+ if (cwant > cbuf)
+ {
+ ubuffree (zbuf);
+ zbuf = zbufalc (cwant);
+ cbuf = cwant;
+ }
+
+ sprintf (zbuf, "File saved as\n\t%s/%s", zSspooldir, zto);
+ ubuffree (zto);
+ return zbuf;
+}
+
+/* Get the jobid of a work file. This is needed by uustat. */
+
+char *
+zsysdep_jobid (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ return zsfile_to_jobid (qsys, ((struct ssline *) pseq)->qfile->zfile,
+ bsgrade (pseq));
+}
+
+/* Get the grade of a work file. The pseq argument can be NULL when
+ this is called from zsysdep_spool_file_name, and simply means that
+ this is a remote file; returning -1 will cause zsfind_file to do
+ the right thing. */
+
+char
+bsgrade (pseq)
+ pointer pseq;
+{
+ const char *zfile;
+ char bgrade;
+
+ if (pseq == NULL)
+ return -1;
+
+ zfile = ((struct ssline *) pseq)->qfile->zfile;
+
+#if ! SPOOLDIR_SVR4
+ bgrade = zfile[strlen (zfile) - CSEQLEN - 1];
+#else
+ bgrade = *(strchr (zfile, '/') + 1);
+#endif
+
+ return bgrade;
+}
diff --git a/gnu/libexec/uucp/libunix/xqtfil.c b/gnu/libexec/uucp/libunix/xqtfil.c
new file mode 100644
index 00000000000..2cdcc185a00
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtfil.c
@@ -0,0 +1,265 @@
+/* xqtfil.c
+ Routines to read execute files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.1 1993/08/04 19:33:21 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Under the V2 or BSD42 spool directory scheme, all execute files are
+ in the main spool directory. Under the BSD43 scheme, they are all
+ in the directory X.. Under the HDB or SVR4 scheme, they are in
+ directories named after systems. Under the ULTRIX scheme, they are
+ in X. subdirectories of subdirectories of sys. Under the TAYLOR
+ scheme, they are all in the subdirectory X. of a directory named
+ after the system.
+
+ This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search
+ directories of directories. */
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42
+#define ZDIR "."
+#define SUBDIRS 0
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+#define ZDIR "."
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_ULTRIX
+#define ZDIR "sys"
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_BSD43
+#define ZDIR "X."
+#define SUBDIRS 0
+#endif
+
+/* Static variables for the execute file scan. */
+
+static DIR *qSxqt_topdir;
+#if ! SUBDIRS
+static const char *zSdir;
+#else /* SUBDIRS */
+static char *zSdir;
+static DIR *qSxqt_dir;
+static char *zSsystem;
+#endif /* SUBDIRS */
+
+/* Initialize the scan for execute files. The function
+ usysdep_get_xqt_free will clear the data out when we are done with
+ the system. This returns FALSE on error. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_get_xqt_init ()
+{
+ usysdep_get_xqt_free ();
+
+ qSxqt_topdir = opendir ((char *) ZDIR);
+ if (qSxqt_topdir == NULL)
+ {
+ if (errno == ENOENT)
+ return TRUE;
+ ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Return the name of the next execute file to read and process. If
+ this returns NULL, *pferr must be checked. If will be TRUE on
+ error, FALSE if there are no more files. On a successful return
+ *pzsystem will be set to the system for which the execute file was
+ created. */
+
+char *
+zsysdep_get_xqt (pzsystem, pferr)
+ char **pzsystem;
+ boolean *pferr;
+{
+ *pferr = FALSE;
+
+ if (qSxqt_topdir == NULL)
+ return NULL;
+
+ /* This loop continues until we find a file. */
+ while (TRUE)
+ {
+ DIR *qdir;
+ struct dirent *q;
+
+#if ! SUBDIRS
+ zSdir = ZDIR;
+ qdir = qSxqt_topdir;
+#else /* SUBDIRS */
+ /* This loop continues until we find a subdirectory to read. */
+ while (qSxqt_dir == NULL)
+ {
+ struct dirent *qtop;
+
+ qtop = readdir (qSxqt_topdir);
+ if (qtop == NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ return NULL;
+ }
+
+ /* No system name may start with a dot (this is enforced by
+ tisystem in sysinf.c). This allows us to quickly skip
+ impossible directories. */
+ if (qtop->d_name[0] == '.')
+ continue;
+
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in top directory",
+ qtop->d_name);
+
+ ubuffree (zSdir);
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zSdir = zbufcpy (qtop->d_name);
+#endif
+#if SPOOLDIR_ULTRIX
+ zSdir = zsappend3 ("sys", qtop->d_name, "X.");
+#endif
+#if SPOOLDIR_TAYLOR
+ zSdir = zsysdep_in_dir (qtop->d_name, "X.");
+#endif
+
+ ubuffree (zSsystem);
+ zSsystem = zbufcpy (qtop->d_name);
+
+ qSxqt_dir = opendir (zSdir);
+
+ if (qSxqt_dir == NULL
+ && errno != ENOTDIR
+ && errno != ENOENT)
+ ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno));
+ }
+
+ qdir = qSxqt_dir;
+#endif /* SUBDIRS */
+
+ q = readdir (qdir);
+
+#if DEBUG > 1
+ if (q != NULL)
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in subdirectory %s",
+ q->d_name, zSdir);
+#endif
+
+ /* If we've found an execute file, return it. We have to get
+ the system name, which is easy for HDB or TAYLOR. For other
+ spool directory schemes, we have to pull it out of the X.
+ file name; this would be insecure, except that zsfind_file
+ clobbers the file name to include the real system name. */
+ if (q != NULL
+ && q->d_name[0] == 'X'
+ && q->d_name[1] == '.')
+ {
+ char *zret;
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+ *pzsystem = zbufcpy (zSsystem);
+#else
+ {
+ size_t clen;
+
+ clen = strlen (q->d_name) - 7;
+ *pzsystem = zbufalc (clen + 1);
+ memcpy (*pzsystem, q->d_name + 2, clen);
+ (*pzsystem)[clen] = '\0';
+ }
+#endif
+
+ zret = zsysdep_in_dir (zSdir, q->d_name);
+#if DEBUG > 1
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Returning %s (system %s)",
+ zret, *pzsystem);
+#endif
+ return zret;
+ }
+
+ /* If we've reached the end of the directory, then if we are
+ using subdirectories loop around to read the next one,
+ otherwise we are finished. */
+ if (q == NULL)
+ {
+ (void) closedir (qdir);
+#if SUBDIRS
+ qSxqt_dir = NULL;
+ continue;
+#else
+ qSxqt_topdir = NULL;
+ return NULL;
+#endif
+ }
+ }
+}
+
+/* Free up the results of an execute file scan, when we're done with
+ this system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_xqt_free ()
+{
+ if (qSxqt_topdir != NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ }
+#if SUBDIRS
+ if (qSxqt_dir != NULL)
+ {
+ (void) closedir (qSxqt_dir);
+ qSxqt_dir = NULL;
+ }
+ ubuffree (zSdir);
+ zSdir = NULL;
+ ubuffree (zSsystem);
+ zSsystem = NULL;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/xqtsub.c b/gnu/libexec/uucp/libunix/xqtsub.c
new file mode 100644
index 00000000000..53e290a0d14
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtsub.c
@@ -0,0 +1,698 @@
+/* xqtsub.c
+ System dependent functions used only by uuxqt.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 1993/08/04 19:33:22 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Get a value for EX_TEMPFAIL. */
+
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_TEMPFAIL
+#define EX_TEMPFAIL 75
+#endif
+
+/* Get the full pathname of the command to execute, given the list of
+ permitted commands and the allowed path. */
+
+char *
+zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
+ const char *zcmd;
+ char **pzcmds;
+ char **pzpath;
+ boolean *pferr;
+{
+ char **pz;
+
+ *pferr = FALSE;
+
+ for (pz = pzcmds; *pz != NULL; pz++)
+ {
+ char *zslash;
+
+ if (strcmp (*pz, "ALL") == 0)
+ break;
+
+ zslash = strrchr (*pz, '/');
+ if (zslash != NULL)
+ ++zslash;
+ else
+ zslash = *pz;
+ if (strcmp (zslash, zcmd) == 0
+ || strcmp (*pz, zcmd) == 0)
+ {
+ /* If we already have an absolute path, we can get out
+ immediately. */
+ if (**pz == '/')
+ return zbufcpy (*pz);
+ break;
+ }
+ }
+
+ /* If we didn't find this command, get out. */
+ if (*pz == NULL)
+ return NULL;
+
+ /* We didn't find an absolute pathname, so we must look through
+ the path. */
+ for (pz = pzpath; *pz != NULL; pz++)
+ {
+ char *zname;
+ struct stat s;
+
+ zname = zsysdep_in_dir (*pz, zcmd);
+ if (stat (zname, &s) == 0)
+ return zname;
+ }
+
+ *pferr = FALSE;
+ return NULL;
+}
+
+/* Expand a local filename for uuxqt. This is special because uuxqt
+ only wants to expand filenames that start with ~ (it does not want
+ to prepend the current directory to other names) and if the ~ is
+ double, it is turned into a single ~. This returns NULL to
+ indicate that no change was required; it has no way to return
+ error. */
+
+char *
+zsysdep_xqt_local_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ if (*zfile != '~')
+ return NULL;
+ if (zfile[1] == '~')
+ {
+ size_t clen;
+ char *zret;
+
+ clen = strlen (zfile);
+ zret = zbufalc (clen);
+ memcpy (zret, zfile + 1, clen);
+ return zret;
+ }
+ return zsysdep_local_file (zfile, qsys->uuconf_zpubdir);
+}
+
+#if ! ALLOW_FILENAME_ARGUMENTS
+
+/* Check to see whether an argument specifies a file name; if it does,
+ make sure that the file may legally be sent and/or received. For
+ Unix, we do not permit any occurrence of "/../" in the name, nor
+ may it start with "../". Otherwise, if it starts with "/" we check
+ against the list of permitted files. */
+
+boolean
+fsysdep_xqt_check_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ size_t clen;
+
+ clen = strlen (zfile);
+ if ((clen == sizeof "../" - 1
+ && strcmp (zfile, "../") == 0)
+ || (clen >= sizeof "/.." - 1
+ && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
+ || strstr (zfile, "/../") != NULL
+ || (*zfile == '/'
+ && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL)
+ || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL))))
+ {
+ ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* ! ALLOW_FILENAME_ARGUMENTS */
+
+/* Invoke the command specified by an execute file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
+ fshell, iseq, pzerror, pftemp)
+ const struct uuconf_system *qsys;
+ const char *zuser;
+ const char **pazargs;
+ const char *zfullcmd;
+ const char *zinput;
+ const char *zoutput;
+ boolean fshell;
+ int iseq;
+ char **pzerror;
+ boolean *pftemp;
+{
+ int aidescs[3];
+ boolean ferr;
+ pid_t ipid;
+ int ierr;
+ char abxqtdir[sizeof XQTDIR + 4];
+ const char *zxqtdir;
+ int istat;
+ char *zpath;
+#if ALLOW_SH_EXECUTION
+ const char *azshargs[4];
+#endif
+
+ *pzerror = NULL;
+ *pftemp = FALSE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ferr = FALSE;
+
+ if (zinput != NULL)
+ {
+ aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
+ if (aidescs[0] < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[0], F_SETFD,
+ fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr && zoutput != NULL)
+ {
+ aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
+ if (aidescs[1] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[1], F_SETFD,
+ fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr)
+ {
+ *pzerror = zstemp_file (qsys);
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ if (aidescs[2] < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (*pzerror, FALSE))
+ {
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ }
+ if (! ferr && aidescs[2] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ }
+ if (! ferr
+ && fcntl (aidescs[2], F_SETFD,
+ fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (ferr)
+ {
+ if (aidescs[0] != SPAWN_NULL)
+ (void) close (aidescs[0]);
+ if (aidescs[1] != SPAWN_NULL)
+ (void) close (aidescs[1]);
+ if (aidescs[2] != SPAWN_NULL)
+ (void) close (aidescs[2]);
+ ubuffree (*pzerror);
+ return FALSE;
+ }
+
+#if ALLOW_SH_EXECUTION
+ if (fshell)
+ {
+ azshargs[0] = "/bin/sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zfullcmd;
+ azshargs[3] = NULL;
+ pazargs = azshargs;
+ }
+#else
+ fshell = FALSE;
+#endif
+
+ if (qsys->uuconf_pzpath == NULL)
+ zpath = NULL;
+ else
+ {
+ size_t c;
+ char **pz;
+
+ c = 0;
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ c += strlen (*pz) + 1;
+ zpath = zbufalc (c);
+ *zpath = '\0';
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ {
+ strcat (zpath, *pz);
+ if (pz[1] != NULL)
+ strcat (zpath, ":");
+ }
+ }
+
+ /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
+ aren't already using the shell. */
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE,
+ ! fshell, zpath, qsys->uuconf_zname, zuser);
+
+ ierr = errno;
+
+ ubuffree (zpath);
+
+ if (aidescs[0] != SPAWN_NULL)
+ (void) close (aidescs[0]);
+ if (aidescs[1] != SPAWN_NULL)
+ (void) close (aidescs[1]);
+ if (aidescs[2] != SPAWN_NULL)
+ (void) close (aidescs[2]);
+
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
+ *pftemp = TRUE;
+ return FALSE;
+ }
+
+ istat = ixswait ((unsigned long) ipid, "Execution");
+
+ if (istat == EX_TEMPFAIL)
+ *pftemp = TRUE;
+
+ return istat == 0;
+}
+
+/* Lock a uuxqt process. */
+
+int
+ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ int i;
+
+ if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
+ cmaxuuxqts = 9999;
+ for (i = 0; i < cmaxuuxqts; i++)
+ {
+ sprintf (ab, "LCK.XQT.%d", i);
+ if (fsdo_lock (ab, TRUE, (boolean *) NULL))
+ break;
+ }
+ if (i >= cmaxuuxqts)
+ return -1;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
+ {
+ (void) fsdo_unlock (ab, TRUE);
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+/* Unlock a uuxqt process. */
+
+boolean
+fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
+ int iseq;
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ boolean fret;
+
+ fret = TRUE;
+
+ sprintf (ab, "LCK.XQT.%d", iseq);
+ if (! fsdo_unlock (ab, TRUE))
+ fret = FALSE;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_unlock (abcmd, TRUE))
+ fret = FALSE;
+ }
+
+ return fret;
+}
+
+/* See whether a particular uuxqt command is locked (this depends on
+ the implementation of fsdo_lock). */
+
+boolean
+fsysdep_uuxqt_locked (zcmd)
+ const char *zcmd;
+{
+ char ab[sizeof "LXQ.123456789"];
+ struct stat s;
+
+ sprintf (ab, "LXQ.%.9s", zcmd);
+ return stat (ab, &s) == 0;
+}
+
+/* Lock a particular execute file. */
+
+boolean
+fsysdep_lock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Unlock a particular execute file. */
+
+boolean
+fsysdep_unlock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_unlock (zcopy, TRUE);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Lock the execute directory. Since we use a different directory
+ depending on which LCK.XQT.dddd file we got, there is actually no
+ need to create a lock file. We do make sure that the directory
+ exists, though. */
+
+boolean
+fsysdep_lock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (mkdir (zxqtdir, S_IRWXU) < 0
+ && errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Unlock the execute directory and clear it out. The lock is
+ actually the LCK.XQT.dddd file, so we don't unlock it, but we do
+ remove all the files. */
+
+boolean
+fsysdep_unlock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ DIR *qdir;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ qdir = opendir ((char *) zxqtdir);
+ if (qdir != NULL)
+ {
+ struct dirent *qentry;
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *z;
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+ z = zsysdep_in_dir (zxqtdir, qentry->d_name);
+ if (remove (z) < 0)
+ {
+ int ierr;
+
+ ierr = errno;
+ if (! fsysdep_directory (z))
+ ulog (LOG_ERROR, "remove (%s): %s", z,
+ strerror (ierr));
+ else
+ (void) fsysdep_rmdir (z);
+ }
+ ubuffree (z);
+ }
+
+ closedir (qdir);
+ }
+
+ return TRUE;
+}
+
+/* Move files into the execution directory. */
+
+boolean
+fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
+ int cfiles;
+ const char *const *pzfrom;
+ const char *const *pzto;
+ boolean fto;
+ int iseq;
+ char **pzinput;
+{
+ char *zinput;
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ int i;
+
+ if (pzinput == NULL)
+ zinput = NULL;
+ else
+ zinput = *pzinput;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ for (i = 0; i < cfiles; i++)
+ {
+ const char *zfrom, *zto;
+ char *zfree;
+
+ if (pzto[i] == NULL)
+ continue;
+
+ zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
+
+ zfrom = pzfrom[i];
+ zto = zfree;
+
+ if (zinput != NULL && strcmp (zinput, zfrom) == 0)
+ {
+ *pzinput = zbufcpy (zto);
+ zinput = NULL;
+ }
+
+ if (! fto)
+ {
+ const char *ztemp;
+
+ ztemp = zfrom;
+ zfrom = zto;
+ zto = ztemp;
+ (void) chmod (zfrom, IPRIVATE_FILE_MODE);
+ }
+
+ if (rename (zfrom, zto) < 0)
+ {
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to
+ copy the file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
+ strerror (errno));
+ ubuffree (zfree);
+ break;
+ }
+
+ if (! fcopy_file (zfrom, zto, FALSE, FALSE))
+ {
+ ubuffree (zfree);
+ break;
+ }
+ if (remove (zfrom) < 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfrom,
+ strerror (errno));
+ }
+
+ if (fto)
+ (void) chmod (zto, IPUBLIC_FILE_MODE);
+
+ ubuffree (zfree);
+ }
+
+ if (i < cfiles)
+ {
+ if (fto)
+ (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
+ (char **) NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libuuconf/COPYING.LIB b/gnu/libexec/uucp/libuuconf/COPYING.LIB
new file mode 100644
index 00000000000..eb685a5ec98
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/libexec/uucp/libuuconf/MANIFEST b/gnu/libexec/uucp/libuuconf/MANIFEST
new file mode 100644
index 00000000000..8d1eb364663
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/MANIFEST
@@ -0,0 +1,92 @@
+README
+COPYING.LIB
+MANIFEST
+Makefile.in
+alloc.h
+syshdr.unx
+uucnfi.h
+addblk.c
+addstr.c
+allblk.c
+alloc.c
+base.c
+bool.c
+callin.c
+calout.c
+chatc.c
+cmdarg.c
+cmdfil.c
+cmdlin.c
+debfil.c
+deblev.c
+diacod.c
+dial.c
+diasub.c
+dnams.c
+errno.c
+errstr.c
+filnam.c
+freblk.c
+fredia.c
+free.c
+freprt.c
+fresys.c
+grdcmp.c
+hdial.c
+hdnams.c
+hinit.c
+hlocnm.c
+hport.c
+hrmunk.c
+hsinfo.c
+hsnams.c
+hsys.c
+hunk.c
+iniglb.c
+init.c
+int.c
+lckdir.c
+lineno.c
+llocnm.c
+local.c
+locnm.c
+logfil.c
+maxuxq.c
+mrgblk.c
+paramc.c
+port.c
+pubdir.c
+prtsub.c
+rdlocs.c
+rdperm.c
+reliab.c
+remunk.c
+sinfo.c
+snams.c
+split.c
+spool.c
+stafil.c
+syssub.c
+tcalou.c
+tdial.c
+tdialc.c
+tdnams.c
+tgcmp.c
+thread.c
+time.c
+tinit.c
+tlocnm.c
+tport.c
+tportc.c
+tsinfo.c
+tsnams.c
+tsys.c
+tval.c
+ugtlin.c
+unk.c
+val.c
+vinit.c
+vport.c
+vsinfo.c
+vsnams.c
+vsys.c
diff --git a/gnu/libexec/uucp/libuuconf/Makefile b/gnu/libexec/uucp/libuuconf/Makefile
new file mode 100644
index 00000000000..098382d1f6a
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/Makefile
@@ -0,0 +1,25 @@
+# This is the Makefile for the Taylor UUCP uuconf library
+
+LIB= uuconf
+SRCS= addblk.c addstr.c allblk.c alloc.c base.c bool.c callin.c \
+ calout.c chatc.c cmdarg.c cmdfil.c cmdlin.c debfil.c deblev.c \
+ diacod.c dial.c diasub.c dnams.c errno.c errstr.c filnam.c \
+ freblk.c fredia.c free.c freprt.c fresys.c grdcmp.c hdial.c \
+ hdnams.c hinit.c hlocnm.c hport.c hrmunk.c hsinfo.c hsnams.c \
+ hsys.c hunk.c iniglb.c init.c int.c lckdir.c lineno.c llocnm.c \
+ local.c locnm.c logfil.c maxuxq.c mrgblk.c paramc.c port.c \
+ prtsub.c pubdir.c rdlocs.c rdperm.c reliab.c remunk.c sinfo.c \
+ snams.c split.c spool.c stafil.c syssub.c tcalou.c tdial.c \
+ tdialc.c tdnams.c tgcmp.c thread.c time.c tinit.c tlocnm.c \
+ tport.c tportc.c tsinfo.c tsnams.c tsys.c tval.c ugtlin.c \
+ unk.c val.c vinit.c vport.c vsinfo.c vsnams.c vsys.c
+CFLAGS+= -I$(.CURDIR)/../common_sources \
+ -DNEWCONFIGLIB=\"$(newconfigdir)\"\
+ -DOLDCONFIGLIB=\"$(oldconfigdir)\"
+
+NOMAN= noman
+NOPROFILE= noprofile
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libuuconf/README b/gnu/libexec/uucp/libuuconf/README
new file mode 100644
index 00000000000..64a5eecf03a
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/README
@@ -0,0 +1,113 @@
+This is the README file for the beta release of the uuconf library.
+
+It was written by Ian Lance Taylor. I can be reached at ian@airs.com,
+or, equivalently, uunet!airs!ian, or c/o Infinity Development Systems,
+P.O. Box 520, Waltham MA, 02254.
+
+This package is covered by the Gnu Library General Public License.
+See the file COPYING.LIB for details. If you would like to do
+something with this package that you feel is reasonable but you feel
+is prohibited by the license, contact me to see if we can work it out.
+
+WHAT IT IS
+
+This is a beta release of the uuconf library. The uuconf library
+provides a set of functions which can be used to read UUCP
+configuration files. V2, HDB, and Taylor UUCP configuration files are
+supported.
+
+Also included are two programs, uuchk and uuconv. uuchk will read
+configuration files and display the information it finds in a verbose
+format. This can be helpful to ensure that your configuration files
+are set up as you expect. uuconv can be used to convert configuration
+files from one type to another. This is particularly helpful for
+people installing Taylor UUCP on a existing system who want to take
+advantage of the additional functionality provided by the Taylor UUCP
+configuration files.
+
+This is strictly a beta release. The library provides all the
+information needed for uuchk and uuconv, but does not yet provide
+everything needed for uucp or cu. I am releasing it now to get
+feedback and to provide the uuconv program to people using Taylor
+UUCP.
+
+This may well be the only time this library is release independently.
+This library will be provided with Taylor UUCP, and future releases of
+the library will probably only occur as part of the complete Taylor
+UUCP package.
+
+HOW TO USE IT
+
+Configure and optionally install the package as described in INSTALL.
+
+The functions provided by the library are described in uuconf.h. At
+the moment there is no additional documentation.
+
+Programs which use the library should include uuconf.h, and should not
+include any of the other header files. The functions listed in
+uuconf.h all begin with the string "uuconf_". The internal library
+functions all begin with the string "_uuconf_". The internal library
+functions should not be called by a program which uses the library, as
+they may change in future releases. The uuchk program is an example
+of program which uses the library; uuconv is not, as it relies upon
+internal data structures.
+
+The uuchk program takes a single optional option, -I, which may be
+used to specify an alternate Taylor UUCP main configuration file. The
+default configuration file is $(newconfigdir)/config ($(newconfigdir)
+is defined in Makefile). For example:
+ uuchk
+ uuchk -I /usr/tmp/tstuu/Config1
+
+The uuconv program requires two options: -i to specify the input type
+and -o to specify the output type. Both options take a string
+argument, which must be one of "v2", "hdb", or "taylor". uuconv also
+takes an optional -I option, which is the same as the -I option to
+uuchk. The conversion is not intended to be perfect, and the results
+should be manually inspected. In particular, the dialcode file is not
+converted (as the format is the same for all three configuration file
+types, it may simply be copied to the appropriate new name). uuconv
+will create new files in the current working directory. For example:
+ uuconv -i hdb -o taylor
+ uuconv -i taylor -I /usr/tmp/tstuu/Config1 -o v2
+
+NOTES
+
+The initial underscore on the internal library functions is required
+by the GNU standards. As ANSI C reserves external identifiers with an
+initial underscore for the implementation, it is possible, though
+unlikely, that this will cause problems on other implementations; no
+workaround is currently provided for such problems.
+
+The library functions rely upon the following functions:
+
+ fclose fopen free fseek
+ ftell getc isalpha isdigit
+ islower isspace isupper malloc
+ realloc rewind strchr strcmp
+ strcspn strlen strncmp strspn
+ tolower toupper
+
+and the following header files:
+
+ ctype.h errno.h stdio.h
+
+If the following functions cannot be found by the configure script,
+replacements will be used (the replacement for strerror is Unix
+dependent):
+
+ getline memcpy strcasecmp strdup
+ strerror strncasecmp strtol
+
+If the following header files are found, they will be included:
+
+ libc.h limits.h memory.h stddef.h
+ stdlib.h string.h strings.h sys/types.h
+
+The following functions are required on Unix only:
+
+ fcntl fileno
+
+The following headers are used, if found, on Unix only:
+
+ fcntl.h sys/file.h
diff --git a/gnu/libexec/uucp/libuuconf/addblk.c b/gnu/libexec/uucp/libuuconf/addblk.c
new file mode 100644
index 00000000000..6244dad875e
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/addblk.c
@@ -0,0 +1,56 @@
+/* addblk.c
+ Add an malloc block to a memory block.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_addblk_rcsid[] = "$Id: addblk.c,v 1.1 1993/08/04 19:33:31 jtc Exp $";
+#endif
+
+#include "alloc.h"
+
+/* Add a memory buffer allocated by malloc to a memory block. This is
+ used by the uuconf_cmd functions so that they don't have to
+ constantly copy data into memory. Returns 0 on success, non 0 on
+ failure. */
+
+int
+uuconf_add_block (pblock, padd)
+ pointer pblock;
+ pointer padd;
+{
+ struct sblock *q = (struct sblock *) pblock;
+ struct sadded *qnew;
+
+ qnew = (struct sadded *) uuconf_malloc (pblock, sizeof (struct sadded));
+ if (qnew == NULL)
+ return 1;
+
+ qnew->qnext = q->qadded;
+ qnew->padded = padd;
+ q->qadded = qnew;
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libuuconf/addstr.c b/gnu/libexec/uucp/libuuconf/addstr.c
new file mode 100644
index 00000000000..8498d502c9c
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/addstr.c
@@ -0,0 +1,139 @@
+/* addstr.c
+ Add a string to a list of strings.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_addstr_rcsid[] = "$Id: addstr.c,v 1.1 1993/08/04 19:33:32 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+/* When setting system information, we need to be able to distinguish
+ between a value that is not set and a value that has been set to
+ NULL. We do this by initializing the value to point to the
+ variable _uuconf_unset, and then correcting it in the function
+ _uuconf_isystem_basic_default. This variable is declared in this
+ file because some linkers will apparently not pull in an object
+ file which merely declarates a variable. This functions happens to
+ be pulled in by almost everything. */
+
+char *_uuconf_unset;
+
+/* Add a string to a list of strings. The list is maintained as an
+ array of elements ending in NULL. The total number of available
+ slots is always a multiple of CSLOTS, so by counting the current
+ number of elements we can tell whether a new slot is needed. If
+ the fcopy argument is TRUE, the new string is duplicated into
+ memory. If the fcheck argument is TRUE, this does not add a string
+ that is already in the list. The pblock argument may be used to do
+ the allocations within a memory block. This returns a standard
+ uuconf error code. */
+
+#define CSLOTS (8)
+
+int
+_uuconf_iadd_string (qglobal, zadd, fcopy, fcheck, ppzstrings, pblock)
+ struct sglobal *qglobal;
+ char *zadd;
+ boolean fcopy;
+ boolean fcheck;
+ char ***ppzstrings;
+ pointer pblock;
+{
+ char **pz;
+ size_t c;
+
+ if (fcheck && *ppzstrings != NULL)
+ {
+ for (pz = *ppzstrings; *pz != NULL; pz++)
+ if (strcmp (zadd, *pz) == 0)
+ return UUCONF_SUCCESS;
+ }
+
+ if (fcopy)
+ {
+ size_t clen;
+ char *znew;
+
+ clen = strlen (zadd) + 1;
+ znew = (char *) uuconf_malloc (pblock, clen);
+ if (znew == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ memcpy ((pointer) znew, (pointer) zadd, clen);
+ zadd = znew;
+ }
+
+ pz = *ppzstrings;
+ if (pz == NULL || pz == (char **) &_uuconf_unset)
+ {
+ pz = (char **) uuconf_malloc (pblock, CSLOTS * sizeof (char *));
+ if (pz == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ *ppzstrings = pz;
+ }
+ else
+ {
+ c = 0;
+ while (*pz != NULL)
+ {
+ ++pz;
+ ++c;
+ }
+
+ if ((c + 1) % CSLOTS == 0)
+ {
+ char **pznew;
+
+ pznew = (char **) uuconf_malloc (pblock,
+ ((c + 1 + CSLOTS)
+ * sizeof (char *)));
+ if (pznew == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ memcpy ((pointer) pznew, (pointer) *ppzstrings,
+ c * sizeof (char *));
+ uuconf_free (pblock, *ppzstrings);
+ *ppzstrings = pznew;
+ pz = pznew + c;
+ }
+ }
+
+ pz[0] = zadd;
+ pz[1] = NULL;
+
+ return UUCONF_SUCCESS;
+}
diff --git a/gnu/libexec/uucp/libuuconf/allblk.c b/gnu/libexec/uucp/libuuconf/allblk.c
new file mode 100644
index 00000000000..b3dd7e0a762
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/allblk.c
@@ -0,0 +1,51 @@
+/* allblk.c
+ Allocate a memory block.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_allblk_rcsid[] = "$Id: allblk.c,v 1.1 1993/08/04 19:33:33 jtc Exp $";
+#endif
+
+#include "alloc.h"
+
+/* Allocate a new memory block. If this fails, uuconf_errno will be
+ set, and the calling routine may return UUCONF_MALLOC_FAILED |
+ UUCONF_ERROR_ERRNO. */
+
+pointer
+uuconf_malloc_block ()
+{
+ struct sblock *qret;
+
+ qret = (struct sblock *) malloc (sizeof (struct sblock));
+ if (qret == NULL)
+ return NULL;
+ qret->qnext = NULL;
+ qret->ifree = 0;
+ qret->plast = NULL;
+ qret->qadded = NULL;
+ return (pointer) qret;
+}
diff --git a/gnu/libexec/uucp/libuuconf/alloc.c b/gnu/libexec/uucp/libuuconf/alloc.c
new file mode 100644
index 00000000000..2808c62088f
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/alloc.c
@@ -0,0 +1,82 @@
+/* alloc.c
+ Allocate within a memory block.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_alloc_rcsid[] = "$Id: alloc.c,v 1.1 1993/08/04 19:33:34 jtc Exp $";
+#endif
+
+#include "alloc.h"
+
+/* Allocate some memory out of a memory block. If the memory block is
+ NULL, this just calls malloc; this is convenient for a number of
+ routines. If this fails, uuconf_errno will be set, and the calling
+ routine may return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO. */
+
+pointer
+uuconf_malloc (pblock, c)
+ pointer pblock;
+ size_t c;
+{
+ struct sblock *q = (struct sblock *) pblock;
+ pointer pret;
+
+ if (c == 0)
+ return NULL;
+
+ if (q == NULL)
+ return malloc (c);
+
+ /* Make sure that c is aligned to a double boundary. */
+ c = ((c + sizeof (double) - 1) / sizeof (double)) * sizeof (double);
+
+ while (q->ifree + c > CALLOC_SIZE)
+ {
+ if (q->qnext != NULL)
+ q = q->qnext;
+ else
+ {
+ if (c > CALLOC_SIZE)
+ q->qnext = (struct sblock *) malloc (sizeof (struct sblock)
+ + c - CALLOC_SIZE);
+ else
+ q->qnext = (struct sblock *) malloc (sizeof (struct sblock));
+ if (q->qnext == NULL)
+ return NULL;
+ q = q->qnext;
+ q->qnext = NULL;
+ q->ifree = 0;
+ q->qadded = NULL;
+ break;
+ }
+ }
+
+ pret = q->u.ab + q->ifree;
+ q->ifree += c;
+ q->plast = pret;
+
+ return pret;
+}
diff --git a/gnu/libexec/uucp/libuuconf/alloc.h b/gnu/libexec/uucp/libuuconf/alloc.h
new file mode 100644
index 00000000000..c5c9cad8e32
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/alloc.h
@@ -0,0 +1,71 @@
+/* alloc.h
+ Header file for uuconf memory allocation routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* This header file is private to the uuconf memory allocation
+ routines, and should not be included by any other files. */
+
+/* We want to be able to keep track of allocated memory blocks, so
+ that we can free them up later. This will let us free up all the
+ memory allocated to hold information for a system, for example. We
+ do this by allocating large chunks and doling them out. Calling
+ uuconf_malloc_block will return a pointer to a magic cookie which
+ can then be passed to uuconf_malloc and uuconf_free. Passing the
+ pointer to uuconf_free_block will free all memory allocated for
+ that block. */
+
+/* We allocate this much space in each block. On most systems, this
+ will make the actual structure 1024 bytes, which may be convenient
+ for some types of memory allocators. */
+#define CALLOC_SIZE (1008)
+
+/* This is the actual structure of a block. */
+struct sblock
+{
+ /* Next block in linked list. */
+ struct sblock *qnext;
+ /* Index of next free spot. */
+ size_t ifree;
+ /* Last value returned by uuconf_malloc for this block. */
+ pointer plast;
+ /* List of additional memory blocks. */
+ struct sadded *qadded;
+ /* Buffer of data. We put it in a union with a double to make sure
+ it is adequately aligned. */
+ union
+ {
+ char ab[CALLOC_SIZE];
+ double l;
+ } u;
+};
+
+/* There is a linked list of additional memory blocks inserted by
+ uuconf_add_block. */
+struct sadded
+{
+ /* The next in the list. */
+ struct sadded *qnext;
+ /* The added block. */
+ pointer padded;
+};
diff --git a/gnu/libexec/uucp/libuuconf/base.c b/gnu/libexec/uucp/libuuconf/base.c
new file mode 100644
index 00000000000..c40f660523a
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/base.c
@@ -0,0 +1,54 @@
+/* base.c
+ Subroutine to turn a cmdtab_offset table into a uuconf_cmdtab table.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_base_rcsid[] = "$Id: base.c,v 1.1 1993/08/04 19:33:38 jtc Exp $";
+#endif
+
+/* This turns a cmdtab_offset table into a uuconf_cmdtab table. Each
+ offset is adjusted by a base value. */
+
+void
+_uuconf_ucmdtab_base (qoff, celes, pbase, qset)
+ register const struct cmdtab_offset *qoff;
+ size_t celes;
+ char *pbase;
+ register struct uuconf_cmdtab *qset;
+{
+ register size_t i;
+
+ for (i = 0; i < celes; i++, qoff++, qset++)
+ {
+ qset->uuconf_zcmd = qoff->zcmd;
+ qset->uuconf_itype = qoff->itype;
+ if (qoff->ioff == (size_t) -1)
+ qset->uuconf_pvar = NULL;
+ else
+ qset->uuconf_pvar = pbase + qoff->ioff;
+ qset->uuconf_pifn = qoff->pifn;
+ }
+}