From 41c799d4e0ace633b1a4d5333466b00803ca42a4 Mon Sep 17 00:00:00 2001 From: "J.T. Conklin" Date: Thu, 5 Aug 1993 18:28:27 +0000 Subject: [PATCH] Taylor UUCP 1.04 --- gnu/libexec/uucp/COPYING | 339 +++ gnu/libexec/uucp/ChangeLog | 3152 ++++++++++++++++++++++ gnu/libexec/uucp/Makefile | 8 + gnu/libexec/uucp/Makefile.inc | 30 + gnu/libexec/uucp/README | 207 ++ gnu/libexec/uucp/TODO | 573 ++++ gnu/libexec/uucp/VERSION | 4 + gnu/libexec/uucp/common_sources/chat.c | 1429 ++++++++++ gnu/libexec/uucp/common_sources/conf.h | 444 +++ gnu/libexec/uucp/common_sources/conn.c | 552 ++++ gnu/libexec/uucp/common_sources/conn.h | 312 +++ gnu/libexec/uucp/common_sources/copy.c | 202 ++ gnu/libexec/uucp/common_sources/cu.h | 80 + gnu/libexec/uucp/common_sources/getopt.h | 120 + gnu/libexec/uucp/common_sources/log.c | 699 +++++ gnu/libexec/uucp/common_sources/policy.h | 521 ++++ gnu/libexec/uucp/common_sources/prot.c | 237 ++ gnu/libexec/uucp/common_sources/prot.h | 250 ++ gnu/libexec/uucp/common_sources/sysdep.h | 530 ++++ gnu/libexec/uucp/common_sources/system.h | 950 +++++++ gnu/libexec/uucp/common_sources/tcp.c | 470 ++++ gnu/libexec/uucp/common_sources/tli.c | 644 +++++ gnu/libexec/uucp/common_sources/trans.h | 268 ++ gnu/libexec/uucp/common_sources/util.c | 144 + gnu/libexec/uucp/common_sources/uuconf.h | 1496 ++++++++++ gnu/libexec/uucp/common_sources/uucp.h | 367 +++ gnu/libexec/uucp/common_sources/uudefs.h | 445 +++ gnu/libexec/uucp/contrib/Dial.Hayes | 108 + gnu/libexec/uucp/contrib/Hangup.Hayes | 57 + gnu/libexec/uucp/contrib/Login.LAT | 137 + gnu/libexec/uucp/contrib/Login.PortSel | 133 + gnu/libexec/uucp/contrib/Login.VMS | 96 + gnu/libexec/uucp/contrib/Makefile.uurt | 30 + gnu/libexec/uucp/contrib/Makefile.xchat | 31 + gnu/libexec/uucp/contrib/README | 46 + gnu/libexec/uucp/contrib/README-UURATE | 20 + gnu/libexec/uucp/contrib/README-XCHAT | 42 + gnu/libexec/uucp/contrib/savelog.man | 130 + gnu/libexec/uucp/contrib/savelog.sh | 247 ++ gnu/libexec/uucp/contrib/stats.sh | 27 + gnu/libexec/uucp/contrib/tstout.c | 158 ++ gnu/libexec/uucp/contrib/uuclean | 23 + gnu/libexec/uucp/contrib/uuq.sh | 125 + gnu/libexec/uucp/contrib/uurate.c | 657 +++++ gnu/libexec/uucp/contrib/uurate.man | 217 ++ gnu/libexec/uucp/contrib/uureroute | 91 + gnu/libexec/uucp/contrib/uusnap.c | 321 +++ gnu/libexec/uucp/contrib/uutraf | 203 ++ gnu/libexec/uucp/contrib/uutry | 43 + gnu/libexec/uucp/contrib/xc-conf.h-dist | 38 + gnu/libexec/uucp/contrib/xchat.c | 1444 ++++++++++ gnu/libexec/uucp/contrib/xchat.man | 614 +++++ gnu/libexec/uucp/cu/Makefile | 16 + gnu/libexec/uucp/cu/cu.1 | 286 ++ gnu/libexec/uucp/cu/cu.c | 2068 ++++++++++++++ gnu/libexec/uucp/libunix/MANIFEST | 76 + gnu/libexec/uucp/libunix/Makefile | 22 + gnu/libexec/uucp/libunix/access.c | 83 + gnu/libexec/uucp/libunix/addbas.c | 50 + gnu/libexec/uucp/libunix/app3.c | 29 + gnu/libexec/uucp/libunix/app4.c | 33 + gnu/libexec/uucp/libunix/basnam.c | 22 + gnu/libexec/uucp/libunix/bytfre.c | 19 + gnu/libexec/uucp/libunix/chmod.c | 25 + gnu/libexec/uucp/libunix/cohtty.c | 244 ++ gnu/libexec/uucp/libunix/cusub.c | 1163 ++++++++ gnu/libexec/uucp/libunix/cwd.c | 55 + gnu/libexec/uucp/libunix/detach.c | 186 ++ gnu/libexec/uucp/libunix/dirent.c | 123 + gnu/libexec/uucp/libunix/dup2.c | 69 + gnu/libexec/uucp/libunix/efopen.c | 132 + gnu/libexec/uucp/libunix/epopen.c | 85 + gnu/libexec/uucp/libunix/exists.c | 16 + gnu/libexec/uucp/libunix/filnam.c | 376 +++ gnu/libexec/uucp/libunix/fsusg.c | 231 ++ gnu/libexec/uucp/libunix/fsusg.h | 31 + gnu/libexec/uucp/libunix/ftw.c | 250 ++ gnu/libexec/uucp/libunix/getcwd.c | 59 + gnu/libexec/uucp/libunix/indir.c | 133 + gnu/libexec/uucp/libunix/init.c | 394 +++ gnu/libexec/uucp/libunix/isdir.c | 18 + gnu/libexec/uucp/libunix/isfork.c | 25 + gnu/libexec/uucp/libunix/iswait.c | 159 ++ gnu/libexec/uucp/libunix/jobid.c | 101 + gnu/libexec/uucp/libunix/lcksys.c | 41 + gnu/libexec/uucp/libunix/link.c | 38 + gnu/libexec/uucp/libunix/locfil.c | 95 + gnu/libexec/uucp/libunix/lock.c | 477 ++++ gnu/libexec/uucp/libunix/loctim.c | 25 + gnu/libexec/uucp/libunix/mail.c | 85 + gnu/libexec/uucp/libunix/mkdir.c | 58 + gnu/libexec/uucp/libunix/mkdirs.c | 49 + gnu/libexec/uucp/libunix/mode.c | 33 + gnu/libexec/uucp/libunix/move.c | 176 ++ gnu/libexec/uucp/libunix/opensr.c | 244 ++ gnu/libexec/uucp/libunix/pause.c | 96 + gnu/libexec/uucp/libunix/picksb.c | 230 ++ gnu/libexec/uucp/libunix/portnm.c | 51 + gnu/libexec/uucp/libunix/proctm.c | 197 ++ gnu/libexec/uucp/libunix/recep.c | 197 ++ gnu/libexec/uucp/libunix/remove.c | 13 + gnu/libexec/uucp/libunix/rename.c | 27 + gnu/libexec/uucp/libunix/rmdir.c | 43 + gnu/libexec/uucp/libunix/run.c | 75 + gnu/libexec/uucp/libunix/seq.c | 126 + gnu/libexec/uucp/libunix/serial.c | 2977 ++++++++++++++++++++ gnu/libexec/uucp/libunix/signal.c | 208 ++ gnu/libexec/uucp/libunix/sindir.c | 26 + gnu/libexec/uucp/libunix/size.c | 27 + gnu/libexec/uucp/libunix/sleep.c | 14 + gnu/libexec/uucp/libunix/spawn.c | 398 +++ gnu/libexec/uucp/libunix/splcmd.c | 115 + gnu/libexec/uucp/libunix/splnam.c | 19 + gnu/libexec/uucp/libunix/spool.c | 420 +++ gnu/libexec/uucp/libunix/srmdir.c | 112 + gnu/libexec/uucp/libunix/statsb.c | 572 ++++ gnu/libexec/uucp/libunix/status.c | 212 ++ gnu/libexec/uucp/libunix/strerr.c | 22 + gnu/libexec/uucp/libunix/time.c | 32 + gnu/libexec/uucp/libunix/tmpfil.c | 83 + gnu/libexec/uucp/libunix/trunc.c | 157 ++ gnu/libexec/uucp/libunix/uacces.c | 205 ++ gnu/libexec/uucp/libunix/ufopen.c | 218 ++ gnu/libexec/uucp/libunix/ultspl.c | 21 + gnu/libexec/uucp/libunix/unknwn.c | 43 + gnu/libexec/uucp/libunix/uuto.c | 31 + gnu/libexec/uucp/libunix/walk.c | 59 + gnu/libexec/uucp/libunix/wldcrd.c | 212 ++ gnu/libexec/uucp/libunix/work.c | 765 ++++++ gnu/libexec/uucp/libunix/xqtfil.c | 265 ++ gnu/libexec/uucp/libunix/xqtsub.c | 698 +++++ gnu/libexec/uucp/libuuconf/COPYING.LIB | 481 ++++ gnu/libexec/uucp/libuuconf/MANIFEST | 92 + gnu/libexec/uucp/libuuconf/Makefile | 26 + gnu/libexec/uucp/libuuconf/README | 113 + gnu/libexec/uucp/libuuconf/addblk.c | 56 + gnu/libexec/uucp/libuuconf/addstr.c | 139 + gnu/libexec/uucp/libuuconf/allblk.c | 51 + gnu/libexec/uucp/libuuconf/alloc.c | 82 + gnu/libexec/uucp/libuuconf/alloc.h | 71 + gnu/libexec/uucp/libuuconf/base.c | 54 + gnu/libexec/uucp/libuuconf/bool.c | 64 + gnu/libexec/uucp/libuuconf/callin.c | 142 + gnu/libexec/uucp/libuuconf/calout.c | 93 + gnu/libexec/uucp/libuuconf/chatc.c | 202 ++ gnu/libexec/uucp/libuuconf/cmdarg.c | 185 ++ gnu/libexec/uucp/libuuconf/cmdfil.c | 103 + gnu/libexec/uucp/libuuconf/cmdlin.c | 142 + gnu/libexec/uucp/libuuconf/debfil.c | 43 + gnu/libexec/uucp/libuuconf/deblev.c | 43 + gnu/libexec/uucp/libuuconf/diacod.c | 129 + gnu/libexec/uucp/libuuconf/dial.c | 61 + gnu/libexec/uucp/libuuconf/diasub.c | 63 + gnu/libexec/uucp/libuuconf/dnams.c | 103 + gnu/libexec/uucp/libuuconf/errno.c | 46 + gnu/libexec/uucp/libuuconf/errstr.c | 241 ++ gnu/libexec/uucp/libuuconf/filnam.c | 44 + gnu/libexec/uucp/libuuconf/freblk.c | 63 + gnu/libexec/uucp/libuuconf/fredia.c | 44 + gnu/libexec/uucp/libuuconf/free.c | 68 + gnu/libexec/uucp/libuuconf/freprt.c | 44 + gnu/libexec/uucp/libuuconf/fresys.c | 44 + gnu/libexec/uucp/libuuconf/grdcmp.c | 76 + gnu/libexec/uucp/libuuconf/hdial.c | 187 ++ gnu/libexec/uucp/libuuconf/hdnams.c | 109 + gnu/libexec/uucp/libuuconf/hinit.c | 295 ++ gnu/libexec/uucp/libuuconf/hlocnm.c | 84 + gnu/libexec/uucp/libuuconf/hport.c | 368 +++ gnu/libexec/uucp/libuuconf/hrmunk.c | 55 + gnu/libexec/uucp/libuuconf/hsinfo.c | 625 +++++ gnu/libexec/uucp/libuuconf/hsnams.c | 142 + gnu/libexec/uucp/libuuconf/hsys.c | 49 + gnu/libexec/uucp/libuuconf/hunk.c | 142 + gnu/libexec/uucp/libuuconf/iniglb.c | 177 ++ gnu/libexec/uucp/libuuconf/init.c | 74 + gnu/libexec/uucp/libuuconf/int.c | 59 + gnu/libexec/uucp/libuuconf/lckdir.c | 43 + gnu/libexec/uucp/libuuconf/lineno.c | 44 + gnu/libexec/uucp/libuuconf/llocnm.c | 70 + gnu/libexec/uucp/libuuconf/local.c | 70 + gnu/libexec/uucp/libuuconf/locnm.c | 46 + gnu/libexec/uucp/libuuconf/logfil.c | 43 + gnu/libexec/uucp/libuuconf/maxuxq.c | 86 + gnu/libexec/uucp/libuuconf/mrgblk.c | 50 + gnu/libexec/uucp/libuuconf/paramc.c | 175 ++ gnu/libexec/uucp/libuuconf/port.c | 77 + gnu/libexec/uucp/libuuconf/prtsub.c | 54 + gnu/libexec/uucp/libuuconf/pubdir.c | 43 + gnu/libexec/uucp/libuuconf/rdlocs.c | 305 +++ gnu/libexec/uucp/libuuconf/rdperm.c | 446 +++ gnu/libexec/uucp/libuuconf/reliab.c | 123 + gnu/libexec/uucp/libuuconf/remunk.c | 45 + gnu/libexec/uucp/libuuconf/sinfo.c | 112 + gnu/libexec/uucp/libuuconf/snams.c | 133 + gnu/libexec/uucp/libuuconf/split.c | 106 + gnu/libexec/uucp/libuuconf/spool.c | 43 + gnu/libexec/uucp/libuuconf/stafil.c | 43 + gnu/libexec/uucp/libuuconf/syshdr.h | 106 + gnu/libexec/uucp/libuuconf/syssub.c | 458 ++++ gnu/libexec/uucp/libuuconf/tcalou.c | 201 ++ gnu/libexec/uucp/libuuconf/tdial.c | 227 ++ gnu/libexec/uucp/libuuconf/tdialc.c | 211 ++ gnu/libexec/uucp/libuuconf/tdnams.c | 119 + gnu/libexec/uucp/libuuconf/tgcmp.c | 42 + gnu/libexec/uucp/libuuconf/thread.c | 70 + gnu/libexec/uucp/libuuconf/time.c | 406 +++ gnu/libexec/uucp/libuuconf/tinit.c | 370 +++ gnu/libexec/uucp/libuuconf/tlocnm.c | 112 + gnu/libexec/uucp/libuuconf/tport.c | 295 ++ gnu/libexec/uucp/libuuconf/tportc.c | 465 ++++ gnu/libexec/uucp/libuuconf/tsinfo.c | 922 +++++++ gnu/libexec/uucp/libuuconf/tsnams.c | 84 + gnu/libexec/uucp/libuuconf/tsys.c | 49 + gnu/libexec/uucp/libuuconf/tval.c | 71 + gnu/libexec/uucp/libuuconf/ugtlin.c | 110 + gnu/libexec/uucp/libuuconf/unk.c | 70 + gnu/libexec/uucp/libuuconf/uucnfi.h | 368 +++ gnu/libexec/uucp/libuuconf/val.c | 46 + gnu/libexec/uucp/libuuconf/vinit.c | 112 + gnu/libexec/uucp/libuuconf/vport.c | 251 ++ gnu/libexec/uucp/libuuconf/vsinfo.c | 575 ++++ gnu/libexec/uucp/libuuconf/vsnams.c | 106 + gnu/libexec/uucp/libuuconf/vsys.c | 49 + gnu/libexec/uucp/libuucp/MANIFEST | 27 + gnu/libexec/uucp/libuucp/Makefile | 14 + gnu/libexec/uucp/libuucp/bsrch.c | 54 + gnu/libexec/uucp/libuucp/buffer.c | 109 + gnu/libexec/uucp/libuucp/bzero.c | 15 + gnu/libexec/uucp/libuucp/crc.c | 112 + gnu/libexec/uucp/libuucp/debug.c | 165 ++ gnu/libexec/uucp/libuucp/escape.c | 98 + gnu/libexec/uucp/libuucp/getlin.c | 81 + gnu/libexec/uucp/libuucp/getop1.c | 144 + gnu/libexec/uucp/libuucp/getopt.c | 621 +++++ gnu/libexec/uucp/libuucp/memchr.c | 149 + gnu/libexec/uucp/libuucp/memcmp.c | 19 + gnu/libexec/uucp/libuucp/memcpy.c | 18 + gnu/libexec/uucp/libuucp/parse.c | 207 ++ gnu/libexec/uucp/libuucp/spool.c | 30 + gnu/libexec/uucp/libuucp/status.c | 20 + gnu/libexec/uucp/libuucp/strcas.c | 33 + gnu/libexec/uucp/libuucp/strchr.c | 16 + gnu/libexec/uucp/libuucp/strdup.c | 18 + gnu/libexec/uucp/libuucp/strncs.c | 39 + gnu/libexec/uucp/libuucp/strrch.c | 24 + gnu/libexec/uucp/libuucp/strstr.c | 55 + gnu/libexec/uucp/libuucp/strtol.c | 175 ++ gnu/libexec/uucp/libuucp/xfree.c | 15 + gnu/libexec/uucp/libuucp/xmall.c | 18 + gnu/libexec/uucp/libuucp/xreall.c | 23 + gnu/libexec/uucp/sample/call | 20 + gnu/libexec/uucp/sample/config | 88 + gnu/libexec/uucp/sample/dial | 35 + gnu/libexec/uucp/sample/dialcode | 19 + gnu/libexec/uucp/sample/passwd | 18 + gnu/libexec/uucp/sample/port | 41 + gnu/libexec/uucp/sample/sys1 | 44 + gnu/libexec/uucp/sample/sys2 | 51 + gnu/libexec/uucp/tstuu.c | 1588 +++++++++++ gnu/libexec/uucp/uuchk/Makefile | 16 + gnu/libexec/uucp/uuchk/uuchk.c | 856 ++++++ gnu/libexec/uucp/uucico/Makefile | 20 + gnu/libexec/uucp/uucico/prote.c | 387 +++ gnu/libexec/uucp/uucico/protf.c | 842 ++++++ gnu/libexec/uucp/uucico/protg.c | 1933 +++++++++++++ gnu/libexec/uucp/uucico/proti.c | 1563 +++++++++++ gnu/libexec/uucp/uucico/protj.c | 671 +++++ gnu/libexec/uucp/uucico/prott.c | 330 +++ gnu/libexec/uucp/uucico/protz.c | 2626 ++++++++++++++++++ gnu/libexec/uucp/uucico/rec.c | 1162 ++++++++ gnu/libexec/uucp/uucico/send.c | 1273 +++++++++ gnu/libexec/uucp/uucico/time.c | 130 + gnu/libexec/uucp/uucico/trans.c | 1439 ++++++++++ gnu/libexec/uucp/uucico/uucico.8 | 225 ++ gnu/libexec/uucp/uucico/uucico.c | 2618 ++++++++++++++++++ gnu/libexec/uucp/uucico/xcmd.c | 396 +++ gnu/libexec/uucp/uuconv/Makefile | 17 + gnu/libexec/uucp/uuconv/uuconv.c | 2012 ++++++++++++++ gnu/libexec/uucp/uucp/Makefile | 16 + gnu/libexec/uucp/uucp/uucp.1 | 175 ++ gnu/libexec/uucp/uucp/uucp.c | 1181 ++++++++ gnu/libexec/uucp/uulog/Makefile | 16 + gnu/libexec/uucp/uulog/uulog.c | 444 +++ gnu/libexec/uucp/uuname/Makefile | 18 + gnu/libexec/uucp/uuname/uuname.c | 192 ++ gnu/libexec/uucp/uupick/Makefile | 16 + gnu/libexec/uucp/uupick/uupick.c | 323 +++ gnu/libexec/uucp/uusched/Makefile | 15 + gnu/libexec/uucp/uusched/uusched.in | 13 + gnu/libexec/uucp/uustat/Makefile | 17 + gnu/libexec/uucp/uustat/uustat.1 | 380 +++ gnu/libexec/uucp/uustat/uustat.c | 2241 +++++++++++++++ gnu/libexec/uucp/uuto/Makefile | 15 + gnu/libexec/uucp/uuto/uuto.in | 16 + gnu/libexec/uucp/uux/Makefile | 16 + gnu/libexec/uucp/uux/uux.1 | 234 ++ gnu/libexec/uucp/uux/uux.c | 1502 +++++++++++ gnu/libexec/uucp/uuxqt/Makefile | 18 + gnu/libexec/uucp/uuxqt/uuxqt.8 | 92 + gnu/libexec/uucp/uuxqt/uuxqt.c | 1549 +++++++++++ 300 files changed, 81211 insertions(+) create mode 100644 gnu/libexec/uucp/COPYING create mode 100644 gnu/libexec/uucp/ChangeLog create mode 100644 gnu/libexec/uucp/Makefile create mode 100644 gnu/libexec/uucp/Makefile.inc create mode 100644 gnu/libexec/uucp/README create mode 100644 gnu/libexec/uucp/TODO create mode 100644 gnu/libexec/uucp/VERSION create mode 100644 gnu/libexec/uucp/common_sources/chat.c create mode 100644 gnu/libexec/uucp/common_sources/conf.h create mode 100644 gnu/libexec/uucp/common_sources/conn.c create mode 100644 gnu/libexec/uucp/common_sources/conn.h create mode 100644 gnu/libexec/uucp/common_sources/copy.c create mode 100644 gnu/libexec/uucp/common_sources/cu.h create mode 100644 gnu/libexec/uucp/common_sources/getopt.h create mode 100644 gnu/libexec/uucp/common_sources/log.c create mode 100644 gnu/libexec/uucp/common_sources/policy.h create mode 100644 gnu/libexec/uucp/common_sources/prot.c create mode 100644 gnu/libexec/uucp/common_sources/prot.h create mode 100644 gnu/libexec/uucp/common_sources/sysdep.h create mode 100644 gnu/libexec/uucp/common_sources/system.h create mode 100644 gnu/libexec/uucp/common_sources/tcp.c create mode 100644 gnu/libexec/uucp/common_sources/tli.c create mode 100644 gnu/libexec/uucp/common_sources/trans.h create mode 100644 gnu/libexec/uucp/common_sources/util.c create mode 100644 gnu/libexec/uucp/common_sources/uuconf.h create mode 100644 gnu/libexec/uucp/common_sources/uucp.h create mode 100644 gnu/libexec/uucp/common_sources/uudefs.h create mode 100644 gnu/libexec/uucp/contrib/Dial.Hayes create mode 100644 gnu/libexec/uucp/contrib/Hangup.Hayes create mode 100644 gnu/libexec/uucp/contrib/Login.LAT create mode 100644 gnu/libexec/uucp/contrib/Login.PortSel create mode 100644 gnu/libexec/uucp/contrib/Login.VMS create mode 100644 gnu/libexec/uucp/contrib/Makefile.uurt create mode 100644 gnu/libexec/uucp/contrib/Makefile.xchat create mode 100644 gnu/libexec/uucp/contrib/README create mode 100644 gnu/libexec/uucp/contrib/README-UURATE create mode 100644 gnu/libexec/uucp/contrib/README-XCHAT create mode 100644 gnu/libexec/uucp/contrib/savelog.man create mode 100644 gnu/libexec/uucp/contrib/savelog.sh create mode 100644 gnu/libexec/uucp/contrib/stats.sh create mode 100644 gnu/libexec/uucp/contrib/tstout.c create mode 100644 gnu/libexec/uucp/contrib/uuclean create mode 100644 gnu/libexec/uucp/contrib/uuq.sh create mode 100644 gnu/libexec/uucp/contrib/uurate.c create mode 100644 gnu/libexec/uucp/contrib/uurate.man create mode 100644 gnu/libexec/uucp/contrib/uureroute create mode 100644 gnu/libexec/uucp/contrib/uusnap.c create mode 100644 gnu/libexec/uucp/contrib/uutraf create mode 100644 gnu/libexec/uucp/contrib/uutry create mode 100644 gnu/libexec/uucp/contrib/xc-conf.h-dist create mode 100644 gnu/libexec/uucp/contrib/xchat.c create mode 100644 gnu/libexec/uucp/contrib/xchat.man create mode 100644 gnu/libexec/uucp/cu/Makefile create mode 100644 gnu/libexec/uucp/cu/cu.1 create mode 100644 gnu/libexec/uucp/cu/cu.c create mode 100644 gnu/libexec/uucp/libunix/MANIFEST create mode 100644 gnu/libexec/uucp/libunix/Makefile create mode 100644 gnu/libexec/uucp/libunix/access.c create mode 100644 gnu/libexec/uucp/libunix/addbas.c create mode 100644 gnu/libexec/uucp/libunix/app3.c create mode 100644 gnu/libexec/uucp/libunix/app4.c create mode 100644 gnu/libexec/uucp/libunix/basnam.c create mode 100644 gnu/libexec/uucp/libunix/bytfre.c create mode 100644 gnu/libexec/uucp/libunix/chmod.c create mode 100644 gnu/libexec/uucp/libunix/cohtty.c create mode 100644 gnu/libexec/uucp/libunix/cusub.c create mode 100644 gnu/libexec/uucp/libunix/cwd.c create mode 100644 gnu/libexec/uucp/libunix/detach.c create mode 100644 gnu/libexec/uucp/libunix/dirent.c create mode 100644 gnu/libexec/uucp/libunix/dup2.c create mode 100644 gnu/libexec/uucp/libunix/efopen.c create mode 100644 gnu/libexec/uucp/libunix/epopen.c create mode 100644 gnu/libexec/uucp/libunix/exists.c create mode 100644 gnu/libexec/uucp/libunix/filnam.c create mode 100644 gnu/libexec/uucp/libunix/fsusg.c create mode 100644 gnu/libexec/uucp/libunix/fsusg.h create mode 100644 gnu/libexec/uucp/libunix/ftw.c create mode 100644 gnu/libexec/uucp/libunix/getcwd.c create mode 100644 gnu/libexec/uucp/libunix/indir.c create mode 100644 gnu/libexec/uucp/libunix/init.c create mode 100644 gnu/libexec/uucp/libunix/isdir.c create mode 100644 gnu/libexec/uucp/libunix/isfork.c create mode 100644 gnu/libexec/uucp/libunix/iswait.c create mode 100644 gnu/libexec/uucp/libunix/jobid.c create mode 100644 gnu/libexec/uucp/libunix/lcksys.c create mode 100644 gnu/libexec/uucp/libunix/link.c create mode 100644 gnu/libexec/uucp/libunix/locfil.c create mode 100644 gnu/libexec/uucp/libunix/lock.c create mode 100644 gnu/libexec/uucp/libunix/loctim.c create mode 100644 gnu/libexec/uucp/libunix/mail.c create mode 100644 gnu/libexec/uucp/libunix/mkdir.c create mode 100644 gnu/libexec/uucp/libunix/mkdirs.c create mode 100644 gnu/libexec/uucp/libunix/mode.c create mode 100644 gnu/libexec/uucp/libunix/move.c create mode 100644 gnu/libexec/uucp/libunix/opensr.c create mode 100644 gnu/libexec/uucp/libunix/pause.c create mode 100644 gnu/libexec/uucp/libunix/picksb.c create mode 100644 gnu/libexec/uucp/libunix/portnm.c create mode 100644 gnu/libexec/uucp/libunix/proctm.c create mode 100644 gnu/libexec/uucp/libunix/recep.c create mode 100644 gnu/libexec/uucp/libunix/remove.c create mode 100644 gnu/libexec/uucp/libunix/rename.c create mode 100644 gnu/libexec/uucp/libunix/rmdir.c create mode 100644 gnu/libexec/uucp/libunix/run.c create mode 100644 gnu/libexec/uucp/libunix/seq.c create mode 100644 gnu/libexec/uucp/libunix/serial.c create mode 100644 gnu/libexec/uucp/libunix/signal.c create mode 100644 gnu/libexec/uucp/libunix/sindir.c create mode 100644 gnu/libexec/uucp/libunix/size.c create mode 100644 gnu/libexec/uucp/libunix/sleep.c create mode 100644 gnu/libexec/uucp/libunix/spawn.c create mode 100644 gnu/libexec/uucp/libunix/splcmd.c create mode 100644 gnu/libexec/uucp/libunix/splnam.c create mode 100644 gnu/libexec/uucp/libunix/spool.c create mode 100644 gnu/libexec/uucp/libunix/srmdir.c create mode 100644 gnu/libexec/uucp/libunix/statsb.c create mode 100644 gnu/libexec/uucp/libunix/status.c create mode 100644 gnu/libexec/uucp/libunix/strerr.c create mode 100644 gnu/libexec/uucp/libunix/time.c create mode 100644 gnu/libexec/uucp/libunix/tmpfil.c create mode 100644 gnu/libexec/uucp/libunix/trunc.c create mode 100644 gnu/libexec/uucp/libunix/uacces.c create mode 100644 gnu/libexec/uucp/libunix/ufopen.c create mode 100644 gnu/libexec/uucp/libunix/ultspl.c create mode 100644 gnu/libexec/uucp/libunix/unknwn.c create mode 100644 gnu/libexec/uucp/libunix/uuto.c create mode 100644 gnu/libexec/uucp/libunix/walk.c create mode 100644 gnu/libexec/uucp/libunix/wldcrd.c create mode 100644 gnu/libexec/uucp/libunix/work.c create mode 100644 gnu/libexec/uucp/libunix/xqtfil.c create mode 100644 gnu/libexec/uucp/libunix/xqtsub.c create mode 100644 gnu/libexec/uucp/libuuconf/COPYING.LIB create mode 100644 gnu/libexec/uucp/libuuconf/MANIFEST create mode 100644 gnu/libexec/uucp/libuuconf/Makefile create mode 100644 gnu/libexec/uucp/libuuconf/README create mode 100644 gnu/libexec/uucp/libuuconf/addblk.c create mode 100644 gnu/libexec/uucp/libuuconf/addstr.c create mode 100644 gnu/libexec/uucp/libuuconf/allblk.c create mode 100644 gnu/libexec/uucp/libuuconf/alloc.c create mode 100644 gnu/libexec/uucp/libuuconf/alloc.h create mode 100644 gnu/libexec/uucp/libuuconf/base.c create mode 100644 gnu/libexec/uucp/libuuconf/bool.c create mode 100644 gnu/libexec/uucp/libuuconf/callin.c create mode 100644 gnu/libexec/uucp/libuuconf/calout.c create mode 100644 gnu/libexec/uucp/libuuconf/chatc.c create mode 100644 gnu/libexec/uucp/libuuconf/cmdarg.c create mode 100644 gnu/libexec/uucp/libuuconf/cmdfil.c create mode 100644 gnu/libexec/uucp/libuuconf/cmdlin.c create mode 100644 gnu/libexec/uucp/libuuconf/debfil.c create mode 100644 gnu/libexec/uucp/libuuconf/deblev.c create mode 100644 gnu/libexec/uucp/libuuconf/diacod.c create mode 100644 gnu/libexec/uucp/libuuconf/dial.c create mode 100644 gnu/libexec/uucp/libuuconf/diasub.c create mode 100644 gnu/libexec/uucp/libuuconf/dnams.c create mode 100644 gnu/libexec/uucp/libuuconf/errno.c create mode 100644 gnu/libexec/uucp/libuuconf/errstr.c create mode 100644 gnu/libexec/uucp/libuuconf/filnam.c create mode 100644 gnu/libexec/uucp/libuuconf/freblk.c create mode 100644 gnu/libexec/uucp/libuuconf/fredia.c create mode 100644 gnu/libexec/uucp/libuuconf/free.c create mode 100644 gnu/libexec/uucp/libuuconf/freprt.c create mode 100644 gnu/libexec/uucp/libuuconf/fresys.c create mode 100644 gnu/libexec/uucp/libuuconf/grdcmp.c create mode 100644 gnu/libexec/uucp/libuuconf/hdial.c create mode 100644 gnu/libexec/uucp/libuuconf/hdnams.c create mode 100644 gnu/libexec/uucp/libuuconf/hinit.c create mode 100644 gnu/libexec/uucp/libuuconf/hlocnm.c create mode 100644 gnu/libexec/uucp/libuuconf/hport.c create mode 100644 gnu/libexec/uucp/libuuconf/hrmunk.c create mode 100644 gnu/libexec/uucp/libuuconf/hsinfo.c create mode 100644 gnu/libexec/uucp/libuuconf/hsnams.c create mode 100644 gnu/libexec/uucp/libuuconf/hsys.c create mode 100644 gnu/libexec/uucp/libuuconf/hunk.c create mode 100644 gnu/libexec/uucp/libuuconf/iniglb.c create mode 100644 gnu/libexec/uucp/libuuconf/init.c create mode 100644 gnu/libexec/uucp/libuuconf/int.c create mode 100644 gnu/libexec/uucp/libuuconf/lckdir.c create mode 100644 gnu/libexec/uucp/libuuconf/lineno.c create mode 100644 gnu/libexec/uucp/libuuconf/llocnm.c create mode 100644 gnu/libexec/uucp/libuuconf/local.c create mode 100644 gnu/libexec/uucp/libuuconf/locnm.c create mode 100644 gnu/libexec/uucp/libuuconf/logfil.c create mode 100644 gnu/libexec/uucp/libuuconf/maxuxq.c create mode 100644 gnu/libexec/uucp/libuuconf/mrgblk.c create mode 100644 gnu/libexec/uucp/libuuconf/paramc.c create mode 100644 gnu/libexec/uucp/libuuconf/port.c create mode 100644 gnu/libexec/uucp/libuuconf/prtsub.c create mode 100644 gnu/libexec/uucp/libuuconf/pubdir.c create mode 100644 gnu/libexec/uucp/libuuconf/rdlocs.c create mode 100644 gnu/libexec/uucp/libuuconf/rdperm.c create mode 100644 gnu/libexec/uucp/libuuconf/reliab.c create mode 100644 gnu/libexec/uucp/libuuconf/remunk.c create mode 100644 gnu/libexec/uucp/libuuconf/sinfo.c create mode 100644 gnu/libexec/uucp/libuuconf/snams.c create mode 100644 gnu/libexec/uucp/libuuconf/split.c create mode 100644 gnu/libexec/uucp/libuuconf/spool.c create mode 100644 gnu/libexec/uucp/libuuconf/stafil.c create mode 100644 gnu/libexec/uucp/libuuconf/syshdr.h create mode 100644 gnu/libexec/uucp/libuuconf/syssub.c create mode 100644 gnu/libexec/uucp/libuuconf/tcalou.c create mode 100644 gnu/libexec/uucp/libuuconf/tdial.c create mode 100644 gnu/libexec/uucp/libuuconf/tdialc.c create mode 100644 gnu/libexec/uucp/libuuconf/tdnams.c create mode 100644 gnu/libexec/uucp/libuuconf/tgcmp.c create mode 100644 gnu/libexec/uucp/libuuconf/thread.c create mode 100644 gnu/libexec/uucp/libuuconf/time.c create mode 100644 gnu/libexec/uucp/libuuconf/tinit.c create mode 100644 gnu/libexec/uucp/libuuconf/tlocnm.c create mode 100644 gnu/libexec/uucp/libuuconf/tport.c create mode 100644 gnu/libexec/uucp/libuuconf/tportc.c create mode 100644 gnu/libexec/uucp/libuuconf/tsinfo.c create mode 100644 gnu/libexec/uucp/libuuconf/tsnams.c create mode 100644 gnu/libexec/uucp/libuuconf/tsys.c create mode 100644 gnu/libexec/uucp/libuuconf/tval.c create mode 100644 gnu/libexec/uucp/libuuconf/ugtlin.c create mode 100644 gnu/libexec/uucp/libuuconf/unk.c create mode 100644 gnu/libexec/uucp/libuuconf/uucnfi.h create mode 100644 gnu/libexec/uucp/libuuconf/val.c create mode 100644 gnu/libexec/uucp/libuuconf/vinit.c create mode 100644 gnu/libexec/uucp/libuuconf/vport.c create mode 100644 gnu/libexec/uucp/libuuconf/vsinfo.c create mode 100644 gnu/libexec/uucp/libuuconf/vsnams.c create mode 100644 gnu/libexec/uucp/libuuconf/vsys.c create mode 100644 gnu/libexec/uucp/libuucp/MANIFEST create mode 100644 gnu/libexec/uucp/libuucp/Makefile create mode 100644 gnu/libexec/uucp/libuucp/bsrch.c create mode 100644 gnu/libexec/uucp/libuucp/buffer.c create mode 100644 gnu/libexec/uucp/libuucp/bzero.c create mode 100644 gnu/libexec/uucp/libuucp/crc.c create mode 100644 gnu/libexec/uucp/libuucp/debug.c create mode 100644 gnu/libexec/uucp/libuucp/escape.c create mode 100644 gnu/libexec/uucp/libuucp/getlin.c create mode 100644 gnu/libexec/uucp/libuucp/getop1.c create mode 100644 gnu/libexec/uucp/libuucp/getopt.c create mode 100644 gnu/libexec/uucp/libuucp/memchr.c create mode 100644 gnu/libexec/uucp/libuucp/memcmp.c create mode 100644 gnu/libexec/uucp/libuucp/memcpy.c create mode 100644 gnu/libexec/uucp/libuucp/parse.c create mode 100644 gnu/libexec/uucp/libuucp/spool.c create mode 100644 gnu/libexec/uucp/libuucp/status.c create mode 100644 gnu/libexec/uucp/libuucp/strcas.c create mode 100644 gnu/libexec/uucp/libuucp/strchr.c create mode 100644 gnu/libexec/uucp/libuucp/strdup.c create mode 100644 gnu/libexec/uucp/libuucp/strncs.c create mode 100644 gnu/libexec/uucp/libuucp/strrch.c create mode 100644 gnu/libexec/uucp/libuucp/strstr.c create mode 100644 gnu/libexec/uucp/libuucp/strtol.c create mode 100644 gnu/libexec/uucp/libuucp/xfree.c create mode 100644 gnu/libexec/uucp/libuucp/xmall.c create mode 100644 gnu/libexec/uucp/libuucp/xreall.c create mode 100644 gnu/libexec/uucp/sample/call create mode 100644 gnu/libexec/uucp/sample/config create mode 100644 gnu/libexec/uucp/sample/dial create mode 100644 gnu/libexec/uucp/sample/dialcode create mode 100644 gnu/libexec/uucp/sample/passwd create mode 100644 gnu/libexec/uucp/sample/port create mode 100644 gnu/libexec/uucp/sample/sys1 create mode 100644 gnu/libexec/uucp/sample/sys2 create mode 100644 gnu/libexec/uucp/tstuu.c create mode 100644 gnu/libexec/uucp/uuchk/Makefile create mode 100644 gnu/libexec/uucp/uuchk/uuchk.c create mode 100644 gnu/libexec/uucp/uucico/Makefile create mode 100644 gnu/libexec/uucp/uucico/prote.c create mode 100644 gnu/libexec/uucp/uucico/protf.c create mode 100644 gnu/libexec/uucp/uucico/protg.c create mode 100644 gnu/libexec/uucp/uucico/proti.c create mode 100644 gnu/libexec/uucp/uucico/protj.c create mode 100644 gnu/libexec/uucp/uucico/prott.c create mode 100644 gnu/libexec/uucp/uucico/protz.c create mode 100644 gnu/libexec/uucp/uucico/rec.c create mode 100644 gnu/libexec/uucp/uucico/send.c create mode 100644 gnu/libexec/uucp/uucico/time.c create mode 100644 gnu/libexec/uucp/uucico/trans.c create mode 100644 gnu/libexec/uucp/uucico/uucico.8 create mode 100644 gnu/libexec/uucp/uucico/uucico.c create mode 100644 gnu/libexec/uucp/uucico/xcmd.c create mode 100644 gnu/libexec/uucp/uuconv/Makefile create mode 100644 gnu/libexec/uucp/uuconv/uuconv.c create mode 100644 gnu/libexec/uucp/uucp/Makefile create mode 100644 gnu/libexec/uucp/uucp/uucp.1 create mode 100644 gnu/libexec/uucp/uucp/uucp.c create mode 100644 gnu/libexec/uucp/uulog/Makefile create mode 100644 gnu/libexec/uucp/uulog/uulog.c create mode 100644 gnu/libexec/uucp/uuname/Makefile create mode 100644 gnu/libexec/uucp/uuname/uuname.c create mode 100644 gnu/libexec/uucp/uupick/Makefile create mode 100644 gnu/libexec/uucp/uupick/uupick.c create mode 100644 gnu/libexec/uucp/uusched/Makefile create mode 100644 gnu/libexec/uucp/uusched/uusched.in create mode 100644 gnu/libexec/uucp/uustat/Makefile create mode 100644 gnu/libexec/uucp/uustat/uustat.1 create mode 100644 gnu/libexec/uucp/uustat/uustat.c create mode 100644 gnu/libexec/uucp/uuto/Makefile create mode 100644 gnu/libexec/uucp/uuto/uuto.in create mode 100644 gnu/libexec/uucp/uux/Makefile create mode 100644 gnu/libexec/uucp/uux/uux.1 create mode 100644 gnu/libexec/uucp/uux/uux.c create mode 100644 gnu/libexec/uucp/uuxqt/Makefile create mode 100644 gnu/libexec/uucp/uuxqt/uuxqt.8 create mode 100644 gnu/libexec/uucp/uuxqt/uuxqt.c diff --git a/gnu/libexec/uucp/COPYING b/gnu/libexec/uucp/COPYING new file mode 100644 index 0000000000..e77696ae8d --- /dev/null +++ b/gnu/libexec/uucp/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 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. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, 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 software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, 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 redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 Program +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 Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, 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 + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. 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. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/libexec/uucp/ChangeLog b/gnu/libexec/uucp/ChangeLog new file mode 100644 index 0000000000..48a52b75a2 --- /dev/null +++ b/gnu/libexec/uucp/ChangeLog @@ -0,0 +1,3152 @@ +Sat Feb 13 15:57:30 1993 Ian Lance Taylor (ian@comton.airs.com) + + * Released version 1.04. + + * unix/detach.c: Andrew A. Chernov: Don't check return of setsid. + +Sun Jan 31 01:45:56 1993 Ian Lance Taylor (ian@comton.airs.com) + + * cu.c (main): Pass "cu" to uuconf_init. + + * protz.c (fzprocess): Restore ZPAD char before calling getinsync. + +Sat Jan 30 22:19:26 1993 Ian Lance Taylor (ian@comton.airs.com) + + * Makefile.in (doc-dist): New target. + +Wed Jan 27 22:55:26 1993 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgstart): Set iGremote_segsize when using + remote-packet-size. + +Tue Jan 26 01:01:34 1993 Ian Lance Taylor (ian@comton.airs.com) + + * proti.c (fiprocess_data): always send an ACK after receiving + half a window, rather than sometimes resending a packet. Half a + window of short packets can arrive very quickly. + + * tstuu.c (main, cread, fsend): rewrote communication routines to + avoid deadlock. + +Sun Jan 24 01:02:47 1993 Ian Lance Taylor (ian@comton.airs.com) + + * trans.c (ufailed): don't report statistics if no bytes + transferred. + + * Makefile.in (install): simplified somewhat. + (dist): distribute the sample directory. + +Sat Jan 23 19:47:12 1993 Ian Lance Taylor (ian@comton.airs.com) + + * configure.in, conf.h.in, tli.c: Karl Swarz: check for and use + . + +Fri Jan 22 00:09:37 1993 Ian Lance Taylor (ian@comton.airs.com) + + * send.c (flocal_send_request): Alan Judge: don't send C in option + string when faking an E command as an S command. + +Thu Jan 21 00:09:31 1993 Ian Lance Taylor (ian@comton.airs.com) + + * uux.c (main): don't use E command if forwarding. + +Wed Jan 20 00:22:38 1993 Ian Lance Taylor (ian@comton.airs.com) + + * send.c (fsend_exec_file_init), rec.c (frec_file_end), uux.c + (main): Chip Salzenberg: always put the C line last in an + execution file, to support Fredmail. + +Tue Jan 19 00:09:43 1993 Ian Lance Taylor (ian@comton.airs.com) + + * trans.h, trans.c (ftcharge, floop, fgot_data): rewrote timing + code. + + * trans.h, trans.c, send.c, rec.c, xcmd.c, protf.c, protz.c + (fqueue_local, fqueue_remote, fqueue_send, fqueue_receive): added + boolean return value and qdaemon argument. + +Mon Jan 18 00:01:46 1993 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (fdo_call, faccept_call): Ted Lindgreen, Chip + Salzenberg: wait for remote hangup string before hanging up. + + * proti.c (fiprocess_data, fiprocess_packet): stop scanning input + buffer after a CLOSE packet. + +Sat Jan 16 22:44:28 1993 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uucico.c (main), uuxqt.c (main), unix/init.c: Ted + Lindgreen: eliminated INIT_DAEMON. + + * log.c (ulog): don't log SIGINT if fLog_sighup is FALSE. + + * unix/move.c (fsysdep_move_file), unix/xqtsub.c + (fsysdep_move_uuxqt_files): the system call rename seems to fail + on some systems for arbitrary reasons, so always try to copy the + file by hand, not just if we get EXDEV. + + * policy.h, unix/pause.c: Gregory Gulik: added HAVE_HUNDREDTHS_NAP + configuration parameter. + +Wed Jan 6 21:06:45 1993 Ian Lance Taylor (ian@comton.airs.com) + + * unix/serial.c (fsserial_lockfile): create HDB lock files when + using HAVE_COHERENT_LOCKING. + unix/cohtty.c (fscoherent_disable_tty): consistently return FALSE + on error. + + * unix/cusub.c (fsysdep_terminal_raw): Andrew A. Chernov: if + POSIX_TERMIOS, turn of IEXTEN flag. + +Sat Jan 2 23:19:27 1993 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgprocess_data): treat a duplicate RR as an RJ. + +Fri Jan 1 11:17:30 1993 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, unix/proctm.c: Steven S. Dick: use sysconf + (_SC_CLK_TCK) for TIMES_TICK if possible. + + * uuconf/diacod.c: Gregory Gulik: accept an empty dialcode string. + + * system.h, uucico.c (main), uucp.c (main), uux.c (main), + unix/run.c: Karsten Thygesen: removed ffork argument from + fsysdep_run. + +Wed Dec 30 00:21:55 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/link.c: Andrey G Blochintsev: don't fail just because + destination directories do not exist. + + * send.c (flocal_send_open_file): Scott Ballantyne: record file + name when logging send of execution command. + + * protz.c: Chip Salzenberg: reformatted to 80 columns. + +Tue Dec 29 23:50:52 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconv.c (uvwrite_time): scott@geom.umn.edu: handle midnight + more correctly. + +Fri Dec 18 00:49:16 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uucp.c (uccopy), uux.c (main), cu.c (icuput, icutake), + unix/ufopen.c (esysdep_user_fopen): Doug Evans: open files used + for %put and %take using esysdep_user_fopen, rather than with + privileges of uucp. Added frd and fbinary arguments to + esysdep_user_fopen. + +Thu Dec 17 00:04:53 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/picksb.c (zsysdep_uupick): Peter Wemm: allocation error. + + * uupick.c (main): Peter Wemm: pass INIT_GETCWD to + usysdep_initialize; really quit if 'q' is typed. + + * uulog.c (main): Peter Wemm: always canonicalize system name, not + just if using HDB_LOGGING. + + * uudefs.h, log.c (ustats), trans.c (ufailed), send.c + (fsend_await_confirm), rec.c (frec_file_end): Peter Wemm: added + fmaster argument to ustats, used only in HDB_LOGGING. + +Wed Dec 16 23:35:51 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uustat.c (main): Marc Unangst: forgot to call strtol for -y. + + * policy.h, sysh.unx: Brian J. Murrell: yet another configuration + parameter: HAVE_BROKEN_SETREUID. + +Tue Dec 15 00:13:04 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconv.c (uvwrite_taylor_system): mnichols@pacesetter.com: use + command-path rather than path. + + * trans.c (floop): Marc Unangst: don't clear frequested_hangup if + we didn't manage to hang up. + + * uucp.h, rec.c (fremote_send_file_init): Oleg Girko: patches to + make code compile if USE_STDIO is 0. + + * unix/proctm.c: Tim Peiffer: reverse sense of TIMES_TICK check in + hopes of avoiding ISC preprocessor bug. + + * unix/fsusg.h, unix/fsusg.c, unix/bytfre.c, system.h, conf.h.in, + configure.in, unix/Makefile.in, unix/MANIFEST: use new disk space + checking routines from GNU fileutils 3.4. + * unix/opensr.c (zsysdep_receive_temp): don't check free space + here any more. + * policy.h, trans.h, trans.c, rec.c, uucico.c, uudefs.h: Chip + Salzenberg: check amount of remaining space on disk every + FREE_SPACE_DELTA bytes, and abort the file transfer if disk space + gets too low. + +Wed Dec 2 00:24:12 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, unix/serial.c (fsserial_set): Frank Conrad: added + HAVE_PARITY_BUG parameter for the Sony NEWS. + +Mon Nov 30 00:06:59 1992 Ian Lance Taylor (ian@comton.airs.com) + + * lib/spool.c (fspool_file): Andrew Chernov: accept any + alphanumeric character in the name, because it could be a grade + from another system. + +Sun Nov 29 22:36:47 1992 Ian Lance Taylor (ian@comton.airs.com) + + * lib/buffer.c (ubuffree): scott@geom.umn.edu, Richard Gumpertz: + use a temporary variable to hold the offsetof result. + + * configure.in: scott@geom.umn.edu: define HAVE_SYS_SELECT_H + correctly. + + * protg.c (fgsend_control): Niels Baggesen: report all non-RR + packets if DEBUG_ABNORMAL. + + * unix/cusub.c (uscu_child): Ed Carp: apparently the read and + write calls can get EAGAIN on some systems. + + * unix/status.c (fsysdep_get_status, fsysdep_set_status): Chip + Salzenberg: map status values when using SPOOLDIR_HDB. + + * rec.c (fremote_send_reply): do file restart correctly for E + commands. + +Sun Nov 22 15:09:43 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protz.c: Chip Salzenberg: always do bitwise operations on + unsigned values. + + * getopt.h: Chip Salzenberg: don't rely on __STDC__. + +Thu Nov 19 00:13:46 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/freblk.c: Niels Baggesen: loop over the right list. + + * uulog.c (main): Peter Wemm: added -D, -F and -S options, made -f + take an argument and default to showing 10 current lines. + (ulusage): added new options and missing old ones. + +Wed Nov 18 22:26:36 1992 Ian Lance Taylor (ian@comton.airs.com) + + * rec.c (frec_file_end): Andrey G Blochintsev: call + fsysdep_remember_reception as soon as the file has been moved to + the final destination; write fake execution file via a temporary + file to prevent uuxqt from getting at it early. + * trans.c (usent_receive_ack): don't call + fsysdep_remember_reception here. + + * unix/tmpfil.c (ZDIGS): don't use '.', since we use it to + separate parts of the file name. + +Sun Nov 15 15:31:49 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uustat.c (fsquery_show, csunits_show): Marc Unangst, Chip + Salzenberg: line up uustat -q output. + + * sysh.unx, ftw.c (ftw_dir, ftw), srmdir.c (isremove_dir), walk.c + (iswalk_dir): Marc Unangst: stat argument to function argument to + ftw is const. + + * unix/serial.c (fsserial_set): Mike Bernson: set CSIZE correctly + when changing parity. + + * uux.c (main): Andrew A. Chernov: check for executions which name + the local system, to handle dumb mailers. + + * uucp.h: Doug Evans: #undef strerror if HAVE_STRERROR is 0, to + avoid macro definition on Xenix. + + * unix/serial.c (fsserial_set): Peter Wemm: only check CRTSCTS if + HAVE_POSIX_TERMIOS. + + * cu.c (main): Peter Wemm: use alternates for systems if a call + fails. + + * tstuu.c (uprepare_test): Gerben Wierda: set execute bits for + Chat1 and Chat2. + + * trans.c (floop): Marc Unangst: don't hang up when requested + unless the send queue is empty. + + * uuxqt.c (iqrequestor): Marc Boucher: new function to accept R + command with two arguments, as generated by UUPC. + + * uucico.c (faccept_call): Christian Seyb: don't free the system + info until after writing the status. + + * configure.in: Marc Boucher: check -lsocket and -lnsl together. + + * unix/portnm.c: Stephen J. Walick: it's types.tcp.h, not + tcp.types.h. + + * configure.in: Brian Campbell: check for /usr/bin/mailx. + +Sat Nov 14 11:11:04 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/hlocnm.c (uuconf_hdb_login_localname): Christian Seyb: + check for _uuconf_unset as well as NULL. + + * conn.c (fconn_dial): initialize *ptdialerfound. + + * many files: rearranged header files to include "sysdep.h" before + system header files. Also eliminated various pedantic warnings, + and made _uuconf_unset char * to avoid possible alignment + problems. + +Tue Nov 10 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com) + + * trans.h, uucico.c (fcall, faccept_call), trans.c (uclear_queue, + floop): Stephen J. Walick: move clean up from end of floop into + uclear_queue, and call it instead of just doing + usysdep_get_work_free. + + * unix/serial.c (fsserial_lockfile): Marc Unangst: bad #endif + location for HAVE_SVR4_LOCKFILES. + (fsserial_init): Doug Evans: null terminate the device name. + +Sun Nov 8 10:58:59 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (fcall, faccept_call): Stephen J. Walick: call + usysdep_get_work_free here. + trans.c (floop): don't call usysdep_get_work free here. + +Sun Nov 1 17:05:07 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Released gamma version 1.04. + + * configure.in: check that sys/select.h and sys/time.h work + together, since that's how they are currently used. + + * cu.c, uustat.c, uuconf/diacod.c: add casts to eliminate + warnings. + + * configure.in: don't add strlwr to LIBOBJS. + + * policy.h, unix/cohtty.c: Bob Hemedinger: finish Coherent style + locking. + +Wed Oct 28 00:20:15 1992 Ian Lance Taylor (ian@comton.airs.com) + + * tstuu.c: Ralf Stephan: check HAVE_POLL_H and HAVE_STROPTS_H. + + * Nickolay Saukh: accept SVR4 style R request file position. + uudefs.h: added ipos field to struct scmd. + lib/parse.c: accept SVR4 style R request with file position to + start from. + send.c (fremote_rec_file_init): start transferring file from + requested position. + uucp.c, uux.c, uuxqt.c, xcmd.c: initialize ipos field. + +Sun Oct 25 10:39:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/serial.c (fsysdep_conn_write, fsysdep_conn_io): T. William + Wells: take special care to ensure we don't write after SIGHUP. + + * policy.h, sysh.unx, unix/MANIFEST, unix/Makefile.in, + unix/serial.c (fsserial_lockfile), unix/cohtty.c (new file): Bob + Hemedinger: added HAVE_COHERENT_LOCKFILES. + + * unix/cusub.c (uscu_child): Igor V. Semenyuk: accept a 0 return + from read until we have read some data at some point. + +Thu Oct 22 10:38:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * proti.c: various tweaks for bad connections. + + * uucp.h: T. William Wells: rename strcasecmp and strncasecmp, if + the system doesn't provide them, to avoid the ANSI C name space. + + * lib/buffer.c: Bob Hemedinger: put ab in union so that offsetof + will not take the address of an array. + + * uuxqt.c (uqdo_xqt_file): Bob Hemedinger: don't take address of + array. + +Wed Oct 21 00:05:31 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uustat.c (fsnotify): Gert Doering: if the file appears to be + binary, don't include it in any mail message. + + * unix/mkdir.c: Michael Yu.Yaroslavtsev: check whether directory + already exists before spawning /bin/mkdir. + + * proti.c: Michael Yu.Yaroslavtsev: iIsendpos and iIrecpos should + be long. + + * send.c (flocal_send_await_reply): Gert Doering: improved error + messages. + + * tli.c, unix/detach.c: include "sysdep.h" before . + + * configure.in, conf.h.in: added some system specific checks + provided by autoconf. + + * tstuu.c, unix/serial.c: Merlyn LeRoy: check for ENODATA as well + as EAGAIN and EWOULDBLOCK. + + * uucico.c (faccept_call): Zacharias J. Beckman: if calling back, + clear status first. + + * uucico.c (fdo_call, faccept_call): Hans-Dieter Doll: avoid + overflow when turning ulimit value into bytes. + +Tue Oct 20 23:12:26 1992 Ian Lance Taylor (ian@comton.airs.com) + + * serial.c (fsmodem_carrier): Hans-Dieter Doll: use IS68K LNOMDM + bit if available. + + * chat.c (fcsend): Hans-Dieter Doll: advance z after EOT. + + * cu.c: T. William Wells: beep on connected and disconnected + messages (only if ANSI_C, to use \a). + + * unix/run.c: Peter Wemm: pass fsetuid as TRUE to ixsspawn. + +Sun Oct 18 13:58:17 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, unix/serial.c (fsmodem_close): Stephen J. Walick: + added HAVE_RESET_BUG for SCO Xenix. + + * configure.in: Igor V. Semenyuk: avoid looking in -linet for + getline, since ISC has a different function there by that name. + + * unix/ufopen.c: Igor V. Semenyuk: handle unsigned uid_t. + +Sat Oct 17 11:00:30 1992 Ian Lance Taylor (ian@comton.airs.com) + + * conf.h.in, configure.in, uucp.h, unix/serial.c + (fsserial_lockfile), lib/MANIFEST: eliminated strlwr. + +Fri Oct 16 01:10:56 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Igor V. Semenyuk: uuchk.c (ukshow): print max-remote-debug + correctly. + lib/debug.c (idebug_parse): accept DEBUG_NONE. + +Thu Oct 15 00:49:58 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/cusub.c (fsysdep_terminal_puts): don't modify zalc before + freeing it up. + + * protg.c (fgcheck_errors, fggot_ack, fgprocess_data): Mark E. + Mallett: better handling of error decay. + +Wed Oct 14 22:09:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/lock.c: Tomi Vainio: make sure SEEK_SET is defined. + + * tcp.c (ftcp_dial): print a better error message if gethostbyname + doesn't set errno. + + * Stephen J. Walick: configure.in, conf.h.in: check for + . + tcp.c, unix/opensr.c: include if available. + lib/debug.c, unix/portnm.c, uuconf/int.c, uuconf/llocnm.c, + uuconf/time.c: cast more arguments to eliminate more warnings. + +Tue Oct 13 00:25:03 1992 Ian Lance Taylor (ian@comton.airs.com) + + * prot.h, proti.c (fistart, fijstart), protj.c, uucico.c, tstuu.c + (uprepare_test), Makefile.in, MANIFEST: added 'j' protocol. + +Sun Oct 11 23:45:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, unix/serial.c (fsserial_set): added HAVE_STRIP_BUG to + policy.h to get around stupid Ultrix bug. + + * sysh.unx, unix/cusub.c, unix/serial.c (fsserial_open): for + HAVE_BSD_TTY, keep tchars and ltchars in the sterminal structure, + and in fsserial_open disable all interrupt characters. + +Sat Oct 10 01:18:31 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/tinit.c (itunknown): Gert Doering: don't save "unknown" + with the other arguments. + +Fri Oct 9 00:56:43 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/lock.c: check for running process before doing kill. + +Thu Oct 8 00:20:12 1992 Ian Lance Taylor (ian@comton.airs.com) + + * chat.c, protf.c, send.c, rec.c, unix/locfil.c: Stephen J. + Walick: cast arguments to strtol and strcspn to avoid warnings. + + * uustat.c (fsnotify): Marc Boucher: don't free string from + uuconf_localname, and only prepend remote system name to execution + requests, not to local UUCP commands. + + * unix/lock.c (fsdo_lock): Marc Boucher: set fret to TRUE before + going around the loop again. + + * uucico.c: Marc Boucher: use 'a' protocol before 'g'. + + * unix/spool.c (zsfind_file): Matthias Zepf: fixed typos for + SPOOLDIR_BSD*. + +Wed Oct 7 00:03:08 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuname.c (main): Marc Boucher: reverse sense of -a, and do not + display aliases by default. + + * uucico.c (fdo_call): Marc Boucher: some systems only provide 14 + characters in the Shere line. + + * tstuu.c (main): Marc Boucher: add support for STREAMS ptys. + +Tue Oct 6 23:16:15 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h: Marc Boucher: improve comments to describe SVR4. + + * chat.c (fcsend, fcecho_send, fcecho_send_strip, + fcecho_send_nostrip): Marc Boucher: don't send CR after BREAK or + EOT, and let chat-seven-bit apply to echo checking. + + * uuname.c (main): Andreas Vogel: usysdep_exit (TRUE) rather than + usysdep_exit (EXIT_SUCCESS). + +Mon Oct 5 22:59:51 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysh.unx, unix/serial.c (fsserial_init): Marc Boucher: avoid + freeing unallocated string. + + * unix/serial.c (fsmodem_carrier): Peter Wemm: eliminated useless + undeclared variable which only appeared if HAVE_CLOCAL_BUG. + + * cu.c (main): don't require carrier when opening a direct line. + (fcudo_cmd, fcudo_subcmd, uculist_fns, icuunrecogfn): T. William + Wells: give reasonable error messages. + +Sun Oct 4 00:03:10 1992 Ian Lance Taylor (ian@comton.airs.com) + + * */Makefile.in: T. William Wells: use ar qc rather than ar rc. + + * many: T. William Wells: renamed isysdep_* functions to + ixsysdep_*, and renamed isfork, isspawn, and isswait similarly, to + avoid ANSI C namespace restrictions. + + * uucp.h: T. William Wells: default size_t to unsigned, not int. + + * configure.in: T. William Wells: new definition for + AC_RETSIGTYPE. + + * configure.in: T. William Wells: test for sh builtin echo. + conf.h.in: default ECHO_PROGRAM to undefined. + + * proti.c (fiprocess_data, fiprocess_packet): fix confusion + between iIremote_winsize and iIrequest_winsize. + + * proti.c (fiwindow_wait, fisenddata): wait for a window opening + before sending SPOS. + + * proti.c (fiprocess_data): don't send a NAK for a duplicate of + the most recent packet. + + * configure.in: Stephen J. Walick: don't use AC_PREFIX, check for + /usr/bin/mail. + + * system.h, sysh.unx, send.c (flocal_send_file_init, + fsend_exec_file_init), rec.c (flocal_rec_file_init, + fremote_send_file_init, frec_file_end), xcmd.c + (fremote_xcmd_init), uuxqt.c (uqdo_xqt_file, uqcleanup), uux.c + (main, uxadd_send_file), uucp.c (main, uccopy), uustat.c + (fsworkfile_show, fsexecutions, fsnotify), unix/filnam.c + (zsfile_name, zsysdep_data_file_name, zsysdep_xqt_file_name), + unix/jobid.c (zsfile_to_jobid, zsjobid_to_file), unix/splcmd.c + (zsysdep_spool_commands), unix/splnam.c (zsysdep_spool_file_name), + spool.c (zsfind_file), statsb.c (fskill_or_rejuv, + isysdep_work_time), work.c (fswork_file, fsysdep_get_work, + zsysdep_jobid, bsgrade): Marc Unangst, Brian Murrell: Corrected + support for SPOOLDIR_SVR4, since SVR4 doesn't use grades in file + names. Changed flocal argument to pseq argument in + zsysdep_spool_file_name, and changed flocal argument to bgrade + argument in zfind_file. Added fxqt argument to + zsysdep_data_file_name. Added bsgrade function. Added bgrade + argument to zsfile_to_jobid, and pbgrade argument to + zsjobid_to_file. + +Sat Oct 3 11:03:13 1992 Ian Lance Taylor (ian@comton.airs.com) + + * MANIFEST, Makefile.in, lib/MANIFEST, lib/Makefile.in, + lib/parse.c: moved parse.c from main directory to lib. + + * system.h, unix/size.c, unix/Makefile.in, unix/MANIFEST: moved + csysdep_size into its own file, made it return -1 if the file does + not exist or -2 on other errors. + uustat.c (fsworkfile_show): handle errors from csysdep_size. + send.c (flocal_send_file_init): handle errors from csysdep_size, + removed unneeded calls to fsysdep_file_exists. + + * trans.c (flocal_poll_file), tcp.c (ftcp_dial): Bob Cunningham: + declare functions consistently static. + + * Makefile.in: Marc Unangst: don't run config.status + unnecessarily. + + * configure.in: Marc Unangst: check for socket and t_open in + -lsocket, -lnsl and -lxti. + + * uuconf/cmdarg.c: check first character to avoid calls to + strcmp or strcasecmp. + +Thu Oct 1 23:44:24 1992 Ian Lance Taylor (ian@comton.airs.com) + + * trans.h, uucico.c (fdo_call, faccept_call), parse.c + (fparse_cmd), send.c (flocal_send_request): Gert Doering: SVR4 + UUCP uses a dummy string between the notify field and the size, + for some reason. + + * tstuu.c (main, uprepare_test): added -n switch to not destroy + existing configuration files. + +Fri Sep 25 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgsenddata): T. William Wells: clear bytes correctly so + that resending a packet doesn't get a completely incorrect size. + + * send.c (usadd_exec_line): Stephen J. Walick: don't send trailing + spaces on the created execute file, because it confuses Waffle. + +Thu Sep 24 00:25:18 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/jobid.c (zsjobid_to_file): Franc,ois Pinard: if the job ID + is too short, return NULL rather than dumping core. + unix/statsb.c (fskill_or_rejuv, isysdep_work_time): handle a NULL + return from zsjobid_to_file. + +Mon Sep 21 09:01:02 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/init.c, uuconf/syssub.c: Lele Gaifax: moved + declaration of _uuconf_unset from syssub.c to addstr.c because + NeXT linker does not pull in object files solely because of + variable declarations. + + * sysh.unx: Lele Gaifax: typo in ftw declaration. + + * lib/Makefile.in, unix/Makefile.in: Lele Gaifax: bug in clean + target. + +Thu Sep 17 01:01:13 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Released beta version 1.04. + +Wed Sep 16 01:02:55 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uux.c (main): null terminate the options list for an 'E' + command. + + * ustat.c (fsexecutions): allow privileged users to kill remote + execution files, and handle local executions correctly. + + * uuconf/hinit.c: added parens to avoid warning. + + * unix/splcmd.c: cast to avoid warning. + + * unix/serial.c (fsmodem_close): fixed HAVE_SYSV_TERMIO typo. + + * trans.c (uqueue_receive, floop, fgot_data): improved timing code + to make fewer system calls. + + * send.c (fsend_exec_file_init, fsend_exec_file): handle separate + E file correctly, and make a good statistics file entry for it. + + * Makefile.in, unix/Makefile.in, uuconf/Makefile.in, + lib/Makefile.in: use -I flags to permit compilation in a separate + directory. Set up clean targets per GNU standards. + +Tue Sep 15 00:07:09 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (zget_uucp_cmd): can't set size_t variable to -1. + + * Makefile.in (install): don't install info files. Added new + targets info and install-info. + +Mon Sep 14 13:19:42 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuxqt.c (main): Gregory Bond: canonicalize the system name given + by the -s argument. + + * system.h, uuconf.h, uucico.c (faccept_call), unix/unknwn.c, + unix/Makefile.in, unix/MANIFEST, uuconf/syshdr.unx, + uuconf/remunk.c, uuconf/hrmunk.c, uuconf/Makefile.in, + uuconf/MANIFEST: support HDB remote.unknown shell script. + + * protg.c (igchecksum, igchecksum2): Inspired by Mark Pizzolato, + put in new, improved checksum routines. + + * uuxqt.c (uqdo_xqt_file): make sure the execution file still + exists after locking it. + + * unix/lock.c (fsdo_lock): don't fail if the lock file is removed + between the link and the open. + + * unix/xqtsub.c (fsysdep_execute, fsysdep_lock_uuxqt_dir, + fsysdep_unlock_uuxqt_dir, fsysdep_move_uuxqt_files): use .Xqtdir + for first uuxqt execution, not .Xqtdir0000. + +Sun Sep 13 11:51:22 1992 Ian Lance Taylor (ian@comton.airs.com) + + * trans.h, uucico.c (fdo_call, faccept_call), send.c + (flocal_send_request), rec.c (flocal_rec_send_request) parse.c + (fparse_cmd): send file size in hex for SVR4 compatibility. + Required new FEATURE_V103 for 1.03 backward compatibility, since + 1.03 requires decimal size. + + * various: eliminated remaining calls to alloca. + + * tcp.c (ftcp_open), tli.c (ftli_open): set FD_CLOEXEC for sockets + and TLI descriptors. + + * tcp.c (ftcp_open): switch to real user ID before binding the + socket when running as a server. This will permit uucico invoked + by root to open privileged TCP ports. Don't switch to real ID if + effective ID is already root, to permit an suid root program to be + invoked by anybody. + + * uuxqt.c (uqdo_xqt_file): removed special case for system which + does not permit any commands: unnecessary and unusual. + + * uucico.c (fconn_call): Ed Carp: clear the SIGHUP signal + indication before opening the modem. + + * trans.h, trans.c (fqueue, fcheck_queue, floop, fgot_data), + send.c (fsend_await_confirm), rec.c (frec_file_send_confirm), + uucico.c (fcall, faccept_call): recheck the work queue every 10 + minutes. Honor CYM from the remote system. Send CYM if we have + something to do. + +Sat Sep 12 15:47:52 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Makefile.in: use $(MAKE) instead of make for recursive calls. + + * system.h, uucp.c (main), uux.c (main), unix/ufopen.c, + unix/MANIFEST, unix/Makefile.in: added esysdep_user_open to open a + file with user permissions. + +Fri Sep 11 00:27:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uudefs.h, copy.c: added fcopy_open_file. + + * policy.h: added HAVE_SAVED_SETUID. + + * configure.in, conf.h.in: check for setreuid. + +Tue Sep 8 00:11:10 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protf.c (ffsendcmd), prott.c (ftsendcmd): eliminate calls to + alloca. + + * uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), + uustat.c (main), uuchk.c (main), uuconv.c (main), uuname.c (main), + uulog.c (main), uupick.c (main), cu.c (main), lib/getop1.c, + lib/Makefile.in, lib/MANIFEST: added getopt_long, and changed all + calls to getopt to call getopt_long instead. + +Mon Sep 7 22:26:51 1992 Ian Lance Taylor (ian@comton.airs.com) + + * getopt.h, lib/getopt.c, lib/Makefile.in: bring getopt up to + glibc 1.04; call malloc instead of alloca in exchange. + + * system.h, uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c + (main), uustat.c (main), cu.c (main), uuname.c (main), unix/init.c + (usysdep_initialize): added INIT_SUID, for old systems which don't + do setuid correctly for root. + + * cu.c, unix/cusub.c: various minor improvements. + +Sun Sep 6 20:25:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uux.c (uxcopy_stdin): use getchar rather than fread to avoid + SVR4 bug. + + * uucico.c (fsend_uucp_cmd): Niels Baggesen: report message when + DEBUG_HANDSHAKE. + + * protg.c (fgsend_control): Niels Baggesen: report sending an RJ + when DEBUG_ABNORMAL. + +Tue Aug 25 00:07:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/time.c: Zacharias Beckman: let user defined time tables + override the defaults. + +Mon Aug 24 00:25:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uuxqt.c (uqdo_xqt_file), unix/xqtsub.c + (zsysdep_xqt_local_file): Jarmo Raiha: expand ~name in uuxqt.c. + + * send.c (fremote_rec_reply): SVR4 sends the size of the file with + the RY string, so we do too. We don't look for it, though. + + * uustat.c, uustat.1: Don Phillips: removed all printing of years + and seconds. Hope nobody complains. + + * uucico.c (fdo_call): don't set the status to TALKING until we + see the Shere string. + + * configure.in, conf.h.in, unix/wldcrd.c: if the system has glob, + use it for wildcards. If it doesn't, quote special characters in + the wildcard string. + + * uucico.c (fdo_call): Zacharias Beckman: don't report ``Login + successful'' until we see the Shere string. + + * prot.c (fsend_data): Don Lewis: bug in crec calculation. + + * uustat.c (fsworkfile_show, usworkfile_header, fsnotify): Don + Lewis: show poll files. + + * unix/init.c: check LOGNAME and USER environment variables before + invoking getlogin. + + * unix/serial.c: Brian Campbell: check for B57600, B76800 and + B115200 in baud rate table. + +Sun Aug 23 13:05:28 1992 Ian Lance Taylor (ian@comton.airs.com) + + * chat.c (fcsend), tstuu.c (uchild): Chip Salzenberg: call sleep + (2) instead of sleep (1). Hopefully this won't break any chat + scripts. + + * system.h, parse.c, trans.c (fqueue, flocal_poll_file), uustat.c + (fsworkfiles_system, fsquery_system), unix/work.c + (fsysdep_get_work, fsysdep_get_work_init): don't delete poll files + immediately, but instead return a 'P' command and delete them when + the command is passed to fsysdep_did_work. + + * tstuu.c (uprepare_test): change ``call-request'' to ``request''. + + * uuconf/iniglb.c (_uuconf_itimetable): return CMDTABRET_KEEP so + we don't lose the timetable name and definition. + + * uuconf.h, send.c (fremote_rec_file_init), rec.c + (fremote_send_file_init), uuchk.c (ukshow), uuconv.c + (uvwrite_taylor_system, uvwrite_hdb_system), uuconf/tsinfo.c + (iirequest), uuconf/hsinfo.c, uuconf/hunk.c, uuconf/syssub.c: + added ``send-request'' and ``receive-request'' commands, + eliminated ``call-request'' and ``called-request'' commands. + + * uux.c (main): make sure we are permitted to transfer files + before queuing requests. + + * uuconf.h, uucico.c (fcall), uuconf/tsinfo.c, uuconf/syssub.c: + David Nugent: added ``success-wait'' command for systems, to set a + minimum time between successful calls. + + * send.c (fremote_rec_file_init): Don Phillips: let a request only + specify the file base name in the TO argument. + + * uucico.c (main): Don Lewis: don't exit with success just because + we were able to start uuxqt. + + * unix/serial.c (fsmodem_close, fsserial_read): always drop DTR + when closing a modem connection. Also, retry if we time out when + setting MIN. + +Sat Aug 22 22:31:34 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/time.c: Stephen Walick: don't require a comma between + time strings, since HDB doesn't seem to. + + * protg.c (fgcheck_errors): added "error-decay" protocol parameter + to decay errors as packets are successfully received. + + * uustat.c (fsmachines), uustat.1: Chris Lewis: don't display the + year or seconds for uustat -m. Probably uustat -q should be + changed as well. + + * tstuu.c: Larry Fahnoe: don't report EWOULDBLOCK errors when + writing to a pty. Also removed functions which are now in lib. + + * MANIFEST, Makefile.in, uusched.in: added a simple uusched shell + script. + + * parse.c: Heiko Rupp: don't die if there is trailing garbage in + an 'R' command. + + * policy.h, system.h, sysh.unx, send.c, rec.c, uuxqt.c, uux.c, + unix/filnam.c, unix/init.c, unix/jobid.c, unix/splnam.c, + unix/spool.c, unix/statsb.c, unix/tmpfil.c, unix/work.c, + unix/xqtfil.c: Brian J. Murrell and Don Phillips: added + SPOOLDIR_SVR4. + +Thu Aug 20 00:06:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysh.unx: Chiaki Ishikawa: some systems define some but not all + of the S_ file mode bits. + + * uuchk.c (ikshow_port): Chiaki Ishikawa: display lockname. + +Wed Aug 19 22:41:39 1992 Ian Lance Taylor (ian@comton.airs.com) + + * log.c (ustats): Scott Blachowicz: avoid overflow when reporting + bytes per second. + + * unix/lock.c (fsdo_lock): Chip Salzenberg: sometimes other + programs create lock files that uucp can't write. + + * trans.h, system.h, trans.c (floop, fgot_data, usent_receive_ack, + uwindow_acked), send.c (flocal_send_await_reply, + flocal_send_fail), rec.c (fremote_send_fail_send, + frec_file_send_confirm), prote.c, protf.c, protg.c, proti.c, + prott.c, protz.c (calls to fgot_data), unix/recep.c, + unix/MANIFEST, unix/Makefile.in: keep trace of whether we have + already received a file, in case the other side never sees our + ack. Added new SN8 rejection, meaning that the file has already + been received. + +Sat Aug 15 11:50:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf/time.c (itadd_span): Don Lewis: fixed bug if later span + overlapped two or more earlier spans. + +Thu Aug 13 00:19:50 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, rec.c (fremote_send_file_init, fremote_send_reply), + uucico.c (fdo_call, faccept_call), uucp.c (main), uux.c (main), + unix/opensr.c (zsysdep_receive_temp, esysdep_open_receive): + implemented file restart. + +Wed Aug 12 23:32:05 1992 Ian Lance Taylor (ian@comton.airs.com) + + * proti.c (fiprocess_data): ensure that the first argument to + fgot_data is always > 0 if the second argument is > 0. + +Mon Aug 10 22:43:40 1992 Ian Lance Taylor (ian@comton.airs.com) + + * trans.c (floop, ustats_failed): handle half-duplex connections + and failed calls correctly. + +Sun Aug 9 17:56:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * proti.c (firesend, fisenddata, ficheck_errors): made several + changes to improve performance on a lossy line: can now shrink + packet size using SYNC packets, avoids multiple bad header errors + in a sequence of INTRO characters, avoids letting one side lock up + if a NAK is lost. + + * configure.in: set HAVE_LONG_FILE_NAMES to 0 if + cross-configuring. + + * tstuu.c: changed -p option to be mod 1000, not mod 100. + + * MANIFEST, Makefile.in, prot.h, uucico.c, protz.c, trans.c: Doug + Evans: added Doug Evans's zmodem implementation as protocol 'a'. + +Wed Aug 5 22:28:14 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, uuconf.h, uucico.c (fcall), uuconf/tsinfo.c, + uuconf/hsinfo.c, uuconf/syssub.c: added "max-retries" command for + systems, eliminated CMAXRETRIES configuration parameter, set + max_retries to 0 for HDB if retry time given, (from Chris Lewis) + call once a day even if max_retries has been exceeded. + + * prot.h, uucico.c (fdo_call, faccept_call), prott.c, prote.c, + proti.c, protg.c, protf.c: added pzlog argument to pfstart + protocol entry point, changed handshake successful message to + display it. + +Tue Aug 4 00:04:31 1992 Ian Lance Taylor (ian@comton.airs.com) + + * prot.h, uucico.c, protg.c (fbiggstart, cGshort_packets): Chip + Salzenberg: added support for 'G' protocol. Added "short-packets" + protocol parameter for 'g' and 'G' protocols. + + * uuconf.h, rec.c (flocal_rec_file_init), uucp.c, uux.c, uuxqt.c, + uuchk.c, uuconv.c, uuconf/local.c, uuconf/tsinfo.c, + uuconf/syssub.c: support UUCP forwarding. Added "forward-from", + "forward-to", and "forward" commands for systems. + + * unix/spawn.c: don't close the file descriptor after dupping it. + +Sun Aug 2 23:04:18 1992 Ian Lance Taylor (ian@comton.airs.com) + + * trans.c (fremote_hangup_reply): don't hangup if a file transfer + is in progress. + + * send.c (flocal_send_cancelled): don't pass a NULL buffer to + pfsenddata. + +Sun Jul 26 13:28:27 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/work.c (fsysdep_get_work_init): return TRUE if there is no + work directory. + + * configure.in, sysh.unx: don't run any programs in configure if + we are cross-configuring; this applies to HAVE_FTIME and + HAVE_RESTARTABLE_SYSCALLS. The code can cope with the buggy + ftime. If we are cross-configuring, HAVE_RESTARTABLE_SYSCALLS is + set to -1, and sysh.unx guesses that if the system has sigvec but + not sigaction or SV_INTERRUPT it is on 4.2BSD and system calls are + automatically restarted. + + * configure.in, conf.h.in, tstuu.c, unix/serial.c: removed + COMBINED_UNBLOCK configuration parameter, and changed the code + which sets O_NONBLOCK and O_NDELAY to drop back to using just + O_NONBLOCK if it gets an EINVAL error. + + * configure.in, conf.h.in, uucp.h, protg.c (fgsenddata), cu.c + (icutake), chat.c (icexpect), lib/MANIFEST: removed all calls to + memmove, avoiding the SCO bug and making the 'g' protocol slightly + more efficient. + +Sat Jul 25 14:20:30 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h, uudefs.h, many other files: broke part of uucp.h out + into uudefs.h, stopped including uuconf.h in uucp.h, fixed up .c + files to include uudefs.h and uuconf.h as necessary. + + * uuconf/syshdr.unx, uuconf/callin.c, uuconf/diacod.c + uuconf/hdial.c, uuconf/hdnams.c, uuconf/hport.c, uuconf/hsinfo.c, + uuconf/hsnams.c uuconf/rdlocs.c, uuconf/tcalou.c, uuconf/tdial.c, + uuconf/tdnams.c, uuconf/tport.c, uuconf/vport.c, uuconf/vsinfo.c, + uuconf/vsnams.c: changed uuconf library to not return an error if + a configuration file does not exist; it now acts as though + whatever it is is not found. + + * tstuu.c (main): use perror if execl fails. + + * configure.in, conf.h.in, uucp.h, uuconf.h, sysh.unx, conn.h, + MANIFEST, Makefile.in, tli.c, chat.c (ccescape), conn.c + (fconn_init), tcp.c, uucico.c (faccept_call), uuconv.c, uuchk.c, + lib/MANIFEST, lib/Makefile.in, lib/escape.c, unix/cusub.c, + unix/serial.c, uuconf/hport.c, uuconf/tportc.c: added support for + TLI connections. Moved ccescape from chat.c to cescape in + lib/escape.c. Made all connections on Unix use the same + system dependent structure. + +Tue Jul 21 22:08:10 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h, trans.h, uucico.c (fdo_call, faccept_call), uuxqt.c + (uqdo_xqt_file), uucp.c (main), uux.c (main), uustat.c + (fsworkfile_show), parse.c (fparse_cmd), trans.c (fqueue, + fgot_data, ftadd_cmd), send.c, rec.c, xcmd.c, protf.c + (ffprocess_data), proti.c (fiprocess_data), tstuu.c + (uprepare_tests), unix/splcmd.c (zsysdep_spool_commands), + unix/statsb.c (fskill_or_rejuv), unix/work.c (fsysdep_get_work): + added E request to send file executions which only require reading + from standard input. + +Sat Jul 18 20:22:50 1992 Ian Lance Taylor (ian@comton.airs.com) + + * proti.c, Makefile.in, MANIFEST, prot.h, system.h, trans.h, + uucico.c, prote.c, protf.c, protg.c, prott.c, trans.c, send.c, + rec.c, xcmd.c, unix/opensr.c: added 'i' protocol. Added local and + remote channel arguments to protocol sendcmd and senddata entry + points. Cleaned up send and receive state machines. Removed + pfgone argument from esysdep_open_send. + +Fri Jul 17 09:41:05 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuxqt.c (uqdo_xqt_file): only report base name of execution + file, not full name. + +Thu Jul 16 00:45:06 1992 Ian Lance Taylor (ian@comton.airs.com) + + * lib/crc.c: unroll the loop a bit. + + * configure.in, conf.h.in, unix/init.c: updated to autoconf 0.120. + +Wed Jul 15 14:45:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconv.c, uuconf/uucnfi.h, uuconf/reliab.c, + uuconf/tportc.c, uuconf/tdialc.c, uuconf/diasub.c, uuconf/hport.c, + uuconf/prtsub.c, uuconf/vsinfo.c: added UUCONF_RELIABLE_FULLDUPLEX + and "half-duplex" command for ports and dialers. + +Mon Jul 13 16:53:04 1992 Ian Lance Taylor (ian@comton.airs.com) + + * prot.h, lib/crc.c, lib/Makefile.in, lib/MANIFEST: added icrc + function to compute 32 bit CRC (from Gary S. Brown, via Doug + Evans). + +Sun Jul 12 21:40:15 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconv.c (uvwrite_time): Chris Lewis: don't output two commas in + a row. + + * uuconv.c (uvwrite_taylor_system, uvwrite_taylor_port): Chris + Lewis: generate command "protocol", not "protocols". + +Sat Jul 11 17:09:09 1992 Ian Lance Taylor (ian@comton.airs.com) + + * xcmd.c (fremote_xcmd_init): Chris Lewis: use qdaemon->puuconf, + since puuconf is not defined. + + * uuconf/syshdr.unx, uuconf/hinit.c (uuconf_hdb_init): Chris + Lewis: added HDB_SEPARATOR to insert between oldconfiglib and + strings in HDB Sysfiles. + + * uuconf/syshdr.unx: Chris Lewis: define strerror as a macro. + + * uuconf/freblk.c, uuconf/free.c: Chris Lewis: don't define as + void when ! UUCONF_ANSI_C. + +Thu Jul 9 09:17:55 1992 Ian Lance Taylor (ian@comton.airs.com) + + * prot.h, uucico.c (fdo_call, faccept_call), prote.c (festart), + protf.c (ffstart), protg.c (fgstart), prott.c (ftstart): no need + to pass fmaster as a separate argument to protocol start routine. + + * protf.c (ffawait_ack, ffawait_cksum): don't try to resend if we + don't have a file. + +Wed Jul 8 14:28:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/srmdir.c (fsysdep_rmdir), unix/walk.c (usysdep_walk_tree): + cast to char * to avoid warning. + + * cu.c (main): don't compare boolean to NULL. + + * unix/serial.c (isblocksigs), unix/signal.c (usset_signal): use + extra parens to avoid bug in SCO 3.2.2 sys/signal.h header file. + + * sysh.unx: always define struct ssysdep_tcp, for the benefit of + systems for which HAVE_TCP is 0. + + * MANIFEST, Makefile.in, unix/Makefile.in, uuconf/Makefile.in, + lib/Makefile.in: updated automatic distribution code for multiple + directories. + + * unix/cusub.c, unix/serial.c: don't clobber CR when using TERMIO + or TERMIOS, and default MIN to 1 to the convenience of cu. + + * Makefile.in, uucp.h, system.h, prot.h, trans.h, uucico.c, + trans.c, send.c, rec.c, xcmd.c, prot.c, protg.c, protf.c, prote.c, + prott.c, log.c, file.c, unix/opensr.c, unix/work.c: rewrote file + transfer internals to support bidirectional transfers. Keep queue + of jobs to do, and support connections. Added new files trans.h, + trans.c, send.c, rec.c, xcmd.c, and removed old file file.c. + +Mon Jun 29 15:14:15 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Makefile.in: Stephen J. Walick: copy uustat.1 to + uustat.$(manext), not uucp.($manext). Also try to create + $(infodir). + + * chat.c (fcsend, fcprogram): check for NULL return from + uuconf_callout. + +Thu Jun 18 22:37:28 1992 Ian Lance Taylor (ian@comton.airs.com) + + * configure.in, Makefile.in: updated to autoconf 0.118. + +Wed Jun 17 14:22:11 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/serial.c (fsserial_init): add /dev if necessary to device + as well as to port name. + + * cu.c (main): set zdevice to NULL when faking line. + + * cu.c (main), uucp.c (main), uux.c (main), uuxqt.c (main): don't + call zsysdep_localname until we've called usysdep_initialize. + +Tue Jun 16 17:42:50 1992 Ian Lance Taylor (ian@comton.airs.com) + + * unix/signal.c (usset_signal): set SA_INTERRUPT to force system + calls to be interrupted on SunOS. + +Mon Jun 15 15:10:24 1992 Ian Lance Taylor (ian@comton.airs.com) + + * everything: integrated uuconf library. Split out lib and unix + libraries. Made many changes, including defaults for port and + dialer files, better handling of changed local name, better + handling of HDB Permissions, new zbufalc routines to manage + strings on the heap. Incorporated uuconv. + +Wed Jun 10 23:51:03 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/Makefile.in, uuconf/locnm.c, uuconf/llocnm.c, + uuconf/hlocnm.c, uuconf/tlocnm.c: renamed uuconf_localname to + uuconf_login_localname and added new uuconf_localname which + doesn't need to read system information. + +Tue Jun 9 14:19:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/Makefile.in, uuconf/local.c: wrote + uuconf_system_local. + +Mon Jun 8 14:14:30 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h: changed description of LOCKDIR, which now need not + always be defined. + + * uuconf.h, uuconf/uucnfi.h, uuconf/lckdir.c, uuconf/iniglb.c, + uuconf/tinit.c, uuconf/Makefile.in: added uuconf_lockdir, and + ``lockdir'' command to config. + +Sat Jun 6 22:07:58 1992 Ian Lance Taylor (ian@comton.airs.com) + + * configure.in: updated to autoconf 0.115, added code to set + LIBOBJS. + + * uuconf/Makefile.in, uuconf/uucnfi.h: removed references to + routines now in lib/, changed to include regular UUCP header + files. + +Fri Jun 5 15:31:29 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/uucnfi.h, uuconf/syssub.c, uuconf/uuconv.c: + always set zpubdir for every system, changed uuconf_zpubdir to + const char *. + +Wed Jun 3 15:15:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/Makefile.in, uuconf/deblev.c, uuconf/maxuxq.c, + uuconf/pubdir.c, uuconf/spool.c: wrote uuconf_debuglevel, + uuconf_maxuuxqts, uuconf_pubdir, uuconf_spooldir. + + * configure.in: updated to autoconf 0.114. + + * uuconf/tportc.c: default TCP ports to being fully reliable. + +Mon Jun 1 17:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/prtsub.c: removed uuconf_psysdep from + uuconf_port. + +Sun May 31 00:07:40 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuconf.h, uuconf/Makefile.in, uuconf/diacod.c: wrote + uuconf_dialcode. + + * uuconf.h, uuconf/Makefile.in, uuconf/logfil.c, uuconf/debfil.c, + uuconf/stafil.c: wrote uuconf_logfile, uuconf_debugfile, + uuconf_statsfile. + + * uuconf.h, uuconf/Makefile.in, uuconf/callin.c: wrote + uuconf_callin. + + * uuconf/chatc.c, uuconf/time.c: Jean Mehat: only call tolower if + isupper is true. + + * uuconf.h, uuconf/Makefile.in, uuconf/val.c, uuconf/tval.c: wrote + uuconf_validate, uuconf_taylor_validate. + +Sat May 30 12:37:02 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, sys1.unx: changed zsysdep_local_name to + zsysdep_localname, and made it fatal out rather than return NULL. + + * uuconf.h, uuconf/Makefile.in, uuconf/uucnfi.h, uuconf/iniglb.c, + uuconf/rdlocs.c, uuconf/locnm.c, uuconf/tlocnm.c, uuconf/hlocnm.c: + wrote uuconf_localname, uuconf_taylor_localname, + uuconf_hdb_localname. + + * uuconf.h, uuconf/Makefile.in, uuconf/uucnfi.h, uuconf/iniglb.c, + uuconf/tinit.c, uuconf/tsinfo.c, uuconf/hunk.c, uuconf/unk.c: + wrote uuconf_system_unknown, uuconf_hdb_system_unknown, + uuconf_taylor_system_unknown. + + * log.c, time.c: always include in uucp.h. + + * configure.in, conf.h.in: check for size_t, renamed checks for + time_t. + + * configure.in, conf.h.in: check for . + +Fri May 29 00:03:05 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysinf.c (ztranslate_system): Jac Kersing: must xstrdup the + argument, since it points to a buffer that will be reused. + +Thu May 28 12:42:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys3.unx (zsysdep_real_file_name): Ted Lindgreen: check return + value of zstilde_expand. + + * copy.c, sys1.unx (usysdep_detach), sys2.unx (fsserial_close), + sys3.unx, sys5.unx, sys7.unx: opening /dev/tty in usysdep_detach + confuses the NeXT, so instead we just call TIOCNOTTY on 0. In + fsserial_close we call TIOCNOTTY on the port before closing it, to + make sure that we have ditched it under BSD. Also added O_NOCTTY + to every open call other than opening a port, although there are + still several fopen calls which should probably have it somehow. + + * system.h, uucico.c (fcall), uustat.c (fsquery_system, + fsquery_show), sys3.unx (fsysdep_get_status), sys7.unx + (zsysdep_all_status): Bob Izenberg: changed output of uustat -q to + count number of commands rather than number of files being + transferred, and to not report a non-existent status. Added + pfnone argument to fsysdep_get_status, and changed all calls. + + * uucico.c, sys1.unx, sys2.unx, sys3.unx, sys5.unx, sys6.unx, + sys7.unx: Rolf Nerstheimer: cast a bunch of arguments to open, + creat, stat and chmod to avoid compiler warnings. + + * uucp.h, log.c (ulog), port.c (fport_close), prot.c (fgetcmd): + Chip Salzenberg: don't log a SIGHUP signal while we're closing + down the connection, since the other side might hang up faster + than we do (we still react to it correctly, we just don't put it + in the log file). + + * sys1.unx (usysdep_detach), tcp.c (ftcp_open): Petri Helenius: + update the process ID we log after a fork. + + * Makefile.in, sys1.unx: Chip Salzenberg: changed LIBDIR to + SBINDIR. + + * uucp.c (main, uccopy): Andreas Vogel: check local-receive of the + correct system, rather than always using sLocalsys. + + * configure.in, conf.h.in, sys2.unx, tstuu.c: Rob Janssen: look + for , and include it if it exists and we are using + select. + + * protg.c: Rob Janssen: rearrange macros to avoid bug in XENIX + compiler. + + * configure.in: Scott Blachowicz: check WIFEXITED before assuming + HAVE_UNION_WAIT, to avoid problems on HP/UX. + + * configure.in, conf.h.in, sysh.unx, sys1.unx: John Theus: use + sv_onstack instead of sv_flags in the sigvec structure on 4.2BSD. + +Wed May 27 23:23:39 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, sys2.unx (fsysdep_modem_no_carrier): Scott Reynolds: + added HAVE_CLOCAL_BUG compilation parameter to work around + problems on some serial ports. + +Tue May 26 15:50:17 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uustat.c, uustat.1: added a bunch of options to support uuclean: + -e, -i, -K, -M, -N, -W, -Q. + + * system.h, sys7.unx (fsysdep_privileged, fskill_or_rejuv): added + fsysdep_privileged function. + +Thu May 21 13:30:21 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuxqt.c (uqdo_xqt_file): processing of execution file has to be + case significant; this will change handling of "n" flag, which was + not correctly handled before. + +Wed May 20 14:22:12 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys1.unx (usysdep_detach): close the statistics file when + detaching. + + * policy.h, sys3.unx (fsdo_lock, fsdo_unlock), sys7.unx + (fsysdep_lock_status): force LOCKDIR to always be defined. + + * uucp.h: put in an extern for alloca. + + * sysh.unx, sys1.unx, sys5.unx, sys6.unx: defined all the ?_OK + macros in sysh.unx, which means that must be included + before "sysdep.h" when they are both included. + + * sys2.unx (fsserial_set): corrected case in termio switch + expression. + + * chat.c (fcsend): simplified expression for old compilers. + + * sys1.unx (rmdir): wrote rmdir replacement which invokes + /bin/rmdir for old systems. + + * configure.in, conf.h.in, Makefile.in: updated for autoconf + 0.112, added checks for ftw, ftw.h, and rmdir. + + * sys1.unx: added extern for ctime, removed externs for functions + returning int, protected externs with ifndefs. + + * uucp.h, prot.h, system.h, uucico.c (fuucp), uuxqt.c + (uqdo_xqt_file), prot.c (freceive_file), file.c (freceived_file), + sys3.unx (fsysdep_move_file, fsysdep_change_mode), sys4.unx + (zsysdep_save_temp_file): changed fsysdep_move_file to not set the + file mode, and added fsysdep_change_mode to do it instead. + + * system.h, uucp.c (main, ucdirfile, uccopy), sys6.unx + (usysdep_walk_tree, isdir, ftw, do_ftw): added -R option to uucp + to recursively copy directories. + +Tue May 19 18:29:32 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys3.unx: changed zsysdep_in_dir to always append the filename + to the directory, even if the directory did not already exist. + + * sysh.unx, sys1.unx, sys3.unx, sys4.unx, sys5.unx: renamed + fsdirectory_exists to fsysdep_directory. + +Mon May 18 14:49:35 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uucp.c (main), sys6.unx (zsysdep_uuto): added -t + option to uucp to emulate uuto, wrote zsysdep_uuto to do Unix + dependent destination translation for uuto, added -p option to + uucp as synonym for -C for uuto compatibility. + +Sun May 17 22:04:09 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgexchange_init): permit a second INITB to override the + segment size given in the first INITB. + +Tue May 5 16:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (main, fdo_call), uucico.8: Chip Salzenberg: added -c + option to uucico to not warn if invoked when the system may not be + called. + +Tue Apr 28 15:05:01 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysh.unx, sys2.unx (fsserial_open, fsblock): preserve file + status flags. + + * protg.c (fgwait_for_packet): Heiko Rupp: only send RJ packet if + there are no unacknowledged packets. + +Mon Apr 27 18:56:42 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h: added several routines for cu. + + * cu.c, cu.h, sys8.unx: checked into RCS. + + * uux.c (main): Jose Manas: dumb bug when checking against + calloc_args. + +Fri Apr 24 20:32:06 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys1.unx: changed HAVE_LONG_NAMES to HAVE_LONG_FILENAMES for new + version of autoconf. + + * sys7.unx: check UTIME_NULL_MISSING with #if rather than #ifdef. + + * sys3.unx: check FS_* macros with #if rather than #ifdef. + + * uucp.h, sysh.unx: changed standard type definitions for new + version of autoconf. + + * sysh.unx, sys1.unx, sys2.unx, tstuu.c: changed SIGtype to + RETSIGTYPE for new version of autoconf. + + * sys1.unx, tstuu.c: make include of optional. + + * sys2.unx: get the right versions of major and minor. + +Wed Apr 22 11:19:11 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgsenddata, fggot_ack): Michael Haberler: the slow + start after error code was essentially shrinking the window size. + + * sysh.unx, system.h, sys1.unx (usysdep_initialize), uuchk.c, + uucico.c, uucp.c, uulog.c, uuname.c, uustat.c, uux.c, uuxqt.c: + changed usysdep_initialize to take a single argument with bit + flags, added INIT_NOCHDIR as one of the flags. + + * uucp.h, log.c (ulog): added pfLstart and pfLend functions for + ulog, so that cu can use them to restore the terminal settings. + + * bnu.c (ubnu_read_systems, fbnu_read_dialer_info), v2.c + (uv2_read_systems): Michael Richardson: don't core dump if no chat + script. + +Tue Apr 21 00:19:47 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (faccept_call): Chris Lewis: a successful call in + should clear the number of retries. + + * sys2.unx (fsserial_set): set LLITOUT if going to CBREAK mode. + + * port.h, prote.c (festart), protf.c (ffstart), protg.c (fgstart), + prott.c (ftstart), port.c (fport_set), sys2.unx + (fsysdep_stdin_set, fsysdep_modem_set, fsysdep_direct_set, + fsserial_set): gave fport_set independent control over output + parity generation, input parity checking, and XON/XOFF + handshaking, all to support cu. + +Mon Apr 20 11:47:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * port.h, uucico.c (fdo_call), port.c (fport_dial, fmodem_dial), + tcp.c (ftcp_dial): added separate zphone argument to fport_dial to + support cu. + +Thu Apr 16 01:15:42 1992 Ian Lance Taylor (ian@comton.airs.com) + + * bnu.c (ubadd_perm, ubadd_perm_alternate): Chris Lewis: handle a + combination of Permissions entries which specify just LOGNAME with + entries that specify both MACHINE and LOGNAME. + +Wed Apr 15 16:11:48 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys1.unx (usysdep_initialize, zsysdep_login_name): John Theus: + don't die if can't get login name, unless it's really needed. + +Tue Apr 14 12:39:18 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (main, fcall): Petri Helenius: must relock system after + detaching from terminal when trying different alternates. + + * system.h, uucico.c (fuucp), uustat.c (fsworkfiles_system, + fsquery_system), sys4.unx (fsysdep_get_work_init, + fsysdep_get_work): Marty Shannon: uustat would remove empty + command files. + + * bnu.c (ubadd_perm_alternate): John Harkin: permit ALIAS in + Permissions. + + * Makefile.in: John Harkin: add sys?.c dependencies to sys?.o to + work around old makes which don't handle transitive .SUFFIXES. + + * sys2.unx: cast some function calls to void. + + * time.c (qttime_parse): cast to void warning. + + * sys1.unx (iswait): cast waitpid argument to avoid warning. + + * configure.in, policy.h, uucp.h, sys7.unx, tstuu.c: Zacharias + Beckman: minor touchups for NeXT. + + * sys1.unx (usysdep_initialize), sys6.unx (zsysdep_add_cwd), uux.c + (main): Jarmo Raiha: heuristic for whether to get the current + directory can fail. + + * sys1.unx: pass argument to uudir, cast sigemptyset calls to + void. + + * uucp.texi: Harlan Stenn: correct case of references. + +Tue Apr 7 01:02:17 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Released version 1.03. + +Mon Apr 6 15:49:08 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (faccept_call): Marc Boucher: set *pqsys to NULL. + + * bnu.c (ubnu_read_systems, fbnu_find_port): Erik Forsberg: + support multiple character modem classes. + +Fri Apr 3 00:37:25 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys2.unx: Petri Helenius: only clear known bits in termio or + termios structure; didn't change HAVE_BSD_TTY handling--maybe next + version. + + * configure.in: test TIMES_DECLARATION_OK correctly. + + * Makefile.in: update version to 1.03, remove distclean, add + mostlyclean per GNU standards. + + * sys1.unx, chat.c: minor cleanups for gcc 2.1. + +Thu Apr 2 17:51:36 1992 Ian Lance Taylor (ian@comton.airs.com) + + * tstuu.c: conditionally declare times. + + * uucp.h, prot.c, sysinf.c, prtinf.c: added gcc 2.0 format + checking to ulog, and fixed a few problems it discovered. + +Wed Apr 1 16:21:08 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys3.unx (esysdep_open_receive): David J. MacKenzie: some + USG_STATFS systems use 512 as the block size of f_bfree, despite + the existence of f_bsize. + + * port.c (fport_open): initialize stdin port. + + * policy.h, log.c: added CLOSE_LOGFILES configuration parameter. + + * sys2.unx: T. William Wells: handle a system without or + . + + * configure.in: Franc,ois Pinard: warn if none of napms, nap, + usleep, poll or select are available, since \p will sleep for a + full second. + + * Makefile.in: Gerben Wierda: fixed uninstall to set file owner + and mode correctly. Also changed install to handle uucp.info-4 + and uustat.1. + + * MANIFEST: added uucp.info-4 and uustat.1. + + * uustat.1: Wrote. + + * uucico.8, uuxqt.8, uucp.1, uux.1: updated -x switch, cleaned up + a bit. + +Tue Mar 31 14:40:06 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys1.unx (usysdep_initialize): use $PWD to get the current + working directory if it's defined and correct. + + * sys1.unx (usysdep_initialize): Brian Antoine: use name from + getpwname rather than getlogin. + + * uucp.texi: David J. MacKenzie: put in a number of corrections. + Also split sys file and config file nodes, and rearranged several + nodes. + + * protg.c (fgsenddata): Niels Baggesen: packet to retransmit did + not get reset correctly. + +Mon Mar 30 10:03:28 1992 Ian Lance Taylor (ian@comton.airs.com) + + * tcp.c (ftcp_reset): Petri Helenius: TCP server never started + uuxqt, because it exited in ftcp_reset. + + * policy.h, sysh.unx, sys2.unx (fsserial_lockfile): added + HAVE_SVR4_LOCKFILES configuration parameter. + + * sys3.unx (esysdep_open_receive): Niels Baggesen: USG statfs has + an f_bsize field. + +Sun Mar 29 23:04:20 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h, sysinf.c, prot.c, prote.c, protf.c, protg.c, prott.c: + Niels Baggesen: added new debugging types abnormal and uucp-proto. + + * uucico.c (fuucp), prot.c (freceive_file), file.c + (fstore_recfile): Dirk Musstopf: if a file receive fails before it + starts, perhaps because the file was too large, remember to remove + the temporary file. + + * sys2.unx (fsserial_lock, fsserial_open, fsserial_write, + fsserial_io): always block and unblock the read and write + descriptors together. + +Sat Mar 28 14:40:50 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uustat.c: allow multiple systems and users to be specified at + once; likewise for kills and rejuvenates. Allow old and young to + be combined with systems and users. As suggested by Niels + Baggesen, make machine status output more columnar. + + * uucp.h, uucico.c, config.c, sys3.unx: Michael I Bushnell: + renamed enum tstatus to tstatus_type to avoid conflict with + on some systems. + + * config.c, sysinf.c, prtinf.c, chat.c: David J. MacKenzie: allow + backslash newline quoting in all TAYLOR_CONFIG configuration + files. + + * chat.c (fchat): David J. MacKenzie: handle empty subexpect + strings correctly. + + * uucico.c (main, fcall): Petri Helenius: must dump controlling + terminal before going to next alternate. Also fixed David J. + MacKenzie bug in which a signal did not prevent the next + alternates from being tried. Also made sure qtime was always + freed up. + + * uucp.h, uucico.c (fdo_call), sysinf.c (tialternate), uuchk.c + (ukshow): Franc,ois Pinard: allow a name to be given to an + alternate, and display the name when placing a call. + + * chat.c (fcprogram), port.c (fport_open, fport_close): David J. + MacKenzie: send port device rather than port name to a chat + program using \Y; make sure port device is reset if port open + fails and when port is closed. + + * uucico.c (fuucp), log.c (ulog, ustats, ustats_close): close log + and statistics file every time master and slave switch roles. + +Fri Mar 27 00:31:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (fdo_call): Mark Mallett: minor cleanup. + + * uuname.c (main): Franc,ois Pinard: output aliases, added -a + switch. + + * uucico.8, uuxqt.8, uux.1, uucp.1: David J. MacKenzie: changed + .TP5 to .TP 5; also updated to 1.03. + + * tstuu.c: Roberto Biancardi: if SIGCHLD is not defined, define it + as SIGCLD. + + * config.c: David J. MacKenzie: cMaxuuxqts is independent of + HAVE_TAYLOR_CONFIG. + + * uucp.h: Gerben Wierda: don't always declare bzero. + + * sys7.unx (ussettime, fsysdep_lock_status): Niels Baggesen, + Gerben Wierda: minor patches. + + * sys2.unx: Gerben Wierda: minor cleanups. + + * uucp.h: Niels Baggesen: simplified debugging message macros to + avoid broken compilers. + + * sys2.unx: don't use TIOCEXCL locking. + + * sys2.unx: rework HAVE_UNBLOCKED_WRITES == 0 to work even if + writes are unblocked. Correct initialization of fwrite_blocking. + + * Makefile.in, configure.in: David J. MacKenzie: various cleanups. + Changed default newconfigdir definition. Supported compilation in + a different directory. Used symbolic links if available. Changed + default infordir definition per Franc,ois Pinard. + + * policy.h: David J. MacKenzie: various cleanups. + +Thu Mar 26 12:17:41 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys3.unx: reduced race condition in fsdo_lock. + + * sys1.unx: Gerben Wierda: various cleanups. Also don't set + sa_flags to SV_INTERRUPT per Chip Salzenberg. + +Wed Mar 25 22:20:24 1992 Ian Lance Taylor (ian@comton.airs.com) + + * configure.in: Overhauled for readability and functionality as + suggested by T. William Wells and others. Added bug checks, + including for SCO memmove and ftime. + +Tue Mar 24 12:18:56 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysinf.c (uiread_systems): fixed handling of alternates in + file-wide defaults. + +Wed Mar 18 01:01:25 1992 Ian Lance Taylor (ian@comton.airs.com) + + * config.c (tprocess_one_cmd): handle CMDTABTYPE_FULLSTRING + correctly if there are no arguments. + + * Released beta version 1.03 + + * sys1.unx (usysdep_detach): open the controlling terminal in non + delay mode since it might be a modem. + +Tue Mar 17 00:01:53 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (fdo_call, faccept_call): T. William Wells: set current + time in status file when call completes. + + * sys1.unx (iswait), sys2.unx (fsserial_read, fsserial_write, + fsserial_io): log signals when they occur, even if we continue + some sort of loop, rather than waiting for the next ulog call. + + * sys2.unx (fsserial_lock, fsserial_open): don't block when + opening the write descriptor. + +Mon Mar 16 00:14:43 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uuxqt.c (uqdo_xqt_file), sys5.unx (fsysdep_execute): + pass command to fsysdep_execute as first element of argument + array. + + * tcp.c: declare _exit. + + * uucp.h: move definition of const before use for non ANSI C. + + * uucp.h, sys1.unx: undefine remove in uucp.h if the system does + not have it to avoid conflict with macro definitions. + + * uucico.c, uuxqt.c, protf.c, prott.c, prote.c, config.c, chat.c, + port.c, sys2.unx: miscellaneous cleanups. + + * tcp.c (ftcp_open): cast argument to bzero. + + * time.c (qtimegrade_parse): cast argument to qttime_parse to + long. + + * file.c: changed iRecmode to unsigned int. + + * configure.in, uucp.h: on SCO 3.2.2 sig_atomic_t is defined in + but not . + + * sys1.unx: undefined remove before the function definition to + avoid trouble on systems for which it is a macro. + + * Makefile.in: removed dependencies of getopt.o. + + * sys1.unx, sys7.unx, tstuu.c: adjusted external declarations. + + * getopt.h, getopt.c: get new versions from glibc 1.01. + + * sys1.unx: don't declare sigemptyset. + + * version.c: updated to beta 1.03. + + * chat.c (fcsend): Scott Ballantyne: go ahead and send a character + for an illegal escape sequence rather than failing out. + + * uuxqt.c (uqdo_xqt_file), sys5.unx (zsysdep_find_command): cast + result of alloca. + + * protg.c (fgprocess_data): Niels Baggesen: improved debugging + information. Also tweaked fgprocess_data code to use memchr to + find the next DLE rather than searching for it by hand. + + * uucico.c (faccept_call, fuucp): accept SVR4 -U flag giving + maximum file transfer size; accept and ignore SVR4 -R flag meaning + that the system supports file restart. + +Sun Mar 15 00:21:56 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysinf.c (titime, titimegrade): permit a retry time to be + specified as an optional additional argument. + + * uucico.c (zget_uucp_cmd, zget_typed_line): turn off DEBUG_PORT + when doing DEBUG_HANDSHAKE. + + * policy.h, sysh.unx, sys1.unx, sys2.unx (fsblock_writes, + fsserial_write, fsserial_io): added configuration parameters + HAVE_UNBLOCKED_WRITES and SINGLE_WRITE. Also blocked signals + while clearing afSignal in fsysdep_modem_close. + + * chat.c (icexpect, fcsend): turn off DEBUG_PORT while doing chat + script debugging. + + * sysh.unx, sys2.unx (fsserial_lock, fsserial_open, + fsserial_write, fsserial_io, fsysdep_tcp_read, fsysdep_tcp_write, + fsysdep_tcp_io): T. William Wells: some systems don't support + unblocked writes, so don't use them. + + * port.c (fport_read, fport_write): show calls to fport_read and + fport_write under DEBUG_PORT. + + * bnu.c (fbnu_find_port): Scott Ballantyne: accept "Any" as a + Device speed. + +Sat Mar 14 20:52:11 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h, system.h, sysh.unx, uucico.c (main, zget_typed_line), + uuxqt.c (main), uucp.c (main), uux.c (main, uxcopy_stdin), tcp.c + (ftcp_open), log.c (ulog, ulog_close), sys1.unx (ussignal), + sys2.unx (fsserial_close, fsysdep_modem_end_dial, fsserial_read, + fsserial_write, fsserial_io, fsysdep_tcp_read, fsysdep_tcp_write, + fsysdep_tcp_io): T. William Wells and Chip Salzenberg: keep an + array of signals so that a new signal doesn't obliterate our + knowledge of an old signal. Johan Vromans: if we get SIGINT + continue the current session but don't start any new ones. + + * sysh.unx, sys1.unx (isspawn, espopen, iswait, fsysdep_mail, + fsysdep_run, getcwd, mkdir), sys2.unx (fsrun_chat), sys3.unx + (fsysdep_wildcard_start), sys5.unx (fsysdep_execute), sys7.unx + (fsysdep_lock_status), uuxqt.c (uqdo_xqt_file), tcp.c (ftcp_open), + tstuu.c (uchild): added function isspawn, espopen and iswait and + channeled all execs of new processes and waits through them. + +Fri Mar 13 18:00:04 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysinf.c (uset_system_defaults): Chip Salzenberg: changed + default login script timeout to 10 seconds. + + * prot.h, prot.c (freceive_data, breceive_char), protg.c, protf.c, + prott.c, prote.c: changed breceive_char to go through + freceive_data rather than calling fport_read directly. Added an + freport argument to freceive_data, and change all old calls to + pass it in as FALSE. + +Thu Mar 12 14:49:59 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h: added a padding byte to scmd structure, since at least + one compiler needs it. + + * uucp.c (main): use fake local name (from ``myname'' command) + when generating an execution request intended for the local + system. + + * sysh.unx: corrected readdir prototype. + + * sys2.unx: moved local header files ahead of sleep routine + determination. + + * General overhaul to change debugging system. Debugging is now + done by type rather than by number. iDebug is now interpreted as + a bit sequence. DEBUG may only be 0 (no checks or debugging), 1 + (checks, no debugging) or 2 (checks and debugging). The debugging + names are parsed by idebug_parse and tidebug_parse in config.c. + The debugging types are additive. Many source files changed. + Inspired by Michael Richardson, Johan Vromans and Peter da Silva. + +Wed Mar 11 12:01:03 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, uuxqt.c (uqdo_xqt_file): Chip Salzenberg: support + Internet mail addresses in uuxqt replies (added configuration + parameter HAVE_INTERNET_MAIL to control this). + + * sys7.unx (fskill_or_rejuv): permit uucp user to delete any job. + + * uucp.h, system.h, sysh.unx, config.c, uuxqt.c (main, uqabort), + sys5.unx (isysdep_lock_uuxqt, fsysdep_unlock_uuxqt), bnu.c + (ubnu_read_sysfiles): Marty Shannon: added max-uuxqts command, + along with support for BNU Maxuuxqts, to limit number of + concurrent uuxqt processes. + + * chat.c (icexpect, fcsend), uucico.c (zget_uucp_cmd, + zget_typed_line): improved debugging by avoiding incredibly long + lines. + + * system.h, sys5.unx (fsysdep_execute), uuxqt.c (uqdo_xqt_file): + Jon Zeef: if a temporary failure occurs, retry the execution + later. + +Tue Mar 10 12:40:30 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sysh.unx, sys1.unx (isfork), sys2.unx, sys5.unx, tcp.c: + Franc,ois Pinard: retry fork several times before giving up. + + * uucp.h, prot.c (fploop, fgot_data), file.c (usendfile_error, + urecfile_error, frecfile_rewind): Niels Baggesen: if we can't read + or write a file, treat it as a temporary error rather than a + permanent error; if we get an error on write, drop the connection + rather they try to continue. + + * uucp.h, system.h, sysh.unx, uucico.c (fuucp), prot.c + (fsend_file, freceive_file), file.c (fsent_file, usendfile_error, + freceived_file, urecfile_error, fmail_transfer), sys1.unx + (usmake_spool_dir), sys4.unx (zsysdep_save_temp_file): if a file + send fails, save the file away rather than lose it forever. + + * uucico.c (main): don't run uuxqt if we got a SIGTERM. + + * tcp.c (ftcp_open): Petri Helenius: have server fork twice to + avoid zombies. + + * port.h, prtinf.c, v2.c, bnu.c (fbnu_find_port), uucico.c + (fdo_call, faccept_call), uuchk.c (fkshow_port): added protocol + command for ports, mostly to support BNU. Also modified uuchk to + make the absence of any matching port or dialer more obvious. + + * sys3.unx (esysdep_open_receive): check size of destination file + system as well as temporary file system; handle f_bsize field + under FS_MNTENT. + + * configure.in, sysh.unx: test for including and + in the same file, setting new configuration + parameter HAVE_TERMIOS_AND_SYS_IOCTL_H accordingly; handle it in + sysh.unx. + +Mon Mar 9 00:06:12 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys2.unx (fsserial_close): Franc,ois Pinard: sleep for a second + after closing the serial port to give it a chance to settle. + + * sysh.unx (fsetterminfodrain), sys2.unx (fsserial_close, + fsserial_reset, fsserial_set): wait for terminal output to drain + before closing it, resetting it, or changing its parameters. + + * uucico.c (zget_uucp_cmd): Ted Lindgreen: strip parity bit from + initial handshake strings. + + * system.h, sys3.unx (esysdep_open_send), uucico.c (fuucp): Ted + Lindgreen: don't send a mail message if a file to send has been + removed, since it might have been sent in a previous session. + + * uuchk.c (ukshow): Zacharias Beckman: put list of permitted + programs and execution path on separate lines. + + * uucico.c (fdo_call, faccept_call): only look for hangup string + in debugging mode, since there's nothing to be done with it + anyhow. + + * uucico.c (faccept_call): Ted Lindgreen: report the minimum + transfer grade requested during an incoming call in the log file. + + * uucp.h, uutime.h, config.c, uucico.c (fcall), time.c + (ftimespan_match, btimegrade, cmax_size_now): added a new status + type for ``wrong time to call''. If a system can never be called, + this status type is not used (if an attempt is made to call the + system, the status is left unchanged). + +Sun Mar 8 11:41:45 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (main, flogin_prompt, faccept_call): Ted Lindgreen: if + we were asked to call a single system, or if a single system + called in, then start uuxqt with -s for just that system. + + * uucico.c (main): Ted Lindgreen: ignore the -u option. + + * tstuu.c: Ted Lindgreen: don't include if it's not + there. Also removed the ``ignore this error'' message from the + chat scripts since it's no longer marked as an error. + + * sys2.unx (fsserial_set): Ted Lindgreen: if CRTSCTS is defined + and turned on, then don't turn on IXOFF. + + * uucp.h, log.c, uucico.c (fdo_call, faccept_call): Ted Lindgreen: + report the port name and (for incoming calls) the login name in + the log file. + +Sat Mar 7 10:00:47 1992 Ian Lance Taylor (ian@comton.airs.com) + + * port.h, prtinf.c, sys2.unx (fsserial_lockfile, fsserial_lock): + Peter da Silva: added ``lockname'' command to ports to permit + specification of the file name to use when locking. + + * sys1.unx (usysdep_detach): let setpgrp fail silently. + + * sys2.unx: always include if it's present on the + system. + + * time.c (btimegrade, cmax_size_now): removed extraneous + semicolons. + + * sys2.unx (fsserial_lock, fsserial_open, fsserial_close): support + TIOCEXCL locking. + + * sys2.unx (fsserial_open): preserve unknown bits in c_cflag when + using HAVE_SYSV_TERMIO or HAVE_POSIX_TERMIOS. + + * prot.h: never included more than once. + +Fri Mar 6 21:53:28 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h: Eric Ziegast: some systems don't define EXIT_SUCCESS or + EXIT_FAILURE in stdlib.h. + + * uucp.h, uutime.h, uucico.c (fuucp), sysinf.c (uinittimetables, + uaddtimetable), uuchk.c (main, ukshow_size, ukshow_time, + qcompress_span), time.c (all new): rewrote time routines + completely for consistency and simplicity. Fixed bug causing + incorrect maximum possible transfer size. Added new file + uutime.h. + +Wed Mar 4 10:06:13 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys2.unx (fsserial_lockfile, fsserial_lock, fsysdep_modem_open, + fsysdep_direct_open, fsysdep_modem_close, fsysdep_direct_close): + Petri Helenius: if the open failed on a serial port, the lock + files were not removed. + + * config.c (igradecmp): the local variables in igradecmp have to + be integers; signed characters might not work correctly (although + they would in all normal cases). + + * sys4.unx (fsysdep_has_work): Johan Vromans: set *pbgrade + correctly if we still have work left over that we haven't looked + at yet. + + * tstuu.c (main, uchoose, fwriteable): Roberto Biancardi: use poll + if we haven't got select. + + * uucico.c (zget_uucp_cmd): Michael Haberler: some systems send \n + after Shere, rather than a null byte. + +Tue Mar 3 01:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uuxqt.c (main, uqdo_xqt_file): permit local executions, don't + get grade out of system dependent file name. + + * sys4.unx (fsysdep_get_work): Bob Denny: warn if we can't open a + command file. + + * v2.c (uv2_read_systems): Jeff Putsch: infinite loop when reading + time string. + + * uucp.h, sys1.unx, sys2.unx, sys3.unx, tstuu.c, configure.in: + Thomas Fischer: some NeXT compatibility stuff: removed externs of + sleep and alarm, included in uucp.h. + + * uucp.h, port.h, uucico.c (zget_uucp_cmd, zget_typed_line), + port.c (cdebug_char, udebug_buffer), chat.c (icexpect, fcsend, + fcphone), log.c (ulog): Michael Richardson: added LOG_DEBUG_START, + LOG_DEBUG_CONTINUE and LOG_DEBUG_END to allow a debugging line in + the log file to be built character by character. Used this new + feature in chat script debugging, rather than having each + character appear on a separate line. Added fPort_debug variable + to control port debugging. + + * uustat.c (fsquery, fsquery_system, fsquery_show): handle + execution files queued up for the local system correctly when + using -q option (they still don't show up on any other option). + + * uucp.texi, protg.c (fgstart, fgshutdown): Aleksey P. Rudnev: + added remote-window and remote-packet-size 'g' protocol + parameters. Reset the parameters to their default values in + fgshutdown. + + * sysh.unx, sys2.unx (fsserial_read, usalarm), sys1.unx + (usset_signal, usysdep_detach), uucico.c (main): overhauled + fsserial_read yet again. The timeout passed in is now an absolute + bound. A special SIGALRM handler does some wierd stuff to avoid + any possible race. + + * config.c (uread_config), sysinf.c (uiread_systems, + fcallout_login, fcheck_login), prtinf.c (ffind_port, + fread_dialer_info), chat.c (fctranslate), uucico.c (faccept_call): + T. William Wells: when using HAVE_TAYLOR_CONFIG in combination + with V2 or BNU configuration files, don't complain if the + HAVE_TAYLOR_CONFIG files are missing. + +Mon Mar 2 10:21:36 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys2.unx (fsserial_read): T. William Wells: don't arbitrarily + extend read timeout. + + * uux.c (main): check iSignal before entering fread, since the + user may have hit ^C earlier in the program. + +Sun Mar 1 23:39:33 1992 Ian Lance Taylor (ian@comton.airs.com) + + * policy.h, uucp.h, sysh.unx, sys2.unx (fsserial_lock, + fsysdep_modem_close, fsysdep_direct_close), util.c (strlwr), + configure.in: Marc Unangst: added HAVE_SCO_LOCKFILES configuration + parameter to force lock file names to lower case. + +Fri Feb 28 00:07:12 1992 Ian Lance Taylor (ian@comton.airs.com) + + * system.h, uucico.c (faccept_call, fdo_xcmd), uuxqt.c + (uqdo_xqt_file), uux.c (main), uucp.c (main, ucspool_cmds), + sys3.unx (zsysdep_spool_cmds), uux.1, uucp.1: added -j switch to + uucp and uux to display the jobid of the spooled job. + + * uucp.h, system.h, sysh.unx, uucico.c (fuucp, fdo_xcmd, + fok_to_send, fok_to_receive), uuxqt.c (uqdo_xqt_files), uux.c + (main, uxcopy_stdin), uucp.c (main), file.c (freceived_file), + config.c (fin_directory_list), sys1.unx (fsysdep_file_exists, + fsuser_access, fsysdep_in_directory), sys3.unx (esysdep_open_send, + fsysdep_move_file), sys5.unx (fsysdep_xqt_check_file): Chip + Salzenberg: recheck file access permissions before sending, to try + to avoid symbolic link games. Check that the user has search + access on all directories down to the file, and read or write + access to the file or directory itself. Check in uucp and uux as + well as uucico, to provide early messages. Check the standard + input file in uuxqt. Be more careful about creating files in the + spool directory. This eliminates all security problems I know of, + except for a very short race in fsysdep_move_file. + + * sys3.unx (esysdep_open_send): give an error message if we try to + send a directory (used to just fail silently). + + * system.h, sysh.unx, sys1.unx (usysdep_detach, ussignal, + fsysdep_catch, usysdep_start_catch), sys2.unx + (fsysdep_modem_end_dial, fsserial_read), uux.c (main): T. William + Wells: fsysdep_catch obviously must be a macro, since it calls + setjmp. Also TIOCNOTTY sets the process group to 0, so we don't + have to fork before calling it. + +Thu Feb 27 00:08:09 1992 Ian Lance Taylor (ian@comton.airs.com) + + * sys1.unx, sys6.unx, sys7.unx: added some extern definitions. + + * configure.in, uucp.h, system.h, sysh.unx, uucico.c (main, + ucatch, uabort, zget_typed_line, zget_uucp_cmd), uuxqt.c (main, + uqcatch, uqabort), uux.c (main, uxcatch, uxrecord_file, uxabort), + uucp.c (main, uccatch, ucrecord_file, ucabort), uustat.c (main, + uscatch), uulog.c (main, ulcatch), uuname.c (main, uncatch), + uucheck.c (main, ukcatch), log.c (ulog_fatal_fn, ulog, + ulog_close), tstuu.c (main, uchild, uprepare_test), sys1.unx + (usysdep_initialize, usysdep_detach, usysdep_signal, + fsysdep_catch, usysdep_end_catch, ussignal, fsset_signal, + fsysdep_run, raise), sys2.unx (usalarm, usysdep_pause, + fsserial_lock, fsserial_open, fsysdep_stdin_close, + fsysdep_modem_close, fsysdep_modem_end_dial, fsserial_read, + fsserial_write, fsserial_io), sys5.unx (fsysdep_execute): T. + William Wells: overhaul to support detaching from the terminal and + completely reliable signals. uucico now calls usysdep_detach at + various points; new option -D prevents detaching. The signal + handling code all goes through usysdep_signal, fsysdep_catch and + usysdep_end_catch. A signal now just sets iSignal, which is + checked at various points, notably in the port routines and in the + main loops in uucico and uuxqt. + +Tue Feb 25 10:59:23 1992 Ian Lance Taylor (ian@comton.airs.com) + + * protg.c (fgwait_for_packet): Bob Denny: reset the count of + timeouts only when data is recognized, so that we aren't fooled by + a sequence of imperfect echoes. + + * sys5.unx (zsysdep_get_xqt): Bob Denny: don't warn if opendir + gets ENOENT. I think POSIX requires ENOTDIR, but what can you do? + +Mon Feb 24 14:37:10 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucico.c (main, uusage): don't treat an extra argument as a port + name. + + * sys3.unx (esysdep_truncate): Roberto Biancardi: support F_CHSIZE + and F_FREESP in esysdep_truncate. + + * configure.in, sys2.unx (fsserial_read, usysdep_pause): Roberto + Biancardi: use poll to sleep less than a second if we haven't got + anything else. + + * v2.c (uv2_read_systems, fv2_find_port), bnu.c + (ubnu_read_systems, fbnu_find_port, fbnu_read_dialer_info), + uustat.c (fsworkfile_show): Roberto Biancardi: skip spaces and + tabs after doing a strtok ((char *) NULL, ""). + + * copy.c (fcopy_file), sys1.unx (esysdep_fopen), sys2.unx, + sys3.unx (esysdep_open_receive, esysdep_truncate, fsdo_lock, + fscmd_seq), sys5.unx (fsysdep_execute), sys7.unx, tstuu.c: John + Theus: some systems use instead of . Also + changed the code to call creat instead of open when appropriate. + Should now work on V7, with the exception of O_NONBLOCK and + O_NDELAY in sys2.unx and tstuu.c. + + * uucp.h: John Theus: if we don't have vprintf, ulog is defined + without an ellipsis, so don't declare it with one. + +Sun Feb 23 14:45:53 1992 Ian Lance Taylor (ian@comton.airs.com) + + * uucp.h, system.h, bnu.c (ubnu_read_systems), config.c + (fin_directory_list), sys1.unx (fsysdep_in_directory), sys5.unx + (fsysdep_xqt_check_file), uucp.c (main), uuxqt.c (uqdo_xqt_file), + uucico.c (fdo_xcmd, fok_to_send, fok_to_receive), tstuu.c + (uprepare_test): only permit files to be received into directories + that are world writeable. Check for this in fsysdep_in_directory, + with a new argument. Changed calls appropriately. In tstuu + create /usr/tmp/tstuu as world writeable. + + * bnu.c (ubadd_perm_alternate): Doug Evans: after all that, I got + it wrong: WRITE only applies to remote requests. + + * uucp.h, uucico.c (fuucp, fdo_xcmd, fok_to_send, fok_to_receive), + uuxqt.c (uqdo_xqt_file), uuchk.c (ukshow), sysinf.c + (uset_system_defaults, tialternate), sys5.unx + (fsysdep_xqt_check_file), bnu.c (ubadd_perm_alternate): fixed READ + and WRITE handling to match BNU semantics. Added + zcalled_local_send, zcalled_local_receive, zcalled_remote_send and + zcalled_remote_receive fields to ssysteminfo structure for this, + and handled them in all the appropriate places. + +Sat Feb 22 22:30:59 1992 Ian Lance Taylor (ian@comton.airs.com) + + * Complete overhaul of configuration to use automatic shell + script. Eliminated conf.h, now generated by configure. Renamed + Makefile to Makefile.in. Added policy.h for administrative + decisions and other choices which can not be made automatically. + Many changes to many source files, none having to do with code. + +Thu Feb 20 17:57:55 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (fdo_call): Chip Salzenberg: some systems truncate the + Shere= machine name to 7 characters. + +Wed Feb 19 14:36:31 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sys7.unx (fskill_or_rejuv): make sure that only the submitter or + the superuser is permitted to cancel (or rejuvenate) a request. + + * system.h, sysh.unx, sys3.unx (zsfile_to_jobid, zsjobid_to_file), + sys4.unx (zsysdep_jobid), sys7.unx, uustat.c, Makefile, MANIFEST: + wrote uustat. Changed CSEQLEN in sys3.unx from 5 to 4. Added + several new system dependent functions, mostly in sys7.unx. + + * system.h, sys1.unx, log.c, file.c, chat.c, protg.c, uucico.c: + rearranged the time functions for the convenience of uustat. Made + isysdep_time take an optional pimicros arguments. Renamed + usysdep_full_time to isysdep_process_time, and made clear that it + need only work within a single process. Changed usysdep_localtime + to take a time returned by isysdep_time rather than always use the + current time. Changed the calls as appropriate. + +Tue Feb 18 14:03:19 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uuxqt.c (main): pass fdaemon argument correctly to + usysdep_initialize. + +Mon Feb 17 17:09:16 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uuxqt.c (uqdo_xqt_file): T. William Wells: make sure sh uses + absolute path of command, rather than relying on PATH. + + * sys5.unx (zsysdep_find_command): Michael Nolan: allow full + command name to be specified by remote system, not just basename, + if command is not in path. + + * log.c (ulog): don't use headers when outputting to terminal. + + * sys2.unx (fsrun_chat): Bob Denny: log chat program messages as + LOG_NORMAL, not LOG_ERROR. + +Fri Feb 14 00:17:57 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (ucatch), uuxqt.c (uqcatch): Neils Baggesen: under + HAVE_BNU_LOGGING, don't lose the system name when dieing. + + * uulog.c, Makefile, MANIFEST: wrote uulog. + + * uuname.c, Makefile, MANIFEST: wrote uuname. + + * bnu.c (ubadd_perm_alternate): T. William Wells: must xstrdup the + system name before calling uadd_validate. + + * log.c (ulog_close): Micheal Nolan: don't refer to eLdebug if the + DEBUG configuration parameter is 0. + + * uucp.c (main): Niels Baggesen: abtname must be copied into + memory, or it will be overwritten by the next file to be copied. + +Sun Feb 9 00:12:58 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (fuucp), prot.c (fsend_file, freceive_file): Bob Denny: + call fmail_transfer before calling fsysdep_did_work, because the + latter frees up strings used by the former. + + * sysh.unx, sys1.unx (mkdir), uudir.c (new file), Makefile: added + HAVE_MKDIR configuration parameter for systems without the mkdir + system call. The emulation function in sys1.unx invokes the new + suid program uudir which sets its uid to uucp and invokes + /bin/mkdir. Added rules to create uudir to Makefile. + +Sat Feb 8 14:25:50 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sysh.unx, sys1.unx (opendir, readdir, closedir), sys4.unx, + sys5.unx: added HAVE_OLD_DIRECTORIES configuration parameter to + support systems without opendir/readdir/closedir which use + original Unix directory format. + + * sysh.unx, sys1.unx (dup2): added HAVE_DUP2 configuration + parameter and dup2 emulation function. + + * sys1.unx (zsysdep_local_name): put utsname structure on stack + rather than making it static. + + * sysh.unx, sys1.unx (usysdep_initialize, getcwd): if we have + neither getcwd nor getwd, fork /bin/pwd to get the current working + directory. + + * system.h, uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c + (main), uuchk.c (main), sys1.unx (usysdep_initialize), sys6.unx + (fsysdep_needs_cwd, zsysdep_add_cwd): because getting the current + working directory can be expensive on Unix, since some + implementation of getcwd fork a shell to execute pwd, only try to + get the cwd if it is going to be needed by uux or uucp. + + * uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), + uuchk.c (main), log.c (ulog): handle all possible signals raised + by abort, namely SIGABRT, SIGILL and SIGIOT. In ulog always call + abort rather than raise (SIGABRT). + + * sys4.unx (usysdep_get_work_free): the qSwork_file information + was freed up incorrectly if a file transfer failed. + + * sysh.unx, sys2.unx: Archaic Zilog System III computers use + setret and longret rather than setjmp and longjmp, so I added a + HAVE_SETRET configuration option. + + * prott.c (ftstart, ftsenddata): shifts of integers by more than + 15 are not portable. + + * prot.c (fsend_file, freceive_file, fploop, fgot_data): I ran + into an old compiler which couldn't handle the calls to pffile, so + I simplified them to use a variable. + + * port.c (fmodem_dial): cast result of alloca. + + * getopt.h, getopt.c: Jay Vassos-Libove: renamed getopt and + related variables by macro defining them to gnu_*. This avoids + conflicts with system header files and system libraries. + +Fri Feb 7 12:08:42 1992 Ian Lance Taylor (ian at comton.airs.com) + + * everything: added HAVE_STRING_H and HAVE_STRINGS_H. Removed + include of in every source file and put it in uucp.h. + Since I had to change everything anyhow, added 1992 to the + copyright date. + + * uucico.c (fcall): Bob Denny: retry time not reached is not + really an error, so just make a normal log entry for it. + +Sun Feb 2 01:38:47 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uucp.c (main): Get the file name for the destination of a local + copy using zsysdep_real_file_name rather than zsysdep_in_dir, + since the latter doesn't get the basename of the argument. + + * sys3.unx (fsysdep_get_status): Niels Baggesen: cast enum to int + before comparison. + + * system.h, uucp.c (main), uux.c (main), sys6.unx (fsysdep_access, + fsysdep_daemon_access): Niels Baggesen: check user access to file + since programs are running setuid. Previously uucp and uux + permitted a file readable only by uucp to be transferred to + another system by user request! + + * chat.c (fchat): Michael Nolan: portions of a chat string might + be separated by more than just a single space if they are read + from a V2 or BNU configuration file. + +Fri Jan 31 19:51:57 1992 Ian Lance Taylor (ian at comton.airs.com) + + * protg.c: Chip Salzenberg: change default window size to 7. + + * sys3.unx (fsdo_unlock): Michael Nolan: cast result of alloca to + (char *), not that it really matters. + + * log.c (ulog): Michael Nolan: if SIGABRT is not defined, just + call abort. + +Thu Jan 30 18:19:33 1992 Ian Lance Taylor (ian at comton.airs.com) + + * bnu.c (ubadd_perm): Michael Nolan: debugging check was done + wrong for entry with LOGNAME but no MACHINE. + +Wed Jan 29 13:28:59 1992 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (zget_uucp_cmd): Patrick Smith: only wait a short time + for the hangup string. + + * sys4.unx (iswork_cmp): Patrick Smith: fixed casts to not cast + away const. + +Tue Jan 28 11:06:34 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sys1.unx, sys3.unx, tstuu.c: Jay Vassos-Libove: removed some + declarations of system functions that conflict with system header + files on BSD/386 alpha. + + * Makefile: Jeff Ross: make sure the uninstall target restores the + original file owner and mode. + + * protg.c (fgsendcmd): the previous patch wasn't really correct. + +Mon Jan 27 22:30:47 1992 Ian Lance Taylor (ian at comton.airs.com) + + * log.c (ustats): Marty Shannon: don't report a failed transfer + under USE_BNU_LOGGING. + + * sys3.unx (zsysdep_real_file_name): Marty Shannon: a trailing '/' + on the name means that it is a directory, even if the directory + does not already exist. + + * uucico.c (fuucp): Marty Shannon: the -f flag indicating that + directories should not be created was not being handled correctly. + + * uucico.c (fcall): Chip Salzenberg: set .Status correctly if + wrong time to call. + + * protg.c (fgsendcmd): John Antypas: didn't handle null byte at + end of command which was exactly a power of two in length + correctly. + +Tue Jan 21 14:37:10 1992 Ian Lance Taylor (ian at comton.airs.com) + + * Released version 1.02. + + * system.h, uucico.c (main), uux.c (main), uucp.c (main, + zcone_system), sys1.unx (fsysdep_run): Chip Salzenberg: have uucp + and uux start up uucico -s system rather than uucico -r1. + +Mon Jan 20 11:45:38 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sys1.unx (fsysdep_make_dirs): don't try to create a directory + with no name. + + * version.c: change version number to 1.02. + + * uucico.8, uuxqt.8, uucp.1, uux.1: change version number to 1.02. + + * MANIFEST: removed texinfo.tex; it's twice the size of any other + file, so I think it's just to large to distribute. + + * uucico.c (fcall, fdo_call): Marty Shannon: update the time in + the .Status file if it's the wrong time to call, and upon + receiving a call. + +Sun Jan 19 13:29:23 1992 Ian Lance Taylor (ian at comton.airs.com) + + * protg.c (fgsendcmd, fgsenddata): Dave Platt: if the remote UUCP + accepts packets larger than 64 bytes, assume it can handle + differing packet sizes, so if we have a small amount of data to + send, use a small packet. Besides the two routines mentioned, + also made minor changes to other routines to get the packet length + out of the packet data rather than always assuming the same packet + size. + + * conf.h, uucp.h: Matthew Lyle: some systems don't declare errno + in , so I added HAVE_ERRNO_DECLARATION. + + * conf.h, uucp.h, util.c (bsearch): added HAVE_BSEARCH + configuration parameter. + +Sat Jan 18 17:45:28 1992 Ian Lance Taylor (ian at comton.airs.com) + + * tstuu.c (utransfer): Mike Park: don't sleep when the input + buffer is full; it's too slow. + + * Makefile: when making a distribution,change the mode of separate + copies of the configuration files Makefile, conf.h and sysh.unx. + + * uucico.c (faccept_call): Marty Shannon: update .Status file on + incoming calls. + + * uucp.h, prot.h, uucico.c (fuucp), prot.c (fsend_file, + fpsendfile_confirm, freceive_file, fprecfile_confirm, fxcmd, + ustats_failed), file.c (fsent_file, usendfile_error, + freceived_file, urecfile_error, frecfile_rewind, fmail_transfer): + reworked calls to fsydep_did_work and sending of mail messages to + be more sensible. Now sends mail to requestor if request fails + permanently and does not remove file if request fails only + temporarily. + +Thu Jan 16 11:33:08 1992 Ian Lance Taylor (ian at comton.airs.com) + + * protg.c (fgsendcmd, fgsenddata): zero out unused bytes in short + packets. + + * prot.c (zgetcmd), protf.c (ffsendcmd), prott.c (ftsendcmd), + prote.c (fesendcmd): Niels Baggesen: added some debugging + messages. + + * protg.c (fgsendcmd): corrected misspelling in debugging message. + + * log.c (ustats): Niels Baggesen: add FAILED to end of xferstats + line if appropriate. + + * uuxqt.c (uqdo_xqt_file): Niels Baggesen: was checking strcmp + return value incorrectly, so messages to other systems were not + being sent. + + * sys2.unx, tstuu.c: Mike Park: ioctl is sometimes declared + varadic, so we can't declare it. + +Wed Jan 15 02:03:43 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sys1.unx: put \n at end of fsysdep_run error message. + + * sysh.unx, sys1.unx, sys2.unx, tstuu.c: Mike Park: on some + systems includes but can only be + included once; added HAVE_SYS_TIME_AND_TIME_H to sysh.unx. + + * tstuu.c: Mike Park: removed prototype for times since some + systems don't have clock_t. + + * conf.h, sys2.unx, util.c: Mike Park: some systems don't have + . Every macro used from it already had a check to make + sure it was defined anyhow. + + * tstuu.c (uprepare_test): Mike Park: sh on NeXT interprets a + leading ~, so we have to quote the argument to system(3). + Incredible. + + * conf.h, uucp.h: Mike Park: if HAVE_ALLOCA is 0 when compiling + with gcc, don't define alloca as a macro. This will let the NeXT + define it in some header file. + + * sysh.unx, sys2.unx, sys5.unx, tstuu.c: Mike Park: handle + HAVE_UNION_WAIT completely. Assume that system(3) returns an int + which should be put into the w_status field. Define macros for + union wait if they are not already defined. Move all this stuff + into sysh.unx rather than duplicating it in three different files. + + * conf.h, uucp.h, sysh.unx, config.c, bnu.c, v2.c, uucico.c, + uuxqt.c, uux.c, uucp.c, uuchk.c, Makefile: set directory to look + for configuration files in in Makefile rather than in sysh.unx. + This forced a number of changes, as now all new style + configuration files are looked up using NEWCONFIGLIB. Old style + configuration files are looked up using OLDCONFIGLIB. + +Mon Jan 13 00:35:43 1992 Ian Lance Taylor (ian at comton.airs.com) + + * sys3.unx: David Nugent: don't declare chmod, since it may be + prototyped to take an argument that is smaller than an int. + + * uucico.c (faccept_call): Chip Salzenberg: only declare sportinfo + if it will be used (if HAVE_TAYLOR_CONFIG is true). + + * sys3.unx (isysdep_get_sequence): Chip Salzenberg: avoid use + before set warning from gcc. + + * protf.c (ffprocess_data): Chip Salzenberg: avoid use before set + warning from gcc. + + * sysh.unx, sys2.unx (fsserial_read, usysdep_pause): Chip + Salzenberg: added HAVE_USLEEP configuration parameter for the AIX + usleep routine. + + * uuchk.c, prtinf.c, config.c: Chip Salzenberg: strcmp is a macro + on AIX, so avoid declaring it and undef it in config.c where we + want to declare it because we want to take its address. + + * uucp.h, sys3.unx (fsysdep_get_status, fsysdep_set_status): Chip + Salzenberg: handle out of range status codes in status files. + + * Makefile, sysh.unx: defined LIBDIR in the Makefile, rather than + forcing the user to define it in two different places. + + * sys.unx, tstuu.c: Chip Salzenberg: can't declare execl, since it + is varadic. + + * sys1.unx, sys2.unx, sys3.unx, sys5.unx, tstuu.c: David Nugent: + can't declare open or fcntl, since they may use ... in header file + prototype; added declaration for popen; added casts of first mkdir + argument to char *. + + * sysh.unx, tstuu.c (uchild): Mike Park: added HAVE_WAITPID and + HAVE_WAIT4 configuration parameters to allow the use of wait4 as + found on the NeXT. + + * tstuu.c (uprepare_test): Mike Park: use IPUBLIC_DIRECTORY_MODE + rather than S_IRWXU | S_IRWXG | S_IRWXO. + + * sysinf.c (tisystem): Mike Park: ulog was being passed the wrong + number of arguments. + +Sun Jan 12 14:32:47 1992 Ian Lance Taylor (ian at comton.airs.com) + + * Eliminated CONFIG, INSTALL and THANKS. They are now included in + uucp.texi. Changed README and MANIFEST accordingly. Added + uucp.info* and texinfo.tex to MANIFEST. + + * Makefile, uucp.texi: renamed taylor.texi to uucp.texi. + + * uucico.c (fcall, fdo_call): John Antypas: pass in sportinfo + structure for fdo_call to use for an unknown port. + + * log.c (ulog): allocate enough bytes to name file if + HAVE_BNU_LOGGING is in use but zLogfile has no %s. + +Sat Jan 11 12:11:56 1992 Ian Lance Taylor (ian at comton.airs.com) + + * Makefile: changed to correspond to GNU standards, according to + standards.text of 24 Nov 91. + + * Makefile: Franc,ois Pinard: use $(INSTALL_PROGRAM) and + $(INSTALL) rather than cp to install the programs. + + * time.c (ftime_now), sys1.unx (usysdep_localtime): John Antypas: + use memcpy to get the result of localtime rather than relying on + structure assignment. + + * sysh.unx, prtinf.c: Hannu Strang: changed definition of + SYSDEP_STDIN_CMDS to pass structure instead of address of + structure to avoid bug in AIX compiler which causes it to fail to + recognize an address constant containing the -> operator. + +Tue Jan 7 10:22:43 1992 Ian Lance Taylor (ian at comton.airs.com) + + * Released beta 1.02. + + * protg.c (fgcheck_errors): discount out of order packets in the + total error count, and allow a negative error count to mean that + any number of errors are accepted. + + * sysinf.c (tadd_proto_param): Niels Baggesen: allocate number of + protocol parameters based on *pc, not sIhold.cproto_params. + +Sat Jan 4 16:42:21 1992 Ian Lance Taylor (ian at comton.airs.com) + + * log.c (ulog): tweaked HAVE_V2_LOGGING slightly. + + * v2.c (uv2_read_systems): set chat script correctly. + + * uucp.h, sys3.unx: avoid redefining SEEK_SET if it appears in + but not . + + * chat.c (fcsend): made fcsend into a static function. + + * uucp.h, uucico.c, uuxqt.c, uux.c, uucp.c, uuchk.c, version.c: + changed abProgram and abVersion from const char [] to char [] + because the Microsoft compiler on SCO can't handle const char [] + arrays correctly. + + * uux.c (main): allocate enough space for log message. + + * sys1.unx (usysdep_localtime): to get the current time, we can't + call usysdep_full_time if the latter uses times. + + * sys1.unx, sys3.unx: added a couple more extern definitions for + SCO 3.2.2. + + * uucico.c (main): start uuxqt even if a call fails. + + * sysh.unx, system.h, uuxqt.c (uqdo_xqt_file), sys5.unx + (fsysdep_xqt_check_file): Chip Salzenberg: added configuration + option ALLOW_FILENAME_ARGUMENTS to permit arguments that look like + filenames, to allow undoing the patch I just made. + +Fri Jan 3 00:44:59 1992 Ian Lance Taylor (ian at comton.airs.com) + + * system.h, uuxqt.c (uqdo_xqt_file), sys5.unx + (fsysdep_xqt_check_file): David J. Fiander: make sure that if an + argument looks like a filename we are permitted to access it. + + * sys3.unx (fsdo_lock): remove temporary file if link fails in + fsdo_lock. + +Thu Jan 2 00:01:53 1992 Ian Lance Taylor (ian at comton.airs.com) + + * protg.c (fgstart, fgshutdown, fgprocess_data): count remote + rejections separately from resent packets when counting errors. + +Tue Dec 31 14:31:38 1991 Ian Lance Taylor (ian at comton.airs.com) + + * protg.c (fgstart): Franc,ois Pinard: forgot to initialize + cGdelayed_packets. + + * prot.h, uucico.c, prote.c: added the 'e' protocol, creating the + new file prote.c + + * prot.c (freceive_data), protf.c (fffile), prott.c (ftfile): + changed pffile protocol entry point to pass number of bytes being + sent; fixed bug in freceive_data which caused to ask for the wrong + number of bytes when the buffer was empty. + +Mon Dec 30 23:16:48 1991 Ian Lance Taylor (ian at comton.airs.com) + + * sys2.unx (fsserial_open): Chip Salzenberg: don't turn on IXON + and IXOFF initially; after all, the initialization packets might + contain an XOFF character. + +Sun Dec 29 00:00:42 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucp.h, prot.c (fploop): John Theus: check for EOF before + reading from file to work around bug in Tektronix library. + + * protg.c (fprocess_data): don't send RR packets when an error + occurs; the other side will probably ignore them, and it may + confuse some Telebit modems. + + * sys1.unx (usysdep_localtime): don't take the address of a cast + value. + + * log.c (zldate_and_time): wasn't allocating enough buffer space. + +Sat Dec 28 01:09:58 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uuxqt.c (uqdo_xqt_file): forgot to initialize zmail. + + * uucp.h, time.c, copy.c, sys1.unx, sys2.unx, sys3.unx, sys4.unx, + sys5.unx, config.c, log.c, uuxqt.c, uux.c, tstuu.c: added a bunch + of externs to decrease the number of implicit function + definitions. + + * system.h, sys1.unx (usysdep_localtime), log.c (zldate_and_time): + Lele Gaifax: put the full year in the log file, using the format + YYYY-MM-DD HH:MM:SS.HH (ending in hundredths of seconds). + + * config.c (uprocesscmds): Terry Gardner: allow a # to be quoted + in a configuration file. Also made uprocesscmds reentrant. + + * sysh.unx, sys2.unx (fsrun_chat), sys5.unx (fsysdep_execute), + tstuu.c (uchild): Monty Solomon: added HAVE_UNION_WAIT + configuration option to pass a variable of type union wait to the + wait and waitpid system calls. + + * sysh.unx, sys1.unx (usysdep_initialize): John Theus: added + HAVE_GETWD to use getwd instead of getcwd. + + * sysh.unx, sys1.unx (usysdep_full_time): added HAVE_FTIME + configuration option. + + * tstuu.c (uchild): use TIMES_TICK from sysh.unx rather than + CLK_TCK. + + * conf.h, uucp.h, util.c, getopt.c, tstuu.c: added HAVE_STRCHR and + HAVE_INDEX to conf.h. + +Fri Dec 27 01:00:41 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (fuucp): set fmasterdone correctly when running as a + slave. + + * port.c (cpshow, upshow, fport_read, fport_write, fport_io): + cleaned up debugging code by isolating out upshow and by making + cpshow handle backslash. + + * tstuu.c (uprepare_test): create spool directories by hand, to + make sure test 6 can be done and to test creating needed + directories. + + * conf.h, uucp.h, bnu.c, v2.c, chat.c, protg.c, prott.c, sysinf.c, + tcp.c, getopt.c, tstuu.c, util.c: added HAVE_MEMFNS and HAVE_BFNS + to conf.h. Changed memset calls to use bzero. + + * protg.c (fgcheck_errors, fgprocess_data): added protocol + parameter ``errors'' to set maximum number of errors permitted. + Also made fgprocess_data only reply once per batch of data. + +Thu Dec 26 17:54:54 1991 Ian Lance Taylor (ian at comton.airs.com) + + * tcp.c (ftcp_dial, itcp_port_number): Monty Solomon: cast + arguments to avoid prototype errors on NeXT. + +Mon Dec 23 00:16:19 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucp.h, sysinf.c, uucico.c (main, flogin_prompt, faccept_call), + uuchk.c (main): David Nugent: allow debugging level to be set for + a specific system. + +Sun Dec 22 15:51:10 1991 Ian Lance Taylor (ian at comton.airs.com) + + * conf.h, uucp.c, sysh.unx, tcp.c, sys1.unx, sys2.unx, sys3.unx, + sys5.unx, sys6.unx, tstuu.c: Monty Solomon: added HAVE_UNISTD_H to + conf.h for systems which don't have . Also added + externs for all functions from , which required adding + definitions for pid_t, uid_t and off_t to sysh.unx. + + * config.c, prtinf.c, time.c, uuchk.c: added externs for + strcasecmp or strncasecmp, to avoid implicit function definitions + now that I took the prototypes out of uucp.h. + + * sys3.unx (fsysdep_get_status): Franc,ois Pinard: the code added + to avoid scanf had a stupid bug. + + * uucp.h: Monty Solomon: removed prototypes for strcasecmp and + strncasecmp from uucp.h, since they may be in string.h. + +Sat Dec 21 16:04:58 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucp.h, uucico.c (ucatch), prot.c (fpsendfile_confirm, + fprecfile_confirm, ustats_failed), file.c (fsent_file, + freceived_file), log.c (ustats): Terry Gardner: record failed file + transfers in the statistics file. + + * uucico.c: change protocol ordering to 't', 'g', 'f'. + + * uucico.c (faccept_call), tstuu.c (uprepare_test): John Theus: + don't warn if the port file doesn't exist when the slave mode + uucico looks up the port. + + * sys1.unx, sys5.unx: moved fsysdep_file_exists from sys5.unx to + sys1.unx so that uucico can call it. + + * uux.c: Fran,cois Pinard: remove parentheses from ZSHELLSEPS so + that they may be used to quote arguments as documented. This + means that may not be used to start subshell, but that is no great + loss. + + * uux.c (main): use ulog to report illegal grade error message. + + * sys1.unx (fsysdep_run): use the real program name from abProgram + in the error messages in fsysdep_run. + +Thu Dec 19 19:02:28 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (fdo_call, faccept_call): Terry Gardner: put the length + of the conversation in the ``Call complete'' log file message. + + * uux.c: added space and tab to ZSHELLSEPS, because otherwise the + command was parsed to include whitespace. + + * protg.c, protf.c: Oleg Tabarovsky: added statistical logging + messages to the 'g' and 'f' protocols. These go to the main log + file right now, but I'm not sure if that's appropriate. + + * sys2.unx (fsserial_set): don't change terminal settings if we + don't have to. + + * port.c (fport_io): add complete diagnostics for fport_io so we + can see every byte that goes in or out. + + * uucico.c (fuucp): don't give user name in errors produced by + getting the next command. + + * uuxqt.c (main): don't process execute files for unknown systems. + This is not unreasonable, I hope, and it avoids errors caused by + an uninitialized sUnknown structure. + + * sys4.unx (fsysdep_get_work_init): sort the previously found + files all together so we can correctly check new files using + bsearch. + + * protf.c (pfprocess, pfprocess_data, pfwait): Franc,ois Pinard: + don't kill 'f' protocol because of an illegal byte. Also slightly + optimized the protocol to wait for up to seven characters at a + time rather than just one. + +Wed Dec 18 00:12:42 1991 Ian Lance Taylor (ian at comton.airs.com) + + * sysh.unx, sys2.unx, tstuu.c: Terry Gardner: added + USE_FOR_UNBLOCKED configuration parameter to support systems that + don't permit O_NONBLOCK and O_NDELAY to both be set. + + * tstuu.c (uchild): give the uucico processes a chance to die on + their own rather than killing them immediately. + + * uuxqt.c (main, uqdo_xqt_file): David Nugent: keep rescanning the + list of execute files until nothing can be done. Also, don't + remove the execute file if we get some sort of internal error. + + * sys4.unx (fsysdep_get_work, usysdep_get_work_free): David + Nugent: after we've processed all the work files we found + initially, rescan the work directory to pick up any that may have + come in in the meantime. Also, reset iSwork_file to 0 in + usysdep_get_work_free so that we can handle more than one system. + + * tstuu.c, uucico.c (main, fwait_for_calls, flogin_prompt): added + -l option to uucico to prompt for the login name and password once + and then exit. + +Tue Dec 17 00:24:41 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucp.h, uucico.c, uuxqt.c, uux.c, uucp.c, config.c + (uread_config), log.c (ulog): eliminated ulog_program and added + abProgram and ulog_to_file. Made log messages output to stderr + more Unix like. + + * log.c (ulog): use a fixed number of fields in a log file message + by replacing a missing system or user with '-'. + + * port.h, chat.c (renamed fchat_send to fcsend), bnu.c + (fbnu_read_dialer_info), prtinf.c (tpcomplete), sys2.unx + (fsysdep_modem_close), uuchk.c (ukshow_dialer): T. William Wells: + change the modem complete and abort strings into chat scripts. + + * sys2.unx (fsserial_open): on BSD start in RAW mode to avoid + dropping characters when we switch over. I originally thought + being able to use XON/XOFF was worth the risk; I no longer think + so. + + * tstuu.c (uprepare_test): have shell script sleep before printing + the login name to make sure the second system has finished + flushing its input buffer. + + * protg.c (fginit_sendbuffers), prott.c (ftsendcmd): David Nugent: + avoid sending confidential information by zeroing out memory + buffers before using them. + + * sysinf.c (tirequest, titransfer), prtinf.c (tpseven_bit, + tpreliable, tpdtr_toggle): Marc Unangst: several functions did not + accept true and false as boolean strings, contradicting the + documentation. + + * uucp.h, system.h, sysh.unx, sys1.unx (usysdep_full_time), file.c + (fstore_sendfile, fsent_file, fstore_recfile, freceived_file), + log.c (ustats): generate statistics in microseconds instead of + seconds for more accurate time keeping. + + * sys2.unx (fsserial_open): David Nugent: flush pending input + when a serial port is opened. This will clear out a + NO\sCARRIER string left by a previous dropped connection. + +Mon Dec 16 11:26:17 1991 Ian Lance Taylor (ian at comton.airs.com) + + * uucico.c (main), uuxqt.c (main), tstuu.c (main, uchild): David + Nugent: ignore SIGHUP in uucico and uuxqt, so that they are + unaffected by the parent shell closing down and by the remote + terminal dropping the connection. + + * bnu.c (ubnu_read_sysfiles, ubnu_read_systems, fbnu_find_port, + fbnu_read_dialer_info): Mike Bernson: ignore lines that begin with + whitespace, fix compilation error. + +Sat Dec 14 20:59:10 1991 Ian Lance Taylor (ian at comton.airs.com) + + * sys2.unx (fsserial_open): don't turn on ISTRIP initially. + + * uucp.h, sysinf.c, chat.c (icexpect), uuchk.c (ukshow_chat): + added chat-seven-bit command to allow control over whether + parity bits are stripped out of chat scripts. + + * uucp.h, port.h, chat.c (fchat, fcprogram), + config.c (tprocess_one_cmd), prtinf.c, + sysinf.c (tichat, tprocess_chat_cmd), + bnu.c (fbnu_read_dialer_info), port.c (fpdo_dial), + uucico.c (fdo_call, faccept_call) uuchk.c (ukshow_chat): + changed processing of chat commands to go through + tprocess_chat_cmd, avoiding repetition. All chat script + information is now held in an schat_info structure. + Eliminated the fchat_program function, renaming it fcprogram + and making it static to chat.c (it is now called via fchat). + Added CMDTABTYPE_PREFIX. Added INIT_CHAT macro to initialize + chat script information. Added TTYPE_CMDTABTYPE and + CARGS_CMDTABTYPE to eliminate hex constants in + tprocess_one_cmd. + + * sys5.unx (zsysdep_get_xqt): Oleg Tabarovsky: don't stop + processing files just because opendir failed on one; it could just + be because we don't have read permission. + +Fri Dec 13 17:43:52 1991 Ian Lance Taylor (ian at comton.airs.com) + + * config.c (uprocesscmds): don't continually allocate and free the + array of arguments. + +Thu Dec 12 12:46:01 1991 Ian Lance Taylor (ian at comton.airs.com) + + * prot.c (fgetcmd): Franc,ois Pinard: don't bother to give an + error if the final HY doesn't come in; apparently the MtXinu UUCP + doesn't send it. + + * chat.c (icexpect, fchat_send): Franc,ois Pinard: add some chat + script debugging messages. + + * log.c (ulog): David Nugent: move ERROR: from the start of the + line to after the date and time; this makes it easier to use awk + on log files. + + * sys3.unx (fsdo_lock), sys1.unx (usysdep_initialize): do locking + using link rather than O_CREAT | O_EXCL to avoid race conditions + and to safely run as the superuser. + + * sys3.unx (fsysdep_move_file): fcopyfile now creates the + destination file with IPRIVATE_MODE, so we don't need to chmod to + it. + + * sys1.unx (usysdep_initialize, fsysdep_other_config): set the + GID as well as the UID, in case anybody wants to run this as a + setgid package. + +Wed Dec 11 10:03:22 1991 Ian Lance Taylor (ian at comton.airs.com) + + * conf.h, uucp.h, util.c (strtol): Mark Powell: added my own + version of strtol to util.c, for systems which lack it. + + * protg.c (fgstart, fgexchange_init): if we start resending + packets during initialization, don't forget which packets we have + already seen; otherwise the other side may assume we've already + seen them while we're looking for them. + +Tue Dec 10 15:42:41 1991 Ian Lance Taylor (ian at comton.airs.com) + + * conf.h, sysh.unx, log.c (ulog, ustats), tstuu.c (uprepare_test): + Arne Ludwig: merged in Arne Ludwig's patches to support V2 and BNU + style logging, with some minor additions and changes. + + * sys1.unx, sys3.unx, sys5.unx, uux.c, uucp.c, uucico.c, copy.c, + uucp.h, system.h: create directories when necessary rather than + assuming that they exist. Added fmkdirs argument to esysdep_fopen + and fcopy_file, changing all calls. Added fpublic argument to + fsysdep_make_dirs, changing all calls. Moved fsysdep_make_dirs + and fsdirectory_exists from sys3.unx to sys1.unx. Added checks + for ENOENT in several places in sys3.unx and sys5.unx. + + * log.c, port.c (fport_open), sys2.unx (fsserial_open): added + ulog_device routine to record device name. This is currently only + used for the BNU statistics file, but more uses might arise later. + + * file.c, log.c, uucp.h: moved statistics file routines from + file.c to log.c in preparation for supporting BNU log file + routines. + +Mon Dec 9 12:00:52 1991 Ian Lance Taylor (ian at comton.airs.com) + + * bnu.c (ubnu_read_systems): Arne Ludwig: the device entry for a + system can be followed by a comma and a list of protocols. + + * sysh.unx, sys3.unx (fsdo_lock): Richard Todd: add + HAVE_V2_LOCKFILES, in which the process ID is written out in + binary. + + * uuxqt.c (uqdo_xqt_file): Richard Todd: the requestor address is + relative to the requesting system. + + * config.c (uprocesscmds, umulti_pushback): Richard Todd: each + line pushed back because of "#" is local to a particular + smulti_file structure. + + * prtinf.c (asPdialer_cmds): Richard Todd: exit the current dialer + if the special command "#" is seen. A similar thing should be put + in for ports, but it's marginally more complex. + + * config.c (uprocesscmds): Richard Todd: don't warn if the special + "#" command is unrecognized. + +Sat Dec 7 13:05:40 1991 Ian Lance Taylor (ian at comton.airs.com) + + * config.c (uprocesscmds): Franc,ois Pinard: don't limit the + number of arguments to a command! + + * chat.c (fchat): handle a chat script which consists only of a + single string. + +Fri Dec 6 16:11:29 1991 Ian Lance Taylor (ian at comton.airs.com) + + * sys5.unx (fsysdep_execute): David J. Fiander: if execve fails + with ENOEXEC, try using /bin/sh with a quoted argument. + + * uux.c (main): split arguments the way /bin/sh does. If any + shell metacharacters appears, request uuxqt to execute the command + using /bin/sh. + + * tstuu.c (uprepare_test): allow the uux to test to send a failure + message. + + * uuxqt.c (uqdo_xqt_file): don't send mail on successful execution + unless specifically requested; pay attention to the 'n' line + which requests mail on success; ignore the 'Z' line because it + now specifies the default action. + + * sys1.unx (usysdep_initialize), sys6.unx (zsysdep_add_cwd): + Franc,ois Pinard: getcwd may legitimately fail, so only give an + error if we really need the result. + + * chat.c (ccescape): Franc,ois Pinard: ccescape should never + return a negative number, since the callers don't know how to deal + with that. + +Mon Dec 2 16:26:16 1991 Ian Lance Taylor (ian at comton.airs.com) + + * bnu.c (ubnu_read_systems): Dave Buck: time strings with grades + were parsed in an endless loop! + + * sys3.unx (fsdo_lock, fsdo_unlock): the alloca when using LOCKDIR + was one byte too small. + + * config.c (tprocess_one_cmd): pass 10 to strtol rather than 0 to + avoid surprises if a leading zero is used. + + * prtinf.c (tpproto_param, tpdialer_proto_param): Niels Baggesen: + the ``protocol-parameter'' command didn't work for ports or + dialers. + +Sun Dec 1 09:46:12 1991 Ian Lance Taylor (ian at comton.airs.com) + + * tstuu.c: don't use the fd_set typedef at all. + + * tstuu.c (uprepare_test): don't read V2 or BNU configuration + files while testing. + + * bnu.c, v2.c, config.c (uread_config): David Nugent: even if the + code was compiled with HAVE_TAYLOR_CONFIG, read the V2 and BNU + configuration files if the code was compiled to support them. + + * uuchk.c (fkshow_port): Bob Izenberg: report dialer/token pairs + correctly. + +Sat Nov 30 17:40:00 1991 Ian Lance Taylor (ian at comton.airs.com) + + * tstuu.c: Bob Izenberg: copied over conditional definitions of + EAGAIN and EWOULDBLOCK from sys2.unx. + + * bnu.c (fbnu_read_dialer_info): Niels Baggesen: accept dialers + with no substitutions. + + * bnu.c (ubnu_read_systems, ubadd_perm): Niels Baggesen: don't + free up zline in ubadd_perm; in fact, changed the calling sequence + to not even pass zline in at all. + + * bnu.c (ubadd_perm): Niels Baggesen: didn't handle multiple + MACHINE= and multiple LOGNAME= values in a single Permissions + line, because it was clobbering the machine name while processing + the first logname. + + * bnu.c: Made zread and zwrite elements of sperm structure const + char * to avoid warning. + + * copy.c, sys1.unx, sys2.unx, sys3.unx, sys5.unx, tstuu.c: Niels + Baggesen: don't multiply include . Eventually there + should be a macro controlling whether it gets included at all, for + non-POSIX systems. + + * sys3.unx (fsysdep_get_status, isysdep_get_sequence): Marty + Shannon: accept a truncated status file. I also eliminated scanf + calls in sys3.unx, since that was the only place it was called; + this was to make the executables smaller for systems which cared. + + * bnu.c (ubnu_read_sysfiles): Marty Shannon: accept comment + characters in Sysfiles. + + * sysh.unx, sys3.unx: Marty Shannon: added HAVE_RENAME, put a fake + rename system call in sys3.unx. + + * prtinf.c (ffind_port): Marty Shannon: failed to handle multiple + ports in the port file since I forgot to reset my pointer + variable. + + * bnu.c (ubnu_read_systems): Marty Shannon: don't initialize the + auto array abpubdir, since old cc didn't permit initialization of + auto aggregates. + +Mon Nov 25 20:56:39 1991 Ian Lance Taylor (ian at comton.airs.com) + + * tstuu.c: Bob Denny: add definitions for FD_SET, FD_ZERO and + FD_ISSET. + + * config.c: Bob Denny: add explicit externs for strcmp and + strcasecmp. + + * sys2.unx: the fread_blocking and fwrite_blocking fields were + not getting initialized correctly in the TCP support routines. + + * sysh.unx, sys2.unx, sys5.unx, tstuu.c: Marty Shannon: added + configuration option HAVE_SYSWAIT_H. + + * bnu.c (fbnu_find_port, fbnu_read_dialer_info), v2.c + (fv2_find_port): Marty Shannon: the ireliable field of ports + and dialers was not getting initialized. + +Sun Nov 24 15:06:37 1991 Ian Lance Taylor (ian at comton.airs.com) + + * tcp.c (itcp_port_number): Michael Haberler: wasn't calling + htons if passed a numeric string. + +Sat Nov 23 13:43:52 1991 Ian Lance Taylor (ian at comton.airs.com) + + * Released version 1.01 to alt.sources and uunet + diff --git a/gnu/libexec/uucp/Makefile b/gnu/libexec/uucp/Makefile new file mode 100644 index 0000000000..e028f7e861 --- /dev/null +++ b/gnu/libexec/uucp/Makefile @@ -0,0 +1,8 @@ +# This is the Makefile for Taylor UUCP +# $Id: Makefile,v 1.4 1993/08/05 17:56:17 jtc Exp $ + +SUBDIR= libunix libuucp libuuconf \ + cu uuchk uucico uuconv uucp uulog uuname uupick uusched \ + uustat uuto uux uuxqt + +.include diff --git a/gnu/libexec/uucp/Makefile.inc b/gnu/libexec/uucp/Makefile.inc new file mode 100644 index 0000000000..4bdbcaafa5 --- /dev/null +++ b/gnu/libexec/uucp/Makefile.inc @@ -0,0 +1,30 @@ +.if exists(${.CURDIR}/../libunix/obj) +LIBUNIX= $(.CURDIR)/../libunix/obj/libunix.a +.else +LIBUNIX= $(.CURDIR)/../libunix/libunix.a +.endif + +.if exists(${.CURDIR}/../libuuconf/obj) +LIBUUCONF= $(.CURDIR)/../libuuconf/obj/libuuconf.a +.else +LIBUUCONF= $(.CURDIR)/../libuuconf/libuuconf.a +.endif + +.if exists(${.CURDIR}/../libuucp/obj) +LIBUUCP= $(.CURDIR)/../libuucp/obj/libuucp.a +.else +LIBUUCP= $(.CURDIR)/../libuucp/libuucp.a +.endif + +VERSION= 1.04 +owner= uucp +bindir= /usr/bin +sbindir= /usr/libexec/uucp + +# The directory to look in for new style configuration files (when +# using HAVE_TAYLOR_CONFIG). +newconfigdir= /etc/uucp + +# The directory to look in for BNU (when using HAVE_BNU_CONFIG) or +# V2 (when using HAVE_V2_CONFIG) style configuration files. +oldconfigdir= /etc/uucp diff --git a/gnu/libexec/uucp/README b/gnu/libexec/uucp/README new file mode 100644 index 0000000000..bfcd46c3f2 --- /dev/null +++ b/gnu/libexec/uucp/README @@ -0,0 +1,207 @@ +This is the README file for version 1.04 of the Taylor UUCP package. + +It was written by Ian Lance Taylor. I can be reached at ian@airs.com, +or, equivalently, uunet!cygint!airs!ian, or c/o Cygnus Support, 4th +Floor, Building 200, 1 Kendall Square, Cambridge MA, 02139, USA. + +There is a mailing list for discussion of the package. To join (or +get off) the list, send mail to taylor-uucp-request@gnu.ai.mit.edu. +Mail to this address is answered by a person, not a program. When +joining the list, make sure you include the address at which you want +to receive mail in the body of your message. To send a message to the +list, send it to taylor-uucp@gnu.ai.mit.edu. + +This package is covered by the Gnu Public License. See the file +COPYING 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 the complete source code for a Unix UUCP package. It provides +everything you need to make a UUCP connection. It includes versions +of uucico, uusched, uuxqt, uux, uucp, uustat, uulog, uuname, uuto, +uupick, and cu, as well as uuchk (a program to check configuration +files), uuconv (a program to convert from one type of configuration +file to another) and tstuu (a test harness for the package). + +The Free Software Foundation plans to make this their standard UUCP +package. + +The package currently supports the 'f', 'g' (in all window and packet +sizes), 'G', 't' and 'e' protocols, as well a Zmodem protocol and two +new bidirectional protocols. If you have a Berkeley sockets library, +it can make TCP connections. If you have TLI libraries, it can make +TLI connections. It supports a new configuration file mechanism which +I like (but other people dislike). + +The package has a few advantages over regular UUCP: + + You get the source code. + + It uses significantly less CPU time than many UUCP packages. + + You can specify a chat script to run when a system calls in, + allowing adjustment of modem parameters on a per system basis. + + You can specify failure strings for chat scripts, allowing the + chat script to fail immediately if the modem returns ``BUSY''. + + If you are talking to another instance of the package, you can use + the new bidirectional protocol for rapid data transfer in both + directions at once. You can also restrict file transfers by size + based on the time of day and who placed the call. + +On the other hand: + + It only runs on Unix. The code is carefully divided into system + dependent and system independent portions, so it should be + possible to port it to other systems. It would not be trivial. + + You don't get uuclean, uusend, uuq, uusnap, uumonitor, uutry, + uupoll, etc. If you have current copies of these programs, you + may be able to use them. Shell scripts versions of uuclean and + uutry are provided, with most, if not all, of the functionality of + the usual programs. I believe the supplied uustat program allows + you to do everything that uuq, uusnap and uumonitor do. uupoll + could be written as a shell script. + + The package does not read modemcap or acucap files, although you + can use V2 configuration files with a BNU Dialers file or a dialer + file written in my new configuration file format. + + The package cannot use SCO dialer programs directly, although it + can with a simple shell script interface. + +If you start using this package, I suggest that you join the mailing +list (see above) to keep up to date on patches and new versions. I am +also open to suggestions for improvements and modifications. + +CHANGES SINCE 1.03 + +For a complete list, see ChangeLog. + +IMPORTANT: the default when talking to another version of 1.04 is to +use the new bidirectional 'i' protocol. If you are using a +half-duplex modem, such as a Telebit T2500, you will want to either +mark the port as half-duplex with the ``half-duplex'' command, or +force use of the 'g' protocol by using the ``protocol'' command in the +sys or port file or by adding ``,g'' after the port name in the +Systems or L.sys or Devices file. + + As usual, many bugs were fixed. + + Bidirectional transfers are supported with the new 'i' protocol; + it requires an eight-bit clear datapath. + + New programs: uusched, cu, uuto and uupick. + + The 'G' protocol and a new Zmodem protocol were added. + + A number of uustat options were added to support uuclean, and a + sample uuclean shell script was added to the contrib directory. + The uustat output formats were changed slightly. + + A protocol extension eliminates transfer of the command file for + simple commands, such as rmail or rnews, when talking to another + version of 1.04. + + Some TLI support was added. + + UUCP forwarding was added, along with the ``forward-to'', + ``forward-from'' and ``forward'' commands. + + If a file transfer fails in the middle, the retry will now start + from where it left off. The implementation is compatible with + SVR4. + + The work queue is checked every 10 minutes during a conversation; + if there is new work and a bidirectional protocol is not in use, + the receiving uucico requests the sender to transfer control. + + The amount of free disk space is checked periodically as a file is + received, and if it drops too low the call is aborted. + + The UUCP configuration file reading routines were moved into a + standalone library, uuconf. All known bugs in V2 and HDB + configuration file reading were fixed. + + The ``half-duplex'' command was added for the port and dialer + files. + + The ``max-retries'', ``success-wait'', ``send-request'' and + ``receive-request'' commands were added for the sys file. The + ``call-request'' and ``called-request'' commands were eliminated + (they did not work correctly anyhow). + + \d in chat scripts now calls sleep (2) rather than sleep (1), so + it will sleep longer (on some systems sleep(1) may delay much less + than one second). + + SPOOLDIR_SVR4 was added for SVR4 style spool directories. + + Defaults are now permitted in the port and dialer files. + + The ALIAS field is supported in the HDB Permissions file. + +DOCUMENTATION + +The documentation is in the file uucp.texi, which is a Texinfo file. +Texinfo is a format used by the Free Software Foundation. You can +print the documentation using TeX in combination with the file +texinfo.tex. DVI, PostScript and info versions of the documentation +are available in a separate package, uucp-doc-1.04.tar.Z. + +See the TODO file for things which should be done. Please feel free +to do them, although you may want to check with me first. Send me +suggestions for new things to do. + +The compilation instructions are in uucp.texi. Here is a summary. + + Edit Makefile.in to set installation directories. + + Type ``sh configure''. You can pass a number of arguments in the + environment (using bash or sh, enter something like ``CC=gcc + configure''; using csh, enter something like ``setenv CC gcc; sh + configure''): + CC: C compiler to use; default is gcc if it exists, else cc + CFLAGS: Flags to pass to $CC when compiling; default -g + LDFLAGS: Flags to pass to $CC when only linking; default none + LIBS: Library arguments to pass to $CC; default none + INSTALL: Install program; default install -c or cp + INSTALLDATA: Install data; default install -c -m 0644 or cp + The configure script will compile a number of test programs to see + what is available on your system, so if your system is at all + unusual you will need to pass in $CC and $LIBS correctly. + + The configure script will create conf.h from conf.h.in and + Makefile from Makefile.in. It will also create config.status, + which is a shell script which actually creates the files. Please + report any configuration problems, so that they can be fixed in + later versions. + + Igor V. Semenyuk provided this (lightly edited) note about ISC + Unix 3.0. The configure script will default to passing -posix to + gcc. However, using -posix changes the environment to POSIX, and + on ISC 3.0, at least, the default for POSIX_NO_TRUNC is 1. This + means nothing for uucp, but can lead to a problem when uuxqt + executes rmail. IDA sendmail has dbm configuration files named + mailertable.{dir,pag}. Notice these names are 15 characters long. + When uuxqt compiled with -posix executes rmail, which in turn + executes sendmail, the later is run under POSIX environment too! + This leads to sendmail bombing out with 'error opening 'M' + database: name too long' (mailertable.dir). It's rather obscure + behaviour, and it took me a day to find out the cause. I don't + use -posix, instead I run gcc with -D_POSIX_SOURCE, and add + -lcposix to LIBS. + + Examine conf.h and Makefile to make sure they're right. + + Edit policy.h for your local system. + + Type ``make''. + + Use ``uuchk'' to check configuration files. You can use + ``uuconv'' to convert between configuration file formats. + + Type ``make install'' to install. diff --git a/gnu/libexec/uucp/TODO b/gnu/libexec/uucp/TODO new file mode 100644 index 0000000000..a1cc643ab5 --- /dev/null +++ b/gnu/libexec/uucp/TODO @@ -0,0 +1,573 @@ +This is a list of things to do for the Taylor UUCP package. Please +feel free to work on any of them. You may want to check with me first +to make sure that nobody else is working on them as well. + +Some of these are my thoughts, but most are suggestions from other +people; I have tried to give credit. They are in the order I received +them; the missing numbers have already been implemented. + +Just because something is on the list doesn't mean that I necessarily +think it is a good idea. It does mean that I think it's worth +thinking about. + +2. + +John Cowan says: + +>I think you should accept a broader range of time specifications. +>Consider using getdate() (from your handy Usenet news source code) +>with its high-powered yacc parser. + +Of course, getdate() accepts a single date, but we want a range. A +better syntax would be certainly be nice. + +9. + +Gordon Burditt warns about modifications +to the TZ environment variable, to fool uucico into dialing out at an +inappropriate time. + +10. + +Gordon Burditt says: + +>(4) Less important, because few people will have this problem, is a +>port-specific dialcodes file. Why? Well, one system I had was connected +>to 2 inside lines "dial 9 for outside line", and one outside line (which +>doesn't want the 9). A number of the systems called were "inside", so +>you didn't add the 9 on those lines dialing from inside, but you did add +>"390" to the 4-digit number if you dialed it via "outside". Also not +>unheard of are systems with 2 outside lines that are local to different +>area codes, or one local outside line and one WATS line (which MUST +>have an area code). +>Example: +> inside-line Dialcodes outside-line Dialcodes +> pbx "" pbx "390" +> local "9" local "" +> nyc "9-1212" nyc "1212" + +12. + +Ralf E. Stranzenbach says: + +>It would be nice to also have the option of running a shell script each time +>uucico connects/disconnects a systen. I do not mean shell scripts for dial/in. +>I would like to do some accounting and batching when the connection +>establishes. + +13. + +les@chinet.chi.il.us (Leslie Mikesell) writes: + +>>local-send /usr/spool/uucppublic !/usr/spool/uucpublic/private +>> +>>The directories are searched from left to right, and the last one to +>>match determines whether the file may be sent or not. This is +>>slightly more general than NOWRITE, since it permits a public +>>directory within a private directory within a public directory, +>>although probably nobody will ever want that. +> +>Interesting... The obvious enhancement is to generalize to shell-like +>wild cards for the READ/WRITE/COMMANDS entries. + +14. + +Should there be a way for chat scripts to specify the parity to +generate? I don't think there's much point to specifying what parity +to accept. + +17. + +The -b and -s switches to uux are not implemented by uuxqt. + +18. + +If we are supposed to call a system back, we should do it immediately +rather than merely queuing up an empty command file. + +22. + +Add an ftp port type which uses anonymous ftp rather than any of the +UUCP protocols to do file transfers. This would allow ftp work to be +done late at night, and allow neighbors of cooperative Internet sites +to use UUCP forwarding for anonymous FTP. + +31. + +David Nugent: add a -C option to uucico to only call the system if +there is work to do. + +32. + +It would be nice if uucico could sleep until a line was available. +This is complicated by the possibility of wanting to wait for any of +several different lines, and one would really want some sort of +semaphore function to do it right. If the available lines could be +sorted, then each could be assigned to a byte in a line lock file. +Looking for a line could be done by sleeping on a read lock on all +possible lines. Once it came through, write locks would be attempted. +If they all failed, somebody else snuck in, so you would sleep on a +read lock again. This isn't great because a process could be starved, +but it might be better than nothing. + +This could be tied in to uucp and uux, such that they wouldn't +actually fire up uucico unless a line was known to be available; an +additional switch would be used to fire up uucico anyhow (or one could +switch the default behaviour and the switch). + +So how do you sort the lines? You could just use the index in the +port (or Devices) file, but what if multiple ports used the same +physical device? Hmmm. + +43. + +David Nugent: it would be nice to be able to set debugging, log, and +statistics files on a site by site basis. +Brian Murrell: heck, set those files on a port by port basis as well. + +74. + +Yanek Martinson: allow each system to independently choose whether to +permit shell execution. + +81. + +Marty Shannon: log reason for dial failure (chat-fail string) in +.Status file. + +83. + +Switch between 'M' and 'S' correctly in the BNU log file output. + +86. + +Les Mikesell: allow a separate program to be specified to handle the +communications with a particular system. + +105. + +T. William Wells: close and open the Debug file after each file +transfer. Alternatively, cycle through a series of Debug file names +every 1000 lines or so. + +106. + +Marty Shannon: add a time command for ports, to specify when they may +be used. + +115. + +T. William Wells: new options for uustat: + -i display job ids only +Also, there should perhaps be a configuration option to request uustat +to only display jobs submitted by the user running uustat, except for +root and uucp. + +117. + +Marc Unangst: provide some way to change the debugging level of a +running uucico. T. William Wells suggests having it read a file to +change arbitrary configuration information, although obviously one has +to be careful of what gets changed while a connection is active. + +120. + +Jarmo Raiha: new chat-fail commands: one to not update the status file +and require a retry wait, and one to permit the string to occur a few +times before reporting an error. + +124. + +Peter da Silva: perhaps there should be a ``chat-end-program'' command +to let a program be run after the initial handshake has been completed +and the protocol has been selected and turned on. This would let +people run stty to change their terminal parameters. + +128. + +Richard Stallman: have an interactive program to set up a chat script. +It would let you type directly to the port, recording what you type as +send strings and recording what comes back from the other side as +expect strings. + +129. + +Use POSIX fcntl locks when possible instead of creating a lock file. + +130. + +Chip Salzenberg: BSD lets you override the timeout for a particular +expect string by using a trailing ~. + +138. + +T. William Wells: BNU apparently uses a file named A.whatever to hold +the line number reached in current C. file processing. This is a +hack, and won't work right with size control anyhow, but +fsysdep_did_work could, for example, clobber the first byte in the +line to a # or something to mark that it had been finished. Still a +hack, but a better one. + +139. + +Patrick Smith: incorporate patches to generate full debugging traces +with less debugging file overhead. The debugging file repeats too +much information at great length right now--not good. + +141. + +Franc,ois Pinard: batch up pauses and delays in chat scripts and do +them all at once in a single system call. This is particularly useful +for pauses on systems which don't support subsecond sleeps. For +everything else it's a fairly minor optimization. + +142. + +Franc,ois Pinard: give uustat an option to requeue jobs to another +system. This only makes a lot of sense for rmail executions, but it's +fairly easy to do for any type of command. I think uucico does all +the file checking needed to ensure that this doesn't break security, +but that should be double-checked. + +144. + +T. William Wells: add a -g option to uucico to permit specifying the +maximum grade to be transferred at that time. This could restrict the +timegrade command further, but should not be permitted to override it. + +145. + +T. William Wells: if uucico or uuxqt get started with bad arguments, +put an indication in the log file since stderr may be /dev/null. + +146. + +Richard Todd: it would be nice to sometimes be able to request the +other side to turn on debugging. + +147. + +Bart Schaefer: some more possible options for uucico: + -R reverse roles (hangup immediately). Not too exciting. + some method to restrict calling to particular systems. + +148. + +Jarmo Raiha: some method to control the work queue at the remote end. +This could get awfully general, though. + +149. + +The interaction of the time command and defaults can be confusing, +since any time command in the actual system entry, even a fairly +specific one, will wipe out the default entry. Not sure what can be +done about this. + +150. + +Jarmo Raiha: should there be some way to specify modem initialization +strings when uucico is hanging on a port with -l or -e? This would +presumably require a new type of chat script associated with a dialer. + +151. + +Petri Helenius: log complete CONNECT string reported by modem, so that +the baud rate is recorded in the log file. + +152. + +Marc Evans: let the protocol selection be based on the CONNECT string, +so that different protocols could be selected based on what type of +connection was made. + +153. + +Chris Lewis: provide a signal to get a core dump even on systems which +won't do core dumps if the uid is not the euid. One could catch a +signal, call setuid (getuid ()), and then raise the signal again. +Unfortunately the core dump has to wind up in a directory which is +world writable, so that the process is able to create the core file, +but is not world readable, since that would permit anybody to read the +core dump file and extract private information from it. + +154. + +Les Mikesell: write a new version of dial.o, with provisions for +running a chat script. + +155. + +Scott Blachowicz: perhaps there should be some way to telling uucico +to not log certain errors. This could get fairly complex, though. + +156. + +Franc,ois Pinard: have uustat -m report the time of the last +successful conversation when reporting a failure. + +158. + +Thomas Fischer: should there be a way to completely disable an entry +in the sys, port or dial file? Such as a ``disable'' command? + +159. + +Petri Helenius: when uuxqt -s is invoked, lock uuxqt for the system so +that only one uuxqt is invoked per system. If the -c option is used, +don't lock on a per system basis, and ignore any per system locks +(regardless of -s). If neither option is used, respect existing +system and command locks, and do any other type of file. + +161. + +Scott Blachowicz: provide some sort of include mechanism for the +configuration files. + +162. + +Chris Lewis: add uuxqtpolicy command, probably in config, supporting +the following values which determine when uuxqt should be run: + - never (let cron or something else worry about it) + - perinvocation (when uucico exits for good - current behaviour) + - persite (when uucico terminates a conversation - HDBish) + - periodic (per 5 or 10 incoming X. files - BSDish) + - perturnaround? + +163. + +Sort jobs in the send queue by size. Pretty easy. + +164. + +Ed Carp: preserve files if uuxqt execution fails. + +165. + +Marc Sheldon: use exit codes from in uux and uucp. + +166. + +Chip Salzenberg: allow chat failure strings to specify a retry time. + +167. + +Gregory Bond: allow a dialer sequence for a TCP port, so you can make +a TCP connection to a modem and then dial out. + +168. + +Jose A. Manas: allow a maximum connect time, after which we try to +hang up the connection. This requires a protocol extension, since +there's no way to force the other side to hang up. The best we can do +without an extension is refuse to send any new jobs ourselves. Of +course, we could just drop the connection. + +169. + +Franc,ois Pinard: when given uustat -k00FC, check each possible job ID +and use it if there is an unambiguous one. + +170. + +T. William Wells: if ! HAVE_SETREUID && ! HAVE_SAVED_SETUID, fork a +subprocesses to revoke setuid and read the file over a pipe. + +171. + +Provide some option to have the internal uuconf functions not start +with an underscore. + +172. + +T. William Wells: have some way to configure the parity for cu. + +173. + +Gert Doering: uuchk should display unknown system information. + +175. + +T. William Wells: +Cu will not let itself be interrupted before the connection is +established. If the chat script doesn't write something, cu does +something odd, I've forgotten exactly what. Cu takes an +inordinate amount of time after the line drops to exit. Somebody, +cu, I think, but maybe uucico, drops dtr twice sometimes. Again, +somebody will attempt to write after a hangup signal has been +received. Once a hangup has been received, I/O should not be +attempted. Among other things this will save the bacon of those +who have brain damaged serial drivers (FAS, sigh, is among them) +that don't handle output properly on a dropped line. + +Me: +Note that sometimes you do want to write to a line after receiving a +hangup signal. For example, you might want to use ATZ to reset a +modem. + +176. + +Hans-Dieter Doll: provide some way (another escape sequence) to pass +the protocol to a chat-program. Or, allow the protocol as an argument +to the chat script command, which is more general, but maybe a bit too +fancy. + +177. + +Nickolay Saukh: use a default port for cu, you can just do ``cu +number''. + +178. + +Don Phillips: should there be some way to restrict of grade of +transfers even when the other system places the call? + +179. + +Nickolay Saukh: add something to chat scripts to specify the timeout +for an expect string, e.g. AT\c OK\W3 to wait for 3 seconds. Except +that perhaps the unit should not be seconds. Berkeley apparently uses +~number, not \W number, but I don't see any reason to prevent use of +the ~ character in an expect string. + +180. + +Nickolay Saukh: if we have received a partial file, request the remote +system to start sending from that point. We currently accept SVR4 +style remote file positioning requests, but we do not generate them. + +181. + +Mark Powell: provide some way to restrict file transfer by size as +well as grade? One way would be to let uux select the grade based on +the file size. + +182. + +Mark Powell: permit using multiple timetables in a single time +statement. + +183. + +Optionally check for interrupts in fcopy_file, since it can take a +long time to copy a file named in a uucp request. + +184. + +Ian Moran: if an attempt is made to a copy a file to a directory which +denies write permission, perhaps the file should be saved somewhere. +It must be saved in a private location, though. + +185. + +A syntax error in a command received from the remote system should not +hold up the queue. Unfortunately, I don't know what can be done +except deny the command and report it. Reporting a garbled command +error should report the command correctly, rather than just the first +character. + +186. + +Franc,ois Pinard: have an option to control nostop vs. stop on the cu +command line. + +187. + +Fix the notion of %nostop to be SVID compatible. + +188. + +Frank Conrad: provide a means to set the strip mode for a port, to +make it easy to use it from cu. + +189. + +Marc Unangst: there should be a way to specify that a system should +only be called if there are jobs of a certain grade, but if the system +is called then jobs of any grade should be transferred. This +basically means splitting the ``timegrade'' command into two commands: +``place-call-timegrade'' and ``transfer-timegrade''. Or maybe another +optional argument to ``timegrade'': + timegrade grade time-string [retry] [transfer-any] +not to mention + time time-string [retry] [transfer-any] +Or maybe a separate command for a system or port like + transfer-any BOOL + +190. + +Chip Salzenberg: it would be really nice if uucico could automatically +figure out when it could use an E command, so that uux didn't have to +generate it and so that uucico could use with other versions of uux. +Unfortunately, it would require uucico to read the execution file to +see if it were suitable; this would be complex, but it would probably +be worth it since normally the execution file would wind up not being +sent. Of course, the current method works too; it's just harder to +combine with other versions of UUCP. + +191. + +Brian J. Murrell: should there be a way to cu a specific alternate? + +192. + +Andrew A. Chernov: Perhaps cu -pport system should be able to try +different alternates for the system, because there might be different +phone numbers to try. + +193. + +Brian J. Murrell: it would be nice to be able to ^C a cu chat script +if you know it's going to fail. Right now you have to use ^\. + +194. + +Steven S. Dick: have some way to force uucico off the phone at a +certain time. If that is done, it might be cool to have some way to +predict how long a file transfer will take, and not do it if it will +take too long. But, if doing file restart, you can just quit and then +pick it up later. + +195. + +Franc,ois Pinard: if the disk fills up, or some other error occurs, +while receiving a file, perhaps it would make sense to turn the +connection around immediately and see if the other side had anything +to do, and then try again later. This would require a protocol +extension. I don't know if it's worth it. The code should be checked +to see how well it handles a disk full situation. + +196. + +For real adjustability, provide some mechanism for picking the lead +characters to use for the shell scripts, between : and #!. + +197. + +Try alternate IP addresses if there are any. + +198. + +Lele Gaifax: mention the device in Stats, and provide some way to +associate the entry in Log with the entry in Stats. + +199. + +Michael Richardson: provide some way to turn on parity for the login +chat, since some systems apparently require it. Provide some way for +cu to control parity after connecting. + +200. + +Chip Salzenberg: add max-remote-debug to config. + +201. + +Gert Doering: change the timeout message in chat scripts to reflect +which chat script timed out (dialer or login). + +202. + +Bill Foote: have uuchk check whether a system is defined more than +once. + +203. diff --git a/gnu/libexec/uucp/VERSION b/gnu/libexec/uucp/VERSION new file mode 100644 index 0000000000..99fd8f0eef --- /dev/null +++ b/gnu/libexec/uucp/VERSION @@ -0,0 +1,4 @@ +Version 1.04 + +a complete, unmodified version of this program is available from +prep.ai.mit.edu. diff --git a/gnu/libexec/uucp/common_sources/chat.c b/gnu/libexec/uucp/common_sources/chat.c new file mode 100644 index 0000000000..86a68d9b94 --- /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 +#include + +#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 0000000000..431ba4d11b --- /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 /* */ +#define HAVE_STRING_H 1 /* */ +#define HAVE_STRINGS_H 1 /* */ +#define HAVE_UNISTD_H 1 /* */ +#define HAVE_STDLIB_H 1 /* */ +#define HAVE_LIMITS_H 1 /* */ +#define HAVE_TIME_H 1 /* */ +#define HAVE_SYS_WAIT_H 1 /* */ +#define HAVE_SYS_IOCTL_H 1 /* */ +#define HAVE_DIRENT_H 1 /* */ +#define HAVE_MEMORY_H 1 /* */ +#define HAVE_SYS_PARAM_H 1 /* */ +#define HAVE_UTIME_H 1 /* */ +#define HAVE_FCNTL_H 1 /* */ +#define HAVE_SYS_FILE_H 1 /* */ +#define HAVE_SYS_TIMES_H 1 /* */ +#define HAVE_LIBC_H 0 /* */ +#define HAVE_SYSEXITS_H 1 /* */ +#define HAVE_POLL_H 0 /* */ +#define HAVE_TIUSER_H 0 /* */ +#define HAVE_XTI_H 0 /* */ +#define HAVE_SYS_TLI_H 0 /* */ +#define HAVE_STROPTS_H 0 /* */ +#define HAVE_FTW_H 0 /* */ +#define HAVE_GLOB_H 1 /* */ +#define HAVE_SYS_SELECT_H 0 /* */ +#define HAVE_SYS_TYPES_TCP_H 0 /* */ + +/* If major and minor are not defined in , but are in + , set MAJOR_IN_MKDEV to 1. If they are in + , set MAJOR_IN_SYSMACROS to 1. */ +#define MAJOR_IN_MKDEV 0 +#define MAJOR_IN_SYSMACROS 0 + +/* If the macro offsetof is not defined in , 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 and 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 and + 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 . 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 . 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 . 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 . 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 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 . 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 or , 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 + 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 + . 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 or , 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 + , 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 + . 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 . */ +#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 . */ +#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 . 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 0000000000..df35e8297f --- /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 + +#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 0000000000..59d4881b07 --- /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 0000000000..6956bb3d7c --- /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 +#include + +/* 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 +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..5a514ee3bf --- /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 0000000000..1a70e02771 --- /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 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 0000000000..b55ca8b10b --- /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 + +#if ANSI_C +#include +#endif + +#if HAVE_TIME_H +#include +#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 0000000000..4c829bf42d --- /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 + , usually 100. On System V before SVR4 this is + typically the size of a clist, CLSIZE in , 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 ) 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 1 +#define HAVE_HDB_CONFIG 1 + +/* 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 0000000000..4cc224ef0f --- /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 + +#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 0000000000..4e2bb584d8 --- /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 0000000000..47675ac238 --- /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 +#define setjmp setret +#define longjmp longret +#define jmp_buf ret_buf +#else /* ! HAVE_SETRET || HAVE_SIGSETJMP */ +#include +#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 +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 +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 +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 + and in the same source files; I don't really know why. + On such systems, we pretend that we don't have . */ +#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 +#endif +#if ! USE_TYPES_H +#include +#endif +#include + +/* 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 + +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 , 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 0000000000..aa9d2a41a4 --- /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 . 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 0000000000..c38760da85 --- /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 + +#if HAVE_SYS_TYPES_TCP_H +#include +#endif +#include +#include +#include + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..6958b80b47 --- /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 + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_TIUSER_H +#include +#else +#if HAVE_XTI_H +#include +#else +#if HAVE_SYS_TLI_H +#include +#endif +#endif +#endif + +#if HAVE_STROPTS_H +#include +#endif + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..79c380ea48 --- /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 0000000000..2ddc2608dd --- /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 + +#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 0000000000..4bf6bccbf3 --- /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 + +/* 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 +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 ). */ +#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 0000000000..8df3ec4c3e --- /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 + to define sig_atomic_t. */ +#if HAVE_STDDEF_H +#include +#endif +#include +#include + +/* On some systems we need 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 +#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 +#else +/* We really need a definition for memchr, and this should not + conflict with anything in . I hope. */ +extern pointer memchr (); +#endif + +#if HAVE_STRING_H +#include +#else /* ! HAVE_STRING_H */ +#if HAVE_STRINGS_H +#include +#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 . */ +#if HAVE_STDLIB_H +#include +#else /* ! HAVE_STDLIB_H */ +extern pointer malloc (), realloc (), bsearch (); +extern long strtol (); +extern char *getenv (); +#endif /* ! HAVE_STDLIB_H */ + +/* NeXT uses to declare a bunch of functions. */ +#if HAVE_LIBC_H +#include +#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 +#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 0000000000..47d2c89896 --- /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 0000000000..32eef82d34 --- /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 0000000000..c111c00fca --- /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 0000000000..d557f97e21 --- /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 0000000000..d8c3a6643a --- /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" +# 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 0000000000..d6196cb2aa --- /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 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 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 0000000000..235fcca889 --- /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 0000000000..5e9aaa8ffe --- /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 0000000000..c4105ed038 --- /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 0000000000..2cc361ce26 --- /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 0000000000..5f93a284bd --- /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 0000000000..919b94f4ec --- /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 100644 index 0000000000..64c989f292 --- /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'. +# +# where 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 +# is never formed. The 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 100644 index 0000000000..ac1d0f556e --- /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 0000000000..dd82633c7a --- /dev/null +++ b/gnu/libexec/uucp/contrib/tstout.c @@ -0,0 +1,158 @@ +/* tstout.c + Put together by Ian Lance Taylor + + 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 +#include + +#include +#include +#include +#include +#include + +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 0000000000..e9c631c86c --- /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 100644 index 0000000000..a5d88e9522 --- /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 0000000000..ceab41c53b --- /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 /* Character Classification */ +#include +#include + +#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 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 0000000000..9f33ef3038 --- /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 0000000000..3eeb654e1e --- /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 +# 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 +# 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 () + { + ($jobid, ) = split; + ($cfile) = substr ($jobid, length ($jobid) - 5); + $cfilename = "$directory/C./C.$cfile"; + open (CFILE, $cfilename) || die "Cannot open $cfilename\n"; + $_ = ; + 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 0000000000..0f878c1e05 --- /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 +#include +#include +#include + +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 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 0000000000..8b56d0f6b4 --- /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 +# 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 0000000000..bc0cf299e9 --- /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 0000000000..8810dd78d9 --- /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 0000000000..cfb4d35966 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#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 0000000000..c980e202fc --- /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 0000000000..5b1ba03d85 --- /dev/null +++ b/gnu/libexec/uucp/cu/Makefile @@ -0,0 +1,16 @@ +# Makefile for cu +# $Id: Makefile,v 1.2 1993/08/05 16:14:45 jtc Exp $ + +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 +.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 0000000000..56409a0042 --- /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 0000000000..72d60a62ec --- /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 +#include +#include + +/* 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 0000000000..d64e799220 --- /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 0000000000..a2cb537acb --- /dev/null +++ b/gnu/libexec/uucp/libunix/Makefile @@ -0,0 +1,22 @@ +# This subdirectory contains Unix specific support functions. +# $Id: Makefile,v 1.2 1993/08/05 16:14:51 jtc Exp $ + +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 diff --git a/gnu/libexec/uucp/libunix/access.c b/gnu/libexec/uucp/libunix/access.c new file mode 100644 index 0000000000..c2c0eef210 --- /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 + +/* 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 0000000000..8597918a3c --- /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 0000000000..5c0b589385 --- /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 0000000000..a3b3787f68 --- /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 0000000000..c61fcaa8de --- /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 0000000000..568eebe030 --- /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 0000000000..cf69f3eb01 --- /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 + +/* 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 0000000000..a7aec1cae3 --- /dev/null +++ b/gnu/libexec/uucp/libunix/cohtty.c @@ -0,0 +1,244 @@ +/* Coherent tty locking support. This file was contributed by Bob + Hemedinger 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 +#include + +/* 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 0000000000..4cee888d71 --- /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 + +/* 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 0000000000..433025db6c --- /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 0000000000..41e1969b5e --- /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 + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef TIOCNOTTY +#define HAVE_TIOCNOTTY 1 +#else +#define HAVE_TIOCNOTTY 0 +#endif + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..83db496cab --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..6a7359fe92 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..7e360b6168 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..dec1b3999d --- /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 + +/* 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 0000000000..9473922f0d --- /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 0000000000..62054767b8 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..e2b40a8ad5 --- /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 +#endif +#endif + +#if STAT_STATFS2_FSIZE /* 4.4BSD. */ +#include +#endif + +#if STAT_STATFS2_FS_DATA /* Ultrix. */ +#include +#include +#endif + +#if STAT_USTAT /* SVR2 and others. */ +#include +#endif + +#if STAT_STATFS4 /* SVR3, Dynix, Irix. */ +#include +#endif +#ifdef _AIX +#ifdef _IBMR2 /* AIX RS6000. */ +#include +#endif +#endif + +#ifdef _AIX +#ifdef _I386 /* AIX PS/2. */ +#include +#include +#endif +#endif + +#if STAT_STATVFS /* SVR4. */ +#include +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 0000000000..8d4d054cb5 --- /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 0000000000..c3372b53ca --- /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 + +#if HAVE_LIMITS_H +#include +#endif + +#if HAVE_SYS_PARAM_H +#include +#endif + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include +#else /* ! HAVE_DIRENT_H */ +#include +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +#if HAVE_FTW_H +#include +#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 0000000000..d3623bd2cd --- /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 + +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 0000000000..2484ec23f8 --- /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 + +/* 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 0000000000..d4a1377628 --- /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 +#include + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#if ! HAVE_GETHOSTNAME && HAVE_UNAME +#include +#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 +#endif + +#if HAVE_LIMITS_H +#include +#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 0000000000..fc95e5275a --- /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 0000000000..f067d07552 --- /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 + +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 0000000000..d2610aa1f8 --- /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 + +#if HAVE_SYS_WAIT_H +#include +#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 0000000000..7f22f1d37d --- /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 0000000000..4ece16afe7 --- /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 0000000000..4550c76c94 --- /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 + +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 0000000000..0e05af9bce --- /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 + +#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 0000000000..c43e31dfd0 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..da5f32e2d2 --- /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 +#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 0000000000..74c1aa95ad --- /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 + +#if HAVE_TIME_H +#include +#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 0000000000..f59ad5dfd6 --- /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 + +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 0000000000..a4e0b67bb8 --- /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 + +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 0000000000..53f74ec81c --- /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 + +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 0000000000..ccfe6d4d72 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..3a8ca7a8b8 --- /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 + +#if HAVE_TIME_H +#include +#endif + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..e774e0897b --- /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 +#if HAVE_SYS_SELECT_H +#include +#endif +#endif + +#if HAVE_POLL +#if HAVE_STROPTS_H +#include +#endif +#if HAVE_POLL_H +#include +#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 +#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 0000000000..3fe5c6f585 --- /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 +#include + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include +#else /* ! HAVE_DIRENT_H */ +#include +#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 0000000000..9eda4ab012 --- /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 +#endif +#include +#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 0000000000..55cf96f0c9 --- /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 +#endif + +#if HAVE_LIMITS_H +#include +#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 +#endif + +#if HAVE_GETTIMEOFDAY +#include +#endif + +#if HAVE_FTIME +#include +#endif + +#if HAVE_TIMES + +#if HAVE_SYS_TIMES_H +#include +#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 0000000000..84a211a7a9 --- /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 + +#if HAVE_TIME_H +#include +#endif + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..b695888ffa --- /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 0000000000..0947ef5cfa --- /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 + +/* 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 0000000000..12a7b9e450 --- /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 + +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 0000000000..e219196283 --- /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 + +/* 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 0000000000..2e01233022 --- /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 + +/* 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 0000000000..2b02cd5aaa --- /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 +#include + +#if HAVE_SYS_PARAM_H +#include +#endif + +#if HAVE_LIMITS_H +#include +#endif + +#if HAVE_TLI +#if HAVE_TIUSER_H +#include +#else /* ! HAVE_TIUSER_H */ +#if HAVE_XTI_H +#include +#endif /* HAVE_XTI_H */ +#endif /* ! HAVE_TIUSER_H */ +#endif /* HAVE_TLI */ + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 +#endif + +#if HAVE_BSD_TTY +#include +#if HAVE_SYS_SELECT_H +#include +#endif +#endif + +#if HAVE_TIME_H +#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY +#include +#endif +#endif + +#if HAVE_STRIP_BUG && HAVE_BSD_TTY +#include +#endif + +#if HAVE_SVR4_LOCKFILES +/* Get the right definitions for major and minor. */ +#if MAJOR_IN_MKDEV +#include +#endif /* MAJOR_IN_MKDEV */ +#if MAJOR_IN_SYSMACROS +#include +#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 0000000000..33e24a7245 --- /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 + +/* 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 0000000000..d987508189 --- /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 0000000000..8d021db3cd --- /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 + +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 0000000000..b232f9674f --- /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 0000000000..7ab080d1a9 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..9f6616a36d --- /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 +#include + +/* 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 0000000000..06ce3605ce --- /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 0000000000..f28229fe4e --- /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 0000000000..28487ef309 --- /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 + +#if HAVE_FTW_H +#include +#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 0000000000..79a14c0e64 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 +#else /* ! HAVE_DIRENT_H */ +#include +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +#if HAVE_TIME_H +#include +#endif + +#if HAVE_UTIME_H +#include +#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 0000000000..f403068a70 --- /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 + +#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 0000000000..d2a6c2128d --- /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 + +#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 0000000000..d0462433a7 --- /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 +#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 0000000000..2dac002438 --- /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 0000000000..c93e82e394 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..c92c78eae3 --- /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 +#include + +#if HAVE_GETGRENT +#include +#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 0000000000..5a7b6f22b0 --- /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 + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 0000000000..34921d2280 --- /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 0000000000..76f5345947 --- /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 + +/* 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 0000000000..debba9d6fd --- /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 0000000000..ab96123127 --- /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 +#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 0000000000..cfbd15eb84 --- /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 +#include + +#if HAVE_GLOB && ! HAVE_GLOB_H +#undef HAVE_GLOB +#define HAVE_GLOB 0 +#endif + +#if HAVE_GLOB +#include +#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 0000000000..3d055c282e --- /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 +#include + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include +#else /* ! HAVE_DIRENT_H */ +#include +#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 0000000000..2cdcc185a0 --- /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 + +#if HAVE_OPENDIR +#if HAVE_DIRENT_H +#include +#else /* ! HAVE_DIRENT_H */ +#include +#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 0000000000..53e290a0d1 --- /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 +#include + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#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 +#else /* ! HAVE_DIRENT_H */ +#include +#define dirent direct +#endif /* ! HAVE_DIRENT_H */ +#endif /* HAVE_OPENDIR */ + +/* Get a value for EX_TEMPFAIL. */ + +#if HAVE_SYSEXITS_H +#include +#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 0000000000..eb685a5ec9 --- /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. + + + Copyright (C) + + 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. + + , 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 0000000000..8d1eb36466 --- /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 0000000000..066e928aaf --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/Makefile @@ -0,0 +1,26 @@ +# This is the Makefile for the Taylor UUCP uuconf library +# $Id: Makefile,v 1.2 1993/08/05 16:14:55 jtc Exp $ + +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 diff --git a/gnu/libexec/uucp/libuuconf/README b/gnu/libexec/uucp/libuuconf/README new file mode 100644 index 0000000000..64a5eecf03 --- /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 0000000000..6244dad875 --- /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 0000000000..8498d502c9 --- /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 + +/* 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 0000000000..b3dd7e0a76 --- /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 0000000000..2808c62088 --- /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 0000000000..c5c9cad8e3 --- /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 0000000000..c40f660523 --- /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; + } +} diff --git a/gnu/libexec/uucp/libuuconf/bool.c b/gnu/libexec/uucp/libuuconf/bool.c new file mode 100644 index 0000000000..c1bbde1326 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/bool.c @@ -0,0 +1,64 @@ +/* bool.c + Parse a boolean string into a variable. + + 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_bool_rcsid[] = "$Id: bool.c,v 1.1 1993/08/04 19:33:40 jtc Exp $"; +#endif + +/* Parse a boolean string into a variable. This is called by + uuconf_cmd_args, as well as other functions. The parsing is done + in a single place to make it easy to change. This should return an + error code, including both UUCONF_CMDTABRET_KEEP and + UUCONF_CMDTABRET_EXIT if appropriate. */ + +/*ARGSIGNORED*/ +int +_uuconf_iboolean (qglobal, zval, pi) + struct sglobal *qglobal; + const char *zval; + boolean *pi; +{ + switch (*zval) + { + case 'y': + case 'Y': + case 't': + case 'T': + *pi = TRUE; + break; + case 'n': + case 'N': + case 'f': + case 'F': + *pi = FALSE; + break; + default: + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + } + + return UUCONF_CMDTABRET_CONTINUE; +} diff --git a/gnu/libexec/uucp/libuuconf/callin.c b/gnu/libexec/uucp/libuuconf/callin.c new file mode 100644 index 0000000000..4df26ddfdd --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/callin.c @@ -0,0 +1,142 @@ +/* callin.c + Check a login name and password against the UUCP password file. + + 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_callin_rcsid[] = "$Id: callin.c,v 1.1 1993/08/04 19:33:42 jtc Exp $"; +#endif + +#include + +static int iplogin P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* Check a login name and password against the UUCP password file. + This looks at the Taylor UUCP password file, but will work even if + uuconf_taylor_init was not called. */ + +int +uuconf_callin (pglobal, zlogin, zpassword) + pointer pglobal; + const char *zlogin; + const char *zpassword; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + char **pz; + struct uuconf_cmdtab as[2]; + char *zfilepass; + + /* If we have no password file names, fill in the default name. */ + if (qglobal->qprocess->pzpwdfiles == NULL) + { + char ab[sizeof NEWCONFIGLIB + sizeof PASSWDFILE - 1]; + + memcpy ((pointer) ab, (pointer) NEWCONFIGLIB, + sizeof NEWCONFIGLIB - 1); + memcpy ((pointer) (ab + sizeof NEWCONFIGLIB - 1), (pointer) PASSWDFILE, + sizeof PASSWDFILE); + iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, + &qglobal->qprocess->pzpwdfiles, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + + as[0].uuconf_zcmd = zlogin; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; + as[0].uuconf_pvar = (pointer) &zfilepass; + as[0].uuconf_pifn = iplogin; + + as[1].uuconf_zcmd = NULL; + + zfilepass = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzpwdfiles; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, + (uuconf_cmdtabfn) NULL, + UUCONF_CMDTABFLAG_CASE, (pointer) NULL); + (void) fclose (e); + + if (iret != UUCONF_SUCCESS || zfilepass != NULL) + break; + } + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME; + } + else if (zfilepass == NULL + || strcmp (zfilepass, zpassword) != 0) + iret = UUCONF_NOT_FOUND; + + if (zfilepass != NULL) + free ((pointer) zfilepass); + + return iret; +} + +/* This is called if it is the name we are looking for. The pvar + argument points to zfilepass, and we set it to the password. */ + +static int +iplogin (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pzpass = (char **) pvar; + + *pzpass = strdup (argv[1]); + if (*pzpass == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + return UUCONF_CMDTABRET_EXIT; +} diff --git a/gnu/libexec/uucp/libuuconf/calout.c b/gnu/libexec/uucp/libuuconf/calout.c new file mode 100644 index 0000000000..957833ebc3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/calout.c @@ -0,0 +1,93 @@ +/* calout.c + Find callout login name and password for a system. + + 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_calout_rcsid[] = "$Id: calout.c,v 1.1 1993/08/04 19:33:45 jtc Exp $"; +#endif + +#include + +/* Find callout login name and password for a system. */ + +/*ARGSUSED*/ +int +uuconf_callout (pglobal, qsys, pzlog, pzpass) + pointer pglobal; + const struct uuconf_system *qsys; + char **pzlog; + char **pzpass; +{ +#if HAVE_TAYLOR_CONFIG + + return uuconf_taylor_callout (pglobal, qsys, pzlog, pzpass); + +#else /* ! HAVE_TAYLOR_CONFIG */ + + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzlog = NULL; + *pzpass = NULL; + + if (qsys->uuconf_zcall_login == NULL + && qsys->uuconf_zcall_password == NULL) + return UUCONF_NOT_FOUND; + + if ((qsys->uuconf_zcall_login != NULL + && strcmp (qsys->uuconf_zcall_login, "*") == 0) + || (qsys->uuconf_zcall_password != NULL + && strcmp (qsys->uuconf_zcall_password, "*") == 0)) + return UUCONF_NOT_FOUND; + + if (qsys->uuconf_zcall_login != NULL) + { + *pzlog = strdup (qsys->uuconf_zcall_login); + if (*pzlog == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + } + + if (qsys->uuconf_zcall_password != NULL) + { + *pzpass = strdup (qsys->uuconf_zcall_password); + if (*pzpass == NULL) + { + qglobal->ierrno = errno; + if (*pzlog != NULL) + { + free ((pointer) *pzlog); + *pzlog = NULL; + } + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + } + + return UUCONF_SUCCESS; + +#endif /* ! HAVE_TAYLOR_CONFIG */ +} diff --git a/gnu/libexec/uucp/libuuconf/chatc.c b/gnu/libexec/uucp/libuuconf/chatc.c new file mode 100644 index 0000000000..f29481b59a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/chatc.c @@ -0,0 +1,202 @@ +/* chatc.c + Subroutines to handle chat script commands. + + 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_chatc_rcsid[] = "$Id: chatc.c,v 1.1 1993/08/04 19:33:48 jtc Exp $"; +#endif + +#include +#include + +static int icchat P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int icchat_fail P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int icunknown P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* The chat script commands. */ + +static const struct cmdtab_offset asChat_cmds[] = +{ + { "chat", UUCONF_CMDTABTYPE_FN, + offsetof (struct uuconf_chat, uuconf_pzchat), icchat }, + { "chat-program", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_chat, uuconf_pzprogram), NULL }, + { "chat-timeout", UUCONF_CMDTABTYPE_INT, + offsetof (struct uuconf_chat, uuconf_ctimeout), NULL }, + { "chat-fail", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_chat, uuconf_pzfail), icchat_fail }, + { "chat-seven-bit", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_chat, uuconf_fstrip), NULL }, + { NULL, 0, 0, NULL } +}; + +#define CCHAT_CMDS (sizeof asChat_cmds / sizeof asChat_cmds[0]) + +/* Handle a chat script command. The chat script commands are entered + as UUCONF_CMDTABTYPE_PREFIX, and the commands are routed to this + function. We copy the command table onto the stack and repoint it + at qchat in order to make the function reentrant. The return value + can include UUCONF_CMDTABRET_KEEP, but should not include + UUCONF_CMDTABRET_EXIT. */ + +int +_uuconf_ichat_cmd (qglobal, argc, argv, qchat, pblock) + struct sglobal *qglobal; + int argc; + char **argv; + struct uuconf_chat *qchat; + pointer pblock; +{ + char *zchat; + struct uuconf_cmdtab as[CCHAT_CMDS]; + int iret; + + /* This is only invoked when argv[0] will contain the string "chat"; + the specific chat script command comes after that point. */ + for (zchat = argv[0]; *zchat != '\0'; zchat++) + if ((*zchat == 'c' || *zchat == 'C') + && strncasecmp (zchat, "chat", sizeof "chat" - 1) == 0) + break; + if (*zchat == '\0') + return UUCONF_SYNTAX_ERROR; + argv[0] = zchat; + + _uuconf_ucmdtab_base (asChat_cmds, CCHAT_CMDS, (char *) qchat, as); + + iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, pblock, + icunknown, 0, pblock); + return iret &~ UUCONF_CMDTABRET_EXIT; +} + +/* Handle the "chat" command. This breaks up substrings in expect + strings, and sticks the arguments into a NULL terminated array. */ + +static int +icchat (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char ***ppz = (char ***) pvar; + pointer pblock = pinfo; + int i; + + *ppz = NULL; + + for (i = 1; i < argc; i += 2) + { + char *z, *zdash; + int iret; + + /* Break the expect string into substrings. */ + z = argv[i]; + zdash = strchr (z, '-'); + while (zdash != NULL) + { + *zdash = '\0'; + iret = _uuconf_iadd_string (qglobal, z, TRUE, FALSE, ppz, + pblock); + if (iret != UUCONF_SUCCESS) + return iret; + *zdash = '-'; + z = zdash; + zdash = strchr (z + 1, '-'); + } + + iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz, pblock); + if (iret != UUCONF_SUCCESS) + return iret; + + /* Add the send string without breaking it up. If it starts + with a dash we must replace it with an escape sequence, to + prevent it from being interpreted as a subsend. */ + + if (i + 1 < argc) + { + if (argv[i + 1][0] != '-') + iret = _uuconf_iadd_string (qglobal, argv[i + 1], FALSE, + FALSE, ppz, pblock); + else + { + size_t clen; + + clen = strlen (argv[i + 1]); + z = uuconf_malloc (pblock, clen + 2); + if (z == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + z[0] = '\\'; + memcpy ((pointer) (z + 1), (pointer) argv[i + 1], clen + 1); + iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz, + pblock); + } + if (iret != UUCONF_SUCCESS) + return iret; + } + } + + return UUCONF_CMDTABRET_KEEP; +} + +/* Add a new chat failure string. */ + +/*ARGSUSED*/ +static int +icchat_fail (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char ***ppz = (char ***) pvar; + pointer pblock = pinfo; + + return _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, ppz, pblock); +} + +/* Return a syntax error for an unknown command. */ + +/*ARGSUSED*/ +static int +icunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_SYNTAX_ERROR; +} diff --git a/gnu/libexec/uucp/libuuconf/cmdarg.c b/gnu/libexec/uucp/libuuconf/cmdarg.c new file mode 100644 index 0000000000..2020ea91a9 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/cmdarg.c @@ -0,0 +1,185 @@ +/* cmdarg.c + Look up a command with arguments in a command 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_cmdarg_rcsid[] = "$Id: cmdarg.c,v 1.1 1993/08/04 19:33:50 jtc Exp $"; +#endif + +#include + +#undef strcmp +#if HAVE_STRCASECMP +#undef strcasecmp +#endif +extern int strcmp (), strcasecmp (); + +/* Look up a command with arguments in a table and execute it. */ + +int +uuconf_cmd_args (pglobal, cargs, pzargs, qtab, pinfo, pfiunknown, iflags, + pblock) + pointer pglobal; + int cargs; + char **pzargs; + const struct uuconf_cmdtab *qtab; + pointer pinfo; + int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); + int iflags; + pointer pblock; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int bfirstu, bfirstl; + int (*pficmp) P((const char *, const char *)); + register const struct uuconf_cmdtab *q; + int itype; + int callowed; + + bfirstu = bfirstl = pzargs[0][0]; + if ((iflags & UUCONF_CMDTABFLAG_CASE) != 0) + pficmp = strcmp; + else + { + if (islower (bfirstu)) + bfirstu = toupper (bfirstu); + if (isupper (bfirstl)) + bfirstl = tolower (bfirstl); + pficmp = strcasecmp; + } + + itype = 0; + + for (q = qtab; q->uuconf_zcmd != NULL; q++) + { + int bfirst; + + bfirst = q->uuconf_zcmd[0]; + if (bfirst != bfirstu && bfirst != bfirstl) + continue; + + itype = UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype); + if (itype != UUCONF_CMDTABTYPE_PREFIX) + { + if ((*pficmp) (q->uuconf_zcmd, pzargs[0]) == 0) + break; + } + else + { + size_t clen; + + clen = strlen (q->uuconf_zcmd); + if ((iflags & UUCONF_CMDTABFLAG_CASE) != 0) + { + if (strncmp (q->uuconf_zcmd, pzargs[0], clen) == 0) + break; + } + else + { + if (strncasecmp (q->uuconf_zcmd, pzargs[0], clen) == 0) + break; + } + } + } + + if (q->uuconf_zcmd == NULL) + { + if (pfiunknown == NULL) + return UUCONF_CMDTABRET_CONTINUE; + return (*pfiunknown) (pglobal, cargs, pzargs, (pointer) NULL, pinfo); + } + + callowed = UUCONF_CARGS_CMDTABTYPE (q->uuconf_itype); + if (callowed != 0 && callowed != cargs) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + switch (itype) + { + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING): + if (cargs == 1) + *(char **) q->uuconf_pvar = (char *) ""; + else if (cargs == 2) + *(char **) q->uuconf_pvar = pzargs[1]; + else + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + return UUCONF_CMDTABRET_KEEP; + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT): + return _uuconf_iint (qglobal, pzargs[1], q->uuconf_pvar, TRUE); + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG): + return _uuconf_iint (qglobal, pzargs[1], q->uuconf_pvar, FALSE); + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN): + return _uuconf_iboolean (qglobal, pzargs[1], (int *) q->uuconf_pvar); + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING): + if (cargs == 1) + { + char ***ppz = (char ***) q->uuconf_pvar; + int iret; + + *ppz = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppz, pblock); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_EXIT; + + return UUCONF_CMDTABRET_CONTINUE; + } + else + { + char ***ppz = (char ***) q->uuconf_pvar; + int i; + + *ppz = NULL; + for (i = 1; i < cargs; i++) + { + int iret; + + iret = _uuconf_iadd_string (qglobal, pzargs[i], FALSE, FALSE, + ppz, pblock); + if (iret != UUCONF_SUCCESS) + { + *ppz = NULL; + return iret | UUCONF_CMDTABRET_EXIT; + } + } + + return UUCONF_CMDTABRET_KEEP; + } + + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FN): + case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_PREFIX): + return (*q->uuconf_pifn) (pglobal, cargs, pzargs, q->uuconf_pvar, + pinfo); + + default: + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + } + + /*NOTREACHED*/ +} diff --git a/gnu/libexec/uucp/libuuconf/cmdfil.c b/gnu/libexec/uucp/libuuconf/cmdfil.c new file mode 100644 index 0000000000..333a4bf376 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/cmdfil.c @@ -0,0 +1,103 @@ +/* cmdfil.c + Read and parse commands from a file. + + 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_cmdfil_rcsid[] = "$Id: cmdfil.c,v 1.1 1993/08/04 19:33:51 jtc Exp $"; +#endif + +#include + +/* Read and parse commands from a file, updating uuconf_lineno as + appropriate. */ + +int +uuconf_cmd_file (pglobal, e, qtab, pinfo, pfiunknown, iflags, pblock) + pointer pglobal; + FILE *e; + const struct uuconf_cmdtab *qtab; + pointer pinfo; + int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); + int iflags; + pointer pblock; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + boolean fcont; + char *zline; + size_t cline; + int iret; + + fcont = (iflags & UUCONF_CMDTABFLAG_BACKSLASH) != 0; + + zline = NULL; + cline = 0; + + iret = UUCONF_SUCCESS; + + qglobal->ilineno = 0; + + while ((fcont + ? _uuconf_getline (qglobal, &zline, &cline, e) + : getline (&zline, &cline, e)) > 0) + { + ++qglobal->ilineno; + + iret = uuconf_cmd_line (pglobal, zline, qtab, pinfo, pfiunknown, + iflags, pblock); + + if ((iret & UUCONF_CMDTABRET_KEEP) != 0) + { + iret &=~ UUCONF_CMDTABRET_KEEP; + + if (pblock != NULL) + { + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + iret = (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_LINENO); + break; + } + } + + zline = NULL; + cline = 0; + } + + if ((iret & UUCONF_CMDTABRET_EXIT) != 0) + { + iret &=~ UUCONF_CMDTABRET_EXIT; + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_ERROR_LINENO; + break; + } + + iret = UUCONF_SUCCESS; + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/cmdlin.c b/gnu/libexec/uucp/libuuconf/cmdlin.c new file mode 100644 index 0000000000..63e9564673 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/cmdlin.c @@ -0,0 +1,142 @@ +/* cmdlin.c + Parse a command line. + + 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_cmdlin_rcsid[] = "$Id: cmdlin.c,v 1.1 1993/08/04 19:33:52 jtc Exp $"; +#endif + +#include +#include + +/* Parse a command line into fields and process it via a command + table. The command table functions may keep the memory allocated + for the line, but they may not keep the memory allocated for the + argv list. This function strips # comments. */ + +#define CSTACK (16) + +int +uuconf_cmd_line (pglobal, zline, qtab, pinfo, pfiunknown, iflags, pblock) + pointer pglobal; + char *zline; + const struct uuconf_cmdtab *qtab; + pointer pinfo; + int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); + int iflags; + pointer pblock; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char *z; + int cargs; + char *azargs[CSTACK]; + char **pzargs; + int iret; + + /* Any # not preceeded by a backslash starts a comment. */ + z = zline; + while ((z = strchr (z, '#')) != NULL) + { + if (z == zline || *(z - 1) != '\\') + { + *z = '\0'; + break; + } + /* Remove the backslash. */ + while ((*(z - 1) = *z) != '\0') + ++z; + } + + /* Parse the first CSTACK arguments by hand to avoid malloc. */ + + z = zline; + cargs = 0; + pzargs = azargs; + while (TRUE) + { + while (*z != '\0' && isspace (BUCHAR (*z))) + ++z; + + if (*z == '\0') + break; + + if (cargs >= CSTACK) + { + char **pzsplit; + size_t csplit; + int cmore; + + pzsplit = NULL; + csplit = 0; + cmore = _uuconf_istrsplit (z, '\0', &pzsplit, &csplit); + if (cmore < 0) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + pzargs = (char **) malloc ((cmore + CSTACK) * sizeof (char *)); + if (pzargs == NULL) + { + qglobal->ierrno = errno; + free ((pointer) pzsplit); + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + memcpy ((pointer) pzargs, (pointer) azargs, + CSTACK * sizeof (char *)); + memcpy ((pointer) (pzargs + CSTACK), (pointer) pzsplit, + cmore * sizeof (char *)); + cargs = cmore + CSTACK; + + free ((pointer) pzsplit); + + break; + } + + azargs[cargs] = z; + ++cargs; + + while (*z != '\0' && ! isspace (BUCHAR (*z))) + z++; + + if (*z == '\0') + break; + + *z++ = '\0'; + } + + if (cargs <= 0) + return UUCONF_CMDTABRET_CONTINUE; + + iret = uuconf_cmd_args (pglobal, cargs, pzargs, qtab, pinfo, pfiunknown, + iflags, pblock); + + if (pzargs != azargs) + free ((pointer) pzargs); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/debfil.c b/gnu/libexec/uucp/libuuconf/debfil.c new file mode 100644 index 0000000000..3be5381e5d --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/debfil.c @@ -0,0 +1,43 @@ +/* debfil.c + Get the name of the UUCP debugging file. + + 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_debfil_rcsid[] = "$Id: debfil.c,v 1.1 1993/08/04 19:33:53 jtc Exp $"; +#endif + +/* Get the name of the UUCP debugging file. */ + +int +uuconf_debugfile (pglobal, pzdebug) + pointer pglobal; + const char **pzdebug; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzdebug = qglobal->qprocess->zdebugfile; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/deblev.c b/gnu/libexec/uucp/libuuconf/deblev.c new file mode 100644 index 0000000000..40cf763b10 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/deblev.c @@ -0,0 +1,43 @@ +/* deblev.c + Get the UUCP debugging level. + + 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_deblev_rcsid[] = "$Id: deblev.c,v 1.1 1993/08/04 19:33:54 jtc Exp $"; +#endif + +/* Get the UUCP debugging level. */ + +int +uuconf_debuglevel (pglobal, pzdebug) + pointer pglobal; + const char **pzdebug; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzdebug = qglobal->qprocess->zdebug; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/diacod.c b/gnu/libexec/uucp/libuuconf/diacod.c new file mode 100644 index 0000000000..823239d953 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/diacod.c @@ -0,0 +1,129 @@ +/* diacod.c + Translate a dialcode. + + 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_diacod_rcsid[] = "$Id: diacod.c,v 1.1 1993/08/04 19:33:55 jtc Exp $"; +#endif + +#include + +static int idcode P((pointer pglobal, int argc, char **argv, + pointer pinfo, pointer pvar)); + +/* Get the name of the UUCP log file. */ + +int +uuconf_dialcode (pglobal, zdial, pznum) + pointer pglobal; + const char *zdial; + char **pznum; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_cmdtab as[2]; + char **pz; + int iret; + + as[0].uuconf_zcmd = zdial; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 0; + as[0].uuconf_pvar = (pointer) pznum; + as[0].uuconf_pifn = idcode; + + as[1].uuconf_zcmd = NULL; + + *pznum = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzdialcodefiles; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, + (uuconf_cmdtabfn) NULL, 0, (pointer) NULL); + (void) fclose (e); + + if (iret != UUCONF_SUCCESS || *pznum != NULL) + break; + } + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME; + } + else if (*pznum == NULL) + iret = UUCONF_NOT_FOUND; + + return iret; +} + +/* This is called if the dialcode is found. It copies the number into + the heap and gets out of reading the file. */ + +/*ARGSUSED*/ +static int +idcode (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pznum = (char **) pvar; + + if (argc == 1) + { + *pznum = malloc (1); + if (*pznum != NULL) + **pznum = '\0'; + } + else if (argc == 2) + *pznum = strdup (argv[1]); + else + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (*pznum == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + return UUCONF_CMDTABRET_EXIT; +} diff --git a/gnu/libexec/uucp/libuuconf/dial.c b/gnu/libexec/uucp/libuuconf/dial.c new file mode 100644 index 0000000000..efdef538c3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/dial.c @@ -0,0 +1,61 @@ +/* dial.c + Find a dialer. + + 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_dial_rcsid[] = "$Id: dial.c,v 1.1 1993/08/04 19:33:57 jtc Exp $"; +#endif + +/* Find a dialer by name. */ + +int +uuconf_dialer_info (pglobal, zdialer, qdialer) + pointer pglobal; + const char *zdialer; + struct uuconf_dialer *qdialer; +{ +#if HAVE_HDB_CONFIG + struct sglobal *qglobal = (struct sglobal *) pglobal; +#endif + int iret; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_dialer_info (pglobal, zdialer, qdialer); + if (iret != UUCONF_NOT_FOUND) + return iret; +#endif + +#if HAVE_HDB_CONFIG + if (qglobal->qprocess->fhdb) + { + iret = uuconf_hdb_dialer_info (pglobal, zdialer, qdialer); + if (iret != UUCONF_NOT_FOUND) + return iret; + } +#endif + + return UUCONF_NOT_FOUND; +} diff --git a/gnu/libexec/uucp/libuuconf/diasub.c b/gnu/libexec/uucp/libuuconf/diasub.c new file mode 100644 index 0000000000..7979d0ebd2 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/diasub.c @@ -0,0 +1,63 @@ +/* diasub.c + Dialer information subroutines. + + 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_diasub_rcsid[] = "$Id: diasub.c,v 1.1 1993/08/04 19:33:58 jtc Exp $"; +#endif + +/* Clear the information in a dialer. */ + +#define INIT_CHAT(q) \ + ((q)->uuconf_pzchat = NULL, \ + (q)->uuconf_pzprogram = NULL, \ + (q)->uuconf_ctimeout = 60, \ + (q)->uuconf_pzfail = NULL, \ + (q)->uuconf_fstrip = TRUE) + +void +_uuconf_uclear_dialer (qdialer) + struct uuconf_dialer *qdialer; +{ + qdialer->uuconf_zname = NULL; + INIT_CHAT (&qdialer->uuconf_schat); + qdialer->uuconf_zdialtone = (char *) ","; + qdialer->uuconf_zpause = (char *) ","; + qdialer->uuconf_fcarrier = TRUE; + qdialer->uuconf_ccarrier_wait = 60; + qdialer->uuconf_fdtr_toggle = FALSE; + qdialer->uuconf_fdtr_toggle_wait = FALSE; + INIT_CHAT (&qdialer->uuconf_scomplete); + INIT_CHAT (&qdialer->uuconf_sabort); + qdialer->uuconf_qproto_params = NULL; + /* Note that we do not set RELIABLE_SPECIFIED; this just sets + defaults, so that ``seven-bit true'' does not imply ``reliable + false''. */ + qdialer->uuconf_ireliable = (UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX); + qdialer->uuconf_palloc = NULL; +} diff --git a/gnu/libexec/uucp/libuuconf/dnams.c b/gnu/libexec/uucp/libuuconf/dnams.c new file mode 100644 index 0000000000..6a10ada811 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/dnams.c @@ -0,0 +1,103 @@ +/* dnams.c + Get all known dialer names. + + 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_dnams_rcsid[] = "$Id: dnams.c,v 1.1 1993/08/04 19:33:59 jtc Exp $"; +#endif + +/* Get all known dialer names. */ + +int +uuconf_dialer_names (pglobal, ppzdialers) + pointer pglobal; + char ***ppzdialers; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pztaylor; + char **pzhdb; + int iret; + + *ppzdialers = NULL; + pztaylor = NULL; + pzhdb = NULL; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_dialer_names (pglobal, &pztaylor); + if (iret != UUCONF_SUCCESS) + return iret; +#endif + +#if HAVE_HDB_CONFIG + if (qglobal->qprocess->fhdb) + { + iret = uuconf_hdb_dialer_names (pglobal, &pzhdb); + if (iret != UUCONF_SUCCESS) + return iret; + } +#endif + + if (pzhdb == NULL) + *ppzdialers = pztaylor; + else if (pztaylor == NULL) + *ppzdialers = pzhdb; + else + { + char **pz; + + iret = UUCONF_SUCCESS; + + for (pz = pztaylor; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, FALSE, TRUE, + ppzdialers, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + + if (iret == UUCONF_SUCCESS) + { + for (pz = pzhdb; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, FALSE, TRUE, + ppzdialers, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + } + + if (pztaylor != NULL) + free ((pointer) pztaylor); + if (pzhdb != NULL) + free ((pointer) pzhdb); + } + + if (iret == UUCONF_SUCCESS && *ppzdialers == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzdialers, (pointer) NULL); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/errno.c b/gnu/libexec/uucp/libuuconf/errno.c new file mode 100644 index 0000000000..d1def82ca3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/errno.c @@ -0,0 +1,46 @@ +/* errno.c + Return the saved errno value. + + 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_errno_rcsid[] = "$Id: errno.c,v 1.1 1993/08/04 19:34:01 jtc Exp $"; +#endif + +#include + +/* Return the saved errno value. */ + +int +uuconf_error_errno (pglobal) + pointer pglobal; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + if (qglobal == NULL) + return errno; + else + return qglobal->ierrno; +} diff --git a/gnu/libexec/uucp/libuuconf/errstr.c b/gnu/libexec/uucp/libuuconf/errstr.c new file mode 100644 index 0000000000..2bed403f25 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/errstr.c @@ -0,0 +1,241 @@ +/* errstr.c + Return a string for a uuconf error. + + 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_errstr_rcsid[] = "$Id: errstr.c,v 1.1 1993/08/04 19:34:02 jtc Exp $"; +#endif + +static char *zeprint_num P((char *zbuf, size_t cbuf, int ival)); + +/* Return an error string for a uuconf error. This does not return a + uuconf error code, but instead returns the total buffer length. */ + +int +uuconf_error_string (pglobal, ierr, zbuf, cbuf) + pointer pglobal; + int ierr; + char *zbuf; + size_t cbuf; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + const char *zfile; + size_t cfile; + const char *zlineno; + char ablineno[100]; + size_t clineno; + const char *zmsg; + char abmsg[100]; + size_t cmsg; + const char *zerrno; + size_t cerrno; + size_t cret; + size_t ccopy; + + /* The format of the message is + + filename:lineno: message: errno + + If there is no filename, the trailing colon is not output. If + there is no linenumber, the trailing colon is not output. If + there is no filename, the linenumber is not output, and neither + is the space before message. If there is no errno, the + preceeding colon and space are not output. */ + + /* Get the filename to put in the error message, if any. */ + if ((ierr & UUCONF_ERROR_FILENAME) == 0 + || qglobal == NULL + || qglobal->zfilename == NULL) + { + zfile = ""; + cfile = 0; + } + else + { + zfile = qglobal->zfilename; + cfile = strlen (zfile) + 1; + } + + /* Get the line number to put in the error message, if any. */ + if (cfile == 0 + || (ierr & UUCONF_ERROR_LINENO) == 0 + || qglobal == NULL + || qglobal->ilineno <= 0) + { + zlineno = ""; + clineno = 0; + } + else + { + zlineno = zeprint_num (ablineno, sizeof ablineno, qglobal->ilineno); + clineno = strlen (zlineno) + 1; + } + + /* Get the main message. */ + switch (UUCONF_ERROR_VALUE (ierr)) + { + case UUCONF_SUCCESS: + zmsg = "no error"; + break; + case UUCONF_NOT_FOUND: + zmsg = "not found"; + break; + case UUCONF_FOPEN_FAILED: + zmsg = "fopen"; + break; + case UUCONF_FSEEK_FAILED: + zmsg = "fseek"; + break; + case UUCONF_MALLOC_FAILED: + zmsg = "malloc"; + break; + case UUCONF_SYNTAX_ERROR: + zmsg = "syntax error"; + break; + default: + zmsg = zeprint_num (abmsg, sizeof abmsg, UUCONF_ERROR_VALUE (ierr)); + zmsg -= sizeof "error " - 1; + memcpy ((pointer) zmsg, (pointer) "error ", sizeof "error " - 1); + break; + } + + cmsg = strlen (zmsg); + if (cfile > 0) + ++cmsg; + + /* Get the errno string. Note that strerror is not necessarily + reentrant. */ + if ((ierr & UUCONF_ERROR_ERRNO) == 0 + || qglobal == NULL) + { + zerrno = ""; + cerrno = 0; + } + else + { + zerrno = strerror (qglobal->ierrno); + cerrno = strlen (zerrno) + 2; + } + + cret = cfile + clineno + cmsg + cerrno + 1; + + if (cbuf == 0) + return cret; + + /* Leave room for the null byte. */ + --cbuf; + + if (cfile > 0) + { + ccopy = cfile - 1; + if (ccopy > cbuf) + ccopy = cbuf; + memcpy ((pointer) zbuf, (pointer) zfile, ccopy); + zbuf += ccopy; + cbuf -= ccopy; + if (cbuf > 0) + { + *zbuf++ = ':'; + --cbuf; + } + } + + if (clineno > 0) + { + ccopy = clineno - 1; + if (ccopy > cbuf) + ccopy = cbuf; + memcpy ((pointer) zbuf, (pointer) zlineno, ccopy); + zbuf += ccopy; + cbuf -= ccopy; + if (cbuf > 0) + { + *zbuf++ = ':'; + --cbuf; + } + } + + if (cbuf > 0 && cfile > 0) + { + *zbuf++ = ' '; + --cbuf; + --cmsg; + } + ccopy = cmsg; + if (ccopy > cbuf) + ccopy = cbuf; + memcpy ((pointer) zbuf, (pointer) zmsg, ccopy); + zbuf += ccopy; + cbuf -= ccopy; + + if (cerrno > 0) + { + if (cbuf > 0) + { + *zbuf++ = ':'; + --cbuf; + } + if (cbuf > 0) + { + *zbuf++ = ' '; + --cbuf; + } + ccopy = cerrno - 2; + if (ccopy > cbuf) + ccopy = cbuf; + memcpy ((pointer) zbuf, (pointer) zerrno, ccopy); + zbuf += ccopy; + cbuf -= ccopy; + } + + *zbuf = '\0'; + + return cret; +} + +/* Turn a number into a string. This should really call sprintf, but + since nothing else in the uuconf library calls any print routine, + it's more interesting to not call it here either. */ + +static char * +zeprint_num (ab, c, i) + char *ab; + size_t c; + register int i; +{ + register char *z; + + z = ab + c; + *--z = '\0'; + do + { + *--z = i % 10 + '0'; + i /= 10; + } + while (i != 0); + + return z; +} diff --git a/gnu/libexec/uucp/libuuconf/filnam.c b/gnu/libexec/uucp/libuuconf/filnam.c new file mode 100644 index 0000000000..ab1b76a51d --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/filnam.c @@ -0,0 +1,44 @@ +/* filnam.c + Return the saved file name. + + 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_filnam_rcsid[] = "$Id: filnam.c,v 1.1 1993/08/04 19:34:03 jtc Exp $"; +#endif + +/* Return the saved file name. */ + +const char * +uuconf_error_filename (pglobal) + pointer pglobal; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + if (qglobal == NULL) + return ""; + else + return qglobal->zfilename; +} diff --git a/gnu/libexec/uucp/libuuconf/freblk.c b/gnu/libexec/uucp/libuuconf/freblk.c new file mode 100644 index 0000000000..cb27d115c0 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/freblk.c @@ -0,0 +1,63 @@ +/* freblk.c + Free up an entire 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_freblk_rcsid[] = "$Id: freblk.c,v 1.1 1993/08/04 19:34:05 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Free up an entire memory block. */ + +#if UUCONF_ANSI_C +void +#endif +uuconf_free_block (pblock) + pointer pblock; +{ + struct sblock *q = (struct sblock *) pblock; + struct sblock *qloop; + + /* We have to free the added blocks first because the list may link + into blocks that are earlier on the list. */ + for (qloop = q; qloop != NULL; qloop = qloop->qnext) + { + struct sadded *qadd; + + for (qadd = qloop->qadded; qadd != NULL; qadd = qadd->qnext) + free (qadd->padded); + } + + while (q != NULL) + { + struct sblock *qnext; + + qnext = q->qnext; + free ((pointer) q); + q = qnext; + } +} diff --git a/gnu/libexec/uucp/libuuconf/fredia.c b/gnu/libexec/uucp/libuuconf/fredia.c new file mode 100644 index 0000000000..60b00b7cf8 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/fredia.c @@ -0,0 +1,44 @@ +/* fredia.c + Free dialer information. + + 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_fredia_rcsid[] = "$Id: fredia.c,v 1.1 1993/08/04 19:34:08 jtc Exp $"; +#endif + +/* Free the memory allocated for a dialer. */ + +#undef uuconf_dialer_free + +/*ARGSUSED*/ +int +uuconf_dialer_free (pglobal, qdialer) + pointer pglobal; + struct uuconf_dialer *qdialer; +{ + uuconf_free_block (qdialer->uuconf_palloc); + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/free.c b/gnu/libexec/uucp/libuuconf/free.c new file mode 100644 index 0000000000..91916f1d3c --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/free.c @@ -0,0 +1,68 @@ +/* free.c + Free a buffer from 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_free_rcsid[] = "$Id: free.c,v 1.1 1993/08/04 19:34:10 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Free memory allocated by uuconf_malloc. If the memory block is + NULL, this just calls free; this is convenient for a number of + routines. Otherwise, this will only do something if this was the + last buffer allocated for one of the memory blocks in the list; in + other cases, the memory is lost until the entire memory block is + freed. */ + +#if UUCONF_ANSI_C +void +#endif +uuconf_free (pblock, pbuf) + pointer pblock; + pointer pbuf; +{ + struct sblock *q = (struct sblock *) pblock; + + if (pbuf == NULL) + return; + + if (q == NULL) + { + free (pbuf); + return; + } + + for (; q != NULL; q = q->qnext) + { + if (q->plast == pbuf) + { + q->ifree = (char *) pbuf - q->u.ab; + /* We could reset q->plast here, but it doesn't matter. */ + return; + } + } +} diff --git a/gnu/libexec/uucp/libuuconf/freprt.c b/gnu/libexec/uucp/libuuconf/freprt.c new file mode 100644 index 0000000000..2906b9dc83 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/freprt.c @@ -0,0 +1,44 @@ +/* freprt.c + Free port information. + + 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_freprt_rcsid[] = "$Id: freprt.c,v 1.1 1993/08/04 19:34:12 jtc Exp $"; +#endif + +/* Free the memory allocated for a port. */ + +#undef uuconf_port_free + +/*ARGSUSED*/ +int +uuconf_port_free (pglobal, qport) + pointer pglobal; + struct uuconf_port *qport; +{ + uuconf_free_block (qport->uuconf_palloc); + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/fresys.c b/gnu/libexec/uucp/libuuconf/fresys.c new file mode 100644 index 0000000000..a73f4c1bc8 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/fresys.c @@ -0,0 +1,44 @@ +/* fresys.c + Free system information. + + 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_fresys_rcsid[] = "$Id: fresys.c,v 1.1 1993/08/04 19:34:13 jtc Exp $"; +#endif + +/* Free the memory allocated for a system. */ + +#undef uuconf_system_free + +/*ARGSUSED*/ +int +uuconf_system_free (pglobal, qsys) + pointer pglobal; + struct uuconf_system *qsys; +{ + uuconf_free_block (qsys->uuconf_palloc); + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/grdcmp.c b/gnu/libexec/uucp/libuuconf/grdcmp.c new file mode 100644 index 0000000000..8b02ff9963 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/grdcmp.c @@ -0,0 +1,76 @@ +/* grdcmp.c + Compare two grades. + + 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_grdcmp_rcsid[] = "$Id: grdcmp.c,v 1.1 1993/08/04 19:34:14 jtc Exp $"; +#endif + +#include + +/* 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. + + This implementation assumes that the upper case letters are in + sequence, and that the lower case letters are in sequence. */ + +int +uuconf_grade_cmp (barg1, barg2) + int barg1; + int barg2; +{ + int b1, b2; + + /* Make sure the arguments are unsigned. */ + b1 = (int) BUCHAR (barg1); + b2 = (int) BUCHAR (barg2); + + if (isdigit (b1)) + { + if (isdigit (b2)) + return b1 - b2; + else + return -1; + } + else if (isupper (b1)) + { + if (isdigit (b2)) + return 1; + else if (isupper (b2)) + return b1 - b2; + else + return -1; + } + else + { + if (! islower (b2)) + return 1; + else + return b1 - b2; + } +} diff --git a/gnu/libexec/uucp/libuuconf/hdial.c b/gnu/libexec/uucp/libuuconf/hdial.c new file mode 100644 index 0000000000..666cc7f62e --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hdial.c @@ -0,0 +1,187 @@ +/* hdial.c + Find a dialer in the HDB configuration files. + + 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_hdial_rcsid[] = "$Id: hdial.c,v 1.1 1993/08/04 19:34:15 jtc Exp $"; +#endif + +#include +#include + +/* Find a dialer in the HDB configuration files by name. */ + +int +uuconf_hdb_dialer_info (pglobal, zname, qdialer) + pointer pglobal; + const char *zname; + struct uuconf_dialer *qdialer; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pz; + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + int iret; + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + + iret = UUCONF_NOT_FOUND; + + for (pz = qglobal->qprocess->pzhdb_dialers; *pz != NULL; pz++) + { + FILE *e; + int cchars; + + qglobal->ilineno = 0; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + int ctoks; + pointer pblock; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + if (isspace (BUCHAR (zline[0])) || zline[0] == '#') + continue; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + if (ctoks < 1) + continue; + + if (strcmp (zname, pzsplit[0]) != 0) + continue; + + /* We found the dialer. */ + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + zline = NULL; + + _uuconf_uclear_dialer (qdialer); + qdialer->uuconf_zname = pzsplit[0]; + qdialer->uuconf_palloc = pblock; + + if (ctoks > 1) + { + /* The second field is characters to send instead of "=" + and "-" in phone numbers. */ + if (strcmp (pzsplit[1], "\"\"") == 0) + { + char *zsubs; + char bnext; + + zsubs = pzsplit[1]; + bnext = *zsubs; + while (bnext != '\0') + { + if (bnext == '=') + qdialer->uuconf_zdialtone = zsubs + 1; + else if (bnext == '-') + qdialer->uuconf_zpause = zsubs + 1; + if (zsubs[1] == '\0') + break; + zsubs += 2; + bnext = *zsubs; + *zsubs = '\0'; + } + } + + /* Any remaining fields form a chat script. */ + if (ctoks > 2) + { + pzsplit[1] = (char *) "chat"; + iret = _uuconf_ichat_cmd (qglobal, ctoks - 1, + pzsplit + 1, + &qdialer->uuconf_schat, + pblock); + iret &=~ UUCONF_CMDTABRET_KEEP; + if (iret != UUCONF_SUCCESS) + { + uuconf_free_block (pblock); + break; + } + } + } + + iret = UUCONF_SUCCESS; + break; + } + + (void) fclose (e); + + if (iret != UUCONF_NOT_FOUND) + break; + } + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + + if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/hdnams.c b/gnu/libexec/uucp/libuuconf/hdnams.c new file mode 100644 index 0000000000..0806059214 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hdnams.c @@ -0,0 +1,109 @@ +/* hdnams.c + Get all known dialer names from the HDB configuration files. + + 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_hdnams_rcsid[] = "$Id: hdnams.c,v 1.1 1993/08/04 19:34:16 jtc Exp $"; +#endif + +#include +#include + +/* Get all the dialer names from the HDB Dialers file. */ + +int +uuconf_hdb_dialer_names (pglobal, ppzdialers) + pointer pglobal; + char ***ppzdialers; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + char *zline; + size_t cline; + char **pz; + + *ppzdialers = NULL; + + iret = UUCONF_SUCCESS; + + zline = NULL; + cline = 0; + + for (pz = qglobal->qprocess->pzhdb_dialers; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + qglobal->ilineno = 0; + + while (_uuconf_getline (qglobal, &zline, &cline, e) > 0) + { + ++qglobal->ilineno; + + /* Lines beginning with whitespace are treated as comments. + No dialer name can contain a '#', which is another + comment character, so eliminating the first '#' does no + harm and catches comments. */ + zline[strcspn (zline, " \t#\n")] = '\0'; + if (*zline == '\0') + continue; + + iret = _uuconf_iadd_string (qglobal, zline, TRUE, TRUE, + ppzdialers, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + { + iret |= UUCONF_ERROR_LINENO; + break; + } + } + + (void) fclose (e); + } + + if (zline != NULL) + free ((pointer) zline); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + return iret | UUCONF_ERROR_FILENAME; + } + + if (*ppzdialers == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzdialers, (pointer) NULL); + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/hinit.c b/gnu/libexec/uucp/libuuconf/hinit.c new file mode 100644 index 0000000000..2b1c1cc6fa --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hinit.c @@ -0,0 +1,295 @@ +/* hinit.c + Initialize for reading HDB configuration files. + + 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_hinit_rcsid[] = "$Id: hinit.c,v 1.1 1993/08/04 19:34:17 jtc Exp $"; +#endif + +#include +#include + +/* Avoid replicating OLDCONFIGLIB several times if not necessary. */ +static const char abHoldconfiglib[] = OLDCONFIGLIB; + +/* Initialize the routines which read HDB configuration files. */ + +int +uuconf_hdb_init (ppglobal, zprogram) + pointer *ppglobal; + const char *zprogram; +{ + struct sglobal **pqglobal = (struct sglobal **) ppglobal; + int iret; + struct sglobal *qglobal; + pointer pblock; + char abdialcodes[sizeof OLDCONFIGLIB + sizeof HDB_DIALCODES - 1]; + char *zsys; + FILE *e; + + if (*pqglobal == NULL) + { + iret = _uuconf_iinit_global (pqglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + qglobal = *pqglobal; + pblock = qglobal->pblock; + + if (zprogram == NULL + || strcmp (zprogram, "uucp") == 0) + zprogram = "uucico"; + + /* Add the Dialcodes file to the global list. */ + memcpy ((pointer) abdialcodes, (pointer) abHoldconfiglib, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (abdialcodes + sizeof OLDCONFIGLIB - 1), + (pointer) HDB_DIALCODES, sizeof HDB_DIALCODES); + iret = _uuconf_iadd_string (qglobal, abdialcodes, TRUE, FALSE, + &qglobal->qprocess->pzdialcodefiles, + pblock); + if (iret != UUCONF_SUCCESS) + return iret; + + /* Read the Sysfiles file. We allocate the name on the heap rather + than the stack so that we can return it in + qerr->uuconf_zfilename. */ + + zsys = uuconf_malloc (pblock, + sizeof OLDCONFIGLIB + sizeof HDB_SYSFILES - 1); + if (zsys == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) zsys, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (zsys + sizeof OLDCONFIGLIB - 1), (pointer) HDB_SYSFILES, + sizeof HDB_SYSFILES); + + iret = UUCONF_SUCCESS; + + e = fopen (zsys, "r"); + if (e == NULL) + uuconf_free (pblock, zsys); + else + { + char *zline; + size_t cline; + char **pzargs; + size_t cargs; + char **pzcolon; + size_t ccolon; + int cchars; + + zline = NULL; + cline = 0; + pzargs = NULL; + cargs = 0; + pzcolon = NULL; + ccolon = 0; + + qglobal->ilineno = 0; + + while (iret == UUCONF_SUCCESS + && (cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + int ctypes, cnames; + int i; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + if (isspace (BUCHAR (zline[0])) || zline[0] == '#') + continue; + + ctypes = _uuconf_istrsplit (zline, '\0', &pzargs, &cargs); + if (ctypes < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + if (ctypes == 0) + continue; + + if (strncmp (pzargs[0], "service=", sizeof "service=" - 1) != 0) + { + iret = UUCONF_SYNTAX_ERROR; + break; + } + pzargs[0] += sizeof "service=" - 1; + + cnames = _uuconf_istrsplit (pzargs[0], ':', &pzcolon, &ccolon); + if (cnames < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + for (i = 0; i < cnames; i++) + if (strcmp (zprogram, pzcolon[i]) == 0) + break; + + if (i >= cnames) + continue; + + for (i = 1; i < ctypes && iret == UUCONF_SUCCESS; i++) + { + char ***ppz; + int cfiles, ifile; + + if (strncmp (pzargs[i], "systems=", sizeof "systems=" - 1) + == 0) + { + ppz = &qglobal->qprocess->pzhdb_systems; + pzargs[i] += sizeof "systems=" - 1; + } + else if (strncmp (pzargs[i], "devices=", sizeof "devices=" - 1) + == 0) + { + ppz = &qglobal->qprocess->pzhdb_devices; + pzargs[i] += sizeof "devices=" - 1; + } + else if (strncmp (pzargs[i], "dialers=", sizeof "dialers=" - 1) + == 0) + { + ppz = &qglobal->qprocess->pzhdb_dialers; + pzargs[i] += sizeof "dialers=" - 1; + } + else + { + iret = UUCONF_SYNTAX_ERROR; + break; + } + + cfiles = _uuconf_istrsplit (pzargs[i], ':', &pzcolon, &ccolon); + if (cfiles < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + for (ifile = 0; + ifile < cfiles && iret == UUCONF_SUCCESS; + ifile++) + { + /* Looking for a leading '/' is Unix dependent, and + should probably be changed. */ + if (pzcolon[ifile][0] == '/') + iret = _uuconf_iadd_string (qglobal, pzcolon[ifile], TRUE, + FALSE, ppz, pblock); + else + { + char *zdir; + size_t clen; + + clen = strlen (pzcolon[ifile]); + zdir = (char *) uuconf_malloc (pblock, + (sizeof OLDCONFIGLIB + + sizeof HDB_SEPARATOR + + clen + - 1)); + if (zdir == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) zdir, (pointer) abHoldconfiglib, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (zdir + sizeof OLDCONFIGLIB - 1), + HDB_SEPARATOR, sizeof HDB_SEPARATOR - 1); + memcpy ((pointer) (zdir + + sizeof OLDCONFIGLIB - 1 + + sizeof HDB_SEPARATOR - 1), + (pointer) pzcolon[ifile], clen + 1); + iret = _uuconf_iadd_string (qglobal, zdir, FALSE, FALSE, + ppz, pblock); + } + } + } + } + + (void) fclose (e); + if (zline != NULL) + free ((pointer) zline); + if (pzargs != NULL) + free ((pointer) pzargs); + if (pzcolon != NULL) + free ((pointer) pzcolon); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = zsys; + return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + } + + if (qglobal->qprocess->pzhdb_systems == NULL) + { + char ab[sizeof OLDCONFIGLIB + sizeof HDB_SYSTEMS - 1]; + + memcpy ((pointer) ab, (pointer) abHoldconfiglib, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), + (pointer) HDB_SYSTEMS, sizeof HDB_SYSTEMS); + iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, + &qglobal->qprocess->pzhdb_systems, + pblock); + } + if (qglobal->qprocess->pzhdb_devices == NULL && iret == UUCONF_SUCCESS) + { + char ab[sizeof OLDCONFIGLIB + sizeof HDB_DEVICES - 1]; + + memcpy ((pointer) ab, (pointer) abHoldconfiglib, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), + (pointer) HDB_DEVICES, sizeof HDB_DEVICES); + iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, + &qglobal->qprocess->pzhdb_devices, + pblock); + } + if (qglobal->qprocess->pzhdb_dialers == NULL && iret == UUCONF_SUCCESS) + { + char ab[sizeof OLDCONFIGLIB + sizeof HDB_DIALERS - 1]; + + memcpy ((pointer) ab, (pointer) abHoldconfiglib, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), + (pointer) HDB_DIALERS, sizeof HDB_DIALERS); + iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, + &qglobal->qprocess->pzhdb_dialers, + pblock); + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/hlocnm.c b/gnu/libexec/uucp/libuuconf/hlocnm.c new file mode 100644 index 0000000000..9af4d7e7a5 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hlocnm.c @@ -0,0 +1,84 @@ +/* hlocnm.c + Get the local name to use from the HDB configuration files. + + 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_hlocnm_rcsid[] = "$Id: hlocnm.c,v 1.1 1993/08/04 19:34:18 jtc Exp $"; +#endif + +#include + +/* Get the local name to use, based on the login name, from the HDB + configuration files. */ + +int +uuconf_hdb_login_localname (pglobal, zlogin, pzname) + pointer pglobal; + const char *zlogin; + char **pzname; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct shpermissions *qperm; + + if (! qglobal->qprocess->fhdb_read_permissions) + { + int iret; + + iret = _uuconf_ihread_permissions (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + for (qperm = qglobal->qprocess->qhdb_permissions; + qperm != NULL; + qperm = qperm->qnext) + { + if (qperm->zmyname != NULL + && qperm->zmyname != (char *) &_uuconf_unset + && qperm->pzlogname != NULL + && qperm->pzlogname != (char **) &_uuconf_unset) + { + char **pz; + + for (pz = qperm->pzlogname; *pz != NULL; pz++) + { + if (strcmp (*pz, zlogin) == 0) + { + *pzname = strdup (qperm->zmyname); + if (*pzname == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + return UUCONF_SUCCESS; + } + } + } + } + + *pzname = NULL; + return UUCONF_NOT_FOUND; +} diff --git a/gnu/libexec/uucp/libuuconf/hport.c b/gnu/libexec/uucp/libuuconf/hport.c new file mode 100644 index 0000000000..690de91fc2 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hport.c @@ -0,0 +1,368 @@ +/* hport.c + Find a port in the HDB configuration files. + + 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_hport_rcsid[] = "$Id: hport.c,v 1.1 1993/08/04 19:34:20 jtc Exp $"; +#endif + +#include +#include + +/* Find a port in the HDB configuration files by name, baud rate, and + special purpose function. */ + +int +uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) + pointer pglobal; + const char *zname; + long ibaud; + long ihighbaud; + int (*pifn) P((struct uuconf_port *, pointer)); + pointer pinfo; + struct uuconf_port *qport; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + int iret; + char **pz; + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + + iret = UUCONF_NOT_FOUND; + + for (pz = qglobal->qprocess->pzhdb_devices; *pz != NULL; pz++) + { + FILE *e; + int cchars; + + qglobal->ilineno = 0; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + iret = UUCONF_NOT_FOUND; + + while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + int ctoks; + char *z, *zprotos, *zport; + long ilow, ihigh; + pointer pblock; + + ++qglobal->ilineno; + + iret = UUCONF_NOT_FOUND; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + if (isspace (BUCHAR (zline[0])) || zline[0] == '#') + continue; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + /* An entry in Devices is + + type device dial-device baud dialer-token pairs + + The type (normally "ACU") is treated as the name. */ + + /* If there aren't enough entries, ignore the line; this + should probably do something more useful. */ + if (ctoks < 4) + continue; + + /* There may be a comma separated list of protocols after + the name. */ + zprotos = strchr (pzsplit[0], ','); + if (zprotos != NULL) + { + *zprotos = '\0'; + ++zprotos; + } + + zport = pzsplit[0]; + + /* Get any modem class, and pick up the baud rate while + we're at it. The modem class will be appended to the + name, so we need to get it before we see if we've found + the port with the right name. */ + z = pzsplit[3]; + if (strcasecmp (z, "Any") == 0 + || strcmp (z, "-") == 0) + { + ilow = 0L; + ihigh = 0L; + } + else + { + char *zend; + + while (*z != '\0' && ! isdigit (BUCHAR (*z))) + ++z; + + ilow = strtol (z, &zend, 10); + if (*zend == '-') + ihigh = strtol (zend + 1, (char **) NULL, 10); + else + ihigh = ilow; + + if (z != pzsplit[3]) + { + size_t cclass, cport; + + cclass = z - pzsplit[3]; + cport = strlen (pzsplit[0]); + zport = malloc (cport + cclass + 1); + if (zport == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) zport, (pointer) pzsplit[0], cport); + memcpy ((pointer) (zport + cport), (pointer) pzsplit[3], + cclass); + zport[cport + cclass] = '\0'; + } + } + + /* Make sure the name and baud rate match any argument. */ + if ((zname != NULL + && strcmp (zport, zname) != 0) + || (ibaud != 0 + && ilow != 0 + && (ilow > ibaud || ihigh < ibaud))) + { + if (zport != pzsplit[0]) + free ((pointer) zport); + continue; + } + + /* Some systems permit ,M after the device name. This means + to open the port with O_NDELAY and then change it. We + just ignore this flag, although perhaps we should record + it somewhere. */ + pzsplit[1][strcspn (pzsplit[1], ",")] = '\0'; + + /* Now we must construct the port information, so that we + can pass it to pifn. The port type is determined by its + name, unfortunately. The name "Direct" is used for a + direct port, "TCP" for a TCP port, and anything else for + a modem port. */ + pblock = NULL; + _uuconf_uclear_port (qport); + qport->uuconf_zname = zport; + qport->uuconf_zprotocols = zprotos; + if (strcmp (pzsplit[0], "Direct") == 0) + { + qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT; + qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1]; + qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow; + } + else if (strcmp (pzsplit[0], "TCP") == 0) + { + /* For a TCP port, the device name is taken as the TCP + port to use. */ + qport->uuconf_ttype = UUCONF_PORTTYPE_TCP; + qport->uuconf_ireliable + = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX + | UUCONF_RELIABLE_SPECIFIED); + qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[1]; + } + else if (ctoks >= 5 + && (strcmp (pzsplit[4], "TLI") == 0 + || strcmp (pzsplit[4], "TLIS") == 0)) + { + size_t c; + char **pzd; + + qport->uuconf_ttype = UUCONF_PORTTYPE_TLI; + qport->uuconf_u.uuconf_stli.uuconf_zdevice = pzsplit[1]; + qport->uuconf_u.uuconf_stli.uuconf_fstream + = strcmp (pzsplit[4], "TLIS") == 0; + qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL; + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + c = (ctoks - 4) * sizeof (char *); + pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); + if (pzd == NULL) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); + pzd[ctoks - 4] = NULL; + qport->uuconf_u.uuconf_stli.uuconf_pzdialer = pzd; + qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL; + qport->uuconf_ireliable + = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX + | UUCONF_RELIABLE_SPECIFIED); + } + else + { + qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM; + qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1]; + if (strcmp (pzsplit[2], "-") != 0) + qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = + pzsplit[2]; + else + qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; + if (ilow == ihigh) + { + qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow; + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; + } + else + { + qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow; + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh; + } + qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; + if (ctoks < 5) + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; + else + { + size_t c; + char **pzd; + + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + c = (ctoks - 4) * sizeof (char *); + pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); + if (pzd == NULL) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); + pzd[ctoks - 4] = NULL; + + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd; + } + qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; + } + + if (pifn != NULL) + { + iret = (*pifn) (qport, pinfo); + if (iret != UUCONF_SUCCESS) + { + if (zport != pzsplit[0]) + free ((pointer) zport); + if (pblock != NULL) + uuconf_free_block (pblock); + if (iret != UUCONF_NOT_FOUND) + break; + continue; + } + } + + /* This is the port we want. */ + if (pblock == NULL) + { + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + } + + if (uuconf_add_block (pblock, zline) != 0 + || (zport != pzsplit[0] + && uuconf_add_block (pblock, zport) != 0)) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + zline = NULL; + + qport->uuconf_palloc = pblock; + + break; + } + + (void) fclose (e); + + if (iret != UUCONF_NOT_FOUND) + break; + } + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + + if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/hrmunk.c b/gnu/libexec/uucp/libuuconf/hrmunk.c new file mode 100644 index 0000000000..e7516f7e78 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hrmunk.c @@ -0,0 +1,55 @@ +/* remunk.c + Get the name of the HDB remote.unknown shell script. + + 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_hrmunk_rcsid[] = "$Id: hrmunk.c,v 1.1 1993/08/04 19:34:22 jtc Exp $"; +#endif + +#include + +/* Get the name of the HDB remote.unknown shell script. */ + +int +uuconf_hdb_remote_unknown (pglobal, pzname) + pointer pglobal; + char **pzname; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + size_t csize; + + csize = sizeof OLDCONFIGLIB + sizeof HDB_REMOTE_UNKNOWN - 1; + *pzname = malloc (csize); + if (*pzname == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy (*pzname, OLDCONFIGLIB, sizeof OLDCONFIGLIB - 1); + memcpy (*pzname + sizeof OLDCONFIGLIB - 1, HDB_REMOTE_UNKNOWN, + sizeof HDB_REMOTE_UNKNOWN); + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/hsinfo.c b/gnu/libexec/uucp/libuuconf/hsinfo.c new file mode 100644 index 0000000000..83129a3e70 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hsinfo.c @@ -0,0 +1,625 @@ +/* hsinfo.c + Get information about a system from the HDB configuration files. + + 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_hsinfo_rcsid[] = "$Id: hsinfo.c,v 1.1 1993/08/04 19:34:24 jtc Exp $"; +#endif + +#include +#include + +static int ihadd_machine_perm P((struct sglobal *qglobal, + struct uuconf_system *qsys, + struct shpermissions *qperm)); +static int ihadd_logname_perm P((struct sglobal *qglobal, + struct uuconf_system *qsys, + struct shpermissions *qperm)); + +/* Get the information for a particular system from the HDB + configuration files. This does not make sure that all the default + values are set. */ + +int +_uuconf_ihdb_system_internal (qglobal, zsystem, qsys) + struct sglobal *qglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + int iret; + struct shpermissions *qperm; + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + char **pzcomma; + size_t ccomma; + pointer pblock; + char **pz; + boolean ffound_machine, ffound_login; + struct shpermissions *qother_machine; + struct uuconf_system *qalt; + + if (! qglobal->qprocess->fhdb_read_permissions) + { + iret = _uuconf_ihread_permissions (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* First look through the Permissions information to see if this is + an alias for some system. I assume that an alias applies to the + first name in the corresponding MACHINE entry. */ + + for (qperm = qglobal->qprocess->qhdb_permissions; + qperm != NULL; + qperm = qperm->qnext) + { + if (qperm->pzalias == NULL + || qperm->pzmachine == NULL + || qperm->pzalias == (char **) &_uuconf_unset + || qperm->pzmachine == (char **) &_uuconf_unset) + continue; + + for (pz = qperm->pzalias; *pz != NULL; pz++) + { + if (strcmp (*pz, zsystem) == 0) + { + zsystem = qperm->pzmachine[0]; + break; + } + } + if (*pz != NULL) + break; + } + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + pzcomma = NULL; + ccomma = 0; + + pblock = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++) + { + FILE *e; + int cchars; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + qglobal->ilineno = 0; + + while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + int ctoks, ctimes, i; + struct uuconf_system *qset; + char *z, *zretry; + int cretry; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + if (isspace (BUCHAR (zline[0])) || zline[0] == '#') + continue; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + /* If this isn't the system we're looking for, keep reading + the file. */ + if (ctoks < 1 + || strcmp (zsystem, pzsplit[0]) != 0) + continue; + + /* If this is the first time we've found the system, we want + to set *qsys directly. Otherwise, we allocate a new + alternate. */ + if (pblock == NULL) + { + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + _uuconf_uclear_system (qsys); + qsys->uuconf_palloc = pblock; + qset = qsys; + } + else + { + struct uuconf_system **pq; + + qset = ((struct uuconf_system *) + uuconf_malloc (pblock, sizeof (struct uuconf_system))); + if (qset == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + _uuconf_uclear_system (qset); + for (pq = &qsys->uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qset; + } + + /* Add this line to the memory block we are building for the + system. */ + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + zline = NULL; + cline = 0; + + /* The format of a line in Systems is + system time device speed phone chat + For example, + airs Any ACU 9600 5551212 ogin: foo pass: bar + */ + + /* Get the system name. */ + + qset->uuconf_zname = pzsplit[0]; + qset->uuconf_fcall = TRUE; + qset->uuconf_fcalled = FALSE; + + if (ctoks < 2) + continue; + + /* A time string is "time/grade,time/grade;retry". A + missing grade is taken as BGRADE_LOW. */ + zretry = strchr (pzsplit[1], ';'); + if (zretry == NULL) + cretry = 0; + else + { + *zretry = '\0'; + cretry = (int) strtol (zretry + 1, (char **) NULL, 10); + } + + ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma); + if (ctimes < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + for (i = 0; i < ctimes; i++) + { + char *zslash; + char bgrade; + + z = pzcomma[i]; + zslash = strchr (z, '/'); + if (zslash == NULL) + bgrade = UUCONF_GRADE_LOW; + else + { + *zslash = '\0'; + bgrade = zslash[1]; + if (! UUCONF_GRADE_LEGAL (bgrade)) + bgrade = UUCONF_GRADE_LOW; + } + + iret = _uuconf_itime_parse (qglobal, z, (long) bgrade, + cretry, _uuconf_itime_grade_cmp, + &qset->uuconf_qtimegrade, + pblock); + if (iret != UUCONF_SUCCESS) + break; + } + + if (iret != UUCONF_SUCCESS) + break; + + if (ctoks < 3) + continue; + + /* Pick up the device name. It can be followed by a comma + and a list of protocols. */ + qset->uuconf_zport = pzsplit[2]; + z = strchr (pzsplit[2], ','); + if (z != NULL) + { + qset->uuconf_zprotocols = z + 1; + *z = '\0'; + } + + if (ctoks < 4) + continue; + + /* The speed entry can be a numeric speed, or a range of + speeds, or "Any", or "-". If it starts with a letter, + the initial nonnumeric prefix is a modem class, which + gets appended to the port name. */ + z = pzsplit[3]; + if (strcasecmp (z, "Any") != 0 + && strcmp (z, "-") != 0) + { + char *zend; + + while (*z != '\0' && ! isdigit (BUCHAR (*z))) + ++z; + + qset->uuconf_ibaud = strtol (z, &zend, 10); + if (*zend == '-') + qset->uuconf_ihighbaud = strtol (zend + 1, (char **) NULL, + 10); + + if (z != pzsplit[3]) + { + size_t cport, cclass; + + cport = strlen (pzsplit[2]); + cclass = z - pzsplit[3]; + qset->uuconf_zport = uuconf_malloc (pblock, + cport + cclass + 1); + if (qset->uuconf_zport == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) qset->uuconf_zport, (pointer) pzsplit[2], + cport); + memcpy ((pointer) (qset->uuconf_zport + cport), + (pointer) pzsplit[3], cclass); + qset->uuconf_zport[cport + cclass] = '\0'; + } + } + + if (ctoks < 5) + continue; + + /* Get the phone number. */ + qset->uuconf_zphone = pzsplit[4]; + + if (ctoks < 6) + continue; + + /* Get the chat script. We just hand this off to the chat + script processor, so that it will parse subsend and + subexpect strings correctly. */ + pzsplit[4] = (char *) "chat"; + iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4, + &qset->uuconf_schat, pblock); + iret &=~ UUCONF_CMDTABRET_KEEP; + if (iret != UUCONF_SUCCESS) + break; + } + + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + break; + } + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + if (pzcomma != NULL) + free ((pointer) pzcomma); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + return iret | UUCONF_ERROR_FILENAME; + } + + if (pblock == NULL) + return UUCONF_NOT_FOUND; + + /* Now we have to put in the Permissions information. The relevant + Permissions entries are those with this system in the MACHINE + list and (if this system does not have a VALIDATE entry) those + with a LOGNAME list but no MACHINE list. If no entry is found + with this system in the MACHINE list, then we must look for an + entry with "OTHER" in the MACHINE list. */ + ffound_machine = FALSE; + ffound_login = FALSE; + qother_machine = NULL; + for (qperm = qglobal->qprocess->qhdb_permissions; + qperm != NULL; + qperm = qperm->qnext) + { + boolean fmachine; + + /* MACHINE=OTHER is recognized specially. It appears that OTHER + need only be recognized by itself, not when combined with + other machine names. */ + if (qother_machine == NULL + && qperm->pzmachine != NULL + && qperm->pzmachine != (char **) &_uuconf_unset + && qperm->pzmachine[0][0] == 'O' + && strcmp (qperm->pzmachine[0], "OTHER") == 0) + qother_machine = qperm; + + /* If this system is named in a MACHINE entry, we must add the + appropriate information to every alternate that could be used + for calling out. */ + fmachine = FALSE; + if (! ffound_machine + && qperm->pzmachine != NULL + && qperm->pzmachine != (char **) &_uuconf_unset) + { + for (pz = qperm->pzmachine; *pz != NULL; pz++) + { + if ((*pz)[0] == zsystem[0] + && strcmp (*pz, zsystem) == 0) + { + for (qalt = qsys; + qalt != NULL; + qalt = qalt->uuconf_qalternate) + { + if (qalt->uuconf_fcall) + { + iret = ihadd_machine_perm (qglobal, qalt, qperm); + if (iret != UUCONF_SUCCESS) + return iret; + } + } + + fmachine = TRUE; + ffound_machine = TRUE; + + break; + } + } + } + + /* A LOGNAME line applies to this machine if it is listed in the + corresponding VALIDATE entry, or if it is not listed in any + VALIDATE entry. On this pass through the Permissions entry + we pick up the information if the system appears in a + VALIDATE entry; if it does not, we make another pass to put + in all the LOGNAME lines. */ + if (qperm->pzlogname != NULL + && qperm->pzlogname != (char **) &_uuconf_unset + && qperm->pzvalidate != NULL + && qperm->pzvalidate != (char **) &_uuconf_unset) + { + for (pz = qperm->pzvalidate; *pz != NULL; ++pz) + if ((*pz)[0] == zsystem[0] + && strcmp (*pz, zsystem) == 0) + break; + if (*pz != NULL) + { + for (pz = qperm->pzlogname; *pz != NULL; ++pz) + { + /* If this LOGNAME line is also a matching MACHINE + line, we can add the LOGNAME permissions to the + first alternate. Otherwise, we must create a new + alternate. We cannot put a LOGNAME line in the + first alternate if MACHINE does not match, + because certain permissions (e.g. READ) may be + specified by both types of lines, and we must use + LOGNAME entries only when accepting calls and + MACHINE entries only when placing calls. */ + if (fmachine + && (qsys->uuconf_zcalled_login == NULL + || (qsys->uuconf_zcalled_login + == (char *) &_uuconf_unset))) + { + qsys->uuconf_zcalled_login = *pz; + iret = ihadd_logname_perm (qglobal, qsys, qperm); + } + else + { + struct uuconf_system *qnew; + struct uuconf_system **pq; + + qnew = ((struct uuconf_system *) + uuconf_malloc (pblock, + sizeof (struct uuconf_system))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + *qnew = *qsys; + qnew->uuconf_qalternate = NULL; + for (pq = &qsys->uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qnew; + + qnew->uuconf_zcalled_login = *pz; + qnew->uuconf_fcall = FALSE; + iret = ihadd_logname_perm (qglobal, qnew, qperm); + } + + if (iret != UUCONF_SUCCESS) + return iret; + } + + ffound_login = TRUE; + } + } + } + + /* If we didn't find an entry for the machine, we must use the + MACHINE=OTHER entry, if any. */ + if (! ffound_machine && qother_machine != NULL) + { + for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) + { + if (qalt->uuconf_fcall) + { + iret = ihadd_machine_perm (qglobal, qalt, qother_machine); + if (iret != UUCONF_SUCCESS) + return iret; + } + } + } + + /* If this system was not listed in any VALIDATE entry, then we must + add a called-login for each LOGNAME entry in Permissions. */ + if (! ffound_login) + { + for (qperm = qglobal->qprocess->qhdb_permissions; + qperm != NULL; + qperm = qperm->qnext) + { + if (qperm->pzlogname == NULL + || qperm->pzlogname == (char **) &_uuconf_unset) + continue; + + for (pz = qperm->pzlogname; *pz != NULL; pz++) + { + struct uuconf_system *qnew; + struct uuconf_system **pq; + + qnew = ((struct uuconf_system *) + uuconf_malloc (pblock, + sizeof (struct uuconf_system))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + *qnew = *qsys; + qnew->uuconf_qalternate = NULL; + for (pq = &qsys->uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qnew; + + /* We recognize LOGNAME=OTHER specially, although this + appears to be an SCO innovation. */ + if (strcmp (*pz, "OTHER") == 0) + qnew->uuconf_zcalled_login = (char *) "ANY"; + else + qnew->uuconf_zcalled_login = *pz; + qnew->uuconf_fcall = FALSE; + iret = ihadd_logname_perm (qglobal, qnew, qperm); + if (iret != UUCONF_SUCCESS) + return iret; + } + } + } + + /* HDB permits local requests to receive to any directory, which is + not the default put in by _uuconf_isystem_basic_default. We set + it here instead. */ + for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) + { + iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, + FALSE, FALSE, + &qalt->uuconf_pzlocal_receive, + pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* HDB does not have a maximum number of retries if a retry time is + given in the time field. */ + if (qsys->uuconf_qtimegrade != NULL + && qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset + && qsys->uuconf_qtimegrade->uuconf_cretry > 0) + qsys->uuconf_cmax_retries = 0; + + return UUCONF_SUCCESS; +} + +/* Add the settings of a MACHINE line in Permissions to a system. */ + +/*ARGSIGNORED*/ +static int +ihadd_machine_perm (qglobal, qsys, qperm) + struct sglobal *qglobal; + struct uuconf_system *qsys; + struct shpermissions *qperm; +{ + if (qperm->frequest >= 0) + qsys->uuconf_fsend_request = qperm->frequest; + else + qsys->uuconf_fsend_request = FALSE; + qsys->uuconf_pzremote_send = qperm->pzread; + qsys->uuconf_pzremote_receive = qperm->pzwrite; + qsys->uuconf_pzcmds = qperm->pzcommands; + qsys->uuconf_zlocalname = qperm->zmyname; + qsys->uuconf_zpubdir = qperm->zpubdir; + qsys->uuconf_pzalias = qperm->pzalias; + + return UUCONF_SUCCESS; +} + +/* Add the settings of a LOGNAME line in Permissions to a system. */ + +/*ARGSIGNORED*/ +static int +ihadd_logname_perm (qglobal, qsys, qperm) + struct sglobal *qglobal; + struct uuconf_system *qsys; + struct shpermissions *qperm; +{ + qsys->uuconf_fcalled = TRUE; + if (qperm->frequest >= 0) + qsys->uuconf_fsend_request = qperm->frequest; + else + qsys->uuconf_fsend_request = FALSE; + qsys->uuconf_fcalled_transfer = qperm->fsendfiles; + qsys->uuconf_pzremote_send = qperm->pzread; + qsys->uuconf_pzremote_receive = qperm->pzwrite; + qsys->uuconf_fcallback = qperm->fcallback; + qsys->uuconf_zlocalname = qperm->zmyname; + qsys->uuconf_zpubdir = qperm->zpubdir; + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/hsnams.c b/gnu/libexec/uucp/libuuconf/hsnams.c new file mode 100644 index 0000000000..de003a3ec5 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hsnams.c @@ -0,0 +1,142 @@ +/* hsnams.c + Get all known system names from the HDB configuration files. + + 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_hsnams_rcsid[] = "$Id: hsnams.c,v 1.1 1993/08/04 19:34:26 jtc Exp $"; +#endif + +#include +#include + +/* Get all the system names from the HDB Systems file. We have to + read the Permissions file in order to support aliases. */ + +int +uuconf_hdb_system_names (pglobal, ppzsystems, falias) + pointer pglobal; + char ***ppzsystems; + int falias; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + char *zline; + size_t cline; + char **pz; + + *ppzsystems = NULL; + + iret = UUCONF_SUCCESS; + + zline = NULL; + cline = 0; + + for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + qglobal->ilineno = 0; + + while (_uuconf_getline (qglobal, &zline, &cline, e) > 0) + { + ++qglobal->ilineno; + + /* Lines beginning with whitespace are treated as comments. + No system name can contain a '#', which is another + comment character, so eliminating the first '#' does no + harm and catches comments. */ + zline[strcspn (zline, " \t#\n")] = '\0'; + if (*zline == '\0') + continue; + + iret = _uuconf_iadd_string (qglobal, zline, TRUE, TRUE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + { + iret |= UUCONF_ERROR_LINENO; + break; + } + } + + (void) fclose (e); + } + + if (zline != NULL) + free ((pointer) zline); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + return iret | UUCONF_ERROR_FILENAME; + } + + /* If we are supposed to return aliases, we must read the + Permissions file. */ + if (falias) + { + struct shpermissions *q; + + if (! qglobal->qprocess->fhdb_read_permissions) + { + iret = _uuconf_ihread_permissions (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + for (q = qglobal->qprocess->qhdb_permissions; + q != NULL; + q = q->qnext) + { + pz = q->pzalias; + if (pz == NULL || pz == (char **) &_uuconf_unset) + continue; + + for (; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, TRUE, TRUE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + return iret; + } + } + } + + if (*ppzsystems == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzsystems, (pointer) NULL); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/hsys.c b/gnu/libexec/uucp/libuuconf/hsys.c new file mode 100644 index 0000000000..676c20ff0e --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hsys.c @@ -0,0 +1,49 @@ +/* hsys.c + User function to get a system from the HDB configuration files. + + 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_hsys_rcsid[] = "$Id: hsys.c,v 1.1 1993/08/04 19:34:29 jtc Exp $"; +#endif + +/* Get system information from the HDB configuration files. This is a + wrapper for the internal function which makes sure that every field + gets a default value. */ + +int +uuconf_hdb_system_info (pglobal, zsystem, qsys) + pointer pglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + + iret = _uuconf_ihdb_system_internal (qglobal, zsystem, qsys); + if (iret != UUCONF_SUCCESS) + return iret; + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/hunk.c b/gnu/libexec/uucp/libuuconf/hunk.c new file mode 100644 index 0000000000..8e997d0b71 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/hunk.c @@ -0,0 +1,142 @@ +/* hunk.c + Get information about an unknown system from the HDB Permissions file. + + 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_hunk_rcsid[] = "$Id: hunk.c,v 1.1 1993/08/04 19:34:31 jtc Exp $"; +#endif + +#include + +/* Get information about an unknown system from the HDB Permissions + file. This doesn't run the remote.unknown shell script, because + that's too system dependent. */ + +int +uuconf_hdb_system_unknown (pglobal, qsys) + pointer pglobal; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + boolean ffirst; + struct shpermissions *qperm; + struct uuconf_system *qalt; + + if (! qglobal->qprocess->fhdb_read_permissions) + { + iret = _uuconf_ihread_permissions (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + _uuconf_uclear_system (qsys); + qsys->uuconf_palloc = uuconf_malloc_block (); + if (qsys->uuconf_palloc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + ffirst = TRUE; + + for (qperm = qglobal->qprocess->qhdb_permissions; + qperm != NULL; + qperm = qperm->qnext) + { + char **pz; + + if (qperm->pzlogname == NULL + || qperm->pzlogname == (char **) &_uuconf_unset) + continue; + + for (pz = qperm->pzlogname; *pz != NULL; pz++) + { + if (ffirst) + { + qalt = qsys; + ffirst = FALSE; + } + else + { + struct uuconf_system **pq; + + qalt = ((struct uuconf_system *) + uuconf_malloc (qsys->uuconf_palloc, + sizeof (struct uuconf_system))); + if (qalt == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + _uuconf_uclear_system (qalt); + for (pq = &qsys->uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qalt; + } + + /* We recognize LOGNAME=OTHER specially, although this + appears to be an SCO innovation. */ + if (strcmp (*pz, "OTHER") == 0) + qalt->uuconf_zcalled_login = (char *) "ANY"; + else + qalt->uuconf_zcalled_login = *pz; + qalt->uuconf_fcall = FALSE; + qsys->uuconf_fcalled = TRUE; + if (qperm->frequest >= 0) + qsys->uuconf_fsend_request = qperm->frequest; + else + qsys->uuconf_fsend_request = FALSE; + qsys->uuconf_fcalled_transfer = qperm->fsendfiles; + qsys->uuconf_pzremote_send = qperm->pzread; + qsys->uuconf_pzremote_receive = qperm->pzwrite; + qsys->uuconf_fcallback = qperm->fcallback; + qsys->uuconf_zlocalname = qperm->zmyname; + qsys->uuconf_zpubdir = qperm->zpubdir; + } + } + + if (ffirst) + return UUCONF_NOT_FOUND; + + /* HDB permits local requests to receive to any directory, which is + not the default put in by _uuconf_isystem_basic_default. We set + it here instead. */ + for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) + { + iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, + FALSE, FALSE, + &qalt->uuconf_pzlocal_receive, + qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/iniglb.c b/gnu/libexec/uucp/libuuconf/iniglb.c new file mode 100644 index 0000000000..2422656efc --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/iniglb.c @@ -0,0 +1,177 @@ +/* iniglb.c + Initialize the global information structure. + + 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_iniglb_rcsid[] = "$Id: iniglb.c,v 1.1 1993/08/04 19:34:33 jtc Exp $"; +#endif + +#include + +/* Initialize the global information structure. */ + +int +_uuconf_iinit_global (pqglobal) + struct sglobal **pqglobal; +{ + pointer pblock; + register struct sprocess *qprocess; + char *azargs[3]; + int iret; + + pblock = uuconf_malloc_block (); + if (pblock == NULL) + return UUCONF_MALLOC_FAILED; + + *pqglobal = (struct sglobal *) uuconf_malloc (pblock, + sizeof (struct sglobal)); + if (*pqglobal == NULL) + { + uuconf_free_block (pblock); + return UUCONF_MALLOC_FAILED; + } + + (*pqglobal)->qprocess = ((struct sprocess *) + uuconf_malloc (pblock, + sizeof (struct sprocess))); + if ((*pqglobal)->qprocess == NULL) + { + uuconf_free_block (pblock); + *pqglobal = NULL; + return UUCONF_MALLOC_FAILED; + } + + (*pqglobal)->pblock = pblock; + (*pqglobal)->ierrno = 0; + (*pqglobal)->ilineno = 0; + (*pqglobal)->zfilename = NULL; + + qprocess = (*pqglobal)->qprocess; + + qprocess->zlocalname = NULL; + qprocess->zspooldir = SPOOLDIR; + qprocess->zpubdir = PUBDIR; +#ifdef LOCKDIR + qprocess->zlockdir = LOCKDIR; +#else + qprocess->zlockdir = SPOOLDIR; +#endif + qprocess->zlogfile = LOGFILE; + qprocess->zstatsfile = STATFILE; + qprocess->zdebugfile = DEBUGFILE; + qprocess->zdebug = ""; + qprocess->cmaxuuxqts = 0; + qprocess->fv2 = TRUE; + qprocess->fhdb = TRUE; + qprocess->pzdialcodefiles = NULL; + qprocess->pztimetables = NULL; + qprocess->zconfigfile = NULL; + qprocess->pzsysfiles = NULL; + qprocess->pzportfiles = NULL; + qprocess->pzdialfiles = NULL; + qprocess->pzpwdfiles = NULL; + qprocess->pzcallfiles = NULL; + qprocess->qunknown = NULL; + qprocess->fread_syslocs = FALSE; + qprocess->qsyslocs = NULL; + qprocess->qvalidate = NULL; + qprocess->fuses_myname = FALSE; + qprocess->zv2systems = NULL; + qprocess->zv2devices = NULL; + qprocess->zv2userfile = NULL; + qprocess->zv2cmds = NULL; + qprocess->pzhdb_systems = NULL; + qprocess->pzhdb_devices = NULL; + qprocess->pzhdb_dialers = NULL; + qprocess->fhdb_read_permissions = FALSE; + qprocess->qhdb_permissions = NULL; + + azargs[0] = NULL; + azargs[1] = (char *) "Evening"; + azargs[2] = (char *) "Wk1705-0755,Sa,Su"; + iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, + (pointer) NULL, (pointer) NULL); + if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) + { + azargs[1] = (char *) "Night"; + azargs[2] = (char *) "Wk2305-0755,Sa,Su2305-1655"; + iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, + (pointer) NULL, (pointer) NULL); + } + if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) + { + azargs[1] = (char *) "NonPeak"; + azargs[2] = (char *) "Wk1805-0655,Sa,Su"; + iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, + (pointer) NULL, (pointer) NULL); + } + if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) + { + uuconf_free_block (pblock); + *pqglobal = NULL; + + /* Strip off any special bits, since there's no global + structure. */ + return UUCONF_ERROR_VALUE (iret); + } + + return UUCONF_SUCCESS; +} + +/* Add a timetable. This is also called by the Taylor UUCP + initialization code, as well as by the Taylor UUCP sys file code + (although the latter is obsolete). There's no point in putting + this in a separate file, since everything must call + _uuconf_init_global. There is a race condition here if this is + called by two different threads on a sys file command, but the sys + file command is obsolete anyhow. */ + +/*ARGSUSED*/ +int +_uuconf_itimetable (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + + iret = _uuconf_iadd_string (qglobal, argv[1], FALSE, FALSE, + &qglobal->qprocess->pztimetables, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_EXIT; + + iret = _uuconf_iadd_string (qglobal, argv[2], FALSE, FALSE, + &qglobal->qprocess->pztimetables, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_EXIT; + + return UUCONF_CMDTABRET_KEEP; +} diff --git a/gnu/libexec/uucp/libuuconf/init.c b/gnu/libexec/uucp/libuuconf/init.c new file mode 100644 index 0000000000..ef252a7824 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/init.c @@ -0,0 +1,74 @@ +/* init.c + Initialize for reading UUCP configuration files. + + 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_init_rcsid[] = "$Id: init.c,v 1.1 1993/08/04 19:34:35 jtc Exp $"; +#endif + +/* Initialize the UUCP configuration file reading routines. This is + just a generic routine which calls the type specific routines. */ + +/*ARGSUSED*/ +int +uuconf_init (ppglobal, zprogram, zname) + pointer *ppglobal; + const char *zprogram; + const char *zname; +{ + struct sglobal **pqglob = (struct sglobal **) ppglobal; + int iret; + + iret = UUCONF_NOT_FOUND; + + *pqglob = NULL; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_init (ppglobal, zprogram, zname); + if (iret != UUCONF_SUCCESS) + return iret; +#endif + +#if HAVE_V2_CONFIG + if (*pqglob == NULL || (*pqglob)->qprocess->fv2) + { + iret = uuconf_v2_init (ppglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } +#endif + +#if HAVE_HDB_CONFIG + if (*pqglob == NULL || (*pqglob)->qprocess->fhdb) + { + iret = uuconf_hdb_init (ppglobal, zprogram); + if (iret != UUCONF_SUCCESS) + return iret; + } +#endif + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/int.c b/gnu/libexec/uucp/libuuconf/int.c new file mode 100644 index 0000000000..b0047ee6c0 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/int.c @@ -0,0 +1,59 @@ +/* int.c + Parse a string into an int or a long. + + 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_int_rcsid[] = "$Id: int.c,v 1.1 1993/08/04 19:34:37 jtc Exp $"; +#endif + +/* Parse a string into a variable. This is called by uuconf_cmd_args, + as well as other functions. The parsing is done in a single place + to make it easy to change. This should return an error code, + including both UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT if + appropriate. */ + +/*ARGSIGNORED*/ +int +_uuconf_iint (qglobal, zval, p, fint) + struct sglobal *qglobal; + const char *zval; + pointer p; + boolean fint; +{ + long i; + char *zend; + + i = strtol ((char *) zval, &zend, 10); + if (*zend != '\0') + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (fint) + *(int *) p = (int) i; + else + *(long *) p = i; + + return UUCONF_CMDTABRET_CONTINUE; +} diff --git a/gnu/libexec/uucp/libuuconf/lckdir.c b/gnu/libexec/uucp/libuuconf/lckdir.c new file mode 100644 index 0000000000..52d1a9fc73 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/lckdir.c @@ -0,0 +1,43 @@ +/* lckdir.c + Get the name of the UUCP lock directory. + + 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_lckdir_rcsid[] = "$Id: lckdir.c,v 1.1 1993/08/04 19:34:39 jtc Exp $"; +#endif + +/* Get the name of the UUCP lock directory. */ + +int +uuconf_lockdir (pglobal, pzlock) + pointer pglobal; + const char **pzlock; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzlock = qglobal->qprocess->zlockdir; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/lineno.c b/gnu/libexec/uucp/libuuconf/lineno.c new file mode 100644 index 0000000000..77839f6ede --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/lineno.c @@ -0,0 +1,44 @@ +/* lineno.c + Return the saved line number. + + 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_lineno_rcsid[] = "$Id: lineno.c,v 1.1 1993/08/04 19:34:41 jtc Exp $"; +#endif + +/* Return the saved line number. */ + +int +uuconf_error_lineno (pglobal) + pointer pglobal; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + if (qglobal == NULL) + return 0; + else + return qglobal->ilineno; +} diff --git a/gnu/libexec/uucp/libuuconf/llocnm.c b/gnu/libexec/uucp/libuuconf/llocnm.c new file mode 100644 index 0000000000..272d6237e9 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/llocnm.c @@ -0,0 +1,70 @@ +/* llocnm.c + Get the local name to use, given a login name. + + 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_llocnm_rcsid[] = "$Id: llocnm.c,v 1.1 1993/08/04 19:34:43 jtc Exp $"; +#endif + +#include + +/* Get the local name to use, given a login name. */ + +int +uuconf_login_localname (pglobal, zlogin, pzname) + pointer pglobal; + const char *zlogin; + char **pzname; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_login_localname (pglobal, zlogin, pzname); + if (iret != UUCONF_NOT_FOUND) + return iret; +#endif + +#if HAVE_HDB_CONFIG + iret = uuconf_hdb_login_localname (pglobal, zlogin, pzname); + if (iret != UUCONF_NOT_FOUND) + return iret; +#endif + + if (qglobal->qprocess->zlocalname != NULL) + { + *pzname = strdup ((char *) qglobal->qprocess->zlocalname); + if (*pzname == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + return UUCONF_SUCCESS; + } + + *pzname = NULL; + return UUCONF_NOT_FOUND; +} diff --git a/gnu/libexec/uucp/libuuconf/local.c b/gnu/libexec/uucp/libuuconf/local.c new file mode 100644 index 0000000000..33adda40b0 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/local.c @@ -0,0 +1,70 @@ +/* local.c + Get default information for the local system. + + 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_local_rcsid[] = "$Id: local.c,v 1.1 1993/08/04 19:34:45 jtc Exp $"; +#endif + +#include + +/* Get default information about the local system. */ + +int +uuconf_system_local (pglobal, qsys) + pointer pglobal; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + + _uuconf_uclear_system (qsys); + qsys->uuconf_palloc = uuconf_malloc_block (); + if (qsys->uuconf_palloc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + qsys->uuconf_zname = (char *) qglobal->qprocess->zlocalname; + + /* By default, we permit the local system to forward to and from any + system. */ + iret = _uuconf_iadd_string (qglobal, (char *) "ANY", FALSE, FALSE, + &qsys->uuconf_pzforward_from, + qsys->uuconf_palloc); + if (iret == UUCONF_SUCCESS) + iret = _uuconf_iadd_string (qglobal, (char *) "ANY", FALSE, FALSE, + &qsys->uuconf_pzforward_to, + qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + { + uuconf_free_block (qsys->uuconf_palloc); + return iret; + } + + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/locnm.c b/gnu/libexec/uucp/libuuconf/locnm.c new file mode 100644 index 0000000000..1bc165b73f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/locnm.c @@ -0,0 +1,46 @@ +/* locnm.c + Get the local node name. + + 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_locnm_rcsid[] = "$Id: locnm.c,v 1.1 1993/08/04 19:34:47 jtc Exp $"; +#endif + +/* Get the local node name. */ + +int +uuconf_localname (pglobal, pzname) + pointer pglobal; + const char **pzname; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzname = qglobal->qprocess->zlocalname; + if (*pzname != NULL) + return UUCONF_SUCCESS; + else + return UUCONF_NOT_FOUND; +} diff --git a/gnu/libexec/uucp/libuuconf/logfil.c b/gnu/libexec/uucp/libuuconf/logfil.c new file mode 100644 index 0000000000..6d76764faa --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/logfil.c @@ -0,0 +1,43 @@ +/* logfil.c + Get the name of the UUCP log file. + + 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_logfil_rcsid[] = "$Id: logfil.c,v 1.1 1993/08/04 19:34:48 jtc Exp $"; +#endif + +/* Get the name of the UUCP log file. */ + +int +uuconf_logfile (pglobal, pzlog) + pointer pglobal; + const char **pzlog; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzlog = qglobal->qprocess->zlogfile; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/maxuxq.c b/gnu/libexec/uucp/libuuconf/maxuxq.c new file mode 100644 index 0000000000..8b5e9e7064 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/maxuxq.c @@ -0,0 +1,86 @@ +/* maxuxq.c + Get the maximum number of simultaneous uuxqt executions. + + 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_maxuxq_rcsid[] = "$Id: maxuxq.c,v 1.1 1993/08/04 19:34:49 jtc Exp $"; +#endif + +/* Get the maximum number of simultaneous uuxqt executions. When + using TAYLOR_CONFIG, this is from the ``max-uuxqts'' command in + config. Otherwise, when using HDB_CONFIG, we read the file + Maxuuxqts. */ + +int +uuconf_maxuuxqts (pglobal, pcmax) + pointer pglobal; + int *pcmax; +{ +#if HAVE_TAYLOR_CONFIG + { + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pcmax = qglobal->qprocess->cmaxuuxqts; + return UUCONF_SUCCESS; + } +#else /* ! HAVE_TAYLOR_CONFIG */ +#if HAVE_HDB_CONFIG + { + char ab[sizeof OLDCONFIGLIB + sizeof HDB_MAXUUXQTS - 1]; + FILE *e; + + *pcmax = 0; + + memcpy ((pointer) ab, (constpointer) OLDCONFIGLIB, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), + (constpointer) HDB_MAXUUXQTS, sizeof HDB_MAXUUXQTS); + e = fopen (ab, "r"); + if (e != NULL) + { + char *z; + size_t c; + + z = NULL; + c = 0; + if (getline (&z, &c, e) > 0) + { + *pcmax = (int) strtol (z, (char **) NULL, 10); + if (*pcmax < 0) + *pcmax = 0; + free ((pointer) z); + } + (void) fclose (e); + } + + return UUCONF_SUCCESS; + } +#else /* ! HAVE_HDB_CONFIG */ + *pcmax = 0; + return UUCONF_SUCCESS; +#endif /* ! HAVE_HDB_CONFIG */ +#endif /* ! HAVE_TAYLOR_CONFIG */ +} diff --git a/gnu/libexec/uucp/libuuconf/mrgblk.c b/gnu/libexec/uucp/libuuconf/mrgblk.c new file mode 100644 index 0000000000..4b2ea1c574 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/mrgblk.c @@ -0,0 +1,50 @@ +/* mrgblk.c + Merge two memory blocks together. + + 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_mrgblk_rcsid[] = "$Id: mrgblk.c,v 1.1 1993/08/04 19:34:50 jtc Exp $"; +#endif + +#include "alloc.h" + +/* Merge one memory block into another one, returning the combined + memory block. */ + +pointer +_uuconf_pmalloc_block_merge (p1, p2) + pointer p1; + pointer p2; +{ + struct sblock *q1 = (struct sblock *) p1; + struct sblock *q2 = (struct sblock *) p2; + struct sblock **pq; + + for (pq = &q1; *pq != NULL; pq = &(*pq)->qnext) + ; + *pq = q2; + return (pointer) q1; +} diff --git a/gnu/libexec/uucp/libuuconf/paramc.c b/gnu/libexec/uucp/libuuconf/paramc.c new file mode 100644 index 0000000000..bcc9a0be7b --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/paramc.c @@ -0,0 +1,175 @@ +/* paramc.c + Handle protocol-parameter commands. + + 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_paramc_rcsid[] = "$Id: paramc.c,v 1.1 1993/08/04 19:34:51 jtc Exp $"; +#endif + +#include + +/* Handle protocol-parameter commands by inserting them into an array + of structures. The return value may include UUCONF_CMDTABRET_KEEP + and UUCONF_CMDTABRET_EXIT, if appropriate. */ + +int +_uuconf_iadd_proto_param (qglobal, argc, argv, pqparam, pblock) + struct sglobal *qglobal; + int argc; + char **argv; + struct uuconf_proto_param **pqparam; + pointer pblock; +{ + struct uuconf_proto_param *q; + size_t c; + struct uuconf_proto_param_entry *qentry; + + if (argc < 2) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + /* The first argument is the protocol character. */ + if (argv[0][1] != '\0') + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (*pqparam == NULL) + { + *pqparam = ((struct uuconf_proto_param *) + uuconf_malloc (pblock, + 2 * sizeof (struct uuconf_proto_param))); + if (*pqparam == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + (*pqparam)[1].uuconf_bproto = '\0'; + q = *pqparam; + q->uuconf_bproto = argv[0][0]; + q->uuconf_qentries = NULL; + } + else + { + c = 0; + for (q = *pqparam; q->uuconf_bproto != '\0'; q++) + { + if (q->uuconf_bproto == argv[0][0]) + break; + ++c; + } + + if (q->uuconf_bproto == '\0') + { + struct uuconf_proto_param *qnew; + + qnew = ((struct uuconf_proto_param *) + uuconf_malloc (pblock, + ((c + 2) + * sizeof (struct uuconf_proto_param)))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + memcpy ((pointer) qnew, (pointer) *pqparam, + c * sizeof (struct uuconf_proto_param)); + qnew[c + 1].uuconf_bproto = '\0'; + + uuconf_free (pblock, *pqparam); + *pqparam = qnew; + + q = qnew + c; + q->uuconf_bproto = argv[0][0]; + q->uuconf_qentries = NULL; + } + } + + if (q->uuconf_qentries == NULL) + { + qentry = ((struct uuconf_proto_param_entry *) + uuconf_malloc (pblock, + 2 * sizeof (struct uuconf_proto_param_entry))); + if (qentry == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + qentry[1].uuconf_cargs = 0; + q->uuconf_qentries = qentry; + } + else + { + struct uuconf_proto_param_entry *qnewent; + + c = 0; + for (qentry = q->uuconf_qentries; qentry->uuconf_cargs != 0; qentry++) + ++c; + + qnewent = ((struct uuconf_proto_param_entry *) + uuconf_malloc (pblock, + ((c + 2) * + sizeof (struct uuconf_proto_param_entry)))); + if (qnewent == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + memcpy ((pointer) qnewent, (pointer) q->uuconf_qentries, + c * sizeof (struct uuconf_proto_param_entry)); + qnewent[c + 1].uuconf_cargs = 0; + + uuconf_free (pblock, q->uuconf_qentries); + q->uuconf_qentries = qnewent; + + qentry = qnewent + c; + } + + qentry->uuconf_cargs = argc - 1; + qentry->uuconf_pzargs = (char **) uuconf_malloc (pblock, + ((argc - 1) + * sizeof (char *))); + if (qentry->uuconf_pzargs == NULL) + { + qglobal->ierrno = errno; + qentry->uuconf_cargs = 0; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + memcpy ((pointer) qentry->uuconf_pzargs, (pointer) (argv + 1), + (argc - 1) * sizeof (char *)); + + return UUCONF_CMDTABRET_KEEP; +} diff --git a/gnu/libexec/uucp/libuuconf/port.c b/gnu/libexec/uucp/libuuconf/port.c new file mode 100644 index 0000000000..586c226944 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/port.c @@ -0,0 +1,77 @@ +/* port.c + Find a port. + + 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_port_rcsid[] = "$Id: port.c,v 1.1 1993/08/04 19:34:52 jtc Exp $"; +#endif + +/* Find a port by name, baud rate, and special purpose function. */ + +int +uuconf_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) + pointer pglobal; + const char *zname; + long ibaud; + long ihighbaud; + int (*pifn) P((struct uuconf_port *, pointer)); + pointer pinfo; + struct uuconf_port *qport; +{ +#if HAVE_V2_CONFIG || HAVE_HDB_CONFIG + struct sglobal *qglobal = (struct sglobal *) pglobal; +#endif + int iret; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_find_port (pglobal, zname, ibaud, ihighbaud, pifn, + pinfo, qport); + if (iret != UUCONF_NOT_FOUND) + return iret; +#endif + +#if HAVE_V2_CONFIG + if (qglobal->qprocess->fv2) + { + iret = uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, + pinfo, qport); + if (iret != UUCONF_NOT_FOUND) + return iret; + } +#endif + +#if HAVE_HDB_CONFIG + if (qglobal->qprocess->fhdb) + { + iret = uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, + pinfo, qport); + if (iret != UUCONF_NOT_FOUND) + return iret; + } +#endif + + return UUCONF_NOT_FOUND; +} diff --git a/gnu/libexec/uucp/libuuconf/prtsub.c b/gnu/libexec/uucp/libuuconf/prtsub.c new file mode 100644 index 0000000000..682f38e687 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/prtsub.c @@ -0,0 +1,54 @@ +/* prtsub.c + Port information subroutines. + + 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_prtsub_rcsid[] = "$Id: prtsub.c,v 1.1 1993/08/04 19:34:53 jtc Exp $"; +#endif + +/* Clear the information in a port. This can only clear the type + independent information; the port type specific information is + cleared when the type of the port is set. */ + +void +_uuconf_uclear_port (qport) + struct uuconf_port *qport; +{ + qport->uuconf_zname = NULL; + qport->uuconf_ttype = UUCONF_PORTTYPE_UNKNOWN; + qport->uuconf_zprotocols = NULL; + qport->uuconf_qproto_params = NULL; + + /* Note that we do not set RELIABLE_SPECIFIED; this just sets + defaults, so that ``seven-bit true'' does not imply ``reliable + false''. */ + qport->uuconf_ireliable = (UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX); + + qport->uuconf_zlockname = NULL; + qport->uuconf_palloc = NULL; +} diff --git a/gnu/libexec/uucp/libuuconf/pubdir.c b/gnu/libexec/uucp/libuuconf/pubdir.c new file mode 100644 index 0000000000..0c4714d466 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/pubdir.c @@ -0,0 +1,43 @@ +/* pubdir.c + Get the name of the UUCP public directory. + + 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_pubdir_rcsid[] = "$Id: pubdir.c,v 1.1 1993/08/04 19:34:54 jtc Exp $"; +#endif + +/* Get the name of the UUCP public directory. */ + +int +uuconf_pubdir (pglobal, pzpub) + pointer pglobal; + const char **pzpub; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzpub = qglobal->qprocess->zpubdir; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/rdlocs.c b/gnu/libexec/uucp/libuuconf/rdlocs.c new file mode 100644 index 0000000000..ba8365fd7b --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/rdlocs.c @@ -0,0 +1,305 @@ +/* rdlocs.c + Get the locations of systems in the Taylor UUCP configuration files. + + 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_rdlocs_rcsid[] = "$Id: rdlocs.c,v 1.1 1993/08/04 19:34:55 jtc Exp $"; +#endif + +#include + +static int itsystem P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int itcalled_login P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int itmyname P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* This code scans through the Taylor UUCP system files in order to + locate each system and to gather the login restrictions (since this + information is held in additional arguments to the "called-login" + command, it can appear anywhere in the systems files). It also + records whether any "myname" appears, as an optimization for + uuconf_taylor_localname. + + This table is used to dispatch the appropriate commands. Most + commands are simply ignored. Note that this is a uuconf_cmdtab, + not a cmdtab_offset. */ + +static const struct uuconf_cmdtab asTcmds[] = +{ + { "system", UUCONF_CMDTABTYPE_FN | 2, NULL, itsystem }, + { "alias", UUCONF_CMDTABTYPE_FN | 2, (pointer) asTcmds, itsystem }, + { "called-login", UUCONF_CMDTABTYPE_FN | 0, NULL, itcalled_login }, + { "myname", UUCONF_CMDTABTYPE_FN | 2, NULL, itmyname }, + { NULL, 0, NULL, NULL } +}; + +/* This structure is used to pass information into the command table + functions. */ + +struct sinfo +{ + /* The sys file name. */ + const char *zname; + /* The open sys file. */ + FILE *e; + /* The list of locations we are building. */ + struct stsysloc *qlocs; + /* The list of validation restrictions we are building. */ + struct svalidate *qvals; +}; + +/* Look through the sys files to find the location and names of all + the systems. Since we're scanning the sys files, we also record + the validation information specified by the additional arguments to + the called-login command. We don't use uuconf_cmd_file to avoid + the overhead of breaking the line up into arguments if not + necessary. */ + +int +_uuconf_iread_locations (qglobal) + struct sglobal *qglobal; +{ + char *zline; + size_t cline; + struct sinfo si; + int iret; + char **pz; + + if (qglobal->qprocess->fread_syslocs) + return UUCONF_SUCCESS; + + zline = NULL; + cline = 0; + + si.qlocs = NULL; + si.qvals = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzsysfiles; *pz != NULL; pz++) + { + FILE *e; + int cchars; + + qglobal->ilineno = 0; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + +#ifdef CLOSE_ON_EXEC + CLOSE_ON_EXEC (e); +#endif + + si.zname = *pz; + si.e = e; + + while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + char *zcmd; + + ++qglobal->ilineno; + + zcmd = zline + strspn (zline, " \t"); + if (strncasecmp (zcmd, "system", sizeof "system" - 1) == 0 + || strncasecmp (zcmd, "alias", sizeof "alias" - 1) == 0 + || strncasecmp (zcmd, "called-login", + sizeof "called-login" - 1) == 0 + || strncasecmp (zcmd, "myname", sizeof "myname" - 1) == 0) + { + iret = uuconf_cmd_line ((pointer) qglobal, zline, asTcmds, + (pointer) &si, (uuconf_cmdtabfn) NULL, + 0, qglobal->pblock); + if ((iret & UUCONF_CMDTABRET_KEEP) != 0) + { + iret &=~ UUCONF_CMDTABRET_KEEP; + zline = NULL; + cline = 0; + } + if (iret != UUCONF_SUCCESS) + { + iret &=~ UUCONF_CMDTABRET_EXIT; + break; + } + } + } + + if (iret != UUCONF_SUCCESS) + break; + } + + if (zline != NULL) + free ((pointer) zline); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + if (UUCONF_ERROR_VALUE (iret) != UUCONF_MALLOC_FAILED) + qglobal->qprocess->fread_syslocs = TRUE; + } + else + { + qglobal->qprocess->qsyslocs = si.qlocs; + qglobal->qprocess->qvalidate = si.qvals; + qglobal->qprocess->fread_syslocs = TRUE; + } + + return iret; +} + +/* Handle a "system" or "alias" command by recording the file and + location. If pvar is not NULL, this is an "alias" command. */ + +/*ARGSUSED*/ +static int +itsystem (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + struct stsysloc *q; + size_t csize; + + q = (struct stsysloc *) uuconf_malloc (qglobal->pblock, + sizeof (struct stsysloc)); + if (q == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + csize = strlen (argv[1]) + 1; + q->zname = uuconf_malloc (qglobal->pblock, csize); + if (q->zname == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + q->qnext = qinfo->qlocs; + memcpy ((pointer) q->zname, (pointer) argv[1], csize); + q->falias = pvar != NULL; + q->zfile = qinfo->zname; + q->e = qinfo->e; + q->iloc = ftell (qinfo->e); + q->ilineno = qglobal->ilineno; + + qinfo->qlocs = q; + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the "called-login" command. This just records any extra + arguments, so that uuconf_validate can check them later if + necessary. */ + +/*ARGSUSED*/ +static int +itcalled_login (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + register struct svalidate *qval; + int i; + + if (argc <= 2) + return UUCONF_CMDTABRET_CONTINUE; + + for (qval = qinfo->qvals; qval != NULL; qval = qval->qnext) + if (strcmp (argv[1], qval->zlogname) == 0) + break; + + if (qval == NULL) + { + qval = (struct svalidate *) uuconf_malloc (qglobal->pblock, + sizeof (struct svalidate)); + if (qval == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + qval->qnext = qinfo->qvals; + qval->zlogname = argv[1]; + qval->pzmachines = NULL; + + qinfo->qvals = qval; + } + + for (i = 2; i < argc; i++) + { + int iret; + + iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, TRUE, + &qval->pzmachines, qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_EXIT; + } + + return UUCONF_CMDTABRET_KEEP; +} + +/* Handle the "myname" command by simply recording that it appears. + This information is used by uuconf_taylor_localname. */ + +/*ARGSUSED*/ +static int +itmyname (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + qglobal->qprocess->fuses_myname = TRUE; + return UUCONF_CMDTABRET_CONTINUE; +} diff --git a/gnu/libexec/uucp/libuuconf/rdperm.c b/gnu/libexec/uucp/libuuconf/rdperm.c new file mode 100644 index 0000000000..dd481c1a8e --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/rdperm.c @@ -0,0 +1,446 @@ +/* rdperm.c + Read the HDB Permissions file. + + 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_rdperm_rcsid[] = "$Id: rdperm.c,v 1.1 1993/08/04 19:34:57 jtc Exp $"; +#endif + +#include +#include + +static int ihcolon P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int ihsendfiles P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int ihunknownperm P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int ihadd_norw P((struct sglobal *qglobal, char ***ppz, char **pzno)); + +/* These routines reads in the HDB Permissions file. We store the + entries in a linked list of shpermissions structures, so we only + have to actually read the file once. */ + +/* This command table and static structure are used to parse a line + from Permissions. The entries are parsed as follows: + + Multiple strings separated by colons: LOGNAME, MACHINE, READ, + WRITE, NOREAD, NOWRITE, COMMANDS, VALIDATE, ALIAS. + + Boolean values: REQUEST, CALLBACK. + + Simple strings: MYNAME, PUBDIR. + + "Yes" or "call": SENDFILES. + + The NOREAD and NOWRITE entries are merged into the READ and WRITE + entries, rather than being permanently stored. They are handled + specially in the uuconf_cmdtab table. */ + +static const struct cmdtab_offset asHperm_cmds[] = +{ + { "NOREAD", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon }, + { "NOWRITE", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon }, + { "LOGNAME", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzlogname), ihcolon }, + { "MACHINE", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzmachine), ihcolon }, + { "REQUEST", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct shpermissions, frequest), NULL }, + { "SENDFILES", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, fsendfiles), ihsendfiles }, + { "READ", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzread), ihcolon }, + { "WRITE", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzwrite), ihcolon }, + { "CALLBACK", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct shpermissions, fcallback), NULL }, + { "COMMANDS", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzcommands), ihcolon }, + { "VALIDATE", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzvalidate), ihcolon }, + { "MYNAME", UUCONF_CMDTABTYPE_STRING, + offsetof (struct shpermissions, zmyname), NULL }, + { "PUBDIR", UUCONF_CMDTABTYPE_STRING, + offsetof (struct shpermissions, zpubdir), NULL }, + { "ALIAS", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct shpermissions, pzalias), ihcolon }, + { NULL, 0, 0, NULL } +}; + +#define CHPERM_CMDS (sizeof asHperm_cmds / sizeof asHperm_cmds[0]) + +/* Actually read the Permissions file into a linked list of + structures. */ + +int +_uuconf_ihread_permissions (qglobal) + struct sglobal *qglobal; +{ + char *zperm; + FILE *e; + int iret; + struct uuconf_cmdtab as[CHPERM_CMDS]; + char **pznoread, **pznowrite; + struct shpermissions shperm; + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + int cchars; + struct shpermissions *qlist, **pq; + + if (qglobal->qprocess->fhdb_read_permissions) + return UUCONF_SUCCESS; + + zperm = (char *) uuconf_malloc (qglobal->pblock, + (sizeof OLDCONFIGLIB + + sizeof HDB_PERMISSIONS - 1)); + if (zperm == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + memcpy ((pointer) zperm, (pointer) OLDCONFIGLIB, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (zperm + sizeof OLDCONFIGLIB - 1), + (pointer) HDB_PERMISSIONS, sizeof HDB_PERMISSIONS); + + e = fopen (zperm, "r"); + if (e == NULL) + { + uuconf_free (qglobal->pblock, zperm); + qglobal->qprocess->fhdb_read_permissions = TRUE; + return UUCONF_SUCCESS; + } + + _uuconf_ucmdtab_base (asHperm_cmds, CHPERM_CMDS, (char *) &shperm, as); + as[0].uuconf_pvar = (pointer) &pznoread; + as[1].uuconf_pvar = (pointer) &pznowrite; + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + + qlist = NULL; + pq = &qlist; + + qglobal->ilineno = 0; + + iret = UUCONF_SUCCESS; + + while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) + { + int centries; + struct shpermissions *qnew; + int i; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + if (isspace (BUCHAR (zline[0])) || zline[0] == '#') + continue; + + centries = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (centries < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + if (centries == 0) + continue; + + shperm.pzlogname = (char **) &_uuconf_unset; + shperm.pzmachine = (char **) &_uuconf_unset; + shperm.frequest = -1; + shperm.fsendfiles = -1; + shperm.pzread = (char **) &_uuconf_unset; + shperm.pzwrite = (char **) &_uuconf_unset; + shperm.fcallback = -1; + shperm.pzcommands = (char **) &_uuconf_unset; + shperm.pzvalidate = (char **) &_uuconf_unset; + shperm.zmyname = (char *) &_uuconf_unset; + shperm.zpubdir = (char *) &_uuconf_unset; + shperm.pzalias = (char **) &_uuconf_unset; + pznoread = (char **) &_uuconf_unset; + pznowrite = (char **) &_uuconf_unset; + + for (i = 0; i < centries; i++) + { + char *zeq; + char *azargs[2]; + + zeq = strchr (pzsplit[i], '='); + if (zeq == NULL) + { + iret = UUCONF_SYNTAX_ERROR; + qglobal->qprocess->fhdb_read_permissions = TRUE; + break; + } + *zeq = '\0'; + + azargs[0] = pzsplit[i]; + azargs[1] = zeq + 1; + + iret = uuconf_cmd_args (qglobal, 2, azargs, as, (pointer) NULL, + ihunknownperm, 0, qglobal->pblock); + if ((iret & UUCONF_CMDTABRET_KEEP) != 0) + { + iret &=~ UUCONF_CMDTABRET_KEEP; + + if (uuconf_add_block (qglobal->pblock, zline) != 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + zline = NULL; + cline = 0; + } + if ((iret & UUCONF_CMDTABRET_EXIT) != 0) + { + iret &=~ UUCONF_CMDTABRET_EXIT; + break; + } + } + + if (iret != UUCONF_SUCCESS) + break; + + if (shperm.pzmachine == (char **) &_uuconf_unset + && shperm.pzlogname == (char **) &_uuconf_unset) + { + iret = UUCONF_SYNTAX_ERROR; + qglobal->qprocess->fhdb_read_permissions = TRUE; + break; + } + + /* Attach any NOREAD or NOWRITE entries to the corresponding + READ or WRITE entries in the format expected for the + pzlocal_receive, etc., fields in uuconf_system. */ + if (pznoread != NULL) + { + iret = ihadd_norw (qglobal, &shperm.pzread, pznoread); + if (iret != UUCONF_SUCCESS) + break; + uuconf_free (qglobal->pblock, pznoread); + } + + if (pznowrite != NULL) + { + iret = ihadd_norw (qglobal, &shperm.pzwrite, pznowrite); + if (iret != UUCONF_SUCCESS) + break; + uuconf_free (qglobal->pblock, pznowrite); + } + + qnew = ((struct shpermissions *) + uuconf_malloc (qglobal->pblock, + sizeof (struct shpermissions))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + *qnew = shperm; + *pq = qnew; + pq = &qnew->qnext; + *pq = NULL; + } + + (void) fclose (e); + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + + if (iret == UUCONF_SUCCESS) + { + qglobal->qprocess->qhdb_permissions = qlist; + qglobal->qprocess->fhdb_read_permissions = TRUE; + } + else + { + qglobal->zfilename = zperm; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + return iret; +} + +/* Split the argument into colon separated strings, and assign a NULL + terminated array of strings to pvar. */ + +/*ARGSUSED*/ +static int +ihcolon (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char ***ppz = (char ***) pvar; + char **pzsplit; + size_t csplit; + int centries; + int i; + int iret; + + *ppz = NULL; + + pzsplit = NULL; + csplit = 0; + + centries = _uuconf_istrsplit (argv[1], ':', &pzsplit, &csplit); + if (centries < 0) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + if (centries == 0) + { + if (pzsplit != NULL) + free ((pointer) pzsplit); + return UUCONF_CMDTABRET_CONTINUE; + } + + iret = UUCONF_SUCCESS; + + for (i = 0; i < centries; i++) + { + iret = _uuconf_iadd_string (qglobal, pzsplit[i], FALSE, FALSE, + ppz, qglobal->pblock); + if (iret != UUCONF_SUCCESS) + { + iret |= UUCONF_CMDTABRET_EXIT; + break; + } + } + + free ((pointer) pzsplit); + + return UUCONF_CMDTABRET_KEEP; +} + +/* Handle the SENDFILES parameter, which can take "yes" or "call" or + "no" as an argument. The string "call" is equivalent to "no". */ + +/*ARGSUSED*/ +static int +ihsendfiles (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + int *pi = (int *) pvar; + + switch (argv[1][0]) + { + case 'C': + case 'c': + case 'N': + case 'n': + *pi = FALSE; + break; + case 'Y': + case 'y': + *pi = TRUE; + break; + default: + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + } + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* If there is an unknown Permissions entry, return a syntax error. + This should probably be more clever. */ + +/*ARGSUSED*/ +static int +ihunknownperm (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; +} + +/* Add a NOREAD or NOWRITE entry to a READ or WRITE entry. */ + +static int +ihadd_norw (qglobal, ppz, pzno) + struct sglobal *qglobal; + char ***ppz; + char **pzno; +{ + register char **pz; + + if (pzno == (char **) &_uuconf_unset) + return UUCONF_SUCCESS; + + for (pz = pzno; *pz != NULL; pz++) + { + size_t csize; + char *znew; + int iret; + + csize = strlen (*pz) + 1; + znew = (char *) uuconf_malloc (qglobal->pblock, csize + 1); + if (znew == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + znew[0] = '!'; + memcpy ((pointer) (znew + 1), (pointer) *pz, csize); + iret = _uuconf_iadd_string (qglobal, znew, FALSE, FALSE, ppz, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/reliab.c b/gnu/libexec/uucp/libuuconf/reliab.c new file mode 100644 index 0000000000..13517d49f3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/reliab.c @@ -0,0 +1,123 @@ +/* reliab.c + Subroutines to handle reliability commands for ports and dialers. + + 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_reliab_rcsid[] = "$Id: reliab.c,v 1.1 1993/08/04 19:34:58 jtc Exp $"; +#endif + +/* Handle the "seven-bit" command for a port or a dialer. The pvar + argument points to an integer which should be set to hold + reliability information. */ + +/*ARGSUSED*/ +int +_uuconf_iseven_bit (pglobal,argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int *pi = (int *) pvar; + int fval; + int iret; + + iret = _uuconf_iboolean (qglobal, argv[1], &fval); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + return iret; + + *pi |= UUCONF_RELIABLE_SPECIFIED; + if (fval) + *pi &=~ UUCONF_RELIABLE_EIGHT; + else + *pi |= UUCONF_RELIABLE_EIGHT; + + return iret; +} + +/* Handle the "reliable" command for a port or a dialer. The pvar + argument points to an integer which should be set to hold + reliability information. */ + +/*ARGSUSED*/ +int +_uuconf_ireliable (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int *pi = (int *) pvar; + int fval; + int iret; + + iret = _uuconf_iboolean (qglobal, argv[1], &fval); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + return iret; + + *pi |= UUCONF_RELIABLE_SPECIFIED; + if (fval) + *pi |= UUCONF_RELIABLE_RELIABLE; + else + *pi &=~ UUCONF_RELIABLE_RELIABLE; + + return iret; +} + +/* Handle the "half-duplex" command for a port or a dialer. The pvar + argument points to an integer which should be set to hold + reliability information. */ + +/*ARGSUSED*/ +int +_uuconf_ihalf_duplex (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int *pi = (int *) pvar; + int fval; + int iret; + + iret = _uuconf_iboolean (qglobal, argv[1], &fval); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + return iret; + + *pi |= UUCONF_RELIABLE_SPECIFIED; + if (fval) + *pi &=~ UUCONF_RELIABLE_FULLDUPLEX; + else + *pi |= UUCONF_RELIABLE_FULLDUPLEX; + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/remunk.c b/gnu/libexec/uucp/libuuconf/remunk.c new file mode 100644 index 0000000000..85297b0212 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/remunk.c @@ -0,0 +1,45 @@ +/* remunk.c + Get the name of the remote.unknown shell script. + + 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_remunk_rcsid[] = "$Id: remunk.c,v 1.1 1993/08/04 19:34:59 jtc Exp $"; +#endif + +/* Get the name of the remote.unknown shell script. */ + +/*ARGSUSED*/ +int +uuconf_remote_unknown (pglobal, pzname) + pointer pglobal; + char **pzname; +{ +#if HAVE_TAYLOR_CONFIG || ! HAVE_HDB_CONFIG + return UUCONF_NOT_FOUND; +#else + return uuconf_hdb_remote_unknown (pglobal, pzname); +#endif +} diff --git a/gnu/libexec/uucp/libuuconf/sinfo.c b/gnu/libexec/uucp/libuuconf/sinfo.c new file mode 100644 index 0000000000..f73851f84a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/sinfo.c @@ -0,0 +1,112 @@ +/* sinfo.c + Get information about a system. + + 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_sinfo_rcsid[] = "$Id: sinfo.c,v 1.1 1993/08/04 19:35:00 jtc Exp $"; +#endif + +/* Get information about a particular system. We combine the + definitions for this system from each type of configuration file, + by passing what we have so far into each one. */ + +int +uuconf_system_info (pglobal, zsystem, qsys) + pointer pglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + boolean fgot; + + fgot = FALSE; + +#if HAVE_TAYLOR_CONFIG + iret = _uuconf_itaylor_system_internal (qglobal, zsystem, qsys); + if (iret == UUCONF_SUCCESS) + fgot = TRUE; + else if (iret != UUCONF_NOT_FOUND) + return iret; +#endif + +#if HAVE_V2_CONFIG + if (qglobal->qprocess->fv2) + { + struct uuconf_system *q; + struct uuconf_system sv2; + + if (fgot) + q = &sv2; + else + q = qsys; + iret = _uuconf_iv2_system_internal (qglobal, zsystem, q); + if (iret == UUCONF_SUCCESS) + { + if (fgot) + { + iret = _uuconf_isystem_default (qglobal, qsys, &sv2, TRUE); + if (iret != UUCONF_SUCCESS) + return iret; + } + fgot = TRUE; + } + else if (iret != UUCONF_NOT_FOUND) + return iret; + } +#endif + +#if HAVE_HDB_CONFIG + if (qglobal->qprocess->fhdb) + { + struct uuconf_system *q; + struct uuconf_system shdb; + + if (fgot) + q = &shdb; + else + q = qsys; + iret = _uuconf_ihdb_system_internal (qglobal, zsystem, q); + if (iret == UUCONF_SUCCESS) + { + if (fgot) + { + iret = _uuconf_isystem_default (qglobal, qsys, &shdb, TRUE); + if (iret != UUCONF_SUCCESS) + return iret; + } + fgot = TRUE; + } + else if (iret != UUCONF_NOT_FOUND) + return iret; + } +#endif + + if (! fgot) + return UUCONF_NOT_FOUND; + + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/snams.c b/gnu/libexec/uucp/libuuconf/snams.c new file mode 100644 index 0000000000..d239b10e08 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/snams.c @@ -0,0 +1,133 @@ +/* snams.c + Get all known system names. + + 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_snams_rcsid[] = "$Id: snams.c,v 1.1 1993/08/04 19:35:01 jtc Exp $"; +#endif + +/* Get all known system names. */ + +int +uuconf_system_names (pglobal, ppzsystems, falias) + pointer pglobal; + char ***ppzsystems; + int falias; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pztaylor; + char **pzv2; + char **pzhdb; + int iret; + + *ppzsystems = NULL; + pztaylor = NULL; + pzv2 = NULL; + pzhdb = NULL; + +#if HAVE_TAYLOR_CONFIG + iret = uuconf_taylor_system_names (pglobal, &pztaylor, falias); + if (iret != UUCONF_SUCCESS) + return iret; +#endif + +#if HAVE_V2_CONFIG + if (qglobal->qprocess->fv2) + { + iret = uuconf_v2_system_names (pglobal, &pzv2, falias); + if (iret != UUCONF_SUCCESS) + return iret; + } +#endif + +#if HAVE_HDB_CONFIG + if (qglobal->qprocess->fhdb) + { + iret = uuconf_hdb_system_names (pglobal, &pzhdb, falias); + if (iret != UUCONF_SUCCESS) + return iret; + } +#endif + + if (pzv2 == NULL && pzhdb == NULL) + *ppzsystems = pztaylor; + else if (pztaylor == NULL && pzhdb == NULL) + *ppzsystems = pzv2; + else if (pztaylor == NULL && pzv2 == NULL) + *ppzsystems = pzhdb; + else + { + char **pz; + + iret = UUCONF_SUCCESS; + + if (pztaylor != NULL) + { + for (pz = pztaylor; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, FALSE, TRUE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + } + + if (pzv2 != NULL && iret == UUCONF_SUCCESS) + { + for (pz = pzv2; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, FALSE, TRUE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + } + + if (pzhdb != NULL && iret == UUCONF_SUCCESS) + { + for (pz = pzhdb; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string (qglobal, *pz, FALSE, TRUE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + } + + if (pztaylor != NULL) + free ((pointer) pztaylor); + if (pzv2 != NULL) + free ((pointer) pzv2); + if (pzhdb != NULL) + free ((pointer) pzhdb); + } + + if (iret == UUCONF_SUCCESS && *ppzsystems == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzsystems, (pointer) NULL); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/split.c b/gnu/libexec/uucp/libuuconf/split.c new file mode 100644 index 0000000000..76cc5e8d36 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/split.c @@ -0,0 +1,106 @@ +/* split.c + Split a string into tokens. + + 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_split_rcsid[] = "$Id: split.c,v 1.1 1993/08/04 19:35:02 jtc Exp $"; +#endif + +#include + +/* Split a string into tokens. The bsep argument is the separator to + use. If it is the null byte, white space is used as the separator, + and leading white space is discarded. Otherwise, each occurrence + of the separator character delimits a field (and thus some fields + may be empty). The array and size arguments may be used to reuse + the same memory. This function is not tied to uuconf; the only way + it can fail is if malloc or realloc fails. */ + +int +_uuconf_istrsplit (zline, bsep, ppzsplit, pcsplit) + register char *zline; + int bsep; + char ***ppzsplit; + size_t *pcsplit; +{ + size_t i; + + i = 0; + + while (TRUE) + { + if (bsep == '\0') + { + while (isspace (BUCHAR (*zline))) + ++zline; + if (*zline == '\0') + break; + } + + if (i >= *pcsplit) + { + char **pznew; + size_t cnew; + + if (*pcsplit == 0) + { + cnew = 8; + pznew = (char **) malloc (cnew * sizeof (char *)); + } + else + { + cnew = *pcsplit * 2; + pznew = (char **) realloc ((pointer) *ppzsplit, + cnew * sizeof (char *)); + } + if (pznew == NULL) + return -1; + *ppzsplit = pznew; + *pcsplit = cnew; + } + + (*ppzsplit)[i] = zline; + ++i; + + if (bsep == '\0') + { + while (*zline != '\0' && ! isspace (BUCHAR (*zline))) + ++zline; + } + else + { + while (*zline != '\0' && *zline != bsep) + ++zline; + } + + if (*zline == '\0') + break; + + *zline++ = '\0'; + } + + return i; +} diff --git a/gnu/libexec/uucp/libuuconf/spool.c b/gnu/libexec/uucp/libuuconf/spool.c new file mode 100644 index 0000000000..e9c13f072c --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/spool.c @@ -0,0 +1,43 @@ +/* spool.c + Get the name of the UUCP spool directory. + + 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_spool_rcsid[] = "$Id: spool.c,v 1.1 1993/08/04 19:35:03 jtc Exp $"; +#endif + +/* Get the name of the UUCP spool directory. */ + +int +uuconf_spooldir (pglobal, pzspool) + pointer pglobal; + const char **pzspool; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzspool = qglobal->qprocess->zspooldir; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/stafil.c b/gnu/libexec/uucp/libuuconf/stafil.c new file mode 100644 index 0000000000..bcea0bffd6 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/stafil.c @@ -0,0 +1,43 @@ +/* stafil.c + Get the name of the UUCP statistics file. + + 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_stafil_rcsid[] = "$Id: stafil.c,v 1.1 1993/08/04 19:35:04 jtc Exp $"; +#endif + +/* Get the name of the UUCP statistics file. */ + +int +uuconf_statsfile (pglobal, pzstats) + pointer pglobal; + const char **pzstats; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pzstats = qglobal->qprocess->zstatsfile; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/syshdr.h b/gnu/libexec/uucp/libuuconf/syshdr.h new file mode 100644 index 0000000000..8ff18a6ca4 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/syshdr.h @@ -0,0 +1,106 @@ +/* syshdr.unx -*- C -*- + Unix system header for the uuconf library. + + 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. + */ + +/* The root directory (used when setting local-send and local-receive + values). */ +#define ZROOTDIR "/" + +/* The current directory (used by uuconv as a prefix for the newly + created file names). */ +#define ZCURDIR "." + +/* The names of the Taylor UUCP configuration files. These are + appended to NEWCONFIGLIB which is defined in Makefile. */ +#define CONFIGFILE "/config" +#define SYSFILE "/sys" +#define PORTFILE "/port" +#define DIALFILE "/dial" +#define CALLFILE "/call" +#define PASSWDFILE "/passwd" +#define DIALCODEFILE "/dialcode" + +/* The names of the various V2 configuration files. These are + appended to OLDCONFIGLIB which is defined in Makefile. */ +#define V2_SYSTEMS "/L.sys" +#define V2_DEVICES "/L-devices" +#define V2_USERFILE "/USERFILE" +#define V2_CMDS "/L.cmds" +#define V2_DIALCODES "/L-dialcodes" + +/* The names of the HDB configuration files. These are appended to + OLDCONFIGLIB which is defined in Makefile. */ +#define HDB_SYSFILES "/Sysfiles" +#define HDB_SYSTEMS "/Systems" +#define HDB_PERMISSIONS "/Permissions" +#define HDB_DEVICES "/Devices" +#define HDB_DIALERS "/Dialers" +#define HDB_DIALCODES "/Dialcodes" +#define HDB_MAXUUXQTS "/Maxuuxqts" +#define HDB_REMOTE_UNKNOWN "/remote.unknown" + +/* A string which is inserted between the value of OLDCONFIGLIB + (defined in the Makefile) and any names specified in the HDB + Sysfiles file. */ +#define HDB_SEPARATOR "/" + +/* A macro to check whether fopen failed because the file did not + exist. */ +#define FNO_SUCH_FILE() (errno == ENOENT) + +#if ! HAVE_STRERROR + +/* We need a definition for strerror; normally the function in the + unix directory is used, but we want to be independent of that + library. This macro evaluates its argument multiple times. */ +extern int sys_nerr; +extern char *sys_errlist[]; + +#define strerror(ierr) \ + ((ierr) >= 0 && (ierr) < sys_nerr ? sys_errlist[ierr] : "unknown error") + +#endif /* ! HAVE_STRERROR */ + +/* We want to be able to mark the Taylor UUCP system files as close on + exec. */ +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +#define CLOSE_ON_EXEC(e) \ + do \ + { \ + int cle_i = fileno (e); \ + \ + fcntl (cle_i, F_SETFD, fcntl (cle_i, F_GETFD, 0) | FD_CLOEXEC); \ + } \ + while (0) diff --git a/gnu/libexec/uucp/libuuconf/syssub.c b/gnu/libexec/uucp/libuuconf/syssub.c new file mode 100644 index 0000000000..f9b52c13fe --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/syssub.c @@ -0,0 +1,458 @@ +/* syssub.c + System information subroutines. + + 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_syssub_rcsid[] = "$Id: syssub.c,v 1.1 1993/08/04 19:35:06 jtc Exp $"; +#endif + +#include + +/* This macro operates on every string (char *) field in struct + uuconf_system. */ +#define SYSTEM_STRINGS(OP) \ + do \ + { \ + OP (uuconf_zname); \ + OP (uuconf_zalternate); \ + OP (uuconf_zdebug); \ + OP (uuconf_zmax_remote_debug); \ + OP (uuconf_zphone); \ + OP (uuconf_zcall_login); \ + OP (uuconf_zcall_password); \ + OP (uuconf_zcalled_login); \ + OP (uuconf_zprotocols); \ + OP (uuconf_zpubdir); \ + OP (uuconf_zlocalname); \ + } \ + while (0) + +/* This macro operates on every string array (char **) field in struct + uuconf_system. */ +#define SYSTEM_STRING_ARRAYS(OP) \ + do \ + { \ + OP (uuconf_pzalias); \ + OP (uuconf_pzlocal_send); \ + OP (uuconf_pzremote_send); \ + OP (uuconf_pzlocal_receive); \ + OP (uuconf_pzremote_receive); \ + OP (uuconf_pzpath); \ + OP (uuconf_pzcmds); \ + OP (uuconf_pzforward_from); \ + OP (uuconf_pzforward_to); \ + OP (uuconf_schat.uuconf_pzchat); \ + OP (uuconf_schat.uuconf_pzprogram); \ + OP (uuconf_schat.uuconf_pzfail); \ + OP (uuconf_scalled_chat.uuconf_pzchat); \ + OP (uuconf_scalled_chat.uuconf_pzprogram); \ + OP (uuconf_scalled_chat.uuconf_pzfail); \ + } \ + while (0) + +/* This macro operations on every timespan pointer (struct + uuconf_timespan *) in struct uuconf_system. */ +#define SYSTEM_TIMESPANS(OP) \ + do \ + { \ + OP (uuconf_qtimegrade); \ + OP (uuconf_qcalltimegrade); \ + OP (uuconf_qcall_local_size); \ + OP (uuconf_qcall_remote_size); \ + OP (uuconf_qcalled_local_size); \ + OP (uuconf_qcalled_remote_size); \ + } \ + while (0) + +/* This macro operates on every boolean value (of type int, although + some type int are not boolean) field in uuconf_system. */ +#define SYSTEM_BOOLEANS(OP) \ + do \ + { \ + OP (uuconf_fcall); \ + OP (uuconf_fcalled); \ + OP (uuconf_fcallback); \ + OP (uuconf_fsequence); \ + OP (uuconf_fsend_request); \ + OP (uuconf_frec_request); \ + OP (uuconf_fcall_transfer); \ + OP (uuconf_fcalled_transfer); \ + OP (uuconf_schat.uuconf_fstrip); \ + OP (uuconf_scalled_chat.uuconf_fstrip); \ + } \ + while (0) + +/* This macro operates on every generic integer (type int or long) in + uuconf_system. */ +#define SYSTEM_INTEGERS(OP) \ + do \ + { \ + OP (uuconf_cmax_retries); \ + OP (uuconf_csuccess_wait); \ + OP (uuconf_ibaud); \ + OP (uuconf_ihighbaud); \ + OP (uuconf_cfree_space); \ + OP (uuconf_schat.uuconf_ctimeout); \ + OP (uuconf_scalled_chat.uuconf_ctimeout); \ + } \ + while (0) + +/* There is no macro for uuconf_qalternate, uuconf_zport, + uuconf_qport, uuconf_qproto_params, or uuconf_palloc. */ + +/* Clear the contents of a struct uuconf_system. */ + +void +_uuconf_uclear_system (q) + struct uuconf_system *q; +{ +#define CLEAR(x) q->x = (char *) &_uuconf_unset + SYSTEM_STRINGS (CLEAR); +#undef CLEAR +#define CLEAR(x) q->x = (char **) &_uuconf_unset + SYSTEM_STRING_ARRAYS (CLEAR); +#undef CLEAR +#define CLEAR(x) q->x = (struct uuconf_timespan *) &_uuconf_unset + SYSTEM_TIMESPANS (CLEAR); +#undef CLEAR +#define CLEAR(x) q->x = -1 + SYSTEM_BOOLEANS (CLEAR); + SYSTEM_INTEGERS (CLEAR); +#undef CLEAR + q->uuconf_qalternate = NULL; + q->uuconf_zport = (char *) &_uuconf_unset; + q->uuconf_qport = (struct uuconf_port *) &_uuconf_unset; + q->uuconf_qproto_params = (struct uuconf_proto_param *) &_uuconf_unset; + q->uuconf_palloc = NULL; +} + +/* Default the contents of one struct uuconf_system to the contents of + another. This default alternate by alternate. Any additional + alternates in q default to the last alternate of qdefault. If the + faddalternates arguments is TRUE, additional alternates or qdefault + are added to q; these alternates are copies of the first alternate + of q, and defaults are set from the additional alternates of + qdefault. */ + +int +_uuconf_isystem_default (qglobal, qset, qdefault, faddalternates) + struct sglobal *qglobal; + struct uuconf_system *qset; + struct uuconf_system *qdefault; + boolean faddalternates; +{ + struct uuconf_system *qalt; + + if (qset->uuconf_palloc != qdefault->uuconf_palloc) + qset->uuconf_palloc = + _uuconf_pmalloc_block_merge (qset->uuconf_palloc, + qdefault->uuconf_palloc); + + /* If we are adding alternates from the default, make sure we have + at least as many alternates in qset as we do in qdefault. Each + new alternate we create gets initialized to the first alternate + of the system. */ + if (faddalternates) + { + struct uuconf_system **pq, *qdef; + + for (qdef = qdefault, pq = &qset; + qdef != NULL; + qdef = qdef->uuconf_qalternate, pq = &(*pq)->uuconf_qalternate) + { + if (*pq == NULL) + { + *pq = ((struct uuconf_system *) + uuconf_malloc (qset->uuconf_palloc, + sizeof (struct uuconf_system))); + if (*pq == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + **pq = *qset; + (*pq)->uuconf_qalternate = NULL; + } + } + } + + for (qalt = qset; qalt != NULL; qalt = qalt->uuconf_qalternate) + { +#define DEFAULT(x) \ + if (qalt->x == (char *) &_uuconf_unset) qalt->x = qdefault->x + SYSTEM_STRINGS (DEFAULT); +#undef DEFAULT +#define DEFAULT(x) \ + if (qalt->x == (char **) &_uuconf_unset) qalt->x = qdefault->x + SYSTEM_STRING_ARRAYS (DEFAULT); +#undef DEFAULT +#define DEFAULT(x) \ + if (qalt->x == (struct uuconf_timespan *) &_uuconf_unset) \ + qalt->x = qdefault->x + SYSTEM_TIMESPANS (DEFAULT); +#undef DEFAULT +#define DEFAULT(x) if (qalt->x < 0) qalt->x = qdefault->x + SYSTEM_BOOLEANS (DEFAULT); + SYSTEM_INTEGERS (DEFAULT); +#undef DEFAULT + + /* We only copy over zport if both zport and qport are NULL, + because otherwise a default zport would override a specific + qport. */ + if (qalt->uuconf_zport == (char *) &_uuconf_unset + && qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) + qalt->uuconf_zport = qdefault->uuconf_zport; + if (qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) + qalt->uuconf_qport = qdefault->uuconf_qport; + + if (qalt->uuconf_qproto_params + == (struct uuconf_proto_param *) &_uuconf_unset) + qalt->uuconf_qproto_params = qdefault->uuconf_qproto_params; + + if (qdefault->uuconf_qalternate != NULL) + qdefault = qdefault->uuconf_qalternate; + } + + return UUCONF_SUCCESS; +} + +/* Put in the basic defaults. This ensures that the fields are valid + on every uuconf_system structure. */ + +int +_uuconf_isystem_basic_default (qglobal, q) + struct sglobal *qglobal; + register struct uuconf_system *q; +{ + int iret; + + iret = UUCONF_SUCCESS; + + for (; q != NULL && iret == UUCONF_SUCCESS; q = q->uuconf_qalternate) + { + /* The default of 26 allowable retries is traditional. */ + if (q->uuconf_cmax_retries < 0) + q->uuconf_cmax_retries = 26; + if (q->uuconf_schat.uuconf_pzchat == (char **) &_uuconf_unset) + { + q->uuconf_schat.uuconf_pzchat = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) "\"\"", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "\\r\\c", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "ogin:", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "\\L", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "word:", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + iret = _uuconf_iadd_string (qglobal, (char *) "\\P", FALSE, + FALSE, + &q->uuconf_schat.uuconf_pzchat, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + if (q->uuconf_schat.uuconf_ctimeout < 0) + q->uuconf_schat.uuconf_ctimeout = 10; + if (q->uuconf_schat.uuconf_fstrip < 0) + q->uuconf_schat.uuconf_fstrip = TRUE; + if (q->uuconf_scalled_chat.uuconf_ctimeout < 0) + q->uuconf_scalled_chat.uuconf_ctimeout = 60; + if (q->uuconf_scalled_chat.uuconf_fstrip < 0) + q->uuconf_scalled_chat.uuconf_fstrip = TRUE; + if (q->uuconf_fsend_request < 0) + q->uuconf_fsend_request = TRUE; + if (q->uuconf_frec_request < 0) + q->uuconf_frec_request = TRUE; + if (q->uuconf_fcall_transfer < 0) + q->uuconf_fcall_transfer = TRUE; + if (q->uuconf_fcalled_transfer < 0) + q->uuconf_fcalled_transfer = TRUE; + if (q->uuconf_pzlocal_send == (char **) &_uuconf_unset) + { + q->uuconf_pzlocal_send = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, FALSE, + FALSE, &q->uuconf_pzlocal_send, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + if (q->uuconf_pzremote_send == (char **) &_uuconf_unset) + { + q->uuconf_pzremote_send = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, + &q->uuconf_pzremote_send, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + if (q->uuconf_pzlocal_receive == (char **) &_uuconf_unset) + { + q->uuconf_pzlocal_receive = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, + &q->uuconf_pzlocal_receive, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + if (q->uuconf_pzremote_receive == (char **) &_uuconf_unset) + { + q->uuconf_pzremote_receive = NULL; + iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, + &q->uuconf_pzremote_receive, + q->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret; + } + + if (q->uuconf_pzpath == (char **) &_uuconf_unset) + { + char *zdup; + char **pz; + size_t csplit; + int c; + + zdup = (char *) uuconf_malloc (q->uuconf_palloc, sizeof CMDPATH); + if (zdup == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + memcpy ((pointer) zdup, (pointer) CMDPATH, sizeof CMDPATH); + pz = NULL; + csplit = 0; + if ((c = _uuconf_istrsplit (zdup, '\0', &pz, &csplit)) < 0) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + q->uuconf_pzpath = (char **) uuconf_malloc (q->uuconf_palloc, + ((c + 1) + * sizeof (char *))); + if (q->uuconf_pzpath == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) q->uuconf_pzpath, (pointer) pz, + c * sizeof (char *)); + q->uuconf_pzpath[c] = NULL; + free ((pointer) pz); + } + + if (q->uuconf_pzcmds == (char **) &_uuconf_unset) + { + q->uuconf_pzcmds = ((char **) + uuconf_malloc (q->uuconf_palloc, + 3 * sizeof (const char *))); + if (q->uuconf_pzcmds == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + q->uuconf_pzcmds[0] = (char *) "rnews"; + q->uuconf_pzcmds[1] = (char *) "rmail"; + q->uuconf_pzcmds[2] = NULL; + } + + if (q->uuconf_cfree_space < 0) + q->uuconf_cfree_space = DEFAULT_FREE_SPACE; + + if (q->uuconf_zpubdir == (const char *) &_uuconf_unset) + q->uuconf_zpubdir = qglobal->qprocess->zpubdir; + +#define SET(x) if (q->x == (char *) &_uuconf_unset) q->x = NULL + SYSTEM_STRINGS(SET); +#undef SET +#define SET(x) if (q->x == (char **) &_uuconf_unset) q->x = NULL + SYSTEM_STRING_ARRAYS(SET); +#undef SET +#define SET(x) \ + if (q->x == (struct uuconf_timespan *) &_uuconf_unset) q->x = NULL + SYSTEM_TIMESPANS (SET); +#undef SET +#define SET(x) if (q->x < 0) q->x = 0 + SYSTEM_BOOLEANS (SET); + SYSTEM_INTEGERS (SET); +#undef SET + + if (q->uuconf_zport == (char *) &_uuconf_unset) + q->uuconf_zport = NULL; + if (q->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) + q->uuconf_qport = NULL; + if (q->uuconf_qproto_params + == (struct uuconf_proto_param *) &_uuconf_unset) + q->uuconf_qproto_params = NULL; + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/tcalou.c b/gnu/libexec/uucp/libuuconf/tcalou.c new file mode 100644 index 0000000000..8eb627eb33 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tcalou.c @@ -0,0 +1,201 @@ +/* tcalou.c + Find callout login name and password from Taylor UUCP configuration files. + + 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_tcalou_rcsid[] = "$Id: tcalou.c,v 1.1 1993/08/04 19:35:07 jtc Exp $"; +#endif + +#include + +static int icsys P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); + +/* Find the callout login name and password for a system from the + Taylor UUCP configuration files. */ + +int +uuconf_taylor_callout (pglobal, qsys, pzlog, pzpass) + pointer pglobal; + const struct uuconf_system *qsys; + char **pzlog; + char **pzpass; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + boolean flookup; + struct uuconf_cmdtab as[2]; + char **pz; + int iret; + pointer pinfo; + + *pzlog = NULL; + *pzpass = NULL; + + flookup = FALSE; + + if (qsys->uuconf_zcall_login != NULL) + { + if (strcmp (qsys->uuconf_zcall_login, "*") == 0) + flookup = TRUE; + else + { + *pzlog = strdup (qsys->uuconf_zcall_login); + if (*pzlog == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + } + } + + if (qsys->uuconf_zcall_password != NULL) + { + if (strcmp (qsys->uuconf_zcall_password, "*") == 0) + flookup = TRUE; + else + { + *pzpass = strdup (qsys->uuconf_zcall_password); + if (*pzpass == NULL) + { + qglobal->ierrno = errno; + if (*pzlog != NULL) + { + free ((pointer) *pzlog); + *pzlog = NULL; + } + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + } + } + + if (! flookup) + { + if (*pzlog == NULL && *pzpass == NULL) + return UUCONF_NOT_FOUND; + return UUCONF_SUCCESS; + } + + as[0].uuconf_zcmd = qsys->uuconf_zname; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 3; + if (*pzlog == NULL) + as[0].uuconf_pvar = (pointer) pzlog; + else + as[0].uuconf_pvar = NULL; + as[0].uuconf_pifn = icsys; + + as[1].uuconf_zcmd = NULL; + + if (*pzpass == NULL) + pinfo = (pointer) pzpass; + else + pinfo = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzcallfiles; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + iret = uuconf_cmd_file (pglobal, e, as, pinfo, + (uuconf_cmdtabfn) NULL, 0, + qsys->uuconf_palloc); + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + break; + if (*pzlog != NULL) + break; + } + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + return iret | UUCONF_ERROR_FILENAME; + } + + if (*pzlog == NULL && *pzpass == NULL) + return UUCONF_NOT_FOUND; + + return UUCONF_SUCCESS; +} + +/* Copy the login name and password onto the heap and set the + pointers. The pzlog argument is passed in pvar, and the pzpass + argument is passed in pinfo. */ + +static int +icsys (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pzlog = (char **) pvar; + char **pzpass = (char **) pinfo; + + if (pzlog != NULL) + { + *pzlog = strdup (argv[1]); + if (*pzlog == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + } + + if (pzpass != NULL) + { + *pzpass = strdup (argv[2]); + if (*pzpass == NULL) + { + qglobal->ierrno = errno; + if (pzlog != NULL) + { + free ((pointer) *pzlog); + *pzlog = NULL; + } + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + } + + return UUCONF_CMDTABRET_EXIT; +} diff --git a/gnu/libexec/uucp/libuuconf/tdial.c b/gnu/libexec/uucp/libuuconf/tdial.c new file mode 100644 index 0000000000..f13c92998a --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tdial.c @@ -0,0 +1,227 @@ +/* tdial.c + Find a dialer in the Taylor UUCP configuration files. + + 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_tdial_rcsid[] = "$Id: tdial.c,v 1.1 1993/08/04 19:35:08 jtc Exp $"; +#endif + +#include + +static int iddialer P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int idunknown P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); + +/* Find a dialer in the Taylor UUCP configuration files by name. */ + +int +uuconf_taylor_dialer_info (pglobal, zname, qdialer) + pointer pglobal; + const char *zname; + struct uuconf_dialer *qdialer; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + FILE *e; + pointer pblock; + int iret; + char **pz; + + e = NULL; + pblock = NULL; + iret = UUCONF_NOT_FOUND; + + for (pz = qglobal->qprocess->pzdialfiles; *pz != NULL; pz++) + { + struct uuconf_cmdtab as[2]; + char *zdialer; + struct uuconf_dialer sdefault; + int ilineno; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + qglobal->ilineno = 0; + + /* Gather the default information from the top of the file. We + do this by handling the "dialer" command ourselves and + passing every other command to _uuconf_idialer_cmd via + idunknown. The value of zdialer will be an malloc block. */ + as[0].uuconf_zcmd = "dialer"; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; + as[0].uuconf_pvar = (pointer) &zdialer; + as[0].uuconf_pifn = iddialer; + + as[1].uuconf_zcmd = NULL; + + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + _uuconf_uclear_dialer (&sdefault); + sdefault.uuconf_palloc = pblock; + zdialer = NULL; + iret = uuconf_cmd_file (pglobal, e, as, (pointer) &sdefault, + idunknown, UUCONF_CMDTABFLAG_BACKSLASH, + pblock); + + /* Now skip until we find a dialer with a matching name. */ + while (iret == UUCONF_SUCCESS + && zdialer != NULL + && strcmp (zname, zdialer) != 0) + { + free ((pointer) zdialer); + zdialer = NULL; + ilineno = qglobal->ilineno; + iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, + (uuconf_cmdtabfn) NULL, + UUCONF_CMDTABFLAG_BACKSLASH, + pblock); + qglobal->ilineno += ilineno; + } + + if (iret != UUCONF_SUCCESS) + { + if (zdialer != NULL) + free ((pointer) zdialer); + break; + } + + if (zdialer != NULL) + { + size_t csize; + + /* We've found the dialer we're looking for. Read the rest + of the commands for it. */ + as[0].uuconf_pvar = NULL; + + *qdialer = sdefault; + csize = strlen (zdialer) + 1; + qdialer->uuconf_zname = uuconf_malloc (pblock, csize); + if (qdialer->uuconf_zname == NULL) + { + qglobal->ierrno = errno; + free ((pointer) zdialer); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) qdialer->uuconf_zname, (pointer) zdialer, + csize); + free ((pointer) zdialer); + + ilineno = qglobal->ilineno; + iret = uuconf_cmd_file (pglobal, e, as, qdialer, idunknown, + UUCONF_CMDTABFLAG_BACKSLASH, pblock); + qglobal->ilineno += ilineno; + break; + } + + (void) fclose (e); + e = NULL; + uuconf_free_block (pblock); + pblock = NULL; + + iret = UUCONF_NOT_FOUND; + } + + if (e != NULL) + (void) fclose (e); + if (iret != UUCONF_SUCCESS && pblock != NULL) + uuconf_free_block (pblock); + + if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME; + } + + return iret; +} + +/* Handle a "dialer" command. This copies the string onto the heap + and returns the pointer in *pvar, unless pvar is NULL. It returns + UUCONF_CMDTABRET_EXIT to force _uuconf_icmd_file_internal to stop + reading and return to the code above, which will then check the + dialer name just read to see if it matches. */ + +/*ARGSUSED*/ +static int +iddialer (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pz = (char **) pvar; + + if (pz != NULL) + { + size_t csize; + + csize = strlen (argv[1]) + 1; + *pz = malloc (csize); + if (*pz == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + memcpy ((pointer) *pz, (pointer) argv[1], csize); + } + return UUCONF_CMDTABRET_EXIT; +} + +/* Handle an unknown command by passing it on to _uuconf_idialer_cmd, + which will parse it into the dialer structure. */ + +/*ARGSUSED*/ +static int +idunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; + + return _uuconf_idialer_cmd (qglobal, argc, argv, qdialer); +} diff --git a/gnu/libexec/uucp/libuuconf/tdialc.c b/gnu/libexec/uucp/libuuconf/tdialc.c new file mode 100644 index 0000000000..e70090f3bb --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tdialc.c @@ -0,0 +1,211 @@ +/* tdialc.c + Handle a Taylor UUCP dialer command. + + 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_tdialc_rcsid[] = "$Id: tdialc.c,v 1.1 1993/08/04 19:35:09 jtc Exp $"; +#endif + +static int idchat P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int iddtr_toggle P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int idcomplete P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int idproto_param P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int idcunknown P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* The command table for dialer commands. The "dialer" command is + handled specially. */ +static const struct cmdtab_offset asDialer_cmds[] = +{ + { "chat", UUCONF_CMDTABTYPE_PREFIX | 0, + offsetof (struct uuconf_dialer, uuconf_schat), idchat }, + { "dialtone", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_dialer, uuconf_zdialtone), NULL }, + { "pause", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_dialer, uuconf_zpause), NULL }, + { "carrier", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_dialer, uuconf_fcarrier), NULL }, + { "carrier-wait", UUCONF_CMDTABTYPE_INT, + offsetof (struct uuconf_dialer, uuconf_ccarrier_wait), NULL }, + { "dtr-toggle", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iddtr_toggle }, + { "complete", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_dialer, uuconf_scomplete), idcomplete }, + { "complete-chat", UUCONF_CMDTABTYPE_PREFIX, + offsetof (struct uuconf_dialer, uuconf_scomplete), idchat }, + { "abort", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_dialer, uuconf_sabort), idcomplete }, + { "abort-chat", UUCONF_CMDTABTYPE_PREFIX, + offsetof (struct uuconf_dialer, uuconf_sabort), idchat }, + { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_dialer, uuconf_qproto_params), idproto_param }, + { "seven-bit", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_dialer, uuconf_ireliable), _uuconf_iseven_bit }, + { "reliable", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_dialer, uuconf_ireliable), _uuconf_ireliable }, + { "half-duplex", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_dialer, uuconf_ireliable), + _uuconf_ihalf_duplex }, + { NULL, 0, 0, NULL } +}; + +#define CDIALER_CMDS (sizeof asDialer_cmds / sizeof asDialer_cmds[0]) + +/* Handle a command passed to a dialer from a Taylor UUCP + configuration file. This can be called when reading the dialer + file, the port file, or the sys file. The return value may have + UUCONF_CMDTABRET_KEEP set, but not UUCONF_CMDTABRET_EXIT. It + assigns values to the elements of qdialer. The first time this is + called, qdialer->uuconf_palloc should be set. This will not set + qdialer->uuconf_zname. */ + +int +_uuconf_idialer_cmd (qglobal, argc, argv, qdialer) + struct sglobal *qglobal; + int argc; + char **argv; + struct uuconf_dialer *qdialer; +{ + struct uuconf_cmdtab as[CDIALER_CMDS]; + int iret; + + _uuconf_ucmdtab_base (asDialer_cmds, CDIALER_CMDS, (char *) qdialer, as); + + iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, + (pointer) qdialer, idcunknown, 0, + qdialer->uuconf_palloc); + + return iret &~ UUCONF_CMDTABRET_EXIT; +} + +/* Reroute a chat script command. */ + +static int +idchat (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_chat *qchat = (struct uuconf_chat *) pvar; + struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; + + return _uuconf_ichat_cmd (qglobal, argc, argv, qchat, + qdialer->uuconf_palloc); +} + +/* Handle the "dtr-toggle" command, which may take two arguments. */ + +/*ARGSUSED*/ +static int +iddtr_toggle (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; + int iret; + + if (argc < 2 || argc > 3) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + iret = _uuconf_iboolean (qglobal, argv[1], &qdialer->uuconf_fdtr_toggle); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + return iret; + + if (argc < 3) + return iret; + + iret |= _uuconf_iboolean (qglobal, argv[2], + &qdialer->uuconf_fdtr_toggle_wait); + + return iret; +} + +/* Handle the "complete" and "abort" commands. These just turn a + string into a trivial chat script. */ + +/*ARGSUSED*/ +static int +idcomplete (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_chat *qchat = (struct uuconf_chat *) pvar; + struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; + char *azargs[3]; + + azargs[0] = (char *) "complete-chat"; + azargs[1] = (char *) "\"\""; + azargs[2] = (char *) argv[1]; + + return _uuconf_ichat_cmd (qglobal, 3, azargs, qchat, + qdialer->uuconf_palloc); +} + +/* Handle the "protocol-parameter" command. */ + +static int +idproto_param (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; + struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; + + return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, + qdialer->uuconf_palloc); +} + +/* Give an error for an unknown dialer command. */ + +/*ARGSUSED*/ +static int +idcunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; +} diff --git a/gnu/libexec/uucp/libuuconf/tdnams.c b/gnu/libexec/uucp/libuuconf/tdnams.c new file mode 100644 index 0000000000..d9e4b0d7e3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tdnams.c @@ -0,0 +1,119 @@ +/* tdnams.c + Get all known dialer names from the Taylor UUCP configuration files. + + 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_tdnams_rcsid[] = "$Id: tdnams.c,v 1.1 1993/08/04 19:35:10 jtc Exp $"; +#endif + +#include + +static int indialer P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); + +/* Get the names of all the dialers from the Taylor UUCP configuration + files. */ + +int +uuconf_taylor_dialer_names (pglobal, ppzdialers) + pointer pglobal; + char ***ppzdialers; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_cmdtab as[2]; + char **pz; + int iret; + + *ppzdialers = NULL; + + as[0].uuconf_zcmd = "dialer"; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; + as[0].uuconf_pvar = (pointer) ppzdialers; + as[0].uuconf_pifn = indialer; + + as[1].uuconf_zcmd = NULL; + + iret = UUCONF_SUCCESS; + + for (pz = qglobal->qprocess->pzdialfiles; *pz != NULL; pz++) + { + FILE *e; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, + (uuconf_cmdtabfn) NULL, + UUCONF_CMDTABFLAG_BACKSLASH, + (pointer) NULL); + + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + break; + } + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = *pz; + return iret | UUCONF_ERROR_FILENAME; + } + + if (*ppzdialers == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzdialers, (pointer) NULL); + + return UUCONF_SUCCESS; +} + +/* Add a dialer name to the list. */ + +/*ARGSUSED*/ +static int +indialer (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char ***ppzdialers = (char ***) pvar; + int iret; + + iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, TRUE, ppzdialers, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/tgcmp.c b/gnu/libexec/uucp/libuuconf/tgcmp.c new file mode 100644 index 0000000000..9bc8de2b5f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tgcmp.c @@ -0,0 +1,42 @@ +/* tgcmp.c + A comparison function for grades for _uuconf_time_parse. + + 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_tgcmp_rcsid[] = "$Id: tgcmp.c,v 1.1 1993/08/04 19:35:11 jtc Exp $"; +#endif + +/* A comparison function to pass to _uuconf_itime_parse. This + compares grades. We can't just pass uuconf_grade_cmp, since + _uuconf_itime_parse wants a function takes longs as arguments. */ + +int +_uuconf_itime_grade_cmp (i1, i2) + long i1; + long i2; +{ + return UUCONF_GRADE_CMP ((int) i1, (int) i2); +} diff --git a/gnu/libexec/uucp/libuuconf/thread.c b/gnu/libexec/uucp/libuuconf/thread.c new file mode 100644 index 0000000000..92f100bba2 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/thread.c @@ -0,0 +1,70 @@ +/* thread.c + Initialize for a new thread. + + 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_thread_rcsid[] = "$Id: thread.c,v 1.1 1993/08/04 19:35:11 jtc Exp $"; +#endif + +#include + +/* Initialize for a new thread, by allocating a new sglobal structure + which points to the same sprocess structure. */ + +int +uuconf_init_thread (ppglobal) + pointer *ppglobal; +{ + struct sglobal **pqglob = (struct sglobal **) ppglobal; + pointer pblock; + struct sglobal *qnew; + + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + (*pqglob)->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + qnew = (struct sglobal *) uuconf_malloc (pblock, + sizeof (struct sglobal)); + if (qnew == NULL) + { + (*pqglob)->ierrno = errno; + uuconf_free_block (pblock); + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + qnew->pblock = pblock; + qnew->ierrno = 0; + qnew->ilineno = 0; + qnew->zfilename = NULL; + qnew->qprocess = (*pqglob)->qprocess; + + *pqglob = qnew; + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/time.c b/gnu/libexec/uucp/libuuconf/time.c new file mode 100644 index 0000000000..6f316828a3 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/time.c @@ -0,0 +1,406 @@ +/* time.c + Parse a time string into a uuconf_timespan structure. + + 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_time_rcsid[] = "$Id: time.c,v 1.1 1993/08/04 19:35:12 jtc Exp $"; +#endif + +#include +#include + +static int itadd_span P((struct sglobal *qglobal, int istart, int iend, + long ival, int cretry, + int (*picmp) P((long, long)), + struct uuconf_timespan **pqspan, + pointer pblock)); +static int itnew P((struct sglobal *qglobal, struct uuconf_timespan **pqset, + struct uuconf_timespan *qnext, int istart, int iend, + long ival, int cretry, pointer pblock)); + +/* An array of weekday abbreviations. The code below assumes that + each one starts with a lower case letter. */ + +static const struct +{ + const char *zname; + int imin; + int imax; +} asTdays[] = +{ + { "any", 0, 6 }, + { "wk", 1, 5 }, + { "su", 0, 0 }, + { "mo", 1, 1 }, + { "tu", 2, 2 }, + { "we", 3, 3 }, + { "th", 4, 4 }, + { "fr", 5, 5 }, + { "sa", 6, 6 }, + { "never", -1, -2 }, + { NULL, 0, 0 } +}; + +/* Parse a time string and add it to a span list. This function is + given the value, the retry time, and the comparison function to + use. */ + +int +_uuconf_itime_parse (qglobal, ztime, ival, cretry, picmp, pqspan, pblock) + struct sglobal *qglobal; + char *ztime; + long ival; + int cretry; + int (*picmp) P((long, long)); + struct uuconf_timespan **pqspan; + pointer pblock; +{ + struct uuconf_timespan *qlist; + char bfirst; + const char *z; + + qlist = *pqspan; + if (qlist == (struct uuconf_timespan *) &_uuconf_unset) + qlist = NULL; + + /* Expand the string using a timetable. Keep rechecking the string + until it does not match. */ + while (TRUE) + { + char **pz; + char *zfound; + + bfirst = *ztime; + if (isupper (BUCHAR (bfirst))) + bfirst = tolower (BUCHAR (bfirst)); + + zfound = NULL; + pz = qglobal->qprocess->pztimetables; + + /* We want the last timetable to have been defined with this + name, so we always look through the entire table. */ + while (*pz != NULL) + { + if ((bfirst == (*pz)[0] + || (isupper (BUCHAR ((*pz)[0])) + && bfirst == tolower (BUCHAR ((*pz)[0])))) + && strcasecmp (ztime, *pz) == 0) + zfound = pz[1]; + pz += 2; + } + if (zfound == NULL) + break; + ztime = zfound; + } + + /* Look through the time string. */ + z = ztime; + while (*z != '\0') + { + int iday; + boolean afday[7]; + int istart, iend; + + if (*z == ',' || *z == '|') + ++z; + if (*z == '\0' || *z == ';') + break; + + for (iday = 0; iday < 7; iday++) + afday[iday] = FALSE; + + /* Get the days. */ + do + { + bfirst = *z; + if (isupper (BUCHAR (bfirst))) + bfirst = tolower (BUCHAR (bfirst)); + for (iday = 0; asTdays[iday].zname != NULL; iday++) + { + size_t clen; + + if (bfirst != asTdays[iday].zname[0]) + continue; + + clen = strlen (asTdays[iday].zname); + if (strncasecmp (z, asTdays[iday].zname, clen) == 0) + { + int iset; + + for (iset = asTdays[iday].imin; + iset <= asTdays[iday].imax; + iset++) + afday[iset] = TRUE; + z += clen; + break; + } + } + if (asTdays[iday].zname == NULL) + return UUCONF_SYNTAX_ERROR; + } + while (isalpha (BUCHAR (*z))); + + /* Get the hours. */ + if (! isdigit (BUCHAR (*z))) + { + istart = 0; + iend = 24 * 60; + } + else + { + char *zendnum; + + istart = (int) strtol ((char *) z, &zendnum, 10); + if (*zendnum != '-' || ! isdigit (BUCHAR (zendnum[1]))) + return UUCONF_SYNTAX_ERROR; + z = zendnum + 1; + iend = (int) strtol ((char *) z, &zendnum, 10); + z = zendnum; + + istart = (istart / 100) * 60 + istart % 100; + iend = (iend / 100) * 60 + iend % 100; + } + + /* Add the times we've found onto the list. */ + for (iday = 0; iday < 7; iday++) + { + if (afday[iday]) + { + int iminute, iret; + + iminute = iday * 24 * 60; + if (istart < iend) + iret = itadd_span (qglobal, iminute + istart, + iminute + iend, ival, cretry, picmp, + &qlist, pblock); + else + { + /* Wrap around midnight. */ + iret = itadd_span (qglobal, iminute, iminute + iend, + ival, cretry, picmp, &qlist, pblock); + if (iret == UUCONF_SUCCESS) + iret = itadd_span (qglobal, iminute + istart, + iminute + 24 * 60, ival, cretry, + picmp, &qlist, pblock); + } + + if (iret != UUCONF_SUCCESS) + return iret; + } + } + } + + *pqspan = qlist; + + return UUCONF_SUCCESS; +} + +/* Add a time span to an existing list of time spans. We keep the + list sorted by time to make this operation easier. This modifies + the existing list, and returns the modified version. It takes a + comparison function which should return < 0 if the first argument + should take precedence over the second argument and == 0 if they + are the same (for grades this is igradecmp; for sizes it is minus + (the binary operator)). */ + +static int +itadd_span (qglobal, istart, iend, ival, cretry, picmp, pqspan, pblock) + struct sglobal *qglobal; + int istart; + int iend; + long ival; + int cretry; + int (*picmp) P((long, long)); + struct uuconf_timespan **pqspan; + pointer pblock; +{ + struct uuconf_timespan **pq; + int iret; + + /* istart < iend */ + for (pq = pqspan; *pq != NULL; pq = &(*pq)->uuconf_qnext) + { + int icmp; + + /* Invariant: PREV (*pq) == NULL || PREV (*pq)->iend <= istart */ + /* istart < iend && (*pq)->istart < (*pq)->iend */ + + if (iend <= (*pq)->uuconf_istart) + { + /* istart < iend <= (*pq)->istart < (*pq)->iend */ + /* No overlap, and we're at the right spot. See if we can + combine these spans. */ + if (iend == (*pq)->uuconf_istart + && cretry == (*pq)->uuconf_cretry + && (*picmp) (ival, (*pq)->uuconf_ival) == 0) + { + (*pq)->uuconf_istart = istart; + return UUCONF_SUCCESS; + } + /* We couldn't combine them. */ + break; + } + + if ((*pq)->uuconf_iend <= istart) + { + /* (*pq)->istart < (*pq)->iend <= istart < iend */ + /* No overlap. Try attaching this span. */ + if ((*pq)->uuconf_iend == istart + && (*pq)->uuconf_cretry == cretry + && ((*pq)->uuconf_qnext == NULL + || iend <= (*pq)->uuconf_qnext->uuconf_istart) + && (*picmp) (ival, (*pq)->uuconf_ival) == 0) + { + (*pq)->uuconf_iend = iend; + return UUCONF_SUCCESS; + } + /* Couldn't attach; keep looking for the right spot. We + might be able to combine part of the new span onto an + existing span, but it's probably not worth it. */ + continue; + } + + /* istart < iend + && (*pq)->istart < (*pq)->iend + && istart < (*pq)->iend + && (*pq)->istart < iend */ + /* Overlap. */ + + icmp = (*picmp) (ival, (*pq)->uuconf_ival); + + if (icmp == 0) + { + /* Just expand the old span to include the new span. */ + if (istart < (*pq)->uuconf_istart) + (*pq)->uuconf_istart = istart; + if ((*pq)->uuconf_iend >= iend) + return UUCONF_SUCCESS; + if ((*pq)->uuconf_qnext == NULL + || iend <= (*pq)->uuconf_qnext->uuconf_istart) + { + (*pq)->uuconf_iend = iend; + return UUCONF_SUCCESS; + } + /* The span we are adding overlaps the next span as well. + Expand the old span up to the next old span, and keep + trying to add the new span. */ + (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart; + istart = (*pq)->uuconf_iend; + } + else if (icmp < 0) + { + /* Replace the old span with the new span. */ + if ((*pq)->uuconf_istart < istart) + { + /* Save the initial portion of the old span. */ + iret = itnew (qglobal, pq, *pq, (*pq)->uuconf_istart, istart, + (*pq)->uuconf_ival, (*pq)->uuconf_cretry, + pblock); + if (iret != UUCONF_SUCCESS) + return iret; + pq = &(*pq)->uuconf_qnext; + } + if (iend < (*pq)->uuconf_iend) + { + /* Save the final portion of the old span. */ + iret = itnew (qglobal, &(*pq)->uuconf_qnext, + (*pq)->uuconf_qnext, iend, (*pq)->uuconf_iend, + (*pq)->uuconf_ival, (*pq)->uuconf_cretry, + pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + (*pq)->uuconf_ival = ival; + (*pq)->uuconf_istart = istart; + (*pq)->uuconf_cretry = cretry; + if ((*pq)->uuconf_qnext == NULL + || iend <= (*pq)->uuconf_qnext->uuconf_istart) + { + (*pq)->uuconf_iend = iend; + return UUCONF_SUCCESS; + } + /* Move this span up to the next one, and keep trying to add + the new span. */ + (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart; + istart = (*pq)->uuconf_iend; + } + else + { + /* Leave the old span untouched. */ + if (istart < (*pq)->uuconf_istart) + { + /* Put in the initial portion of the new span. */ + iret = itnew (qglobal, pq, *pq, istart, (*pq)->uuconf_istart, + ival, cretry, pblock); + if (iret != UUCONF_SUCCESS) + return iret; + pq = &(*pq)->uuconf_qnext; + } + if (iend <= (*pq)->uuconf_iend) + return UUCONF_SUCCESS; + /* Keep trying to add the new span. */ + istart = (*pq)->uuconf_iend; + } + } + + /* This is the spot for the new span, and there's no overlap. */ + + return itnew (qglobal, pq, *pq, istart, iend, ival, cretry, pblock); +} + +/* A utility function to create a new uuconf_timespan structure. */ + +static int +itnew (qglobal, pqset, qnext, istart, iend, ival, cretry, pblock) + struct sglobal *qglobal; + struct uuconf_timespan **pqset; + struct uuconf_timespan *qnext; + int istart; + int iend; + long ival; + int cretry; + pointer pblock; +{ + register struct uuconf_timespan *qnew; + + qnew = ((struct uuconf_timespan *) + uuconf_malloc (pblock, sizeof (struct uuconf_timespan))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + qnew->uuconf_qnext = qnext; + qnew->uuconf_istart = istart; + qnew->uuconf_iend = iend; + qnew->uuconf_ival = ival; + qnew->uuconf_cretry = cretry; + + *pqset = qnew; + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/tinit.c b/gnu/libexec/uucp/libuuconf/tinit.c new file mode 100644 index 0000000000..829fd12285 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tinit.c @@ -0,0 +1,370 @@ +/* tinit.c + Initialize for reading Taylor UUCP configuration files. + + 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_tinit_rcsid[] = "$Id: tinit.c,v 1.1 1993/08/04 19:35:14 jtc Exp $"; +#endif + +#include + +/* Local functions. */ + +static int itset_default P((struct sglobal *qglobal, char ***ppzvar, + const char *zfile)); +static int itadd P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int itunknown P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int itprogram P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); + +static const struct cmdtab_offset asCmds[] = +{ + { "nodename", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zlocalname), NULL }, + { "hostname", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zlocalname), NULL }, + { "uuname", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zlocalname), NULL }, + { "spool", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zspooldir), NULL }, + { "pubdir", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zpubdir), NULL }, + { "lockdir", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zlockdir), NULL }, + { "logfile", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zlogfile), NULL }, + { "statfile", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zstatsfile), NULL }, + { "debugfile", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zdebugfile), NULL }, + { "debug", UUCONF_CMDTABTYPE_STRING, + offsetof (struct sprocess, zdebug), NULL }, + { "max-uuxqts", UUCONF_CMDTABTYPE_INT, + offsetof (struct sprocess, cmaxuuxqts), NULL }, + { "sysfile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzsysfiles), itadd }, + { "portfile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzportfiles), itadd }, + { "dialfile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzdialfiles), itadd }, + { "dialcodefile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzdialcodefiles), itadd }, + { "callfile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzcallfiles), itadd }, + { "passwdfile", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct sprocess, pzpwdfiles), itadd }, + { "unknown", UUCONF_CMDTABTYPE_FN, offsetof (struct sprocess, qunknown), + itunknown }, + { "v2-files", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct sprocess, fv2), NULL }, + { "hdb-files", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct sprocess, fhdb), NULL }, + { "bnu-files", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct sprocess, fhdb), NULL }, + { "timetable", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct sprocess, pztimetables), _uuconf_itimetable }, + { NULL, 0, 0, NULL } +}; + +#define CCMDS (sizeof asCmds / sizeof asCmds[0]) + +/* This structure is used to pass information into the command table + functions. */ + +struct sinfo +{ + /* The program name. */ + const char *zname; + /* A pointer to the command table being used, passed to isystem so + it can call uuconf_cmd_args. */ + struct uuconf_cmdtab *qcmds; +}; + +/* Initialize the routines which read the Taylor UUCP configuration + files. */ + +int +uuconf_taylor_init (ppglobal, zprogram, zname) + pointer *ppglobal; + const char *zprogram; + const char *zname; +{ + struct sglobal **pqglobal = (struct sglobal **) ppglobal; + int iret; + char *zcopy; + struct sglobal *qglobal; + boolean fdefault; + FILE *e; + struct sinfo si; + + if (*pqglobal == NULL) + { + iret = _uuconf_iinit_global (pqglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + qglobal = *pqglobal; + + if (zname != NULL) + { + size_t csize; + + csize = strlen (zname) + 1; + zcopy = uuconf_malloc (qglobal->pblock, csize); + if (zcopy == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) zcopy, (pointer) zname, csize); + fdefault = FALSE; + } + else + { + zcopy = uuconf_malloc (qglobal->pblock, + sizeof NEWCONFIGLIB + sizeof CONFIGFILE - 1); + if (zcopy == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + memcpy ((pointer) zcopy, (pointer) NEWCONFIGLIB, + sizeof NEWCONFIGLIB - 1); + memcpy ((pointer) (zcopy + sizeof NEWCONFIGLIB - 1), + (pointer) CONFIGFILE, sizeof CONFIGFILE); + fdefault = TRUE; + } + + qglobal->qprocess->zconfigfile = zcopy; + + e = fopen (zcopy, "r"); + if (e == NULL) + { + if (! fdefault) + { + qglobal->ierrno = errno; + qglobal->zfilename = zcopy; + return (UUCONF_FOPEN_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_FILENAME); + } + + /* There is no config file, so just use the default values. */ + } + else + { + struct uuconf_cmdtab as[CCMDS]; + + _uuconf_ucmdtab_base (asCmds, CCMDS, (char *) qglobal->qprocess, + as); + + if (zprogram == NULL) + zprogram = "uucp"; + + si.zname = zprogram; + si.qcmds = as; + iret = uuconf_cmd_file (qglobal, e, as, (pointer) &si, itprogram, + UUCONF_CMDTABFLAG_BACKSLASH, + qglobal->pblock); + + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = zcopy; + return iret | UUCONF_ERROR_FILENAME; + } + } + + /* Get the defaults for the file names. */ + + iret = itset_default (qglobal, &qglobal->qprocess->pzsysfiles, SYSFILE); + if (iret != UUCONF_SUCCESS) + return iret; + iret = itset_default (qglobal, &qglobal->qprocess->pzportfiles, PORTFILE); + if (iret != UUCONF_SUCCESS) + return iret; + iret = itset_default (qglobal, &qglobal->qprocess->pzdialfiles, DIALFILE); + if (iret != UUCONF_SUCCESS) + return iret; + iret = itset_default (qglobal, &qglobal->qprocess->pzdialcodefiles, + DIALCODEFILE); + if (iret != UUCONF_SUCCESS) + return iret; + iret = itset_default (qglobal, &qglobal->qprocess->pzpwdfiles, PASSWDFILE); + if (iret != UUCONF_SUCCESS) + return iret; + iret = itset_default (qglobal, &qglobal->qprocess->pzcallfiles, CALLFILE); + if (iret != UUCONF_SUCCESS) + return iret; + + return UUCONF_SUCCESS; +} + +/* Add new strings to a variable. */ + +/*ARGSUSED*/ +static int +itadd (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char ***ppz = (char ***) pvar; + int i; + int iret; + + if (argc == 1) + { + iret = _uuconf_iadd_string (qglobal, NULL, FALSE, FALSE, ppz, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + else + { + for (i = 1; i < argc; i++) + { + iret = _uuconf_iadd_string (qglobal, argv[i], TRUE, FALSE, ppz, + qglobal->pblock); + if (iret != UUCONF_SUCCESS) + return iret; + } + } + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle an "unknown" command. We accumulate this into a linked + list, and only parse them later in uuconf_unknown_system_info. */ + +/*ARGSUSED*/ +static int +itunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sunknown **pq = (struct sunknown **) pvar; + struct sunknown *q; + + q = (struct sunknown *) uuconf_malloc (qglobal->pblock, + sizeof (struct sunknown)); + if (q == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + q->qnext = NULL; + q->ilineno = qglobal->ilineno; + q->cargs = argc - 1; + q->pzargs = (char **) uuconf_malloc (qglobal->pblock, + (argc - 1) * sizeof (char *)); + if (q->pzargs == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + memcpy ((pointer) q->pzargs, (pointer) (argv + 1), + (argc - 1) * sizeof (char *)); + + while (*pq != NULL) + pq = &(*pq)->qnext; + + *pq = q; + + return UUCONF_CMDTABRET_KEEP; +} + +/* If we encounter an unknown command, see if it is the program with + which we were invoked. If it was, pass the remaining arguments + back through the table. */ + +/*ARGSUSED*/ +static int +itprogram (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + + if (argc <= 1 + || strcasecmp (qinfo->zname, argv[0]) != 0) + return UUCONF_CMDTABRET_CONTINUE; + + return uuconf_cmd_args (pglobal, argc - 1, argv + 1, qinfo->qcmds, + (pointer) NULL, (uuconf_cmdtabfn) NULL, 0, + qglobal->pblock); +} + +/* If a filename was not set by the configuration file, add in the + default value. */ + +static int +itset_default (qglobal, ppzvar, zfile) + struct sglobal *qglobal; + char ***ppzvar; + const char *zfile; +{ + size_t clen; + char *zadd; + + if (*ppzvar != NULL) + return UUCONF_SUCCESS; + + clen = strlen (zfile); + zadd = (char *) uuconf_malloc (qglobal->pblock, + sizeof NEWCONFIGLIB + clen); + if (zadd == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + memcpy ((pointer) zadd, (pointer) NEWCONFIGLIB, sizeof NEWCONFIGLIB - 1); + memcpy ((pointer) (zadd + sizeof NEWCONFIGLIB - 1), (pointer) zfile, + clen + 1); + + return _uuconf_iadd_string (qglobal, zadd, FALSE, FALSE, ppzvar, + qglobal->pblock); +} diff --git a/gnu/libexec/uucp/libuuconf/tlocnm.c b/gnu/libexec/uucp/libuuconf/tlocnm.c new file mode 100644 index 0000000000..bf09446e8f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tlocnm.c @@ -0,0 +1,112 @@ +/* tlocnm.c + Get the local name to use from the Taylor UUCP configuration files. + + 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_tlocnm_rcsid[] = "$Id: tlocnm.c,v 1.1 1993/08/04 19:35:14 jtc Exp $"; +#endif + +#include + +/* Get the local name to use, based on the login name, from the Taylor + UUCP configuration files. This could probably be done in a + slightly more intelligent fashion, but no matter what it has to + read the systems files. */ + +int +uuconf_taylor_login_localname (pglobal, zlogin, pzname) + pointer pglobal; + const char *zlogin; + char **pzname; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pznames, **pz; + int iret; + + if (! qglobal->qprocess->fread_syslocs) + { + iret = _uuconf_iread_locations (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* As a simple optimization, if there is no "myname" command we can + simply return immediately. */ + if (! qglobal->qprocess->fuses_myname) + { + *pzname = NULL; + return UUCONF_NOT_FOUND; + } + + iret = uuconf_taylor_system_names (pglobal, &pznames, 0); + if (iret != UUCONF_SUCCESS) + return iret; + + *pzname = NULL; + iret = UUCONF_NOT_FOUND; + + for (pz = pznames; *pz != NULL; pz++) + { + struct uuconf_system ssys; + struct uuconf_system *qsys; + + iret = uuconf_system_info (pglobal, *pz, &ssys); + if (iret != UUCONF_SUCCESS) + break; + + for (qsys = &ssys; qsys != NULL; qsys = qsys->uuconf_qalternate) + { + if (qsys->uuconf_zlocalname != NULL + && qsys->uuconf_fcalled + && qsys->uuconf_zcalled_login != NULL + && strcmp (qsys->uuconf_zcalled_login, zlogin) == 0) + { + *pzname = strdup (qsys->uuconf_zlocalname); + if (*pzname != NULL) + iret = UUCONF_SUCCESS; + else + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + break; + } + } + + (void) uuconf_system_free (pglobal, &ssys); + + if (qsys != NULL) + break; + + iret = UUCONF_NOT_FOUND; + } + + for (pz = pznames; *pz != NULL; pz++) + free ((pointer) *pz); + free ((pointer) pznames); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/tport.c b/gnu/libexec/uucp/libuuconf/tport.c new file mode 100644 index 0000000000..0a94a81c11 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tport.c @@ -0,0 +1,295 @@ +/* tport.c + Find a port in the Taylor UUCP configuration files. + + 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_tport_rcsid[] = "$Id: tport.c,v 1.1 1993/08/04 19:35:15 jtc Exp $"; +#endif + +#include + +static int ipport P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int ipunknown P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* Find a port in the Taylor UUCP configuration files by name, baud + rate, and special purpose function. */ + +int +uuconf_taylor_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, + qport) + pointer pglobal; + const char *zname; + long ibaud; + long ihighbaud; + int (*pifn) P((struct uuconf_port *, pointer)); + pointer pinfo; + struct uuconf_port *qport; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + FILE *e; + pointer pblock; + char *zfree; + int iret; + char **pz; + + if (ihighbaud == 0L) + ihighbaud = ibaud; + + e = NULL; + pblock = NULL; + zfree = NULL; + iret = UUCONF_NOT_FOUND; + + for (pz = qglobal->qprocess->pzportfiles; *pz != NULL; pz++) + { + struct uuconf_cmdtab as[2]; + char *zport; + struct uuconf_port sdefault; + int ilineno; + + e = fopen (*pz, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + continue; + qglobal->ierrno = errno; + iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + qglobal->ilineno = 0; + + /* Gather the default information from the top of the file. We + do this by handling the "port" command ourselves and passing + every other command to _uuconf_iport_cmd via ipunknown. The + value of zport will be an malloc block. */ + as[0].uuconf_zcmd = "port"; + as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; + as[0].uuconf_pvar = (pointer) &zport; + as[0].uuconf_pifn = ipport; + + as[1].uuconf_zcmd = NULL; + + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + _uuconf_uclear_port (&sdefault); + sdefault.uuconf_palloc = pblock; + zport = NULL; + iret = uuconf_cmd_file (pglobal, e, as, (pointer) &sdefault, + ipunknown, UUCONF_CMDTABFLAG_BACKSLASH, + pblock); + if (iret != UUCONF_SUCCESS) + { + zfree = zport; + break; + } + + /* Now skip until we find a port with a matching name. If the + zname argument is NULL, we will have to read every port. */ + iret = UUCONF_NOT_FOUND; + while (zport != NULL) + { + uuconf_cmdtabfn piunknown; + boolean fmatch; + + if (zname == NULL || strcmp (zname, zport) == 0) + { + piunknown = ipunknown; + *qport = sdefault; + qport->uuconf_zname = zport; + zfree = zport; + fmatch = TRUE; + } + else + { + piunknown = NULL; + free ((pointer) zport); + fmatch = FALSE; + } + + zport = NULL; + ilineno = qglobal->ilineno; + iret = uuconf_cmd_file (pglobal, e, as, (pointer) qport, + piunknown, UUCONF_CMDTABFLAG_BACKSLASH, + pblock); + qglobal->ilineno += ilineno; + if (iret != UUCONF_SUCCESS) + break; + iret = UUCONF_NOT_FOUND; + + /* We may have just gathered information about a port. See + if it matches the name, the baud rate and the special + function. */ + if (fmatch) + { + if (ibaud != 0) + { + if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) + { + long imbaud, imhigh, imlow; + + imbaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud; + imhigh = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud; + imlow = qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud; + + if (imbaud == 0 && imlow == 0) + ; + else if (ibaud <= imbaud && imbaud <= ihighbaud) + ; + else if (imlow != 0 + && imlow <= ihighbaud + && imhigh >= ibaud) + ; + else + fmatch = FALSE; + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) + { + long idbaud; + + idbaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; + if (idbaud != 0 && idbaud != ibaud) + fmatch = FALSE; + } + } + } + + if (fmatch) + { + if (pifn != NULL) + { + iret = (*pifn) (qport, pinfo); + if (iret == UUCONF_NOT_FOUND) + fmatch = FALSE; + else if (iret != UUCONF_SUCCESS) + break; + } + } + + if (fmatch) + { + if (uuconf_add_block (pblock, zfree) == 0) + { + zfree = NULL; + iret = UUCONF_SUCCESS; + } + else + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + break; + } + + if (zfree != NULL) + { + free ((pointer) zfree); + zfree = NULL; + } + } + + (void) fclose (e); + e = NULL; + + if (iret != UUCONF_NOT_FOUND) + break; + + uuconf_free_block (pblock); + pblock = NULL; + } + + if (e != NULL) + (void) fclose (e); + if (zfree != NULL) + free ((pointer) zfree); + if (iret != UUCONF_SUCCESS && pblock != NULL) + uuconf_free_block (pblock); + + if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) + { + qglobal->zfilename = *pz; + iret |= UUCONF_ERROR_FILENAME; + } + + return iret; +} + +/* Handle a "port" command. This copies the string onto the heap and + returns the pointer in *pvar. It returns UUCONF_CMDTABRET_EXIT to + force uuconf_cmd_file to stop reading and return to the code above, + which will then check the port just read to see if it matches. */ + +/*ARGSUSED*/ +static int +ipport (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + char **pz = (char **) pvar; + size_t csize; + + csize = strlen (argv[1]) + 1; + *pz = malloc (csize); + if (*pz == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + memcpy ((pointer) *pz, (pointer) argv[1], csize); + return UUCONF_CMDTABRET_EXIT; +} + +/* Handle an unknown command by passing it on to _uuconf_iport_cmd, + which will parse it into the port structure. */ + +/*ARGSUSED*/ +static int +ipunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_port *qport = (struct uuconf_port *) pinfo; + + return _uuconf_iport_cmd (qglobal, argc, argv, qport); +} diff --git a/gnu/libexec/uucp/libuuconf/tportc.c b/gnu/libexec/uucp/libuuconf/tportc.c new file mode 100644 index 0000000000..7b796eacb0 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tportc.c @@ -0,0 +1,465 @@ +/* tportc.c + Handle a Taylor UUCP port command. + + 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_tportc_rcsid[] = "$Id: tportc.c,v 1.1 1993/08/04 19:35:16 jtc Exp $"; +#endif + +#include + +static int ipproto_param P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int ipbaud_range P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int ipdialer P((pointer pglobal, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int ipcunknown P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* The string names of the port types. This array corresponds to the + uuconf_porttype enumeration. */ + +static const char * const azPtype_names[] = +{ + NULL, + "stdin", + "modem", + "direct", + "tcp", + "tli" +}; + +#define CPORT_TYPES (sizeof azPtype_names / sizeof azPtype_names[0]) + +/* The command table for generic port commands. The "port" and "type" + commands are handled specially. */ +static const struct cmdtab_offset asPort_cmds[] = +{ + { "protocol", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_zprotocols), NULL }, + { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_port, uuconf_qproto_params), ipproto_param }, + { "seven-bit", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_iseven_bit }, + { "reliable", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_ireliable }, + { "half-duplex", UUCONF_CMDTABTYPE_FN | 2, + offsetof (struct uuconf_port, uuconf_ireliable), + _uuconf_ihalf_duplex }, + { "lockname", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_zlockname), NULL }, + { NULL, 0, 0, NULL } +}; + +#define CPORT_CMDS (sizeof asPort_cmds / sizeof asPort_cmds[0]) + +/* The stdin port command table. */ +static const struct cmdtab_offset asPstdin_cmds[] = +{ + { NULL, 0, 0, NULL } +}; + +#define CSTDIN_CMDS (sizeof asPstdin_cmds / sizeof asPstdin_cmds[0]) + +/* The modem port command table. */ +static const struct cmdtab_offset asPmodem_cmds[] = +{ + { "device", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_zdevice), + NULL }, + { "baud", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), + NULL }, + { "speed", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), + NULL }, + { "baud-range", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, + { "speed-range", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, + { "carrier", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fcarrier), + NULL }, + { "dial-device", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, + uuconf_u.uuconf_smodem.uuconf_zdial_device), + NULL }, + { "dialer", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipdialer }, + { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_pzdialer), + NULL }, + { NULL, 0, 0, NULL } +}; + +#define CMODEM_CMDS (sizeof asPmodem_cmds / sizeof asPmodem_cmds[0]) + +/* The direct port command table. */ +static const struct cmdtab_offset asPdirect_cmds[] = +{ + { "device", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_zdevice), + NULL }, + { "baud", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), + NULL }, + { "speed", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), + NULL }, + { NULL, 0, 0, NULL } +}; + +#define CDIRECT_CMDS (sizeof asPdirect_cmds / sizeof asPdirect_cmds[0]) + +/* The TCP port command table. */ +static const struct cmdtab_offset asPtcp_cmds[] = +{ + { "service", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport), + NULL }, + { NULL, 0, 0, NULL } +}; + +#define CTCP_CMDS (sizeof asPtcp_cmds / sizeof asPtcp_cmds[0]) + +/* The TLI port command table. */ +static const struct cmdtab_offset asPtli_cmds[] = +{ + { "device", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zdevice), + NULL }, + { "stream", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_fstream), + NULL }, + { "push", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzpush), + NULL }, + { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzdialer), + NULL }, + { "server-address", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zservaddr), + NULL }, + { NULL, 0, 0, NULL } +}; + +#define CTLI_CMDS (sizeof asPtli_cmds / sizeof asPtli_cmds[0]) + +#undef max +#define max(i1, i2) ((i1) > (i2) ? (i1) : (i2)) +#define CCMDS \ + max (max (max (CPORT_CMDS, CSTDIN_CMDS), CMODEM_CMDS), \ + max (max (CDIRECT_CMDS, CTCP_CMDS), CTLI_CMDS)) + +/* Handle a command passed to a port from a Taylor UUCP configuration + file. This can be called when reading either the port file or the + sys file. The return value may have UUCONF_CMDTABRET_KEEP set, but + not UUCONF_CMDTABRET_EXIT. It assigns values to the elements of + qport. The first time this is called, qport->uuconf_zname and + qport->uuconf_palloc should be set and qport->uuconf_ttype should + be UUCONF_PORTTYPE_UNKNOWN. */ + +int +_uuconf_iport_cmd (qglobal, argc, argv, qport) + struct sglobal *qglobal; + int argc; + char **argv; + struct uuconf_port *qport; +{ + boolean fgottype; + const struct cmdtab_offset *qcmds; + size_t ccmds; + struct uuconf_cmdtab as[CCMDS]; + int i; + int iret; + + fgottype = strcasecmp (argv[0], "type") == 0; + + if (fgottype || qport->uuconf_ttype == UUCONF_PORTTYPE_UNKNOWN) + { + enum uuconf_porttype ttype; + + /* We either just got a "type" command, or this is an + uninitialized port. If the first command to a port is not + "type", it is assumed to be a modem port. This + implementation will actually permit "type" at any point, but + will effectively discard any type specific information that + appears before the "type" command. This supports defaults, + in that the default may be of a specific type while future + ports in the same file may be of other types. */ + if (! fgottype) + ttype = UUCONF_PORTTYPE_MODEM; + else + { + if (argc != 2) + return UUCONF_SYNTAX_ERROR; + + for (i = 0; i < CPORT_TYPES; i++) + if (azPtype_names[i] != NULL + && strcasecmp (argv[1], azPtype_names[i]) == 0) + break; + + if (i >= CPORT_TYPES) + return UUCONF_SYNTAX_ERROR; + + ttype = (enum uuconf_porttype) i; + } + + qport->uuconf_ttype = ttype; + + switch (ttype) + { + default: + case UUCONF_PORTTYPE_STDIN: + break; + case UUCONF_PORTTYPE_MODEM: + qport->uuconf_u.uuconf_smodem.uuconf_zdevice = NULL; + qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; + qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; + qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; + break; + case UUCONF_PORTTYPE_DIRECT: + qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL; + qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = -1; + break; + case UUCONF_PORTTYPE_TCP: + qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp"; + qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED + | UUCONF_RELIABLE_ENDTOEND + | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX); + break; + case UUCONF_PORTTYPE_TLI: + qport->uuconf_u.uuconf_stli.uuconf_zdevice = NULL; + qport->uuconf_u.uuconf_stli.uuconf_fstream = FALSE; + qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL; + qport->uuconf_u.uuconf_stli.uuconf_pzdialer = NULL; + qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL; + qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED + | UUCONF_RELIABLE_ENDTOEND + | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX); + break; + } + + if (fgottype) + return UUCONF_CMDTABRET_CONTINUE; + } + + /* See if this command is one of the generic ones. */ + qcmds = asPort_cmds; + ccmds = CPORT_CMDS; + + for (i = 0; i < CPORT_CMDS - 1; i++) + if (strcasecmp (argv[0], asPort_cmds[i].zcmd) == 0) + break; + + if (i >= CPORT_CMDS - 1) + { + /* It's not a generic command, so we must check the type + specific commands. */ + switch (qport->uuconf_ttype) + { + case UUCONF_PORTTYPE_STDIN: + qcmds = asPstdin_cmds; + ccmds = CSTDIN_CMDS; + break; + case UUCONF_PORTTYPE_MODEM: + qcmds = asPmodem_cmds; + ccmds = CMODEM_CMDS; + break; + case UUCONF_PORTTYPE_DIRECT: + qcmds = asPdirect_cmds; + ccmds = CDIRECT_CMDS; + break; + case UUCONF_PORTTYPE_TCP: + qcmds = asPtcp_cmds; + ccmds = CTCP_CMDS; + break; + case UUCONF_PORTTYPE_TLI: + qcmds = asPtli_cmds; + ccmds = CTLI_CMDS; + break; + default: + return UUCONF_SYNTAX_ERROR; + } + } + + /* Copy the command table onto the stack and modify it to point to + qport. */ + _uuconf_ucmdtab_base (qcmds, ccmds, (char *) qport, as); + + iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, + (pointer) qport, ipcunknown, 0, + qport->uuconf_palloc); + + return iret &~ UUCONF_CMDTABRET_EXIT; +} + +/* Handle the "protocol-parameter" command. */ + +static int +ipproto_param (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; + struct uuconf_port *qport = (struct uuconf_port *) pinfo; + + return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, + qport->uuconf_palloc); +} + +/* Handle the "baud-range" command. */ + +/*ARGSUSED*/ +static int +ipbaud_range (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; + int iret; + + iret = _uuconf_iint (qglobal, argv[1], + (pointer) &qmodem->uuconf_ilowbaud, FALSE); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + return iret; + + iret |= _uuconf_iint (qglobal, argv[2], + (pointer) &qmodem->uuconf_ihighbaud, FALSE); + + return iret; +} + +/* Handle the "dialer" command. If there is one argument, this names + a dialer. Otherwise, the remaining arguments form a command + describing the dialer. */ + +static int +ipdialer (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; + struct uuconf_port *qport = (struct uuconf_port *) pinfo; + int iret; + + if (argc < 2) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (argc > 2) + { + if (qmodem->uuconf_qdialer == NULL) + { + struct uuconf_dialer *qnew; + size_t clen; + + qnew = ((struct uuconf_dialer *) + uuconf_malloc (qport->uuconf_palloc, + sizeof (struct uuconf_dialer))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + _uuconf_uclear_dialer (qnew); + + clen = strlen (qport->uuconf_zname); + qnew->uuconf_zname = (char *) uuconf_malloc (qport->uuconf_palloc, + (clen + + sizeof " dialer")); + if (qnew->uuconf_zname == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + memcpy ((pointer) qnew->uuconf_zname, + (pointer) qport->uuconf_zname, clen); + memcpy ((pointer) (qnew->uuconf_zname + clen), (pointer) " dialer", + sizeof " dialer"); + + qnew->uuconf_palloc = qport->uuconf_palloc; + + qmodem->uuconf_qdialer = qnew; + } + + iret = _uuconf_idialer_cmd (qglobal, argc - 1, argv + 1, + qmodem->uuconf_qdialer); + if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; + } + else + { + qmodem->uuconf_pzdialer = NULL; + iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, + &qmodem->uuconf_pzdialer, + qport->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; + } +} + +/* Give an error for an unknown port command. */ + +/*ARGSUSED*/ +static int +ipcunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; +} diff --git a/gnu/libexec/uucp/libuuconf/tsinfo.c b/gnu/libexec/uucp/libuuconf/tsinfo.c new file mode 100644 index 0000000000..5e31ca2c2d --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tsinfo.c @@ -0,0 +1,922 @@ +/* tsinfo.c + Get information about a system from the Taylor UUCP configuration files. + + 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_tsinfo_rcsid[] = "$Id: tsinfo.c,v 1.1 1993/08/04 19:35:18 jtc Exp $"; +#endif + +#include +#include + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +static void uiset_call P((struct uuconf_system *qsys)); +static int iisizecmp P((long i1, long i2)); + +/* Local functions needed to parse the system information file. */ + +#define CMDTABFN(z) \ + static int z P((pointer, int, char **, pointer, pointer)) + +CMDTABFN (iisystem); +CMDTABFN (iialias); +CMDTABFN (iialternate); +CMDTABFN (iidefault_alternates); +CMDTABFN (iitime); +CMDTABFN (iitimegrade); +CMDTABFN (iisize); +CMDTABFN (iibaud_range); +CMDTABFN (iiport); +CMDTABFN (iichat); +CMDTABFN (iicalled_login); +CMDTABFN (iiproto_param); +CMDTABFN (iirequest); +CMDTABFN (iitransfer); +CMDTABFN (iiforward); +CMDTABFN (iiunknown); + +#undef CMDTABFN + +/* We have to pass a fair amount of information in and out of the + various system commands. Using global variables would make the + code non-reentrant, so we instead pass a pointer to single + structure as the pinfo argument to the system commands. */ + +struct sinfo +{ + /* The system information we're building up. */ + struct uuconf_system *qsys; + /* Whether any alternates have been used. */ + boolean falternates; + /* A list of the previous alternates. */ + struct uuconf_system salternate; + /* Whether to use extra alternates from the file wide defaults. */ + int fdefault_alternates; +}; + +/* The command table for system commands. */ +static const struct cmdtab_offset asIcmds[] = +{ + { "system", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iisystem }, + { "alias", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iialias }, + { "alternate", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iialternate }, + { "default-alternates", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, + iidefault_alternates }, + { "time", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_system, uuconf_qtimegrade), iitime }, + { "timegrade", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_system, uuconf_qtimegrade), iitimegrade }, + { "max-retries", UUCONF_CMDTABTYPE_INT, + offsetof (struct uuconf_system, uuconf_cmax_retries), NULL }, + { "success-wait", UUCONF_CMDTABTYPE_INT, + offsetof (struct uuconf_system, uuconf_csuccess_wait), NULL }, + { "call-timegrade", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_system, uuconf_qcalltimegrade), iitimegrade }, + { "call-local-size", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_system, uuconf_qcall_local_size), iisize }, + { "call-remote-size", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_system, uuconf_qcall_remote_size), iisize }, + { "called-local-size", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_system, uuconf_qcalled_local_size), iisize }, + { "called-remote-size", UUCONF_CMDTABTYPE_FN | 3, + offsetof (struct uuconf_system, uuconf_qcalled_remote_size), iisize }, + { "timetable", UUCONF_CMDTABTYPE_FN | 3, (size_t) -1, _uuconf_itimetable }, + { "baud", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_system, uuconf_ibaud), NULL }, + { "speed", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_system, uuconf_ibaud), NULL }, + { "baud-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range }, + { "speed-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range }, + { "port", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiport }, + { "phone", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zphone), NULL }, + { "address", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zphone), NULL }, + { "chat", UUCONF_CMDTABTYPE_PREFIX | 0, + offsetof (struct uuconf_system, uuconf_schat), iichat }, + { "call-login", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zcall_login), NULL }, + { "call-password", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zcall_password), NULL }, + { "called-login", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_system, uuconf_zcalled_login), iicalled_login }, + { "callback", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_fcallback), NULL }, + { "sequence", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_fsequence), NULL }, + { "protocol", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zprotocols), NULL }, + { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, + offsetof (struct uuconf_system, uuconf_qproto_params), iiproto_param }, + { "called-chat", UUCONF_CMDTABTYPE_PREFIX | 0, + offsetof (struct uuconf_system, uuconf_scalled_chat), iichat }, + { "debug", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zdebug), NULL }, + { "max-remote-debug", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zmax_remote_debug), NULL }, + { "send-request", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_fsend_request), NULL }, + { "receive-request", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_frec_request), NULL }, + { "request", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iirequest }, + { "call-transfer", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_fcall_transfer), NULL }, + { "called-transfer", UUCONF_CMDTABTYPE_BOOLEAN, + offsetof (struct uuconf_system, uuconf_fcalled_transfer), NULL }, + { "transfer", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iitransfer }, + { "local-send", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzlocal_send), NULL }, + { "remote-send", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzremote_send), NULL }, + { "local-receive", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzlocal_receive), NULL }, + { "remote-receive", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzremote_receive), NULL }, + { "command-path", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzpath), NULL }, + { "commands", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzcmds), NULL }, + { "free-space", UUCONF_CMDTABTYPE_LONG, + offsetof (struct uuconf_system, uuconf_cfree_space), NULL }, + { "forward-from", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzforward_from), NULL }, + { "forward-to", UUCONF_CMDTABTYPE_FULLSTRING, + offsetof (struct uuconf_system, uuconf_pzforward_to), NULL }, + { "forward", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiforward }, + { "pubdir", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zpubdir), NULL }, + { "myname", UUCONF_CMDTABTYPE_STRING, + offsetof (struct uuconf_system, uuconf_zlocalname), NULL }, + { NULL, 0, 0, NULL } +}; + +#define CSYSTEM_CMDS (sizeof asIcmds / sizeof asIcmds[0]) + +/* Get information about the system zsystem from the Taylor UUCP + configuration files. Sets *qsys. This does not ensure that all + default information is set. */ + +int +_uuconf_itaylor_system_internal (qglobal, zsystem, qsys) + struct sglobal *qglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + int iret; + struct stsysloc *qloc; + struct uuconf_cmdtab as[CSYSTEM_CMDS]; + struct sinfo si; + struct uuconf_system sdefaults; + + if (! qglobal->qprocess->fread_syslocs) + { + iret = _uuconf_iread_locations (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* Find the system in the list of locations. */ + for (qloc = qglobal->qprocess->qsyslocs; qloc != NULL; qloc = qloc->qnext) + if (qloc->zname[0] == zsystem[0] + && strcmp (qloc->zname, zsystem) == 0) + break; + if (qloc == NULL) + return UUCONF_NOT_FOUND; + + /* If this is an alias, then the real system is the next non-alias + in the list. */ + while (qloc->falias) + { + qloc = qloc->qnext; + if (qloc == NULL) + return UUCONF_NOT_FOUND; + } + + _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as); + + rewind (qloc->e); + + /* Read the file wide defaults from the start of the file. */ + _uuconf_uclear_system (qsys); + + si.qsys = qsys; + si.falternates = FALSE; + si.fdefault_alternates = TRUE; + qsys->uuconf_palloc = uuconf_malloc_block (); + if (qsys->uuconf_palloc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + iret = uuconf_cmd_file ((pointer) qglobal, qloc->e, as, (pointer) &si, + iiunknown, UUCONF_CMDTABFLAG_BACKSLASH, + qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = qloc->zfile; + return iret | UUCONF_ERROR_FILENAME; + } + + if (! si.falternates) + uiset_call (qsys); + else + { + /* Attach the final alternate. */ + iret = iialternate ((pointer) qglobal, 0, (char **) NULL, + (pointer) NULL, (pointer) &si); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* Save off the defaults. */ + sdefaults = *qsys; + + /* Advance to the information for the system we want. */ + if (fseek (qloc->e, qloc->iloc, SEEK_SET) != 0) + { + qglobal->ierrno = errno; + qglobal->zfilename = qloc->zfile; + return (UUCONF_FSEEK_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_FILENAME); + } + + /* Read in the system we want. */ + _uuconf_uclear_system (qsys); + qsys->uuconf_zname = (char *) qloc->zname; + qsys->uuconf_palloc = sdefaults.uuconf_palloc; + + si.falternates = FALSE; + + iret = uuconf_cmd_file (qglobal, qloc->e, as, (pointer) &si, iiunknown, + UUCONF_CMDTABFLAG_BACKSLASH, qsys->uuconf_palloc); + qglobal->ilineno += qloc->ilineno; + + if (iret == UUCONF_SUCCESS) + { + if (! si.falternates) + uiset_call (qsys); + else + iret = iialternate ((pointer) qglobal, 0, (char **) NULL, + (pointer) NULL, (pointer) &si); + } + + /* Merge in the defaults. */ + if (iret == UUCONF_SUCCESS) + iret = _uuconf_isystem_default (qglobal, qsys, &sdefaults, + si.fdefault_alternates); + + /* The first alternate is always available for calling in. */ + if (iret == UUCONF_SUCCESS) + qsys->uuconf_fcalled = TRUE; + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = qloc->zfile; + iret |= UUCONF_ERROR_FILENAME; + } + + return iret; +} + +/* Set the fcall and fcalled field for the system. This marks a + particular alternate for use when calling out or calling in. This + is where we implement the semantics described in the documentation: + a change to a relevant field implies that the alternate is used. + If all the relevant fields are unchanged, the alternate is not + used. */ + +static void +uiset_call (qsys) + struct uuconf_system *qsys; +{ + qsys->uuconf_fcall = + (qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset + || qsys->uuconf_zport != (char *) &_uuconf_unset + || qsys->uuconf_qport != (struct uuconf_port *) &_uuconf_unset + || qsys->uuconf_ibaud >= 0 + || qsys->uuconf_zphone != (char *) &_uuconf_unset + || qsys->uuconf_schat.uuconf_pzchat != (char **) &_uuconf_unset + || qsys->uuconf_schat.uuconf_pzprogram != (char **) &_uuconf_unset); + + qsys->uuconf_fcalled = + qsys->uuconf_zcalled_login != (char *) &_uuconf_unset; +} + +/* Handle the "system" command. Because we skip directly to the + system we want to read, a "system" command means we've reached the + end of it. */ + +static int +iisystem (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_CMDTABRET_EXIT; +} + +/* Handle the "alias" command. */ + +/*ARGSUSED*/ +static int +iialias (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + int iret; + + iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, + &qinfo->qsys->uuconf_pzalias, + qinfo->qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; +} + +/* Handle the "alternate" command. The information just read is in + sIhold. If this is the first "alternate" command for this system, + we save off the current information in sIalternate. Otherwise we + default this information to sIalternate, and then add it to the end + of the list of alternates in sIalternate. */ + +static int +iialternate (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + + uiset_call (qinfo->qsys); + + if (! qinfo->falternates) + { + qinfo->salternate = *qinfo->qsys; + qinfo->falternates = TRUE; + } + else + { + int iret; + struct uuconf_system *qnew, **pq; + + iret = _uuconf_isystem_default (qglobal, qinfo->qsys, + &qinfo->salternate, FALSE); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_EXIT; + qnew = ((struct uuconf_system *) + uuconf_malloc (qinfo->qsys->uuconf_palloc, + sizeof (struct uuconf_system))); + if (qnew == NULL) + { + qglobal->ierrno = errno;; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + *qnew = *qinfo->qsys; + for (pq = &qinfo->salternate.uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qnew; + } + + /* If this is the last alternate command, move the information back + to qinfo->qsys. */ + if (argc == 0) + *qinfo->qsys = qinfo->salternate; + else + { + _uuconf_uclear_system (qinfo->qsys); + qinfo->qsys->uuconf_zname = qinfo->salternate.uuconf_zname; + qinfo->qsys->uuconf_palloc = qinfo->salternate.uuconf_palloc; + if (argc > 1) + { + qinfo->qsys->uuconf_zalternate = argv[1]; + return UUCONF_CMDTABRET_KEEP; + } + } + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the "default-alternates" command. This just takes a boolean + argument which is used to set the fdefault_alternates field of the + sinfo structure. */ + +/*ARGSUSED*/ +static int +iidefault_alternates (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + + return _uuconf_iboolean (qglobal, argv[1], &qinfo->fdefault_alternates); +} + +/* Handle the "time" command. We do this by turning it into a + "timegrade" command with a grade of BGRADE_LOW. The first argument + is a time string, and the optional second argument is the retry + time. */ + +/*ARGSUSED*/ +static int +iitime (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + char *aznew[4]; + char ab[2]; + + if (argc != 2 && argc != 3) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + aznew[0] = argv[0]; + ab[0] = UUCONF_GRADE_LOW; + ab[1] = '\0'; + aznew[1] = ab; + aznew[2] = argv[1]; + if (argc > 2) + aznew[3] = argv[2]; + + return iitimegrade (pglobal, argc + 1, aznew, pvar, pinfo); +} + +/* Handle the "timegrade" command by calling _uuconf_itime_parse with + appropriate ival (the work grade) and cretry (the retry time) + arguments. */ + +static int +iitimegrade (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar; + struct sinfo *qinfo = (struct sinfo *) pinfo; + int cretry; + int iret; + + if (argc < 3 || argc > 4) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (argv[1][1] != '\0' || ! UUCONF_GRADE_LEGAL (argv[1][0])) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + + if (argc == 3) + cretry = 0; + else + { + iret = _uuconf_iint (qglobal, argv[3], (pointer) &cretry, TRUE); + if (iret != UUCONF_SUCCESS) + return iret; + } + + iret = _uuconf_itime_parse (qglobal, argv[2], (long) argv[1][0], + cretry, _uuconf_itime_grade_cmp, pqspan, + qinfo->qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; +} + +/* Handle the "baud-range" command, also known as "speed-range". */ + +static int +iibaud_range (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_system *qsys = (struct uuconf_system *) pvar; + int iret; + + iret = _uuconf_iint (qglobal, argv[1], (pointer) &qsys->uuconf_ibaud, + FALSE); + if (iret != UUCONF_SUCCESS) + return iret; + return _uuconf_iint (qglobal, argv[2], (pointer) &qsys->uuconf_ihighbaud, + FALSE); +} + +/* Handle one of the size commands ("call-local-size", etc.). The + first argument is a number of bytes, and the second argument is a + time string. The pvar argument points to the string array to which + we add this new string. */ + +/*ARGSUSED*/ +static int +iisize (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar; + struct sinfo *qinfo = (struct sinfo *) pinfo; + long ival; + int iret; + + iret = _uuconf_iint (qglobal, argv[1], (pointer) &ival, FALSE); + if (iret != UUCONF_SUCCESS) + return iret; + + iret = _uuconf_itime_parse (qglobal, argv[2], ival, 0, iisizecmp, + pqspan, qinfo->qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; +} + +/* A comparison function for sizes to pass to _uuconf_itime_parse. */ + +static int +iisizecmp (i1, i2) + long i1; + long i2; +{ + /* We can't just return i1 - i2 because that would be a long. */ + if (i1 < i2) + return -1; + else if (i1 == i2) + return 0; + else + return 1; +} + +/* Handle the "port" command. If there is one argument, this names a + port. Otherwise, the remaining arguments form a command describing + the port. */ + +/*ARGSUSED*/ +static int +iiport (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + + if (argc < 2) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + else if (argc == 2) + { + qinfo->qsys->uuconf_zport = argv[1]; + return UUCONF_CMDTABRET_KEEP; + } + else + { + int iret; + + if (qinfo->qsys->uuconf_qport + == (struct uuconf_port *) &_uuconf_unset) + { + struct uuconf_port *qnew; + + qnew = ((struct uuconf_port *) + uuconf_malloc (qinfo->qsys->uuconf_palloc, + sizeof (struct uuconf_port))); + if (qnew == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + _uuconf_uclear_port (qnew); + + if (qinfo->qsys->uuconf_zname == NULL) + qnew->uuconf_zname = (char *) "default system file port"; + else + { + char *zname; + size_t clen; + + clen = strlen (qinfo->qsys->uuconf_zname); + zname = (char *) uuconf_malloc (qinfo->qsys->uuconf_palloc, + clen + sizeof "system port"); + if (zname == NULL) + { + qglobal->ierrno = errno; + return (UUCONF_MALLOC_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_CMDTABRET_EXIT); + } + + memcpy ((pointer) zname, (pointer) "system ", + sizeof "system " - 1); + memcpy ((pointer) (zname + sizeof "system " - 1), + (pointer) qinfo->qsys->uuconf_zname, + clen); + memcpy ((pointer) (zname + sizeof "system " - 1 + clen), + (pointer) " port", sizeof " port"); + + qnew->uuconf_zname = zname; + } + + qnew->uuconf_palloc = qinfo->qsys->uuconf_palloc; + + qinfo->qsys->uuconf_qport = qnew; + } + + iret = _uuconf_iport_cmd (qglobal, argc - 1, argv + 1, + qinfo->qsys->uuconf_qport); + if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; + } +} + +/* Handle the "chat" and "called-chat" set of commands. These just + hand off to the generic chat script function. */ + +static int +iichat (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + struct uuconf_chat *qchat = (struct uuconf_chat *) pvar; + int iret; + + iret = _uuconf_ichat_cmd (qglobal, argc, argv, qchat, + qinfo->qsys->uuconf_palloc); + if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) + iret |= UUCONF_CMDTABRET_EXIT; + return iret; +} + +/* Handle the "called-login" command. This only needs to be in a + function because there can be additional arguments listing the + remote systems which are permitted to use this login name. The + additional arguments are not actually handled here; they are + handled by uuconf_taylor_system_names, which already has to go + through all the system files. */ + +/*ARGSUSED*/ +static int +iicalled_login (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + char **pz = (char **) pvar; + + if (argc < 2) + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; + *pz = argv[1]; + return UUCONF_CMDTABRET_KEEP; +} + +/* Handle the "protocol-parameter" command. This just hands off to + the generic protocol parameter handler. */ + +static int +iiproto_param (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; + struct sinfo *qinfo = (struct sinfo *) pinfo; + + if (*pqparam == (struct uuconf_proto_param *) &_uuconf_unset) + *pqparam = NULL; + return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, + qinfo->qsys->uuconf_palloc); +} + +/* Handle the "request" command. This is equivalent to specifying + both "call-request" and "called-request". */ + +/*ARGSUSED*/ +static int +iirequest (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + int iret; + + iret = _uuconf_iboolean (qglobal, argv[1], + &qinfo->qsys->uuconf_fsend_request); + if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) + qinfo->qsys->uuconf_frec_request = qinfo->qsys->uuconf_fsend_request; + + return iret; +} + +/* Handle the "transfer" command. This is equivalent to specifying + both "call-transfer" and "called-transfer". */ + +/*ARGSUSED*/ +static int +iitransfer (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + int iret; + + iret = _uuconf_iboolean (qglobal, argv[1], + &qinfo->qsys->uuconf_fcall_transfer); + if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) + qinfo->qsys->uuconf_fcalled_transfer = qinfo->qsys->uuconf_fcall_transfer; + + return iret; +} + +/* Handle the "forward" command. This is equivalent to specifying + both "forward-from" and "forward-to". */ + +/*ARGSUSED*/ +static int +iiforward (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct sinfo *qinfo = (struct sinfo *) pinfo; + struct uuconf_system *qsys; + int i; + int iret; + + qsys = qinfo->qsys; + qsys->uuconf_pzforward_from = NULL; + qsys->uuconf_pzforward_to = NULL; + for (i = 1; i < argc; i++) + { + iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE, + &qsys->uuconf_pzforward_to, + qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT; + iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE, + &qsys->uuconf_pzforward_from, + qsys->uuconf_palloc); + if (iret != UUCONF_SUCCESS) + return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT; + } + + return UUCONF_CMDTABRET_KEEP; +} + +/* Handle an unknown command. This should probably be done more + intelligently. */ + +/*ARGSUSED*/ +static int +iiunknown (pglobal, argc, argv, pvar, pinfo) + pointer pglobal; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; +} + +/* Return information for an unknown system. It would be better to + put this in a different file, but it would require breaking several + functions out of this file. Perhaps I will do it sometime. */ + +int +uuconf_taylor_system_unknown (pglobal, qsys) + pointer pglobal; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct uuconf_cmdtab as[CSYSTEM_CMDS]; + struct sinfo si; + struct sunknown *q; + int iret; + + if (qglobal->qprocess->qunknown == NULL) + return UUCONF_NOT_FOUND; + + _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as); + + _uuconf_uclear_system (qsys); + + si.qsys = qsys; + si.falternates = FALSE; + si.fdefault_alternates = TRUE; + qsys->uuconf_palloc = uuconf_malloc_block (); + if (qsys->uuconf_palloc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + for (q = qglobal->qprocess->qunknown; q != NULL; q = q->qnext) + { + iret = uuconf_cmd_args (pglobal, q->cargs, q->pzargs, as, + (pointer) &si, iiunknown, + UUCONF_CMDTABFLAG_BACKSLASH, + qsys->uuconf_palloc); + iret &=~ UUCONF_CMDTABRET_KEEP; + if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) + { + qglobal->zfilename = qglobal->qprocess->zconfigfile; + qglobal->ilineno = q->ilineno; + return ((iret &~ UUCONF_CMDTABRET_EXIT) + | UUCONF_ERROR_FILENAME + | UUCONF_ERROR_LINENO); + } + if ((iret & UUCONF_CMDTABRET_EXIT) != 0) + break; + } + + if (! si.falternates) + uiset_call (qsys); + else + { + iret = iialternate (pglobal, 0, (char **) NULL, (pointer) NULL, + (pointer) &si); + if (iret != UUCONF_SUCCESS) + return iret; + } + + /* The first alternate is always available for calling in. */ + qsys->uuconf_fcalled = TRUE; + + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/tsnams.c b/gnu/libexec/uucp/libuuconf/tsnams.c new file mode 100644 index 0000000000..c0f96e53f6 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tsnams.c @@ -0,0 +1,84 @@ +/* tsnams.c + Get all known system names from the Taylor UUCP configuration files. + + 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_tsnams_rcsid[] = "$Id: tsnams.c,v 1.1 1993/08/04 19:35:19 jtc Exp $"; +#endif + +/* Get all the system names from the Taylor UUCP configuration files. + These were actually already recorded by uuconf_taylor_init, so this + function is pretty simple. */ + +int +uuconf_taylor_system_names (pglobal, ppzsystems, falias) + pointer pglobal; + char ***ppzsystems; + int falias; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + register struct stsysloc *q; + char **pz; + int c, i; + + if (! qglobal->qprocess->fread_syslocs) + { + iret = _uuconf_iread_locations (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + *ppzsystems = NULL; + c = 0; + + for (q = qglobal->qprocess->qsyslocs; q != NULL; q = q->qnext) + { + if (! falias && q->falias) + continue; + + iret = _uuconf_iadd_string (qglobal, (char *) q->zname, TRUE, FALSE, + ppzsystems, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + return iret; + ++c; + } + + /* The order of the qSyslocs list is reversed from the list in the + configuration files. Reverse the returned list in order to make + uuname output more intuitive. */ + pz = *ppzsystems; + for (i = c / 2 - 1; i >= 0; i--) + { + char *zhold; + + zhold = pz[i]; + pz[i] = pz[c - i - 1]; + pz[c - i - 1] = zhold; + } + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/tsys.c b/gnu/libexec/uucp/libuuconf/tsys.c new file mode 100644 index 0000000000..6a1f662109 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tsys.c @@ -0,0 +1,49 @@ +/* tsys.c + User function to get a system from the Taylor UUCP configuration files. + + 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_tsys_rcsid[] = "$Id: tsys.c,v 1.1 1993/08/04 19:35:20 jtc Exp $"; +#endif + +/* Get system information from the Taylor UUCP configuration files. + This is a wrapper for the internal function which makes sure that + every field gets a default value. */ + +int +uuconf_taylor_system_info (pglobal, zsystem, qsys) + pointer pglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + + iret = _uuconf_itaylor_system_internal (qglobal, zsystem, qsys); + if (iret != UUCONF_SUCCESS) + return iret; + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuuconf/tval.c b/gnu/libexec/uucp/libuuconf/tval.c new file mode 100644 index 0000000000..be8769612d --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/tval.c @@ -0,0 +1,71 @@ +/* tval.c + Validate a login name for a system using Taylor UUCP files. + + 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_tval_rcsid[] = "$Id: tval.c,v 1.1 1993/08/04 19:35:21 jtc Exp $"; +#endif + +/* Validate a login name for a system using Taylor UUCP configuration + files. This assumes that the zcalled_login field is either NULL or + "ANY". If makes sure that the login name does not appear in some + other "called-login" command listing systems not including this + one. */ + +int +uuconf_taylor_validate (pglobal, qsys, zlogin) + pointer pglobal; + const struct uuconf_system *qsys; + const char *zlogin; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + struct svalidate *q; + + if (! qglobal->qprocess->fread_syslocs) + { + int iret; + + iret = _uuconf_iread_locations (qglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + for (q = qglobal->qprocess->qvalidate; q != NULL; q = q->qnext) + { + if (strcmp (q->zlogname, zlogin) == 0) + { + char **pz; + + for (pz = q->pzmachines; *pz != NULL; pz++) + if (strcmp (*pz, qsys->uuconf_zname) == 0) + return UUCONF_SUCCESS; + + return UUCONF_NOT_FOUND; + } + } + + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/libuuconf/ugtlin.c b/gnu/libexec/uucp/libuuconf/ugtlin.c new file mode 100644 index 0000000000..88ca350738 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/ugtlin.c @@ -0,0 +1,110 @@ +/* ugtlin.c + Read a line with backslash continuations. + + 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_ugtlin_rcsid[] = "$Id: ugtlin.c,v 1.1 1993/08/04 19:35:22 jtc Exp $"; +#endif + +/* Read a line from a file with backslash continuations. This updates + the qglobal->ilineno count for each additional line it reads. */ + +int +_uuconf_getline (qglobal, pzline, pcline, e) + struct sglobal *qglobal; + char **pzline; + size_t *pcline; + FILE *e; +{ + int ctot; + char *zline; + size_t cline; + + ctot = -1; + + zline = NULL; + cline = 0; + + while (TRUE) + { + int cchars; + + if (ctot < 0) + cchars = getline (pzline, pcline, e); + else + cchars = getline (&zline, &cline, e); + if (cchars < 0) + { + if (zline != NULL) + free ((pointer) zline); + if (ctot >= 0) + return ctot; + else + return cchars; + } + + if (ctot < 0) + ctot = cchars; + else + { + if (*pcline <= ctot + cchars) + { + char *znew; + + if (*pcline > 0) + znew = (char *) realloc ((pointer) *pzline, + (size_t) (ctot + cchars + 1)); + else + znew = (char *) malloc ((size_t) (ctot + cchars + 1)); + if (znew == NULL) + { + free ((pointer) zline); + return -1; + } + *pzline = znew; + *pcline = ctot + cchars + 1; + } + + memcpy ((pointer) ((*pzline) + ctot), (pointer) zline, + (size_t) (cchars + 1)); + ctot += cchars; + } + + if (ctot < 2 + || (*pzline)[ctot - 1] != '\n' + || (*pzline)[ctot - 2] != '\\') + { + if (zline != NULL) + free ((pointer) zline); + return ctot; + } + + ++qglobal->ilineno; + + ctot -= 2; + (*pzline)[ctot] = '\0'; + } +} diff --git a/gnu/libexec/uucp/libuuconf/unk.c b/gnu/libexec/uucp/libuuconf/unk.c new file mode 100644 index 0000000000..565dd270f2 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/unk.c @@ -0,0 +1,70 @@ +/* unk.c + Get information about an unknown system. + + 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_unk_rcsid[] = "$Id: unk.c,v 1.1 1993/08/04 19:35:22 jtc Exp $"; +#endif + +#include + +/* Get information about an unknown system. If we are using + HAVE_TAYLOR_CONFIG, we just use it. Otherwise if we are using + HAVE_HDB_CONFIG, we use it. Otherwise we return a default system. + This isn't right for HAVE_V2_CONFIG, because it is possible to + specify default directories to read and write in USERFILE. + However, I'm not going to bother to write that code unless somebody + actually wants it. */ + +/*ARGSUSED*/ +int +uuconf_system_unknown (pglobal, qsys) + pointer pglobal; + struct uuconf_system *qsys; +{ +#if HAVE_TAYLOR_CONFIG + return uuconf_taylor_system_unknown (pglobal, qsys); +#else /* ! HAVE_TAYLOR_CONFIG */ +#if HAVE_HDB_CONFIG + return uuconf_hdb_system_unknown (pglobal, qsys); +#else /* ! HAVE_HDB_CONFIG */ +#if HAVE_V2_CONFIG + struct sglobal *qglobal = (struct sglobal *) pglobal; + + _uuconf_uclear_system (qsys); + qsys->uuconf_palloc = uuconf_malloc_block (); + if (qsys->uuconf_palloc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + return _uuconf_isystem_basic_default (qglobal, qsys); +#else /* ! HAVE_V2_CONFIG */ + return UUCONF_NOT_FOUND; +#endif /* ! HAVE_V2_CONFIG */ +#endif /* ! HAVE_HDB_CONFIG */ +#endif /* ! HAVE_TAYLOR_CONFIG */ +} diff --git a/gnu/libexec/uucp/libuuconf/uucnfi.h b/gnu/libexec/uucp/libuuconf/uucnfi.h new file mode 100644 index 0000000000..9ce6a62dc7 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/uucnfi.h @@ -0,0 +1,368 @@ +/* uucnfi.h + Internal header file for the uuconf package. + + 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 is the internal header file for the uuconf package. It should + not be included by anything other than the uuconf code itself. */ + +/* Get all the general definitions. */ +#include "uucp.h" + +/* Get the uuconf header file itself. */ +#include "uuconf.h" + +/* We need the system dependent header file. */ +#include "syshdr.h" + +/* This is the generic information structure. This holds all the + per-thread global information needed by the uuconf code. The + per-process global information is held in an sprocess structure, + which this structure points to. This permits the code to not have + any global variables at all. */ + +struct sglobal +{ + /* A pointer to the per-process global information. */ + struct sprocess *qprocess; + /* A memory block in which all the memory for these fields is + allocated. */ + pointer pblock; + /* The value of errno after an error. */ + int ierrno; + /* The filename for which an error occurred. */ + const char *zfilename; + /* The line number at which an error occurred. */ + int ilineno; +}; + +/* This is the per-process information structure. This essentially + holds all the global variables used by uuconf. */ + +struct sprocess +{ + /* The name of the local machine. This will be NULL if it is not + specified in a configuration file. */ + const char *zlocalname; + /* The spool directory. */ + const char *zspooldir; + /* The default public directory. */ + const char *zpubdir; + /* The lock directory. */ + const char *zlockdir; + /* The log file. */ + const char *zlogfile; + /* The statistics file. */ + const char *zstatsfile; + /* The debugging file. */ + const char *zdebugfile; + /* The default debugging level. */ + const char *zdebug; + /* The maximum number of simultaneously executing uuxqts. */ + int cmaxuuxqts; + /* Whether we are reading the V2 configuration files. */ + boolean fv2; + /* Whether we are reading the HDB configuration files. */ + boolean fhdb; + /* The names of the dialcode files. */ + char **pzdialcodefiles; + /* Timetables. These are in pairs. The first element is the name, + the second is the time string. */ + char **pztimetables; + + /* Taylor UUCP config file name. */ + char *zconfigfile; + /* Taylor UUCP sys file names. */ + char **pzsysfiles; + /* Taylor UUCP port file names. */ + char **pzportfiles; + /* Taylor UUCP dial file names. */ + char **pzdialfiles; + /* Taylor UUCP passwd file names. */ + char **pzpwdfiles; + /* Taylor UUCP call file names. */ + char **pzcallfiles; + /* List of "unknown" commands from config file. */ + struct sunknown *qunknown; + /* Whether the Taylor UUCP system information locations have been + read. */ + boolean fread_syslocs; + /* Taylor UUCP system information locations. */ + struct stsysloc *qsyslocs; + /* Taylor UUCP validation restrictions. */ + struct svalidate *qvalidate; + /* Whether the "myname" command is used in a Taylor UUCP file. */ + boolean fuses_myname; + + /* V2 system file name (L.sys). */ + char *zv2systems; + /* V2 device file name (L-devices). */ + char *zv2devices; + /* V2 user permissions file name (USERFILE). */ + char *zv2userfile; + /* V2 user permitted commands file (L.cmds). */ + char *zv2cmds; + + /* HDB system file names (Systems). */ + char **pzhdb_systems; + /* HDB device file names (Devices). */ + char **pzhdb_devices; + /* HDB dialer file names (Dialers). */ + char **pzhdb_dialers; + /* Whether the HDB Permissions file has been read. */ + boolean fhdb_read_permissions; + /* The HDB Permissions file entries. */ + struct shpermissions *qhdb_permissions; +}; + +/* This structure is used to hold the "unknown" commands from the + Taylor UUCP config file before they have been parsed. */ + +struct sunknown +{ + /* Next element in linked list. */ + struct sunknown *qnext; + /* Line number in config file. */ + int ilineno; + /* Number of arguments. */ + int cargs; + /* Arguments. */ + char **pzargs; +}; + +/* This structure is used to hold the locations of systems within the + Taylor UUCP sys files. */ + +struct stsysloc +{ + /* Next element in linked list. */ + struct stsysloc *qnext; + /* System name. */ + const char *zname; + /* Whether system is an alias or a real system. If this is an + alias, the real system is the next entry in the linked list which + is not an alias. */ + boolean falias; + /* File name (one of the sys files). */ + const char *zfile; + /* Open file. */ + FILE *e; + /* Location within file (from ftell). */ + long iloc; + /* Line number within file. */ + int ilineno; +}; + +/* This structure is used to hold validation restrictions. This is a + list of machines which are permitted to use a particular login + name. If a machine logs in, and there is no called login entry for + it, the login name and machine name must be passed to + uuconf_validate to confirm that either there is no entry for this + login name or that the machine name appears on the entry. */ + +struct svalidate +{ + /* Next element in linked list. */ + struct svalidate *qnext; + /* Login name. */ + const char *zlogname; + /* NULL terminated list of machine names. */ + char **pzmachines; +}; + +/* This structure is used to hold a linked list of HDB Permissions + file entries. */ + +struct shpermissions +{ + /* Next entry in linked list. */ + struct shpermissions *qnext; + /* NULL terminated array of LOGNAME values. */ + char **pzlogname; + /* NULL terminated array of MACHINE values. */ + char **pzmachine; + /* Boolean REQUEST value. */ + int frequest; + /* Boolean SENDFILES value ("call" is taken as "no"). */ + int fsendfiles; + /* NULL terminated array of READ values. */ + char **pzread; + /* NULL terminated array of WRITE values. */ + char **pzwrite; + /* Boolean CALLBACK value. */ + int fcallback; + /* NULL terminated array of COMMANDS values. */ + char **pzcommands; + /* NULL terminated array of VALIDATE values. */ + char **pzvalidate; + /* String MYNAME value. */ + char *zmyname; + /* String PUBDIR value. */ + const char *zpubdir; + /* NULL terminated array of ALIAS values. */ + char **pzalias; +}; + +/* This structure is used to build reentrant uuconf_cmdtab tables. + The ioff field is either (size_t) -1 or an offsetof macro. The + table is then copied into a uuconf_cmdtab, except that offsets of + (size_t) -1 are converted to pvar elements of NULL, and other + offsets are converted to an offset off some base address. */ + +struct cmdtab_offset +{ + const char *zcmd; + int itype; + size_t ioff; + uuconf_cmdtabfn pifn; +}; + +/* A value in a uuconf_system structure which holds the address of + this special variable is known to be uninitialized. */ +extern char *_uuconf_unset; + +/* Internal function to read a system from the Taylor UUCP + configuration files. This does not apply the basic defaults. */ +extern int _uuconf_itaylor_system_internal P((struct sglobal *qglobal, + const char *zsystem, + struct uuconf_system *qsys)); + +/* Read the system locations and validation information from the + Taylor UUCP configuration files. This sets the qsyslocs, + qvalidate, and fread_syslocs elements of the global structure. */ +extern int _uuconf_iread_locations P((struct sglobal *qglobal)); + +/* Process a command for a port from a Taylor UUCP file. */ +extern int _uuconf_iport_cmd P((struct sglobal *qglobal, int argc, + char **argv, struct uuconf_port *qport)); + +/* Process a command for a dialer from a Taylor UUCP file. */ +extern int _uuconf_idialer_cmd P((struct sglobal *qglobal, int argc, + char **argv, + struct uuconf_dialer *qdialer)); + +/* Process a command for a chat script from a Taylor UUCP file; this + is also called for HDB or V2 files, with a made up command. */ +extern int _uuconf_ichat_cmd P((struct sglobal *qglobal, int argc, + char **argv, struct uuconf_chat *qchat, + pointer pblock)); + +/* Process a protocol-parameter command from a Taylor UUCP file. */ +extern int _uuconf_iadd_proto_param P((struct sglobal *qglobal, + int argc, char **argv, + struct uuconf_proto_param **pq, + pointer pblock)); + +/* Handle a "seven-bit", "reliable", or "half-duplex" command from a + Taylor UUCP port or dialer file. The pvar field should point to + the ireliable element of the structure. */ +extern int _uuconf_iseven_bit P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +extern int _uuconf_ireliable P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); +extern int _uuconf_ihalf_duplex P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* Internal function to read a system from the V2 configuration files. + This does not apply the basic defaults. */ +extern int _uuconf_iv2_system_internal P((struct sglobal *qglobal, + const char *zsystem, + struct uuconf_system *qsys)); + +/* Internal function to read a system from the HDB configuration + files. This does not apply the basic defaults. */ +extern int _uuconf_ihdb_system_internal P((struct sglobal *qglobal, + const char *zsystem, + struct uuconf_system *qsys)); + +/* Read the HDB Permissions file. */ +extern int _uuconf_ihread_permissions P((struct sglobal *qglobal)); + +/* Initialize the global information structure. */ +extern int _uuconf_iinit_global P((struct sglobal **pqglobal)); + +/* Clear system information. */ +extern void _uuconf_uclear_system P((struct uuconf_system *qsys)); + +/* Default unset aspects of one system to the contents of another. */ +extern int _uuconf_isystem_default P((struct sglobal *qglobal, + struct uuconf_system *q, + struct uuconf_system *qdefault, + boolean faddalternates)); + +/* Put in the basic system defaults. */ +extern int _uuconf_isystem_basic_default P((struct sglobal *qglobal, + struct uuconf_system *qsys)); + +/* Clear port information. */ +extern void _uuconf_uclear_port P((struct uuconf_port *qport)); + +/* Clear dialer information. */ +extern void _uuconf_uclear_dialer P((struct uuconf_dialer *qdialer)); + +/* Add a timetable. */ +extern int _uuconf_itimetable P((pointer pglobal, int argc, char **argv, + pointer pvar, pointer pinfo)); + +/* Parse a time string. */ +extern int _uuconf_itime_parse P((struct sglobal *qglobal, char *ztime, + long ival, int cretry, + int (*picmp) P((long, long)), + struct uuconf_timespan **pqspan, + pointer pblock)); + +/* A grade comparison function to pass to _uuconf_itime_parse. */ +extern int _uuconf_itime_grade_cmp P((long, long)); + +/* Add a string to a NULL terminated list of strings. */ +extern int _uuconf_iadd_string P((struct sglobal *qglobal, + char *zadd, boolean fcopy, + boolean fdupcheck, char ***ppzstrings, + pointer pblock)); + +/* Parse a string into a boolean value. */ +extern int _uuconf_iboolean P((struct sglobal *qglobal, const char *zval, + int *pi)); + +/* Parse a string into an integer value. The argument p is either an + int * or a long *, according to the argument fint. */ +extern int _uuconf_iint P((struct sglobal *qglobal, const char *zval, + pointer p, boolean fint)); + +/* Turn a cmdtab_offset table into a uuconf_cmdtab table. */ +extern void _uuconf_ucmdtab_base P((const struct cmdtab_offset *qoff, + size_t celes, char *pbase, + struct uuconf_cmdtab *qset)); + +/* Merge two memory blocks into one. This cannot fail. */ +extern pointer _uuconf_pmalloc_block_merge P((pointer, pointer)); + +/* A wrapper for getline that continues lines if they end in a + backslash. It needs qglobal so that it can increment ilineno + correctly. */ +extern int _uuconf_getline P((struct sglobal *qglobal, + char **, size_t *, FILE *)); + +/* Split a string into tokens. */ +extern int _uuconf_istrsplit P((char *zline, int bsep, + char ***ppzsplit, size_t *csplit)); diff --git a/gnu/libexec/uucp/libuuconf/val.c b/gnu/libexec/uucp/libuuconf/val.c new file mode 100644 index 0000000000..a4eb30fb67 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/val.c @@ -0,0 +1,46 @@ +/* val.c + Validate a login name for a system. + + 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_val_rcsid[] = "$Id: val.c,v 1.1 1993/08/04 19:35:25 jtc Exp $"; +#endif + +/* Validate a login name for a system. */ + +/*ARGSUSED*/ +int +uuconf_validate (pglobal, qsys, zlogin) + pointer pglobal; + const struct uuconf_system *qsys; + const char *zlogin; +{ +#if HAVE_TAYLOR_CONFIG + return uuconf_taylor_validate (pglobal, qsys, zlogin); +#else + return UUCONF_SUCCESS; +#endif +} diff --git a/gnu/libexec/uucp/libuuconf/vinit.c b/gnu/libexec/uucp/libuuconf/vinit.c new file mode 100644 index 0000000000..20ff5bcb1b --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/vinit.c @@ -0,0 +1,112 @@ +/* vinit.c + Initialize for reading V2 configuration files. + + 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_vinit_rcsid[] = "$Id: vinit.c,v 1.1 1993/08/04 19:35:25 jtc Exp $"; +#endif + +#include + +static int ivinlib P((struct sglobal *qglobal, const char *z, size_t csize, + char **pz)); + +/* Return an allocated buffer holding a file name in OLDCONFIGLIB. + The c argument is the size of z including the trailing null byte, + since this is convenient for both the caller and this function. */ + +static int +ivinlib (qglobal, z, c, pz) + struct sglobal *qglobal; + const char *z; + size_t c; + char **pz; +{ + char *zalc; + + zalc = uuconf_malloc (qglobal->pblock, sizeof OLDCONFIGLIB - 1 + c); + if (zalc == NULL) + { + qglobal->ierrno = errno; + return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + memcpy ((pointer) zalc, (pointer) OLDCONFIGLIB, + sizeof OLDCONFIGLIB - 1); + memcpy ((pointer) (zalc + sizeof OLDCONFIGLIB - 1), (pointer) z, c); + + *pz = zalc; + + return UUCONF_SUCCESS; +} + +/* Initialize the routines which read V2 configuration files. The + only thing we do here is allocate the file names. */ + +int +uuconf_v2_init (ppglobal) + pointer *ppglobal; +{ + struct sglobal **pqglobal = (struct sglobal **) ppglobal; + int iret; + struct sglobal *qglobal; + char *zdialcodes; + + if (*pqglobal == NULL) + { + iret = _uuconf_iinit_global (pqglobal); + if (iret != UUCONF_SUCCESS) + return iret; + } + + qglobal = *pqglobal; + + iret = ivinlib (qglobal, V2_SYSTEMS, sizeof V2_SYSTEMS, + &qglobal->qprocess->zv2systems); + if (iret != UUCONF_SUCCESS) + return iret; + iret = ivinlib (qglobal, V2_DEVICES, sizeof V2_DEVICES, + &qglobal->qprocess->zv2devices); + if (iret != UUCONF_SUCCESS) + return iret; + iret = ivinlib (qglobal, V2_USERFILE, sizeof V2_USERFILE, + &qglobal->qprocess->zv2userfile); + if (iret != UUCONF_SUCCESS) + return iret; + iret = ivinlib (qglobal, V2_CMDS, sizeof V2_CMDS, + &qglobal->qprocess->zv2cmds); + if (iret != UUCONF_SUCCESS) + return iret; + + iret = ivinlib (qglobal, V2_DIALCODES, sizeof V2_DIALCODES, + &zdialcodes); + if (iret != UUCONF_SUCCESS) + return iret; + + return _uuconf_iadd_string (qglobal, zdialcodes, FALSE, FALSE, + &qglobal->qprocess->pzdialcodefiles, + qglobal->pblock); +} diff --git a/gnu/libexec/uucp/libuuconf/vport.c b/gnu/libexec/uucp/libuuconf/vport.c new file mode 100644 index 0000000000..b9382a3861 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/vport.c @@ -0,0 +1,251 @@ +/* vport.c + Find a port in the V2 configuration files. + + 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_vport_rcsid[] = "$Id: vport.c,v 1.1 1993/08/04 19:35:27 jtc Exp $"; +#endif + +#include +#include + +/* Find a port in the V2 configuration files by name, baud rate, and + special purpose function. */ + +int +uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) + pointer pglobal; + const char *zname; + long ibaud; + long ihighbaud; + int (*pifn) P((struct uuconf_port *, pointer)); + pointer pinfo; + struct uuconf_port *qport; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + FILE *e; + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + int iret; + int cchars; + + e = fopen (qglobal->qprocess->zv2devices, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + return UUCONF_NOT_FOUND; + qglobal->ierrno = errno; + qglobal->zfilename = qglobal->qprocess->zv2devices; + return (UUCONF_FOPEN_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_FILENAME); + } + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + + iret = UUCONF_NOT_FOUND; + + qglobal->ilineno = 0; + + while ((cchars = getline (&zline, &cline, e)) > 0) + { + int ctoks; + char *zend; + long ilow, ihigh; + pointer pblock; + + ++qglobal->ilineno; + + iret = UUCONF_NOT_FOUND; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + zline[strcspn (zline, "#")] = '\0'; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + /* An entry in L-devices is + + type device dial-device baud dialer + + The type (normally "ACU") is treated as the name. */ + + /* If there aren't enough entries, ignore the line; this + should probably do something more useful. */ + if (ctoks < 4) + continue; + + /* Make sure the name matches any argument. */ + if (zname != NULL + && strcmp (pzsplit[0], zname) != 0) + continue; + + /* Get the baud rate. */ + ilow = strtol (pzsplit[3], &zend, 10); + if (*zend == '-') + ihigh = strtol (zend + 1, (char **) NULL, 10); + else + ihigh = ilow; + + /* Make sure the baud rate matches any argument. */ + if (ibaud != 0 + && ilow != 0 + && (ilow > ibaud || ihigh < ibaud)) + continue; + + /* Now we must construct the port information, so that we can + pass it to pifn. The port type is determined by it's name, + unfortunately. The name "DIR" is used for a direct port, and + anything else for a modem port. */ + pblock = NULL; + _uuconf_uclear_port (qport); + qport->uuconf_zname = pzsplit[0]; + if (strcmp (pzsplit[0], "DIR") == 0) + { + qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT; + qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1]; + qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow; + } + else + { + qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM; + qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1]; + if (strcmp (pzsplit[2], "-") != 0) + qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = pzsplit[2]; + else + qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; + if (ilow == ihigh) + { + qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow; + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; + } + else + { + qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow; + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh; + } + qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; + if (ctoks < 5) + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; + else + { + size_t c; + char **pzd; + + /* We support dialer/token pairs, although normal V2 + doesn't. */ + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + c = (ctoks - 4) * sizeof (char *); + pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); + if (pzd == NULL) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); + pzd[ctoks - 4] = NULL; + + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd; + } + qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; + } + + if (pifn != NULL) + { + iret = (*pifn) (qport, pinfo); + if (iret != UUCONF_SUCCESS) + { + if (pblock != NULL) + uuconf_free_block (pblock); + if (iret != UUCONF_NOT_FOUND) + break; + continue; + } + } + + /* This is the port we want. */ + if (pblock == NULL) + { + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + } + + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + uuconf_free_block (pblock); + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + zline = NULL; + + qport->uuconf_palloc = pblock; + + break; + } + + (void) fclose (e); + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + + if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) + { + qglobal->zfilename = qglobal->qprocess->zv2devices; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/vsinfo.c b/gnu/libexec/uucp/libuuconf/vsinfo.c new file mode 100644 index 0000000000..c528ce3501 --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/vsinfo.c @@ -0,0 +1,575 @@ +/* vsinfo.c + Get information about a system from the V2 configuration files. + + 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_vsinfo_rcsid[] = "$Id: vsinfo.c,v 1.1 1993/08/04 19:35:28 jtc Exp $"; +#endif + +#include +#include + +/* Get the information for a particular system from the V2 + configuration files. This does not make sure that all the default + values are set. */ + +int +_uuconf_iv2_system_internal (qglobal, zsystem, qsys) + struct sglobal *qglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + char *zline; + size_t cline; + char **pzsplit; + size_t csplit; + char **pzcomma; + size_t ccomma; + FILE *e; + int cchars; + pointer pblock; + int iret; + + e = fopen (qglobal->qprocess->zv2systems, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + return UUCONF_NOT_FOUND; + qglobal->ierrno = errno; + qglobal->zfilename = qglobal->qprocess->zv2systems; + return (UUCONF_FOPEN_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_FILENAME); + } + + zline = NULL; + cline = 0; + pzsplit = NULL; + csplit = 0; + pzcomma = NULL; + ccomma = 0; + + pblock = NULL; + iret = UUCONF_SUCCESS; + + qglobal->ilineno = 0; + + while ((cchars = getline (&zline, &cline, e)) > 0) + { + int ctoks, ctimes, i; + struct uuconf_system *qset; + char *z, *zretry; + int cretry; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + zline[strcspn (zline, "#")] = '\0'; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + /* If this isn't the system we're looking for, keep reading + the file. */ + if (ctoks < 1 + || strcmp (zsystem, pzsplit[0]) != 0) + continue; + + /* If this is the first time we've found the system, we want + to set *qsys directly. Otherwise, we allocate a new + alternate. */ + if (pblock == NULL) + { + pblock = uuconf_malloc_block (); + if (pblock == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + _uuconf_uclear_system (qsys); + qsys->uuconf_palloc = pblock; + qset = qsys; + } + else + { + struct uuconf_system **pq; + + qset = ((struct uuconf_system *) + uuconf_malloc (pblock, sizeof (struct uuconf_system))); + if (qset == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + _uuconf_uclear_system (qset); + for (pq = &qsys->uuconf_qalternate; + *pq != NULL; + pq = &(*pq)->uuconf_qalternate) + ; + *pq = qset; + } + + /* Add this line to the memory block we are building for the + system. */ + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + zline = NULL; + cline = 0; + + /* The format of a line in Systems is + system time device speed phone chat + For example, + airs Any ACU 9600 5551212 ogin: foo pass: bar + */ + + /* Get the system name. */ + + qset->uuconf_zname = pzsplit[0]; + qset->uuconf_fcall = TRUE; + qset->uuconf_fcalled = TRUE; + + if (ctoks < 2) + continue; + + /* A time string is "time/grade,time/grade;retry". A missing + grade is taken as BGRADE_LOW. On some versions the retry + time is actually separated by a comma, which won't work right + here. */ + zretry = strchr (pzsplit[1], ';'); + if (zretry == NULL) + cretry = 0; + else + { + *zretry = '\0'; + cretry = (int) strtol (zretry + 1, (char **) NULL, 10); + } + + ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma); + if (ctimes < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + for (i = 0; i < ctimes; i++) + { + char *zslash; + char bgrade; + + z = pzcomma[i]; + zslash = strchr (z, '/'); + if (zslash == NULL) + bgrade = UUCONF_GRADE_LOW; + else + { + *zslash = '\0'; + bgrade = zslash[1]; + if (! UUCONF_GRADE_LEGAL (bgrade)) + bgrade = UUCONF_GRADE_LOW; + } + + iret = _uuconf_itime_parse (qglobal, z, (long) bgrade, cretry, + _uuconf_itime_grade_cmp, + &qset->uuconf_qtimegrade, + pblock); + if (iret != UUCONF_SUCCESS) + break; + } + + if (iret != UUCONF_SUCCESS) + break; + + if (ctoks < 3) + continue; + + /* Pick up the device name. It can be followed by a comma and a + list of protocols (this is not actually supported by most V2 + systems, but it should be compatible). */ + qset->uuconf_zport = pzsplit[2]; + z = strchr (pzsplit[2], ','); + if (z != NULL) + { + qset->uuconf_zprotocols = z + 1; + *z = '\0'; + } + + /* If the port is "TCP", we set up a system specific port. The + baud rate becomes the service number and the phone number + becomes the address (still stored in qsys->zphone). */ + if (strcmp (qset->uuconf_zport, "TCP") == 0) + { + qset->uuconf_zport = NULL; + qset->uuconf_qport = ((struct uuconf_port *) + uuconf_malloc (pblock, + sizeof (struct uuconf_port))); + if (qset->uuconf_qport == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + _uuconf_uclear_port (qset->uuconf_qport); + qset->uuconf_qport->uuconf_zname = (char *) "TCP"; + qset->uuconf_qport->uuconf_ttype = UUCONF_PORTTYPE_TCP; + qset->uuconf_qport->uuconf_ireliable + = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX + | UUCONF_RELIABLE_SPECIFIED); + if (ctoks < 4) + qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport + = (char *) "uucp"; + else + qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport + = pzsplit[3]; + } + + if (ctoks < 4) + continue; + + qset->uuconf_ibaud = strtol (pzsplit[3], (char **) NULL, 10); + + if (ctoks < 5) + continue; + + /* Get the phone number. */ + qset->uuconf_zphone = pzsplit[4]; + + if (ctoks < 6) + continue; + + /* Get the chat script. We just hand this off to the chat + script processor, so that it will parse subsend and + subexpect strings correctly. */ + pzsplit[4] = (char *) "chat"; + iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4, + &qset->uuconf_schat, pblock); + iret &=~ UUCONF_CMDTABRET_KEEP; + if (iret != UUCONF_SUCCESS) + break; + } + + (void) fclose (e); + + if (pzcomma != NULL) + free ((pointer) pzcomma); + + if (iret != UUCONF_SUCCESS) + { + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + qglobal->zfilename = qglobal->qprocess->zv2systems; + return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + if (pblock == NULL) + { + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + return UUCONF_NOT_FOUND; + } + + /* Now read USERFILE and L.cmds to get permissions. We can't fully + handle USERFILE since that specifies permissions based on local + users which we do not support. */ + { + e = fopen (qglobal->qprocess->zv2userfile, "r"); + if (e != NULL) + { + char **pzlocal, **pzremote; + boolean fdefault_callback; + char *zdefault_login; + struct uuconf_system *q; + + pzlocal = NULL; + pzremote = NULL; + fdefault_callback = FALSE; + zdefault_login = NULL; + + qglobal->ilineno = 0; + + while ((cchars = getline (&zline, &cline, e)) > 0) + { + int ctoks; + char *zcomma; + boolean fcallback; + char **pzlist, **pznew; + + ++qglobal->ilineno; + + --cchars; + if (zline[cchars] == '\n') + zline[cchars] = '\0'; + zline[strcspn (zline, "#")] = '\0'; + + ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + + if (ctoks == 0) + continue; + + /* The first field is username,machinename */ + zcomma = strchr (pzsplit[0], ','); + if (zcomma == NULL) + continue; + + *zcomma++ = '\0'; + + /* The rest of the line is the list of directories, except + that if the first directory is "c" we must call the + system back. */ + fcallback = FALSE; + pzlist = pzsplit + 1; + --ctoks; + if (ctoks > 0 + && pzsplit[1][0] == 'c' + && pzsplit[1][1] == '\0') + { + fcallback = TRUE; + pzlist = pzsplit + 2; + --ctoks; + } + + /* Now pzsplit[0] is the user name, zcomma is the system + name, fcallback indicates whether a call back is + required, ctoks is the number of directories and pzlist + points to the directories. If the system name matches, + then the user name is the name that the system must use + to log in, and the list of directories is what may be + transferred in by either local or remote request. + Otherwise, if no system name matches, then the first + line with no user name gives the list of directories + that may be transferred by local request, and the first + line with no system name gives the list of directories + that may be transferred by remote request. */ + if ((pzsplit[0][0] != '\0' || pzlocal != NULL) + && (zcomma[0] != '\0' || pzremote != NULL) + && strcmp (zcomma, zsystem) != 0) + continue; + + /* NULL terminate the list of directories. */ + pznew = (char **) uuconf_malloc (pblock, + (ctoks + 1) * sizeof (char *)); + if (pznew == NULL) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + memcpy ((pointer) pznew, (pointer) pzlist, + ctoks * sizeof (char *)); + pznew[ctoks] = NULL; + + if (uuconf_add_block (pblock, zline) != 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + break; + } + zline = NULL; + cline = 0; + + if (pzsplit[0][0] == '\0') + { + pzlocal = pznew; + fdefault_callback = fcallback; + } + else if (zcomma[0] == '\0') + { + pzremote = pznew; + zdefault_login = pzsplit[0]; + } + else + { + /* Both the login name and the machine name were + listed; require the machine to be logged in under + this name. This is not fully backward compatible, + and perhaps should be changed. On the other hand, + it is more useful. */ + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + { + q->uuconf_zcalled_login = pzsplit[0]; + q->uuconf_fcallback = fcallback; + q->uuconf_pzlocal_send = pznew; + q->uuconf_pzlocal_receive = pznew; + q->uuconf_pzremote_send = pznew; + q->uuconf_pzremote_receive = pznew; + } + + break; + } + } + + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + { + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + qglobal->zfilename = qglobal->qprocess->zv2userfile; + return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + if (qsys->uuconf_pzlocal_send == (char **) &_uuconf_unset + && pzlocal != NULL) + { + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + { + q->uuconf_fcallback = fdefault_callback; + q->uuconf_pzlocal_send = pzlocal; + q->uuconf_pzlocal_receive = pzlocal; + } + } + + if (qsys->uuconf_pzremote_send == (char **) &_uuconf_unset + && pzremote != NULL) + { + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + { + q->uuconf_zcalled_login = zdefault_login; + q->uuconf_pzremote_send = pzremote; + q->uuconf_pzremote_receive = pzremote; + } + } + } + } + + /* Now we must read L.cmds to determine which commands may be + executed. */ + { + e = fopen (qglobal->qprocess->zv2cmds, "r"); + if (e != NULL) + { + qglobal->ilineno = 0; + + if (getline (&zline, &cline, e) > 0) + { + ++qglobal->ilineno; + + zline[strcspn (zline, "#\n")] = '\0'; + if (strncmp (zline, "PATH=", sizeof "PATH=" - 1) == 0) + { + int ctoks; + char **pznew; + + zline += sizeof "PATH=" - 1; + ctoks = _uuconf_istrsplit (zline, ':', &pzsplit, &csplit); + if (ctoks < 0) + { + qglobal->ierrno = errno; + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + + pznew = NULL; + if (iret == UUCONF_SUCCESS) + { + pznew = ((char **) + uuconf_malloc (pblock, + (ctoks + 1) * sizeof (char *))); + if (pznew == NULL) + iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; + } + if (iret == UUCONF_SUCCESS) + { + memcpy ((pointer) pznew, (pointer) pzsplit, + ctoks * sizeof (char *)); + pznew[ctoks] = NULL; + qsys->uuconf_pzpath = pznew; + zline = NULL; + cline = 0; + } + + if (getline (&zline, &cline, e) < 0) + { + if (zline != NULL) + { + free ((pointer) zline); + zline = NULL; + } + } + else + ++qglobal->ilineno; + } + } + + if (iret == UUCONF_SUCCESS && zline != NULL) + { + while (TRUE) + { + zline[strcspn (zline, "#\n")] = '\0'; + iret = _uuconf_iadd_string (qglobal, zline, TRUE, FALSE, + &qsys->uuconf_pzcmds, + pblock); + if (iret != UUCONF_SUCCESS) + break; + if (getline (&zline, &cline, e) < 0) + break; + ++qglobal->ilineno; + } + } + + (void) fclose (e); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = qglobal->qprocess->zv2cmds; + iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + } + } + + if (zline != NULL) + free ((pointer) zline); + if (pzsplit != NULL) + free ((pointer) pzsplit); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/vsnams.c b/gnu/libexec/uucp/libuuconf/vsnams.c new file mode 100644 index 0000000000..0bf04b581d --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/vsnams.c @@ -0,0 +1,106 @@ +/* vsnams.c + Get all known system names from the V2 configuration files. + + 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_vsnams_rcsid[] = "$Id: vsnams.c,v 1.1 1993/08/04 19:35:29 jtc Exp $"; +#endif + +#include + +/* Get all the system names from the V2 L.sys file. This code does + not support aliases, although some V2 versions do have an L-aliases + file. */ + +/*ARGSUSED*/ +int +uuconf_v2_system_names (pglobal, ppzsystems, falias) + pointer pglobal; + char ***ppzsystems; + int falias; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + FILE *e; + int iret; + char *zline; + size_t cline; + + *ppzsystems = NULL; + + e = fopen (qglobal->qprocess->zv2systems, "r"); + if (e == NULL) + { + if (FNO_SUCH_FILE ()) + return _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzsystems, (pointer) NULL); + qglobal->ierrno = errno; + qglobal->zfilename = qglobal->qprocess->zv2systems; + return (UUCONF_FOPEN_FAILED + | UUCONF_ERROR_ERRNO + | UUCONF_ERROR_FILENAME); + } + + qglobal->ilineno = 0; + iret = UUCONF_SUCCESS; + + zline = NULL; + cline = 0; + while (getline (&zline, &cline, e) > 0) + { + char *zname; + + ++qglobal->ilineno; + + /* Skip leading whitespace to get to the system name. Then cut + the system name off at the first whitespace, comment, or + newline. */ + zname = zline + strspn (zline, " \t"); + zname[strcspn (zname, " \t#\n")] = '\0'; + if (*zname == '\0') + continue; + + iret = _uuconf_iadd_string (qglobal, zname, TRUE, TRUE, ppzsystems, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + break; + } + + (void) fclose (e); + if (zline != NULL) + free ((pointer) zline); + + if (iret != UUCONF_SUCCESS) + { + qglobal->zfilename = qglobal->qprocess->zv2systems; + return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; + } + + if (*ppzsystems == NULL) + iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, + ppzsystems, (pointer) NULL); + + return iret; +} diff --git a/gnu/libexec/uucp/libuuconf/vsys.c b/gnu/libexec/uucp/libuuconf/vsys.c new file mode 100644 index 0000000000..c0280cce3f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/vsys.c @@ -0,0 +1,49 @@ +/* vsys.c + User function to get a system from the V2 configuration files. + + 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_vsys_rcsid[] = "$Id: vsys.c,v 1.1 1993/08/04 19:35:30 jtc Exp $"; +#endif + +/* Get system information from the V2 configuration files. This is a + wrapper for the internal function which makes sure that every field + gets a default value. */ + +int +uuconf_v2_system_info (pglobal, zsystem, qsys) + pointer pglobal; + const char *zsystem; + struct uuconf_system *qsys; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + int iret; + + iret = _uuconf_iv2_system_internal (qglobal, zsystem, qsys); + if (iret != UUCONF_SUCCESS) + return iret; + return _uuconf_isystem_basic_default (qglobal, qsys); +} diff --git a/gnu/libexec/uucp/libuucp/MANIFEST b/gnu/libexec/uucp/libuucp/MANIFEST new file mode 100644 index 0000000000..093924858e --- /dev/null +++ b/gnu/libexec/uucp/libuucp/MANIFEST @@ -0,0 +1,27 @@ +Makefile.in +MANIFEST +bsrch.c +buffer.c +bzero.c +crc.c +debug.c +escape.c +getlin.c +getopt.c +getop1.c +memchr.c +memcmp.c +memcpy.c +parse.c +spool.c +status.c +strcas.c +strchr.c +strdup.c +strncs.c +strrch.c +strstr.c +strtol.c +xfree.c +xmall.c +xreall.c diff --git a/gnu/libexec/uucp/libuucp/Makefile b/gnu/libexec/uucp/libuucp/Makefile new file mode 100644 index 0000000000..6870a6039a --- /dev/null +++ b/gnu/libexec/uucp/libuucp/Makefile @@ -0,0 +1,14 @@ +# This is the Makefile for the libuucp subdirectory of Taylor UUCP +# $Id: Makefile,v 1.2 1993/08/05 16:14:59 jtc Exp $ + +LIB= uucp +SRCS= buffer.o crc.o debug.o escape.o getopt.o getop1.o parse.o \ + spool.o status.o xfree.o xmall.o xreall.o getlin.o +CFLAGS+= -I$(.CURDIR)/../common_sources + +NOMAN= noman +NOPROFILE= noprofile + +install: + +.include diff --git a/gnu/libexec/uucp/libuucp/bsrch.c b/gnu/libexec/uucp/libuucp/bsrch.c new file mode 100644 index 0000000000..3b1a61c170 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/bsrch.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +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. + +This file was modified slightly by Ian Lance Taylor, May 1992, for +Taylor UUCP. */ + +#include "uucp.h" + +/* Perform a binary search for KEY in BASE which has NMEMB elements + of SIZE bytes each. The comparisons are done by (*COMPAR)(). */ +pointer +bsearch (key, base, nmemb, size, compar) + register constpointer key; + register constpointer base; + size_t nmemb; + register size_t size; + register int (*compar) P((constpointer, constpointer)); +{ + register size_t l, u, idx; + register constpointer p; + register int comparison; + + l = 0; + u = nmemb; + while (l < u) + { + idx = (l + u) / 2; + p = (constpointer) (((const char *) base) + (idx * size)); + comparison = (*compar)(key, p); + if (comparison < 0) + u = idx; + else if (comparison > 0) + l = idx + 1; + else + return (pointer) p; + } + + return NULL; +} diff --git a/gnu/libexec/uucp/libuucp/buffer.c b/gnu/libexec/uucp/libuucp/buffer.c new file mode 100644 index 0000000000..c44fa45139 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/buffer.c @@ -0,0 +1,109 @@ +/* buffer.c + Manipulate buffers used to hold strings. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of Taylor UUCP. + + 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 "uucp.h" + +#include "uudefs.h" + +/* We keep a linked list of buffers. The union is a hack because the + default definition of offsetof, in uucp.h, takes the address of the + field, and some C compilers will not let you take the address of an + array. */ + +struct sbuf +{ + struct sbuf *qnext; + size_t c; + union + { + char ab[4]; + char bdummy; + } + u; +}; + +static struct sbuf *qBlist; + +/* Get a buffer of a given size. The buffer is returned with the + ubuffree function. */ + +char * +zbufalc (c) + size_t c; +{ + register struct sbuf *q; + + if (qBlist == NULL) + { + q = (struct sbuf *) xmalloc (sizeof (struct sbuf) + c - 4); + q->c = c; + } + else + { + q = qBlist; + qBlist = q->qnext; + if (q->c < c) + { + q = (struct sbuf *) xrealloc ((pointer) q, + sizeof (struct sbuf) + c - 4); + q->c = c; + } + } + return q->u.ab; +} + +/* Get a buffer holding a given string. */ + +char * +zbufcpy (z) + const char *z; +{ + size_t csize; + char *zret; + + if (z == NULL) + return NULL; + csize = strlen (z) + 1; + zret = zbufalc (csize); + memcpy (zret, z, csize); + return zret; +} + +/* Free up a buffer back onto the linked list. */ + +void +ubuffree (z) + char *z; +{ + size_t ioff; + struct sbuf *q; + + if (z == NULL) + return; + ioff = offsetof (struct sbuf, u); + q = (struct sbuf *) (pointer) (z - ioff); + q->qnext = qBlist; + qBlist = q; +} diff --git a/gnu/libexec/uucp/libuucp/bzero.c b/gnu/libexec/uucp/libuucp/bzero.c new file mode 100644 index 0000000000..098e551572 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/bzero.c @@ -0,0 +1,15 @@ +/* bzero.c + Zero out a buffer. */ + +#include "uucp.h" + +void +bzero (parg, c) + pointer parg; + int c; +{ + char *p = (char *) parg; + + while (c-- != 0) + *p++ = 0; +} diff --git a/gnu/libexec/uucp/libuucp/crc.c b/gnu/libexec/uucp/libuucp/crc.c new file mode 100644 index 0000000000..fc9687b57c --- /dev/null +++ b/gnu/libexec/uucp/libuucp/crc.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* Modified slightly by Ian Lance Taylor, ian@airs.com, for use with + Taylor UUCP. */ + +#include "uucp.h" +#include "prot.h" + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* [this code is no longer present--ian] */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static const unsigned long aicrc32tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, +0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, +0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, +0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, +0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, +0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, +0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, +0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, +0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, +0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, +0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, +0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, +0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, +0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, +0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, +0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, +0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, +0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, +0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, +0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, +0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, +0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, +0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, +0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, +0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, +0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, +0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, +0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, +0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, +0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, +0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, +0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +/* + * IUPDC32 macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First argument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define IUPDC32(b, ick) \ + (aicrc32tab[((int) (ick) ^ (b)) & 0xff] ^ (((ick) >> 8) & 0x00ffffffL)) + +unsigned long +icrc (z, c, ick) + const char *z; + size_t c; + unsigned long ick; +{ + while (c > 4) + { + ick = IUPDC32 (*z++, ick); + ick = IUPDC32 (*z++, ick); + ick = IUPDC32 (*z++, ick); + ick = IUPDC32 (*z++, ick); + c -= 4; + } + while (c-- != 0) + ick = IUPDC32 (*z++, ick); + return ick; +} diff --git a/gnu/libexec/uucp/libuucp/debug.c b/gnu/libexec/uucp/libuucp/debug.c new file mode 100644 index 0000000000..86f784154a --- /dev/null +++ b/gnu/libexec/uucp/libuucp/debug.c @@ -0,0 +1,165 @@ +/* debug.c + UUCP debugging 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" + +#include + +#include "uudefs.h" + +/* The debugging level. */ +int iDebug; + +/* Parse a debugging string. This may be a simple number, which sets + the given number of bits in iDebug, or it may be a series of single + letters. */ + +static const char * const azDebug_names[] = DEBUG_NAMES; + +int +idebug_parse (z) + const char *z; +{ + char *zend; + int i, iret; + char *zcopy, *ztok; + + if (strncasecmp (z, DEBUG_NONE, sizeof DEBUG_NONE - 1) == 0) + return 0; + + i = (int) strtol ((char *) z, &zend, 0); + if (*zend == '\0') + { + if (i > 15) + i = 15; + else if (i < 0) + i = 0; + return (1 << i) - 1; + } + + zcopy = zbufcpy (z); + + iret = 0; + + for (ztok = strtok (zcopy, ","); + ztok != NULL; + ztok = strtok ((char *) NULL, ",")) + { + if (strcasecmp (ztok, "all") == 0) + { + iret = DEBUG_MAX; + break; + } + for (i = 0; azDebug_names[i] != NULL; i++) + { + if (strncasecmp (ztok, azDebug_names[i], + strlen (azDebug_names[i])) == 0) + { + iret |= 1 << i; + break; + } + } + if (azDebug_names[i] == NULL) + ulog (LOG_ERROR, "Unrecognized debugging option \"%s\"", + ztok); + } + + ubuffree (zcopy); + + return iret; +} + +/* A debugging routine used when displaying buffers. */ + +size_t +cdebug_char (z, ichar) + char *z; + int ichar; +{ + char b; + + if (isprint (BUCHAR (ichar)) + && ichar != '\"' + && ichar != '\\') + { + *z++ = (char) ichar; + *z = '\0'; + return 1; + } + + *z++ = '\\'; + + switch (ichar) + { + case '\n': + b = 'n'; + break; + case '\r': + b = 'r'; + break; + case '\"': + b = '\"'; + break; + case '\\': + b = '\\'; + break; + default: + sprintf (z, "%03o", (unsigned int) BUCHAR (ichar)); + return strlen (z) + 1; + } + + *z++ = b; + *z = '\0'; + return 2; +} + +/* Display a buffer when debugging. */ + +void +udebug_buffer (zhdr, zbuf, clen) + const char *zhdr; + const char *zbuf; + size_t clen; +{ + char *z, *zalc; + int i; + + zalc = zbufalc (clen * 4 + 1); + + z = zalc; + for (i = 0; i < clen && i < 80; i++) + z += cdebug_char (z, zbuf[i]); + if (i < clen) + { + *z++ = '.'; + *z++ = '.'; + *z++ = '.'; + } + *z = '\0'; + + ulog (LOG_DEBUG, "%s %lu \"%s\"", zhdr, (unsigned long) clen, zalc); + + ubuffree (zalc); +} diff --git a/gnu/libexec/uucp/libuucp/escape.c b/gnu/libexec/uucp/libuucp/escape.c new file mode 100644 index 0000000000..646b787d6e --- /dev/null +++ b/gnu/libexec/uucp/libuucp/escape.c @@ -0,0 +1,98 @@ +/* escape.c + Translate escape sequences. */ + +#include "uucp.h" + +#include + +#include "uudefs.h" + +size_t +cescape (z) + char *z; +{ + char *zto, *zfrom; + + zto = z; + zfrom = z; + while (*zfrom != '\0') + { + if (*zfrom != '\\') + { + *zto++ = *zfrom++; + continue; + } + ++zfrom; + switch (*zfrom) + { + case '-': + *zto++ = '-'; + break; + case 'b': + *zto++ = '\b'; + break; + case 'n': + *zto++ = '\n'; + break; + case 'N': + *zto++ = '\0'; + break; + case 'r': + *zto++ = '\r'; + break; + case 's': + *zto++ = ' '; + break; + case 't': + *zto++ = '\t'; + break; + case '\0': + --zfrom; + /* Fall through. */ + case '\\': + *zto++ = '\\'; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int i; + + i = *zfrom - '0'; + if (zfrom[1] >= '0' && zfrom[1] <= '7') + i = 8 * i + *++zfrom - '0'; + if (zfrom[1] >= '0' && zfrom[1] <= '7') + i = 8 * i + *++zfrom - '0'; + *zto++ = (char) i; + } + break; + case 'x': + { + int i; + + i = 0; + while (isxdigit (BUCHAR (zfrom[1]))) + { + if (isdigit (BUCHAR (zfrom[1]))) + i = 16 * i + *++zfrom - '0'; + else if (isupper (BUCHAR (zfrom[1]))) + i = 16 * i + *++zfrom - 'A' + 10; + else + i = 16 * i + *++zfrom - 'a' + 10; + } + *zto++ = (char) i; + } + break; + default: + ulog (LOG_ERROR, "Unrecognized escape sequence \\%c", + *zfrom); + *zto++ = *zfrom; + break; + } + + ++zfrom; + } + + *zto = '\0'; + + return (size_t) (zto - z); +} diff --git a/gnu/libexec/uucp/libuucp/getlin.c b/gnu/libexec/uucp/libuucp/getlin.c new file mode 100644 index 0000000000..1c204e74ee --- /dev/null +++ b/gnu/libexec/uucp/libuucp/getlin.c @@ -0,0 +1,81 @@ +/* getlin.c + Replacement for getline. + + Copyright (C) 1992 Ian Lance Taylor + + This file is part of Taylor UUCP. + + 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 "uucp.h" + +/* Read a line from a file, returning the number of characters read. + This should really return ssize_t. Returns -1 on error. */ + +#define CGETLINE_DEFAULT (63) + +int +getline (pzline, pcline, e) + char **pzline; + size_t *pcline; + FILE *e; +{ + char *zput, *zend; + int bchar; + + if (*pzline == NULL) + { + *pzline = (char *) malloc (CGETLINE_DEFAULT); + if (*pzline == NULL) + return -1; + *pcline = CGETLINE_DEFAULT; + } + + zput = *pzline; + zend = *pzline + *pcline - 1; + + while ((bchar = getc (e)) != EOF) + { + if (zput >= zend) + { + size_t cnew; + char *znew; + + cnew = *pcline * 2 + 1; + znew = (char *) realloc ((pointer) *pzline, cnew); + if (znew == NULL) + return -1; + zput = znew + *pcline - 1; + zend = znew + cnew - 1; + *pzline = znew; + *pcline = cnew; + } + + *zput++ = bchar; + + if (bchar == '\n') + break; + } + + if (zput == *pzline) + return -1; + + *zput = '\0'; + return zput - *pzline; +} diff --git a/gnu/libexec/uucp/libuucp/getop1.c b/gnu/libexec/uucp/libuucp/getop1.c new file mode 100644 index 0000000000..c3ebc08bb3 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/getop1.c @@ -0,0 +1,144 @@ +/* Getopt for GNU. + Copyright (C) 1987, 88, 89, 90, 91, 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, June 1992, for + Taylor UUCP. */ + +#include "uucp.h" + +#include "getopt.h" + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/libexec/uucp/libuucp/getopt.c b/gnu/libexec/uucp/libuucp/getopt.c new file mode 100644 index 0000000000..f97c64eda5 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/getopt.c @@ -0,0 +1,621 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 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, June 1992, for + Taylor UUCP. */ + +#include "uucp.h" +#include "uudefs.h" + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +#undef GETOPT_COMPAT + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* 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. */ + +char *optarg = 0; + +/* 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. */ + +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#define my_index strchr +#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + size_t nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); + char **temp = (char **) malloc (nonopts_size); + + if (temp == NULL) + abort (); + + /* Interchange the two blocks of data in ARGV. */ + + my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); + my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], + (optind - last_nonopt) * sizeof (char *)); + my_bcopy ((char *) temp, + (char *) &argv[first_nonopt + optind - last_nonopt], + nonopts_size); + + xfree (temp); + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, (size_t) (s - nextchar))) + { + if (s - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], (unsigned int) c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); + } + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/libexec/uucp/libuucp/memchr.c b/gnu/libexec/uucp/libuucp/memchr.c new file mode 100644 index 0000000000..e1f399afeb --- /dev/null +++ b/gnu/libexec/uucp/libuucp/memchr.c @@ -0,0 +1,149 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. + Based on strlen implemention by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + +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. + +This file was modified slightly by Ian Lance Taylor, May 1992, for +Taylor UUCP. It assumes 32 bit longs. I'm willing to trust that any +system which does not have 32 bit longs will have its own +implementation of memchr. */ + +#include "uucp.h" + +/* Search no more than N bytes of S for C. */ + +pointer +memchr (s, c, n) + constpointer s; + int c; + size_t n; +{ + const char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + + c = BUCHAR (c); + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a 4-byte border. */ + for (char_ptr = s; n > 0 && ((unsigned long int) char_ptr & 3) != 0; + --n, ++char_ptr) + if (BUCHAR (*char_ptr) == c) + return (pointer) char_ptr; + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + magic_bits = 0x7efefeff; + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (n >= 4) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C, not zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *longword_ptr++ ^ charmask; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0) + { + /* Which of the bytes was C? If none of them were, it was + a misfire; continue the search. */ + + const char *cp = (const char *) (longword_ptr - 1); + + if (BUCHAR (cp[0]) == c) + return (pointer) cp; + if (BUCHAR (cp[1]) == c) + return (pointer) &cp[1]; + if (BUCHAR (cp[2]) == c) + return (pointer) &cp[2]; + if (BUCHAR (cp[3]) == c) + return (pointer) &cp[3]; + } + + n -= 4; + } + + char_ptr = (const char *) longword_ptr; + + while (n-- > 0) + { + if (BUCHAR (*char_ptr) == c) + return (pointer) char_ptr; + else + ++char_ptr; + } + + return NULL; +} diff --git a/gnu/libexec/uucp/libuucp/memcmp.c b/gnu/libexec/uucp/libuucp/memcmp.c new file mode 100644 index 0000000000..b61578a4af --- /dev/null +++ b/gnu/libexec/uucp/libuucp/memcmp.c @@ -0,0 +1,19 @@ +/* memcmp.c + Compare two memory buffers. */ + +#include "uucp.h" + +int +memcmp (p1arg, p2arg, c) + constpointer p1arg; + constpointer p2arg; + size_t c; +{ + const char *p1 = (const char *) p1arg; + const char *p2 = (const char *) p2arg; + + while (c-- != 0) + if (*p1++ != *p2++) + return BUCHAR (*--p1) - BUCHAR (*--p2); + return 0; +} diff --git a/gnu/libexec/uucp/libuucp/memcpy.c b/gnu/libexec/uucp/libuucp/memcpy.c new file mode 100644 index 0000000000..2258123752 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/memcpy.c @@ -0,0 +1,18 @@ +/* memcpy.c + Copy one memory buffer to another. */ + +#include "uucp.h" + +pointer +memcpy (ptoarg, pfromarg, c) + pointer ptoarg; + constpointer pfromarg; + size_t c; +{ + char *pto = (char *) ptoarg; + const char *pfrom = (const char *) pfromarg; + + while (c-- != 0) + *pto++ = *pfrom++; + return ptoarg; +} diff --git a/gnu/libexec/uucp/libuucp/parse.c b/gnu/libexec/uucp/libuucp/parse.c new file mode 100644 index 0000000000..6b928a4eed --- /dev/null +++ b/gnu/libexec/uucp/libuucp/parse.c @@ -0,0 +1,207 @@ +/* parse.c + Parse a UUCP command string. + + 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 parse_rcsid[] = "$Id: parse.c,v 1.1 1993/08/04 19:35:49 jtc Exp $"; +#endif + +#include "uudefs.h" + +/* Parse a UUCP command string into an scmd structure. This is called + by the 'g' protocol and the UNIX command file reading routines. It + destroys the string it is passed, and the scmd string pointers are + left pointing into it. For the convenience of the Unix work file + routines, it will parse "P" into a simple 'P' command (representing + a poll file). It returns TRUE if the string is successfully + parsed, FALSE otherwise. */ + +boolean +fparse_cmd (zcmd, qcmd) + char *zcmd; + struct scmd *qcmd; +{ + char *z, *zend; + + z = strtok (zcmd, " \t\n"); + if (z == NULL) + return FALSE; + + qcmd->bcmd = *z; + if (qcmd->bcmd != 'S' + && qcmd->bcmd != 'R' + && qcmd->bcmd != 'X' + && qcmd->bcmd != 'E' + && qcmd->bcmd != 'H' + && qcmd->bcmd != 'P') + return FALSE; + + qcmd->pseq = NULL; + qcmd->zfrom = NULL; + qcmd->zto = NULL; + qcmd->zuser = NULL; + qcmd->zoptions = NULL; + qcmd->ztemp = NULL; + qcmd->imode = 0666; + qcmd->znotify = NULL; + qcmd->cbytes = -1; + qcmd->zcmd = NULL; + qcmd->ipos = 0; + + /* Handle hangup commands specially. If it's just "H", return + the command 'H' to indicate a hangup request. If it's "HY" + return 'Y' and if it's "HN" return 'N'. */ + if (qcmd->bcmd == 'H') + { + if (z[1] != '\0') + { + if (z[1] == 'Y') + qcmd->bcmd = 'Y'; + else if (z[1] == 'N') + qcmd->bcmd = 'N'; + else + return FALSE; + } + + return TRUE; + } + if (qcmd->bcmd == 'P') + return TRUE; + + if (z[1] != '\0') + return FALSE; + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL) + return FALSE; + qcmd->zfrom = z; + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL) + return FALSE; + qcmd->zto = z; + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL) + return FALSE; + qcmd->zuser = z; + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL || *z != '-') + return FALSE; + qcmd->zoptions = z + 1; + + if (qcmd->bcmd == 'X') + return TRUE; + + if (qcmd->bcmd == 'R') + { + z = strtok ((char *) NULL, " \t\n"); + if (z != NULL) + { + if (strcmp (z, "dummy") != 0) + { + /* This may be the maximum number of bytes the remote + system wants to receive, if it using Taylor UUCP size + negotiation. */ + qcmd->cbytes = strtol (z, &zend, 0); + if (*zend != '\0') + qcmd->cbytes = -1; + } + else + { + /* This is from an SVR4 system, and may include the + position at which to start sending the file. The + next fields are the mode bits, the remote owner (?), + the remote temporary file name, and finally the + restart position. */ + if (strtok ((char *) NULL, " \t\n") != NULL + && strtok ((char *) NULL, " \t\n") != NULL + && strtok ((char *) NULL, " \t\n") != NULL) + { + z = strtok ((char *) NULL, " \t\n"); + if (z != NULL) + { + qcmd->ipos = strtol (z, &zend, 0); + if (*zend != '\0') + qcmd->ipos = 0; + } + } + } + } + + return TRUE; + } + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL) + return FALSE; + qcmd->ztemp = z; + + z = strtok ((char *) NULL, " \t\n"); + if (z == NULL) + return FALSE; + qcmd->imode = (int) strtol (z, &zend, 8); + if (*zend != '\0') + return FALSE; + + z = strtok ((char *) NULL, " \t\n"); + if (qcmd->bcmd == 'E' && z == NULL) + return FALSE; + qcmd->znotify = z; + + /* SVR4 UUCP will send the string "dummy" after the notify string + but before the size. I do not know when it sends anything other + than "dummy". Fortunately, it doesn't really hurt to not get the + file size. */ + if (z != NULL && strcmp (z, "dummy") == 0) + z = strtok ((char *) NULL, " \t\n"); + + if (z != NULL) + { + z = strtok ((char *) NULL, " \t\n"); + if (z != NULL) + { + qcmd->cbytes = strtol (z, &zend, 0); + if (*zend != '\0') + qcmd->cbytes = -1; + } + else if (qcmd->bcmd == 'E') + return FALSE; + + if (z != NULL) + { + z = strtok ((char *) NULL, ""); + if (z != NULL) + z[strcspn (z, "\n")] = '\0'; + if (qcmd->bcmd == 'E' && z == NULL) + return FALSE; + qcmd->zcmd = z; + } + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/libuucp/spool.c b/gnu/libexec/uucp/libuucp/spool.c new file mode 100644 index 0000000000..52223fb585 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/spool.c @@ -0,0 +1,30 @@ +/* spool.c + See whether a filename is legal for the spool directory. */ + +#include "uucp.h" + +#include + +#include "uudefs.h" + +/* See whether a file is a spool file. Spool file names are specially + crafted to hand around to other UUCP packages. They always begin + with 'C', 'D' or 'X', and the second character is always a period. + The remaining characters may be any printable characters, since + they may include a grade set by another system. */ + +boolean +fspool_file (zfile) + const char *zfile; +{ + const char *z; + + if (*zfile != 'C' && *zfile != 'D' && *zfile != 'X') + return FALSE; + if (zfile[1] != '.') + return FALSE; + for (z = zfile + 2; *z != '\0'; z++) + if (*z == '/' || ! isprint (BUCHAR (*z)) || isspace (BUCHAR (*z))) + return FALSE; + return TRUE; +} diff --git a/gnu/libexec/uucp/libuucp/status.c b/gnu/libexec/uucp/libuucp/status.c new file mode 100644 index 0000000000..bee5f83dd0 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/status.c @@ -0,0 +1,20 @@ +/* status.c + Strings for status codes. */ + +#include "uucp.h" + +#include "uudefs.h" + +/* Status strings. These must match enum tstatus_type. */ + +const char *azStatus[] = +{ + "Conversation complete", + "Port unavailable", + "Dial failed", + "Login failed", + "Handshake failed", + "Call failed", + "Talking", + "Wrong time to call" +}; diff --git a/gnu/libexec/uucp/libuucp/strcas.c b/gnu/libexec/uucp/libuucp/strcas.c new file mode 100644 index 0000000000..4bb2251129 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strcas.c @@ -0,0 +1,33 @@ +/* strcas.c + Compare two strings case insensitively. */ + +#include "uucp.h" +#include + +int +strcasecmp (z1, z2) + const char *z1; + const char *z2; +{ + char b1, b2; + + while ((b1 = *z1++) != '\0') + { + b2 = *z2++; + if (b2 == '\0') + return 1; + if (b1 != b2) + { + if (isupper (BUCHAR (b1))) + b1 = tolower (BUCHAR (b1)); + if (isupper (BUCHAR (b2))) + b2 = tolower (BUCHAR (b2)); + if (b1 != b2) + return b1 - b2; + } + } + if (*z2 == '\0') + return 0; + else + return -1; +} diff --git a/gnu/libexec/uucp/libuucp/strchr.c b/gnu/libexec/uucp/libuucp/strchr.c new file mode 100644 index 0000000000..ca8d8e9b1b --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strchr.c @@ -0,0 +1,16 @@ +/* strchr.c + Look for a character in a string. This works for a null byte. */ + +#include "uucp.h" + +char * +strchr (z, b) + const char *z; + int b; +{ + b = (char) b; + while (*z != b) + if (*z++ == '\0') + return NULL; + return (char *) z; +} diff --git a/gnu/libexec/uucp/libuucp/strdup.c b/gnu/libexec/uucp/libuucp/strdup.c new file mode 100644 index 0000000000..231e35b3f6 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strdup.c @@ -0,0 +1,18 @@ +/* strdup.c + Duplicate a string into memory. */ + +#include "uucp.h" + +char * +strdup (z) + const char *z; +{ + size_t csize; + char *zret; + + csize = strlen (z) + 1; + zret = malloc (csize); + if (zret != NULL) + memcpy (zret, z, csize); + return zret; +} diff --git a/gnu/libexec/uucp/libuucp/strncs.c b/gnu/libexec/uucp/libuucp/strncs.c new file mode 100644 index 0000000000..6959d625d6 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strncs.c @@ -0,0 +1,39 @@ +/* strncs.c + Compare two strings case insensitively up to a point. */ + +#include "uucp.h" +#include + +int +strncasecmp (z1, z2, c) + const char *z1; + const char *z2; + size_t c; +{ + char b1, b2; + + if (c == 0) + return 0; + while ((b1 = *z1++) != '\0') + { + b2 = *z2++; + if (b2 == '\0') + return 1; + if (b1 != b2) + { + if (isupper (BUCHAR (b1))) + b1 = tolower (BUCHAR (b1)); + if (isupper (BUCHAR (b2))) + b2 = tolower (BUCHAR (b2)); + if (b1 != b2) + return b1 - b2; + } + --c; + if (c == 0) + return 0; + } + if (*z2 == '\0') + return 0; + else + return -1; +} diff --git a/gnu/libexec/uucp/libuucp/strrch.c b/gnu/libexec/uucp/libuucp/strrch.c new file mode 100644 index 0000000000..a88e4b4358 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strrch.c @@ -0,0 +1,24 @@ +/* strrch.c + Look for the last occurrence of a character in a string. This is + supposed to work for a null byte, although we never actually call + it with one. */ + +#include "uucp.h" + +char * +strrchr (z, b) + const char *z; + int b; +{ + char *zret; + + b = (char) b; + zret = NULL; + do + { + if (*z == b) + zret = (char *) z; + } + while (*z++ != '\0'); + return zret; +} diff --git a/gnu/libexec/uucp/libuucp/strstr.c b/gnu/libexec/uucp/libuucp/strstr.c new file mode 100644 index 0000000000..111460b11d --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strstr.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +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. + +This file was modified slightly by Ian Lance Taylor, May 1992, for +Taylor UUCP. */ + +#include "uucp.h" + +/* Return the first ocurrence of NEEDLE in HAYSTACK. */ +char * +strstr (haystack, needle) + const char *const haystack; + const char *const needle; +{ + register const char *const needle_end = strchr(needle, '\0'); + register const char *const haystack_end = strchr(haystack, '\0'); + register const size_t needle_len = needle_end - needle; + register const size_t needle_last = needle_len - 1; + register const char *begin; + + if (needle_len == 0) + return (char *) haystack_end; + if ((size_t) (haystack_end - haystack) < needle_len) + return NULL; + + for (begin = &haystack[needle_last]; begin < haystack_end; ++begin) + { + register const char *n = &needle[needle_last]; + register const char *h = begin; + do + if (*h != *n) + goto loop; + while (--n >= needle && --h >= haystack); + + return (char *) h; + loop:; + } + + return NULL; +} diff --git a/gnu/libexec/uucp/libuucp/strtol.c b/gnu/libexec/uucp/libuucp/strtol.c new file mode 100644 index 0000000000..f663994bf9 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/strtol.c @@ -0,0 +1,175 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +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. + +This file was modified slightly by Ian Lance Taylor, May 1992, for +Taylor UUCP. */ + +#include "uucp.h" + +#include +#include + +#if HAVE_LIMITS_H +#include +#else +#define ULONG_MAX 4294967295 +#define LONG_MIN (- LONG_MAX - 1) +#define LONG_MAX 2147483647 +#endif + +#ifndef UNSIGNED +#define UNSIGNED 0 +#endif + +/* Convert NPTR to an `unsigned long int' or `long int' in base BASE. + If BASE is 0 the base is determined by the presence of a leading + zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. + If BASE is < 2 or > 36, it is reset to 10. + If ENDPTR is not NULL, a pointer to the character after the last + one converted is stored in *ENDPTR. */ +#if UNSIGNED +unsigned long int +#define strtol strtoul +#else +long int +#endif +strtol (nptr, endptr, base) + const char *nptr; + char **endptr; + int base; +{ + int negative; + register unsigned long int cutoff; + register unsigned int cutlim; + register unsigned long int i; + register const char *s; + register unsigned int c; + const char *save; + int overflow; + + if (base < 0 || base == 1 || base > 36) + base = 10; + + s = nptr; + + /* Skip white space. */ + while (isspace(BUCHAR (*s))) + ++s; + if (*s == '\0') + goto noconv; + + /* Check for a sign. */ + if (*s == '-') + { + negative = 1; + ++s; + } + else if (*s == '+') + { + negative = 0; + ++s; + } + else + negative = 0; + + if (base == 16 + && s[0] == '0' + && (s[1] == 'x' || s[1] == 'X')) + s += 2; + + /* If BASE is zero, figure it out ourselves. */ + if (base == 0) + if (*s == '0') + { + if (s[1] == 'x' || s[1] == 'X') + { + s += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + + cutoff = ULONG_MAX / (unsigned long int) base; + cutlim = ULONG_MAX % (unsigned long int) base; + + overflow = 0; + i = 0; + for (c = BUCHAR (*s); c != '\0'; c = BUCHAR (*++s)) + { + if (isdigit(c)) + c -= '0'; + else if (islower(c)) + c = c - 'a' + 10; + else if (isupper(c)) + c = c - 'A' + 10; + else + break; + if (c >= base) + break; + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned long int) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (char *) s; + +#if !UNSIGNED + /* Check for a value that is within the range of + `unsigned long int', but outside the range of `long int'. */ + if (i > (negative ? + - (unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX)) + overflow = 1; +#endif + + if (overflow) + { + errno = ERANGE; +#if UNSIGNED + return ULONG_MAX; +#else + return negative ? LONG_MIN : LONG_MAX; +#endif + } + + /* Return the result of the appropriate sign. */ + return (negative ? - i : i); + + noconv: + /* There was no number to convert. */ + if (endptr != NULL) + *endptr = (char *) nptr; + return 0L; +} diff --git a/gnu/libexec/uucp/libuucp/xfree.c b/gnu/libexec/uucp/libuucp/xfree.c new file mode 100644 index 0000000000..239b015db2 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/xfree.c @@ -0,0 +1,15 @@ +/* xfree.c + Some versions of free (like the one in SCO Unix 3.2.2) don't handle + null pointers correctly, so we go through our own routine. */ + +#include "uucp.h" + +#include "uudefs.h" + +void +xfree (p) + pointer p; +{ + if (p != NULL) + free (p); +} diff --git a/gnu/libexec/uucp/libuucp/xmall.c b/gnu/libexec/uucp/libuucp/xmall.c new file mode 100644 index 0000000000..4aac23748c --- /dev/null +++ b/gnu/libexec/uucp/libuucp/xmall.c @@ -0,0 +1,18 @@ +/* xmalloc.c + Allocate a block of memory without fail. */ + +#include "uucp.h" + +#include "uudefs.h" + +pointer +xmalloc (c) + size_t c; +{ + pointer pret; + + pret = malloc (c); + if (pret == NULL && c != 0) + ulog (LOG_FATAL, "Out of memory"); + return pret; +} diff --git a/gnu/libexec/uucp/libuucp/xreall.c b/gnu/libexec/uucp/libuucp/xreall.c new file mode 100644 index 0000000000..36ae313a50 --- /dev/null +++ b/gnu/libexec/uucp/libuucp/xreall.c @@ -0,0 +1,23 @@ +/* xreall.c + Realloc a block of memory without fail. Supposedly some versions of + realloc can't handle a NULL first argument, so we check for that + here. */ + +#include "uucp.h" + +#include "uudefs.h" + +pointer +xrealloc (p, c) + pointer p; + size_t c; +{ + pointer pret; + + if (p == NULL) + return xmalloc (c); + pret = realloc (p, c); + if (pret == NULL && c != 0) + ulog (LOG_FATAL, "Out of memory"); + return pret; +} diff --git a/gnu/libexec/uucp/sample/call b/gnu/libexec/uucp/sample/call new file mode 100644 index 0000000000..de4190ce61 --- /dev/null +++ b/gnu/libexec/uucp/sample/call @@ -0,0 +1,20 @@ +# This is an example of call, the call out password file for Taylor +# UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# This file is used when the ``call-login'' or ``call-password'' +# commands are used in the sys file with a "*" argument (e.g., +# ``call-login *''). The system name is looked up in this file, and +# the login name and password are used. + +# The point of this is that the sys file may then be publically +# readable, while still concealing the login names and passwords used +# to connect to the remote system. + +# The format is just system-name login-name password. +uunet Uairs foobar diff --git a/gnu/libexec/uucp/sample/config b/gnu/libexec/uucp/sample/config new file mode 100644 index 0000000000..e7d683bb03 --- /dev/null +++ b/gnu/libexec/uucp/sample/config @@ -0,0 +1,88 @@ +# This is an example of config, the main configuration file for Taylor +# UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# You need not use this file at all; all the important commands have +# defaults which will be used if this file can not be found. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# You must choose a UUCP name. If your system is going to be +# communicating with other systems outside your organization, the name +# must be unique in the entire world. The usual method is to pick a +# name, and then search the UUCP maps (in the newsgroup +# comp.mail.maps) to see whether it has already been taken. See the +# README posting in comp.mail.maps for more information. If the name +# of your system as returned by "uuname -n" or "hostname" is the name +# you want to use, you do not need to set the name in this file. +# Otherwise uncomment and edit the following line. +# nodename uucp # The UUCP name of this system + +# The default spool directory is set in policy.h (the default is +# /usr/spool/uucp). All UUCP jobs and status information are kept in +# the spool directory. If you wish to change it, use the spool +# command. +# spool /usr/spool/uucp # The UUCP spool directory + +# The default public directory is set in policy.h (the default is +# /usr/spool/uucppublic). Remote systems may refer to a file in this +# directory using "~/FILE". By default, the public directory is the +# only directory which remote systems may transfer files in and out +# of. If you wish to change the public directory, use the pubdir +# command. +# pubdir /usr/spool/uucppublic # The UUCP public directory + +# The names of the UUCP log files are set in policy.h. The default +# names depend on the logging option you have chosen. If +# HAVE_TAYLOR_LOGGING is set in policy.h, the default log file name is +# /usr/spool/uucp/Log, the default statistics file name is +# /usr/spool/uucp/Stats, and the default debugging file name is +# /usr/spool/uucp/Debug. These file names may be set by the following +# commands. +# logfile /usr/spool/uucp/Log # The UUCP log file +# statfile /usr/spool/uucp/Stats # The UUCP statistics file +# debugfile /usr/spool/uucp/Debug # The UUCP debugging file + +# uuxqt is the program which executes UUCP requests from other +# systems. Normally one is started after each run of uucico, the +# communications daemon. You may control the maximum number of uuxqt +# programs run at the same time with the following command. The +# default is to have no maximum. +# max-uuxqts 1 # The maximum number of uuxqts + +# There are several files that uucico uses. By default it looks for +# them in newconfigdir, as set in Makefile.in. You may name one or +# more of each type of file using the following commands. +# sysfile FILES # Default "sys" +# portfile FILES # Default "port" +# dialfile FILES # Default "dial" +# dialcodefile FILES # Default "dialcode" +# callfile FILES # Default "call" +# passwdfile FILES # Default "passwd" + +# The ``timetable'' command may be used to declare timetables. These +# may then be referred to in time strings in the other files. +# timetable Day Wk0905-1655 + +# The ``unknown'' command is followed by any command which may appear +# in a sys file. These commands are taken together to describe what +# is permitted to a system which is not listed in any sys file. If +# the ``unknown'' command, then unknown systems are not permitted to +# connect. + +# Here is an example which permits unknown systems to download files +# from /usr/spool/anonymous, and to upload them to +# /usr/spool/anonymous/upload. +# +# No commands may be executed (the list of permitted commands is empty) +# unknown commands +# The public directory is /usr/spool/anonymous +# unknown pubdir /usr/spool/anonymous +# Only files in the public directory may be sent; users may not download +# files from the upload directory +# unknown remote-send ~ !~/upload +# May only upload files into /usr/spool/anonymous/upload +# unknown remote-receive ~/upload diff --git a/gnu/libexec/uucp/sample/dial b/gnu/libexec/uucp/sample/dial new file mode 100644 index 0000000000..f0d4bdd8aa --- /dev/null +++ b/gnu/libexec/uucp/sample/dial @@ -0,0 +1,35 @@ +# This is an example of dial, the dialer configuration file for Taylor +# UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# All dialers named in the port (or sys) file must be described in the +# dial file. It is also possible to describe a dialer directly in the +# port (or sys) file. + +# This is a typical Hayes modem definition. +dialer hayes + +# The chat script used to dial the phone. +# This means: +# 1) expect nothing (i.e., continue with step 2) +# 2) send "ATZ", then a carriage return, then sleep for 1 to 2 +# seconds. The \c means to not send a final carriage return. +# 3) wait until the modem echoes "OK" +# 4) send "ATDT", then the telephone number (after translating any +# dialcodes). +# 5) wait until the modem echoes "CONNECT" +chat "" ATZ\r\d\c OK ATDT\T CONNECT + +# If we get "BUSY" or "NO CARRIER" during the dial chat script we +# abort the dial immediately. +chat-fail BUSY +chat-fail NO\sCARRIER + +# When the call is over, we make sure we hangup the modem. +complete \d\d+++\d\dATH\r\c +abort \d\d+++\d\dATH\r\c diff --git a/gnu/libexec/uucp/sample/dialcode b/gnu/libexec/uucp/sample/dialcode new file mode 100644 index 0000000000..710a07bf73 --- /dev/null +++ b/gnu/libexec/uucp/sample/dialcode @@ -0,0 +1,19 @@ +# This is an example of dialcode, the dialcode configuration file for +# Taylor UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# The dialcode file is used if \T is used in the dialer chat script +# and the telephone number begins with alphabetic characters. The +# alphabetic characters are looked up and translated in dialcode. + +# Here are a couple of sample dialcodes. +MA 617 +CA 415 + +# For example, if the phone number (from the sys file) is MA7389449, +# then the string sent to the modem will be 6177389449. diff --git a/gnu/libexec/uucp/sample/passwd b/gnu/libexec/uucp/sample/passwd new file mode 100644 index 0000000000..2b04e13a34 --- /dev/null +++ b/gnu/libexec/uucp/sample/passwd @@ -0,0 +1,18 @@ +# This is an example of passwd, the call in password file for Taylor +# UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# This file is used when uucico is invoked with the -l or -e argument. +# uucico will then prompt for a login name and password. The login +# name is looked up in this file to check the password (the system +# password file, /etc/passwd, is not checked). This permits uucico to +# completely take over a port, allowing UUCP access to remote systems +# but not permitting remote users to actually log in to the system. + +# The format is just login-name password. +Uairs foobar diff --git a/gnu/libexec/uucp/sample/port b/gnu/libexec/uucp/sample/port new file mode 100644 index 0000000000..8e481869b5 --- /dev/null +++ b/gnu/libexec/uucp/sample/port @@ -0,0 +1,41 @@ +# This is an example of port, the port configuration file for Taylor +# UUCP. To use it, you must compile the package with +# HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), copy +# this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# All ports named in the sys file must be described in a port file. +# It is also possible to describe the port directly in the sys file. + +# Commands that appears before the first ``port'' command are defaults +# for all ports that appear later in the file. In this case all ports +# will default to being modems (other possible types are direct, tcp +# and tli). +type modem + +# Now we describe two ports. + +# This is the name of the port. This name may be used in the sys file +# to select the port, or the sys file may just specify a baud rate in +# which case the first matching unlocked port will be used. +port port1 + +# This is the device name to open to dial out. +device /dev/ttyd0 + +# This is the dialer to use, as described in the dialer file. +dialer hayes + +# This is the baud rate to dial out at. +speed 2400 + +# Here is a second port. This is like the first, except that it uses +# a different device. It also permits a range of speeds, which is +# mainly useful if the system specifies a particular baud rate. +port port2 +device /dev/ttyd1 +dialer hayes +speed-range 2400 9600 diff --git a/gnu/libexec/uucp/sample/sys1 b/gnu/libexec/uucp/sample/sys1 new file mode 100644 index 0000000000..fa9e7709e1 --- /dev/null +++ b/gnu/libexec/uucp/sample/sys1 @@ -0,0 +1,44 @@ +# This is an example of a sys file, the file(s) which describe remote +# systems for Taylor UUCP. To use it, you must compile the package +# with HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), +# copy this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# If you do not use the ``unknown'' command in the config file, then +# each system that you communicate with must be listed in a sys file. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# This is a sample sys file that might be used in a leaf system. A +# leaf system is one that only contacts one other system. sys2 +# provides another example. + +# The name of the remote system that we call. +system uunet + +# The login name and password are kept in the callout password file +# (by default this is the file "call" in newconfigdir). +call-login * +call-password * + +# We can send anything at any time. +time any + +# During the day we only accept grade 'Z' or above; at other times +# (not mentioned here) we accept all grades. uunet queues up news +# at grade 'd', which is lower than 'Z'. +call-timegrade Z Wk0755-2305,Su1655-2305 + +# The phone number to call. +phone 7389449 + +# uunet tends to be slow, so we increase the timeout +chat-timeout 120 + +# The port we use to dial out. +port serial + +# Increase the timeout and the number of retries. +protocol-parameter g timeout 20 +protocol-parameter g retries 10 diff --git a/gnu/libexec/uucp/sample/sys2 b/gnu/libexec/uucp/sample/sys2 new file mode 100644 index 0000000000..856529a500 --- /dev/null +++ b/gnu/libexec/uucp/sample/sys2 @@ -0,0 +1,51 @@ +# This is an example of a sys file, the file(s) which describe remote +# systems for Taylor UUCP. To use it, you must compile the package +# with HAVE_TAYLOR_CONFIG set to 1 in policy.h (that is the default), +# copy this file to newconfigdir as set in Makefile.in (the default is +# /usr/local/conf/uucp), and edit it as appropriate for your system. + +# If you do not use the ``unknown'' command in the config file, then +# each system that you communicate with must be listed in a sys file. + +# Everything after a '#' character is a comment. To uncomment any of +# the sample lines below, just delete the '#'. + +# This is a sample sys file that might be used by a system that +# contacts a couple of other systems, both of which are treated the +# same. sys1 provides another example. + +# Commands that appear before the first ``system'' commands are +# defaults for all systems listed in the file. + +# Get the login name and password to use from the call-out file. By +# default this is the file "call" in newconfigdir. +call-login * +call-password * + +# The systems must use a particular login +called-login Ulocal + +# Permit local users to send any world readable file +local-send / + +# Permit local uses to request into any world writable directory +local-receive / + +# Call at any time +time any + +# Use port1, then port2 +port port1 + +alternate + +port port2 + +# Now define the systems themselves. Because of all the defaults we +# used, there is very little to specify for the systems themselves. + +system comton +phone 5551212 + +system bugs +phone 5552424 diff --git a/gnu/libexec/uucp/tstuu.c b/gnu/libexec/uucp/tstuu.c new file mode 100644 index 0000000000..d30549907d --- /dev/null +++ b/gnu/libexec/uucp/tstuu.c @@ -0,0 +1,1588 @@ +/* tstuu.c + Test the uucp package on a UNIX 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" + +#if USE_RCS_ID +const char tstuu_rcsid[] = "$Id: tstuu.c,v 1.2 1993/08/04 19:29:58 jtc Exp $"; +#endif + +#include "sysdep.h" +#include "system.h" +#include "getopt.h" + +#include +#include +#include + +#if HAVE_SYS_TIMES_H +#include +#endif + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_SELECT +#include +#if HAVE_SYS_SELECT_H +#include +#endif +#endif + +#if HAVE_POLL +#if HAVE_STROPTS_H +#include +#endif +#if HAVE_POLL_H +#include +#endif +#endif + +#if HAVE_FCNTL_H +#include +#else +#if HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT) +#include +#endif + +#if HAVE_SYS_WAIT_H +#include +#endif + +#if HAVE_UNION_WAIT +typedef union wait wait_status; +#else +typedef int wait_status; +#endif + +#if HAVE_STREAMS_PTYS +#include +extern char *ptsname (); +#endif + +/* 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 CLK_TCK definition, even if it makes no sense. + This is in case TIMES_TICK is defined as CLK_TCK. */ +#ifndef CLK_TCK +#define CLK_TCK (60) +#endif + +/* Don't try too hard to get a TIMES_TICK value; it doesn't matter + that much. */ +#if TIMES_TICK == 0 +#undef TIMES_TICK +#define TIMES_TICK CLK_TCK +#endif + +#if TIMES_DECLARATION_OK +extern long times (); +#endif + +#ifndef SIGCHLD +#define SIGCHLD SIGCLD +#endif + +#if 1 +#define ZUUCICO_CMD "login uucp" +#define UUCICO_EXECL "/bin/login", "login", "uucp" +#else +#define ZUUCICO_CMD "su - nuucp" +#define UUCICO_EXECL "/bin/su", "su", "-", "nuucp" +#endif + +#if ! HAVE_SELECT && ! HAVE_POLL + #error You need select or poll +#endif + +#if ! HAVE_REMOVE +#undef remove +#define remove unlink +#endif + +/* Buffer chain to hold data read from a uucico. */ + +#define BUFCHARS (512) + +struct sbuf +{ + struct sbuf *qnext; + int cstart; + int cend; + char ab[BUFCHARS]; +}; + +/* Local functions. */ + +static void umake_file P((const char *zfile, int cextra)); +static void uprepare_test P((boolean fmake, int itest, + boolean fcall_uucico, + const char *zsys)); +static void ucheck_file P((const char *zfile, const char *zerr, + int cextra)); +static void ucheck_test P((int itest, boolean fcall_uucico)); +static RETSIGTYPE uchild P((int isig)); +static int cpshow P((char *z, int bchar)); +static void uchoose P((int *po1, int *po2)); +static long cread P((int o, struct sbuf **)); +static boolean fsend P((int o, int oslave, struct sbuf **)); +static boolean fwritable P((int o)); +static void xsystem P((const char *zcmd)); +static FILE *xfopen P((const char *zname, const char *zmode)); + +static char *zDebug; +static int iTest; +static boolean fCall_uucico; +static int iPercent; +static pid_t iPid1, iPid2; +static int cFrom1, cFrom2; +static char abLogout1[sizeof "tstout /dev/ptyp0"]; +static char abLogout2[sizeof "tstout /dev/ptyp0"]; +static char *zProtocols; + +int +main (argc, argv) + int argc; + char **argv; +{ + int iopt; + const char *zcmd1, *zcmd2; + const char *zsys; + boolean fmake = TRUE; + int omaster1, oslave1, omaster2, oslave2; + char abpty1[sizeof "/dev/ptyp0"]; + char abpty2[sizeof "/dev/ptyp0"]; + struct sbuf *qbuf1, *qbuf2; + + zcmd1 = NULL; + zcmd2 = NULL; + zsys = "test2"; + + while ((iopt = getopt (argc, argv, "c:np:s:t:ux:1:2:")) != EOF) + { + switch (iopt) + { + case 'c': + zProtocols = optarg; + break; + case 'n': + fmake = FALSE; + break; + case 'p': + iPercent = (int) strtol (optarg, (char **) NULL, 10); + srand ((unsigned int) ixsysdep_time ((long *) NULL)); + break; + case 's': + zsys = optarg; + break; + case 't': + iTest = (int) strtol (optarg, (char **) NULL, 10); + break; + case 'u': + fCall_uucico = TRUE; + break; + case 'x': + zDebug = optarg; + break; + case '1': + zcmd1 = optarg; + break; + case '2': + zcmd2 = optarg; + break; + default: + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: tstuu [-xn] [-t #] [-u] [-1 cmd] [-2 cmd]\n"); + exit (EXIT_FAILURE); + } + } + + if (fCall_uucico && zcmd2 == NULL) + zcmd2 = ZUUCICO_CMD; + + uprepare_test (fmake, iTest, fCall_uucico, zsys); + + (void) remove ("/usr/tmp/tstuu/spool1/core"); + (void) remove ("/usr/tmp/tstuu/spool2/core"); + + omaster1 = -1; + oslave1 = -1; + omaster2 = -1; + oslave2 = -1; + +#if ! HAVE_STREAMS_PTYS + + { + char *zptyname; + const char *zpty; + + zptyname = abpty1; + + for (zpty = "pqrs"; *zpty != '\0'; ++zpty) + { + int ipty; + + for (ipty = 0; ipty < 16; ipty++) + { + int om, os; + FILE *e; + + sprintf (zptyname, "/dev/pty%c%c", *zpty, + "0123456789abcdef"[ipty]); + om = open (zptyname, O_RDWR); + if (om < 0) + continue; + zptyname[5] = 't'; + os = open (zptyname, O_RDWR); + if (os < 0) + { + (void) close (om); + continue; + } + + if (omaster1 == -1) + { + omaster1 = om; + oslave1 = os; + + e = fopen ("/usr/tmp/tstuu/pty1", "w"); + if (e == NULL) + { + perror ("fopen"); + exit (EXIT_FAILURE); + } + fprintf (e, "%s", zptyname + 5); + if (fclose (e) != 0) + { + perror ("fclose"); + exit (EXIT_FAILURE); + } + + zptyname = abpty2; + } + else + { + omaster2 = om; + oslave2 = os; + + e = fopen ("/usr/tmp/tstuu/pty2", "w"); + if (e == NULL) + { + perror ("fopen"); + exit (EXIT_FAILURE); + } + fprintf (e, "%s", zptyname + 5); + if (fclose (e) != 0) + { + perror ("fclose"); + exit (EXIT_FAILURE); + } + break; + } + } + + if (omaster1 != -1 && omaster2 != -1) + break; + } + } + +#else /* HAVE_STREAMS_PTYS */ + + { + int ipty; + + for (ipty = 0; ipty < 2; ipty++) + { + int om, os; + FILE *e; + char *znam; + struct termio stio; + + om = open ((char *) "/dev/ptmx", O_RDWR); + if (om < 0) + break; + znam = ptsname (om); + if (znam == NULL) + break; + if (unlockpt (om) != 0 + || grantpt (om) != 0) + break; + + os = open (znam, O_RDWR); + if (os < 0) + { + (void) close (om); + om = -1; + break; + } + + if (ioctl (os, I_PUSH, "ptem") < 0 + || ioctl(os, I_PUSH, "ldterm") < 0) + { + perror ("ioctl"); + exit (EXIT_FAILURE); + } + + /* Can this really be right? */ + memset (&stio, 0, sizeof (stio)); + stio.c_cflag = B9600 | CS8 | CREAD | HUPCL; + + if (ioctl(os, TCSETA, &stio) < 0) + { + perror ("TCSETA"); + exit (EXIT_FAILURE); + } + + if (omaster1 == -1) + { + strcpy (abpty1, znam); + omaster1 = om; + oslave1 = os; + e = fopen ("/usr/tmp/tstuu/pty1", "w"); + if (e == NULL) + { + perror ("fopen"); + exit (EXIT_FAILURE); + } + fprintf (e, "%s", znam + 5); + if (fclose (e) != 0) + { + perror ("fclose"); + exit (EXIT_FAILURE); + } + } + else + { + strcpy (abpty2, znam); + omaster2 = om; + oslave2 = os; + e = fopen ("/usr/tmp/tstuu/pty2", "w"); + if (e == NULL) + { + perror ("fopen"); + exit (EXIT_FAILURE); + } + fprintf (e, "%s", znam + 5); + if (fclose (e) != 0) + { + perror ("fclose"); + exit (EXIT_FAILURE); + } + } + } + } + +#endif /* HAVE_STREAMS_PTYS */ + + if (omaster2 == -1) + { + fprintf (stderr, "No pseudo-terminals available\n"); + exit (EXIT_FAILURE); + } + + /* Make sure we can or these into an int for the select call. Most + systems could use 31 instead of 15, but it should never be a + problem. */ + if (omaster1 > 15 || omaster2 > 15) + { + fprintf (stderr, "File descriptors are too large\n"); + exit (EXIT_FAILURE); + } + + /* Prepare to log out the command if it is a login command. On + Ultrix 4.0 uucico can only be run from login for some reason. */ + + if (zcmd1 == NULL + || strncmp (zcmd1, "login", sizeof "login" - 1) != 0) + abLogout1[0] = '\0'; + else + sprintf (abLogout1, "tstout %s", abpty1); + + if (zcmd2 == NULL + || strncmp (zcmd2, "login", sizeof "login" - 1) != 0) + abLogout2[0] = '\0'; + else + sprintf (abLogout2, "tstout %s", abpty2); + + iPid1 = fork (); + if (iPid1 < 0) + { + perror ("fork"); + exit (EXIT_FAILURE); + } + else if (iPid1 == 0) + { + if (close (0) < 0 + || close (1) < 0 + || close (omaster1) < 0 + || close (omaster2) < 0 + || close (oslave2) < 0) + perror ("close"); + + if (dup2 (oslave1, 0) < 0 + || dup2 (oslave1, 1) < 0) + perror ("dup2"); + + if (close (oslave1) < 0) + perror ("close"); + + if (zDebug != NULL) + fprintf (stderr, "About to exec first process\n"); + + if (zcmd1 != NULL) + exit (system ((char *) zcmd1)); + else + { + (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config1", + "-q", "-S", zsys, "-pstdin", (const char *) NULL); + perror ("execl failed"); + exit (EXIT_FAILURE); + } + } + + iPid2 = fork (); + if (iPid2 < 0) + { + perror ("fork"); + kill (iPid1, SIGTERM); + exit (EXIT_FAILURE); + } + else if (iPid2 == 0) + { + if (close (0) < 0 + || close (1) < 0 + || close (omaster1) < 0 + || close (oslave1) < 0 + || close (omaster2) < 0) + perror ("close"); + + if (dup2 (oslave2, 0) < 0 + || dup2 (oslave2, 1) < 0) + perror ("dup2"); + + if (close (oslave2) < 0) + perror ("close"); + + if (zDebug != NULL) + fprintf (stderr, "About to exec second process\n"); + + if (fCall_uucico) + { + (void) execl (UUCICO_EXECL, (const char *) NULL); + perror ("execl failed"); + exit (EXIT_FAILURE); + } + else if (zcmd2 != NULL) + exit (system ((char *) zcmd2)); + else + { + (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config2", + "-lq", (const char *)NULL); + perror ("execl failed"); + exit (EXIT_FAILURE); + } + } + + signal (SIGCHLD, uchild); + + if (fcntl (omaster1, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 + && errno == EINVAL) + (void) fcntl (omaster1, F_SETFL, O_NONBLOCK); + if (fcntl (omaster2, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 + && errno == EINVAL) + (void) fcntl (omaster2, F_SETFL, O_NONBLOCK); + + qbuf1 = NULL; + qbuf2 = NULL; + + while (TRUE) + { + int o1, o2; + boolean fcont; + + o1 = omaster1; + o2 = omaster2; + uchoose (&o1, &o2); + + if (o1 == -1 && o2 == -1) + { + if (zDebug != NULL) + fprintf (stderr, "Five second pause\n"); + continue; + } + + if (o1 != -1) + cFrom1 += cread (omaster1, &qbuf1); + + if (o2 != -1) + cFrom2 += cread (omaster2, &qbuf2); + + do + { + fcont = FALSE; + + if (qbuf1 != NULL + && fwritable (omaster2) + && fsend (omaster2, oslave2, &qbuf1)) + fcont = TRUE; + + if (qbuf2 != NULL + && fwritable (omaster1) + && fsend (omaster1, oslave1, &qbuf2)) + fcont = TRUE; + + if (! fcont + && (qbuf1 != NULL || qbuf2 != NULL)) + { + long cgot1, cgot2; + + cgot1 = cread (omaster1, &qbuf1); + cFrom1 += cgot1; + cgot2 = cread (omaster2, &qbuf2); + cFrom2 += cgot2; + fcont = TRUE; + } + } + while (fcont); + } + + /*NOTREACHED*/ +} + +/* When a child dies, kill them both. */ + +static RETSIGTYPE +uchild (isig) + int isig; +{ + struct tms sbase, s1, s2; + + signal (SIGCHLD, SIG_DFL); + + /* Give the processes a chance to die on their own. */ + sleep (2); + + (void) kill (iPid1, SIGTERM); + (void) kill (iPid2, SIGTERM); + + (void) times (&sbase); + +#if HAVE_WAITPID + (void) waitpid (iPid1, (pointer) NULL, 0); +#else /* ! HAVE_WAITPID */ +#if HAVE_WAIT4 + (void) wait4 (iPid1, (pointer) NULL, 0, (struct rusage *) NULL); +#else /* ! HAVE_WAIT4 */ + (void) wait ((wait_status *) NULL); +#endif /* ! HAVE_WAIT4 */ +#endif /* ! HAVE_WAITPID */ + + (void) times (&s1); + +#if HAVE_WAITPID + (void) waitpid (iPid2, (pointer) NULL, 0); +#else /* ! HAVE_WAITPID */ +#if HAVE_WAIT4 + (void) wait4 (iPid2, (wait_status *) NULL, 0, (struct rusage *) NULL); +#else /* ! HAVE_WAIT4 */ + (void) wait ((wait_status *) NULL); +#endif /* ! HAVE_WAIT4 */ +#endif /* ! HAVE_WAITPID */ + + (void) times (&s2); + + fprintf (stderr, + " First child: user: %g; system: %g\n", + (double) (s1.tms_cutime - sbase.tms_cutime) / (double) TIMES_TICK, + (double) (s1.tms_cstime - sbase.tms_cstime) / (double) TIMES_TICK); + fprintf (stderr, + "Second child: user: %g; system: %g\n", + (double) (s2.tms_cutime - s1.tms_cutime) / (double) TIMES_TICK, + (double) (s2.tms_cstime - s1.tms_cstime) / (double) TIMES_TICK); + + ucheck_test (iTest, fCall_uucico); + + if (abLogout1[0] != '\0') + { + if (zDebug != NULL) + fprintf (stderr, "Executing %s\n", abLogout1); + (void) system (abLogout1); + } + if (abLogout2[0] != '\0') + { + if (zDebug != NULL) + fprintf (stderr, "Executing %s\n", abLogout2); + (void) system (abLogout2); + } + + fprintf (stderr, "Wrote %d bytes from 1 to 2\n", cFrom1); + fprintf (stderr, "Wrote %d bytes from 2 to 1\n", cFrom2); + + if (access ("/usr/tmp/tstuu/spool1/core", R_OK) == 0) + fprintf (stderr, "core file 1 exists\n"); + if (access ("/usr/tmp/tstuu/spool2/core", R_OK) == 0) + fprintf (stderr, "core file 2 exists\n"); + + exit (EXIT_SUCCESS); +} + +/* Open a file without error. */ + +static FILE * +xfopen (zname, zmode) + const char *zname; + const char *zmode; +{ + FILE *eret; + + eret = fopen (zname, zmode); + if (eret == NULL) + { + perror (zname); + exit (EXIT_FAILURE); + } + return eret; +} + +/* Close a file without error. */ + +static void xfclose P((FILE *e)); + +static void +xfclose (e) + FILE *e; +{ + if (fclose (e) != 0) + { + perror ("fclose"); + exit (EXIT_FAILURE); + } +} + +/* Create a test file. */ + +static void +umake_file (z, c) + const char *z; + int c; +{ + int i; + FILE *e; + + e = xfopen (z, "w"); + + for (i = 0; i < 256; i++) + { + int i2; + + for (i2 = 0; i2 < 256; i2++) + putc (i, e); + } + + for (i = 0; i < c; i++) + putc (i, e); + + xfclose (e); +} + +/* Check a test file. */ + +static void +ucheck_file (z, zerr, c) + const char *z; + const char *zerr; + int c; +{ + int i; + FILE *e; + + e = xfopen (z, "r"); + + for (i = 0; i < 256; i++) + { + int i2; + + for (i2 = 0; i2 < 256; i2++) + { + int bread; + + bread = getc (e); + if (bread == EOF) + { + fprintf (stderr, + "%s: Unexpected EOF at position %d,%d\n", + zerr, i, i2); + xfclose (e); + return; + } + if (bread != i) + fprintf (stderr, + "%s: At position %d,%d got %d expected %d\n", + zerr, i, i2, bread, i); + } + } + + for (i = 0; i < c; i++) + { + int bread; + + bread = getc (e); + if (bread == EOF) + { + fprintf (stderr, "%s: Unexpected EOF at extra %d\n", zerr, i); + xfclose (e); + return; + } + if (bread != i) + fprintf (stderr, "%s: At extra %d got %d expected %d\n", + zerr, i, bread, i); + } + + if (getc (e) != EOF) + fprintf (stderr, "%s: File is too long", zerr); + + xfclose (e); +} + +/* Prepare all the configuration files for testing. */ + +static void +uprepare_test (fmake, itest, fcall_uucico, zsys) + boolean fmake; + int itest; + boolean fcall_uucico; + const char *zsys; +{ + FILE *e; + const char *zuucp1, *zuucp2; + const char *zuux1, *zuux2; + char ab[1000]; + const char *zfrom; + const char *zto; + +/* We must make /usr/tmp/tstuu world writeable or we won't be able to + receive files into it. */ + (void) umask (0); + +#ifndef S_IWOTH +#define S_IWOTH 02 +#endif + + if (mkdir ((char *) "/usr/tmp/tstuu", + IPUBLIC_DIRECTORY_MODE | S_IWOTH) != 0 + && errno != EEXIST) + { + perror ("mkdir"); + exit (EXIT_FAILURE); + } + + if (mkdir ((char *) "/usr/tmp/tstuu/spool1", IPUBLIC_DIRECTORY_MODE) != 0 + && errno != EEXIST) + { + perror ("mkdir"); + exit (EXIT_FAILURE); + } + + if (mkdir ((char *) "/usr/tmp/tstuu/spool2", IPUBLIC_DIRECTORY_MODE) != 0 + && errno != EEXIST) + { + perror ("mkdir"); + exit (EXIT_FAILURE); + } + + if (fmake) + { + e = xfopen ("/usr/tmp/tstuu/Config1", "w"); + + fprintf (e, "# First test configuration file\n"); + fprintf (e, "nodename test1\n"); + fprintf (e, "spool /usr/tmp/tstuu/spool1\n"); + fprintf (e, "lockdir /usr/tmp/tstuu/spool1\n"); + fprintf (e, "sysfile /usr/tmp/tstuu/System1\n"); + fprintf (e, "sysfile /usr/tmp/tstuu/System1.2\n"); + fprintf (e, "portfile /usr/tmp/tstuu/Port1\n"); + (void) remove ("/usr/tmp/tstuu/Log1"); +#if ! HAVE_HDB_LOGGING + fprintf (e, "logfile /usr/tmp/tstuu/Log1\n"); +#else + fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log1/%s/%s"); +#endif + fprintf (e, "statfile /usr/tmp/tstuu/Stats1\n"); + fprintf (e, "debugfile /usr/tmp/tstuu/Debug1\n"); + fprintf (e, "callfile /usr/tmp/tstuu/Call1\n"); + fprintf (e, "pubdir /usr/tmp/tstuu\n"); +#if HAVE_V2_CONFIG + fprintf (e, "v2-files no\n"); +#endif +#if HAVE_HDB_CONFIG + fprintf (e, "hdb-files no\n"); +#endif + if (zDebug != NULL) + fprintf (e, "debug %s\n", zDebug); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/System1", "w"); + + fprintf (e, "# This file is ignored, to test multiple system files\n"); + fprintf (e, "time never\n"); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/System1.2", "w"); + + fprintf (e, "# First test system file\n"); + fprintf (e, "time any\n"); + fprintf (e, "port stdin\n"); + fprintf (e, "# That was the defaults\n"); + fprintf (e, "system %s\n", zsys); + if (! fcall_uucico) + { + FILE *eprog; + + eprog = xfopen ("/usr/tmp/tstuu/Chat1", "w"); + + /* Wait for the other side to open the port and flush input. */ + fprintf (eprog, "sleep 2\n"); + fprintf (eprog, + "echo password $1 speed $2 1>&2\n"); + fprintf (eprog, "echo test1\n"); + fprintf (eprog, "exit 0\n"); + + xfclose (eprog); + + if (chmod ("/usr/tmp/tstuu/Chat1", + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + { + perror ("chmod (/usr/tmp/tstuu/Chat1)"); + exit (EXIT_FAILURE); + } + + fprintf (e, "chat-program /usr/tmp/tstuu/Chat1 \\P \\S\n"); + + fprintf (e, "chat word: \\P\n"); + fprintf (e, "chat-fail login;\n"); + fprintf (e, "call-login *\n"); + fprintf (e, "call-password *\n"); + } + else + fprintf (e, "chat \"\"\n"); + fprintf (e, "call-transfer yes\n"); + fprintf (e, "commands cat\n"); + if (! fcall_uucico && iPercent == 0) + { + fprintf (e, "protocol-parameter g window 7\n"); + fprintf (e, "protocol-parameter g packet-size 4096\n"); + fprintf (e, "protocol-parameter j avoid \\377\n"); + } + if (zProtocols != NULL) + fprintf (e, "protocol %s\n", zProtocols); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/Port1", "w"); + + fprintf (e, "port stdin\n"); + fprintf (e, "type stdin\n"); + fprintf (e, "pty true\n"); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/Call1", "w"); + + fprintf (e, "Call out password file\n"); + fprintf (e, "%s test1 pass1\n", zsys); + + xfclose (e); + + if (! fcall_uucico) + { + FILE *eprog; + + e = xfopen ("/usr/tmp/tstuu/Config2", "w"); + + fprintf (e, "# Second test configuration file\n"); + fprintf (e, "nodename test2\n"); + fprintf (e, "spool /usr/tmp/tstuu/spool2\n"); + fprintf (e, "lockdir /usr/tmp/tstuu/spool2\n"); + fprintf (e, "sysfile /usr/tmp/tstuu/System2\n"); + (void) remove ("/usr/tmp/tstuu/Log2"); +#if ! HAVE_HDB_LOGGING + fprintf (e, "logfile /usr/tmp/tstuu/Log2\n"); +#else + fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log2/%s/%s"); +#endif + fprintf (e, "statfile /usr/tmp/tstuu/Stats2\n"); + fprintf (e, "debugfile /usr/tmp/tstuu/Debug2\n"); + fprintf (e, "passwdfile /usr/tmp/tstuu/Pass2\n"); + fprintf (e, "pubdir /usr/tmp/tstuu\n"); +#if HAVE_V2_CONFIG + fprintf (e, "v2-files no\n"); +#endif +#if HAVE_HDB_CONFIG + fprintf (e, "hdb-files no\n"); +#endif + if (zDebug != NULL) + fprintf (e, "debug %s\n", zDebug); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/System2", "w"); + + fprintf (e, "# Second test system file\n"); + fprintf (e, "system test1\n"); + fprintf (e, "called-login test1\n"); + fprintf (e, "request true\n"); + fprintf (e, "commands cat\n"); + if (zProtocols != NULL) + fprintf (e, "protocol %s\n", zProtocols); + + eprog = xfopen ("/usr/tmp/tstuu/Chat2", "w"); + + fprintf (eprog, + "echo port $1 1>&2\n"); + fprintf (eprog, "exit 0\n"); + + xfclose (eprog); + + if (chmod ("/usr/tmp/tstuu/Chat2", + S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + { + perror ("chmod (/usr/tmp/tstuu/Chat2"); + exit (EXIT_FAILURE); + } + + fprintf (e, "called-chat-program /bin/sh /usr/tmp/tstuu/Chat2 \\Y\n"); + fprintf (e, "time any\n"); + + xfclose (e); + + e = xfopen ("/usr/tmp/tstuu/Pass2", "w"); + + fprintf (e, "# Call in password file\n"); + fprintf (e, "test1 pass1\n"); + + xfclose (e); + } + } + + zuucp1 = "./uucp -I /usr/tmp/tstuu/Config1 -r"; + zuux1 = "./uux -I /usr/tmp/tstuu/Config1 -r"; + + if (fcall_uucico) + { + zuucp2 = "/usr/bin/uucp -r"; + zuux2 = "/usr/bin/uux -r"; + } + else + { + zuucp2 = "./uucp -I /usr/tmp/tstuu/Config2 -r"; + zuux2 = "./uux -I /usr/tmp/tstuu/Config2 -r"; + } + + /* Test transferring a file from the first system to the second. */ + if (itest == 0 || itest == 1) + { + zfrom = "/usr/tmp/tstuu/from1"; + if (fcall_uucico) + zto = "/usr/spool/uucppublic/to1"; + else + zto = "/usr/tmp/tstuu/to1"; + + (void) remove (zto); + umake_file (zfrom, 0); + + sprintf (ab, "%s %s %s!%s", zuucp1, zfrom, zsys, zto); + xsystem (ab); + } + + /* Test having the first system request a file from the second. */ + if (itest == 0 || itest == 2) + { + if (fcall_uucico) + zfrom = "/usr/spool/uucppublic/from2"; + else + zfrom = "/usr/tmp/tstuu/from2"; + zto = "/usr/tmp/tstuu/to2"; + + (void) remove (zto); + umake_file (zfrom, 3); + + sprintf (ab, "%s %s!%s %s", zuucp1, zsys, zfrom, zto); + xsystem (ab); + } + + /* Test having the second system send a file to the first. */ + if (itest == 0 || itest == 3) + { + if (fcall_uucico) + zfrom = "/usr/spool/uucppublic/from3"; + else + zfrom = "/usr/tmp/tstuu/from3"; + zto = "/usr/tmp/tstuu/to3"; + + (void) remove (zto); + umake_file (zfrom, 5); + + sprintf (ab, "%s -c \\~/from3 test1!~/to3", zuucp2); + xsystem (ab); + } + + /* Test having the second system request a file from the first. */ + if (itest == 0 || itest == 4) + { + zfrom = "/usr/tmp/tstuu/from4"; + if (fcall_uucico) + zto = "/usr/spool/uucppublic/to4"; + else + zto = "/usr/tmp/tstuu/to4"; + + (void) remove (zto); + umake_file (zfrom, 7); + + sprintf (ab, "%s test1!%s %s", zuucp2, zfrom, zto); + xsystem (ab); + } + + /* Test having the second system make an execution request. */ + if (itest == 0 || itest == 5) + { + zfrom = "/usr/tmp/tstuu/from5"; + if (fcall_uucico) + zto = "/usr/spool/uucppublic/to5"; + else + zto = "/usr/tmp/tstuu/to5"; + + (void) remove (zto); + umake_file (zfrom, 11); + + sprintf (ab, "%s test1!cat '<%s' '>%s'", zuux2, zfrom, zto); + xsystem (ab); + } + + /* Test having the first system request a wildcard. */ + if (itest == 0 || itest == 6) + { + const char *zfrom1, *zfrom2; + + if (fcall_uucico) + { + zfrom = "/usr/spool/uucppublic/to6\\*"; + zfrom1 = "/usr/spool/uucppublic/to6.1"; + zfrom2 = "/usr/spool/uucppublic/to6.2"; + } + else + { + zfrom = "/usr/tmp/tstuu/spool2/to6\\*"; + zfrom1 = "/usr/tmp/tstuu/spool2/to6.1"; + zfrom2 = "/usr/tmp/tstuu/spool2/to6.2"; + } + + umake_file (zfrom1, 100); + umake_file (zfrom2, 101); + (void) remove ("/usr/tmp/tstuu/to6.1"); + (void) remove ("/usr/tmp/tstuu/to6.2"); + + sprintf (ab, "%s %s!%s /usr/tmp/tstuu", zuucp1, zsys, zfrom); + xsystem (ab); + } + + /* Test having the second system request a wildcard. */ + if (itest == 0 || itest == 7) + { + const char *zto1, *zto2; + + if (fcall_uucico) + { + zto = "/usr/spool/uucppublic"; + zto1 = "/usr/spool/uucppublic/to7.1"; + zto2 = "/usr/spool/uucppublic/to7.2"; + } + else + { + zto = "/usr/tmp/tstuu"; + zto1 = "/usr/tmp/tstuu/to7.1"; + zto2 = "/usr/tmp/tstuu/to7.2"; + } + + umake_file ("/usr/tmp/tstuu/spool1/to7.1", 150); + umake_file ("/usr/tmp/tstuu/spool1/to7.2", 155); + (void) remove (zto1); + (void) remove (zto2); + + sprintf (ab, "%s test1!/usr/tmp/tstuu/spool1/to7.\\* %s", zuucp2, + zto); + xsystem (ab); + } + + /* Test an E command. This runs cat, discarding the output. */ + if ((itest == 0 || itest == 8) && ! fcall_uucico) + { + umake_file ("/usr/tmp/tstuu/from8", 30); + sprintf (ab, "%s - test2!cat < /usr/tmp/tstuu/from8", zuux1); + xsystem (ab); + } +} + +/* Try to make sure the file transfers were successful. */ + +static void +ucheck_test (itest, fcall_uucico) + int itest; + boolean fcall_uucico; +{ + if (itest == 0 || itest == 1) + { + if (fcall_uucico) + ucheck_file ("/usr/spool/uucppublic/to1", "test 1", 0); + else + ucheck_file ("/usr/tmp/tstuu/to1", "test 1", 0); + } + + if (itest == 0 || itest == 2) + ucheck_file ("/usr/tmp/tstuu/to2", "test 2", 3); + + if (itest == 0 || itest == 3) + ucheck_file ("/usr/tmp/tstuu/to3", "test 3", 5); + + if (itest == 0 || itest == 4) + { + if (fcall_uucico) + ucheck_file ("/usr/spool/uucppublic/to4", "test 4", 7); + else + ucheck_file ("/usr/tmp/tstuu/to4", "test 4", 7); + } + + if (itest == 0 || itest == 6) + { + ucheck_file ("/usr/tmp/tstuu/to6.1", "test 6.1", 100); + ucheck_file ("/usr/tmp/tstuu/to6.2", "test 6.2", 101); + } + + if (itest == 0 || itest == 7) + { + const char *zto1, *zto2; + + if (fcall_uucico) + { + zto1 = "/usr/spool/uucppublic/to7.1"; + zto2 = "/usr/spool/uucppublic/to7.2"; + } + else + { + zto1 = "/usr/tmp/tstuu/to7.1"; + zto2 = "/usr/tmp/tstuu/to7.2"; + } + + ucheck_file (zto1, "test 7.1", 150); + ucheck_file (zto2, "test 7.2", 155); + } +} + +/* A debugging routine used when displaying buffers. */ + +static int +cpshow (z, ichar) + char *z; + int ichar; +{ + if (isprint (BUCHAR (ichar)) && ichar != '\"') + { + *z = (char) ichar; + return 1; + } + + *z++ = '\\'; + + switch (ichar) + { + case '\n': + *z = 'n'; + return 2; + case '\r': + *z = 'r'; + return 2; + case '\"': + *z = '\"'; + return 2; + default: + sprintf (z, "%03o", (unsigned int)(ichar & 0xff)); + return strlen (z) + 1; + } +} + +/* Pick one of two file descriptors which is ready for reading, or + return in five seconds. If the argument is ready for reading, + leave it alone; otherwise set it to -1. */ + +static void +uchoose (po1, po2) + int *po1; + int *po2; +{ +#if HAVE_SELECT + + int iread; + struct timeval stime; + + iread = (1 << *po1) | (1 << *po2); + stime.tv_sec = 5; + stime.tv_usec = 0; + + if (select ((*po1 > *po2 ? *po1 : *po2) + 1, (pointer) &iread, + (pointer) NULL, (pointer) NULL, &stime) < 0) + { + perror ("select"); + uchild (SIGCHLD); + } + + if ((iread & (1 << *po1)) == 0) + *po1 = -1; + + if ((iread & (1 << *po2)) == 0) + *po2 = -1; + +#else /* ! HAVE_SELECT */ + +#if HAVE_POLL + + struct pollfd as[2]; + + as[0].fd = *po1; + as[0].events = POLLIN; + as[1].fd = *po2; + as[1].events = POLLIN; + + if (poll (as, 2, 5 * 1000) < 0) + { + perror ("poll"); + uchild (SIGCHLD); + } + + if ((as[0].revents & POLLIN) == 0) + *po1 = -1; + + if ((as[1].revents & POLLIN) == 0) + *po2 = -1; + +#endif /* HAVE_POLL */ +#endif /* ! HAVE_SELECT */ +} + +/* Read some data from a file descriptor. This keeps reading until + one of the reads gets no data. */ + +static long +cread (o, pqbuf) + int o; + struct sbuf **pqbuf; +{ + long ctotal; + + while (*pqbuf != NULL && (*pqbuf)->qnext != NULL) + pqbuf = &(*pqbuf)->qnext; + + ctotal = 0; + + while (TRUE) + { + int cgot; + + if (*pqbuf != NULL + && (*pqbuf)->cend >= sizeof (*pqbuf)->ab) + pqbuf = &(*pqbuf)->qnext; + + if (*pqbuf == NULL) + { + *pqbuf = (struct sbuf *) malloc (sizeof (struct sbuf)); + if (*pqbuf == NULL) + { + fprintf (stderr, "Out of memory\n"); + uchild (SIGCHLD); + } + (*pqbuf)->qnext = NULL; + (*pqbuf)->cstart = 0; + (*pqbuf)->cend = 0; + } + + cgot = read (o, (*pqbuf)->ab + (*pqbuf)->cend, + (sizeof (*pqbuf)->ab) - (*pqbuf)->cend); + if (cgot < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) + cgot = 0; + else + { + perror ("read"); + uchild (SIGCHLD); + } + } + + if (cgot == 0) + return ctotal; + + ctotal += cgot; + + if (zDebug != NULL) + { + char abshow[325]; + char *zfrom; + char *zshow; + int i; + + zfrom = (*pqbuf)->ab + (*pqbuf)->cend; + zshow = abshow; + for (i = 0; i < cgot && i < 80; i++, zfrom++) + zshow += cpshow (zshow, *zfrom); + if (i < cgot) + { + *zshow++ = '.'; + *zshow++ = '.'; + *zshow++ = '.'; + } + *zshow = '\0'; + fprintf (stderr, "Read from %d: %d \"%s\"\n", o, cgot, abshow); + fflush (stderr); + } + + if (iPercent > 0) + { + int i; + int c; + + c = 0; + for (i = 0; i < cgot; i++) + { + if (rand () % 1000 < iPercent) + { + ++(*pqbuf)->ab[(*pqbuf)->cend + i]; + ++c; + } + } + if (zDebug != NULL && c > 0) + fprintf (stderr, "Clobbered %d bytes\n", c); + } + + (*pqbuf)->cend += cgot; + + if (ctotal > 256) + return ctotal; + } +} + +/* Write data to a file descriptor until one of the writes gets no + data. */ + +static boolean +fsend (o, oslave, pqbuf) + int o; + int oslave; + struct sbuf **pqbuf; +{ + long ctotal; + + ctotal = 0; + while (*pqbuf != NULL) + { + int cwrite, cwrote; + + if ((*pqbuf)->cstart >= (*pqbuf)->cend) + { + struct sbuf *qfree; + + qfree = *pqbuf; + *pqbuf = (*pqbuf)->qnext; + free ((pointer) qfree); + continue; + } + +#ifdef FIONREAD + { + long cunread; + + if (ioctl (oslave, FIONREAD, &cunread) < 0) + { + perror ("FIONREAD"); + uchild (SIGCHLD); + } + if (zDebug != NULL) + fprintf (stderr, "%ld unread\n", cunread); + cwrite = 256 - cunread; + if (cwrite <= 0) + break; + } +#else /* ! FIONREAD */ + if (! fwritable (o)) + break; + cwrite = 1; +#endif /* ! FIONREAD */ + + if (cwrite > (*pqbuf)->cend - (*pqbuf)->cstart) + cwrite = (*pqbuf)->cend - (*pqbuf)->cstart; + + cwrote = write (o, (*pqbuf)->ab + (*pqbuf)->cstart, cwrite); + if (cwrote < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) + cwrote = 0; + else + { + perror ("write"); + uchild (SIGCHLD); + } + } + + if (cwrote == 0) + break; + + ctotal += cwrote; + (*pqbuf)->cstart += cwrote; + } + + if (zDebug != NULL && ctotal > 0) + fprintf (stderr, "Wrote %ld to %d\n", ctotal, o); + + return ctotal > 0; +} + +/* Check whether a file descriptor can be written to. */ + +static boolean +fwritable (o) + int o; +{ +#if HAVE_SELECT + + int iwrite; + struct timeval stime; + int cfds; + + iwrite = 1 << o; + + stime.tv_sec = 0; + stime.tv_usec = 0; + + cfds = select (o + 1, (pointer) NULL, (pointer) &iwrite, + (pointer) NULL, &stime); + if (cfds < 0) + { + perror ("select"); + uchild (SIGCHLD); + } + + return cfds > 0; + +#else /* ! HAVE_SELECT */ + +#if HAVE_POLL + + struct pollfd s; + int cfds; + + s.fd = o; + s.events = POLLOUT; + + cfds = poll (&s, 1, 0); + if (cfds < 0) + { + perror ("poll"); + uchild (SIGCHLD); + } + + return cfds > 0; + +#endif /* HAVE_POLL */ +#endif /* ! HAVE_SELECT */ +} + +/* A version of the system command that checks for errors. */ + +static void +xsystem (zcmd) + const char *zcmd; +{ + int istat; + + istat = system ((char *) zcmd); + if (istat != 0) + { + fprintf (stderr, "Command failed with status %d\n", istat); + fprintf (stderr, "%s\n", zcmd); + exit (EXIT_FAILURE); + } +} diff --git a/gnu/libexec/uucp/uuchk/Makefile b/gnu/libexec/uucp/uuchk/Makefile new file mode 100644 index 0000000000..0aaa00f4cd --- /dev/null +++ b/gnu/libexec/uucp/uuchk/Makefile @@ -0,0 +1,16 @@ +# Makefile for uuchk +# $Id: Makefile,v 1.2 1993/08/05 16:15:02 jtc Exp $ + +BINDIR= $(sbindir) +BINOWN= $(owner) + +PROG= uuchk +SRCS= uuchk.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +NOMAN= noman + +.include diff --git a/gnu/libexec/uucp/uuchk/uuchk.c b/gnu/libexec/uucp/uuchk/uuchk.c new file mode 100644 index 0000000000..41021defb8 --- /dev/null +++ b/gnu/libexec/uucp/uuchk/uuchk.c @@ -0,0 +1,856 @@ +/* uuchk.c + Display what we think the permissions of systems are. + + 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 uuchk_rcsid[] = "$Id: uuchk.c,v 1.1 1993/08/04 19:36:14 jtc Exp $"; +#endif + +#include "getopt.h" + +#include "uuconf.h" + +/* Local functions. */ + +static void ukusage P((void)); +static void ukshow P((const struct uuconf_system *qsys, + pointer puuconf)); +static int ikshow_port P((struct uuconf_port *qport, pointer pinfo)); +static void ukshow_dialer P((struct uuconf_dialer *qdial)); +static void ukshow_chat P((const struct uuconf_chat *qchat, + const char *zhdr)); +static void ukshow_size P((struct uuconf_timespan *q, boolean fcall, + boolean flocal)); +static void ukshow_proto_params P((struct uuconf_proto_param *pas, + int cindent)); +static void ukshow_time P((const struct uuconf_timespan *)); +static struct uuconf_timespan *qcompress_span P((struct uuconf_timespan *)); +static void ukuuconf_error P((pointer puuconf, int iret)); + +/* Structure used to pass uuconf pointer into ikshow_port and also let + it record whether any ports were found. */ +struct sinfo +{ + /* The uuconf global pointer. */ + pointer puuconf; + /* The system. */ + const struct uuconf_system *qsys; + /* Whether any ports were seen. */ + boolean fgot; +}; + +/* Long getopt options. */ +static const struct option asKlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + int iopt; + /* The configuration file name. */ + const char *zconfig = NULL; + int iret; + pointer puuconf; + char **pzsystems; + + while ((iopt = getopt_long (argc, argv, "I:x:", asKlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'I': + /* Set the configuration file name. */ + zconfig = optarg; + break; + + case 'x': + /* Set the debugging level. There is actually no debugging + information for this program. */ + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + ukusage (); + break; + } + } + + if (optind != argc) + ukusage (); + + iret = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iret != UUCONF_SUCCESS) + ukuuconf_error (puuconf, iret); + + iret = uuconf_system_names (puuconf, &pzsystems, FALSE); + if (iret != UUCONF_SUCCESS) + ukuuconf_error (puuconf, iret); + + while (*pzsystems != NULL) + { + struct uuconf_system ssys; + + iret = uuconf_system_info (puuconf, *pzsystems, &ssys); + if (iret != UUCONF_SUCCESS) + ukuuconf_error (puuconf, iret); + else + ukshow (&ssys, puuconf); + (void) uuconf_system_free (puuconf, &ssys); + ++pzsystems; + if (*pzsystems != NULL) + printf ("\n"); + } + + exit (EXIT_SUCCESS); + + /* Avoid errors about not returning a value. */ + return 0; +} + +/* Print a usage message and die. */ + +static void +ukusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uuchk [-I file]\n"); + fprintf (stderr, + " -I file: Set configuration file to use\n"); + exit (EXIT_FAILURE); +} + +/* Dump out the information for a system. */ + +static void +ukshow (qsys, puuconf) + const struct uuconf_system *qsys; + pointer puuconf; +{ + char **pz; + int i; + int iret; + + printf ("System: %s", qsys->uuconf_zname); + if (qsys->uuconf_pzalias != NULL) + { + printf (" ("); + for (pz = qsys->uuconf_pzalias; *pz != NULL; pz++) + { + printf ("%s", *pz); + if (pz[1] != NULL) + printf (" "); + } + printf (")"); + } + printf ("\n"); + + for (i = 0; qsys != NULL; qsys = qsys->uuconf_qalternate, i++) + { + boolean fcall, fcalled; + struct uuconf_timespan *qtime, *qspan; + + if (i != 0 || qsys->uuconf_qalternate != NULL) + { + printf ("Alternate %d", i); + if (qsys->uuconf_zalternate != NULL) + printf (" (%s)", qsys->uuconf_zalternate); + printf ("\n"); + } + + /* See if this alternate could be used when calling out. */ + fcall = qsys->uuconf_fcall; + if (qsys->uuconf_qtimegrade == NULL) + fcall = FALSE; + + /* See if this alternate could be used when calling in. */ + fcalled = qsys->uuconf_fcalled; + + if (! fcall && ! fcalled) + { + printf (" This alternate is never used\n"); + continue; + } + + if (fcalled) + { + if (qsys->uuconf_zcalled_login != NULL + && strcmp (qsys->uuconf_zcalled_login, "ANY") != 0) + { + if (i == 0 && qsys->uuconf_qalternate == NULL) + printf (" Caller must log in as %s\n", + qsys->uuconf_zcalled_login); + else + printf (" When called using login name %s\n", + qsys->uuconf_zcalled_login); + } + else + printf (" When called using any login name\n"); + + if (qsys->uuconf_zlocalname != NULL) + printf (" Will use %s as name of local system\n", + qsys->uuconf_zlocalname); + } + + if (fcalled && qsys->uuconf_fcallback) + { + printf (" If called, will call back\n"); + fcalled = FALSE; + } + + if (fcall) + { + struct sinfo si; + + if (i == 0 && qsys->uuconf_qalternate == NULL) + printf (" Call out"); + else + printf (" This alternate applies when calling"); + + if (qsys->uuconf_zport != NULL || qsys->uuconf_qport != NULL) + { + printf (" using "); + if (qsys->uuconf_zport != NULL) + printf ("port %s", qsys->uuconf_zport); + else + printf ("a specially defined port"); + if (qsys->uuconf_ibaud != 0) + { + printf (" at speed %ld", qsys->uuconf_ibaud); + if (qsys->uuconf_ihighbaud != 0) + printf (" to %ld", qsys->uuconf_ihighbaud); + } + printf ("\n"); + } + else if (qsys->uuconf_ibaud != 0) + { + printf (" at speed %ld", qsys->uuconf_ibaud); + if (qsys->uuconf_ihighbaud != 0) + printf (" to %ld", qsys->uuconf_ihighbaud); + printf ("\n"); + } + else + printf (" using any port\n"); + + si.puuconf = puuconf; + si.qsys = qsys; + si.fgot = FALSE; + + if (qsys->uuconf_qport != NULL) + { + printf (" The port is defined as:\n"); + (void) ikshow_port (qsys->uuconf_qport, (pointer) &si); + } + else + { + struct uuconf_port sdummy; + + printf (" The possible ports are:\n"); + iret = uuconf_find_port (puuconf, qsys->uuconf_zport, + qsys->uuconf_ibaud, + qsys->uuconf_ihighbaud, + ikshow_port, (pointer) &si, + &sdummy); + if (iret != UUCONF_NOT_FOUND) + ukuuconf_error (puuconf, iret); + if (! si.fgot) + printf (" *** There are no matching ports\n"); + } + + if (qsys->uuconf_zphone != NULL) + { + if ((qsys->uuconf_zport != NULL + && strcmp (qsys->uuconf_zport, "TCP") == 0) + || (qsys->uuconf_qport != NULL + && (qsys->uuconf_qport->uuconf_ttype + == UUCONF_PORTTYPE_TCP + || qsys->uuconf_qport->uuconf_ttype + == UUCONF_PORTTYPE_TLI))) + printf (" Remote address %s\n", qsys->uuconf_zphone); + else + printf (" Phone number %s\n", qsys->uuconf_zphone); + } + + ukshow_chat (&qsys->uuconf_schat, " Chat"); + + if (qsys->uuconf_zcall_login != NULL + || qsys->uuconf_zcall_password != NULL) + { + char *zlogin, *zpass; + + iret = uuconf_callout (puuconf, qsys, &zlogin, &zpass); + if (iret == UUCONF_NOT_FOUND) + printf (" Can not determine login name or password\n"); + else if (iret != UUCONF_SUCCESS) + ukuuconf_error (puuconf, iret); + else + { + if (zlogin != NULL) + { + printf (" Login name %s\n", zlogin); + free ((pointer) zlogin); + } + if (zpass != NULL) + { + printf (" Password %s\n", zpass); + free ((pointer) zpass); + } + } + } + + qtime = qcompress_span (qsys->uuconf_qtimegrade); + + for (qspan = qtime; qspan != NULL; qspan = qspan->uuconf_qnext) + { + printf (" "); + ukshow_time (qspan); + printf (" may call if "); + if ((char) qspan->uuconf_ival == UUCONF_GRADE_LOW) + printf ("any work"); + else + printf ("work grade %c or higher", (char) qspan->uuconf_ival); + if (qspan->uuconf_cretry != 0) + printf (" (retry %d)", qspan->uuconf_cretry); + printf ("\n"); + } + + if (qsys->uuconf_qcalltimegrade != NULL) + { + boolean fprint, fother; + + qtime = qcompress_span (qsys->uuconf_qcalltimegrade); + fprint = FALSE; + fother = FALSE; + if (qtime->uuconf_istart != 0) + fother = TRUE; + for (qspan = qtime; qspan != NULL; qspan = qspan->uuconf_qnext) + { + if ((char) qspan->uuconf_ival == UUCONF_GRADE_LOW) + { + fother = TRUE; + continue; + } + fprint = TRUE; + printf (" "); + ukshow_time (qspan); + printf (" may accept work grade %c or higher\n", + (char) qspan->uuconf_ival); + if (qspan->uuconf_qnext == NULL) + { + if (qspan->uuconf_iend != 7 * 24 * 60) + fother = TRUE; + } + else + { + if (qspan->uuconf_iend + != qspan->uuconf_qnext->uuconf_istart) + fother = TRUE; + } + } + if (fprint && fother) + printf (" (At other times may accept any work)\n"); + } + } + + if (qsys->uuconf_fsequence) + printf (" Sequence numbers are used\n"); + + if (fcalled) + ukshow_chat (&qsys->uuconf_scalled_chat, " When called, chat"); + + if (qsys->uuconf_zdebug != NULL) + printf (" Debugging level %s\n", qsys->uuconf_zdebug); + if (qsys->uuconf_zmax_remote_debug != NULL) + printf (" Max remote debugging level %s\n", + qsys->uuconf_zmax_remote_debug); + + if (fcall) + { + ukshow_size (qsys->uuconf_qcall_local_size, TRUE, TRUE); + ukshow_size (qsys->uuconf_qcall_remote_size, TRUE, FALSE); + } + if (fcalled) + { + ukshow_size (qsys->uuconf_qcalled_local_size, FALSE, TRUE); + ukshow_size (qsys->uuconf_qcalled_remote_size, FALSE, TRUE); + } + + if (fcall) + printf (" May %smake local requests when calling\n", + qsys->uuconf_fcall_transfer ? "" : "not "); + + if (fcalled) + printf (" May %smake local requests when called\n", + qsys->uuconf_fcalled_transfer ? "" : "not "); + + if (qsys->uuconf_fcall_transfer || qsys->uuconf_fcalled_transfer) + { + printf (" May send by local request:"); + for (pz = qsys->uuconf_pzlocal_send; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (! qsys->uuconf_fsend_request) + printf (" May not send files by remote request\n"); + else + { + printf (" May send by remote request:"); + for (pz = qsys->uuconf_pzremote_send; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (qsys->uuconf_fcall_transfer || qsys->uuconf_fcalled_transfer) + { + printf (" May accept by local request:"); + for (pz = qsys->uuconf_pzlocal_receive; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (! qsys->uuconf_frec_request) + printf (" May not receive files by remote request\n"); + else + { + printf (" May receive by remote request:"); + for (pz = qsys->uuconf_pzremote_receive; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + + printf (" May execute"); + for (pz = qsys->uuconf_pzcmds; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + + printf (" Execution path"); + for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++) + printf (" %s" , *pz); + printf ("\n"); + + if (qsys->uuconf_cfree_space != 0) + printf (" Will leave %ld bytes available\n", qsys->uuconf_cfree_space); + + if (qsys->uuconf_zpubdir != NULL) + printf (" Public directory is %s\n", qsys->uuconf_zpubdir); + + if (qsys->uuconf_pzforward_from != NULL) + { + printf (" May forward from"); + for (pz = qsys->uuconf_pzforward_from; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + + if (qsys->uuconf_pzforward_to != NULL) + { + printf (" May forward to"); + for (pz = qsys->uuconf_pzforward_to; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + + if (qsys->uuconf_zprotocols != NULL) + printf (" Will use protocols %s\n", qsys->uuconf_zprotocols); + else + printf (" Will use any known protocol\n"); + + if (qsys->uuconf_qproto_params != NULL) + ukshow_proto_params (qsys->uuconf_qproto_params, 1); + } +} + +/* Show information about a port. */ + +/*ARGSUSED*/ +static int +ikshow_port (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + struct sinfo *qi = (struct sinfo *) pinfo; + char **pz; + struct uuconf_modem_port *qmodem; + struct uuconf_tli_port *qtli; + + qi->fgot = TRUE; + + printf (" Port name %s\n", qport->uuconf_zname); + switch (qport->uuconf_ttype) + { + case UUCONF_PORTTYPE_STDIN: + printf (" Port type stdin\n"); + break; + case UUCONF_PORTTYPE_DIRECT: + printf (" Port type direct\n"); + if (qport->uuconf_u.uuconf_sdirect.uuconf_zdevice != NULL) + printf (" Device %s\n", + qport->uuconf_u.uuconf_sdirect.uuconf_zdevice); + printf (" Speed %ld\n", qport->uuconf_u.uuconf_sdirect.uuconf_ibaud); + break; + case UUCONF_PORTTYPE_MODEM: + qmodem = &qport->uuconf_u.uuconf_smodem; + printf (" Port type modem\n"); + if (qmodem->uuconf_zdevice != NULL) + printf (" Device %s\n", qmodem->uuconf_zdevice); + if (qmodem->uuconf_zdial_device != NULL) + printf (" Dial device %s\n", qmodem->uuconf_zdial_device); + printf (" Speed %ld\n", qmodem->uuconf_ibaud); + if (qmodem->uuconf_ilowbaud != qmodem->uuconf_ihighbaud) + printf (" Speed range %ld to %ld\n", qmodem->uuconf_ilowbaud, + qmodem->uuconf_ihighbaud); + printf (" Carrier %savailable\n", + qmodem->uuconf_fcarrier ? "" : "not "); + if (qmodem->uuconf_qdialer != NULL) + { + printf (" Specially defined dialer\n"); + ukshow_dialer (qmodem->uuconf_qdialer); + } + else if (qmodem->uuconf_pzdialer != NULL + && qmodem->uuconf_pzdialer[0] != NULL) + { + struct uuconf_dialer sdial; + int iret; + + /* This might be a single dialer name, or it might be a + sequence of dialer/token pairs. */ + + if (qmodem->uuconf_pzdialer[1] == NULL + || qmodem->uuconf_pzdialer[2] == NULL) + { + iret = uuconf_dialer_info (qi->puuconf, + qmodem->uuconf_pzdialer[0], + &sdial); + if (iret == UUCONF_NOT_FOUND) + printf (" *** No dialer %s\n", qmodem->uuconf_pzdialer[0]); + else if (iret != UUCONF_SUCCESS) + ukuuconf_error (qi->puuconf, iret); + else + { + printf (" Dialer %s\n", qmodem->uuconf_pzdialer[0]); + ukshow_dialer (&sdial); + if (qmodem->uuconf_pzdialer[1] != NULL) + printf (" Token %s\n", qmodem->uuconf_pzdialer[1]); + } + } + else + { + pz = qmodem->uuconf_pzdialer; + while (*pz != NULL) + { + iret = uuconf_dialer_info (qi->puuconf, *pz, &sdial); + if (iret == UUCONF_NOT_FOUND) + printf (" *** No dialer %s\n", *pz); + else if (iret != UUCONF_SUCCESS) + ukuuconf_error (qi->puuconf, iret); + else + { + printf (" Dialer %s\n", *pz); + ukshow_dialer (&sdial); + } + + ++pz; + if (*pz != NULL) + { + printf (" Token %s\n", *pz); + ++pz; + } + } + } + } + else + printf (" *** No dialer information\n"); + break; + case UUCONF_PORTTYPE_TCP: + printf (" Port type tcp\n"); + printf (" TCP service %s\n", + qport->uuconf_u.uuconf_stcp.uuconf_zport); + break; + case UUCONF_PORTTYPE_TLI: + qtli = &qport->uuconf_u.uuconf_stli; + printf (" Port type TLI%s\n", + qtli->uuconf_fstream ? "S" : ""); + if (qtli->uuconf_zdevice != NULL) + printf (" Device %s\n", qtli->uuconf_zdevice); + if (qtli->uuconf_pzpush != NULL) + { + printf (" Push"); + for (pz = qtli->uuconf_pzpush; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (qtli->uuconf_pzdialer != NULL + && qtli->uuconf_pzdialer[0] != NULL) + { + printf (" Dialer sequence"); + for (pz = qtli->uuconf_pzdialer; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (qtli->uuconf_zservaddr != NULL) + printf (" Server address %s\n", qtli->uuconf_zservaddr); + break; + default: + fprintf (stderr, " CAN'T HAPPEN\n"); + break; + } + + if (qport->uuconf_zprotocols != NULL) + printf (" Will use protocols %s\n", qport->uuconf_zprotocols); + + if (qport->uuconf_zlockname != NULL) + printf (" Will use lockname %s\n", qport->uuconf_zlockname); + + if (qport->uuconf_qproto_params != NULL) + ukshow_proto_params (qport->uuconf_qproto_params, 3); + + /* Return NOT_FOUND to force find_port to continue searching. */ + return UUCONF_NOT_FOUND; +} + +/* Show information about a dialer. */ + +static void +ukshow_dialer (q) + struct uuconf_dialer *q; +{ + ukshow_chat (&q->uuconf_schat, " Chat"); + printf (" Wait for dialtone %s\n", q->uuconf_zdialtone); + printf (" Pause while dialing %s\n", q->uuconf_zpause); + printf (" Carrier %savailable\n", q->uuconf_fcarrier ? "" : "not "); + if (q->uuconf_fcarrier) + printf (" Wait %d seconds for carrier\n", q->uuconf_ccarrier_wait); + if (q->uuconf_fdtr_toggle) + { + printf (" Toggle DTR"); + if (q->uuconf_fdtr_toggle_wait) + printf (" and wait"); + printf ("\n"); + } + ukshow_chat (&q->uuconf_scomplete, " When complete chat"); + ukshow_chat (&q->uuconf_sabort, " When aborting chat"); + if (q->uuconf_qproto_params != NULL) + ukshow_proto_params (q->uuconf_qproto_params, 4); +} + +/* Show a chat script. */ + +static void +ukshow_chat (qchat, zhdr) + const struct uuconf_chat *qchat; + const char *zhdr; +{ + char **pz; + + if (qchat->uuconf_pzprogram != NULL) + { + printf ("%s program", zhdr); + for (pz = qchat->uuconf_pzprogram; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + + if (qchat->uuconf_pzchat != NULL) + { + + printf ("%s script", zhdr); + for (pz = qchat->uuconf_pzchat; *pz != NULL; pz++) + { + if ((*pz)[0] != '-' || pz == qchat->uuconf_pzchat) + printf (" "); + printf ("%s", *pz); + } + printf ("\n"); + printf ("%s script timeout %d\n", zhdr, qchat->uuconf_ctimeout); + if (qchat->uuconf_pzfail != NULL) + { + printf ("%s failure strings", zhdr); + for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++) + printf (" %s", *pz); + printf ("\n"); + } + if (qchat->uuconf_fstrip) + printf ("%s script incoming bytes stripped to seven bits\n", zhdr); + } +} + +/* Show a size/time restriction. */ + +static void +ukshow_size (qspan, fcall, flocal) + struct uuconf_timespan *qspan; + boolean fcall; + boolean flocal; +{ + struct uuconf_timespan *q; + boolean fother; + + qspan = qcompress_span (qspan); + if (qspan == NULL) + return; + + printf (" If call%s the following applies to a %s request:\n", + fcall ? "ing" : "ed", flocal ? "local" : "remote"); + + fother = FALSE; + if (qspan->uuconf_istart >= 60) + fother = TRUE; + + for (q = qspan; q != NULL; q = q->uuconf_qnext) + { + printf (" "); + ukshow_time (q); + printf (" may transfer files %ld bytes or smaller\n", q->uuconf_ival); + if (q->uuconf_qnext == NULL) + { + if (q->uuconf_iend <= 6 * 24 * 60 + 23 * 60) + fother = TRUE; + } + else + { + if (q->uuconf_iend + 60 <= q->uuconf_qnext->uuconf_istart) + fother = TRUE; + } + } + + if (fother) + printf (" (At other times may send files of any size)\n"); +} + +/* Show protocol parameters. */ + +static void +ukshow_proto_params (pas, cindent) + struct uuconf_proto_param *pas; + int cindent; +{ + struct uuconf_proto_param *q; + + for (q = pas; q->uuconf_bproto != '\0'; q++) + { + int i; + struct uuconf_proto_param_entry *qe; + + for (i = 0; i < cindent; i++) + printf (" "); + printf ("For protocol %c will use the following parameters\n", + q->uuconf_bproto); + for (qe = q->uuconf_qentries; qe->uuconf_cargs > 0; qe++) + { + int ia; + + for (i = 0; i < cindent; i++) + printf (" "); + for (ia = 0; ia < qe->uuconf_cargs; ia++) + printf (" %s", qe->uuconf_pzargs[ia]); + printf ("\n"); + } + } +} + +/* Display a time span. */ + +static void +ukshow_time (q) + const struct uuconf_timespan *q; +{ + int idaystart, idayend; + int ihourstart, ihourend; + int iminutestart, iminuteend; + const char * const zdays = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0Sun"; + + if (q->uuconf_istart == 0 && q->uuconf_iend == 7 * 24 * 60) + { + printf ("At any time"); + return; + } + + idaystart = q->uuconf_istart / (24 * 60); + ihourstart = (q->uuconf_istart % (24 * 60)) / 60; + iminutestart = q->uuconf_istart % 60; + idayend = q->uuconf_iend / (24 * 60); + ihourend = (q->uuconf_iend % (24 * 60)) / 60; + iminuteend = q->uuconf_iend % 60; + + if (idaystart == idayend) + printf ("%s from %02d:%02d to %02d:%02d", zdays + idaystart * 4, + ihourstart, iminutestart, ihourend, iminuteend); + else + printf ("From %s %02d:%02d to %s %02d:%02d", + zdays + idaystart * 4, ihourstart, iminutestart, + zdays + idayend * 4, ihourend, iminuteend); +} + +/* Compress a time span by merging any two adjacent spans with + identical values. This isn't necessary for uucico, but it looks + nicer when printed out. */ + +static struct uuconf_timespan * +qcompress_span (qlist) + struct uuconf_timespan *qlist; +{ + struct uuconf_timespan **pq; + + pq = &qlist; + while (*pq != NULL) + { + if ((*pq)->uuconf_qnext != NULL + && (*pq)->uuconf_iend == (*pq)->uuconf_qnext->uuconf_istart + && (*pq)->uuconf_ival == (*pq)->uuconf_qnext->uuconf_ival) + { + struct uuconf_timespan *qnext; + + qnext = (*pq)->uuconf_qnext; + (*pq)->uuconf_qnext = qnext->uuconf_qnext; + (*pq)->uuconf_iend = qnext->uuconf_iend; + } + else + pq = &(*pq)->uuconf_qnext; + } + + return qlist; +} + +/* Display a uuconf error and exit. */ + +static void +ukuuconf_error (puuconf, iret) + pointer puuconf; + int iret; +{ + char ab[512]; + + (void) uuconf_error_string (puuconf, iret, ab, sizeof ab); + if ((iret & UUCONF_ERROR_FILENAME) == 0) + fprintf (stderr, "uuchk: %s\n", ab); + else + fprintf (stderr, "uuchk:%s\n", ab); + exit (EXIT_FAILURE); +} diff --git a/gnu/libexec/uucp/uucico/Makefile b/gnu/libexec/uucp/uucico/Makefile new file mode 100644 index 0000000000..e4c58aa7af --- /dev/null +++ b/gnu/libexec/uucp/uucico/Makefile @@ -0,0 +1,20 @@ +# Makefile for uucico +# $Id: Makefile,v 1.2 1993/08/05 16:15:06 jtc Exp $ + +BINDIR= $(sbindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uucico +SRCS= uucico.c trans.c send.c rec.c xcmd.c prot.c protg.c protf.c \ + prott.c prote.c proti.c protj.c protz.c time.c chat.c \ + conn.c copy.c log.c tcp.c tli.c util.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +MAN8= uucico.0 + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uucico/prote.c b/gnu/libexec/uucp/uucico/prote.c new file mode 100644 index 0000000000..2d2e77e1d8 --- /dev/null +++ b/gnu/libexec/uucp/uucico/prote.c @@ -0,0 +1,387 @@ +/* prote.c + The 'e' protocol. + + 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 prote_rcsid[] = "$Id: prote.c,v 1.1 1993/08/04 19:36:18 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* This implementation is based on my implementation of the 't' + protocol, which is fairly similar. The main difference between the + protocols seems to be that 't' breaks the file into packets and + transmits the size of the packet with each packet, whereas 'e' + sends the size of the entire file and then sends all the data in a + single enormous packet. + + The 'e' protocol does no error checking whatsoever and thus + requires an end-to-end verified eight bit communication line, such + as is provided by TCP. Using it with a modem is inadvisable, since + errors can occur between the modem and the computer. */ + +/* The buffer size we use. */ +#define CEBUFSIZE (CRECBUFLEN / 2) + +/* The size of the initial file size message. */ +#define CEFRAMELEN (20) + +/* A pointer to the buffer we will use. */ +static char *zEbuf; + +/* True if we are receiving a file. */ +static boolean fEfile; + +/* The number of bytes we have left to send or receive. */ +static long cEbytes; + +/* The timeout we use. */ +static int cEtimeout = 120; + +struct uuconf_cmdtab asEproto_params[] = +{ + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cEtimeout, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Local function. */ + +static boolean feprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, + size_t *pcneed)); + +/* Start the protocol. */ + +boolean +festart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + *pzlog = NULL; + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + zEbuf = (char *) xmalloc (CEBUFSIZE); + fEfile = FALSE; + usysdep_sleep (2); + return TRUE; +} + +/* Stop the protocol. */ + +/*ARGSUSED*/ +boolean +feshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + xfree ((pointer) zEbuf); + zEbuf = NULL; + cEtimeout = 120; + return TRUE; +} + +/* Send a command string. We send everything up to and including the + null byte. */ + +/*ARGSUSED*/ +boolean +fesendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fesendcmd: Sending command \"%s\"", z); + + return fsend_data (qdaemon->qconn, z, strlen (z) + 1, TRUE); +} + +/* Get space to be filled with data. We provide a buffer which has + 20 bytes at the start available to hold the length. */ + +/*ARGSUSED*/ +char * +zegetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = CEBUFSIZE; + return zEbuf; +} + +/* Send out some data. We are allowed to modify the 20 bytes + preceding the buffer. This allows us to send the entire block with + header bytes in a single call. */ + +/*ARGSIGNORED*/ +boolean +fesenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ +#if DEBUG > 0 + /* Keep track of the number of bytes we send out to make sure it all + adds up. */ + cEbytes -= cdata; + if (cEbytes < 0) + { + ulog (LOG_ERROR, "Protocol 'e' internal error"); + return FALSE; + } +#endif + + /* We pass FALSE to fsend_data since we don't expect the other side + to be sending us anything just now. */ + return fsend_data (qdaemon->qconn, zdata, cdata, FALSE); +} + +/* Process data and return the amount we need in *pfneed. */ + +static boolean +feprocess_data (qdaemon, pfexit, pcneed) + struct sdaemon *qdaemon; + boolean *pfexit; + size_t *pcneed; +{ + int cinbuf, cfirst, clen; + + *pfexit = FALSE; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + + if (! fEfile) + { + /* We are not receiving a file. Commands continue up to a null + byte. */ + while (cinbuf > 0) + { + char *pnull; + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > cinbuf) + cfirst = cinbuf; + + pnull = memchr (abPrecbuf + iPrecstart, '\0', (size_t) cfirst); + if (pnull != NULL) + cfirst = pnull - (abPrecbuf + iPrecstart) + 1; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "feprocess_data: Got %d command bytes", + cfirst); + + if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, + (size_t) cfirst, (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + cfirst) % CRECBUFLEN; + + if (*pfexit) + return TRUE; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + } + + if (pcneed != NULL) + *pcneed = 1; + + return TRUE; + } + + /* Here we are receiving a file. We want cEbytes in total. If we + don't have cEbytes yet, we have to get it first. */ + + if (cEbytes == -1) + { + char ab[CEFRAMELEN + 1]; + + if (cinbuf < CEFRAMELEN) + { + if (pcneed != NULL) + *pcneed = CEFRAMELEN - cinbuf; + return TRUE; + } + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst >= CEFRAMELEN) + memcpy (ab, abPrecbuf + iPrecstart, (size_t) CEFRAMELEN); + else + { + memcpy (ab, abPrecbuf + iPrecstart, (size_t) cfirst); + memcpy (ab + cfirst, abPrecbuf, (size_t) CEFRAMELEN - cfirst); + } + + ab[CEFRAMELEN] = '\0'; + cEbytes = strtol (ab, (char **) NULL, 10); + + iPrecstart = (iPrecstart + CEFRAMELEN) % CRECBUFLEN; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + } + + /* Here we can read real data for the file. */ + + while (cinbuf > 0) + { + clen = cinbuf; + if ((long) clen > cEbytes) + clen = (int) cEbytes; + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > clen) + cfirst = clen; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "feprocess_data: Got %d data bytes", + clen); + + if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, + (size_t) cfirst, abPrecbuf, (size_t) (clen - cfirst), + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + cEbytes -= clen; + + if (cEbytes == 0) + { + if (! fgot_data (qdaemon, abPrecbuf, (size_t) 0, + (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + if (*pfexit) + return TRUE; + } + + cinbuf -= clen; + } + + if (pcneed != NULL) + { + if (cEbytes > CRECBUFLEN / 2) + *pcneed = CRECBUFLEN / 2; + else + *pcneed = (int) cEbytes; + } + + return TRUE; +} + +/* Wait for data to come in and process it until we've reached the end + of a command or a file. */ + +boolean +fewait (qdaemon) + struct sdaemon *qdaemon; +{ + while (TRUE) + { + boolean fexit; + size_t cneed, crec; + + if (! feprocess_data (qdaemon, &fexit, &cneed)) + return FALSE; + if (fexit) + return TRUE; + + if (! freceive_data (qdaemon->qconn, cneed, &crec, cEtimeout, TRUE)) + return FALSE; + + if (crec == 0) + { + ulog (LOG_ERROR, "Timed out waiting for data"); + return FALSE; + } + } +} + +/* File level routine, to handle transferring the amount of data and + to set fEfile correctly. */ + +boolean +fefile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fstart; + boolean fsend; + long cbytes; + boolean *pfhandled; +{ + *pfhandled = FALSE; + + if (fstart) + { + if (fsend) + { + char ab[CEFRAMELEN]; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "Protocol 'e' starting to send %ld bytes", + cbytes); + + bzero (ab, (size_t) CEFRAMELEN); + sprintf (ab, "%ld", cbytes); + if (! fsend_data (qdaemon->qconn, ab, (size_t) CEFRAMELEN, TRUE)) + return FALSE; + cEbytes = cbytes; + } + else + { + cEbytes = -1; + fEfile = TRUE; + } + } + else + { + if (! fsend) + fEfile = FALSE; +#if DEBUG > 0 + if (cEbytes != 0) + { + ulog (LOG_ERROR, + "Protocol 'e' internal error: %ld bytes left over", + cEbytes); + return FALSE; + } +#endif + } + + return TRUE; +} diff --git a/gnu/libexec/uucp/uucico/protf.c b/gnu/libexec/uucp/uucico/protf.c new file mode 100644 index 0000000000..3cdacef25e --- /dev/null +++ b/gnu/libexec/uucp/uucico/protf.c @@ -0,0 +1,842 @@ +/* protf.c + The 'f' protocol. + + 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 protf_rcsid[] = "$Id: protf.c,v 1.1 1993/08/04 19:36:19 jtc Exp $"; +#endif + +#include +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* This implementation is based on code by Piet Beertema, CWI, + Amsterdam, Sep 1984. + + This code implements the 'f' protocol, which requires a + flow-controlled error-free seven-bit data path. It does check for + errors, but only at the end of each file transmission, so a noisy + line without error correcting modems will be unusable. + + The conversion to seven bit data is done as follows, where b + represents the character to convert: + + 0 <= b <= 037: 0172, b + 0100 (0100 to 0137) + 040 <= b <= 0171: b ( 040 to 0171) + 0172 <= b <= 0177: 0173, b - 0100 ( 072 to 077) + 0200 <= b <= 0237: 0174, b - 0100 (0100 to 0137) + 0240 <= b <= 0371: 0175, b - 0200 ( 040 to 0171) + 0372 <= b <= 0377: 0176, b - 0300 ( 072 to 077) + + This causes all output bytes to be in the range 040 to 0176; these + are the printable ASCII characters. */ + +/* This structure is used to hold information when dealing with the + end of file acknowledgement. */ + +struct sfinfo +{ + /* The functions from the generic code. */ + boolean (*psendfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon)); + boolean (*precfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); + /* The info pointer from the generic code. */ + pointer pinfo; + /* The character to send after receiving the checksum. */ + char bsend; +}; + +/* Internal functions. */ +static boolean ffprocess_data P((struct sdaemon *qdaemon, + boolean *pfexit, size_t *pcneed)); +static boolean ffawait_ack P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean ffawait_cksum P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean ffsend_ack P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); + +/* The size of the buffer we allocate to store outgoing data in. */ +#define CFBUFSIZE (256) + +/* The timeout to wait for data to arrive before giving up. */ +static int cFtimeout = 120; + +/* The maximum number of retries. */ +static int cFmaxretries = 2; + +/* The buffer we allocate for outgoing data. */ +static char *zFbuf; + +/* TRUE if we are receiving a file rather than a command. */ +static boolean fFfile; + +/* The checksum so far. */ +static unsigned int iFcheck; + +/* The last special byte (0172 to 0176) or 0 if none. */ +static char bFspecial; + +/* The number of times we have retried this file. */ +static int cFretries; + +/* Whether this file has been acknowledged. */ +static boolean fFacked; + +struct uuconf_cmdtab asFproto_params[] = +{ + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cFtimeout, NULL }, + { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cFmaxretries, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Statistics. */ + +/* The number of data bytes sent in files. */ +static long cFsent_data; + +/* The number of actual bytes sent in files. */ +static long cFsent_bytes; + +/* The number of data bytes received in files. */ +static long cFrec_data; + +/* The number of actual bytes received in files. */ +static long cFrec_bytes; + +/* The number of file retries when sending. */ +static long cFsend_retries; + +/* The number of file retries when receiving. */ +static long cFrec_retries; + +/* Start the protocol. */ + +boolean +ffstart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + *pzlog = NULL; + + cFsent_data = 0; + cFsent_bytes = 0; + cFrec_data = 0; + cFrec_bytes = 0; + cFsend_retries = 0; + cFrec_retries = 0; + + /* Use XON/XOFF handshaking. */ + if (! fconn_set (qdaemon->qconn, PARITYSETTING_DEFAULT, + STRIPSETTING_SEVENBITS, XONXOFF_ON)) + return FALSE; + + /* We sleep to allow the other side to reset the terminal; this is + what Mr. Beertema's code does. */ + usysdep_sleep (2); + + return TRUE; +} + +/* Shutdown the protocol. */ + +/*ARGSIGNORED*/ +boolean +ffshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + xfree ((pointer) zFbuf); + zFbuf = NULL; + ulog (LOG_NORMAL, + "Protocol 'f': sent %ld bytes for %ld, received %ld bytes for %ld", + cFsent_bytes, cFsent_data, cFrec_bytes, cFrec_data); + if (cFsend_retries != 0 || cFrec_retries != 0) + ulog (LOG_NORMAL, "Protocol 'f' file retries: %ld sending, %ld receiving", + cFsend_retries, cFrec_retries); + cFtimeout = 120; + cFmaxretries = 2; + return TRUE; +} + +/* Send a command string. We just send the string followed by a carriage + return. */ + +/*ARGSUSED*/ +boolean +ffsendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen; + char *zalc; + boolean fret; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ffsendcmd: Sending command \"%s\"", z); + + clen = strlen (z); + zalc = zbufalc (clen + 2); + memcpy (zalc, z, clen); + zalc[clen] = '\r'; + zalc[clen + 1] = '\0'; + fret = fsend_data (qdaemon->qconn, zalc, clen + 1, TRUE); + ubuffree (zalc); + return fret; +} + +/* Get space to be filled with data. We allocate the space from the + heap. */ + +/*ARGSIGNORED*/ +char * +zfgetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = CFBUFSIZE; + if (zFbuf == NULL) + zFbuf = (char *) xmalloc (CFBUFSIZE); + return zFbuf; +} + +/* Send out a data packet. We have to encode the data into seven bits + and accumulate a checksum. */ + +/*ARGSIGNORED*/ +boolean +ffsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ + char ab[CFBUFSIZE * 2]; + char *ze; + register unsigned int itmpchk; + + cFsent_data += cdata; + + ze = ab; + itmpchk = iFcheck; + while (cdata-- > 0) + { + register int b; + + /* Rotate the checksum left. */ + if ((itmpchk & 0x8000) == 0) + itmpchk <<= 1; + else + { + itmpchk <<= 1; + ++itmpchk; + } + + /* Add the next byte into the checksum. */ + b = *zdata++ & 0xff; + itmpchk += b; + + /* Encode the byte. */ + if (b <= 0177) + { + if (b <= 037) + { + *ze++ = '\172'; + *ze++ = (char) (b + 0100); + } + else if (b <= 0171) + *ze++ = (char) b; + else + { + *ze++ = '\173'; + *ze++ = (char) (b - 0100); + } + } + else + { + if (b <= 0237) + { + *ze++ = '\174'; + *ze++ = (char) (b - 0100); + } + else if (b <= 0371) + { + *ze++ = '\175'; + *ze++ = (char) (b - 0200); + } + else + { + *ze++ = '\176'; + *ze++ = (char) (b - 0300); + } + } + } + + iFcheck = itmpchk; + + cFsent_bytes += ze - ab; + + /* Passing FALSE tells fsend_data not to bother looking for incoming + information, since we really don't expect any. */ + return fsend_data (qdaemon->qconn, ab, (size_t) (ze - ab), FALSE); +} + +/* Process data and return the amount of data we are looking for in + *pcneed. The 'f' protocol doesn't really reveal this, but when + transferring file we know that we need at least seven characters + for the checksum. */ + +static boolean +ffprocess_data (qdaemon, pfexit, pcneed) + struct sdaemon *qdaemon; + boolean *pfexit; + size_t *pcneed; +{ + int i; + register unsigned int itmpchk; + + *pfexit = FALSE; + if (pcneed != NULL) + *pcneed = 1; + + if (! fFfile) + { + /* A command continues until a '\r' character, which we turn + into '\0' before calling fgot_data. */ + while (iPrecstart != iPrecend) + { + for (i = iPrecstart; i < CRECBUFLEN && i != iPrecend; i++) + { + if (abPrecbuf[i] == '\r') + { + int istart; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "ffprocess_data: Got %d command bytes", + i - iPrecstart + 1); + + abPrecbuf[i] = '\0'; + istart = iPrecstart; + iPrecstart = (i + 1) % CRECBUFLEN; + if (pcneed != NULL) + *pcneed = 0; + return fgot_data (qdaemon, abPrecbuf + istart, + (size_t) (i - istart + 1), + (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit); + } + } + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "ffprocess_data: Got %d command bytes", + i - iPrecstart); + + if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, + (size_t) (i - iPrecstart), + (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = i % CRECBUFLEN; + } + + return TRUE; + } + + /* Here the data is destined for a file, and we must decode it. */ + + itmpchk = iFcheck; + + while (iPrecstart != iPrecend) + { + char *zstart, *zto, *zfrom; + int c; + + zto = zfrom = zstart = abPrecbuf + iPrecstart; + + c = iPrecend - iPrecstart; + if (c < 0) + c = CRECBUFLEN - iPrecstart; + + while (c-- != 0) + { + int b; + + b = *zfrom++ & 0xff; + if (b < 040 || b > 0176) + { + ulog (LOG_ERROR, "Illegal byte %d", b); + continue; + } + + /* Characters >= 0172 are always special characters. The + only legal pair of consecutive special characters + are 0176 0176 which immediately precede the four + digit checksum. */ + if (b >= 0172) + { + if (bFspecial != 0) + { + if (bFspecial != 0176 || b != 0176) + { + ulog (LOG_ERROR, "Illegal bytes %d %d", + bFspecial, b); + bFspecial = 0; + continue; + } + + /* Pass any initial data. */ + if (zto != zstart) + { + /* Don't count the checksum in the received bytes. */ + cFrec_bytes += zfrom - zstart - 2; + cFrec_data += zto - zstart; + if (! fgot_data (qdaemon, zstart, + (size_t) (zto - zstart), + (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + } + + /* The next characters we want to read are the + checksum, so skip the second 0176. */ + iPrecstart = (iPrecstart + zfrom - zstart) % CRECBUFLEN; + + iFcheck = itmpchk; + + /* Tell fgot_data that we've read the entire file by + passing 0 length data. This will wind up calling + fffile to verify the checksum. We set *pcneed to + 0 because we don't want to read any more data + from the port, since we may have already read the + checksum. */ + if (pcneed != NULL) + *pcneed = 0; + return fgot_data (qdaemon, (const char *) NULL, + (size_t) 0, (const char *) NULL, + (size_t) 0, -1, -1, (long) -1, + TRUE, pfexit); + } + + /* Here we have encountered a special character that + does not follow another special character. */ + bFspecial = (char) b; + } + else + { + int bnext; + + /* Here we have encountered a nonspecial character. */ + + switch (bFspecial) + { + default: + bnext = b; + break; + case 0172: + bnext = b - 0100; + break; + case 0173: + case 0174: + bnext = b + 0100; + break; + case 0175: + bnext = b + 0200; + break; + case 0176: + bnext = b + 0300; + break; + } + + *zto++ = (char) bnext; + bFspecial = 0; + + /* Rotate the checksum left. */ + if ((itmpchk & 0x8000) == 0) + itmpchk <<= 1; + else + { + itmpchk <<= 1; + ++itmpchk; + } + + /* Add the next byte into the checksum. */ + itmpchk += bnext; + } + } + + if (zto != zstart) + { + DEBUG_MESSAGE1 (DEBUG_PROTO, + "ffprocess_data: Got %d bytes", + zto - zstart); + + cFrec_data += zto - zstart; + if (! fgot_data (qdaemon, zstart, (size_t) (zto - zstart), + (const char *) NULL, (size_t) 0, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + } + + cFrec_bytes += zfrom - zstart; + + iPrecstart = (iPrecstart + zfrom - zstart) % CRECBUFLEN; + } + + iFcheck = itmpchk; + + if (pcneed != NULL) + { + /* At this point we may have seen the first 0176 in the checksum + but not the second. The checksum is at least seven + characters long (0176 0176 a b c d \r). This won't help + much, but reading seven characters is a lot better than + reading two, which is what I saw in a 2400 baud log file. */ + if (bFspecial == 0176) + *pcneed = 6; + else + *pcneed = 7; + } + + return TRUE; +} + +/* Wait for data to come in and process it until we've finished a + command or a file. */ + +boolean +ffwait (qdaemon) + struct sdaemon *qdaemon; +{ + while (TRUE) + { + boolean fexit; + size_t cneed, crec; + + if (! ffprocess_data (qdaemon, &fexit, &cneed)) + return FALSE; + if (fexit) + return TRUE; + + if (cneed > 0) + { + /* We really want to do something like get all available + characters, then sleep for half a second and get all + available characters again, and keep this up until we + don't get anything after sleeping. */ + if (! freceive_data (qdaemon->qconn, cneed, &crec, cFtimeout, TRUE)) + return FALSE; + if (crec == 0) + { + ulog (LOG_ERROR, "Timed out waiting for data"); + return FALSE; + } + } + } +} + +/* File level operations. Reset the checksums when starting to send + or receive a file, and output the checksum when we've finished + sending a file. */ + +/*ARGSUSED*/ +boolean +fffile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fstart; + boolean fsend; + long cbytes; + boolean *pfhandled; +{ + DEBUG_MESSAGE3 (DEBUG_PROTO, "fffile: fstart %s; fsend %s; fFacked %s", + fstart ? "true" : "false", fsend ? "true" : "false", + fFacked ? "true" : "false"); + + *pfhandled = FALSE; + + if (fstart) + { + iFcheck = 0xffff; + cFretries = 0; + fFacked = FALSE; + if (! fsend) + { + bFspecial = 0; + fFfile = TRUE; + } + return TRUE; + } + else + { + struct sfinfo *qinfo; + + /* We need to handle the checksum and the acknowledgement. If + we get a successful ACK, we set fFacked to TRUE and call the + send or receive function by hand. This will wind up calling + here again, so if fFacked is TRUE we just return out and let + the send or receive function do whatever it does. This is a + bit of a hack. */ + if (fFacked) + { + fFacked = FALSE; + return TRUE; + } + + if (fsend) + { + char ab[sizeof "\176\176ABCD\r"]; + + /* Send the final checksum. */ + sprintf (ab, "\176\176%04x\r", iFcheck & 0xffff); + if (! fsend_data (qdaemon->qconn, ab, (size_t) 7, TRUE)) + return FALSE; + + /* Now wait for the acknowledgement. */ + fFfile = FALSE; + qinfo = (struct sfinfo *) xmalloc (sizeof (struct sfinfo)); + qinfo->psendfn = qtrans->psendfn; + qinfo->precfn = qtrans->precfn; + qinfo->pinfo = qtrans->pinfo; + qtrans->psendfn = NULL; + qtrans->precfn = ffawait_ack; + qtrans->pinfo = (pointer) qinfo; + qtrans->fcmd = TRUE; + + *pfhandled = TRUE; + + return fqueue_receive (qdaemon, qtrans); + } + else + { + /* Wait for the checksum. */ + fFfile = FALSE; + qinfo = (struct sfinfo *) xmalloc (sizeof (struct sfinfo)); + qinfo->psendfn = qtrans->psendfn; + qinfo->precfn = qtrans->precfn; + qinfo->pinfo = qtrans->pinfo; + qtrans->psendfn = NULL; + qtrans->precfn = ffawait_cksum; + qtrans->pinfo = (pointer) qinfo; + qtrans->fcmd = TRUE; + + *pfhandled = TRUE; + + return fqueue_receive (qdaemon, qtrans); + } + } +} + +/* Wait for the ack after sending a file and the checksum. */ + +static boolean +ffawait_ack (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; + + qtrans->precfn = NULL; + + /* An R means to retry sending the file. */ + if (*zdata == 'R') + { + if (! ffileisopen (qtrans->e)) + { + ulog (LOG_ERROR, "Request to resent non-file"); + return FALSE; + } + + ++cFretries; + if (cFretries > cFmaxretries) + { + ulog (LOG_ERROR, "Too many retries"); + return FALSE; + } + + ulog (LOG_NORMAL, "Resending file"); + if (! ffilerewind (qtrans->e)) + { + ulog (LOG_ERROR, "rewind: %s", strerror (errno)); + return FALSE; + } + qtrans->ipos = (long) 0; + + iFcheck = 0xffff; + ++cFsend_retries; + + qtrans->psendfn = qinfo->psendfn; + qtrans->precfn = qinfo->precfn; + qtrans->pinfo = qinfo->pinfo; + xfree ((pointer) qinfo); + qtrans->fsendfile = TRUE; + + return fqueue_send (qdaemon, qtrans); + } + + if (*zdata != 'G') + { + DEBUG_MESSAGE1 (DEBUG_PROTO, "fffile: Got \"%s\"", zdata); + ulog (LOG_ERROR, "File send failed"); + return FALSE; + } + + qtrans->psendfn = qinfo->psendfn; + qtrans->precfn = qinfo->precfn; + qtrans->pinfo = qinfo->pinfo; + xfree ((pointer) qinfo); + + /* Now call the send function by hand after setting fFacked to TRUE. + Since fFacked is true fffile will simply return out, and the send + function can do whatever it what was going to do. */ + fFacked = TRUE; + return (*qtrans->psendfn) (qtrans, qdaemon); +} + +/* This function is called when the checksum arrives. */ + +/*ARGSUSED*/ +static boolean +ffawait_cksum (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; + unsigned int icheck; + + qtrans->precfn = NULL; + + if (! isxdigit (zdata[0]) + || ! isxdigit (zdata[1]) + || ! isxdigit (zdata[2]) + || ! isxdigit (zdata[3]) + || zdata[4] != '\0') + { + ulog (LOG_ERROR, "Bad checksum format"); + xfree (qtrans->pinfo); + return FALSE; + } + + icheck = (unsigned int) strtol ((char *) zdata, (char **) NULL, 16); + + if (icheck != (iFcheck & 0xffff)) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "Checksum failed; calculated 0x%x, got 0x%x", + iFcheck & 0xffff, icheck); + + if (! ffileisopen (qtrans->e)) + { + ulog (LOG_ERROR, "Failed to get non-file"); + return FALSE; + } + + ++cFretries; + if (cFretries > cFmaxretries) + { + ulog (LOG_ERROR, "Too many retries"); + qinfo->bsend = 'Q'; + } + else + { + ulog (LOG_NORMAL, "File being resent"); + + /* This bit of code relies on the receive code setting + qtrans->s.ztemp to the full name of the temporary file + being used. */ + qtrans->e = esysdep_truncate (qtrans->e, qtrans->s.ztemp); + if (! ffileisopen (qtrans->e)) + return FALSE; + qtrans->ipos = (long) 0; + + iFcheck = 0xffff; + bFspecial = 0; + fFfile = TRUE; + ++cFrec_retries; + + /* Send an R to tell the other side to resend the file. */ + qinfo->bsend = 'R'; + } + } + else + { + /* Send a G to tell the other side the file was received + correctly. */ + qinfo->bsend = 'G'; + } + + qtrans->psendfn = ffsend_ack; + + return fqueue_send (qdaemon, qtrans); +} + +/* Send the acknowledgement, and then possible wait for the resent + file. */ + +static boolean +ffsend_ack (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; + char ab[2]; + + ab[0] = qinfo->bsend; + ab[1] = '\0'; + if (! ffsendcmd (qdaemon, ab, 0, 0)) + return FALSE; + + qtrans->psendfn = qinfo->psendfn; + qtrans->precfn = qinfo->precfn; + qtrans->pinfo = qinfo->pinfo; + xfree ((pointer) qinfo); + + if (ab[0] == 'Q') + return FALSE; + if (ab[0] == 'R') + { + qtrans->frecfile = TRUE; + return fqueue_receive (qdaemon, qtrans); + } + + fFacked = TRUE; + return (*qtrans->precfn) (qtrans, qdaemon, (const char *) NULL, + (size_t) 0); +} diff --git a/gnu/libexec/uucp/uucico/protg.c b/gnu/libexec/uucp/uucico/protg.c new file mode 100644 index 0000000000..e9eaeb0490 --- /dev/null +++ b/gnu/libexec/uucp/uucico/protg.c @@ -0,0 +1,1933 @@ +/* protg.c + The 'g' protocol. + + 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 protg_rcsid[] = "$Id: protg.c,v 1.1 1993/08/04 19:36:20 jtc Exp $"; +#endif + +#include +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* Each 'g' protocol packet begins with six bytes. They are: + + + + is the ASCII DLE character (^P or '\020'). + if 1 <= <= 8, the packet is followed by 2 ** (k + 4) bytes of data; + if == 9, these six bytes are a complete control packet; + other value of are illegal. + is the low byte of a checksum. + is the high byte of a checksum. + is a control byte (see below). + is ^ ^ ^ . + + The control byte is divided into three bitfields: + + t t x x x y y y + + The two bit field tt is the packet type. + The three bit field xxx is the control type for a control packet, or + the sequence number for a data packet. + The three bit field yyy is a value for a control packet, or the + sequence number of the last packet received for a data packet. + + For all successfully recieved packets, the control byte is stored + into iGpacket_control. */ + +/* Names for the bytes in the frame header. */ +#define IFRAME_DLE (0) +#define IFRAME_K (1) +#define IFRAME_CHECKLOW (2) +#define IFRAME_CHECKHIGH (3) +#define IFRAME_CONTROL (4) +#define IFRAME_XOR (5) + +/* Length of the frame header. */ +#define CFRAMELEN (6) + +/* Macros to break apart the control bytes. */ +#define CONTROL_TT(b) ((int)(((b) >> 6) & 03)) +#define CONTROL_XXX(b) ((int)(((b) >> 3) & 07)) +#define CONTROL_YYY(b) ((int)((b) & 07)) + +/* DLE value. */ +#define DLE ('\020') + +/* Get the length of a packet given a pointer to the header. */ +#define CPACKLEN(z) ((size_t) (1 << ((z)[IFRAME_K] + 4))) + +/* field value for a control message. */ +#define KCONTROL (9) + +/* Get the next sequence number given a sequence number. */ +#define INEXTSEQ(i) ((i + 1) & 07) + +/* Compute i1 - i2 modulo 8. */ +#define CSEQDIFF(i1, i2) (((i1) + 8 - (i2)) & 07) + +/* Packet types. These are from the tt field. + CONTROL -- control packet + ALTCHAN -- alternate channel; not used by UUCP + DATA -- full data segment + SHORTDATA -- less than full data segment (all the bytes specified by + the packet length are always transferred). Let be the number + of bytes in the data segment not to be used. If <= 0x7f, the first + byte of the data segment is and the data follows. If > 0x7f, + the first byte of the data segment is 0x80 | ( & 0x7f), the second + byte of the data segment is >> 7, and the data follows. The + maximum possible data segment size is 2**12, so this handles all + possible cases. */ +#define CONTROL (0) +#define ALTCHAN (1) +#define DATA (2) +#define SHORTDATA (3) + +/* Control types. These are from the xxx field if the type (tt field) + is CONTROL. + + CLOSE -- close the connection + RJ -- reject; packet yyy last to be received correctly + SRJ -- selective reject; reject only packet yyy (not used by UUCP) + RR -- receiver ready; packet yyy received correctly + INITC -- third step of initialization; yyy holds window size + INITB -- second step of initialization; yyy holds maximum value - 1 + INITA -- first step of initialization; yyy holds window size. + + The yyy value for RR is the same as the yyy value for an ordinary + data packet. */ +#define CLOSE (1) +#define RJ (2) +#define SRJ (3) +#define RR (4) +#define INITC (5) +#define INITB (6) +#define INITA (7) + +/* Maximum amount of data in a single packet. This is set by the + field in the header; the amount of data in a packet is + 2 ** ( + 4). ranges from 1 to 8. */ + +#define CMAXDATAINDEX (8) + +#define CMAXDATA (1 << (CMAXDATAINDEX + 4)) + +/* Maximum window size. */ +#define CMAXWINDOW (7) + +/* Defaults for the protocol parameters. These may all be changed by + using the ``protocol-parameter g'' command, so there is no + particular reason to change the values given here. */ + +/* The desired window size. This is what we tell the other system to + use. It must be between 1 and 7, and there's no reason to use less + than 7. Protocol parameter ``window''. */ +#define IWINDOW (7) + +/* The desired packet size. Many implementations only support 64 byte + packets. Protocol parameter ``packet-size''. */ +#define IPACKSIZE (64) + +/* The number of times to retry the exchange of INIT packets when + starting the protocol. Protocol parameter ``startup-retries''. */ +#define CSTARTUP_RETRIES (8) + +/* The timeout to use when waiting for an INIT packet when starting up + the protocol. Protocol parameter ``init-timeout''. */ +#define CEXCHANGE_INIT_TIMEOUT (10) + +/* The number of times to retry sending and waiting for a single INIT + packet when starting the protocol. This controls a single INIT + packet, while CSTARTUP_RETRIES controls how many times to try the + entire INIT sequence. Protocol parameter ``init-retries''. */ +#define CEXCHANGE_INIT_RETRIES (4) + +/* The timeout to use when waiting for a packet. Protocol parameter + ``timeout''. */ +#define CTIMEOUT (10) + +/* The number of times to retry waiting for a packet. Each time the + timeout fails we send a copy of our last data packet or a reject + message for the packet we expect from the other side, depending on + whether we are waiting for an acknowledgement or a data packet. + This is the number of times we try doing that and then waiting + again. Protocol parameter ``retries''. */ +#define CRETRIES (6) + +/* If we see more than this much unrecognized data, we drop the + connection. This must be larger than a single packet size, which + means it must be larger than 4096 (the largest possible packet + size). Protocol parameter ``garbage''. */ +#define CGARBAGE (10000) + +/* If we see more than this many protocol errors, we drop the + connection. Protocol parameter ``errors''. */ +#define CERRORS (100) + +/* Default decay rate. Each time we send or receive this many packets + succesfully, we decrement the error level by one (protocol + parameter ``error-decay''). */ +#define CERROR_DECAY (10) + +/* If this value is non-zero, it will be used as the remote window + size regardless of what the other side requested. This can be + useful for dealing with some particularly flawed packages. This + default value should always be 0, and protocol parameter + ``remote-window'' should be used for the affected systems. */ +#define IREMOTE_WINDOW (0) + +/* If this value is non-zero, it will be used as the packet size to + send to the remote system regardless of what it requested. It's + difficult to imagine any circumstances where you would want to set + this. Protocol parameter ``remote-packet-size''. */ +#define IREMOTE_PACKSIZE (0) + +/* Local variables. */ + +/* Next sequence number to send. */ +static int iGsendseq; + +/* Last sequence number that has been acked. */ +static int iGremote_ack; + +/* Last sequence number to be retransmitted. */ +static int iGretransmit_seq; + +/* Last sequence number we have received. */ +static int iGrecseq; + +/* Last sequence number we have acked. */ +static int iGlocal_ack; + +/* Window size to request (protocol parameter ``window''). */ +static int iGrequest_winsize = IWINDOW; + +/* Packet size to request (protocol parameter ``packet-size''). */ +static int iGrequest_packsize = IPACKSIZE; + +/* Remote window size (set during handshake). */ +static int iGremote_winsize; + +/* Forced remote window size (protocol parameter ``remote-window''). */ +static int iGforced_remote_winsize = IREMOTE_WINDOW; + +/* Remote segment size (set during handshake). This is one less than + the value in a packet header. */ +static int iGremote_segsize; + +/* Remote packet size (set based on iGremote_segsize). */ +static size_t iGremote_packsize; + +/* Forced remote packet size (protocol parameter + ``remote-packet-size''). */ +static int iGforced_remote_packsize = IREMOTE_PACKSIZE; + +/* Recieved control byte. */ +static int iGpacket_control; + +/* Number of times to retry the initial handshake. Protocol parameter + ``startup-retries''. */ +static int cGstartup_retries = CSTARTUP_RETRIES; + +/* Number of times to retry sending an initial control packet. + Protocol parameter ``init-retries''. */ +static int cGexchange_init_retries = CEXCHANGE_INIT_RETRIES; + +/* Timeout (seconds) for receiving an initial control packet. + Protocol parameter ``init-timeout''. */ +static int cGexchange_init_timeout = CEXCHANGE_INIT_TIMEOUT; + +/* Timeout (seconds) for receiving a data packet. Protocol parameter + ``timeout''. */ +static int cGtimeout = CTIMEOUT; + +/* Maximum number of timeouts when receiving a data packet or + acknowledgement. Protocol parameter ``retries''. */ +static int cGretries = CRETRIES; + +/* Amount of garbage data we are prepared to see before giving up. + Protocol parameter ``garbage''. */ +static int cGgarbage_data = CGARBAGE; + +/* Maximum number of errors we are prepared to see before giving up. + Protocol parameter ``errors''. */ +static int cGmax_errors = CERRORS; + +/* Each time we receive this many packets succesfully, we decrement + the error level by one (protocol parameter ``error-decay''). */ +static int cGerror_decay = CERROR_DECAY; + +/* Whether to use shorter packets when possible. Protocol parameter + ``short-packets''. */ +static boolean fGshort_packets = TRUE; + +/* Protocol parameter commands. */ +struct uuconf_cmdtab asGproto_params[] = +{ + { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iGrequest_winsize, NULL }, + { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iGrequest_packsize, + NULL }, + { "startup-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGstartup_retries, + NULL }, + { "init-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cGexchange_init_timeout, + NULL }, + { "init-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGexchange_init_retries, + NULL }, + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cGtimeout, NULL }, + { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGretries, NULL }, + { "garbage", UUCONF_CMDTABTYPE_INT, (pointer) &cGgarbage_data, NULL }, + { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cGmax_errors, NULL }, + { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cGerror_decay, NULL }, + { "remote-window", UUCONF_CMDTABTYPE_INT, + (pointer) &iGforced_remote_winsize, NULL }, + { "remote-packet-size", UUCONF_CMDTABTYPE_INT, + (pointer) &iGforced_remote_packsize, NULL }, + { "short-packets", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fGshort_packets, + NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Statistics. */ + +/* Number of packets we have sent. */ +static long cGsent_packets; + +/* Number of packets we have resent (these are not included in + cGsent_packets). */ +static long cGresent_packets; + +/* Number of packets we have delayed sending (these should not be + counted in cGresent_packets). */ +static long cGdelayed_packets; + +/* Number of packets we have received. */ +static long cGrec_packets; + +/* Number of packets rejected because the header was bad. */ +static long cGbad_hdr; + +/* Number of packets rejected because the checksum was bad. */ +static long cGbad_checksum; + +/* Number of packets received out of order. */ +static long cGbad_order; + +/* Number of packets rejected by receiver (number of RJ packets + received). */ +static long cGremote_rejects; + +/* The error level. This is the total number of errors as adjusted by + cGerror_decay. */ +static long cGerror_level; + +/* Each time we send an RJ, we can expect several out of order of + packets, because the other side will probably have sent a full + window by the time it sees the RJ. This variable keeps track of + the number of out of order packets we expect to see. We don't + count expected out of order packets against the error level. This + is reset to 0 when an in order packet is received. */ +static int cGexpect_bad_order; + +#if DEBUG > 1 +/* Control packet names used for debugging. */ +static const char * const azGcontrol[] = +{"?0?", "CLOSE", "RJ", "SRJ", "RR", "INITC", "INITB", "INITA"}; +#endif + +/* Local functions. */ +static boolean fgexchange_init P((struct sdaemon *qdaemon, int ictl, + int ival, int *piset)); +static boolean fgsend_control P((struct sdaemon *qdaemon, int ictl, + int ival)); +static char *zgadjust_ack P((int iseq)); +static boolean fgwait_for_packet P((struct sdaemon *qdaemon, + boolean freturncontrol, int ctimeout, + int cretries)); +static boolean fgsend_acks P((struct sdaemon *qdaemon)); +static boolean fggot_ack P((struct sdaemon *qdaemon, int iack)); +static boolean fgprocess_data P((struct sdaemon *qdaemon, boolean fdoacks, + boolean freturncontrol, + boolean *pfexit, size_t *pcneed, + boolean *pffound)); +static boolean fginit_sendbuffers P((boolean fallocate)); +static boolean fgcheck_errors P((struct sdaemon *qdaemon)); +static int igchecksum P((const char *zdata, size_t clen)); +static int igchecksum2 P((const char *zfirst, size_t cfirst, + const char *zsecond, size_t csecond)); + +/* Start the protocol. This requires a three way handshake. Both sides + must send and receive an INITA packet, an INITB packet, and an INITC + packet. The INITA and INITC packets contain the window size, and the + INITB packet contains the packet size. */ + +boolean +fgstart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + int iseg; + int i; + boolean fgota, fgotb; + + *pzlog = NULL; + + /* The 'g' protocol requires a full eight bit interface. */ + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + + iGsendseq = 1; + iGremote_ack = 0; + iGretransmit_seq = -1; + iGrecseq = 0; + iGlocal_ack = 0; + cGsent_packets = 0; + cGresent_packets = 0; + cGdelayed_packets = 0; + cGrec_packets = 0; + cGbad_hdr = 0; + cGbad_checksum = 0; + cGbad_order = 0; + cGremote_rejects = 0; + cGerror_level = 0; + cGexpect_bad_order = 0; + + /* We must determine the segment size based on the packet size + which may have been modified by a protocol parameter command. + A segment size of 2^n is passed as n - 5. */ + i = iGrequest_packsize; + iseg = -1; + while (i > 0) + { + ++iseg; + i >>= 1; + } + iseg -= 5; + if (iseg < 0 || iseg > 7) + { + ulog (LOG_ERROR, "Illegal packet size %d for '%c' protocol", + iGrequest_packsize, qdaemon->qproto->bname); + iseg = 1; + } + + fgota = FALSE; + fgotb = FALSE; + for (i = 0; i < cGstartup_retries; i++) + { + if (fgota) + { + if (! fgsend_control (qdaemon, INITA, iGrequest_winsize)) + return FALSE; + } + else + { + if (! fgexchange_init (qdaemon, INITA, iGrequest_winsize, + &iGremote_winsize)) + continue; + } + fgota = TRUE; + + if (fgotb) + { + if (! fgsend_control (qdaemon, INITB, iseg)) + return FALSE; + } + else + { + if (! fgexchange_init (qdaemon, INITB, iseg, &iGremote_segsize)) + continue; + } + fgotb = TRUE; + + if (! fgexchange_init (qdaemon, INITC, iGrequest_winsize, + &iGremote_winsize)) + continue; + + /* We have succesfully connected. Determine the remote packet + size. */ + iGremote_packsize = 1 << (iGremote_segsize + 5); + + /* If the user requested us to force specific remote window and + packet sizes, do so now. */ + if (iGforced_remote_winsize > 0 + && iGforced_remote_winsize <= CMAXWINDOW) + iGremote_winsize = iGforced_remote_winsize; + + if (iGforced_remote_packsize >= 32 + && iGforced_remote_packsize <= 4096) + { + /* Force the value to a power of two. */ + i = iGforced_remote_packsize; + iseg = -1; + while (i > 0) + { + ++iseg; + i >>= 1; + } + iGremote_packsize = 1 << iseg; + iGremote_segsize = iseg - 5; + } + + /* Set up packet buffers to use. We don't do this until we know + the maximum packet size we are going to send. */ + if (! fginit_sendbuffers (TRUE)) + return FALSE; + + *pzlog = zbufalc (sizeof "protocol '' packet size window " + 50); + sprintf (*pzlog, "protocol '%c' packet size %d window %d", + qdaemon->qproto->bname, (int) iGremote_packsize, + (int) iGremote_winsize); + + return TRUE; + } + + DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgstart: Protocol startup failed"); + + return FALSE; +} + +/* The 'G' protocol is identical to the 'g' protocol, except that + short packets are never supported. */ + +boolean +fbiggstart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + fGshort_packets = FALSE; + return fgstart (qdaemon, pzlog); +} + +/* Exchange initialization messages with the other system. + + A problem: + + We send INITA; it gets received + We receive INITA + We send INITB; it gets garbled + We receive INITB + + We have seen and sent INITB, so we start to send INITC. The other + side as sent INITB but not seen it, so it times out and resends + INITB. We will continue sending INITC and the other side will + continue sending INITB until both sides give up and start again + with INITA. + + It might seem as though if we are sending INITC and receive INITB, + we should resend our INITB, but this could cause infinite echoing + of INITB on a long-latency line. Rather than risk that, I have + implemented a fast drop-back procedure. If we are sending INITB and + receive INITC, the other side has gotten ahead of us. We immediately + fail and begin again with INITA. For the other side, if we are + sending INITC and see INITA, we also immediately fail back to INITA. + + Unfortunately, this doesn't work for the other case, in which we + are sending INITB but the other side has not yet seen INITA. As + far as I can see, if this happens we just have to wait until we + time out and resend INITA. */ + +static boolean +fgexchange_init (qdaemon, ictl, ival, piset) + struct sdaemon *qdaemon; + int ictl; + int ival; + int *piset; +{ + int i; + + /* The three-way handshake should be independent of who initializes + it, but it seems that some versions of uucico assume that the + caller sends first and the callee responds. This only matters if + we are the callee and the first packet is garbled. If we send a + packet, the other side will assume that we must have seen the + packet they sent and will never time out and send it again. + Therefore, if we are the callee we don't send a packet the first + time through the loop. This can still fail, but should usually + work, and, after all, if the initialization packets are received + correctly there will be no problem no matter what we do. */ + for (i = 0; i < cGexchange_init_retries; i++) + { + long itime; + int ctimeout; + + if (qdaemon->fcaller || i > 0) + { + if (! fgsend_control (qdaemon, ictl, ival)) + return FALSE; + } + + itime = ixsysdep_time ((long *) NULL); + ctimeout = cGexchange_init_timeout; + + do + { + long inewtime; + + /* We pass 0 as the retry count to fgwait_for_packet because + we want to handle retries here and because if it retried + it would send a packet, which would be bad. */ + if (! fgwait_for_packet (qdaemon, TRUE, ctimeout, 0)) + break; + + if (CONTROL_TT (iGpacket_control) == CONTROL) + { + if (CONTROL_XXX (iGpacket_control) == ictl) + { + *piset = CONTROL_YYY (iGpacket_control); + + /* If we didn't already send our initialization + packet, send it now. */ + if (! qdaemon->fcaller && i == 0) + { + if (! fgsend_control (qdaemon, ictl, ival)) + return FALSE; + } + + return TRUE; + } + + /* If the other side is farther along than we are, + we have lost a packet. Fail immediately back to + INITA (but don't fail if we are already doing INITA, + since that would count against cStart_retries more + than it should). */ + if (CONTROL_XXX (iGpacket_control) < ictl && ictl != INITA) + return FALSE; + + /* If we are sending INITC and we receive an INITA, the other + side has failed back (we know this because we have + seen an INITB from them). Fail back ourselves to + start the whole handshake over again. */ + if (CONTROL_XXX (iGpacket_control) == INITA && ictl == INITC) + return FALSE; + + /* As a special hack, if we are sending INITC and we + receive INITB, we update the segment size from the + packet. This permits a second INITB to override the + first one. It would be nice to do this in a cleaner + way. */ + if (CONTROL_XXX (iGpacket_control) == INITB && ictl == INITC) + iGremote_segsize = CONTROL_YYY (iGpacket_control); + } + + inewtime = ixsysdep_time ((long *) NULL); + ctimeout -= inewtime - itime; + } + while (ctimeout > 0); + } + + return FALSE; +} + +/* Shut down the protocol. */ + +boolean +fgshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + (void) fgsend_control (qdaemon, CLOSE, 0); + (void) fgsend_control (qdaemon, CLOSE, 0); + (void) fginit_sendbuffers (FALSE); + + /* The count of sent packets may not be accurate, because some of + them may have not been sent yet if the connection failed in the + middle (the ones that counted for cGdelayed_packets). I don't + think it's worth being precise. */ + ulog (LOG_NORMAL, + "Protocol '%c' packets: sent %ld, resent %ld, received %ld", + qdaemon->qproto->bname, cGsent_packets, + cGresent_packets - cGdelayed_packets, cGrec_packets); + if (cGbad_hdr != 0 + || cGbad_checksum != 0 + || cGbad_order != 0 + || cGremote_rejects != 0) + ulog (LOG_NORMAL, + "Errors: header %ld, checksum %ld, order %ld, remote rejects %ld", + cGbad_hdr, cGbad_checksum, cGbad_order, cGremote_rejects); + + /* Reset all the parameters to their default values, so that the + protocol parameters used for this connection do not affect the + next one. */ + iGrequest_winsize = IWINDOW; + iGrequest_packsize = IPACKSIZE; + cGstartup_retries = CSTARTUP_RETRIES; + cGexchange_init_timeout = CEXCHANGE_INIT_TIMEOUT; + cGexchange_init_retries = CEXCHANGE_INIT_RETRIES; + cGtimeout = CTIMEOUT; + cGretries = CRETRIES; + cGgarbage_data = CGARBAGE; + cGmax_errors = CERRORS; + cGerror_decay = CERROR_DECAY; + iGforced_remote_winsize = IREMOTE_WINDOW; + iGforced_remote_packsize = IREMOTE_PACKSIZE; + fGshort_packets = TRUE; + + return TRUE; +} + +/* Send a command string. We send packets containing the string until + the entire string has been sent. Each packet is full. */ + +/*ARGSUSED*/ +boolean +fgsendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen; + boolean fagain; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fgsendcmd: Sending command \"%s\"", z); + + clen = strlen (z); + + do + { + char *zpacket; + size_t cdummy; + + zpacket = zggetspace (qdaemon, &cdummy); + + if (clen < iGremote_packsize) + { + size_t csize; + + /* If the remote packet size is larger than 64 (the default, + which may indicate an older UUCP package), try to fit + this command into a smaller packet. We still always send + a complete packet, though. */ + if (iGremote_packsize <= 64 || ! fGshort_packets) + csize = iGremote_packsize; + else + { + csize = 32; + while (csize <= clen) + csize <<= 1; + } + + memcpy (zpacket, z, clen); + bzero (zpacket + clen, csize - clen); + fagain = FALSE; + + if (! fgsenddata (qdaemon, zpacket, csize, 0, 0, (long) 0)) + return FALSE; + } + else + { + memcpy (zpacket, z, iGremote_packsize); + z += iGremote_packsize; + clen -= iGremote_packsize; + fagain = TRUE; + + if (! fgsenddata (qdaemon, zpacket, iGremote_packsize, + 0, 0, (long) 0)) + return FALSE; + } + } + while (fagain); + + return TRUE; +} + +/* We keep an array of buffers to retransmit as necessary. Rather + than waste static space on large buffer sizes, we allocate the + buffers once we know how large the other system expects them to be. + The sequence numbers used in the 'g' protocol are only three bits + long, so we allocate eight buffers and maintain a correspondence + between buffer index and sequence number. This always wastes some + buffer space, but it's easy to implement. + + We leave room at the front of the buffer for the frame header and + two additional bytes. The two extra bytes are used for short + packets, which essentially use a longer header and shorter data. + We do this to avoid moving the data. We zero out any unused bytes + before the frame, so we can locate the real header given a buffer + by finding the first non-zero byte (which will be one of the first + three bytes in the buffer). */ + +#define CSENDBUFFERS (CMAXWINDOW + 1) + +static char *azGsendbuffers[CSENDBUFFERS]; + +static boolean +fginit_sendbuffers (fallocate) + boolean fallocate; +{ + int i; + + /* Free up any remaining old buffers. */ + for (i = 0; i < CSENDBUFFERS; i++) + { + xfree ((pointer) azGsendbuffers[i]); + if (fallocate) + { + azGsendbuffers[i] = (char *) malloc (CFRAMELEN + 2 + + iGremote_packsize); + if (azGsendbuffers[i] == NULL) + return FALSE; + + /* This bzero might not seem necessary, since before we send + out each packet we zero out any non-data bytes. However, + if we receive an SRJ at the start of the conversation, we + will send out the packet before it has been set to + anything, thus sending the contents of our heap. We + avoid this by using bzero. */ + bzero (azGsendbuffers[i], CFRAMELEN + 2 + iGremote_packsize); + } + else + azGsendbuffers[i] = NULL; + } + return TRUE; +} + +/* Allocate a packet to send out. The return value of this function + must be filled in and passed to fgsenddata, or discarded. This + will ensure that the buffers and iGsendseq stay in synch. Set + *pclen to the amount of data to place in the buffer. */ + +/*ARGSUSED*/ +char * +zggetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = iGremote_packsize; + return azGsendbuffers[iGsendseq] + CFRAMELEN + 2; +} + +/* Send out a data packet. This computes the checksum, sets up the + header, and sends the packet out. The argument zdata should point + to the return value of zggetspace. */ + +/*ARGSIGNORED*/ +boolean +fgsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ + char *z; + int itt, iseg; + size_t csize; + int iclr1, iclr2; + unsigned short icheck; + + /* Set the initial length bytes. See the description at the definition + of SHORTDATA, above. */ + itt = DATA; + csize = iGremote_packsize; + iseg = iGremote_segsize + 1; + +#if DEBUG > 0 + if (cdata > csize) + ulog (LOG_FATAL, "fgsend_packet: Packet size too large"); +#endif + + iclr1 = -1; + iclr2 = -2; + if (cdata < csize) + { + /* If the remote packet size is larger than 64, the default, we + can assume they can handle a smaller packet as well, which + will be more efficient to send. */ + if (iGremote_packsize > 64 && fGshort_packets) + { + /* The packet size is 1 << (iseg + 4). */ + iseg = 1; + csize = 32; + while (csize < cdata) + { + csize <<= 1; + ++iseg; + } + } + + if (csize != cdata) + { + size_t cshort; + + /* We have to add bytes which indicate how short the packet + is. We do this by pushing the header backward, which we + can do because we allocated two extra bytes for this + purpose. */ + iclr2 = 0; + itt = SHORTDATA; + cshort = csize - cdata; + if (cshort <= 127) + { + --zdata; + zdata[0] = (char) cshort; + zdata[-1] = '\0'; + bzero (zdata + cdata + 1, cshort - 1); + } + else + { + zdata -= 2; + zdata[0] = (char) (0x80 | (cshort & 0x7f)); + zdata[1] = (char) (cshort >> 7); + bzero (zdata + cdata + 2, cshort - 2); + iclr1 = 0; + } + } + } + + z = zdata - CFRAMELEN; + + /* Zero out the preceding bytes, in case the last time this buffer + was used those bytes were used. We need to zero out the initial + bytes so that we can find the true start of the packet in + zgadjust_ack. */ + z[iclr1] = '\0'; + z[iclr2] = '\0'; + + z[IFRAME_DLE] = DLE; + z[IFRAME_K] = (char) iseg; + + icheck = (unsigned short) igchecksum (zdata, csize); + + /* We're just about ready to go. Wait until there is room in the + receiver's window for us to send the packet. We do this now so + that we send the correct value for the last packet received. + Note that if iGsendseq == iGremote_ack, this means that the + sequence numbers are actually 8 apart, since the packet could not + have been acknowledged before it was sent; this can happen when + the window size is 7. */ + while (iGsendseq == iGremote_ack + || CSEQDIFF (iGsendseq, iGremote_ack) > iGremote_winsize) + { + if (! fgwait_for_packet (qdaemon, TRUE, cGtimeout, cGretries)) + return FALSE; + } + + /* Ack all packets up to the next one, since the UUCP protocol + requires that all packets be acked in order. */ + while (CSEQDIFF (iGrecseq, iGlocal_ack) > 1) + { + iGlocal_ack = INEXTSEQ (iGlocal_ack); + if (! fgsend_control (qdaemon, RR, iGlocal_ack)) + return FALSE; + } + iGlocal_ack = iGrecseq; + + z[IFRAME_CONTROL] = (char) ((itt << 6) | (iGsendseq << 3) | iGrecseq); + + iGsendseq = INEXTSEQ (iGsendseq); + + icheck = ((unsigned short) + ((0xaaaa - (icheck ^ (z[IFRAME_CONTROL] & 0xff))) & 0xffff)); + z[IFRAME_CHECKLOW] = (char) (icheck & 0xff); + z[IFRAME_CHECKHIGH] = (char) (icheck >> 8); + + z[IFRAME_XOR] = (char) (z[IFRAME_K] ^ z[IFRAME_CHECKLOW] + ^ z[IFRAME_CHECKHIGH] ^ z[IFRAME_CONTROL]); + + /* If we're waiting for acks of retransmitted packets, then don't + send this packet yet. The other side may not be ready for it + yet. Instead, code in fggot_ack will send the outstanding + packets when an ack is received. */ + ++cGsent_packets; + + if (iGretransmit_seq != -1) + { + ++cGdelayed_packets; + return TRUE; + } + + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fgsenddata: Sending packet %d (%d bytes)", + CONTROL_XXX (z[IFRAME_CONTROL]), cdata); + + return fsend_data (qdaemon->qconn, z, CFRAMELEN + csize, TRUE); +} + +/* Recompute the control byte and checksum of a packet so that it + includes the correct packet acknowledgement. This is called when a + packet is retransmitted to make sure the retransmission does not + confuse the other side. It returns a pointer to the start of the + packet, skipping the bytes that may be unused at the start of + azGsendbuffers[iseq]. */ + +static char * +zgadjust_ack (iseq) + int iseq; +{ + register char *z; + unsigned short icheck; + + z = azGsendbuffers[iseq]; + if (*z == '\0') + ++z; + if (*z == '\0') + ++z; + + /* If the received packet number is the same, there is nothing + to do. */ + if (CONTROL_YYY (z[IFRAME_CONTROL]) == iGrecseq) + return z; + + /* Get the old checksum. */ + icheck = (unsigned short) (((z[IFRAME_CHECKHIGH] & 0xff) << 8) + | (z[IFRAME_CHECKLOW] & 0xff)); + icheck = ((unsigned short) + (((0xaaaa - icheck) ^ (z[IFRAME_CONTROL] & 0xff)) & 0xffff)); + + /* Update the control byte. */ + z[IFRAME_CONTROL] = (char) ((z[IFRAME_CONTROL] &~ 07) | iGrecseq); + + /* Create the new checksum. */ + icheck = ((unsigned short) + ((0xaaaa - (icheck ^ (z[IFRAME_CONTROL] & 0xff))) & 0xffff)); + z[IFRAME_CHECKLOW] = (char) (icheck & 0xff); + z[IFRAME_CHECKHIGH] = (char) (icheck >> 8); + + /* Update the XOR byte. */ + z[IFRAME_XOR] = (char) (z[IFRAME_K] ^ z[IFRAME_CHECKLOW] + ^ z[IFRAME_CHECKHIGH] ^ z[IFRAME_CONTROL]); + + return z; +} + +/* Send a control packet. These are fairly simple to construct. It + seems reasonable to me that we should be able to send a control + packet at any time, even if the receive window is closed. In + particular, we don't want to delay when sending a CLOSE control + message. If I'm wrong, it can be changed easily enough. */ + +static boolean +fgsend_control (qdaemon, ixxx, iyyy) + struct sdaemon *qdaemon; + int ixxx; + int iyyy; +{ + char ab[CFRAMELEN]; + int ictl; + unsigned short icheck; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_PROTO) || + (FDEBUGGING (DEBUG_ABNORMAL) && ixxx != RR)) + ulog (LOG_DEBUG, "fgsend_control: Sending control %s %d", + azGcontrol[ixxx], iyyy); +#endif + + ab[IFRAME_DLE] = DLE; + ab[IFRAME_K] = KCONTROL; + + ictl = (CONTROL << 6) | (ixxx << 3) | iyyy; + icheck = (unsigned short) (0xaaaa - ictl); + ab[IFRAME_CHECKLOW] = (char) (icheck & 0xff); + ab[IFRAME_CHECKHIGH] = (char) (icheck >> 8); + + ab[IFRAME_CONTROL] = (char) ictl; + + ab[IFRAME_XOR] = (char) (ab[IFRAME_K] ^ ab[IFRAME_CHECKLOW] + ^ ab[IFRAME_CHECKHIGH] ^ ab[IFRAME_CONTROL]); + + return fsend_data (qdaemon->qconn, ab, (size_t) CFRAMELEN, TRUE); +} + +/* Wait for data to come in. This continues processing until a + complete file or command has been received. */ + +boolean +fgwait (qdaemon) + struct sdaemon *qdaemon; +{ + return fgwait_for_packet (qdaemon, FALSE, cGtimeout, cGretries); +} + +/* Get a packet. This is called when we have nothing to send, but + want to wait for a packet to come in. If freturncontrol is TRUE, + this will return after getting any control packet. Otherwise, it + will continue to receive packets until a complete file or a + complete command has been received. The timeout and the number of + retries are specified as arguments. The function returns FALSE if + an error occurs or if cretries timeouts of ctimeout seconds were + exceeded. */ + +static boolean +fgwait_for_packet (qdaemon, freturncontrol, ctimeout, cretries) + struct sdaemon *qdaemon; + boolean freturncontrol; + int ctimeout; + int cretries; +{ + int ctimeouts; + int cgarbage; + int cshort; + + ctimeouts = 0; + cgarbage = 0; + cshort = 0; + + while (TRUE) + { + boolean fexit; + size_t cneed; + boolean ffound; + size_t crec; + + if (! fgprocess_data (qdaemon, TRUE, freturncontrol, &fexit, + &cneed, &ffound)) + return FALSE; + + if (fexit) + return TRUE; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fgwait_for_packet: Need %lu bytes", + (unsigned long) cneed); + + if (ffound) + { + ctimeouts = 0; + cgarbage = 0; + } + else + { + if (cgarbage > cGgarbage_data) + { + ulog (LOG_ERROR, "Too much unrecognized data"); + return FALSE; + } + } + + if (! freceive_data (qdaemon->qconn, cneed, &crec, ctimeout, TRUE)) + return FALSE; + + cgarbage += crec; + + if (crec != 0) + { + /* If we don't get enough data twice in a row, we may have + dropped some data and still be looking for the end of a + large packet. Incrementing iPrecstart will force + fgprocess_data to skip that packet and look through the + rest of the data. In some situations, this will be a + mistake. */ + if (crec >= cneed) + cshort = 0; + else + { + ++cshort; + if (cshort > 1) + { + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + cshort = 0; + } + } + } + else + { + /* The read timed out. If we have an unacknowledged packet, + send it again. Otherwise, send an RJ with the last + packet we received correctly. */ + ++ctimeouts; + if (ctimeouts > cretries) + { + if (cretries > 0) + ulog (LOG_ERROR, "Timed out waiting for packet"); + return FALSE; + } + + if (INEXTSEQ (iGremote_ack) != iGsendseq) + { + int inext; + char *zsend; + + inext = INEXTSEQ (iGremote_ack); + + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgwait_for_packet: Resending packet %d", + inext); + + ++cGresent_packets; + zsend = zgadjust_ack (inext); + if (! fsend_data (qdaemon->qconn, zsend, + CFRAMELEN + CPACKLEN (zsend), TRUE)) + return FALSE; + iGretransmit_seq = inext; + } + else + { + /* Send all pending acks first, to avoid confusing + the other side. */ + if (iGlocal_ack != iGrecseq) + { + if (! fgsend_acks (qdaemon)) + return FALSE; + } + if (! fgsend_control (qdaemon, RJ, iGrecseq)) + return FALSE; + } + } + } +} + +/* Send acks for all packets we haven't acked yet. */ + +static boolean +fgsend_acks (qdaemon) + struct sdaemon *qdaemon; +{ + while (iGlocal_ack != iGrecseq) + { + iGlocal_ack = INEXTSEQ (iGlocal_ack); + if (! fgsend_control (qdaemon, RR, iGlocal_ack)) + return FALSE; + } + return TRUE; +} + +/* Handle an ack of a packet. According to Hanrahan's paper, this + acknowledges all previous packets. If this is an ack for a + retransmitted packet, continue by resending up to two more packets + following the retransmitted one. This should recover quickly from + a line glitch, while avoiding the problem of continual + retransmission. */ + +static boolean +fggot_ack (qdaemon, iack) + struct sdaemon *qdaemon; + int iack; +{ + int inext; + char *zsend; + + /* We only decrement the error level if we are not retransmitting + packets. We want to catch a sudden downgrade in line quality as + fast as possible. */ + if (cGerror_level > 0 + && iGretransmit_seq == -1 + && cGsent_packets % cGerror_decay == 0) + --cGerror_level; + cGexpect_bad_order = 0; + + /* Each time packet 0 is acknowledged, we call uwindow_acked since a + new window has been acked. */ + if (iack < iGremote_ack) + uwindow_acked (qdaemon, FALSE); + + iGremote_ack = iack; + + if (iGretransmit_seq == -1) + return TRUE; + + inext = INEXTSEQ (iGretransmit_seq); + if (inext == iGsendseq) + iGretransmit_seq = -1; + else + { + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fggot_ack: Sending packet %d", inext); + + ++cGresent_packets; + zsend = zgadjust_ack (inext); + if (! fsend_data (qdaemon->qconn, zsend, CFRAMELEN + CPACKLEN (zsend), + TRUE)) + return FALSE; + inext = INEXTSEQ (inext); + if (inext == iGsendseq) + iGretransmit_seq = -1; + else + { + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fggot_ack: Sending packet %d", inext); + + ++cGresent_packets; + zsend = zgadjust_ack (inext); + if (! fsend_data (qdaemon->qconn, zsend, + CFRAMELEN + CPACKLEN (zsend), TRUE)) + return FALSE; + iGretransmit_seq = inext; + } + } + + return TRUE; +} + +/* See if we've received more than the permitted number of errors. If + we receive a bad packet, we can expect a window full (less one) of + out of order packets to follow, so we discount cGbad_order + accordingly. */ + +static boolean +fgcheck_errors (qdaemon) + struct sdaemon *qdaemon; +{ + if (cGerror_level > cGmax_errors && cGmax_errors >= 0) + { + ulog (LOG_ERROR, "Too many '%c' protocol errors", + qdaemon->qproto->bname); + return FALSE; + } + + return TRUE; +} + +/* Process the receive buffer into a data packet, if possible. All + control packets are handled here. When a data packet is received, + fgprocess_data calls fgot_data with the data; if that sets its + pfexit argument to TRUE fgprocess_data will set *pfexit to TRUE and + return TRUE. Also, if the freturncontrol argument is TRUE + fgprocess_data will set *pfexit to TRUE and return TRUE. Otherwise + fgprocess_data will continue trying to process data. If some error + occurs, fgprocess_data will return FALSE. If there is not enough + data to form a complete packet, then *pfexit will be set to FALSE, + *pcneed will be set to the number of bytes needed to form a + complete packet (unless pcneed is NULL) and fgprocess_data will + return TRUE. If this function found a data packet, and pffound is + not NULL, it will set *pffound to TRUE; this can be used to tell + valid data from an endless stream of garbage and control packets. + If fdoacks is TRUE, received packets will be acknowledged; + otherwise they must be acknowledged later. */ + +static boolean +fgprocess_data (qdaemon, fdoacks, freturncontrol, pfexit, pcneed, pffound) + struct sdaemon *qdaemon; + boolean fdoacks; + boolean freturncontrol; + boolean *pfexit; + size_t *pcneed; + boolean *pffound; +{ + *pfexit = FALSE; + if (pffound != NULL) + *pffound = FALSE; + + while (iPrecstart != iPrecend) + { + char ab[CFRAMELEN]; + int i, iget, cwant; + unsigned short ihdrcheck, idatcheck; + const char *zfirst, *zsecond; + int cfirst, csecond; + boolean fduprr; + + /* Look for the DLE which must start a packet. */ + if (abPrecbuf[iPrecstart] != DLE) + { + char *zdle; + + cfirst = iPrecend - iPrecstart; + if (cfirst < 0) + cfirst = CRECBUFLEN - iPrecstart; + + zdle = memchr (abPrecbuf + iPrecstart, DLE, (size_t) cfirst); + + if (zdle == NULL) + { + iPrecstart = (iPrecstart + cfirst) % CRECBUFLEN; + continue; + } + + /* We don't need % CRECBUFLEN here because zdle - (abPrecbuf + + iPrecstart) < cfirst <= CRECBUFLEN - iPrecstart. */ + iPrecstart += zdle - (abPrecbuf + iPrecstart); + } + + /* Get the first six bytes into ab. */ + for (i = 0, iget = iPrecstart; + i < CFRAMELEN && iget != iPrecend; + i++, iget = (iget + 1) % CRECBUFLEN) + ab[i] = abPrecbuf[iget]; + + /* If there aren't six bytes, there is no packet. */ + if (i < CFRAMELEN) + { + if (pcneed != NULL) + *pcneed = CFRAMELEN - i; + return TRUE; + } + + /* Make sure these six bytes start a packet. The check on + IFRAME_DLE is basically a debugging check, since the above + code should have ensured that it will never fail. If this is + not the start of a packet, bump iPrecstart and loop around to + look for another DLE. */ + if (ab[IFRAME_DLE] != DLE + || ab[IFRAME_K] < 1 + || ab[IFRAME_K] > 9 + || ab[IFRAME_XOR] != (ab[IFRAME_K] ^ ab[IFRAME_CHECKLOW] + ^ ab[IFRAME_CHECKHIGH] ^ ab[IFRAME_CONTROL]) + || CONTROL_TT (ab[IFRAME_CONTROL]) == ALTCHAN) + { + ++cGbad_hdr; + ++cGerror_level; + + DEBUG_MESSAGE4 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Bad header: K %d TT %d XOR byte %d calc %d", + ab[IFRAME_K] & 0xff, + CONTROL_TT (ab[IFRAME_CONTROL]), + ab[IFRAME_XOR] & 0xff, + (ab[IFRAME_K] + ^ ab[IFRAME_CHECKLOW] + ^ ab[IFRAME_CHECKHIGH] + ^ ab[IFRAME_CONTROL]) & 0xff); + + if (! fgcheck_errors (qdaemon)) + return FALSE; + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + + /* The zfirst and cfirst pair point to the first set of data for + this packet; the zsecond and csecond point to the second set, + in case the packet wraps around the end of the buffer. */ + zfirst = abPrecbuf + iPrecstart + CFRAMELEN; + cfirst = 0; + zsecond = NULL; + csecond = 0; + + if (ab[IFRAME_K] == KCONTROL) + { + /* This is a control packet. It should not have any data. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) + { + ++cGbad_hdr; + ++cGerror_level; + + DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Bad header: control packet with data"); + + if (! fgcheck_errors (qdaemon)) + return FALSE; + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + + idatcheck = (unsigned short) (0xaaaa - ab[IFRAME_CONTROL]); + cwant = 0; + } + else + { + int cinbuf; + unsigned short icheck; + + /* This is a data packet. It should not be type CONTROL. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL) + { + ++cGbad_hdr; + ++cGerror_level; + + DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Bad header: data packet is type CONTROL"); + + if (! fgcheck_errors (qdaemon)) + return FALSE; + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + cinbuf -= CFRAMELEN; + + /* Make sure we have enough data. If we don't, wait for + more. */ + + cwant = (int) CPACKLEN (ab); + if (cinbuf < cwant) + { + if (pcneed != NULL) + *pcneed = cwant - cinbuf; + return TRUE; + } + + /* Set up the data pointers and compute the checksum. */ + if (iPrecend >= iPrecstart) + cfirst = cwant; + else + { + cfirst = CRECBUFLEN - (iPrecstart + CFRAMELEN); + if (cfirst >= cwant) + cfirst = cwant; + else if (cfirst > 0) + { + zsecond = abPrecbuf; + csecond = cwant - cfirst; + } + else + { + /* Here cfirst is non-positive, so subtracting from + abPrecbuf will actually skip the appropriate number + of bytes at the start of abPrecbuf. */ + zfirst = abPrecbuf - cfirst; + cfirst = cwant; + } + } + + if (csecond == 0) + icheck = (unsigned short) igchecksum (zfirst, (size_t) cfirst); + else + icheck = (unsigned short) igchecksum2 (zfirst, (size_t) cfirst, + zsecond, + (size_t) csecond); + + idatcheck = ((unsigned short) + (((0xaaaa - (icheck ^ (ab[IFRAME_CONTROL] & 0xff))) + & 0xffff))); + } + + ihdrcheck = (unsigned short) (((ab[IFRAME_CHECKHIGH] & 0xff) << 8) + | (ab[IFRAME_CHECKLOW] & 0xff)); + + if (ihdrcheck != idatcheck) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Bad checksum: header 0x%x, data 0x%x", + ihdrcheck, idatcheck); + + ++cGbad_checksum; + ++cGerror_level; + + if (! fgcheck_errors (qdaemon)) + return FALSE; + + /* If the checksum failed for a data packet, then if it was + the one we were expecting send an RJ, otherwise ignore + it. Previously if this code got the wrong packet number + it would send an RR, but that may confuse some Telebit + modems and it doesn't help in any case since the receiver + will probably just ignore the RR as a duplicate (that's + basically what this code does). If we totally missed the + packet we will time out and send an RJ in the function + fgwait_for_packet above. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) + { + /* Make sure we've acked everything up to this point. */ + if (iGrecseq != iGlocal_ack) + { + if (! fgsend_acks (qdaemon)) + return FALSE; + } + + /* If this is the packet we wanted, tell the sender that + it failed. */ + if (CONTROL_XXX (ab[IFRAME_CONTROL]) == INEXTSEQ (iGrecseq)) + { + if (! fgsend_control (qdaemon, RJ, iGrecseq)) + return FALSE; + cGexpect_bad_order += iGrequest_winsize - 1; + } + } + + /* We can't skip the packet data after this, because if we + have lost incoming bytes the next DLE will be somewhere + in what we thought was the packet data. */ + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + + /* We have a packet; remove the processed bytes from the receive + buffer. */ + iPrecstart = (iPrecstart + cwant + CFRAMELEN) % CRECBUFLEN; + + /* Store the control byte for the handshake routines. */ + iGpacket_control = ab[IFRAME_CONTROL] & 0xff; + + /* Annoyingly, some UUCP packages appear to send an RR packet + rather than an RJ packet when they want a packet to be + resent. If we get a duplicate RR, we treat it as an RJ. */ + fduprr = FALSE; + if (CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL + && CONTROL_XXX (ab[IFRAME_CONTROL]) == RR + && iGremote_ack == CONTROL_YYY (ab[IFRAME_CONTROL]) + && INEXTSEQ (iGremote_ack) != iGsendseq) + { + DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Treating duplicate RR as RJ"); + fduprr = TRUE; + } + + /* Update the received sequence number from the yyy field of a + data packet or an RR control packet. If we've been delaying + sending packets until we received an ack, this may send out + some packets. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL + || CONTROL_XXX (ab[IFRAME_CONTROL]) == RR) + { + if (! fggot_ack (qdaemon, CONTROL_YYY (ab[IFRAME_CONTROL]))) + return FALSE; + } + + /* If this isn't a control message, make sure we have received + the expected packet sequence number, acknowledge the packet + if it's the right one, and process the data. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) + { + if (CONTROL_XXX (ab[IFRAME_CONTROL]) != INEXTSEQ (iGrecseq)) + { + /* We got the wrong packet number. */ + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Got packet %d; expected %d", + CONTROL_XXX (ab[IFRAME_CONTROL]), + INEXTSEQ (iGrecseq)); + + if (cGexpect_bad_order > 0) + --cGexpect_bad_order; + else + { + ++cGbad_order; + ++cGerror_level; + if (! fgcheck_errors (qdaemon)) + return FALSE; + } + + /* This code used to send an RR to encourage the other + side to get back in synch, but that may confuse some + Telebit modems and does little good in any case, + since the other side will probably just ignore it + anyhow (that's what this code does). */ + continue; + } + + /* We got the packet we expected. */ + ++cGrec_packets; + if (cGerror_level > 0 + && cGrec_packets % cGerror_decay == 0) + --cGerror_level; + cGexpect_bad_order = 0; + + iGrecseq = INEXTSEQ (iGrecseq); + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fgprocess_data: Got packet %d", iGrecseq); + + /* Tell the caller that we found something. */ + if (pffound != NULL) + *pffound = TRUE; + + /* If we are supposed to do acknowledgements here, send back + an RR packet. */ + if (fdoacks) + { + if (! fgsend_acks (qdaemon)) + return FALSE; + } + + /* If this is a short data packet, adjust the data pointers + and lengths. */ + if (CONTROL_TT (ab[IFRAME_CONTROL]) == SHORTDATA) + { + int cshort, cmove; + + if ((zfirst[0] & 0x80) == 0) + { + cshort = zfirst[0] & 0xff; + cmove = 1; + } + else + { + int cbyte2; + + if (cfirst > 1) + cbyte2 = zfirst[1] & 0xff; + else + cbyte2 = zsecond[0] & 0xff; + cshort = (zfirst[0] & 0x7f) + (cbyte2 << 7); + cmove = 2; + } + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fgprocess_data: Packet short by %d", + cshort); + + /* Adjust the start of the buffer for the bytes used + by the count. */ + if (cfirst > cmove) + { + zfirst += cmove; + cfirst -= cmove; + } + else + { + zfirst = zsecond + (cmove - cfirst); + cfirst = csecond - (cmove - cfirst); + csecond = 0; + } + + /* Adjust the length of the buffer for the bytes we are + not supposed to consider. */ + cshort -= cmove; + if (csecond >= cshort) + csecond -= cshort; + else + { + cfirst -= cshort - csecond; + csecond = 0; + } + +#if DEBUG > 0 + /* This should not happen, but just in case. */ + if (cfirst < 0) + cfirst = 0; +#endif + } + + if (! fgot_data (qdaemon, zfirst, (size_t) cfirst, + zsecond, (size_t) csecond, + -1, -1, (long) -1, + INEXTSEQ (iGremote_ack) == iGsendseq, + pfexit)) + return FALSE; + + /* If fgot_data told us that we were finished, get out. */ + if (*pfexit) + return TRUE; + + /* If we've been asked to return control packets, get out + now. */ + if (freturncontrol) + { + *pfexit = TRUE; + return TRUE; + } + + continue; + } + + /* Handle control messages here. */ +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_PROTO) + || (FDEBUGGING (DEBUG_ABNORMAL) + && CONTROL_XXX (ab[IFRAME_CONTROL]) != RR)) + ulog (LOG_DEBUG, "fgprocess_data: Got control %s %d", + azGcontrol[CONTROL_XXX (ab[IFRAME_CONTROL])], + CONTROL_YYY (ab[IFRAME_CONTROL])); +#endif + + switch (CONTROL_XXX (ab[IFRAME_CONTROL])) + { + case CLOSE: + /* The other side has closed the connection. */ + if (fLog_sighup) + { + ulog (LOG_ERROR, "Received unexpected CLOSE packet"); + (void) fgsend_control (qdaemon, CLOSE, 0); + } + return FALSE; + case RR: + /* Acknowledge receipt of a packet. This was already handled + above, unless we are treating it as RJ. */ + if (! fduprr) + break; + /* Fall through. */ + case RJ: + /* The other side dropped a packet. Begin retransmission with + the packet following the one acknowledged. We don't + retransmit the packets immediately, but instead wait + for the first one to be acked. This prevents us from + sending an entire window several times if we get several + RJ packets. */ + iGremote_ack = CONTROL_YYY (ab[IFRAME_CONTROL]); + iGretransmit_seq = INEXTSEQ (iGremote_ack); + if (iGretransmit_seq == iGsendseq) + iGretransmit_seq = -1; + else + { + char *zpack; + + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Remote reject: next %d resending %d", + iGsendseq, iGretransmit_seq); + + ++cGresent_packets; + ++cGremote_rejects; + ++cGerror_level; + if (! fgcheck_errors (qdaemon)) + return FALSE; + zpack = zgadjust_ack (iGretransmit_seq); + if (! fsend_data (qdaemon->qconn, zpack, + CFRAMELEN + CPACKLEN (zpack), + TRUE)) + return FALSE; + } + break; + case SRJ: + /* Selectively reject a particular packet. This is not used + by UUCP, but it's easy to support. */ + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fgprocess_data: Selective reject of %d", + CONTROL_YYY (ab[IFRAME_CONTROL])); + { + char *zpack; + + ++cGresent_packets; + ++cGremote_rejects; + ++cGerror_level; + zpack = zgadjust_ack (CONTROL_YYY (ab[IFRAME_CONTROL])); + if (! fsend_data (qdaemon->qconn, zpack, + CFRAMELEN + CPACKLEN (zpack), + TRUE)) + return FALSE; + } + break; + case INITC: + case INITB: + case INITA: + /* Ignore attempts to reinitialize. */ + break; + } + + /* If we've been asked to return control packets, get out. */ + if (freturncontrol) + { + *pfexit = TRUE; + return TRUE; + } + + /* Loop around to look for the next packet, if any. */ + } + + /* There is no data left in the receive buffer. */ + if (pcneed != NULL) + *pcneed = CFRAMELEN; + return TRUE; +} + +/* Compute the 'g' protocol checksum. This is unfortunately rather + awkward. This is the most time consuming code in the entire + program. It's also not a great checksum, since it can be fooled + by some single bit errors. */ + +/* Sorry about this knavery, but it speeds up the VAX code + significantly. It would be better to rewrite the whole routine in + assembler. */ +#ifdef __GNUC__ +#ifdef __vax__ +#define VAX_ASM 1 +#endif +#endif + +#if VAX_ASM +#define ROTATE(i) \ + asm ("cvtwl %1,%0\n\trotl $1,%0,%0" : "=g" (i) : "g" (i)) +#else +#define ROTATE(i) i += i + ((i & 0x8000) >> 15) +#endif + +#define ITERATION \ + /* Rotate ichk1 left. */ \ + ROTATE (ichk1); \ + \ + /* The guts of the checksum. */ \ + b = BUCHAR (*z++); \ + if (b != 0) \ + { \ + ichk1 &= 0xffff; \ + ichk1 += b; \ + ichk2 += ichk1 ^ c; \ + if ((ichk1 >> 16) != 0) \ + ichk1 ^= ichk2; \ + } \ + else \ + { \ + ichk2 += ichk1 ^ c; \ + ichk1 ^= ichk2; \ + } \ + \ + --c + +static int +igchecksum (z, c) + register const char *z; + register size_t c; +{ + register unsigned long ichk1, ichk2; + + ichk1 = 0xffff; + ichk2 = 0; + + do + { + register unsigned int b; + + ITERATION; + ITERATION; + ITERATION; + ITERATION; + } + while (c > 0); + + return ichk1 & 0xffff; +} + +/* We use a separate function compute the checksum if the block is + split around the end of the receive buffer since it occurs much + less frequently and the checksum is already high up in the + profiles. These functions are almost identical, and this one + actually only has a few more instructions in the inner loop. */ + +static int +igchecksum2 (zfirst, cfirst, zsecond, csecond) + const char *zfirst; + size_t cfirst; + const char *zsecond; + size_t csecond; +{ + register unsigned long ichk1, ichk2; + register const char *z; + register size_t c; + + z = zfirst; + c = cfirst + csecond; + + ichk1 = 0xffff; + ichk2 = 0; + + do + { + register unsigned int b; + + ITERATION; + + /* If the first buffer has been finished, switch to the second. */ + --cfirst; + if (cfirst == 0) + z = zsecond; + } + while (c > 0); + + return ichk1 & 0xffff; +} diff --git a/gnu/libexec/uucp/uucico/proti.c b/gnu/libexec/uucp/uucico/proti.c new file mode 100644 index 0000000000..606b2bd94f --- /dev/null +++ b/gnu/libexec/uucp/uucico/proti.c @@ -0,0 +1,1563 @@ +/* proti.c + The 'i' protocol. + + 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 proti_rcsid[] = "$Id: proti.c,v 1.1 1993/08/04 19:36:22 jtc Exp $"; +#endif + +#include +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* The 'i' protocol is a simple sliding window protocol, created by + me. It is in many ways similar to the 'g' protocol. Several ideas + are also taken from the paper ``A High-Throughput Message Transport + System'' by P. Lauder. I don't know where the paper was published, + but the author's e-mail address is piers@cs.su.oz.au. However, I + haven't adopted his main idea, which is to dispense with windows + entirely. This is because some links still do require flow control + and, more importantly, because I want to have a limit to the amount + of data I must be able to resend upon request. To reduce the costs + of window acknowledgements, I use a large window and only require + an ack at the halfway point. + + Each packet starts with a header containing the following + information: + + Intro byte 8 bits byte 1 + Packet number 5 bits byte 2 + Local channel 3 bits + Packet ack 5 bits byte 3 + Remote channel 3 bits + Packet type 3 bits bytes 4-5 + Direction 1 bit + Data length 12 bits + Header check 8 bits byte 6 + + If the data length is not 0, this is followed by the data and a 32 + bit CRC checksum. + + The following packet types are defined: + + SYNC Initialize the connection + DATA Data packet + ACK Simple acknowledgement with no data + NAK Negative acknowledgement; requests resend of single packet + SPOS Set file position + CLOSE Close the connection + */ + +/* The offsets of the bytes in the packet header. */ + +#define IHDR_INTRO (0) +#define IHDR_LOCAL (1) +#define IHDR_REMOTE (2) +#define IHDR_CONTENTS1 (3) +#define IHDR_CONTENTS2 (4) +#define IHDR_CHECK (5) + +/* Macros to set and extract values of IHDR_LOCAL and IHDR_REMOTE. */ +#define IHDRWIN_SET(iseq, ichan) (((iseq) << 3) | (ichan)) +#define IHDRWIN_GETSEQ(ival) (((ival) >> 3) & 0x1f) +#define IHDRWIN_GETCHAN(ival) ((ival) & 0x07) + +/* Macros to set and extract values of IHDR_CONTENTS fields. */ +#define IHDRCON_SET1(ttype, fcaller, cbytes) \ + (((ttype) << 5) | ((fcaller) ? (1 << 4) : 0) | (((cbytes) >> 8) & 0x0f)) +#define IHDRCON_SET2(ttype, fcaller, cbytes) ((cbytes) & 0xff) +#define THDRCON_GETTYPE(i1, i2) (((i1) >> 5) & 0x07) +#define FHDRCON_GETCALLER(i1, i2) (((i1) & (1 << 4)) != 0) +#define CHDRCON_GETBYTES(i1, i2) ((((i1) & 0x0f) << 8) | ((i2) & 0xff)) + +/* Macros for the IHDR_CHECK field. */ +#define IHDRCHECK_VAL(zhdr) \ + ((zhdr[IHDR_LOCAL] \ + ^ zhdr[IHDR_REMOTE] \ + ^ zhdr[IHDR_CONTENTS1] \ + ^ zhdr[IHDR_CONTENTS2]) \ + & 0xff) + +/* Length of the packet header. */ +#define CHDRLEN (6) + +/* Amount of space to skip between start of packet and actual data. + This is used to make the actual data longword aligned, to encourage + good performance when copying data into the buffer. */ +#define CHDRSKIPLEN (CHDRLEN + (sizeof (long) - CHDRLEN % sizeof (long))) + +/* Amount of space to skip between memory buffer and header. */ +#define CHDROFFSET (CHDRSKIPLEN - CHDRLEN) + +/* Length of the trailing checksum. */ +#define CCKSUMLEN (4) + +/* Macros to set and get the checksum. These multiply evaluate their + arguments. */ +#define ICKSUM_GET(z) \ + ((((((((unsigned long) ((z)[0] & 0xff)) << 8) \ + | (unsigned long) ((z)[1] & 0xff)) << 8) \ + | (unsigned long) ((z)[2] & 0xff)) << 8) \ + | (unsigned long) ((z)[3] & 0xff)) +#define UCKSUM_SET(z, i) \ + (void) ((z)[0] = (((i) >> 24) & 0xff), \ + (z)[1] = (((i) >> 16) & 0xff), \ + (z)[2] = (((i) >> 8) & 0xff), \ + (z)[3] = ((i) & 0xff)) + +/* The header introduction character. */ +#define IINTRO ('\007') + +/* The packet types. */ + +#define DATA (0) +#define SYNC (1) +#define ACK (2) +#define NAK (3) +#define SPOS (4) +#define CLOSE (5) + +/* Largest possible packet size (plus 1). */ +#define IMAXPACKSIZE (1 << 12) + +/* Largest possible sequence number (plus 1). */ +#define IMAXSEQ 32 + +/* Get the next sequence number given a sequence number. */ +#define INEXTSEQ(i) ((i + 1) & (IMAXSEQ - 1)) + +/* Compute i1 - i2 in sequence space (i.e., the number of packets from + i2 to i1). */ +#define CSEQDIFF(i1, i2) (((i1) + IMAXSEQ - (i2)) & (IMAXSEQ - 1)) + +/* Largest possible channel number (plus 1). */ +#define IMAXICHAN (8) + +/* Default packet size to request (protocol parameter + ``packet-size''). */ +#define IREQUEST_PACKSIZE (1024) + +/* Default window size to request (protocol parameter ``window''). */ +#define IREQUEST_WINSIZE (16) + +/* Default timeout to use when sending the SYNC packet (protocol + parameter ``sync-timeout''). */ +#define CSYNC_TIMEOUT (10) + +/* Default number of times to retry sending the SYNC packet (protocol + parameter ``sync-retries''). */ +#define CSYNC_RETRIES (6) + +/* Default timeout to use when waiting for a packet (protocol + parameter ``timeout''). */ +#define CTIMEOUT (10) + +/* Default number of times to retry sending a packet before giving up + (protocol parameter ``retries''). */ +#define CRETRIES (6) + +/* Default maximum level of errors to accept before giving up + (protocol parameter ``errors''). */ +#define CERRORS (100) + +/* Default decay rate. Each time we receive this many packets + succesfully, we decrement the error level by one (protocol + parameter ``error-decay''). */ +#define CERROR_DECAY (10) + +/* The default list of characters to avoid: XON and XOFF. This string + is processed as an escape sequence. This is 'j' protocol parameter + ``avoid''; it is defined in this file because the 'i' and 'j' + protocols share protocol parameters. */ +#define ZAVOID "\\021\\023" + +/* Local variables. */ + +/* Packet size to request (protocol parameter ``packet-size''). */ +static int iIrequest_packsize = IREQUEST_PACKSIZE; + +/* Window size to request (protocol parameter ``window''). */ +static int iIrequest_winsize = IREQUEST_WINSIZE; + +/* Remote packet size (set from SYNC packet or from + iIforced_remote_packsize). */ +static int iIremote_packsize; + +/* Size which buffers were allocated for. */ +static int iIalc_packsize; + +/* Forced remote packet size, used if non-zero (protocol parameter + ``remote-packet-size''). */ +static int iIforced_remote_packsize = 0; + +/* Remote window size (set from SYNC packet or from + iIforced_remote_winsize). */ +static int iIremote_winsize; + +/* Forced remote window size, used if non-zero (protocol parameter + ``remote-window''). */ +static int iIforced_remote_winsize = 0; + +/* Timeout to use when sending the SYNC packet (protocol + parameter ``sync-timeout''). */ +int cIsync_timeout = CSYNC_TIMEOUT; + +/* Number of times to retry sending the SYNC packet (protocol + parameter ``sync-retries''). */ +static int cIsync_retries = CSYNC_RETRIES; + +/* Timeout to use when waiting for a packet (protocol parameter + ``timeout''). */ +static int cItimeout = CTIMEOUT; + +/* Number of times to retry sending a packet before giving up + (protocol parameter ``retries''). */ +static int cIretries = CRETRIES; + +/* Maximum level of errors to accept before giving up (protocol + parameter ``errors''). */ +static int cIerrors = CERRORS; + +/* Each time we receive this many packets succesfully, we decrement + the error level by one (protocol parameter ``error-decay''). */ +static int cIerror_decay = CERROR_DECAY; + +/* The set of characters to avoid (protocol parameter ``avoid''). + This is actually part of the 'j' protocol; it is defined in this + file because the 'i' and 'j' protocols use the same protocol + parameters. */ +const char *zJavoid_parameter = ZAVOID; + +/* Routine to use when sending data. This is a hook for the 'j' + protocol. */ +static boolean (*pfIsend) P((struct sconnection *qconn, const char *zsend, + size_t csend, boolean fdoread)); + +/* Routine to use to use when reading data. This is a hook for the + 'j' protocol. */ +static boolean (*pfIreceive) P((struct sconnection *qconn, size_t cneed, + size_t *pcrec, int ctimeout, + boolean freport)); + +/* Next sequence number to send. */ +static int iIsendseq; + +/* Last sequence number received. */ +static int iIrecseq; + +/* Last sequence number we have acknowledged. */ +static int iIlocal_ack; + +/* Last sequence number remote system has acknowledged. */ +static int iIremote_ack; + +/* File position we are sending from. */ +static long iIsendpos; + +/* File position we are receiving to. */ +static long iIrecpos; + +/* TRUE if closing the connection. */ +static boolean fIclosing; + +/* Array of sent packets indexed by packet number. */ +static char *azIsendbuffers[IMAXSEQ]; + +/* Array of received packets that we aren't ready to process yet, + indexed by packet number. */ +static char *azIrecbuffers[IMAXSEQ]; + +/* For each packet sequence number, record whether we sent a NAK for + the packet. */ +static boolean afInaked[IMAXSEQ]; + +/* Number of SYNC packets received (used only to detect whether one + was received). */ +static int cIsyncs; + +/* Number of packets sent. */ +static long cIsent_packets; + +/* Number of packets received. */ +static long cIreceived_packets; + +/* Number of packets resent. */ +static long cIresent_packets; + +/* Number of bad packet headers received. */ +static long cIbad_hdr; + +/* Number of out of order packets received. */ +static long cIbad_order; + +/* Number of bad checksums received. */ +static long cIbad_cksum; + +/* Number of packets rejected by remote system. */ +static long cIremote_rejects; + +/* Protocol parameter commands. */ + +struct uuconf_cmdtab asIproto_params[] = +{ + { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_packsize, + NULL }, + { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_winsize, NULL }, + { "remote-packet-size", UUCONF_CMDTABTYPE_INT, + (pointer) &iIforced_remote_packsize, NULL }, + { "remote-window", UUCONF_CMDTABTYPE_INT, + (pointer) &iIforced_remote_winsize, NULL }, + { "sync-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_timeout, + NULL }, + { "sync-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_retries, + NULL }, + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cItimeout, NULL }, + { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIretries, NULL }, + { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cIerrors, NULL }, + { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cIerror_decay, NULL }, + /* The ``avoid'' protocol parameter is part of the 'j' protocol, but + it is convenient for the 'i' and 'j' protocols to share the same + protocol parameter table. */ + { "avoid", UUCONF_CMDTABTYPE_STRING, (pointer) &zJavoid_parameter, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Local functions. */ + +static boolean finak P((struct sdaemon *qdaemon, int iseq)); +static boolean firesend P((struct sdaemon *qdaemon)); +static boolean fiwindow_wait P((struct sdaemon *qdaemon)); +static boolean fiwait_for_packet P((struct sdaemon *qdaemon, + int ctimeout, int cretries, + boolean fone, boolean *ftimedout)); +static boolean ficheck_errors P((struct sdaemon *qdaemon)); +static boolean fiprocess_data P((struct sdaemon *qdaemon, + boolean *pfexit, boolean *pffound, + size_t *pcneed)); +static boolean fiprocess_packet P((struct sdaemon *qdaemon, + const char *zhdr, + const char *zfirst, int cfirst, + const char *zsecond, int csecond, + boolean *pfexit)); + +/* The 'i' protocol start routine. The work is done in a routine + which is also called by the 'j' protocol start routine. */ + +boolean +fistart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fsend_data, freceive_data); +} + +/* Start the protocol. This routine is called by both the 'i' and 'j' + protocol start routines. We keep transmitting a SYNC packet + containing the window and packet size we would like to receive + until we receive a SYNC packet from the remote system. The first + two bytes of the data contents of a SYNC packet are the maximum + packet size we want to receive (high byte, low byte), and the next + byte is the maximum window size we want to use. */ + +boolean +fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) + 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)); +{ + char ab[CHDRLEN + 3 + CCKSUMLEN]; + unsigned long icksum; + int ctries; + int csyncs; + + *pzlog = NULL; + + pfIsend = pfsend; + pfIreceive = pfreceive; + + if (iIforced_remote_packsize <= 0 + || iIforced_remote_packsize >= imaxpacksize) + iIforced_remote_packsize = 0; + else + iIremote_packsize = iIforced_remote_packsize; + iIalc_packsize = 0; + if (iIforced_remote_winsize <= 0 || iIforced_remote_winsize >= IMAXSEQ) + iIforced_remote_winsize = 0; + else + iIremote_winsize = iIforced_remote_winsize; + + iIsendseq = 1; + iIrecseq = 0; + iIlocal_ack = 0; + iIremote_ack = 0; + iIsendpos = 0; + iIrecpos = 0; + fIclosing = FALSE; + + cIsent_packets = 0; + cIreceived_packets = 0; + cIresent_packets = 0; + cIbad_hdr = 0; + cIbad_order = 0; + cIbad_cksum = 0; + cIremote_rejects = 0; + + ab[IHDR_INTRO] = IINTRO; + ab[IHDR_LOCAL] = ab[IHDR_REMOTE] = IHDRWIN_SET (0, 0); + ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3); + ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3); + ab[IHDR_CHECK] = IHDRCHECK_VAL (ab); + ab[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff; + ab[CHDRLEN + 1] = iIrequest_packsize & 0xff; + ab[CHDRLEN + 2] = iIrequest_winsize; + icksum = icrc (ab + CHDRLEN, 3, ICRCINIT); + UCKSUM_SET (ab + CHDRLEN + 3, icksum); + + /* The static cIsyncs is incremented each time a SYNC packet is + received. */ + csyncs = cIsyncs; + ctries = 0; + + while (TRUE) + { + boolean ftimedout; + + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fistart: Sending SYNC packsize %d winsize %d", + iIrequest_packsize, iIrequest_winsize); + + if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 3 + CCKSUMLEN, + TRUE)) + return FALSE; + + if (fiwait_for_packet (qdaemon, cIsync_timeout, 0, FALSE, + &ftimedout)) + { + if (csyncs != cIsyncs) + break; + } + else + { + if (! ftimedout) + return FALSE; + + ++ctries; + if (ctries > cIsync_retries) + { + ulog (LOG_ERROR, "Protocol startup failed"); + return FALSE; + } + } + } + + /* We got a SYNC packet; set up packet buffers to use. */ + if (iIremote_packsize > imaxpacksize) + iIremote_packsize = imaxpacksize; + do + { + int iseq; + + for (iseq = 0; iseq < IMAXSEQ; iseq++) + { + azIrecbuffers[iseq] = NULL; + afInaked[iseq] = FALSE; + azIsendbuffers[iseq] = (char *) malloc (iIremote_packsize + + CHDRSKIPLEN + + CCKSUMLEN); + if (azIsendbuffers[iseq] == NULL) + { + int ifree; + + for (ifree = 0; ifree < iseq; ifree++) + free ((pointer) azIsendbuffers[ifree]); + break; + } + } + + if (iseq >= IMAXSEQ) + { + *pzlog = zbufalc (sizeof "protocol 'i' packet size %d window %d" + + 50); + sprintf (*pzlog, "protocol '%c' packet size %d window %d", + qdaemon->qproto->bname, iIremote_packsize, + iIremote_winsize); + iIalc_packsize = iIremote_packsize; + + return TRUE; + } + + iIremote_packsize >>= 1; + } + while (iIremote_packsize > 200); + + ulog (LOG_ERROR, + "'%c' protocol startup failed; insufficient memory for packets", + qdaemon->qproto->bname); + + return FALSE; +} + +/* Shut down the protocol. We can be fairly informal about this, + since we know that the upper level protocol has already exchanged + hangup messages. If we didn't know that, we would have to make + sure that all packets before the CLOSE had been received. */ + +boolean +fishutdown (qdaemon) + struct sdaemon *qdaemon; +{ + char *z; + size_t clen; + + fIclosing = TRUE; + + z = zigetspace (qdaemon, &clen) - CHDRLEN; + + z[IHDR_INTRO] = IINTRO; + z[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0); + z[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + z[IHDR_CONTENTS1] = IHDRCON_SET1 (CLOSE, qdaemon->fcaller, 0); + z[IHDR_CONTENTS2] = IHDRCON_SET2 (CLOSE, qdaemon->fcaller, 0); + z[IHDR_CHECK] = IHDRCHECK_VAL (z); + + DEBUG_MESSAGE0 (DEBUG_PROTO, "fishutdown: Sending CLOSE"); + + if (! (*pfIsend) (qdaemon->qconn, z, CHDRLEN, FALSE)) + return FALSE; + + ulog (LOG_NORMAL, + "Protocol '%c' packets: sent %ld, resent %ld, received %ld", + qdaemon->qproto->bname, cIsent_packets, cIresent_packets, + cIreceived_packets); + if (cIbad_hdr != 0 + || cIbad_cksum != 0 + || cIbad_order != 0 + || cIremote_rejects != 0) + ulog (LOG_NORMAL, + "Errors: header %ld, checksum %ld, order %ld, remote rejects %ld", + cIbad_hdr, cIbad_cksum, cIbad_order, cIremote_rejects); + + /* Reset the protocol parameters to their default values. */ + iIrequest_packsize = IREQUEST_PACKSIZE; + iIrequest_winsize = IREQUEST_WINSIZE; + iIforced_remote_packsize = 0; + iIforced_remote_winsize = 0; + cIsync_timeout = CSYNC_TIMEOUT; + cIsync_retries = CSYNC_RETRIES; + cItimeout = CTIMEOUT; + cIretries = CRETRIES; + cIerrors = CERRORS; + cIerror_decay = CERROR_DECAY; + zJavoid_parameter = ZAVOID; + + return TRUE; +} + +/* Send a command string. These are just sent as normal packets, + ending in a packet containing a null byte. */ + +boolean +fisendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fisendcmd: Sending command \"%s\"", z); + + clen = strlen (z); + + while (TRUE) + { + char *zpacket; + size_t csize; + + zpacket = zigetspace (qdaemon, &csize); + + if (clen < csize) + { + memcpy (zpacket, z, clen + 1); + return fisenddata (qdaemon, zpacket, clen + 1, ilocal, iremote, + (long) -1); + } + + memcpy (zpacket, z, csize); + z += csize; + clen -= csize; + + if (! fisenddata (qdaemon, zpacket, csize, ilocal, iremote, (long) -1)) + return FALSE; + } + /*NOTREACHED*/ +} + +/* Send a NAK. */ + +static boolean +finak (qdaemon, iseq) + struct sdaemon *qdaemon; + int iseq; +{ + char abnak[CHDRLEN]; + + abnak[IHDR_INTRO] = IINTRO; + abnak[IHDR_LOCAL] = IHDRWIN_SET (iseq, 0); + abnak[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + abnak[IHDR_CONTENTS1] = IHDRCON_SET1 (NAK, qdaemon->fcaller, 0); + abnak[IHDR_CONTENTS2] = IHDRCON_SET2 (NAK, qdaemon->fcaller, 0); + abnak[IHDR_CHECK] = IHDRCHECK_VAL (abnak); + + afInaked[iseq] = TRUE; + + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "finak: Sending NAK %d", iseq); + + return (*pfIsend) (qdaemon->qconn, abnak, CHDRLEN, TRUE); +} + +/* Resend the latest packet the remote has not acknowledged. */ + +static boolean +firesend (qdaemon) + struct sdaemon *qdaemon; +{ + int iseq; + char *zhdr; + size_t clen; + + iseq = INEXTSEQ (iIremote_ack); + if (iseq == iIsendseq) + { + /* Everything has been ACKed and there is nothing to resend. */ + return TRUE; + } + + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "firesend: Resending packet %d", iseq); + + /* Update the received sequence number. */ + zhdr = azIsendbuffers[iseq] + CHDROFFSET; + if (IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE]) != iIrecseq) + { + int iremote; + + iremote = IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]); + zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); + zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr); + iIlocal_ack = iIrecseq; + } + + ++cIresent_packets; + + clen = CHDRCON_GETBYTES (zhdr[IHDR_CONTENTS1], + zhdr[IHDR_CONTENTS2]); + + return (*pfIsend) (qdaemon->qconn, zhdr, + CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), + TRUE); +} + +/* Wait until there is an opening in the receive window of the remote + system. */ + +static boolean +fiwindow_wait (qdaemon) + struct sdaemon *qdaemon; +{ + /* iIsendseq is the sequence number we are sending, and iIremote_ack + is the last sequence number acknowledged by the remote. */ + while (CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) + { + /* If a NAK is lost, it is possible for the other side to be + sending a stream of packets while we are waiting for an ACK. + This should be caught in fiprocess_data; if it is about to + send an ACK, but it has an unacknowledged packet to send, it + sends the entire packet. Hopefully that will trigger an ACK + or a NAK and get us going again. */ + DEBUG_MESSAGE0 (DEBUG_PROTO, "fiwindow_wait: Waiting for ACK"); + if (! fiwait_for_packet (qdaemon, cItimeout, cIretries, + TRUE, (boolean *) NULL)) + return FALSE; + } + + return TRUE; +} + +/* Get buffer space to use for packet data. We return a pointer to + the space to be used for the actual data, leaving room for the + header. */ + +/*ARGSUSED*/ +char * +zigetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = iIremote_packsize; + return azIsendbuffers[iIsendseq] + CHDRSKIPLEN; +} + +/* Send a data packet. The zdata argument will always point to value + returned by zigetspace, so we know that we have room before it for + the header information. */ + +boolean +fisenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ + char *zhdr; + unsigned long icksum; + boolean fret; + +#if DEBUG > 0 + if (ilocal < 0 || ilocal >= IMAXICHAN + || iremote < 0 || iremote >= IMAXICHAN) + ulog (LOG_FATAL, "fisenddata: ilocal %d iremote %d", ilocal, iremote); +#endif + + /* If we are changing the file position, we must send an SPOS + packet. */ + if (ipos != iIsendpos && ipos != (long) -1) + { + int inext; + char *zspos; + + /* We need to get a buffer to hold the SPOS packet, and it needs + to be next sequence number. However, the data we have been + given is currently in the next sequence number buffer. So we + shuffle the buffers around. */ + inext = INEXTSEQ (iIsendseq); + zspos = azIsendbuffers[inext]; + azIsendbuffers[inext] = zdata - CHDRSKIPLEN; + azIsendbuffers[iIsendseq] = zspos; + zspos += CHDROFFSET; + + zspos[IHDR_INTRO] = IINTRO; + zspos[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0); + zspos[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + zspos[IHDR_CONTENTS1] = IHDRCON_SET1 (SPOS, qdaemon->fcaller, + CCKSUMLEN); + zspos[IHDR_CONTENTS2] = IHDRCON_SET2 (SPOS, qdaemon->fcaller, + CCKSUMLEN); + zspos[IHDR_CHECK] = IHDRCHECK_VAL (zspos); + UCKSUM_SET (zspos + CHDRLEN, (unsigned long) ipos); + icksum = icrc (zspos + CHDRLEN, CCKSUMLEN, ICRCINIT); + UCKSUM_SET (zspos + CHDRLEN + CCKSUMLEN, icksum); + + /* Wait for an opening in the window. */ + if (iIremote_winsize > 0 + && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) + { + if (! fiwindow_wait (qdaemon)) + return FALSE; + } + + DEBUG_MESSAGE1 (DEBUG_PROTO, "fisenddata: Sending SPOS %ld", + ipos); + + if (! (*pfIsend) (qdaemon->qconn, zspos, + CHDRLEN + CCKSUMLEN + CCKSUMLEN, TRUE)) + return FALSE; + + iIsendseq = INEXTSEQ (iIsendseq); + iIsendpos = ipos; + } + + zhdr = zdata - CHDRLEN; + zhdr[IHDR_INTRO] = IINTRO; + zhdr[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, ilocal); + zhdr[IHDR_CONTENTS1] = IHDRCON_SET1 (DATA, qdaemon->fcaller, cdata); + zhdr[IHDR_CONTENTS2] = IHDRCON_SET2 (DATA, qdaemon->fcaller, cdata); + + /* Compute and set the checksum. */ + if (cdata > 0) + { + icksum = icrc (zdata, cdata, ICRCINIT); + UCKSUM_SET (zdata + cdata, icksum); + } + + /* Wait until there is an opening in the window (we hope to not have + to wait here at all, actually; ideally the window should be large + enough to avoid a wait). */ + if (iIremote_winsize > 0 + && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) + { + if (! fiwindow_wait (qdaemon)) + return FALSE; + } + + /* We only fill in IHDR_REMOTE now, since only now do know the + correct value of iIrecseq. */ + zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); + iIlocal_ack = iIrecseq; + zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr); + + DEBUG_MESSAGE2 (DEBUG_PROTO, "fisenddata: Sending packet %d (%d bytes)", + iIsendseq, (int) cdata); + + iIsendseq = INEXTSEQ (iIsendseq); + ++cIsent_packets; + + fret = (*pfIsend) (qdaemon->qconn, zhdr, + cdata + CHDRLEN + (cdata > 0 ? CCKSUMLEN : 0), + TRUE); + + iIsendpos += cdata; + + if (fret && iPrecstart != iPrecend) + { + boolean fexit; + + fret = fiprocess_data (qdaemon, &fexit, (boolean *) NULL, + (size_t *) NULL); + } + + return fret; +} + +/* Wait for data to come in. */ + +boolean +fiwait (qdaemon) + struct sdaemon *qdaemon; +{ + return fiwait_for_packet (qdaemon, cItimeout, cIretries, + FALSE, (boolean *) NULL); +} + +/* Wait for a packet. Either there is no data to send, or the remote + window is full. */ + +static boolean +fiwait_for_packet (qdaemon, ctimeout, cretries, fone, pftimedout) + struct sdaemon *qdaemon; + int ctimeout; + int cretries; + boolean fone; + boolean *pftimedout; +{ + int cshort; + int ctimeouts; + + if (pftimedout != NULL) + *pftimedout = FALSE; + + cshort = 0; + ctimeouts = 0; + + while (TRUE) + { + boolean fexit, ffound; + size_t cneed; + size_t crec; + + if (! fiprocess_data (qdaemon, &fexit, &ffound, &cneed)) + return FALSE; + + if (fexit || (fone && ffound)) + return TRUE; + + if (cneed == 0) + continue; + + DEBUG_MESSAGE1 (DEBUG_PROTO, "fiwait_for_packet: Need %d bytes", + (int) cneed); + + if (! (*pfIreceive) (qdaemon->qconn, cneed, &crec, ctimeout, TRUE)) + return FALSE; + + if (crec != 0) + { + /* If we didn't get enough data twice in a row, we may have + dropped some data and be waiting for the end of a large + packet. Incrementing iPrecstart will force + fiprocess_data to skip the current packet and try to find + the next one. */ + if (crec >= cneed) + cshort = 0; + else + { + ++cshort; + if (cshort > 1) + { + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + cshort = 0; + } + } + } + else + { + int i; + + /* We timed out on the read. */ + ++ctimeouts; + if (ctimeouts > cretries) + { + if (cretries > 0) + ulog (LOG_ERROR, "Timed out waiting for packet"); + if (pftimedout != NULL) + *pftimedout = TRUE; + return FALSE; + } + + /* Clear out the list of packets we have sent NAKs for. We + should have seen some sort of response by now. */ + for (i = 0; i < IMAXSEQ; i++) + afInaked[i] = FALSE; + + /* Send a NAK for the packet we want, and, if we have an + unacknowledged packet, send it again. */ + if (! finak (qdaemon, INEXTSEQ (iIrecseq)) + || ! firesend (qdaemon)) + return FALSE; + } + } + /*NOTREACHED*/ +} + +/* Make sure we haven't overflowed the permissible error level. */ + +static boolean +ficheck_errors (qdaemon) + struct sdaemon *qdaemon; +{ + if (cIerrors < 0) + return TRUE; + + if (((cIbad_order + cIbad_hdr + cIbad_cksum + cIremote_rejects) + - (cIreceived_packets / cIerror_decay)) + > cIerrors) + { + /* Try shrinking the packet size. */ + if (iIrequest_packsize > 400) + { + char absync[CHDRLEN + 3 + CCKSUMLEN]; + unsigned long icksum; + + iIrequest_packsize /= 2; + absync[IHDR_INTRO] = IINTRO; + absync[IHDR_LOCAL] = IHDRWIN_SET (0, 0); + absync[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + absync[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3); + absync[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3); + absync[IHDR_CHECK] = IHDRCHECK_VAL (absync); + absync[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff; + absync[CHDRLEN + 1] = iIrequest_packsize & 0xff; + absync[CHDRLEN + 2] = iIrequest_winsize; + icksum = icrc (absync + CHDRLEN, 3, ICRCINIT); + UCKSUM_SET (absync + CHDRLEN + 3, icksum); + + cIerrors *= 2; + + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "ficheck_errors: Sending SYNC packsize %d winsize %d", + iIrequest_packsize, iIrequest_winsize); + + return (*pfIsend) (qdaemon->qconn, absync, + CHDRLEN + 3 + CCKSUMLEN, TRUE); + } + + ulog (LOG_ERROR, "Too many '%c' protocol errors", + qdaemon->qproto->bname); + return FALSE; + } + + return TRUE; +} + +/* Process data waiting in the receive buffer, passing to the + fgot_data function. */ + +static boolean +fiprocess_data (qdaemon, pfexit, pffound, pcneed) + struct sdaemon *qdaemon; + boolean *pfexit; + boolean *pffound; + size_t *pcneed; +{ + boolean fbadhdr; + + if (pfexit != NULL) + *pfexit = FALSE; + if (pffound != NULL) + *pffound = FALSE; + + fbadhdr = FALSE; + + while (iPrecstart != iPrecend) + { + char ab[CHDRLEN]; + int cfirst, csecond; + char *zfirst, *zsecond; + int i; + int iget; + int ttype; + int iseq; + int csize; + int iack; + + /* If we're closing the connection, ignore any data remaining in + the input buffer. */ + if (fIclosing) + { + if (pfexit != NULL) + *pfexit = TRUE; + if (pcneed != NULL) + *pcneed = 0; + return TRUE; + } + + /* Look for the IINTRO character. */ + if (abPrecbuf[iPrecstart] != IINTRO) + { + char *zintro; + int cintro; + + cintro = iPrecend - iPrecstart; + if (cintro < 0) + cintro = CRECBUFLEN - iPrecstart; + + zintro = memchr (abPrecbuf + iPrecstart, IINTRO, (size_t) cintro); + + if (zintro == NULL) + { + iPrecstart = (iPrecstart + cintro) % CRECBUFLEN; + continue; + } + + /* We don't need % CRECBUFLEN here because zintro - (abPrecbuf + + iPrecstart) < cintro <= CRECBUFLEN - iPrecstart. */ + iPrecstart += zintro - (abPrecbuf + iPrecstart); + } + + /* Get the header into ab. */ + for (i = 0, iget = iPrecstart; + i < CHDRLEN && iget != iPrecend; + i++, iget = (iget + 1) % CRECBUFLEN) + ab[i] = abPrecbuf[iget]; + + if (i < CHDRLEN) + { + if (pcneed != NULL) + *pcneed = CHDRLEN - i; + return TRUE; + } + + if ((ab[IHDR_CHECK] & 0xff) != IHDRCHECK_VAL (ab) + || (FHDRCON_GETCALLER (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]) + ? qdaemon->fcaller : ! qdaemon->fcaller)) + { + /* We only report a single bad header message per call, to + avoid generating many errors if we get many INTRO bytes + in a row. */ + if (! fbadhdr) + { + DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Bad header"); + + ++cIbad_hdr; + if (! ficheck_errors (qdaemon)) + return FALSE; + + fbadhdr = TRUE; + } + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + + zfirst = zsecond = NULL; + cfirst = csecond = 0; + + ttype = THDRCON_GETTYPE (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]); + if (ttype == DATA || ttype == SPOS || ttype == CLOSE) + iseq = IHDRWIN_GETSEQ (ab[IHDR_LOCAL]); + else + iseq = -1; + csize = CHDRCON_GETBYTES (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]); + + if (iseq != -1) + { + /* Make sure this packet is in our receive window. The last + packet we have acked is iIlocal_ack. */ + if (iIrequest_winsize > 0 + && CSEQDIFF (iseq, iIlocal_ack) > iIrequest_winsize) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Out of order packet %d", + iseq); + + ++cIbad_order; + if (! ficheck_errors (qdaemon)) + return FALSE; + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + + continue; + } + } + + if (csize > 0) + { + int cinbuf; + char abcksum[CCKSUMLEN]; + unsigned long ickdata; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + if (cinbuf < CHDRLEN + csize + CCKSUMLEN) + { + if (pcneed != NULL) + *pcneed = CHDRLEN + csize + CCKSUMLEN - cinbuf; + return TRUE; + } + + if (iPrecend > iPrecstart) + { + cfirst = csize; + zfirst = abPrecbuf + iPrecstart + CHDRLEN; + } + else + { + cfirst = CRECBUFLEN - (iPrecstart + CHDRLEN); + if (cfirst <= 0) + { + /* Here cfirst is non-positive, so subtracting from + abPrecbuf will actually skip the appropriate number + of bytes at the start of abPrecbuf. */ + zfirst = abPrecbuf - cfirst; + cfirst = csize; + } + else + { + if (cfirst >= csize) + cfirst = csize; + else + { + zsecond = abPrecbuf; + csecond = csize - cfirst; + } + zfirst = abPrecbuf + iPrecstart + CHDRLEN; + } + } + + /* Get the checksum into abcksum. */ + for (i = 0, iget = (iPrecstart + CHDRLEN + csize) % CRECBUFLEN; + i < CCKSUMLEN; + i++, iget = (iget + 1) % CRECBUFLEN) + abcksum[i] = abPrecbuf[iget]; + + ickdata = icrc (zfirst, (size_t) cfirst, ICRCINIT); + if (csecond > 0) + ickdata = icrc (zsecond, (size_t) csecond, ickdata); + + if (ICKSUM_GET (abcksum) != ickdata) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Bad checksum; data %lu, frame %lu", + ickdata, ICKSUM_GET (abcksum)); + + ++cIbad_cksum; + if (! ficheck_errors (qdaemon)) + return FALSE; + + /* If this sequence number is in our receive window, + send a NAK. iIrecseq is the last sequence number we + have succesfully received. */ + if (iseq != -1 + && iseq != iIrecseq + && (iIrequest_winsize <= 0 + || CSEQDIFF (iseq, iIrecseq) <= iIrequest_winsize) + && azIrecbuffers[iseq] == NULL) + { + if (! finak (qdaemon, iseq)) + return FALSE; + } + + iPrecstart = (iPrecstart + 1) % CRECBUFLEN; + continue; + } + } + + /* Here we know that this is a valid packet, so we can adjust + iPrecstart accordingly. */ + if (csize == 0) + iPrecstart = (iPrecstart + CHDRLEN) % CRECBUFLEN; + else + { + iPrecstart = ((iPrecstart + CHDRLEN + csize + CCKSUMLEN) + % CRECBUFLEN); + ++cIreceived_packets; + } + + /* Get the ack from the packet, if appropriate. iIsendseq is + the next sequence number we are going to send, and + iIremote_ack is the last sequence number acknowledged by the + remote system. */ + iack = IHDRWIN_GETSEQ (ab[IHDR_REMOTE]); + if (iIremote_winsize > 0 + && iack != iIsendseq + && CSEQDIFF (iack, iIremote_ack) <= iIremote_winsize + && CSEQDIFF (iIsendseq, iack) <= iIremote_winsize) + { + /* Call uwindow_acked each time packet 0 is acked. */ + if (iack < iIremote_ack) + uwindow_acked (qdaemon, FALSE); + iIremote_ack = iack; + } + + if (iseq != -1) + { + afInaked[iseq] = FALSE; + + /* If we haven't handled all previous packets, we must save + off this packet and deal with it later. */ + if (iseq != INEXTSEQ (iIrecseq)) + { + if (iseq == iIrecseq + || (iIrequest_winsize > 0 + && CSEQDIFF (iseq, iIrecseq) > iIrequest_winsize)) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Ignoring out of order packet %d", + iseq); + continue; + } + else + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Saving unexpected packet %d", + iseq); + + if (azIrecbuffers[iseq] == NULL) + { + azIrecbuffers[iseq] = zbufalc ((size_t) (CHDRLEN + + csize)); + memcpy (azIrecbuffers[iseq], ab, CHDRLEN); + if (csize > 0) + { + memcpy (azIrecbuffers[iseq] + CHDRLEN, zfirst, + (size_t) cfirst); + if (csecond > 0) + memcpy (azIrecbuffers[iseq] + CHDRLEN + cfirst, + zsecond, (size_t) csecond); + } + } + } + + /* Send NAK's for each packet between the last one we + received and this one, avoiding any packets for which + we've already sent NAK's or which we've already + received. */ + for (i = INEXTSEQ (iIrecseq); + i != iseq; + i = INEXTSEQ (i)) + { + if (! afInaked[i] + && azIrecbuffers[i] == NULL) + { + if (! finak (qdaemon, i)) + return FALSE; + } + } + + continue; + } + + iIrecseq = iseq; + } + + if (pffound != NULL) + *pffound = TRUE; + + if (! fiprocess_packet (qdaemon, ab, zfirst, cfirst, zsecond, csecond, + pfexit)) + return FALSE; + + if (iseq != -1) + { + int inext; + + /* If we've already received the next packet(s), process + them. */ + inext = INEXTSEQ (iIrecseq); + while (azIrecbuffers[inext] != NULL) + { + char *z; + int c; + + z = azIrecbuffers[inext]; + c = CHDRCON_GETBYTES (z[IHDR_CONTENTS1], z[IHDR_CONTENTS2]); + iIrecseq = inext; + if (! fiprocess_packet (qdaemon, z, z + CHDRLEN, c, + (char *) NULL, 0, pfexit)) + return FALSE; + ubuffree (azIrecbuffers[inext]); + azIrecbuffers[inext] = NULL; + inext = INEXTSEQ (inext); + } + } + + /* If we have received half of our window size or more since the + last ACK, send one now. Sending an ACK for half the window + at a time should significantly cut the acknowledgement + traffic when only one side is sending. We should normally + not have to send an ACK if we have data to send, since each + packet sent will ACK the most recently received packet. + However, it can happen if we receive a burst of short + packets, such as a set of command acknowledgements. */ + if (iIrequest_winsize > 0 + && CSEQDIFF (iIrecseq, iIlocal_ack) >= iIrequest_winsize / 2) + { + char aback[CHDRLEN]; + + aback[IHDR_INTRO] = IINTRO; + aback[IHDR_LOCAL] = IHDRWIN_SET (0, 0); + aback[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + aback[IHDR_CONTENTS1] = IHDRCON_SET1 (ACK, qdaemon->fcaller, 0); + aback[IHDR_CONTENTS2] = IHDRCON_SET2 (ACK, qdaemon->fcaller, 0); + aback[IHDR_CHECK] = IHDRCHECK_VAL (aback); + + DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_data: Sending ACK %d", + iIrecseq); + + if (! (*pfIsend) (qdaemon->qconn, aback, CHDRLEN, TRUE)) + return FALSE; + } + } + + if (pcneed != NULL) + *pcneed = CHDRLEN; + + return TRUE; +} + +/* Process a single packet. */ + +static boolean +fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) + struct sdaemon *qdaemon; + const char *zhdr; + const char *zfirst; + int cfirst; + const char *zsecond; + int csecond; + boolean *pfexit; +{ + int ttype; + + ttype = THDRCON_GETTYPE (zhdr[IHDR_CONTENTS1], zhdr[IHDR_CONTENTS2]); + switch (ttype) + { + case DATA: + { + int iseq; + boolean fret; + + iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fiprocess_packet: Got DATA packet %d size %d", + iseq, cfirst + csecond); + fret = fgot_data (qdaemon, zfirst, (size_t) cfirst, + zsecond, (size_t) csecond, + IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]), + IHDRWIN_GETCHAN (zhdr[IHDR_LOCAL]), + iIrecpos, + INEXTSEQ (iIremote_ack) == iIsendseq, + pfexit); + iIrecpos += cfirst + csecond; + return fret; + } + + case SYNC: + { + int ipack, iwin; + + /* We accept a SYNC packet to adjust the packet and window + sizes at any time. */ + if (cfirst + csecond < 3) + { + ulog (LOG_ERROR, "Bad SYNC packet"); + return FALSE; + } + ipack = (zfirst[0] & 0xff) << 8; + if (cfirst > 1) + ipack |= zfirst[1] & 0xff; + else + ipack |= zsecond[0]; + if (cfirst > 2) + iwin = zfirst[2]; + else + iwin = zsecond[2 - cfirst]; + + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fiprocess_packet: Got SYNC packsize %d winsize %d", + ipack, iwin); + + if (iIforced_remote_packsize == 0 + && (iIalc_packsize == 0 + || ipack <= iIalc_packsize)) + iIremote_packsize = ipack; + if (iIforced_remote_winsize == 0) + iIremote_winsize = iwin; + + /* We increment a static variable to tell the initialization + code that a SYNC was received, and we set *pfexit to TRUE + to get out to the initialization code (this will do no harm + if we are called from elsewhere). */ + ++cIsyncs; + *pfexit = TRUE; + return TRUE; + } + + case ACK: + /* There is nothing to do here, since the ack was already + handled in fiprocess_data. */ + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fiprocess_packet: Got ACK %d", + IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE])); + return TRUE; + + case NAK: + /* We must resend the requested packet. */ + { + int iseq; + char *zsend; + size_t clen; + + ++cIremote_rejects; + if (! ficheck_errors (qdaemon)) + return FALSE; + + iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); + + /* The timeout code will send a NAK for the packet the remote + side wants. So we may see a NAK here for the packet we are + about to send. */ + if (iseq == iIsendseq + || (iIremote_winsize > 0 + && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize + || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize))) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_packet: Ignoring out of order NAK %d", + iseq); + return TRUE; + } + + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_packet: Got NAK %d; resending packet", + iseq); + + /* Update the received sequence number. */ + zsend = azIsendbuffers[iseq] + CHDROFFSET; + if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq) + { + int iremote; + + iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]); + zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); + zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend); + iIlocal_ack = iIrecseq; + } + + ++cIresent_packets; + + clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1], + zsend[IHDR_CONTENTS2]); + + return (*pfIsend) (qdaemon->qconn, zsend, + CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), + TRUE); + } + + case SPOS: + /* Set the file position. */ + { + char abpos[CCKSUMLEN]; + const char *zpos; + + if (cfirst >= CCKSUMLEN) + zpos = zfirst; + else + { + memcpy (abpos, zfirst, (size_t) cfirst); + memcpy (abpos + cfirst, zsecond, (size_t) (CCKSUMLEN - cfirst)); + zpos = abpos; + } + iIrecpos = (long) ICKSUM_GET (zpos); + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fiprocess_packet: Got SPOS %ld", iIrecpos); + return TRUE; + } + + case CLOSE: + { + boolean fexpected; + + fexpected = ! fLog_sighup || fIclosing; + if (! fexpected) + ulog (LOG_ERROR, "Received unexpected CLOSE packet"); + else + DEBUG_MESSAGE0 (DEBUG_PROTO, "fiprocess_packet: Got CLOSE packet"); + + fIclosing = TRUE; + *pfexit = TRUE; + return fexpected; + } + + default: + /* Just ignore unrecognized packet types, for future protocol + enhancements. */ + DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Got packet type %d", + ttype); + return TRUE; + } + /*NOTREACHED*/ +} diff --git a/gnu/libexec/uucp/uucico/protj.c b/gnu/libexec/uucp/uucico/protj.c new file mode 100644 index 0000000000..bdf2b85611 --- /dev/null +++ b/gnu/libexec/uucp/uucico/protj.c @@ -0,0 +1,671 @@ +/* protj.c + The 'j' protocol. + + 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 protj_rcsid[] = "$Id: protj.c,v 1.1 1993/08/04 19:36:23 jtc Exp $"; +#endif + +#include +#include + +#include "uudefs.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* The 'j' protocol. + + The 'j' protocol is a wrapper around the 'i' protocol, which avoids + the use of certain characters, such as XON and XOFF. + + Each 'j' protocol packet begins with a '^' character, followed by a + two byte encoded size giving the total number of bytes in the + packet. The first byte is HIGH, the second byte is LOW, and the + number of bytes is (HIGH - 32) * 64 + (LOW - 32), where 32 <= HIGH + < 127 and 32 <= LOW < 96 (i.e., HIGH and LOW are printable ASCII + characters). This is followed by a '=' character. The next two + bytes are the number of data bytes in the packet, using the same + encoding. This is followed by a '@' character, and then that + number of data bytes. The remaining bytes in the packet are + indices of bytes which must be transformed, followed by a trailing + '~' character. The indices are encoded in the following overly + complex format. + + Each byte index is two bytes long. The first byte in the index is + INDEX-HIGH and the second is INDEX-LOW. If 32 <= INDEX-HIGH < 126, + the byte index refers to the byte at position (INDEX-HIGH - 32) * + 32 + INDEX-LOW % 32 in the actual data, where 32 <= INDEX-LOW < + 127. If 32 <= INDEX-LOW < 64, then 128 must be added to the + indexed byte. If 64 <= INDEX-LOW < 96, then the indexed byte must + be exclusive or'red with 32. If 96 <= INDEX-LOW < 127, both + operations must be performed. If INDEX-HIGH == 126, then the byte + index refers to the byte at position (INDEX-LOW - 32) * 32 + 31, + where 32 <= INDEX-LOW < 126. 128 must be added to the byte, and it + must be exclusive or'red with 32. This unfortunately requires a + special test (when encoding INDEX-LOW must be checked for 127; when + decoding INDEX-HIGH must be checked for 126). It does, however, + permit the byte indices field to consist exclusively of printable + ASCII characters. + + The maximum value for a byte index is (125 - 32) * 32 + 31 == 3007, + so the is the maximum number of data bytes permitted. Since it is + convenient to have each 'j' protocol packet correspond to each 'i' + protocol packet, we restrict the 'i' protocol accordingly. + + Note that this encoding method assumes that we can send all + printable ASCII characters. */ + +/* The first byte of each packet. I just picked these values + randomly, trying to get characters that were perhaps slightly less + likely to appear in normal text. */ +#define FIRST '\136' + +/* The fourth byte of each packet. */ +#define FOURTH '\075' + +/* The seventh byte of each packet. */ +#define SEVENTH '\100' + +/* The trailing byte of each packet. */ +#define TRAILER '\176' + +/* The length of the header. */ +#define CHDRLEN (7) + +/* Get a number of bytes encoded in a two byte length at the start of + a packet. */ +#define CGETLENGTH(b1, b2) (((b1) - 32) * 64 + ((b2) - 32)) + +/* Set the high and low bytes of a two byte length at the start of a + packet. */ +#define ISETLENGTH_FIRST(i) ((i) / 64 + 32) +#define ISETLENGTH_SECOND(i) ((i) % 64 + 32) + +/* The maximum packet size we support, as determined by the byte + indices. */ +#define IMAXPACKSIZE ((125 - 32) * 32 + 31) + +/* Amount to offset the bytes in the byte index by. */ +#define INDEX_OFFSET (32) + +/* Maximum value of INDEX-LOW, before offsetting. */ +#define INDEX_MAX_LOW (32) + +/* Maximum value of INDEX-HIGH, before offsetting. */ +#define INDEX_MAX_HIGH (94) + +/* The set of characters to avoid. */ +static char *zJavoid; + +/* The number of characters to avoid. */ +static size_t cJavoid; + +/* A buffer used when sending data. */ +static char *zJbuf; + +/* The end of the undecoded data in abPrecbuf. */ +static int iJrecend; + +/* Local functions. */ +static boolean fjsend_data P((struct sconnection *qconn, const char *zsend, + size_t csend, boolean fdoread)); +static boolean fjreceive_data P((struct sconnection *qconn, size_t cneed, + size_t *pcrec, int ctimeout, + boolean freport)); +static boolean fjprocess_data P((size_t *pcneed)); + +/* Start the protocol. We first send over the list of characters to + avoid as an escape sequence, starting with FIRST and ending with + TRAILER. There is no error checking done on this string. */ + +boolean +fjstart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + size_t clen; + char *zsend; + int b; + size_t cbuf, cgot; + char *zbuf; + int i; + + /* Send the characters we want to avoid to the other side. */ + clen = strlen (zJavoid_parameter); + zsend = zbufalc (clen + 3); + zsend[0] = FIRST; + memcpy (zsend + 1, zJavoid_parameter, clen); + zsend[clen + 1] = TRAILER; + zsend[clen + 2] = '\0'; + if (! fsend_data (qdaemon->qconn, zsend, clen + 2, TRUE)) + { + ubuffree (zsend); + return FALSE; + } + ubuffree (zsend); + + /* Read the characters the other side wants to avoid. */ + while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE)) + != FIRST) + { + if (b < 0) + { + if (b == -1) + ulog (LOG_ERROR, "Timed out in 'j' protocol startup"); + return FALSE; + } + } + + cbuf = 20; + zbuf = zbufalc (cbuf); + cgot = 0; + while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE)) + != TRAILER) + { + if (b < 0) + { + ubuffree (zbuf); + if (b == -1) + ulog (LOG_ERROR, "Timed out in 'j' protocol startup"); + return FALSE; + } + if (cgot + 1 >= cbuf) + { + char *znew; + + cbuf += 20; + znew = zbufalc (cbuf); + memcpy (znew, zbuf, cgot); + ubuffree (zbuf); + zbuf = znew; + } + zbuf[cgot] = b; + ++cgot; + } + zbuf[cgot] = '\0'; + + /* Merge the local and remote avoid bytes into one list, translated + into bytes. */ + cgot = cescape (zbuf); + + clen = strlen (zJavoid_parameter); + zJavoid = zbufalc (clen + cgot + 1); + memcpy (zJavoid, zJavoid_parameter, clen + 1); + cJavoid = cescape (zJavoid); + + for (i = 0; i < cgot; i++) + { + if (memchr (zJavoid, zbuf[i], cJavoid) == NULL) + { + zJavoid[cJavoid] = zbuf[i]; + ++cJavoid; + } + } + + ubuffree (zbuf); + + /* We can't avoid ASCII printable characters, since the encoding + method assumes that they can always be sent. If it ever turns + out to be important, a different encoding method could be used, + perhaps keyed by a different FIRST character. */ + if (cJavoid == 0) + { + ulog (LOG_ERROR, "No characters to avoid in 'j' protocol"); + return FALSE; + } + for (i = 0; i < cJavoid; i++) + { + if (zJavoid[i] >= 32 && zJavoid[i] <= 126) + { + ulog (LOG_ERROR, "'j' protocol can't avoid character '\\%03o'", + zJavoid[i]); + return FALSE; + } + } + + /* If we are avoiding XON and XOFF, use XON/XOFF handshaking. */ + if (memchr (zJavoid, '\021', cJavoid) != NULL + && memchr (zJavoid, '\023', cJavoid) != NULL) + { + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_ON)) + return FALSE; + } + + /* Let the port settle. */ + usysdep_sleep (2); + + /* Allocate a buffer we use when sending data. We will probably + never actually need one this big; if this code is ported to a + computer with small amounts of memory, this should be changed to + increase the buffer size as needed. */ + zJbuf = zbufalc (CHDRLEN + IMAXPACKSIZE * 3 + 1); + zJbuf[0] = FIRST; + zJbuf[3] = FOURTH; + zJbuf[6] = SEVENTH; + + /* iJrecend is the end of the undecoded data, and iPrecend is the + end of the decoded data. At this point there is no decoded data, + and we must initialize the variables accordingly. */ + iJrecend = iPrecend; + iPrecend = iPrecstart; + + /* Now do the 'i' protocol startup. */ + return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fjsend_data, + fjreceive_data); +} + +/* Shut down the protocol. */ + +boolean +fjshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + boolean fret; + + fret = fishutdown (qdaemon); + ubuffree (zJavoid); + ubuffree (zJbuf); + return fret; +} + +/* Encode a packet of data and send it. This copies the data, which + is a waste of time, but calling fsend_data three times (for the + header, the body, and the trailer) would waste even more time. */ + +static boolean +fjsend_data (qconn, zsend, csend, fdoread) + struct sconnection *qconn; + const char *zsend; + size_t csend; + boolean fdoread; +{ + char *zput, *zindex; + const char *zfrom, *zend; + char bfirst, bsecond; + int iprecendhold; + boolean fret; + + zput = zJbuf + CHDRLEN; + zindex = zput + csend; + zfrom = zsend; + zend = zsend + csend; + + /* Optimize for the common case of avoiding two characters. */ + bfirst = zJavoid[0]; + if (cJavoid <= 1) + bsecond = bfirst; + else + bsecond = zJavoid[1]; + while (zfrom < zend) + { + char b; + boolean f128, f32; + int i, ihigh, ilow; + + b = *zfrom++; + if (b != bfirst && b != bsecond) + { + int ca; + char *za; + + if (cJavoid <= 2) + { + *zput++ = b; + continue; + } + + ca = cJavoid - 2; + za = zJavoid + 2; + while (ca-- != 0) + if (*za++ == b) + break; + + if (ca < 0) + { + *zput++ = b; + continue; + } + } + + if ((b & 0x80) == 0) + f128 = FALSE; + else + { + b &=~ 0x80; + f128 = TRUE; + } + if (b >= 32 && b != 127) + f32 = FALSE; + else + { + b ^= 0x20; + f32 = TRUE; + } + + /* We must now put the byte index into the buffer. The byte + index is encoded similarly to the length of the actual data, + but the byte index also encodes the operations that must be + performed on the byte. The first byte in the index is the + most significant bits. If we only had to subtract 128 from + the byte, we use the second byte directly. If we had to xor + the byte with 32, we add 32 to the second byte index. If we + had to perform both operations, we add 64 to the second byte + index. However, if we had to perform both operations, and + the second byte index was 31, then after adding 64 and + offsetting by 32 we would come up with 127, which we are not + permitted to use. Therefore, in this special case we set the + first byte of the index to 126 and put the original first + byte into the second byte position instead. This is why we + could not permit the high byte of the length of the actual + data to be 126. We can get away with the switch because both + the value of the second byte index (31) and the operations to + perform (both) are known. */ + i = zput - (zJbuf + CHDRLEN); + ihigh = i / INDEX_MAX_LOW; + ilow = i % INDEX_MAX_LOW; + + if (f128 && ! f32) + ; + else if (f32 && ! f128) + ilow += INDEX_MAX_LOW; + else + { + /* Both operations had to be performed. */ + if (ilow != INDEX_MAX_LOW - 1) + ilow += 2 * INDEX_MAX_LOW; + else + { + ilow = ihigh; + ihigh = INDEX_MAX_HIGH; + } + } + + *zindex++ = ihigh + INDEX_OFFSET; + *zindex++ = ilow + INDEX_OFFSET; + *zput++ = b; + } + + *zindex++ = TRAILER; + + /* Set the lengths into the buffer. zJbuf[0,3,6] were set when + zJbuf was allocated, and are never changed thereafter. */ + zJbuf[1] = ISETLENGTH_FIRST (zindex - zJbuf); + zJbuf[2] = ISETLENGTH_SECOND (zindex - zJbuf); + zJbuf[4] = ISETLENGTH_FIRST (csend); + zJbuf[5] = ISETLENGTH_SECOND (csend); + + /* Send the data over the line. We must preserve iPrecend as + discussed in fjreceive_data. */ + iprecendhold = iPrecend; + iPrecend = iJrecend; + fret = fsend_data (qconn, zJbuf, (size_t) (zindex - zJbuf), fdoread); + iJrecend = iPrecend; + iPrecend = iprecendhold; + + /* Process any bytes that may have been placed in abPrecbuf. */ + if (fret && iPrecend != iJrecend) + { + if (! fjprocess_data ((size_t *) NULL)) + return FALSE; + } + + return fret; +} + +/* Receive and decode data. This is called by fiwait_for_packet. We + need to be able to return decoded data between iPrecstart and + iPrecend, while not losing any undecoded partial packets we may + have read. We use iJrecend as a pointer to the end of the + undecoded data, and set iPrecend for the decoded data. iPrecend + points to the start of the undecoded data. */ + +static boolean +fjreceive_data (qconn, cineed, pcrec, ctimeout, freport) + struct sconnection *qconn; + size_t cineed; + size_t *pcrec; + int ctimeout; + boolean freport; +{ + int iprecendstart; + size_t cjneed; + size_t crec; + int cnew; + + iprecendstart = iPrecend; + + /* Figure out how many bytes we need to decode the next packet. */ + if (! fjprocess_data (&cjneed)) + return FALSE; + + /* As we long as we read some data but don't have enough to decode a + packet, we try to read some more. We decrease the timeout each + time so that we will not wait forever if the connection starts + dribbling data. */ + do + { + int iprecendhold; + size_t cneed; + + if (cjneed > cineed) + cneed = cjneed; + else + cneed = cineed; + + /* We are setting iPrecend to the end of the decoded data for + the 'i' protocol. When we do the actual read, we have to set + it to the end of the undecoded data so that any undecoded + data we have received is not overwritten. */ + iprecendhold = iPrecend; + iPrecend = iJrecend; + if (! freceive_data (qconn, cneed, &crec, ctimeout, freport)) + return FALSE; + iJrecend = iPrecend; + iPrecend = iprecendhold; + + /* Process any data we have received. This will set iPrecend to + the end of the new decoded data. */ + if (! fjprocess_data (&cjneed)) + return FALSE; + + cnew = iPrecend - iprecendstart; + if (cnew < 0) + cnew += CRECBUFLEN; + + if (cnew > cineed) + cineed = 0; + else + cineed -= cnew; + + --ctimeout; + } + while (cnew == 0 && crec > 0 && ctimeout > 0); + + DEBUG_MESSAGE1 (DEBUG_PROTO, "fjreceive_data: Got %d decoded bytes", + cnew); + + *pcrec = cnew; + return TRUE; +} + +/* Decode the data in the buffer, optionally returning the number of + bytes needed to complete the next packet. */ + +static boolean +fjprocess_data (pcneed) + size_t *pcneed; +{ + int istart; + + istart = iPrecend; + while (istart != iJrecend) + { + int i, iget; + char ab[CHDRLEN]; + int cpacket, cdata, chave; + int iindex, iendindex; + + /* Find the next occurrence of FIRST. If we have to skip some + garbage bytes to get to it, zero them out (so they don't + confuse the 'i' protocol) and advance iPrecend. This will + save us from looking at them again. */ + if (abPrecbuf[istart] != FIRST) + { + int cintro; + char *zintro; + size_t cskipped; + + cintro = iJrecend - istart; + if (cintro < 0) + cintro = CRECBUFLEN - istart; + + zintro = memchr (abPrecbuf + istart, FIRST, (size_t) cintro); + if (zintro == NULL) + { + bzero (abPrecbuf + istart, (size_t) cintro); + istart = (istart + cintro) % CRECBUFLEN; + iPrecend = istart; + continue; + } + + cskipped = zintro - (abPrecbuf + istart); + bzero (abPrecbuf + istart, cskipped); + istart += cskipped; + iPrecend = istart; + } + + for (i = 0, iget = istart; + i < CHDRLEN && iget != iJrecend; + ++i, iget = (iget + 1) % CRECBUFLEN) + ab[i] = abPrecbuf[iget]; + + if (i < CHDRLEN) + { + if (pcneed != NULL) + *pcneed = CHDRLEN - i; + return TRUE; + } + + cpacket = CGETLENGTH (ab[1], ab[2]); + cdata = CGETLENGTH (ab[4], ab[5]); + + /* Make sure the header has the right magic characters, that the + data is not larger than the packet, and that we have an even + number of byte index characters. */ + if (ab[3] != FOURTH + || ab[6] != SEVENTH + || cdata > cpacket - CHDRLEN - 1 + || (cpacket - cdata - CHDRLEN - 1) % 2 == 1) + { + istart = (istart + 1) % CRECBUFLEN; + continue; + } + + chave = iJrecend - istart; + if (chave < 0) + chave += CRECBUFLEN; + + if (chave < cpacket) + { + if (pcneed != NULL) + *pcneed = cpacket - chave; + return TRUE; + } + + /* Figure out where the byte indices start and end. */ + iindex = (istart + CHDRLEN + cdata) % CRECBUFLEN; + iendindex = (istart + cpacket - 1) % CRECBUFLEN; + + /* Make sure the magic trailer character is there. */ + if (abPrecbuf[iendindex] != TRAILER) + { + istart = (istart + 1) % CRECBUFLEN; + continue; + } + + /* We have a packet to decode. The decoding process is simpler + than the encoding process, since all we have to do is examine + the byte indices. We zero out the byte indices as we go, so + that they will not confuse the 'i' protocol. */ + while (iindex != iendindex) + { + int ihigh, ilow; + boolean f32, f128; + int iset; + + ihigh = abPrecbuf[iindex] - INDEX_OFFSET; + abPrecbuf[iindex] = 0; + iindex = (iindex + 1) % CRECBUFLEN; + ilow = abPrecbuf[iindex] - INDEX_OFFSET; + abPrecbuf[iindex] = 0; + iindex = (iindex + 1) % CRECBUFLEN; + + /* Now we must undo the encoding, by adding 128 and xoring + with 32 as appropriate. Which to do is encoded in the + low byte, except that if the high byte is the special + value 126, then the low byte is actually the high byte + and both operations are performed. */ + f128 = TRUE; + f32 = TRUE; + if (ihigh == INDEX_MAX_HIGH) + iset = ilow * INDEX_MAX_LOW + INDEX_MAX_LOW - 1; + else + { + iset = ihigh * INDEX_MAX_LOW + ilow % INDEX_MAX_LOW; + if (ilow < INDEX_MAX_LOW) + f32 = FALSE; + else if (ilow < 2 * INDEX_MAX_LOW) + f128 = FALSE; + } + + /* Now iset is the index from the start of the data to the + byte to modify; adjust it to an index in abPrecbuf. */ + iset = (istart + CHDRLEN + iset) % CRECBUFLEN; + + if (f128) + abPrecbuf[iset] |= 0x80; + if (f32) + abPrecbuf[iset] ^= 0x20; + } + + /* Zero out the header and trailer to avoid confusing the 'i' + protocol, and update iPrecend to the end of decoded data. */ + for (i = 0, iget = istart; + i < CHDRLEN && iget != iJrecend; + ++i, iget = (iget + 1) % CRECBUFLEN) + abPrecbuf[iget] = 0; + abPrecbuf[iendindex] = 0; + iPrecend = (iendindex + 1) % CRECBUFLEN; + istart = iPrecend; + } + + if (pcneed != NULL) + *pcneed = CHDRLEN + 1; + return TRUE; +} diff --git a/gnu/libexec/uucp/uucico/prott.c b/gnu/libexec/uucp/uucico/prott.c new file mode 100644 index 0000000000..477ccf4f49 --- /dev/null +++ b/gnu/libexec/uucp/uucico/prott.c @@ -0,0 +1,330 @@ +/* prott.c + The 't' protocol. + + 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 prott_rcsid[] = "$Id: prott.c,v 1.1 1993/08/04 19:36:24 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* This implementation is based on code written by Rick Adams. + + This code implements the 't' protocol, which does no error checking + whatsoever and thus requires an end-to-end verified eight bit + communication line, such as is provided by TCP. Using it with a + modem is unadvisable, since errors can occur between the modem and + the computer. */ + +/* The buffer size we use. */ +#define CTBUFSIZE (1024) + +/* The offset in the buffer to the data. */ +#define CTFRAMELEN (4) + +/* Commands are sent in multiples of this size. */ +#define CTPACKSIZE (512) + +/* A pointer to the buffer we will use. */ +static char *zTbuf; + +/* True if we are receiving a file. */ +static boolean fTfile; + +/* The timeout we use. */ +static int cTtimeout = 120; + +struct uuconf_cmdtab asTproto_params[] = +{ + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cTtimeout, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Local function. */ + +static boolean ftprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, + size_t *pcneed)); + +/* Start the protocol. */ + +boolean +ftstart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + *pzlog = NULL; + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + zTbuf = (char *) xmalloc (CTBUFSIZE + CTFRAMELEN); + /* The first two bytes of the buffer are always zero. */ + zTbuf[0] = 0; + zTbuf[1] = 0; + fTfile = FALSE; + usysdep_sleep (2); + return TRUE; +} + +/* Stop the protocol. */ + +/*ARGSUSED*/ +boolean +ftshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + xfree ((pointer) zTbuf); + zTbuf = NULL; + cTtimeout = 120; + return TRUE; +} + +/* Send a command string. We send everything up to and including the + null byte. The number of bytes we send must be a multiple of + TPACKSIZE. */ + +/*ARGSUSED*/ +boolean +ftsendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen, csend; + char *zalc; + boolean fret; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ftsendcmd: Sending command \"%s\"", z); + + clen = strlen (z); + + /* We need to send the smallest multiple of CTPACKSIZE which is + greater than clen (not equal to clen, since we need room for the + null byte). */ + csend = ((clen / CTPACKSIZE) + 1) * CTPACKSIZE; + + zalc = zbufalc (csend); + memcpy (zalc, z, clen); + bzero (zalc + clen, csend - clen); + + fret = fsend_data (qdaemon->qconn, zalc, csend, TRUE); + ubuffree (zalc); + return fret; +} + +/* Get space to be filled with data. We provide a buffer which has + four bytes at the start available to hold the length. */ + +/*ARGSIGNORED*/ +char * +ztgetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = CTBUFSIZE; + return zTbuf + CTFRAMELEN; +} + +/* Send out some data. We are allowed to modify the four bytes + preceding the buffer. This allows us to send the entire block with + header bytes in a single call. */ + +/*ARGSIGNORED*/ +boolean +ftsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ + /* Here we do htonl by hand, since it doesn't exist everywhere. We + know that the amount of data cannot be greater than CTBUFSIZE, so + the first two bytes of this value will always be 0. They were + set to 0 in ftstart so we don't touch them here. This is useful + because we cannot portably right shift by 24 or 16, since we + might be dealing with sixteen bit integers. */ + zdata[-2] = (char) ((cdata >> 8) & 0xff); + zdata[-1] = (char) (cdata & 0xff); + + /* We pass FALSE to fsend_data since we don't expect the other side + to be sending us anything just now. */ + return fsend_data (qdaemon->qconn, zdata - CTFRAMELEN, cdata + CTFRAMELEN, + FALSE); +} + +/* Process data and return the amount we need in *pfneed. */ + +static boolean +ftprocess_data (qdaemon, pfexit, pcneed) + struct sdaemon *qdaemon; + boolean *pfexit; + size_t *pcneed; +{ + int cinbuf, cfirst, clen; + + *pfexit = FALSE; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + + if (! fTfile) + { + /* We are not receiving a file. Commands are read in chunks of + CTPACKSIZE. */ + while (cinbuf >= CTPACKSIZE) + { + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > CTPACKSIZE) + cfirst = CTPACKSIZE; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "ftprocess_data: Got %d command bytes", + cfirst); + + if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, + (size_t) cfirst, abPrecbuf, + (size_t) CTPACKSIZE - cfirst, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + CTPACKSIZE) % CRECBUFLEN; + + if (*pfexit) + return TRUE; + + cinbuf -= CTPACKSIZE; + } + + if (pcneed != NULL) + *pcneed = CTPACKSIZE - cinbuf; + + return TRUE; + } + + /* Here we are receiving a file. The data comes in blocks. The + first four bytes contain the length, followed by that amount of + data. */ + + while (cinbuf >= CTFRAMELEN) + { + /* The length is stored in network byte order, MSB first. */ + + clen = (((((((abPrecbuf[iPrecstart] & 0xff) << 8) + + (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN] & 0xff)) << 8) + + (abPrecbuf[(iPrecstart + 2) % CRECBUFLEN] & 0xff)) << 8) + + (abPrecbuf[(iPrecstart + 3) % CRECBUFLEN] & 0xff)); + + if (cinbuf < clen + CTFRAMELEN) + { + if (pcneed != NULL) + *pcneed = clen + CTFRAMELEN - cinbuf; + return TRUE; + } + + iPrecstart = (iPrecstart + CTFRAMELEN) % CRECBUFLEN; + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > clen) + cfirst = clen; + + DEBUG_MESSAGE1 (DEBUG_PROTO, + "ftprocess_data: Got %d data bytes", + clen); + + if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, + (size_t) cfirst, abPrecbuf, (size_t) (clen - cfirst), + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + + if (*pfexit) + return TRUE; + + cinbuf -= clen + CTFRAMELEN; + } + + if (pcneed != NULL) + *pcneed = CTFRAMELEN - cinbuf; + + return TRUE; +} + +/* Wait for data to come in and process it until we've reached the end + of a command or a file. */ + +boolean +ftwait (qdaemon) + struct sdaemon *qdaemon; +{ + while (TRUE) + { + boolean fexit; + size_t cneed, crec; + + if (! ftprocess_data (qdaemon, &fexit, &cneed)) + return FALSE; + if (fexit) + return TRUE; + + if (! freceive_data (qdaemon->qconn, cneed, &crec, cTtimeout, TRUE)) + return FALSE; + + if (crec == 0) + { + ulog (LOG_ERROR, "Timed out waiting for data"); + return FALSE; + } + } +} + +/* File level routine, to set fTfile correctly. */ + +/*ARGSUSED*/ +boolean +ftfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fstart; + boolean fsend; + long cbytes; + boolean *pfhandled; +{ + *pfhandled = FALSE; + + if (! fsend) + fTfile = fstart; + + return TRUE; +} diff --git a/gnu/libexec/uucp/uucico/protz.c b/gnu/libexec/uucp/uucico/protz.c new file mode 100644 index 0000000000..e593e07e5b --- /dev/null +++ b/gnu/libexec/uucp/uucico/protz.c @@ -0,0 +1,2626 @@ +/* protz.c Version 1.5, 92Apr24 */ +/* Modified by Ian Lance Taylor for Taylor UUCP 1.04 92Aug4. */ + +/* + * Doug Evans, dje@sspiff.UUCP or dje@ersys.edmonton.ab.ca + * + * This file provides the Zmodem protocol (by Chuck Forsberg) for + * Ian Taylor's UUCP package. + * + * It was originally developed to establish a uucp link between myself and my + * employer: Ivation Datasystems, Inc. of Ottawa. + * + * My thanks to Ivation for letting me release this to the public. Given that + * Zmodem is in the public domain, no additional copyrights have been added. + * + ***************************************************************************** + * + * It's been difficult fitting Zmodem into the UUCP world. I have been guided + * mostly by trying to plug it into Taylor UUCP. Where "the Zmodem way of doing + * things" conflicted with "the UUCP way of doing things", I have err'd on the + * side of UUCP. At the end of it all, I have achieved something that will plug + * into Taylor UUCP very easily, but some might argue that I have corrupted Z + * too much. At any rate, compatibility with sz/rz was sacrificed to achieve a + * clean UUCP protocol. Given that, I took the opportunity to start from + * scratch when defining protocol constants (EG: ZBIN). + * + * 1) I wasn't quite sure how to enhance Zmodem to handle send+receive in one + * session, so I added a 'g' protocol like initialization sequence. This + * also gets this stuff out of the way, in case we ever try to support + * full-duplex. + * + * Caller Callee + * ------ ------ + * ZINIT --> <-- ZINIT + * ZDATA (ZCRCF) --> <-- ZDATA (ZCRCF) + * ZACK --> <-- ZACK + * ZINITEND --> <-- ZINITEND + * + * ZINIT is a combination of ZRINIT and ZSINIT and is intended to exchange + * simple protocol information (flags) and the protocol version number. + * ZDATA is intended to include window size information as well as the + * "Myattn" string (although at the moment it doesn't contain anything). + * ZDATA may contain at most 1k bytes of data and is sent out as one ZCRCF + * packet. Two ack's (ZACK + ZINITEND) are needed to ensure both sides have + * received ZDATA. + * + * 2) I've hardcoded several protocol parameters, like 32 bit CRC's for data. + * Others are not supported (we don't need them). + * + * 3) ZHEX headers use 32 bit CRC's. + * + * 4) Zmodem sends the ZFILE message "in one chunk". If there are errors, the + * entire string is resent. I have continued this practice. All UUCP + * commands are sent "in one chunk". This can be changed down the road if + * necessary. + * + * 5) The ZEOF message has been replaced with a new ZCRCx value: ZCRCF. ZCRCF + * is identical to ZCRCW except that it indicates the end of the message. + * The protocol here is *not* a file transfer protocol. It is an end to end + * transport protocol (that preserves message boundaries). + * + * 6) Zmodem handles restarting a file transfer, but as best as I can tell UUCP + * does not. At least Taylor UUCP doesn't. And if UUCP does start handling + * file restart, can it be plugged into the existing Zmodem way with zero + * changes? Beats me. Therefore I have removed this part of the code. One + * can always put it back in if and when UUCP handles it. Ditto for other + * pieces of removed code: there's no point in overly complicating this code + * when supporting all the bells and whistles requires enhancements to UUCP + * itself. + * + * *** It is easier to put code back in in an upward compatible manner *** + * *** than it is to correct for misunderstood code or poorly merged *** + * *** (Zmodem vs UUCP) code. *** + * + * 7) For the character in the initial "protocol selection" sequence, I have + * chosen 'a'. I'm told 'z' is already in use for something that isn't + * Zmodem. It's entirely reasonable to believe that if Zmodem ever becomes a + * standard UUCP protocol, this won't be it (so I'll leave z/Z for them). + * Publicly, this is the 'a' protocol. Internally, it is refered to as 'z'. + * A little confusing, I know. Maybe in time I'll refer to it internally as + * 'a', or maybe in time this will be *the* 'z' protocol. + * + * 8) Since we are writing a transport protocol, which isn't supposed to know + * anything about what is being transfered or where it is coming from, the + * header data value has changed meaning. It no longer means "file position" + * but instead means "window position". It is a running counter of the bytes + * transfered. Each "message" begins on a 1k boundary so the count isn't a + * precise byte count. The counter wraps every 4 gigabytes, although this + * wrapping isn't supported yet. + * + * FIXME: At present the max data transfered per session is 4 gigabytes. + * + **************************************************************************** + * + * A typical message sequence is (master sending file to slave): + * + * Master Slave + * ------ ----- + * ZDATA (S, ZCRCF) --> + * <-- ZACK + * <-- ZDATA (SY, ZCRCF) + * ZACK --> + * ZDATA --> + * ... <-- ZACK/ZRPOS + * ZDATA (ZCRCF) --> + * <-- ZACK + * <-- ZDATA (CY, ZCRCF) + * ZACK --> + * + * A typical message sequence is (master receiving file from slave): + * + * Master Slave + * ------ ----- + * ZDATA (R, ZCRCF) --> + * <-- ZACK + * <-- ZDATA (RY, ZCRCF) + * ZACK --> + * <-- ZDATA + * ZACK/ZRPOS ... --> + * <-- ZDATA (ZCRCF) + * ZACK --> + * ZDATA (CY, ZCRCF) --> + * <-- ZACK + * + ***************************************************************************** + * + * Notes: + * 1) For future bidirectional concerns, keep packet types "unidirectional". + * Sender always uses: ZDATA, ZNAK + * Receiver always uses: ZRPOS, ZACK + * There is no intersection. + * + * I'm not sure if this is necessary or even useful, but it seems to be. + * + * 2) I use to store the byte count / 32 in the data header. This left 5 bits + * unused for future concerns. I removed this because of the following + * situation when sending a file: + * + * ZDATA (ZCRCG, xx bytes) - received ok + * ZDATA (ZCRCF, 0 bytes) - corrupted + * + * At this point the receiver would like to send back a ZRPOS with a value + * of the size of the file. However, it can't because the value is divided + * by 32, and it would have to round up to the next multiple of 32. This + * seemed a little ugly, so I went with using the entire header to store + * the byte count. + * + ***************************************************************************** + * + * Source version: + * + * 1.1,2,3 + * Protocol version 0 + * Early attempts, completely rewritten later. + * + * 1.4 Protocol version 1 + * Beta test sent to Ian for analysis 92Apr18. + * + * 1.5 Protocol version 1 + * Released 92Apr24. + * + ***************************************************************************** + * + * Protocol version: + * + * A version number is exchanged in the ZINIT message, so it is possible to + * correct or enhance the protocol, without breaking existing versions. + * The purpose of this section is to document these versions as they come out. + * Remember, this is the protocol version, not the source version. + * + * 0 Initial version. + * Zmodem controlled file transfer. This was more of a "plug Z + * into UUCP as is" port. + * + * 1 Complete rewrite. + * Made Z more of a transport protocol. UUCP now controls transfer and Z + * is on the same footing as the other UUCP protocols. + * Theoretically, there will be little pain when UUCP goes bidirectional. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char protz_rcsid[] = "$Id: protz.c,v 1.1 1993/08/04 19:36:25 jtc Exp $"; +#endif + +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +#define ZPROTOCOL_VERSION 1 + +/* + * Control message characters ... + */ + +#define ZPAD '*' /* Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZBIN 'A' /* Binary frame indicator */ +#define ZHEX 'B' /* HEX frame indicator */ + +/* + * Frame types (see array "frametypes" in zm.c) ... + * + * Note that the numbers here have been reorganized, as we don't support + * all of them (nor do we need to). + * + * WARNING: The init sequence assumes ZINIT < ZDATA < ZACK < ZINITEND. + */ + +#define ZINIT 0 /* Init (contains protocol version, flags) */ +#define ZDATA 1 /* Data packet(s) follow */ +#define ZRPOS 2 /* Resume data trans at this position */ +#define ZACK 3 /* ACK to above */ +#define ZNAK 4 /* Last packet was garbled */ +#define Zreserved 5 /* reserved (for future concerns) */ +#define ZINITEND 6 /* end of init sequence */ +#define ZFIN 7 /* Finish session */ + +/* + * ZDLE sequences ... + * + * Note addition of ZCRCF: "end of message". + */ + +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZCRCF 'l' /* CRC next, ZACK expected, end of message */ + +#define ZRUB0 'm' /* Translate to rubout 0177 */ +#define ZRUB1 'n' /* Translate to rubout 0377 */ + + +/* + * zdlread return values (internal) ... + * Other values are ZM_ERROR, ZM_TIMEOUT, ZM_RCDO. + */ + +#define GOTOR 0400 +#define GOTCRCE (ZCRCE | GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG | GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ | GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW | GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCRCF (ZCRCF | GOTOR) /* ZDLE-ZCRCF received */ + +/* + * Byte positions within header array ... + */ + +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 + +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of position */ + +/* + * Bit Masks for ZRQINIT flags byte ZF0 ... + */ + +#define TX_ESCCTL 1 /* Tx will escape control chars */ + +/* + * Possible errors when running ZMODEM ... + */ + +#define ZM_ERROR (-1) /* crc error, etc. */ +#define ZM_TIMEOUT (-2) +#define ZM_RCDO (-3) /* Carrier Lost */ + +/* + * ASCII characters ... + */ + +#define LF 012 +#define CR 015 +#define XON 021 +#define XOFF 023 + +#define XON_WAIT 10 /* seconds */ + +/* + * Packet sizes ... + * + * FIXME: CPACKETSIZE is hardcoded in a lot of places. + * It's not clear to me whether changing it's value would be a + * "good thing" or not. But of course that doesn't excuse the hardcoding. + */ + +#define CPACKETSIZE 1024 /* max packet size (data only) */ +#define CFRAMELEN 12 /* header size */ +#define CSUFFIXLEN 10 /* suffix at end of data packets */ +#define CEXCHANGE_INIT_RETRIES 4 + +/* The header CRC value. */ + +#if ANSI_C +#define IHDRCRC 0xDEBB20E3UL +#else +#define IHDRCRC ((unsigned long) 0xDEBB20E3L) +#endif + +/* packet buffer size */ +#define CPACKBUFSIZE (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/) + +/* + * Data types ... + */ + +typedef unsigned char achdrval_t[4]; +typedef unsigned long hdrval_t; +typedef unsigned long winpos_t; + +/* + * Configurable parms ... + * + * FIXME: isn't used yet. It may not be needed. + */ + +#define CTIMEOUT 10 +#define CRETRIES 10 +#define CSTARTUP_RETRIES 4 +#define CGARBAGE 2400 +#define CSEND_WINDOW 16384 +#define FESCAPE_CONTROL FALSE + +static int cZtimeout = CTIMEOUT; /* (seconds) */ +static int cZretries = CRETRIES; +static int cZstartup_retries = CSTARTUP_RETRIES; +static int cZmax_garbage = CGARBAGE; /* max garbage before header */ +static int cZtx_window = CSEND_WINDOW; /* our transmission window */ +static int cZrx_buf_len = 0; /* our reception buffer size */ +static boolean fZesc_ctl = FESCAPE_CONTROL; /* escape control chars */ + +struct uuconf_cmdtab asZproto_params[] = +{ + {"timeout", UUCONF_CMDTABTYPE_INT, (pointer) & cZtimeout, NULL}, + {"retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZretries, NULL}, + {"startup-retries", UUCONF_CMDTABTYPE_INT, + (pointer) & cZstartup_retries, NULL}, + {"garbage", UUCONF_CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL}, + {"send-window", UUCONF_CMDTABTYPE_INT, (pointer) & cZtx_window, NULL}, + {"escape-control", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl, + NULL}, + {NULL, 0, NULL, NULL} +}; + +/* + * Variables for statistic gathering ... + * + * We use to record the number of "packets" + * sent/received. Packets is in double quotes because some of them aren't full. + */ + +static unsigned long cZheaders_sent; +static unsigned long cZheaders_received; +static unsigned long cZbytes_resent; +static unsigned long cZtimeouts; +static unsigned long cZerrors; + +/* + * Data buffers ... + */ + +static char *zZtx_buf; /* transmit buffer */ + +static char *zZtx_packet_buf; /* raw outgoing packet data */ +static char *zZrx_packet_buf; /* raw incoming packet data */ + +/* + * Transmitter state variables ... + */ + +static unsigned cZblklen; /* data length in sent/received packets */ +static unsigned cZtxwspac; /* spacing between ZCRCQ requests */ +/*static unsigned cZblklen_override;*//* override value for */ +static unsigned cZtxwcnt; /* counter used to space ack requests */ +static unsigned cZrxwcnt; /* counter used to watch receiver's buf size */ +static winpos_t wpZtxstart; /* when message started */ +static winpos_t wpZtxpos; /* transmitter position */ +static winpos_t wpZlastsync; /* last offset to which we got a ZRPOS */ +static winpos_t wpZlrxpos; /* receiver's last reported offset */ +static winpos_t wpZrxpos; /* receiver file position */ + +static int iZlast_tx_data_packet; /* type of last ZDATA packet (ZCRCx) */ +static int iZjunk_count; /* amount of garbage characters received */ +static int iZtleft; /* for dynamic packet resizing */ + +static int iZbeenhereb4; /* times we've been ZRPOS'd to same place */ + +/* + * Receiver state variables ... + */ + +static winpos_t wpZrxbytes; /* receiver byte count */ +static int iZlast_rx_data_packet; /* last successfully received ZCRCx packet */ + +/* + * Misc. globals ... + */ + +static char xon = XON; + +#ifdef DJE_TESTING +int uucptest = -1; +int uucptest2; +int uucptestseed; +#endif + +/* + * Kludge!!! + * See fzfinish_tx(). Basically the next two globals are used to record the + * fact that we got a ZDATA, but aren't quite ready to process it. + */ + +static int iZpkt_rcvd_kludge; /* -1 if not valid */ +static hdrval_t hvZpkt_hdrval_kludge; + +/* + * Packet types ... + */ + +static const char *azZframe_types[] = { + "Carrier Lost", /* -3 */ + "Timeout", /* -2 */ + "Error", /* -1 */ +#define FTOFFSET 3 + "ZINIT", + "ZDATA", + "ZRPOS", + "ZACK", + "ZNAK", + "Zreserved", + "ZINITEND", + "ZFIN", + "UNKNOWN!!!" +}; +#define FTNUMBER (sizeof(azZframe_types) / sizeof(char *)) + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif +#define ZZHEADER_NAME(itype) \ + azZframe_types[min((itype) + FTOFFSET, FTNUMBER - 1)] + +/* + * Local functions ... + */ + +static boolean fzsend_data P((struct sdaemon *qdaemon, char *zdata, + size_t cdata, boolean fendofmessage)); +static boolean fzprocess P((struct sdaemon *qdaemon)); +static boolean fzstart_proto P((struct sdaemon *qdaemon)); +static int izexchange_init P((struct sdaemon *qdaemon, int send_type, + achdrval_t send_val, achdrval_t recv_val)); +static boolean fzshutdown_proto P((struct sdaemon *qdaemon)); +static boolean fzstart_tx P((void)); +static boolean fzfinish_tx P((struct sdaemon *qdaemon, long *plredo)); +static boolean fzstart_rx P((void)); +static boolean fzfinish_rx P((struct sdaemon *qdaemon)); +static boolean fzsend_hdr P((struct sdaemon *qdaemon, int ipkttype, + int ihdrtype, hdrval_t hdrval, + boolean fcheckreceive)); +static boolean fzsend_data_packet P((struct sdaemon *qdaemon, char *zdata, + size_t cdata, int frameend, + boolean fcheckreceive)); +static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype, + hdrval_t hdrval)); +static int czbuild_data_packet P((char *zresult, const char *zdata, + size_t cdata, int frameend)); +/* + * The rest of the functions do not follow Ian's naming style. I have left + * the names the same as the original zm source. Over time, they may change. + */ +static int izrecv_hdr P((struct sdaemon *qdaemon, achdrval_t hdr)); +static int zrbhdr32 P((struct sdaemon *qdaemon, achdrval_t hdr)); +static int zrhhdr P((struct sdaemon *qdaemon, achdrval_t hdr)); +static int zrdat32 P((struct sdaemon *qdaemon, char *buf, int length, + int *iprxcount)); +static int getinsync P((struct sdaemon *qdaemon, boolean flag)); +static char *zputhex P((char *p, int ch)); +static char *zputchar P((char *p, int ch)); +static int zgethex P((struct sdaemon *qdaemon)); +static int zdlread P((struct sdaemon *qdaemon)); +static int noxrd7 P((struct sdaemon *qdaemon)); +static int realreadchar P((struct sdaemon *qdaemon, int timeout)); +static boolean fzreceive_ready P((void)); +static void stohdr P((hdrval_t pos, achdrval_t hdr)); +static hdrval_t rclhdr P((achdrval_t hdr)); +static hdrval_t hvzencode_data_hdr P((winpos_t cbytes)); +static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes)); +static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos, + winpos_t lrxpos, winpos_t txpos)); + +/* + * This macro replaces readchar() because it achieves a noticable speed up. The + * readchar() function has been renamed realreadchar(). Thanks to Ian for + * running this stuff through a profiler to find this out. Ian suggests further + * speed ups may be obtained by doing a similar thing in zrdat32(). + */ + +/* Assign the next character to b. */ +#define READCHAR(qdaemon, b, i) \ + (iPrecstart != iPrecend \ + ? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \ + iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \ + : ((b) = realreadchar ((qdaemon), (i)))) + +/************************************************************************/ + + +/* + * Start the protocol ... + */ + +boolean +fzstart(qdaemon, pzlog) +struct sdaemon *qdaemon; +char **pzlog; +{ + *pzlog = zbufalc (sizeof "protocol 'a' starting: , , , , , " + 100); + sprintf (*pzlog, "protocol 'a' starting: %d, %d, %d, %d, %d, %d", + cZtimeout, cZretries, cZstartup_retries, + cZmax_garbage, cZtx_window, fZesc_ctl); + + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + + /* + * For now, we place tight restrictions on the size of the transmit + * window. This might be relaxed in the future. If it is relaxed, + * some of these tests will stay, some will go. That is why it is + * coded like it is. + */ + + if (cZtx_window % 1024 != 0 || + cZtx_window < 4096 || cZtx_window > 65536 || + 65536 % cZtx_window != 0 + ) { + ulog (LOG_ERROR, + "fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536"); + return FALSE; + } + + zZtx_buf = (char *) xmalloc (CPACKETSIZE); + zZtx_packet_buf = (char *) xmalloc (CPACKBUFSIZE); + zZrx_packet_buf = (char *) xmalloc (CPACKBUFSIZE); + + iZlast_tx_data_packet = -1; + iZlast_rx_data_packet = -1; + + wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0; + cZtxwspac = cZtx_window / 4; + + cZheaders_sent = cZheaders_received = cZbytes_resent = 0; + cZtimeouts = cZerrors = 0; + + iZpkt_rcvd_kludge = -1; + +#if 0 + /* + * We ensure is at least 4k, so the following is + * unnecessary. It can be put back in later if needed. + */ + if (cZblklen_override > cZtxwspac + || (!cZblklen_override && cZtxwspac < 1024)) + cZblklen_override = cZtxwspac; +#endif + +#ifdef DJE_TESTING + { + extern int uucptest,uucptest2,uucptestseed; + FILE *f; + + if (uucptest == -1) { + f = fopen ("/usr/local/src/bin/uucp/uucptest", "r"); + if (f != NULL) { + fscanf (f, "%d %d %d", + &uucptestseed, &uucptest, &uucptest2); + fclose (f); + } + srand (uucptestseed); + } + } +#endif + + /* + * Fire up the protocol (exchange init messages) ... + */ + + if (!fzstart_proto (qdaemon)) + return FALSE; + + return TRUE; +} + +/* + * Stop the protocol ... + */ + +boolean +fzshutdown(qdaemon) +struct sdaemon *qdaemon; +{ + (void) fzshutdown_proto (qdaemon); + + xfree ((pointer) zZtx_buf); + xfree ((pointer) zZtx_packet_buf); + xfree ((pointer) zZrx_packet_buf); + zZtx_buf = NULL; + zZtx_packet_buf = NULL; + zZrx_packet_buf = NULL; + + /* + * Print some informative statistics ... + * + * I use the word "messages" here instead of "headers" because the + * latter is jargonese. + */ + + ulog (LOG_NORMAL, + "Protocol 'a' messages: sent %lu, received %lu", + cZheaders_sent, cZheaders_received); + ulog (LOG_NORMAL, + "Protocol 'a' packets: sent %lu, received %lu", + wpZtxpos / 1024, wpZrxbytes / 1024); + if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0) + ulog (LOG_NORMAL, + "Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu", + cZbytes_resent, cZtimeouts, cZerrors); + + /* + * Reset all the parameters to their default values, so that the + * protocol parameters used for this connection do not affect the + * next one. + */ + + cZtimeout = CTIMEOUT; + cZretries = CRETRIES; + cZstartup_retries = CSTARTUP_RETRIES; + cZmax_garbage = CGARBAGE; + cZtx_window = CSEND_WINDOW; + fZesc_ctl = FESCAPE_CONTROL; + + cZheaders_sent = cZheaders_received = cZbytes_resent = 0; + cZtimeouts = cZerrors = 0; + + return TRUE; +} + +/* + * Send a command string ... + * We send everything up to and including the null byte. + * + * We assume the command will fit in the outgoing data buffer. + * FIXME: A valid assumption? + */ + +/*ARGSUSED*/ +boolean +fzsendcmd(qdaemon, z, ilocal, iremote) +struct sdaemon *qdaemon; +const char *z; +int ilocal; +int iremote; +{ + size_t n,clen; + long lredo; + char *zbuf; + + clen = strlen (z) + 1; + + DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsendcmd: sending command %s", z); + + if (!fzstart_tx ()) /* must be called before zzgetspace() */ + return FALSE; + + if ((zbuf = zzgetspace (qdaemon, &n)) == NULL) + return FALSE; + +#if DEBUG > 0 + if (clen > n) + ulog (LOG_FATAL, "fzsendcmd: clen > n"); +#endif + + strcpy (zbuf, z); + + /* + * Send it out ... + */ + + do { + if (!fzsend_data (qdaemon, zbuf, clen, TRUE)) + return FALSE; + if (!fzfinish_tx (qdaemon, &lredo)) + return FALSE; + } while (lredo >= 0); + + return fzprocess (qdaemon); +} + +/* + * Allocate a packet to send out ... + * + * Note that 'z' has dynamic packet resizing and that will range + * from 32 to 1024, in multiples of 2. + */ + +/*ARGSUSED*/ +char * +zzgetspace(qdaemon, pclen) +struct sdaemon *qdaemon; +size_t *pclen; +{ + *pclen = cZblklen; + return zZtx_buf; +} + +/* + * Send a block of data ... + * + * If (cdata == 0) then the end of the file has been reached. + */ + +/*ARGSUSED*/ +boolean +fzsenddata(qdaemon, zdata, cdata, ilocal, iremote, ipos) +struct sdaemon *qdaemon; +char *zdata; +size_t cdata; +int ilocal; +int iremote; +long ipos; +{ + DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsenddata: %d bytes", cdata); + + if (! fzsend_data (qdaemon, zdata, cdata, cdata == 0)) + return FALSE; + return fzprocess (qdaemon); +} + +/* + * Send a block of data (command or file) ... + */ + +/* This should buffer the data internally. Until it does, it needs to + be able to reset the file position when it is called. This is + really ugly. */ +extern struct stransfer *qTsend; + +static boolean +fzsend_data(qdaemon, zdata, cdata, fendofmessage) +struct sdaemon *qdaemon; +char *zdata; +size_t cdata; +boolean fendofmessage; +{ + size_t n; + + if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) { + cZtxwcnt = cZrxwcnt = 0; + iZjunk_count = 0; + if (!fzsend_hdr (qdaemon, ZBIN, ZDATA, + hvzencode_data_hdr (wpZtxpos), TRUE)) + return FALSE; + } + + n = cdata; + + if (fendofmessage) + iZlast_tx_data_packet = ZCRCF; + else if (iZjunk_count > 3) + iZlast_tx_data_packet = ZCRCW; + else if (wpZtxpos == wpZlastsync) + iZlast_tx_data_packet = ZCRCW; + else if (cZrx_buf_len && (cZrxwcnt += n) >= cZrx_buf_len) + iZlast_tx_data_packet = ZCRCW; + else if ((cZtxwcnt += n) >= cZtxwspac) { + iZlast_tx_data_packet = ZCRCQ; + cZtxwcnt = 0; + } else + iZlast_tx_data_packet = ZCRCG; + + if (++iZtleft > 3) { + iZtleft = 0; + if (cZblklen < 1024) + cZblklen *= 2; +#if 0 /* is currently unnecessary */ + if (cZblklen_override && cZblklen > cZblklen_override) + cZblklen = cZblklen_override; +#endif + if (cZblklen > 1024) + cZblklen = 1024; + if (cZrx_buf_len && cZblklen > cZrx_buf_len) + cZblklen = cZrx_buf_len; + } + +#if DEBUG > 1 + if (FDEBUGGING(DEBUG_PROTO)) { + const char *type; + + switch (iZlast_tx_data_packet) { + case ZCRCW: type = "ZCRCW"; break; + case ZCRCG: type = "ZCRCG"; break; + case ZCRCQ: type = "ZCRCQ"; break; + case ZCRCE: type = "ZCRCE"; break; + case ZCRCF: type = "ZCRCF"; break; + default : type = "UNKNOWN!!!"; break; + } + DEBUG_MESSAGE3 (DEBUG_PROTO, + "fzsend_data: %s, pos 0x%lx, %d bytes", + type, wpZtxpos, n); + } +#endif + + if (!fzsend_data_packet (qdaemon, zdata, n, iZlast_tx_data_packet, + TRUE)) + return FALSE; + + wpZtxpos += n; + + if (iZlast_tx_data_packet == ZCRCW) { + /* + * FIXME: Ideally this would be done in fzprocess. However, it + * is only called if there is data pending which there + * may not be yet. I could have patched fploop() a bit but + * for now, I've done it like this. + */ + switch (getinsync (qdaemon, FALSE)) { + case ZACK: + break; + case ZRPOS: + if (qTsend == NULL + || ! ffileisopen (qTsend->e)) { + ulog (LOG_ERROR, "Can't reset non-file"); + return FALSE; + } + iZlast_tx_data_packet = -1; /* trigger ZDATA */ + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fzsend_data: Seeking to %ld", + (long) (wpZrxpos - wpZtxstart)); + if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + return FALSE; + } + break; + default: + return FALSE; + } + return TRUE; + } + + /* + * If we've reached the maximum transmit window size, let the + * receiver catch up ... + * + * I use (cZtx_window - 2048) to play it safe. + */ + + while (wpZtxpos - wpZlrxpos >= cZtx_window - 2048) { + if (iZlast_tx_data_packet != ZCRCQ) { + if (!fzsend_data_packet (qdaemon, zdata, (size_t) 0, + iZlast_tx_data_packet = ZCRCQ, + TRUE)) + return FALSE; + } + /* + * FIXME: I'd rather not call ffileseek() in this file. When we + * start buffering the outgoing data, the following + * ffileseek() will disappear. + */ + switch (getinsync (qdaemon, TRUE)) { + case ZACK: + break; + case ZRPOS: + if (qTsend == NULL + || ! ffileisopen (qTsend->e)) { + ulog (LOG_ERROR, "Can't reset non-file"); + return FALSE; + } + iZlast_tx_data_packet = -1; /* trigger ZDATA */ + DEBUG_MESSAGE1 (DEBUG_PROTO, + "fzsend_data: Seeking to %ld", + (long) (wpZrxpos - wpZtxstart)); + if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + return FALSE; + } + break; + default: + return FALSE; + } + } + + return TRUE; +} + +/* + * Process existing data ... + */ + +static boolean +fzprocess(qdaemon) +struct sdaemon *qdaemon; +{ + int c,ch; + + while (fzreceive_ready ()) { + READCHAR (qdaemon, ch, 1); + switch (ch) { + case ZPAD: + /* see if we're detecting ZRPOS packets quickly */ + DEBUG_MESSAGE0 (DEBUG_PROTO, + "fzprocess: possible ZRPOS packet"); + /* We just ate the ZPAD char that getinsync + expects, so put it back. */ + iPrecstart = ((iPrecstart + CRECBUFLEN - 1) + % CRECBUFLEN); + c = getinsync (qdaemon, TRUE); + if (c == ZACK) + break; + /* FIXME: sz does a TCFLSH here */ +#if 0 /* FIXME: Not sure if this is needed, or where to put it. */ + /* ZCRCE - dinna wanna starta ping-pong game */ + if (!fzsend_data_packet (qdaemon, zZtx_packet_buf, + 0, ZCRCE, TRUE)) + return FALSE; +#endif + if (c == ZRPOS) { + if (qTsend == NULL + || ! ffileisopen (qTsend->e)) { + ulog (LOG_ERROR, + "Attempt to back up non-file"); + return FALSE; + } + if (! ffileseek (qTsend->e, + wpZrxpos - wpZtxstart)) { + ulog (LOG_ERROR, + "seek: %s", strerror (errno)); + return FALSE; + } + iZlast_tx_data_packet = -1; /* trigger ZDATA */ + break; /* not returning is intentional */ + } + return FALSE; + case XOFF: + case XOFF | 0200: + READCHAR (qdaemon, ch, XON_WAIT); + break; + case CR: + break; + default: + iZjunk_count++; + break; + } + } + + return TRUE; +} + +/* + * Wait for data to come in. + * + * This continues processing until a complete file or command has been + * received. + */ + +boolean +fzwait(qdaemon) +struct sdaemon *qdaemon; +{ + int c,cerr,rxcount; + boolean fexit; + achdrval_t rx_hdr; + + if (!fzstart_rx ()) + return FALSE; + + cerr = cZretries; + + goto nxthdr; + + for (;;) { + if (!fzsend_hdr (qdaemon, ZHEX, ZRPOS, + hvzencode_data_hdr (wpZrxbytes), FALSE)) + return FALSE; +nxthdr: + c = izrecv_hdr (qdaemon, rx_hdr); + + switch (c) { + case ZM_TIMEOUT: + case ZNAK: + if (--cerr < 0) { + ulog (LOG_ERROR, "fzwait: retries exhausted"); + return FALSE; + } + continue; + case ZM_ERROR: + if (--cerr < 0) { + ulog (LOG_ERROR, "fzwait: retries exhausted"); + return FALSE; + } + /*fport_break ();*/ + continue; + case ZM_RCDO: + case ZFIN: + return FALSE; + case ZRPOS: + case ZACK: + goto nxthdr; /* ignore, partner is out of sync */ + case ZDATA: { + winpos_t rx_bytes; + + zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fzwait: bytes(us,them) 0x%lx,0x%lx", + wpZrxbytes, rx_bytes); + if (rx_bytes != wpZrxbytes) { + if (--cerr < 0) { + ulog (LOG_ERROR, + "fzwait: retries exhausted"); + return FALSE; + } + (void) zrdat32 (qdaemon, zZrx_packet_buf, + 1024, &rxcount); + /*fport_break ();*/ + /* + * FIXME: Seems to me we should ignore this one + * and go for a timeout, the theory being + * that the appropriate ZRPOS has already + * been sent. We're obviously out of sync. + * /dje 92Mar10 + */ + continue; /* goto nxthdr? */ + } +moredata: + /* + * Do not call fgot_data() with (rxcount == 0) if it's + * not ZCRCF. fgot_data() will erroneously think this + * is the end of the message. + */ + c = zrdat32 (qdaemon, zZrx_packet_buf, 1024, + &rxcount); +#if DEBUG > 1 + if (FDEBUGGING(DEBUG_PROTO)) { + const char *msg; + + if (c < 0) { + msg = ZZHEADER_NAME(c); + } else { + switch (c) { + case GOTCRCW: msg = "ZCRCW"; break; + case GOTCRCG: msg = "ZCRCG"; break; + case GOTCRCQ: msg = "ZCRCQ"; break; + case GOTCRCE: msg = "ZCRCE"; break; + case GOTCRCF: msg = "ZCRCF"; break; + default : msg = NULL; break; + } + } + if (msg != NULL) + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fzwait: zrdat32: %s, %d bytes", + msg, rxcount); + else + DEBUG_MESSAGE2 (DEBUG_PROTO, + "fzwait: zrdat32: %d, %d bytes", + c, rxcount); + } +#endif + switch (c) { + case ZM_ERROR: /* CRC error */ + cZerrors++; + if (--cerr < 0) { + ulog (LOG_ERROR, + "fzwait: retries exhausted"); + return FALSE; + } + /*fport_break ();*/ + continue; + case ZM_TIMEOUT: + cZtimeouts++; + if (--cerr < 0) { + ulog (LOG_ERROR, + "fzwait: retries exhausted"); + return FALSE; + } + continue; + case ZM_RCDO: + return FALSE; + case GOTCRCW: + iZlast_rx_data_packet = ZCRCW; + cerr = cZretries; + if (rxcount != 0 + && !fgot_data (qdaemon, zZrx_packet_buf, + (size_t) rxcount, + (const char *) NULL, + (size_t) 0, + -1, -1, (long) -1, + TRUE, &fexit)) + return FALSE; + wpZrxbytes += rxcount; + if (!fzsend_hdr (qdaemon, ZHEX, ZACK, + hvzencode_data_hdr (wpZrxbytes), + FALSE)) + return FALSE; + if (! fsend_data (qdaemon->qconn, &xon, + (size_t) 1, FALSE)) + return FALSE; + goto nxthdr; + case GOTCRCQ: + iZlast_rx_data_packet = ZCRCQ; + cerr = cZretries; + if (rxcount != 0 + && !fgot_data (qdaemon, zZrx_packet_buf, + (size_t) rxcount, + (const char *) NULL, + (size_t) 0, + -1, -1, (long) -1, + TRUE, &fexit)) + return FALSE; + wpZrxbytes += rxcount; + if (!fzsend_hdr (qdaemon, ZHEX, ZACK, + hvzencode_data_hdr (wpZrxbytes), + FALSE)) + return FALSE; + goto moredata; + case GOTCRCG: + iZlast_rx_data_packet = ZCRCG; + cerr = cZretries; + if (rxcount != 0 + && !fgot_data (qdaemon, zZrx_packet_buf, + (size_t) rxcount, + (const char *) NULL, + (size_t) 0, + -1, -1, (long) -1, + TRUE, &fexit)) + return FALSE; + wpZrxbytes += rxcount; + goto moredata; + case GOTCRCE: + iZlast_rx_data_packet = ZCRCE; + cerr = cZretries; + if (rxcount != 0 + && !fgot_data (qdaemon, zZrx_packet_buf, + (size_t) rxcount, + (const char *) NULL, + (size_t) 0, + -1, -1, (long) -1, + TRUE, &fexit)) + return FALSE; + wpZrxbytes += rxcount; + goto nxthdr; + case GOTCRCF: + iZlast_rx_data_packet = ZCRCF; + /* + * fzfinish_rx() must be called before + * fgot_data() because fgot_data() will send + * out a UUCP-command but the sender won't be + * ready for it until it receives our final + * ZACK. + */ + cerr = cZretries; + wpZrxbytes += rxcount; + if (!fzfinish_rx (qdaemon)) + return FALSE; + if (!fgot_data (qdaemon, zZrx_packet_buf, + (size_t) rxcount, + (const char *) NULL, + (size_t) 0, -1, -1, + (long) -1, TRUE, &fexit)) + return FALSE; + /* + * FIXME: Examine ? + * Or maybe ensure it's TRUE? + */ + return TRUE; + } + return FALSE; + } + default: + ulog (LOG_FATAL, "fzwait: received header %s", + ZZHEADER_NAME(c)); + return FALSE; + } + } + + return TRUE; +} + +/* + * File level routine. Called when initiating/terminating file transfers. + * + * When starting to send a file: (TRUE, TRUE, cbytes) + * When starting to receive a file: (TRUE, FALSE, -1) + * When send EOF, check resend: (FALSE, TRUE, -1) + * When receive EOF, check re-receive: (FALSE, FALSE, -1) + */ + +boolean +fzfile(qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) +struct sdaemon *qdaemon; +struct stransfer *qtrans; +boolean fstart; +boolean fsend; +long cbytes; +boolean *pfhandled; +{ + long iredo; + + *pfhandled = FALSE; + + DEBUG_MESSAGE2 (DEBUG_PROTO, "fzfile: fstart=%d, fsend=%d", fstart, + fsend); + + if (fsend) { + if (fstart) + return fzstart_tx (); + if (! fzfinish_tx (qdaemon, &iredo)) + return FALSE; + if (iredo >= 0) { + if (! ffileisopen (qtrans->e)) { + ulog (LOG_ERROR, + "Attempt to back up non-file"); + return FALSE; + } + if (! ffileseek (qtrans->e, iredo)) { + ulog (LOG_ERROR, + "seek: %s", strerror (errno)); + return FALSE; + } + *pfhandled = TRUE; + qtrans->fsendfile = TRUE; + return fqueue_send (qdaemon, qtrans); + } + } + + return TRUE; +} + +/****************************************************************************/ + + +#if 0 /* not used, we only use 32 bit crc's */ +/* + * crctab calculated by Mark G. Mendel, Network Systems Corporation + */ + +static unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; +#endif /* crctab */ + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static unsigned long crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, + 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, + 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, + 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, + 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, + 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, + 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, + 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, + 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, + 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, + 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, + 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, + 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, + 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, + 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, + 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, + 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, + 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +/* + * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First argument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + +#define UPDC32(b, crc) \ + (crc_32_tab[((unsigned)(crc) ^ (unsigned)(b)) & 0xff] \ + ^ (((crc) >> 8) & 0x00ffffffL)) + +/****************************************************************************/ + +/* + * This section contains the guts of the Zmodem protocol. The intention + * is to leave as much of it alone as possible at the start. Overtime it + * will be cleaned up (EG: I'd like to clean up the naming of the globals). + * Also, Zmodem has a different coding style. Over time this will be converted + * to the Taylor UUCP coding style. + */ + +/* + * Start the protocol (exchange init packets) ... + * + * UUCP can transfer files in both directions in one session. Therefore the + * init sequence is a little different. + * + * 1) ZINIT packets are exchanged + * - contains protocol version and protocol flags + * 2) ZDATA packets are exchanged + * - is intended to contain various numeric and string information + * 3) ZACK packets are exchanged + * 4) ZINITEND packets are exchanged + */ + +static boolean +fzstart_proto(qdaemon) +struct sdaemon *qdaemon; +{ + int i; + achdrval_t tx_hdr,rx_hdr; + + for (i = 0; i < cZstartup_retries; i++) { + stohdr (0L, tx_hdr); + tx_hdr[ZF0] = ZPROTOCOL_VERSION; + if (fZesc_ctl) + tx_hdr[ZF1] |= TX_ESCCTL; + switch (izexchange_init (qdaemon, ZINIT, tx_hdr, rx_hdr)) { + case -1: return FALSE; + case 0: continue; + case 1: break; + } +#if 0 /* can't work, but kept for documentation */ + if (rx_hdr[ZF0] == 0) { + ulog (LOG_ERROR, "Old protocol version, init failed"); + return FALSE; + } +#endif + fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0; + + stohdr (0L, tx_hdr); + switch (izexchange_init (qdaemon, ZDATA, tx_hdr, rx_hdr)) { + case -1: return FALSE; + case 0: continue; + case 1: break; + } + + stohdr (0L, tx_hdr); + switch (izexchange_init (qdaemon, ZACK, tx_hdr, rx_hdr)) { + case -1: return FALSE; + case 0: continue; + case 1: break; + } + + stohdr (0L, tx_hdr); + switch (izexchange_init (qdaemon, ZINITEND, tx_hdr, rx_hdr)) { + case -1: return FALSE; + case 0: continue; + case 1: break; + } + + DEBUG_MESSAGE0 (DEBUG_PROTO, + "fzstart_proto: Protocol started"); + return TRUE; + + /* FIXME: see protg.c regarding sequencing here. */ + } + + ulog (LOG_ERROR, "Protocol init failed"); + return FALSE; +} + +/* + * Exchange init messages. This is based on 'g'. + * See the comments concerning fgexchange_init() in protg.c. + * + * We return 1 for success, 0 for restart, -1 for comm failure (terminate). + */ + +static int +izexchange_init(qdaemon, send_type, send_val, recv_val) +struct sdaemon *qdaemon; +int send_type; +achdrval_t send_val; +achdrval_t recv_val; +{ + int i,recv_type,count; + + for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) { + if (!fzsend_hdr (qdaemon, send_type == ZDATA ? ZBIN : ZHEX, + send_type, rclhdr (send_val), FALSE)) + return -1; + + /* + * The ZDATA packet is intended to contain the string + * (eventually, if it's ever usable) and allow for anything + * else that will need to be thrown in. + */ + + if (send_type == ZDATA) { + count = czbuild_data_packet (zZtx_packet_buf, "", + (size_t) 1, ZCRCF); + if (!fsend_data (qdaemon->qconn, zZtx_packet_buf, + (size_t) count, FALSE)) + return -1; + } + + recv_type = izrecv_hdr (qdaemon, recv_val); + + switch (recv_type) { + case ZM_TIMEOUT: + case ZM_ERROR: + continue; + case ZM_RCDO: + case ZFIN: + return -1; + case ZINIT: + case ZACK: + case ZINITEND: + break; + case ZDATA: + if (zrdat32 (qdaemon, zZrx_packet_buf, 1024, &count) + == GOTCRCF) + break; + continue; + default: + continue; + } + + if (recv_type == send_type) + return 1; + + /* + * If the other side is farther along than we are, we have lost + * a packet. Fall immediately back to ZINIT (but don't fail + * if we are already doing ZINIT, since that would count + * against cStart_retries more than it should). + * + * FIXME: The ">" test is "<" in protg.c. Check who's right. + */ + + if (recv_type > send_type && send_type != ZINIT) + return 0; + + /* + * If we are sending ZINITEND and we receive an ZINIT, the + * other side has falled back (we know this because we have + * seen a ZINIT from them). Fall back ourselves to start + * the whole handshake over again. + */ + + if (recv_type == ZINIT && send_type == ZINITEND) + return 0; + } + + return 0; +} + +/* + * Shut down the protocol ... + */ + +static boolean +fzshutdown_proto(qdaemon) +struct sdaemon *qdaemon; +{ + (void) fzsend_hdr (qdaemon, ZHEX, ZFIN, 0L, FALSE); + return TRUE; +} + +/* + * Reset the transmitter side for sending a new message ... + */ + +static boolean +fzstart_tx() +{ + iZlast_tx_data_packet = -1; + + /* + * is set to -1L to suppress ZCRCW request otherwise + * triggered by (wpZlastsync == wpZtxpos). + */ + + cZblklen = 1024; + wpZlastsync = -1L; + iZbeenhereb4 = 0; + iZtleft = 0; + iZjunk_count = 0; + + wpZtxpos = (wpZtxpos + 1024L) & ~1023L; /* next packet boundary */ + wpZlrxpos = wpZrxpos = wpZtxpos; + + wpZtxstart = wpZtxpos; /* so we can compute the "file offset" */ + + return TRUE; +} + +/* + * Finish the sending of a message ... + * + * Basically, we wait for some indication that the receiver received our last + * message. If the receiver tells us to restart from some point, we set + * *plredo to that point. + * + * FIXME: This function is a major kludge at the moment. It is taken from + * getinsync(). It is necessary because I don't yet buffer outgoing data. + * It will go away when we do (buffer outgoing data). + */ + +static boolean +fzfinish_tx(qdaemon, plredo) +struct sdaemon *qdaemon; +long *plredo; +{ + int c,cerr,ctimeouts; + achdrval_t rx_hdr; + winpos_t rx_bytes; + + *plredo = -1; + cerr = cZretries; + ctimeouts = 0; + + DEBUG_MESSAGE4 (DEBUG_PROTO, + "fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx", + wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes); + + for (;;) { + c = izrecv_hdr (qdaemon, rx_hdr); + + switch (c) { + case ZRPOS: + wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, + wpZlrxpos, wpZtxpos); + /* + * If the receiver sends a ZRPOS for the 1k block after + * the one we're currently at, we lost the final ZACK. + * We cheat and ignore this ZRPOS. Remember: the theory + * is that this entire function will go away when we + * begin buffering the outgoing data. Of course, one + * can reword the protocol definition and say this + * isn't cheating at all. + */ + if (((wpZtxpos + 1024) & ~1023) == wpZrxpos) + return TRUE; + cZbytes_resent += wpZtxpos - wpZrxpos; + wpZlrxpos = wpZtxpos = wpZrxpos; + if (wpZlastsync == wpZrxpos) { + if (++iZbeenhereb4 > 4) + if (cZblklen > 32) + cZblklen /= 2; + /* FIXME: shouldn't we reset iZbeenhereb4? */ + } + wpZlastsync = wpZrxpos; + iZlast_tx_data_packet = ZCRCW; /* force a timeout */ + *plredo = wpZrxpos - wpZtxstart; + return TRUE; + case ZACK: + wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, + wpZlrxpos, wpZtxpos); + wpZlrxpos = wpZrxpos; + if (wpZtxpos == wpZrxpos) /* the ACK we want? */ + return TRUE; + break; + case ZDATA: + /* + * We cheat here and take advantage of UUCP's current + * half duplex nature. If we get a ZDATA starting on + * the next 1k boundary, we lost the ZACK. We cheat and + * tuck it away so that izrecv_hdr() can later detect + * it. Remember: see above. + */ + zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); + if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) { + iZpkt_rcvd_kludge = ZDATA; + hvZpkt_hdrval_kludge = rclhdr (rx_hdr); + return TRUE; + } + break; /* ignore, out of sync (old) */ + case ZNAK: + /* + * We cheat here and take advantage of UUCP's current + * half duplex nature. If we get a ZNAK starting on + * the next 1k boundary, we lost the ZACK. We cheat and + * throw the ZNAK away. Remember: see above. + * + * On the other hand, if (rx_bytes == wpZrxbytes) then + * the other side is also in fzfinish_tx(). He must + * have lost our ZACK, so we send him another. + */ + zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); + if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) + return TRUE; + if (rx_bytes == wpZrxbytes) { + if (!fzsend_hdr (qdaemon, ZHEX, ZACK, + hvzencode_data_hdr (wpZrxbytes), + TRUE)) + return FALSE; + } + break; /* ignore, out of sync (old) */ + case ZFIN: + case ZM_RCDO: + return FALSE; + case ZM_TIMEOUT: + if (--cerr < 0) { + ulog (LOG_ERROR, + "fzfinish_tx: retries exhausted"); + return FALSE; + } + /* + * Normally the sender doesn't send NAK's for timeouts. + * We have to here because of the following scenario: + * + * - We send ZDATA/ZCRCF + * - They send ZACK (corrupted) + * - They send ZDATA/ZCRCF (corrupted) + * + * At this point, both sides are in fzfinish_tx(). + * We only send ZNAK every second timeout to increase + * our timeout delay vs. our partner. This tries to + * avoid ZRPOS and ZNAK "passing in transit". + */ + if (++ctimeouts % 2 == 0) + if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, + hvzencode_data_hdr (wpZtxpos), + TRUE)) + return FALSE; + break; + case ZM_ERROR: + default: + if (--cerr < 0) { + ulog (LOG_ERROR, + "fzfinish_tx: retries exhausted"); + return FALSE; + } + if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, + hvzencode_data_hdr (wpZtxpos), + TRUE)) + return FALSE; + break; + } + } +} + +/* + * Initialize the receiver ... + */ + +static boolean +fzstart_rx() +{ + wpZrxbytes = (wpZrxbytes + 1024L) & ~1023L; /* next packet boundary */ + + return TRUE; +} + +/* + * Terminate the receiver ... + * + * Acknowledge the last packet received. + */ + +static boolean +fzfinish_rx(qdaemon) +struct sdaemon *qdaemon; +{ + DEBUG_MESSAGE0 (DEBUG_PROTO, "fzfinish_rx: message/file received"); + + return fzsend_hdr (qdaemon, ZHEX, ZACK, + hvzencode_data_hdr (wpZrxbytes), FALSE); +} + +/* + * Send a Zmodem header to our partner ... + */ + +static boolean +fzsend_hdr(qdaemon, ipkttype, ihdrtype, hdrval, fcheckreceive) +struct sdaemon *qdaemon; +int ipkttype; +int ihdrtype; +hdrval_t hdrval; +boolean fcheckreceive; +{ + int cpacketlen; + + DEBUG_MESSAGE2 (DEBUG_PROTO, "fzsend_hdr: %s, data = 0x%lx", + ZZHEADER_NAME(ihdrtype), hdrval); + + cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype, + ihdrtype, hdrval); + +#ifdef DJE_TESTING +#if 0 + if (ihdrtype == ZACK && rand () % 100 < uucptest2) { + cZheaders_sent++; + return TRUE; + } +#else + if (ihdrtype == ZACK || ihdrtype == ZDATA) { + boolean fresult; + int old; + extern int uucptest,uucptest2; + + old = uucptest; + uucptest = uucptest2; + cZheaders_sent++; + fresult = fsend_data (qdaemon->qconn, zZtx_packet_buf, + (size_t) cpacketlen, fcheckreceive); + uucptest = old; + return fresult; + } +#endif +#endif + cZheaders_sent++; + return fsend_data (qdaemon->qconn, zZtx_packet_buf, + (size_t) cpacketlen, fcheckreceive); +} + +/* + * Send a data packet to our partner ... + * is one of ZCRCx. + */ + +static boolean +fzsend_data_packet(qdaemon, zdata, cdata, frameend, fcheckreceive) +struct sdaemon *qdaemon; +char *zdata; +size_t cdata; +int frameend; +boolean fcheckreceive; +{ + int cpacketlen; + + cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata, + frameend); + + return fsend_data (qdaemon->qconn, zZtx_packet_buf, + (size_t) cpacketlen, fcheckreceive); +} + +/* + * Build Zmodem headers ... + * + * Note that we use 32 bit CRC's for ZHEX headers. + * + * This function is a combination of zm fns: zsbhdr(), zsbh32(), and zshhdr(). + */ + +static int +czbuild_header(zresult, ipkttype, ihdrtype, hdrval) +char *zresult; +int ipkttype; +int ihdrtype; +hdrval_t hdrval; +{ + char *p; + int i; + unsigned long crc; + achdrval_t achdrval; + + p = zresult; + + switch (ipkttype) { + case ZBIN: + *p++ = ZPAD; + *p++ = ZDLE; + *p++ = ZBIN; + p = zputchar (p, ihdrtype); + crc = ICRCINIT; + crc = UPDC32 (ihdrtype, crc); + stohdr (hdrval, achdrval); + for (i = 0; i < 4; i++) { + p = zputchar (p, achdrval[i]); + crc = UPDC32 (achdrval[i], crc); + } + crc = ~crc; + for (i = 0; i < 4; i++) { + p = zputchar (p, (char) crc); + crc >>= 8; + } + break; + case ZHEX: /* build hex header */ + *p++ = ZPAD; + *p++ = ZPAD; + *p++ = ZDLE; + *p++ = ZHEX; + p = zputhex (p, ihdrtype); + crc = ICRCINIT; + crc = UPDC32 (ihdrtype, crc); + stohdr (hdrval, achdrval); + for (i = 0; i < 4; i++) { + p = zputhex (p, achdrval[i]); + crc = UPDC32 (achdrval[i], crc); + } + crc = ~crc; + for (i = 0; i < 4; i++) { + p = zputhex (p, (char) crc); + crc >>= 8; + } + *p++ = CR; + /* + * Uncork the remote in case a fake XOFF has stopped data flow. + */ + if (ihdrtype != ZFIN && ihdrtype != ZACK) /* FIXME: why? */ + *p++ = XON; + break; + default: + ulog (LOG_FATAL, "czbuild_header: ipkttype == %d", ipkttype); + break; + } + + return p - zresult; +} + +/* + * Build Zmodem data packets ... + * + * This function is zsdata() and zsda32() from the zm source. + */ + +static int +czbuild_data_packet(zresult, zdata, cdata, frameend) +char *zresult; +const char *zdata; +size_t cdata; +int frameend; +{ + char *p; + unsigned long crc; + + p = zresult; + + crc = ICRCINIT; + for ( ; cdata-- != 0; zdata++) { + char c; + + c = *zdata; + if (c & 0140) + *p++ = c; + else + p = zputchar (p, c); + crc = UPDC32 ((unsigned char) c, crc); + } + *p++ = ZDLE; + *p++ = frameend; + crc = UPDC32 (frameend, crc); + crc = ~crc; + for (cdata = 0; cdata < 4; cdata++) { + p = zputchar (p, (char) crc); + crc >>= 8; + } + if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) { + *p++ = CR; + *p++ = XON; + } + + return p - zresult; +} + +/* + * Read in a header ... + * + * This is function zgethdr() from the Zmodem source. + */ + +static int +izrecv_hdr(qdaemon, hdr) +struct sdaemon *qdaemon; +achdrval_t hdr; +{ + int c,cerr; + + /* + * Kludge alert! If another part of the program received a packet but + * wasn't ready to handle it, it is tucked away for us to handle now. + */ + + if (iZpkt_rcvd_kludge != -1) { + c = iZpkt_rcvd_kludge; + iZpkt_rcvd_kludge = -1; + stohdr (hvZpkt_hdrval_kludge, hdr); + DEBUG_MESSAGE2 (DEBUG_PROTO, + "izrecv_hdr: queued %s, data = 0x%lx", + ZZHEADER_NAME(c), rclhdr (hdr)); + cZheaders_received++; + return c; + } + + cerr = cZmax_garbage; /* Max bytes before start of frame */ + +again: + switch (c = noxrd7 (qdaemon)) { + case ZM_TIMEOUT: + case ZM_ERROR: + case ZM_RCDO: + goto fifi; + case ZPAD: /* This is what we want */ + break; + case CR: /* padding at end of previous header */ + default: + if (--cerr < 0) { + c = ZM_ERROR; + goto fifi; + } + goto again; + } + +splat: + switch (c = noxrd7 (qdaemon)) { + case ZPAD: + if (--cerr < 0) { + c = ZM_ERROR; + goto fifi; + } + goto splat; + case ZM_TIMEOUT: + case ZM_RCDO: + goto fifi; + case ZDLE: /* This is what we want */ + break; + default: + if (--cerr < 0) { + c = ZM_ERROR; + goto fifi; + } + goto again; + } + + switch (c = noxrd7 (qdaemon)) { + case ZM_TIMEOUT: + case ZM_RCDO: + goto fifi; + case ZBIN: + c = zrbhdr32 (qdaemon, hdr); + break; + case ZHEX: + c = zrhhdr (qdaemon, hdr); + break; + default: + if (--cerr < 0) { + c = ZM_ERROR; + goto fifi; + } + goto again; + } + +fifi: + switch (c) { + case ZM_TIMEOUT: + cZtimeouts++; + break; + case ZM_ERROR: + cZerrors++; + break; + case ZM_RCDO: + break; + default: + cZheaders_received++; + break; + } + DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%x", + ZZHEADER_NAME(c), rclhdr (hdr)); + + return c; +} + +/* + * Receive a binary style header (type and position) with 32 bit FCS ... + */ + +static int +zrbhdr32(qdaemon, hdr) +struct sdaemon *qdaemon; +achdrval_t hdr; +{ + int c,i,type; + unsigned long crc; + + if ((c = zdlread (qdaemon)) & ~0377) + return c; + type = c; + crc = ICRCINIT; + crc = UPDC32 (c, crc); + + for (i = 0; i < 4; i++) { + if ((c = zdlread (qdaemon)) & ~0377) + return c; + crc = UPDC32 (c, crc); + hdr[i] = (char) c; + } + for (i = 0; i < 4; i++) { + if ((c = zdlread (qdaemon)) & ~0377) + return c; + crc = UPDC32 (c, crc); + } + if (crc != IHDRCRC) + return ZM_ERROR; + + return type; +} + +/* + * Receive a hex style header (type and position) ... + */ + +static int +zrhhdr(qdaemon, hdr) +struct sdaemon *qdaemon; +achdrval_t hdr; +{ + int c,i,type; + unsigned long crc; + + if ((c = zgethex (qdaemon)) < 0) + return c; + type = c; + crc = ICRCINIT; + crc = UPDC32 (c, crc); + + for (i = 0; i < 4; i++) { + if ((c = zgethex (qdaemon)) < 0) + return c; + crc = UPDC32 (c, crc); + hdr[i] = (char) c; + } + for (i = 0; i < 4; i++) { + if ((c = zgethex (qdaemon)) < 0) + return c; + crc = UPDC32 (c, crc); + } + if (crc != IHDRCRC) + return ZM_ERROR; + + return type; +} + +/* + * Receive a data packet ... + */ + +static int +zrdat32(qdaemon, buf, length, iprxcount) +struct sdaemon *qdaemon; +char *buf; +int length; +int *iprxcount; +{ + int c,d; + unsigned long crc; + char *end; + + crc = ICRCINIT; + *iprxcount = 0; + end = buf + length; + while (buf <= end) { + if ((c = zdlread (qdaemon)) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + case GOTCRCF: + d = c; + c &= 0377; + crc = UPDC32 (c, crc); + if ((c = zdlread (qdaemon)) & ~0377) + goto crcfoo; + crc = UPDC32 (c, crc); + if ((c = zdlread (qdaemon)) & ~0377) + goto crcfoo; + crc = UPDC32 (c, crc); + if ((c = zdlread (qdaemon)) & ~0377) + goto crcfoo; + crc = UPDC32 (c, crc); + if ((c = zdlread (qdaemon)) & ~0377) + goto crcfoo; + crc = UPDC32 (c, crc); + if (crc != IHDRCRC) + return ZM_ERROR; + *iprxcount = length - (end - buf); + return d; + case ZM_TIMEOUT: + case ZM_RCDO: + return c; + default: + return ZM_ERROR; + } + } + *buf++ = (char) c; + crc = UPDC32 (c, crc); + } + + return ZM_ERROR; /* bad packet, too long */ +} + +/* + * Respond to receiver's complaint, get back in sync with receiver ... + */ + +static int +getinsync(qdaemon, flag) +struct sdaemon *qdaemon; +boolean flag; +{ + int c,cerr; + achdrval_t rx_hdr; + + cerr = cZretries; + + for (;;) { + c = izrecv_hdr (qdaemon, rx_hdr); + + switch (c) { + case ZRPOS: + wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, + wpZlrxpos, wpZtxpos); + cZbytes_resent += wpZtxpos - wpZrxpos; + wpZlrxpos = wpZtxpos = wpZrxpos; + if (wpZlastsync == wpZrxpos) { + if (++iZbeenhereb4 > 4) + if (cZblklen > 32) + cZblklen /= 2; + /* FIXME: shouldn't we reset iZbeenhereb4? */ + } + wpZlastsync = wpZrxpos; + return ZRPOS; + case ZACK: + wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, + wpZlrxpos, wpZtxpos); + wpZlrxpos = wpZrxpos; + if (flag || wpZtxpos == wpZrxpos) + return ZACK; + break; + case ZNAK: { + winpos_t rx_bytes; + /* + * Our partner is in fzfinish_tx() and is waiting + * for ZACK ... + */ + zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); + if (rx_bytes == wpZrxbytes) { + if (!fzsend_hdr (qdaemon, ZHEX, ZACK, + hvzencode_data_hdr (wpZrxbytes), + TRUE)) + return FALSE; + } + break; + } + case ZFIN: + case ZM_RCDO: + return c; + case ZM_TIMEOUT: + if (--cerr < 0) { + ulog (LOG_ERROR, + "getinsync: retries exhausted"); + return ZM_ERROR; + } + break; /* sender doesn't send ZNAK for timeout */ + case ZM_ERROR: + default: + if (--cerr < 0) { + ulog (LOG_ERROR, + "getinsync: retries exhausted"); + return ZM_ERROR; + } + if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, + hvzencode_data_hdr (wpZtxpos), + TRUE)) + return ZM_ERROR; + break; + } + } +} + +/* + * Send a byte as two hex digits ... + */ + +static char * +zputhex(p, ch) +char *p; +int ch; +{ + static char digits[] = "0123456789abcdef"; + + *p++ = digits[(ch & 0xF0) >> 4]; + *p++ = digits[ch & 0xF]; + return p; +} + +/* + * Send character c with ZMODEM escape sequence encoding ... + * + * Escape XON, XOFF. + * FIXME: Escape CR following @ (Telenet net escape) ... disabled for now + * Will need to put back references to . + */ + +static char * +zputchar(p, ch) +char *p; +int ch; +{ + char c = ch; + + /* Quick check for non control characters */ + + if (c & 0140) { + *p++ = c; + } else { + switch (c & 0377) { + case ZDLE: + *p++ = ZDLE; + *p++ = c ^ 0100; + break; + case CR: +#if 0 + if (!fZesc_ctl && (lastsent & 0177) != '@') + goto sendit; +#endif + /* fall through */ + case 020: /* ^P */ + case XON: + case XOFF: + *p++ = ZDLE; + c ^= 0100; +/*sendit:*/ + *p++ = c; + break; + default: + if (fZesc_ctl && !(c & 0140)) { + *p++ = ZDLE; + c ^= 0100; + } + *p++ = c; + break; + } + } + + return p; +} + +/* + * Decode two lower case hex digits into an 8 bit byte value ... + */ + +static int +zgethex(qdaemon) +struct sdaemon *qdaemon; +{ + int c,n; + + if ((c = noxrd7 (qdaemon)) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return ZM_ERROR; + if ((c = noxrd7 (qdaemon)) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return ZM_ERROR; + c += (n << 4); + + return c; +} + +/* + * Read a byte, checking for ZMODEM escape encoding ... + */ + +static int +zdlread(qdaemon) +struct sdaemon *qdaemon; +{ + int c; + +again: + READCHAR (qdaemon, c, cZtimeout); + if (c < 0) + return c; + if (c & 0140) /* quick check for non control characters */ + return c; + switch (c) { + case ZDLE: + break; + case XON: + goto again; + case XOFF: + READCHAR (qdaemon, c, XON_WAIT); + goto again; + default: + if (fZesc_ctl && !(c & 0140)) + goto again; + return c; + } + +again2: + READCHAR (qdaemon, c, cZtimeout); + if (c < 0) + return c; + switch (c) { + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + case ZCRCF: + return c | GOTOR; + case ZRUB0: /* FIXME: This is never generated. */ + return 0177; + case ZRUB1: /* FIXME: This is never generated. */ + return 0377; + case XON: + goto again2; + case XOFF: + READCHAR (qdaemon, c, XON_WAIT); + goto again2; + default: + if (fZesc_ctl && !(c & 0140)) + goto again2; /* FIXME: why again2? */ + if ((c & 0140) == 0100) + return c ^ 0100; + break; + } + + return ZM_ERROR; +} + +/* + * Read a character from the modem line with timeout ... + * Eat parity bit, XON and XOFF characters. + */ + +static int +noxrd7(qdaemon) +struct sdaemon *qdaemon; +{ + int c; + + for (;;) { + READCHAR (qdaemon, c, cZtimeout); + if (c < 0) + return c; + switch (c &= 0177) { + case XON: + continue; + case XOFF: + READCHAR (qdaemon, c, XON_WAIT); + continue; + case CR: + case ZDLE: + return c; + default: + if (fZesc_ctl && !(c & 0140)) + continue; + return c; + } + } +} + +/* + * Read a character from the receive buffer, or from the line if empty ... + * + * is in seconds (maybe make it tenths of seconds like in Zmodem?) + */ + +static int +realreadchar(qdaemon, timeout) +struct sdaemon *qdaemon; +int timeout; +{ + int c; + + if ((c = breceive_char (qdaemon->qconn, timeout, TRUE)) >= 0) + return c; + + switch (c) { + case -1: + return ZM_TIMEOUT; + case -2: + return ZM_RCDO; + } + + ulog (LOG_FATAL, "realreadchar: breceive_char() returned %d", c); + return ZM_ERROR; +} + + +/* + * Check if the receive channel has any characters in it. + * + * At present we can only test the receive buffer. No mechanism is available + * to go to the hardware. This should not be a problem though, as long as all + * appropriate calls to fsend_data() set to TRUE. + */ + +static boolean +fzreceive_ready() +{ + return iPrecstart != iPrecend; +} + +/* + * Store integer value in an achdrval_t ... + */ + +static void +stohdr(val, hdr) +hdrval_t val; +achdrval_t hdr; +{ + hdr[ZP0] = (char) val; + hdr[ZP1] = (char) (val >> 8); + hdr[ZP2] = (char) (val >> 16); + hdr[ZP3] = (char) (val >> 24); +} + +/* + * Recover an integer from a header ... + */ + +static hdrval_t +rclhdr(hdr) +achdrval_t hdr; +{ + hdrval_t v; + + v = hdr[ZP3] & 0377; + v = (v << 8) | (hdr[ZP2] & 0377); + v = (v << 8) | (hdr[ZP1] & 0377); + v = (v << 8) | (hdr[ZP0] & 0377); + + return v; +} + +/* + * Encode a from the byte count ... + * + * We use to store the byte count / 32 and a message sequence number which + * made this function very useful. Don't remove it. + * FIXME: Well, maybe remove it later. + */ + +static hdrval_t +hvzencode_data_hdr(cbytes) +winpos_t cbytes; +{ + return (hdrval_t) cbytes; +} + +/* + * Decode a into a byte count ... + * + * We use to store the byte count / 32 and a message sequence number which + * made this function very useful. Don't remove it. + * FIXME: Well, maybe remove it later. + */ + +static void +zdecode_data_hdr(hdrval, pcbytes) +hdrval_t hdrval; +winpos_t *pcbytes; +{ + *pcbytes = hdrval; +} + +/* + * Update from the received data header value ... + * + * FIXME: Here is where we'd handle wrapping around at 4 gigabytes. + */ + +static winpos_t +lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos) +achdrval_t rx_hdr; +winpos_t rxpos,lrxpos,txpos; +{ + winpos_t rx_pktpos; + + zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos); + + DEBUG_MESSAGE4 (DEBUG_PROTO, + "lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx", + rx_pktpos, rxpos, lrxpos, txpos); + + /* + * Check if valid. It could be old. + */ + + if (rx_pktpos < wpZlrxpos + || rx_pktpos > ((wpZtxpos + 1024L) & ~1023L)) + return rxpos; + + return rx_pktpos; +} diff --git a/gnu/libexec/uucp/uucico/rec.c b/gnu/libexec/uucp/uucico/rec.c new file mode 100644 index 0000000000..160aab705a --- /dev/null +++ b/gnu/libexec/uucp/uucico/rec.c @@ -0,0 +1,1162 @@ +/* rec.c + Routines to receive 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" + +#if USE_RCS_ID +const char rec_rcsid[] = "$Id: rec.c,v 1.1 1993/08/04 19:36:28 jtc Exp $"; +#endif + +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "prot.h" +#include "trans.h" + +/* If the other side does not tell us the size of a file it wants to + send us, we assume it is this long. This is only used for free + space checking. */ +#define CASSUMED_FILE_SIZE (10240) + +/* We keep this information in the pinfo field of the stransfer + structure. */ +struct srecinfo +{ + /* Local user to send mail to (may be NULL). */ + char *zmail; + /* Full file name. */ + char *zfile; + /* Temporary file name. */ + char *ztemp; + /* TRUE if this is a spool directory file. */ + boolean fspool; + /* TRUE if this was a local request. */ + boolean flocal; + /* TRUE if the file has been completely received. */ + boolean freceived; + /* TRUE if remote request has been replied to. */ + boolean freplied; + /* TRUE if we moved the file to the final destination. */ + boolean fmoved; +}; + +/* This structure is kept in the pinfo field if we are refusing a + remote request. */ +struct srecfailinfo +{ + /* Reason for refusal. */ + enum tfailure twhy; + /* TRUE if we have sent the reason for refusal. */ + boolean fsent; + /* TRUE if we have seen the end of the file. */ + boolean freceived; +}; + +/* Local functions. */ + +static void urrec_free P((struct stransfer *qtrans)); +static boolean flocal_rec_fail P((struct stransfer *qtrans, + struct scmd *qcmd, + const struct uuconf_system *qsys, + const char *zwhy)); +static boolean flocal_rec_send_request P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean flocal_rec_await_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, + size_t cdata)); +static boolean fremote_send_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fremote_send_fail P((struct sdaemon *qdaemon, + struct scmd *qcmd, + enum tfailure twhy, + int iremote)); +static boolean fremote_send_fail_send P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fremote_discard P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean frec_file_end P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean frec_file_send_confirm P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); + +/* Free up a receive stransfer structure. */ + +static void +urrec_free (qtrans) + struct stransfer *qtrans; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + + if (qinfo != NULL) + { + ubuffree (qinfo->zmail); + ubuffree (qinfo->zfile); + ubuffree (qinfo->ztemp); + xfree (qtrans->pinfo); + } + + utransfree (qtrans); +} + +/* Set up a request for a file from the remote system. This may be + called before the remote system has been called. + + This is the order of function calls: + + flocal_rec_file_init --> fqueue_local + flocal_rec_send_request (send R ...) --> fqueue_receive + flocal_rec_await_reply (open file, call pffile) --> fqueue_receive + receive file + frec_file_end (close and move file, call pffile) --> fqueue_send + frec_file_send_confirm (send CY) + */ + +boolean +flocal_rec_file_init (qdaemon, qcmd) + struct sdaemon *qdaemon; + struct scmd *qcmd; +{ + const struct uuconf_system *qsys; + boolean fspool; + char *zfile; + struct srecinfo *qinfo; + struct stransfer *qtrans; + + qsys = qdaemon->qsys; + + /* Make sure we are permitted to transfer files. */ + if (qdaemon->fcaller + ? ! qsys->uuconf_fcall_transfer + : ! qsys->uuconf_fcalled_transfer) + { + /* This case will have been checked by uucp or uux, but it could + have changed. */ + if (! qsys->uuconf_fcall_transfer + && ! qsys->uuconf_fcalled_transfer) + return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, + "not permitted to request files"); + return TRUE; + } + + fspool = fspool_file (qcmd->zto); + + if (fspool) + { + pointer puuconf; + int iuuconf; + const char *zlocalname; + struct uuconf_system slocalsys; + + /* Normal users are not allowed to request files to be received + into the spool directory. To support uux forwarding, we use + the special option '9'. This permits a file to be received + into the spool directory for the local system only without + the usual checking. This is only done for local requests, of + course. */ + if (qcmd->zto[0] != 'D' + || strchr (qcmd->zoptions, '9') == NULL) + return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, + "not permitted to receive"); + + puuconf = qdaemon->puuconf; + iuuconf = uuconf_localname (puuconf, &zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zlocalname = zsysdep_localname (); + if (zlocalname == NULL) + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys); + if (iuuconf == UUCONF_NOT_FOUND) + { + iuuconf = uuconf_system_local (puuconf, &slocalsys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + zfile = zsysdep_spool_file_name (&slocalsys, qcmd->zto, qcmd->pseq); + + (void) uuconf_system_free (puuconf, &slocalsys); + + if (zfile == NULL) + return FALSE; + } + else + { + zfile = zsysdep_add_base (qcmd->zto, qcmd->zfrom); + if (zfile == NULL) + return FALSE; + + /* Check permissions. */ + if (! fin_directory_list (zfile, qsys->uuconf_pzlocal_receive, + qsys->uuconf_zpubdir, TRUE, + FALSE, qcmd->zuser)) + { + ubuffree (zfile); + return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, + "not permitted to receive"); + } + + /* The 'f' option means that directories should not + be created if they do not already exist. */ + if (strchr (qcmd->zoptions, 'f') == NULL) + { + if (! fsysdep_make_dirs (zfile, TRUE)) + { + ubuffree (zfile); + return flocal_rec_fail ((struct stransfer *) NULL, qcmd, + qsys, "cannot create directories"); + } + } + } + + qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo)); + if (strchr (qcmd->zoptions, 'm') == NULL) + qinfo->zmail = NULL; + else + qinfo->zmail = zbufcpy (qcmd->zuser); + qinfo->zfile = zfile; + qinfo->ztemp = NULL; + qinfo->fspool = fspool; + qinfo->flocal = TRUE; + qinfo->freceived = FALSE; + qinfo->freplied = TRUE; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = flocal_rec_send_request; + qtrans->pinfo = (pointer) qinfo; + + return fqueue_local (qdaemon, qtrans); +} + +/* Report an error for a local receive request. */ + +static boolean +flocal_rec_fail (qtrans, qcmd, qsys, zwhy) + struct stransfer *qtrans; + struct scmd *qcmd; + const struct uuconf_system *qsys; + const char *zwhy; +{ + if (zwhy != NULL) + { + ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy); + (void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, zwhy, + qcmd->zfrom, qsys->uuconf_zname, + qcmd->zto, (const char *) NULL, + (const char *) NULL); + (void) fsysdep_did_work (qcmd->pseq); + } + if (qtrans != NULL) + urrec_free (qtrans); + return TRUE; +} + +/* This is called when we are ready to send the actual request to the + other system. */ + +static boolean +flocal_rec_send_request (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + long cbytes, cbytes2; + size_t clen; + char *zsend; + boolean fret; + + qinfo->ztemp = zsysdep_receive_temp (qdaemon->qsys, qinfo->zfile, + (const char *) NULL); + if (qinfo->ztemp == NULL) + { + urrec_free (qtrans); + return FALSE; + } + + /* Check the amount of free space available for both the temporary + file and the real file. */ + cbytes = csysdep_bytes_free (qinfo->ztemp); + cbytes2 = csysdep_bytes_free (qinfo->zfile); + if (cbytes < cbytes2) + cbytes = cbytes2; + if (cbytes != -1) + { + cbytes -= qdaemon->qsys->uuconf_cfree_space; + if (cbytes < 0) + cbytes = 0; + } + + if (qdaemon->clocal_size != -1 + && (cbytes == -1 || qdaemon->clocal_size < cbytes)) + cbytes = qdaemon->clocal_size; + + /* We send the string + R from to user options + + We put a dash in front of options. If we are talking to a + counterpart, we also send the maximum size file we are prepared + to accept, as returned by esysdep_open_receive. */ + clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 30); + zsend = zbufalc (clen); + if ((qdaemon->ifeatures & FEATURE_SIZES) == 0) + sprintf (zsend, "R %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto, + qtrans->s.zuser, qtrans->s.zoptions); + else if ((qdaemon->ifeatures & FEATURE_V103) == 0) + sprintf (zsend, "R %s %s %s -%s 0x%lx", qtrans->s.zfrom, qtrans->s.zto, + qtrans->s.zuser, qtrans->s.zoptions, (unsigned long) cbytes); + else + sprintf (zsend, "R %s %s %s -%s %ld", qtrans->s.zfrom, qtrans->s.zto, + qtrans->s.zuser, qtrans->s.zoptions, cbytes); + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, + qtrans->iremote); + ubuffree (zsend); + if (! fret) + { + urrec_free (qtrans); + return FALSE; + } + + qtrans->fcmd = TRUE; + qtrans->precfn = flocal_rec_await_reply; + + return fqueue_receive (qdaemon, qtrans); +} + +/* This is called when a reply is received for the request. */ + +/*ARGSUSED*/ +static boolean +flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + long crestart; + const char *zlog; + + if (zdata[0] != 'R' + || (zdata[1] != 'Y' && zdata[1] != 'N')) + { + ulog (LOG_ERROR, "%s: bad response to receive request: \"%s\"", + qtrans->s.zfrom, zdata); + urrec_free (qtrans); + return FALSE; + } + + if (zdata[1] == 'N') + { + boolean fnever; + const char *zerr; + + fnever = TRUE; + if (zdata[2] == '2') + zerr = "no such file"; + else if (zdata[2] == '6') + { + /* We sent over the maximum file size we were prepared to + receive, and the remote system is telling us that the + file is larger than that. Try again later. It would be + better if we could know whether there will ever be enough + room. */ + zerr = "too large to receive now"; + fnever = FALSE; + } + else + zerr = "unknown reason"; + + if (fnever) + return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, zerr); + + ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); + + urrec_free (qtrans); + + return TRUE; + } + + /* The mode should have been sent as "RY 0%o". If it wasn't, we use + 0666. */ + qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2), + (char **) NULL, 8); + if (qtrans->s.imode == 0) + qtrans->s.imode = 0666; + + /* Open the file to receive into. We just ignore any restart count, + since we have no way to tell it to the other side. SVR4 may have + some way to do this, but I don't know what it is. */ + qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile, + (const char *) NULL, qinfo->ztemp, + &crestart); + if (! ffileisopen (qtrans->e)) + return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, + "cannot open file"); + + if (qinfo->fspool) + zlog = qtrans->s.zto; + else + zlog = qinfo->zfile; + qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); + sprintf (qtrans->zlog, "Receiving %s", zlog); + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, + (long) -1, &fhandled)) + { + (void) ffileclose (qtrans->e); + return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, + (const char *) NULL); + } + if (fhandled) + return TRUE; + } + + qtrans->frecfile = TRUE; + qtrans->psendfn = frec_file_send_confirm; + qtrans->precfn = frec_file_end; + + return fqueue_receive (qdaemon, qtrans); +} + +/* Make sure there is still enough disk space available to receive a + file. */ + +boolean +frec_check_free (qtrans, cfree_space) + struct stransfer *qtrans; + long cfree_space; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + long cfree1, cfree2; + + cfree1 = csysdep_bytes_free (qinfo->ztemp); + cfree2 = csysdep_bytes_free (qinfo->zfile); + if (cfree1 < cfree2) + cfree1 = cfree2; + if (cfree1 != -1 && cfree1 < cfree_space) + { + ulog (LOG_ERROR, "%s: too big to receive now", qinfo->zfile); + return FALSE; + } + + return TRUE; +} + +/* A remote request to send a file to the local system, meaning that + we are going to receive a file. + + If we are using a protocol which does not support multiple + channels, the remote system will not start sending us the file + until it has received our confirmation. In that case, the order of + functions is as follows: + + fremote_send_file_init (open file) --> fqueue_remote + fremote_send_reply (send SY, call pffile) --> fqueue_receive + receive file + frec_file_end (close and move file, call pffile) --> fqueue_send + frec_file_send_confirm (send CY) + + If the protocol supports multiple channels, then the remote system + will start sending the file immediately after the send request. + That means that the data may come in before remote_send_reply is + called, so frec_file_end may be called before fremote_send_reply. + Note that this means the pffile entry points may be called in + reverse order for such a protocol. + + If the send request is rejected, via fremote_send_fail, and the + protocol supports multiple channels, we must accept and discard + data until a zero byte buffer is received from the other side, + indicating that it has received our rejection. + + This code also handles execution requests, which are very similar + to send requests. */ + +boolean +fremote_send_file_init (qdaemon, qcmd, iremote) + struct sdaemon *qdaemon; + struct scmd *qcmd; + int iremote; +{ + const struct uuconf_system *qsys; + boolean fspool; + char *zfile; + openfile_t e; + char *ztemp; + long cbytes, cbytes2; + long crestart; + struct srecinfo *qinfo; + struct stransfer *qtrans; + const char *zlog; + + qsys = qdaemon->qsys; + + if (! qsys->uuconf_frec_request) + { + ulog (LOG_ERROR, "%s: not permitted to receive files from remote", + qcmd->zfrom); + return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); + } + + fspool = fspool_file (qcmd->zto); + + /* We don't accept remote command files. An execution request may + only send a simple data file. */ + if ((fspool && qcmd->zto[0] == 'C') + || (qcmd->bcmd == 'E' + && (! fspool || qcmd->zto[0] != 'D'))) + { + ulog (LOG_ERROR, "%s: not permitted to receive", qcmd->zfrom); + return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); + } + + /* See if we have already received this file in a previous + conversation. */ + if (fsysdep_already_received (qsys, qcmd->zto, qcmd->ztemp)) + return fremote_send_fail (qdaemon, qcmd, FAILURE_RECEIVED, iremote); + + if (fspool) + { + zfile = zsysdep_spool_file_name (qsys, qcmd->zto, (pointer) NULL); + if (zfile == NULL) + return FALSE; + } + else + { + zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir); + if (zfile != NULL) + { + char *zadd; + + zadd = zsysdep_add_base (zfile, qcmd->zfrom); + ubuffree (zfile); + zfile = zadd; + } + if (zfile == NULL) + return FALSE; + + /* Check permissions. */ + if (! fin_directory_list (zfile, qsys->uuconf_pzremote_receive, + qsys->uuconf_zpubdir, TRUE, + FALSE, (const char *) NULL)) + { + ulog (LOG_ERROR, "%s: not permitted to receive", zfile); + ubuffree (zfile); + return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); + } + + if (strchr (qcmd->zoptions, 'f') == NULL) + { + if (! fsysdep_make_dirs (zfile, TRUE)) + { + ubuffree (zfile); + return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, + iremote); + } + } + } + + ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp); + + /* Adjust the number of bytes we are prepared to receive according + to the amount of free space we are supposed to leave available + and the maximum file size we are permitted to transfer. */ + cbytes = csysdep_bytes_free (ztemp); + cbytes2 = csysdep_bytes_free (zfile); + if (cbytes < cbytes2) + cbytes = cbytes2; + + if (cbytes != -1) + { + cbytes -= qsys->uuconf_cfree_space; + if (cbytes < 0) + cbytes = 0; + } + + if (qdaemon->cremote_size != -1 + && (cbytes == -1 || qdaemon->cremote_size < cbytes)) + cbytes = qdaemon->cremote_size; + + /* If the number of bytes we are prepared to receive is less than + the file size, we must fail. If the remote did not tell us the + file size, arbitrarily assumed that it is 10240 bytes. */ + if (cbytes != -1) + { + long csize; + + csize = qcmd->cbytes; + if (csize == -1) + csize = CASSUMED_FILE_SIZE; + if (cbytes < csize) + { + ulog (LOG_ERROR, "%s: too big to receive", zfile); + ubuffree (ztemp); + ubuffree (zfile); + return fremote_send_fail (qdaemon, qcmd, FAILURE_SIZE, iremote); + } + } + + /* Open the file to receive into. This may find an old copy of the + file, which will be used for file restart if the other side + supports it. */ + e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp, &crestart); + if (! ffileisopen (e)) + { + ubuffree (ztemp); + ubuffree (zfile); + return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote); + } + + if (crestart > 0) + { + if ((qdaemon->ifeatures & FEATURE_RESTART) == 0) + crestart = -1; + else + { + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, + "fremote_send_file_init: Restarting receive from %ld", + crestart); + if (! ffileseek (e, crestart)) + { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + (void) ffileclose (e); + ubuffree (ztemp); + ubuffree (zfile); + return FALSE; + } + } + } + + qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo)); + if (strchr (qcmd->zoptions, 'n') == NULL) + qinfo->zmail = NULL; + else + qinfo->zmail = zbufcpy (qcmd->znotify); + qinfo->zfile = zfile; + qinfo->ztemp = ztemp; + qinfo->fspool = fspool; + qinfo->flocal = FALSE; + qinfo->freceived = FALSE; + qinfo->freplied = FALSE; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = fremote_send_reply; + qtrans->precfn = frec_file_end; + qtrans->iremote = iremote; + qtrans->pinfo = (pointer) qinfo; + qtrans->frecfile = TRUE; + qtrans->e = e; + if (crestart > 0) + qtrans->ipos = crestart; + + if (qcmd->bcmd == 'E') + zlog = qcmd->zcmd; + else + { + if (qinfo->fspool) + zlog = qcmd->zto; + else + zlog = qinfo->zfile; + } + qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); + sprintf (qtrans->zlog, "Receiving %s", zlog); + + return fqueue_remote (qdaemon, qtrans); +} + +/* Reply to a send request, and prepare to receive the file. */ + +static boolean +fremote_send_reply (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + char ab[50]; + + ab[0] = qtrans->s.bcmd; + ab[1] = 'Y'; + if (qtrans->ipos <= 0) + ab[2] = '\0'; + else + sprintf (ab + 2, " 0x%lx", (unsigned long) qtrans->ipos); + + if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, + qtrans->iremote)) + { + (void) ffileclose (qtrans->e); + (void) remove (qinfo->ztemp); + urrec_free (qtrans); + return FALSE; + } + + qinfo->freplied = TRUE; + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, + (long) -1, &fhandled)) + { + (void) ffileclose (qtrans->e); + (void) remove (qinfo->ztemp); + urrec_free (qtrans); + return FALSE; + } + if (fhandled) + return TRUE; + } + + /* If the file has been completely received, we just want to send + the final confirmation. Otherwise, we must wait for the file + first. */ + qtrans->psendfn = frec_file_send_confirm; + if (qinfo->freceived) + return fqueue_send (qdaemon, qtrans); + else + return fqueue_receive (qdaemon, qtrans); +} + +/* If we can't receive a file, queue up a response to the remote + system. */ + +static boolean +fremote_send_fail (qdaemon, qcmd, twhy, iremote) + struct sdaemon *qdaemon; + struct scmd *qcmd; + enum tfailure twhy; + int iremote; +{ + struct srecfailinfo *qinfo; + struct stransfer *qtrans; + + qinfo = (struct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo)); + qinfo->twhy = twhy; + qinfo->fsent = FALSE; + + /* If the protocol does not support multiple channels (cchans <= 1), + then we have essentially already received the entire file. */ + qinfo->freceived = qdaemon->qproto->cchans <= 1; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = fremote_send_fail_send; + qtrans->precfn = fremote_discard; + qtrans->iremote = iremote; + qtrans->pinfo = (pointer) qinfo; + + return fqueue_remote (qdaemon, qtrans); +} + +/* Send a failure string for a send command to the remote system; + this is called when we are ready to reply to the command. */ + +static boolean +fremote_send_fail_send (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; + char ab[4]; + boolean fret; + + ab[0] = qtrans->s.bcmd; + ab[1] = 'N'; + + switch (qinfo->twhy) + { + case FAILURE_PERM: + ab[2] = '2'; + break; + case FAILURE_OPEN: + ab[2] = '4'; + break; + case FAILURE_SIZE: + ab[2] = '6'; + break; + case FAILURE_RECEIVED: + /* Remember this file as though we successfully received it; + when the other side acknowledges our rejection, we know that + we no longer have to remember that we received this file. */ + usent_receive_ack (qdaemon, qtrans); + ab[2] = '8'; + break; + default: + ab[2] = '\0'; + break; + } + + ab[3] = '\0'; + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, + qtrans->iremote); + + qinfo->fsent = TRUE; + + /* Wait for the end of file marker if we haven't gotten it yet. */ + if (! qinfo->freceived) + { + if (! fqueue_receive (qdaemon, qtrans)) + fret = FALSE; + } + else + { + xfree (qtrans->pinfo); + utransfree (qtrans); + } + + return fret; +} + +/* Discard data until we reach the end of the file. This is used for + a protocol with multiple channels, since the remote system may + start sending the file before the confirmation is sent. If we + refuse the file, the remote system will get us back in synch by + sending an empty buffer, which is what we look for here. */ + +/*ARGSUSED*/ +static boolean +fremote_discard (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, + "fremote_discard: Discarding %lu bytes", + (unsigned long) cdata); + + if (cdata != 0) + return TRUE; + + qinfo->freceived = TRUE; + + /* If we have already sent the denial, we are done. */ + if (qinfo->fsent) + { + xfree (qtrans->pinfo); + utransfree (qtrans); + } + + return TRUE; +} + +/* This is called when a file has been completely received. It sends + a response to the remote system. */ + +/*ARGSUSED*/ +static boolean +frec_file_end (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + const char *zerr; + boolean fnever; + + DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, "frec_file_end: %s to %s (freplied %s)", + qtrans->s.zfrom, qtrans->s.zto, + qinfo->freplied ? "TRUE" : "FALSE"); + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, FALSE, + (long) -1, &fhandled)) + { + (void) ffileclose (qtrans->e); + (void) remove (qinfo->ztemp); + urrec_free (qtrans); + return FALSE; + } + if (fhandled) + return TRUE; + } + + qinfo->freceived = TRUE; + + fnever = FALSE; + + if (! ffileclose (qtrans->e)) + { + zerr = strerror (errno); + ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr); + } + else if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool, + FALSE, ! qinfo->fspool, + (qinfo->flocal + ? qtrans->s.zuser + : (const char *) NULL))) + { + zerr = "could not move to final location"; + ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr); + fnever = TRUE; + } + else + { + if (! qinfo->fspool) + { + unsigned int imode; + + /* Unless we can change the ownership of the file, the only + choice to make about these bits is whether to set the + execute bit or not. */ + if ((qtrans->s.imode & 0111) != 0) + imode = 0777; + else + imode = 0666; + (void) fsysdep_change_mode (qinfo->zfile, imode); + } + + zerr = NULL; + } + + if (zerr != NULL) + (void) remove (qinfo->ztemp); + + ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname, + FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros, + qdaemon->fmaster); + + if (zerr == NULL) + { + if (qinfo->zmail != NULL && *qinfo->zmail != '\0') + (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail, + (const char *) NULL, + qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, + qtrans->s.zto, (const char *) NULL, + (const char *) NULL); + + if (qtrans->s.pseq != NULL) + (void) fsysdep_did_work (qtrans->s.pseq); + + if (! qinfo->flocal) + { + /* Remember that we have received this file, so that if the + connection drops at this point we won't receive it again. + We could check the return value here, but if we return + FALSE we couldn't do anything but drop the connection, + which would hardly be reasonable. Instead we trust that + the administrator will notice and handle any error + messages, which are very unlikely to occur if everything + is set up correctly. */ + (void) fsysdep_remember_reception (qdaemon->qsys, qtrans->s.zto, + qtrans->s.ztemp); + } + } + else + { + /* If the transfer failed, we send mail if it was requested + locally and if it can never succeed. */ + if (qinfo->flocal && fnever) + { + (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail, + zerr, qtrans->s.zfrom, + qdaemon->qsys->uuconf_zname, + qtrans->s.zto, (const char *) NULL, + (const char *) NULL); + (void) fsysdep_did_work (qtrans->s.pseq); + } + } + + /* If this is an execution request, we must create the execution + file itself. */ + if (qtrans->s.bcmd == 'E' && zerr == NULL) + { + char *zxqt, *zxqtfile, *ztemp; + FILE *e; + boolean fbad; + + /* We get an execution file name by simply replacing the leading + D in the received file name with an X. This pretty much + always has to work since we can always receive a file name + starting with X, so the system dependent code must be + prepared to see one. */ + zxqt = zbufcpy (qtrans->s.zto); + zxqt[0] = 'X'; + zxqtfile = zsysdep_spool_file_name (qdaemon->qsys, zxqt, + (pointer) NULL); + ubuffree (zxqt); + + if (zxqtfile == NULL) + { + urrec_free (qtrans); + return FALSE; + } + + /* We have to write via a temporary file, because otherwise + uuxqt might pick up the file before we have finished writing + it. */ + e = NULL; + ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0"); + if (ztemp != NULL) + e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE); + + if (e == NULL) + { + ubuffree (zxqtfile); + ubuffree (ztemp); + urrec_free (qtrans); + return FALSE; + } + + fprintf (e, "U %s %s\n", qtrans->s.zuser, qdaemon->qsys->uuconf_zname); + fprintf (e, "F %s\n", qtrans->s.zto); + fprintf (e, "I %s\n", qtrans->s.zto); + if (strchr (qtrans->s.zoptions, 'N') != NULL) + fprintf (e, "N\n"); + if (strchr (qtrans->s.zoptions, 'Z') != NULL) + fprintf (e, "Z\n"); + if (strchr (qtrans->s.zoptions, 'R') != NULL) + fprintf (e, "R %s\n", qtrans->s.znotify); + if (strchr (qtrans->s.zoptions, 'e') != NULL) + fprintf (e, "e\n"); + fprintf (e, "C %s\n", qtrans->s.zcmd); + + fbad = FALSE; + if (fclose (e) == EOF) + { + ulog (LOG_ERROR, "fclose: %s", strerror (errno)); + (void) remove (ztemp); + fbad = TRUE; + } + + if (! fbad) + { + if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE, + (const char *) NULL)) + fbad = TRUE; + } + + ubuffree (zxqtfile); + ubuffree (ztemp); + + if (fbad) + { + urrec_free (qtrans); + return FALSE; + } + } + + /* Prepare to send the completion string to the remote system. If + we have not yet replied to the remote send request, we leave the + transfer structure on the remote queue. Otherwise we add it to + the send queue. The psendfn field will already be set. */ + qinfo->fmoved = zerr == NULL; + if (qinfo->freplied) + return fqueue_send (qdaemon, qtrans); + + return TRUE; +} + +/* Send the final confirmation string to the remote system. */ + +static boolean +frec_file_send_confirm (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + const char *zsend; + boolean fret; + + if (! qinfo->fmoved) + zsend = "CN5"; + else if (! qdaemon->frequest_hangup) + zsend = "CY"; + else + { +#if DEBUG > 0 + if (qdaemon->fmaster) + ulog (LOG_FATAL, "frec_file_send_confirm: Can't happen"); +#endif + + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, + "frec_send_file_confirm: Requesting remote to transfer control"); + zsend = "CYM"; + } + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, + qtrans->ilocal, qtrans->iremote); + + /* Now, if that was a remote command, then when the confirmation + message is acked we no longer have to remember that we received + that file. */ + if (! qinfo->flocal && qinfo->fmoved) + usent_receive_ack (qdaemon, qtrans); + + urrec_free (qtrans); + return fret; +} + +/* Discard a temporary file if it is not useful. A temporary file is + useful if it could be used to restart a receive. This is called if + the connection is lost. It is only called if qtrans->frecfile is + TRUE. */ + +boolean +frec_discard_temp (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ + struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; + + if ((qdaemon->ifeatures & FEATURE_RESTART) == 0 + || qtrans->s.ztemp == NULL + || qtrans->s.ztemp[0] != 'D' + || strcmp (qtrans->s.ztemp, "D.0") == 0) + (void) remove (qinfo->ztemp); + return TRUE; +} diff --git a/gnu/libexec/uucp/uucico/send.c b/gnu/libexec/uucp/uucico/send.c new file mode 100644 index 0000000000..9337de39c6 --- /dev/null +++ b/gnu/libexec/uucp/uucico/send.c @@ -0,0 +1,1273 @@ +/* send.c + Routines to send 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" + +#if USE_RCS_ID +const char send_rcsid[] = "$Id: send.c,v 1.1 1993/08/04 19:36:29 jtc Exp $"; +#endif + +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "prot.h" +#include "trans.h" + +/* We keep this information in the pinfo field of the stransfer + structure. */ +struct ssendinfo +{ + /* Local user to send mail to (may be NULL). */ + char *zmail; + /* Full file name. */ + char *zfile; + /* Number of bytes in file. */ + long cbytes; + /* TRUE if this was a local request. */ + boolean flocal; + /* TRUE if this is a spool directory file. */ + boolean fspool; + /* TRUE if the file has been completely sent. */ + boolean fsent; + /* Execution file for sending an unsupported E request. */ + char *zexec; +}; + +/* Local functions. */ + +static void usfree_send P((struct stransfer *qtrans)); +static boolean flocal_send_fail P((struct stransfer *qtrans, + struct scmd *qcmd, + const struct uuconf_system *qsys, + const char *zwhy)); +static boolean flocal_send_request P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean flocal_send_await_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean flocal_send_cancelled P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean flocal_send_open_file P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fremote_rec_fail P((struct sdaemon *qdaemon, + enum tfailure twhy, int iremote)); +static boolean fremote_rec_fail_send P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fremote_rec_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fsend_file_end P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean fsend_await_confirm P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean fsend_exec_file_init P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static void usadd_exec_line P((char **pz, size_t *pcalc, size_t *pclen, + int bcmd, const char *z1, const char *z2)); +static boolean fsend_exec_file P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); + +/* Free up a send stransfer structure. */ + +static void +usfree_send (qtrans) + struct stransfer *qtrans; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + + if (qinfo != NULL) + { + ubuffree (qinfo->zmail); + ubuffree (qinfo->zfile); + ubuffree (qinfo->zexec); + xfree (qtrans->pinfo); + } + + utransfree (qtrans); +} + +/* Set up a local request to send a file. This may be called before + we have even tried to call the remote system. + + If we are using a traditional protocol, which doesn't support + channel numbers and doesn't permit the file to be sent until an + acknowledgement has been received, the sequence of function calls + looks like this: + + flocal_send_file_init --> fqueue_local + flocal_send_request (sends S request) --> fqueue_receive + flocal_send_await_reply (waits for SY) --> fqueue_send + flocal_send_open_file (opens file, calls pffile) --> fqueue_send + send file + fsend_file_end (calls pffile) --> fqueue_receive + fsend_await_confirm (waits for CY) + + If flocal_send_await_reply gets an SN, it deletes the request. If + the SY reply contains a file position at which to start sending, + flocal_send_await_reply sets qinfo->ipos. + + This gets more complex if the protocol supports channels. In that + case, we want to start sending the file data immediately, to avoid + the round trip delay between flocal_send_request and + flocal_send_await_reply. To do this, flocal_send_request calls + fqueue_send rather than fqueue_receive. The main execution + sequence looks like this: + + flocal_send_file_init --> fqueue_local + flocal_send_request (sends S request) --> fqueue_send + flocal_send_open_file (opens file, calls pffile) --> fqueue_send + send file + fsend_file_end (calls pffile) --> fqueue_receive + sometime: flocal_send_await_reply (waits for SY) + fsend_await_confirm (waits for CY) + + In this case flocal_send_await_reply must be run before + fsend_await_confirm; it may be run anytime after + flocal_send_request. + + If flocal_send_await_reply is called before the entire file has + been sent: if it gets an SN, it calls flocal_send_cancelled to send + an empty data block to inform the remote system that the file + transfer has stopped. If it gets a file position request, it must + adjust the file position accordingly. + + If flocal_send_await_reply is called after the entire file has been + sent: if it gets an SN, it can simply delete the request. It can + ignore any file position request. + + If the request is not deleted, flocal_send_await_reply must arrange + for the next string to be passed to fsend_await_confirm. + Presumably fsend_await_confirm will only be called after the entire + file has been sent. + + Just to make things even more complex, these same routines support + sending execution requests, since that is much like sending a file. + For an execution request, the bcmd character will be E rather than + S. If an execution request is being sent to a system which does + not support them, it must be sent as two S requests instead. The + second one will be the execution file, but no actual file is + created; instead the zexec and znext fields in the ssendinfo + structure are used. So if the bcmd character is E, then if the + zexec field is NULL, the data file is being sent, otherwise the + fake execution file is being sent. */ + +boolean +flocal_send_file_init (qdaemon, qcmd) + struct sdaemon *qdaemon; + struct scmd *qcmd; +{ + const struct uuconf_system *qsys; + boolean fspool; + char *zfile; + long cbytes; + struct ssendinfo *qinfo; + struct stransfer *qtrans; + + qsys = qdaemon->qsys; + + if (qdaemon->fcaller + ? ! qsys->uuconf_fcall_transfer + : ! qsys->uuconf_fcalled_transfer) + { + /* uux or uucp should have already made sure that the transfer + is possible, but it might have changed since then. */ + if (! qsys->uuconf_fcall_transfer + && ! qsys->uuconf_fcalled_transfer) + return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, + "not permitted to transfer files"); + + /* We can't do the request now, but it may get done later. */ + return TRUE; + } + + /* The 'C' option means that the file has been copied to the spool + directory. */ + if (strchr (qcmd->zoptions, 'C') == NULL + && ! fspool_file (qcmd->zfrom)) + { + fspool = FALSE; + if (! fin_directory_list (qcmd->zfrom, + qsys->uuconf_pzlocal_send, + qsys->uuconf_zpubdir, TRUE, + TRUE, qcmd->zuser)) + return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, + "not permitted to send"); + zfile = zbufcpy (qcmd->zfrom); + } + else + { + fspool = TRUE; + zfile = zsysdep_spool_file_name (qsys, qcmd->ztemp, qcmd->pseq); + if (zfile == NULL) + return FALSE; + } + + /* Make sure we meet any local size restrictions. The connection + may not have been opened at this point, so we can't check remote + size restrictions. */ + cbytes = csysdep_size (zfile); + if (cbytes < 0) + { + ubuffree (zfile); + if (cbytes != -1) + return FALSE; + /* A cbytes value of -1 means that the file does not exist. + This can happen legitimately if it has already been sent from + the spool directory. */ + if (! fspool) + return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, + "does not exist"); + (void) fsysdep_did_work (qcmd->pseq); + return TRUE; + } + + if (qdaemon->clocal_size != -1 + && qdaemon->clocal_size < cbytes) + { + ubuffree (zfile); + + if (qdaemon->cmax_ever == -2) + { + long c1, c2; + + c1 = cmax_size_ever (qsys->uuconf_qcall_local_size); + c2 = cmax_size_ever (qsys->uuconf_qcalled_local_size); + if (c1 > c2) + qdaemon->cmax_ever = c1; + else + qdaemon->cmax_ever = c2; + } + + if (qdaemon->cmax_ever != -1 + && qdaemon->cmax_ever < qcmd->cbytes) + return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, + "too large to send"); + + return TRUE; + } + + /* We are now prepared to send the command to the remote system. We + queue up a transfer request to send the command when we are + ready. */ + qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo)); + if (strchr (qcmd->zoptions, 'm') == NULL) + qinfo->zmail = NULL; + else + qinfo->zmail = zbufcpy (qcmd->zuser); + qinfo->zfile = zfile; + qinfo->cbytes = cbytes; + qinfo->flocal = TRUE; + qinfo->fspool = fspool; + qinfo->fsent = FALSE; + qinfo->zexec = NULL; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = flocal_send_request; + qtrans->pinfo = (pointer) qinfo; + + return fqueue_local (qdaemon, qtrans); +} + +/* Clean up after a failing local send request. If zwhy is not NULL, + this reports an error to the log file and to the user. */ + +static boolean +flocal_send_fail (qtrans, qcmd, qsys, zwhy) + struct stransfer *qtrans; + struct scmd *qcmd; + const struct uuconf_system *qsys; + const char *zwhy; +{ + if (zwhy != NULL) + { + char *zfree; + + if (qcmd->bcmd != 'E') + zfree = NULL; + else + { + zfree = zbufalc (sizeof "Execution of \"\": " + + strlen (qcmd->zcmd) + + strlen (zwhy)); + sprintf (zfree, "Execution of \"%s\": %s", qcmd->zcmd, zwhy); + zwhy = zfree; + } + + ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy); + (void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, + zwhy, qcmd->zfrom, (const char *) NULL, + qcmd->zto, qsys->uuconf_zname, + zsysdep_save_temp_file (qcmd->pseq)); + + ubuffree (zfree); + } + + (void) fsysdep_did_work (qcmd->pseq); + + if (qtrans != NULL) + usfree_send (qtrans); + + return TRUE; +} + +/* This is called when we are ready to send the request to the remote + system. We form the request and send it over. If the protocol + does not support multiple channels, we start waiting for the + response; otherwise we can start sending the file immediately. */ + +static boolean +flocal_send_request (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + char *zsend; + const char *znotify; + char absize[20]; + boolean fret; + + /* Make sure the file meets any remote size restrictions. */ + if (qdaemon->cmax_receive != -1 + && qdaemon->cmax_receive < qinfo->cbytes) + return flocal_send_fail (qtrans, &qtrans->s, qdaemon->qsys, + "too large for receiver"); + + /* Construct the notify string to send. If we are going to send a + size or an execution command, it must be non-empty. */ + znotify = qtrans->s.znotify; + if (znotify == NULL) + znotify = ""; + if ((qdaemon->ifeatures & FEATURE_SIZES) != 0 + || (qtrans->s.bcmd == 'E' + && (qdaemon->ifeatures & FEATURE_EXEC) != 0)) + { + if (*znotify == '\0') + znotify = "\"\""; + } + else + { + /* We don't need a notify string. Some crufty UUCP code can't + handle a pair of double quotes. */ + if (strcmp (znotify, "\"\"") == 0) + znotify = ""; + } + + /* Construct the size string to send. */ + if ((qdaemon->ifeatures & FEATURE_SIZES) == 0 + && (qtrans->s.bcmd != 'E' + || (qdaemon->ifeatures & FEATURE_EXEC) == 0)) + absize[0] = '\0'; + else if ((qdaemon->ifeatures & FEATURE_V103) == 0) + sprintf (absize, "0x%lx", (unsigned long) qinfo->cbytes); + else + sprintf (absize, "%ld", qinfo->cbytes); + + zsend = zbufalc (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + + strlen (qtrans->s.ztemp) + strlen (znotify) + + strlen (absize) + + (qtrans->s.zcmd != NULL ? strlen (qtrans->s.zcmd) : 0) + + 50); + + /* If this an execution request and the other side supports + execution requests, we send an E command. Otherwise we send an S + command. The case of an execution request when we are sending + the fake execution file is handled just like an S request at this + point. */ + if (qtrans->s.bcmd == 'E' + && (qdaemon->ifeatures & FEATURE_EXEC) != 0) + { + /* Send the string + E zfrom zto zuser zoptions ztemp imode znotify size zcmd + to the remote system. We put a '-' in front of the (possibly + empty) options and a '0' in front of the mode. */ + sprintf (zsend, "E %s %s %s -%s %s 0%o %s %s %s", qtrans->s.zfrom, + qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions, + qtrans->s.ztemp, qtrans->s.imode, znotify, absize, + qtrans->s.zcmd); + } + else + { + const char *zoptions, *zdummy; + + /* Send the string + S zfrom zto zuser zoptions ztemp imode znotify + to the remote system. We put a '-' in front of the (possibly + empty) options and a '0' in front of the mode. If size + negotiation is supported, we also send the size; in this case + if znotify is empty we must send it as "". If this is really + an execution request, we have to simplify the options string + to remove the various execution options which may confuse the + remote system. SVR4 expects a string "dummy" between the + notify string and the size; I don't know why. */ + if (qtrans->s.bcmd != 'E') + zoptions = qtrans->s.zoptions; + else if (strchr (qtrans->s.zoptions, 'C') != NULL) + { + /* This should set zoptions to "C", but at least one UUCP + program gets confused by it. That means that it will + fail in certain cases, but I suppose we might as well + kowtow to compatibility. This shouldn't matter to any + other program, I hope. */ + zoptions = ""; + } + else + zoptions = "c"; + + if ((qdaemon->ifeatures & FEATURE_SVR4) != 0) + zdummy = " dummy "; + else + zdummy = " "; + + sprintf (zsend, "S %s %s %s -%s %s 0%o %s%s%s", qtrans->s.zfrom, + qtrans->s.zto, qtrans->s.zuser, zoptions, + qtrans->s.ztemp, qtrans->s.imode, znotify, zdummy, + absize); + } + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, + qtrans->iremote); + ubuffree (zsend); + if (! fret) + { + usfree_send (qtrans); + return FALSE; + } + + /* If we are using a protocol which can make multiple channels, then + we can open and send the file whenever we are ready. This is + because we will be able to distinguish the response by the + channel it is directed to. This assumes that every protocol + which supports multiple channels also supports sending the file + position in mid-stream, since otherwise we would not be able to + restart files. */ + qtrans->fcmd = TRUE; + qtrans->psendfn = flocal_send_open_file; + qtrans->precfn = flocal_send_await_reply; + + if (qdaemon->qproto->cchans > 1) + return fqueue_send (qdaemon, qtrans); + else + return fqueue_receive (qdaemon, qtrans); +} + +/* This is called when a reply is received for the send request. As + described at length above, if the protocol supports multiple + channels we may be in the middle of sending the file, or we may + even finished sending the file. */ + +static boolean +flocal_send_await_reply (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + char bcmd; + + if (qtrans->s.bcmd == 'E' + && (qdaemon->ifeatures & FEATURE_EXEC) != 0) + bcmd = 'E'; + else + bcmd = 'S'; + if (zdata[0] != bcmd + || (zdata[1] != 'Y' && zdata[1] != 'N')) + { + ulog (LOG_ERROR, "%s: Bad response to %c request: \"%s\"", + qtrans->s.zfrom, bcmd, zdata); + usfree_send (qtrans); + return FALSE; + } + + if (zdata[1] == 'N') + { + const char *zerr; + boolean fnever; + + fnever = TRUE; + if (zdata[2] == '2') + zerr = "permission denied by remote"; + else if (zdata[2] == '4') + { + zerr = "remote cannot create work files"; + fnever = FALSE; + } + else if (zdata[2] == '6') + { + zerr = "too large for remote now"; + fnever = FALSE; + } + else if (zdata[2] == '7') + { + /* The file is too large to ever send. */ + zerr = "too large for remote"; + } + else if (zdata[2] == '8') + { + /* The file was already received by the remote system. This + is not an error, it just means that the ack from the + remote was lost in the previous conversation, and there + is no need to resend the file. */ + zerr = NULL; + } + else + zerr = "unknown reason"; + + if (! fnever) + { + if (qtrans->s.bcmd == 'E') + ulog (LOG_ERROR, "Execution of \"%s\": %s", qtrans->s.zcmd, + zerr); + else + ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); + } + else + { + if (! flocal_send_fail ((struct stransfer *) NULL, &qtrans->s, + qdaemon->qsys, zerr)) + return FALSE; + } + + /* If the protocol does not support multiple channels, we can + simply remove the transaction. Otherwise we must make sure + the remote side knows that we have finished sending the file + data. If we have already sent the entire file, there will be + no confusion. */ + if (qdaemon->qproto->cchans == 1 || qinfo->fsent) + { + usfree_send (qtrans); + return TRUE; + } + else + { + qtrans->psendfn = flocal_send_cancelled; + qtrans->precfn = NULL; + qtrans->fsendfile = FALSE; + return fqueue_send (qdaemon, qtrans); + } + } + + /* A number following the SY or EY is the file position to start + sending from. If we are already sending the file, we must set + the position accordingly. */ + if (zdata[2] != '\0') + { + long cskip; + + cskip = strtol ((char *) (zdata + 2), (char **) NULL, 0); + if (cskip > 0 && qtrans->ipos < cskip) + { + if (qtrans->fsendfile && ! qinfo->fsent) + { + if (! ffileseek (qtrans->e, cskip)) + { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + usfree_send (qtrans); + return FALSE; + } + } + qtrans->ipos = cskip; + } + } + + /* Now queue up to send the file or to wait for the confirmation. + We already set psendfn at the end of flocal_send_request. If the + protocol supports multiple channels, we have already called + fqueue_send; calling it again would move the request in the + queue, which would make the log file a bit confusing. */ + qtrans->precfn = fsend_await_confirm; + if (qinfo->fsent) + return fqueue_receive (qdaemon, qtrans); + else if (qdaemon->qproto->cchans <= 1) + return fqueue_send (qdaemon, qtrans); + else + return TRUE; +} + +/* Open the file, if any, and prepare to send it. */ + +static boolean +flocal_send_open_file (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + const char *zuser; + + /* If this is not a fake execution file, open it. */ + if (qinfo->zexec == NULL) + { + /* If there is an ! in the user name, this is a remote request + queued up by fremote_xcmd_init. */ + zuser = qtrans->s.zuser; + if (strchr (zuser, '!') != NULL) + zuser = NULL; + + qtrans->e = esysdep_open_send (qdaemon->qsys, qinfo->zfile, + ! qinfo->fspool, zuser); + if (! ffileisopen (qtrans->e)) + { + (void) fmail_transfer (FALSE, qtrans->s.zuser, + (const char *) NULL, + "cannot open file", + qtrans->s.zfrom, (const char *) NULL, + qtrans->s.zto, + qdaemon->qsys->uuconf_zname, + zsysdep_save_temp_file (qtrans->s.pseq)); + (void) fsysdep_did_work (qtrans->s.pseq); + usfree_send (qtrans); + + /* Unfortunately, there is no way to cancel a file send + after we've already put it in progress. So we have to + return FALSE to drop the connection. */ + return FALSE; + } + } + + /* If flocal_send_await_reply has received a reply with a file + position, it will have set qtrans->ipos to the position at which + to start. */ + if (qtrans->ipos > 0) + { + if (qinfo->zexec != NULL) + { + if (qtrans->ipos > qtrans->cbytes) + qtrans->ipos = qtrans->cbytes; + } + else + { + if (! ffileseek (qtrans->e, qtrans->ipos)) + { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + usfree_send (qtrans); + return FALSE; + } + } + } + + /* We don't bother to log sending the execution file. */ + if (qinfo->zexec == NULL) + { + const char *zsend; + char *zalc; + + if (qtrans->s.bcmd != 'E') + { + zsend = qtrans->s.zfrom; + zalc = NULL; + } + else + { + zalc = zbufalc (strlen (qtrans->s.zcmd) + sizeof " ()" + + strlen (qtrans->s.zfrom)); + sprintf (zalc, "%s (%s)", qtrans->s.zcmd, qtrans->s.zfrom); + zsend = zalc; + } + qtrans->zlog = zbufalc (sizeof "Sending " + strlen (zsend)); + sprintf (qtrans->zlog, "Sending %s", zsend); + ubuffree (zalc); + } + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE, + qinfo->cbytes, &fhandled)) + { + usfree_send (qtrans); + return FALSE; + } + + if (fhandled) + return TRUE; + } + + if (qinfo->zexec != NULL) + qtrans->psendfn = fsend_exec_file; + else + { + qtrans->fsendfile = TRUE; + qtrans->psendfn = fsend_file_end; + } + + return fqueue_send (qdaemon, qtrans); +} + +/* Cancel a file send by sending an empty buffer. This is only called + for a protocol which supports multiple channels. It is needed + so that both systems agree as to when a channel is no longer + needed. */ + +static boolean +flocal_send_cancelled (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + char *zdata; + size_t cdata; + boolean fret; + + zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); + if (zdata == NULL) + { + usfree_send (qtrans); + return FALSE; + } + + fret = (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, (size_t) 0, + qtrans->ilocal, qtrans->iremote, + qtrans->ipos); + usfree_send (qtrans); + return fret; +} + +/* A remote request to receive a file (meaning that we have to send a + file). The sequence of functions calls is as follows: + + fremote_rec_file_init (open file) --> fqueue_remote + fremote_rec_reply (send RY, call pffile) --> fqueue_send + send file + fsend_file_end (calls pffile) --> fqueue_receive + fsend_await_confirm (waits for CY) + */ + +boolean +fremote_rec_file_init (qdaemon, qcmd, iremote) + struct sdaemon *qdaemon; + struct scmd *qcmd; + int iremote; +{ + const struct uuconf_system *qsys; + char *zfile; + long cbytes; + unsigned int imode; + openfile_t e; + struct ssendinfo *qinfo; + struct stransfer *qtrans; + + qsys = qdaemon->qsys; + + if (! qsys->uuconf_fsend_request) + { + ulog (LOG_ERROR, "%s: not permitted to send files to remote", + qcmd->zfrom); + return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); + } + + if (fspool_file (qcmd->zfrom)) + { + ulog (LOG_ERROR, "%s: not permitted to send", qcmd->zfrom); + return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); + } + + zfile = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir); + if (zfile != NULL) + { + char *zbased; + + zbased = zsysdep_add_base (zfile, qcmd->zto); + ubuffree (zfile); + zfile = zbased; + } + if (zfile == NULL) + return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); + + if (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, + qsys->uuconf_zpubdir, TRUE, TRUE, + (const char *) NULL)) + { + ulog (LOG_ERROR, "%s: not permitted to send", zfile); + ubuffree (zfile); + return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); + } + + /* If the file is larger than the amount of space the other side + reported, we can't send it. Should we adjust this check based on + the restart position? */ + cbytes = csysdep_size (zfile); + if (cbytes != -1 + && ((qcmd->cbytes != -1 && qcmd->cbytes < cbytes) + || (qdaemon->cremote_size != -1 + && qdaemon->cremote_size < cbytes) + || (qdaemon->cmax_receive != -1 + && qdaemon->cmax_receive < cbytes))) + { + ulog (LOG_ERROR, "%s: too large to send", zfile); + ubuffree (zfile); + return fremote_rec_fail (qdaemon, FAILURE_SIZE, iremote); + } + + imode = ixsysdep_file_mode (zfile); + + e = esysdep_open_send (qsys, zfile, TRUE, (const char *) NULL); + if (! ffileisopen (e)) + { + ubuffree (zfile); + return fremote_rec_fail (qdaemon, FAILURE_OPEN, iremote); + } + + /* If the remote requested that the file send start from a + particular position, arrange to do so. */ + if (qcmd->ipos > 0) + { + if (! ffileseek (e, qcmd->ipos)) + { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + ubuffree (zfile); + return FALSE; + } + } + + qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo)); + qinfo->zmail = NULL; + qinfo->zfile = zfile; + qinfo->cbytes = cbytes; + qinfo->flocal = FALSE; + qinfo->fspool = FALSE; + qinfo->fsent = FALSE; + qinfo->zexec = NULL; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = fremote_rec_reply; + qtrans->iremote = iremote; + qtrans->pinfo = (pointer) qinfo; + qtrans->e = e; + qtrans->ipos = qcmd->ipos; + qtrans->s.imode = imode; + + return fqueue_remote (qdaemon, qtrans); +} + +/* Reply to a receive request from the remote system, and prepare to + start sending the file. */ + +static boolean +fremote_rec_reply (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + char absend[50]; + + sprintf (absend, "RY 0%o 0x%lx", qtrans->s.imode, + (unsigned long) qinfo->cbytes); + if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, absend, qtrans->ilocal, + qtrans->iremote)) + { + (void) ffileclose (qtrans->e); + usfree_send (qtrans); + return FALSE; + } + + qtrans->zlog = zbufalc (sizeof "Sending " + strlen (qtrans->s.zfrom)); + sprintf (qtrans->zlog, "Sending %s", qtrans->s.zfrom); + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE, + qinfo->cbytes, &fhandled)) + { + usfree_send (qtrans); + return FALSE; + } + + if (fhandled) + return TRUE; + } + + qtrans->fsendfile = TRUE; + qtrans->psendfn = fsend_file_end; + qtrans->precfn = fsend_await_confirm; + + return fqueue_send (qdaemon, qtrans); +} + +/* If we can't send a file as requested by the remote system, queue up + a failure reply which will be sent when possible. */ + +static boolean +fremote_rec_fail (qdaemon, twhy, iremote) + struct sdaemon *qdaemon; + enum tfailure twhy; + int iremote; +{ + enum tfailure *ptinfo; + struct stransfer *qtrans; + + ptinfo = (enum tfailure *) xmalloc (sizeof (enum tfailure)); + *ptinfo = twhy; + + qtrans = qtransalc ((struct scmd *) NULL); + qtrans->psendfn = fremote_rec_fail_send; + qtrans->iremote = iremote; + qtrans->pinfo = (pointer) ptinfo; + + return fqueue_remote (qdaemon, qtrans); +} + +/* Send a failure string for a receive command to the remote system; + this is called when we are ready to reply to the command. */ + +static boolean +fremote_rec_fail_send (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + enum tfailure *ptinfo = (enum tfailure *) qtrans->pinfo; + const char *z; + boolean fret; + + switch (*ptinfo) + { + case FAILURE_PERM: + case FAILURE_OPEN: + z = "RN2"; + break; + case FAILURE_SIZE: + z = "RN6"; + break; + default: + z = "RN"; + break; + } + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, z, qtrans->ilocal, + qtrans->iremote); + xfree (qtrans->pinfo); + utransfree (qtrans); + return fret; +} + +/* This is called when the main loop has finished sending a file. It + prepares to wait for a response from the remote system. Note that + if this is a local request and the protocol supports multiple + channels, we may not even have received a confirmation of the send + request. */ + +static boolean +fsend_file_end (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + + if (qdaemon->qproto->pffile != NULL) + { + boolean fhandled; + + if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, TRUE, + (long) -1, &fhandled)) + { + usfree_send (qtrans); + return FALSE; + } + + if (fhandled) + return TRUE; + } + + qinfo->fsent = TRUE; + + /* qtrans->precfn should have been set by a previous function. */ + qtrans->fcmd = TRUE; + return fqueue_receive (qdaemon, qtrans); +} + +/* Handle the confirmation string received after sending a file. */ + +/*ARGSUSED*/ +static boolean +fsend_await_confirm (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + boolean fnever; + const char *zerr; + + if (qinfo->zexec == NULL) + (void) ffileclose (qtrans->e); + + fnever = FALSE; + if (zdata[0] != 'C' + || (zdata[1] != 'Y' && zdata[1] != 'N')) + { + zerr = "bad confirmation from remote"; + ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata); + } + else if (zdata[1] == 'N') + { + fnever = TRUE; + if (zdata[2] == '5') + { + zerr = "file could not be stored in final location"; + ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); + } + else + { + zerr = "file send failed for unknown reason"; + ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata); + } + } + else + { + zerr = NULL; + + /* If we receive CYM, it means that the other side wants us to + hang up so that they can send us something. The + fhangup_requested field is checked in the main loop. */ + if (zdata[2] == 'M' && qdaemon->fmaster) + { + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, + "fsend_await_confirm: Remote has requested transfer of control"); + qdaemon->fhangup_requested = TRUE; + } + } + + ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname, + TRUE, qtrans->cbytes, qtrans->isecs, qtrans->imicros, + qdaemon->fmaster); + + if (zerr == NULL) + { + /* If this is an execution request, and the remote system + doesn't support execution requests, we have to set up the + fake execution file and loop around again. */ + if (qtrans->s.bcmd == 'E' + && (qdaemon->ifeatures & FEATURE_EXEC) == 0 + && qinfo->zexec == NULL) + return fsend_exec_file_init (qtrans, qdaemon); + + /* Send mail about the transfer if requested. */ + if (qinfo->zmail != NULL && *qinfo->zmail != '\0') + (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail, + (const char *) NULL, + qtrans->s.zfrom, (const char *) NULL, + qtrans->s.zto, qdaemon->qsys->uuconf_zname, + (const char *) NULL); + + if (qtrans->s.pseq != NULL) + (void) fsysdep_did_work (qtrans->s.pseq); + } + else + { + /* If the file send failed, we only try to save the file and + send mail if it was requested locally and it will never + succeed. We send mail to qinfo->zmail if set, otherwise to + qtrans->s.zuser. I hope this is reasonable. */ + if (fnever && qinfo->flocal) + { + (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail, + zerr, qtrans->s.zfrom, (const char *) NULL, + qtrans->s.zto, qdaemon->qsys->uuconf_zname, + zsysdep_save_temp_file (qtrans->s.pseq)); + (void) fsysdep_did_work (qtrans->s.pseq); + } + } + + usfree_send (qtrans); + + return TRUE; +} + +/* Prepare to send an execution file to a system which does not + support execution requests. We build the execution file in memory, + and then call flocal_send_request as though we were sending a real + file. Instead of sending a file, the code in flocal_send_open_file + will arrange to call fsend_exec_file which will send data out of + the buffer we have created. */ + +static boolean +fsend_exec_file_init (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + char *zxqtfile; + char abtname[CFILE_NAME_LEN]; + char abxname[CFILE_NAME_LEN]; + char *z; + size_t calc, clen; + + z = NULL; + calc = 0; + clen = 0; + + usadd_exec_line (&z, &calc, &clen, 'U', qtrans->s.zuser, + qdaemon->zlocalname); + usadd_exec_line (&z, &calc, &clen, 'F', qtrans->s.zto, ""); + usadd_exec_line (&z, &calc, &clen, 'I', qtrans->s.zto, ""); + if (strchr (qtrans->s.zoptions, 'N') != NULL) + usadd_exec_line (&z, &calc, &clen, 'N', "", ""); + if (strchr (qtrans->s.zoptions, 'Z') != NULL) + usadd_exec_line (&z, &calc, &clen, 'Z', "", ""); + if (strchr (qtrans->s.zoptions, 'R') != NULL) + usadd_exec_line (&z, &calc, &clen, 'R', qtrans->s.znotify, ""); + if (strchr (qtrans->s.zoptions, 'e') != NULL) + usadd_exec_line (&z, &calc, &clen, 'e', "", ""); + usadd_exec_line (&z, &calc, &clen, 'C', qtrans->s.zcmd, ""); + + qinfo->zexec = z; + qinfo->cbytes = clen; + + zxqtfile = zsysdep_data_file_name (qdaemon->qsys, qdaemon->zlocalname, + BDEFAULT_UUX_GRADE, TRUE, abtname, + (char *) NULL, abxname); + if (zxqtfile == NULL) + { + usfree_send (qtrans); + return FALSE; + } + ubuffree (zxqtfile); + + ubuffree ((char *) qtrans->s.zfrom); + qtrans->s.zfrom = zbufcpy (abtname); + ubuffree ((char *) qtrans->s.zto); + qtrans->s.zto = zbufcpy (abxname); + ubuffree ((char *) qtrans->s.zoptions); + qtrans->s.zoptions = zbufcpy ("C"); + ubuffree ((char *) qtrans->s.ztemp); + qtrans->s.ztemp = zbufcpy (abtname); + + qtrans->psendfn = flocal_send_request; + qtrans->precfn = NULL; + qtrans->ipos = 0; + qtrans->cbytes = 0; + qtrans->isecs = 0; + qtrans->imicros = 0; + qinfo->fsent = FALSE; + + return fqueue_send (qdaemon, qtrans); +} + +/* Add a line to the fake execution file. */ + +static void +usadd_exec_line (pz, pcalc, pclen, bcmd, z1, z2) + char **pz; + size_t *pcalc; + size_t *pclen; + int bcmd; + const char *z1; + const char *z2; +{ + size_t c1, c2; + char *znew; + + c1 = strlen (z1); + c2 = strlen (z2); + + if (*pclen + c1 + c2 + 4 >= *pcalc) + { + *pcalc += c1 + c2 + 100; + znew = zbufalc (*pcalc); + if (*pclen > 0) + { + memcpy (znew, *pz, *pclen); + ubuffree (*pz); + } + *pz = znew; + } + + znew = *pz + *pclen; + *znew++ = bcmd; + if (*z1 != '\0') + { + *znew++ = ' '; + memcpy (znew, z1, c1); + znew += c1; + if (*z2 != '\0') + { + *znew++ = ' '; + memcpy (znew, z2, c2); + znew += c2; + } + } + + /* In some bizarre non-Unix case we might have to worry about the + newline here. We don't know how a newline is normally written + out to a file, but whatever is written to a file is what we will + normally transfer. If that is not simply \n then this fake + execution file will not look like other execution files. */ + *znew++ = '\n'; + + *pclen = znew - *pz; +} + +/* This routine is called to send the contents of the fake execution + file. Normally file data is sent by the floop routine in trans.c, + but since we don't have an actual file we must do it here. This + routine sends the complete buffer, followed by a zero length + packet, and then calls fsend_file_end. */ + +static boolean +fsend_exec_file (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; + char *zdata; + size_t cdata; + size_t csend; + + zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); + if (zdata == NULL) + { + usfree_send (qtrans); + return FALSE; + } + + csend = qinfo->cbytes - qtrans->ipos; + if (csend > cdata) + csend = cdata; + + memcpy (zdata, qinfo->zexec + qtrans->ipos, csend); + + if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, csend, + qtrans->ilocal, qtrans->iremote, + qtrans->ipos)) + { + usfree_send (qtrans); + return FALSE; + } + + qtrans->cbytes += csend; + qtrans->ipos += csend; + + if (csend == 0) + return fsend_file_end (qtrans, qdaemon); + + /* Leave the job on the send queue. */ + + return TRUE; +} diff --git a/gnu/libexec/uucp/uucico/time.c b/gnu/libexec/uucp/uucico/time.c new file mode 100644 index 0000000000..c082662c2b --- /dev/null +++ b/gnu/libexec/uucp/uucico/time.c @@ -0,0 +1,130 @@ +/* time.c + Routines to deal with UUCP time spans. + + 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 time_rcsid[] = "$Id: time.c,v 1.1 1993/08/04 19:36:30 jtc Exp $"; +#endif + +#include + +#if HAVE_TIME_H +#include +#endif + +#include "uudefs.h" +#include "uuconf.h" + +/* External functions. */ +#ifndef time +extern time_t time (); +#endif +#ifndef localtime +extern struct tm *localtime (); +#endif + +/* See if the current time matches a time span. If it does, return + TRUE, set *pival to the value for the matching span, and set + *pcretry to the retry for the matching span. Otherwise return + FALSE. */ + +boolean +ftimespan_match (qspan, pival, pcretry) + const struct uuconf_timespan *qspan; + long *pival; + int *pcretry; +{ + time_t inow; + struct tm *qtm; + int itm; + const struct uuconf_timespan *q; + + if (qspan == NULL) + return FALSE; + + time (&inow); + qtm = localtime (&inow); + + /* Get the number of minutes since Sunday for the time. */ + itm = qtm->tm_wday * 24 * 60 + qtm->tm_hour * 60 + qtm->tm_min; + + for (q = qspan; q != NULL; q = q->uuconf_qnext) + { + if (q->uuconf_istart <= itm && itm <= q->uuconf_iend) + { + if (pival != NULL) + *pival = q->uuconf_ival; + if (pcretry != NULL) + *pcretry = q->uuconf_cretry; + return TRUE; + } + } + + return FALSE; +} + +/* Determine the maximum size that may ever be transferred, according + to a timesize span. This returns -1 if there is no limit. */ + +long +cmax_size_ever (qtimesize) + const struct uuconf_timespan *qtimesize; +{ + long imax; + const struct uuconf_timespan *q; + + if (qtimesize == NULL) + return -1; + + /* Look through the list of spans. If there is any gap larger than + 1 hour, we assume there are no restrictions. Otherwise we keep + track of the largest value we see. I picked 1 hour arbitrarily, + on the theory that a 1 hour span to transfer large files might + actually occur, and is probably not an accident. */ + if (qtimesize->uuconf_istart >= 60) + return -1; + + imax = -1; + + for (q = qtimesize; q != NULL; q = q->uuconf_qnext) + { + if (q->uuconf_qnext == NULL) + { + if (q->uuconf_iend <= 6 * 24 * 60 + 23 * 60) + return -1; + } + else + { + if (q->uuconf_iend + 60 <= q->uuconf_qnext->uuconf_istart) + return -1; + } + + if (imax < q->uuconf_ival) + imax = q->uuconf_ival; + } + + return imax; +} diff --git a/gnu/libexec/uucp/uucico/trans.c b/gnu/libexec/uucp/uucico/trans.c new file mode 100644 index 0000000000..065caa4ac7 --- /dev/null +++ b/gnu/libexec/uucp/uucico/trans.c @@ -0,0 +1,1439 @@ +/* trans.c + Routines to handle file transfers. + + 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 trans_rcsid[] = "$Id: trans.c,v 1.1 1993/08/04 19:36:31 jtc Exp $"; +#endif + +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "prot.h" +#include "system.h" +#include "trans.h" + +/* Local functions. */ + +static void utqueue P((struct stransfer **, struct stransfer *, + boolean fhead)); +static void utdequeue P((struct stransfer *)); +static void utchanalc P((struct sdaemon *qdaemon, struct stransfer *qtrans)); +__inline__ static struct stransfer *qtchan P((int ichan)); +__inline__ static void utchanfree P((struct stransfer *qtrans)); +static boolean ftcharge P((struct sdaemon *qdaemon, + struct stransfer *qtrans, + boolean fsend, boolean fforce)); +static boolean fcheck_queue P((struct sdaemon *qdaemon)); +static boolean ftadd_cmd P((struct sdaemon *qdaemon, const char *z, + size_t cdata, int iremote, boolean flast)); +static boolean fremote_hangup_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean flocal_poll_file P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); + +/* Queue of transfer structures that are ready to start which have + been requested by the local system. These are only permitted to + start when the local system is the master. */ +static struct stransfer *qTlocal; + +/* Queue of transfer structures that are ready to start which have + been requested by the remote system. These are responses to + commands received from the remote system, and should be started as + soon as possible. */ +static struct stransfer *qTremote; + +/* Queue of transfer structures that have been started and want to + send information. This should be static, but the 'a' protocol + looks at it, at least for now. */ +struct stransfer *qTsend; + +/* Queue of transfer structures that have been started and are waiting + to receive information. */ +static struct stransfer *qTreceive; + +/* Queue of free transfer structures. */ +static struct stransfer *qTavail; + +/* Array of transfer structures indexed by local channel number. This + is maintained for local jobs. */ +static struct stransfer *aqTchan[IMAX_CHAN + 1]; + +/* Number of local channel numbers currently allocated. */ +static int cTchans; + +/* Next channel number to allocate. */ +static int iTchan; + +/* Array of transfer structures indexed by remote channel number. + This is maintained for remote jobs. */ +static struct stransfer *aqTremote[IMAX_CHAN + 1]; + +/* A structure used to charge time to file transfers. */ +struct scharge +{ + /* The transfer we are currently charging. */ + struct stransfer *qtrans; + /* The time at the last update. */ + long isecs; + long imicros; +}; + +/* We are always charging one send and one receive. */ +static struct scharge sTsend; +static struct scharge sTreceive; + +/* The minimum amount of time, in seconds, to wait between times we + check the spool directory, if we are busy transferring data. If we + have nothing to do, we will check the spool directory regardless of + how long ago the last check was. This should probably be + configurable. */ +#define CCHECKWAIT (600) + +/* The time we last checked the spool directory for work. This is set + from the return value of ixsysdep_process_time, not ixsysdep_time, + for convenience in the routines which use it. */ +static long iTchecktime; + +/* The size of the command we have read so far in ftadd_cmd. */ +static size_t cTcmdlen; + +/* The structure we use when waiting for an acknowledgement of a + confirmed received file in fsent_receive_ack, and a list of those + structures. */ + +struct sreceive_ack +{ + struct sreceive_ack *qnext; + char *zto; + char *ztemp; + boolean fmarked; +}; + +static struct sreceive_ack *qTreceive_ack; + +/* Queue up a transfer structure before *pq. This puts it at the head + or the tail of the list headed by *pq. */ + +static void +utqueue (pq, q, fhead) + struct stransfer **pq; + struct stransfer *q; + boolean fhead; +{ + if (*pq == NULL) + { + *pq = q; + q->qprev = q->qnext = q; + } + else + { + q->qnext = *pq; + q->qprev = (*pq)->qprev; + q->qprev->qnext = q; + q->qnext->qprev = q; + if (fhead) + *pq = q; + } + q->pqqueue = pq; +} + +/* Dequeue a transfer structure. */ + +static void +utdequeue (q) + struct stransfer *q; +{ + if (q->pqqueue != NULL) + { + if (*(q->pqqueue) == q) + { + if (q->qnext == q) + *(q->pqqueue) = NULL; + else + *(q->pqqueue) = q->qnext; + } + q->pqqueue = NULL; + } + if (q->qprev != NULL) + q->qprev->qnext = q->qnext; + if (q->qnext != NULL) + q->qnext->qprev = q->qprev; + q->qprev = NULL; + q->qnext = NULL; +} + +/* Queue up a transfer structure requested by the local system. */ + +/*ARGSIGNORED*/ +boolean +fqueue_local (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ + utdequeue (qtrans); + utqueue (&qTlocal, qtrans, FALSE); + return TRUE; +} + +/* Queue up a transfer structure requested by the remote system. The + stransfer structure should have the iremote field set. We need to + record it, so that any subsequent data associated with this + channel can be routed to the right place. */ + +boolean +fqueue_remote (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fqueue_remote: Channel %d", + qtrans->iremote); + if (qtrans->iremote > 0) + aqTremote[qtrans->iremote] = qtrans; + utdequeue (qtrans); + utqueue (&qTremote, qtrans, FALSE); + + /* We just received data for this transfer, so start charging. */ + return ftcharge (qdaemon, qtrans, FALSE, FALSE); +} + +/* Queue up a transfer with something to send. */ + +boolean +fqueue_send (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ +#if DEBUG > 0 + if (qtrans->psendfn == NULL) + ulog (LOG_FATAL, "fqueue_send: Bad call"); +#endif + utdequeue (qtrans); + utqueue (&qTsend, qtrans, FALSE); + + /* Since we're now going to wait to send data, don't charge this + transfer for receive time. */ + if (qtrans == sTreceive.qtrans) + return ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, FALSE); + return TRUE; +} + +/* Queue up a transfer with something to receive. */ + +boolean +fqueue_receive (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ +#if DEBUG > 0 + if (qtrans->precfn == NULL) + ulog (LOG_FATAL, "fqueue_receive: Bad call"); +#endif + utdequeue (qtrans); + utqueue (&qTreceive, qtrans, FALSE); + + /* Since we are now going to wait to receive data, don't charge this + transfer for send time. */ + if (qtrans == sTsend.qtrans) + return ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, FALSE); + return TRUE; +} + +/* Get a new local channel number. */ + +static void +utchanalc (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ + do + { + ++iTchan; + if (iTchan > qdaemon->qproto->cchans) + iTchan = 1; + } + while (aqTchan[iTchan] != NULL); + + qtrans->ilocal = iTchan; + aqTchan[iTchan] = qtrans; + ++cTchans; +} + +/* Return the transfer for a channel number. */ + +__inline__ +static struct stransfer * +qtchan (ic) + int ic; +{ + return aqTchan[ic]; +} + +/* Clear the channel number for a transfer. */ + +__inline__ +static void +utchanfree (qt) + struct stransfer *qt; +{ + if (qt->ilocal != 0) + { + aqTchan[qt->ilocal] = NULL; + qt->ilocal = 0; + --cTchans; + } +} + +/* Allocate a new transfer structure. */ + +struct stransfer * +qtransalc (qcmd) + struct scmd *qcmd; +{ + register struct stransfer *q; + + q = qTavail; + if (q != NULL) + utdequeue (q); + else + q = (struct stransfer *) xmalloc (sizeof (struct stransfer)); + q->qnext = NULL; + q->qprev = NULL; + q->pqqueue = NULL; + q->psendfn = NULL; + q->precfn = NULL; + q->pinfo = NULL; + q->fsendfile = FALSE; + q->frecfile = FALSE; + q->e = EFILECLOSED; + q->ipos = 0; + q->fcmd = FALSE; + q->zcmd = NULL; + q->ccmd = 0; + q->ilocal = 0; + q->iremote = 0; + if (qcmd != NULL) + { + q->s = *qcmd; + q->s.zfrom = zbufcpy (qcmd->zfrom); + q->s.zto = zbufcpy (qcmd->zto); + q->s.zuser = zbufcpy (qcmd->zuser); + q->s.zoptions = zbufcpy (qcmd->zoptions); + q->s.ztemp = zbufcpy (qcmd->ztemp); + q->s.znotify = zbufcpy (qcmd->znotify); + q->s.zcmd = zbufcpy (qcmd->zcmd); + } + else + { + q->s.zfrom = NULL; + q->s.zto = NULL; + q->s.zuser = NULL; + q->s.zoptions = NULL; + q->s.ztemp = NULL; + q->s.znotify = NULL; + q->s.zcmd = NULL; + } + q->isecs = 0; + q->imicros = 0; + q->cbytes = 0; + + return q; +} + +/* Free a transfer structure. This does not free any pinfo + information that may have been allocated. */ + +void +utransfree (q) + struct stransfer *q; +{ + ubuffree (q->zcmd); + ubuffree ((char *) q->s.zfrom); + ubuffree ((char *) q->s.zto); + ubuffree ((char *) q->s.zuser); + ubuffree ((char *) q->s.zoptions); + ubuffree ((char *) q->s.ztemp); + ubuffree ((char *) q->s.znotify); + ubuffree ((char *) q->s.zcmd); + + utchanfree (q); + if (q->iremote > 0) + { + aqTremote[q->iremote] = NULL; + q->iremote = 0; + } + +#if DEBUG > 0 + q->zcmd = NULL; + q->s.zfrom = NULL; + q->s.zto = NULL; + q->s.zuser = NULL; + q->s.zoptions = NULL; + q->s.ztemp = NULL; + q->s.znotify = NULL; + q->s.zcmd = NULL; + q->psendfn = NULL; + q->precfn = NULL; +#endif + + /* Don't try to charge time to this structure any longer. */ + if (sTsend.qtrans == q) + sTsend.qtrans = NULL; + if (sTreceive.qtrans == q) + sTreceive.qtrans = NULL; + + utdequeue (q); + utqueue (&qTavail, q, FALSE); +} + +/* Handle timing of file tranfers. This is called when processing + starts for a transfer structure. All time up to the next call to + this function is charged to that transfer structure. Sending time + and receiving time are charged separately. Normally if we are + about to start charging the same structure we are already charging, + we do nothing; but if the fforce argument is TRUE, we charge the + time anyhow. */ + +static boolean +ftcharge (qdaemon, qtrans, fsend, fforce) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fsend; + boolean fforce; +{ + struct scharge *qcharge, *qother; + long inextsecs, inextmicros; + + if (fsend) + { + qcharge = &sTsend; + qother = &sTreceive; + } + else + { + qcharge = &sTreceive; + qother = &sTsend; + } + + if (! fforce && qtrans == qcharge->qtrans) + return TRUE; + + inextsecs = ixsysdep_process_time (&inextmicros); + if (qcharge->qtrans != NULL) + { + qcharge->qtrans->isecs += inextsecs - qcharge->isecs; + qcharge->qtrans->imicros += inextmicros - qcharge->imicros; + + /* If we are charging the same structure for both send and + receive, update the time we are not currently charging so + that we don't charge twice for the same time. */ + if (qcharge->qtrans == qother->qtrans) + { + qother->isecs = inextsecs; + qother->imicros = inextmicros; + } + } + + qcharge->qtrans = qtrans; + qcharge->isecs = inextsecs; + qcharge->imicros = inextmicros; + + /* If enough time has elapsed since the last time we checked the + queue, check it again. We do this here because we have already + gone to the trouble of getting the time. */ + if (inextsecs - iTchecktime >= CCHECKWAIT) + { + if (! fcheck_queue (qdaemon)) + return FALSE; + } + + return TRUE; +} + + +/* Gather local commands and queue them up for later processing. Also + recompute time based control values. */ + +boolean +fqueue (qdaemon, pfany) + struct sdaemon *qdaemon; + boolean *pfany; +{ + const struct uuconf_system *qsys; + int bgrade; + struct uuconf_timespan *qlocal_size, *qremote_size; + + if (pfany != NULL) + *pfany = FALSE; + + qsys = qdaemon->qsys; + + /* If we are not the caller, the grade will be set during the + initial handshake. */ + if (! qdaemon->fcaller) + bgrade = qdaemon->bgrade; + else + { + long ival; + + if (! ftimespan_match (qsys->uuconf_qtimegrade, &ival, + (int *) NULL)) + bgrade = '\0'; + else + bgrade = (char) ival; + } + + /* Determine the maximum sizes we can send and receive. */ + if (qdaemon->fcaller) + { + qlocal_size = qsys->uuconf_qcall_local_size; + qremote_size = qsys->uuconf_qcall_remote_size; + } + else + { + qlocal_size = qsys->uuconf_qcalled_local_size; + qremote_size = qsys->uuconf_qcalled_remote_size; + } + + if (! ftimespan_match (qlocal_size, &qdaemon->clocal_size, (int *) NULL)) + qdaemon->clocal_size = (long) -1; + if (! ftimespan_match (qremote_size, &qdaemon->cremote_size, (int *) NULL)) + qdaemon->cremote_size = (long) -1; + + if (bgrade == '\0') + return TRUE; + + if (! fsysdep_get_work_init (qsys, bgrade)) + return FALSE; + + while (TRUE) + { + struct scmd s; + + if (! fsysdep_get_work (qsys, bgrade, &s)) + return FALSE; + + if (s.bcmd == 'H') + { + ulog_user ((const char *) NULL); + break; + } + + if (s.bcmd == 'P') + { + struct stransfer *qtrans; + + /* A poll file. */ + ulog_user ((const char *) NULL); + qtrans = qtransalc (&s); + qtrans->psendfn = flocal_poll_file; + if (! fqueue_local (qdaemon, qtrans)) + return FALSE; + continue; + } + + ulog_user (s.zuser); + + switch (s.bcmd) + { + case 'S': + case 'E': + if (! flocal_send_file_init (qdaemon, &s)) + return FALSE; + break; + case 'R': + if (! flocal_rec_file_init (qdaemon, &s)) + return FALSE; + break; + case 'X': + if (! flocal_xcmd_init (qdaemon, &s)) + return FALSE; + break; +#if DEBUG > 0 + default: + ulog (LOG_FATAL, "fqueue: Can't happen"); + break; +#endif + } + } + + if (pfany != NULL) + *pfany = qTlocal != NULL; + + iTchecktime = ixsysdep_process_time ((long *) NULL); + + return TRUE; +} + +/* Clear everything off the work queue. This is used when the call is + complete, or if the call is never made. */ + +void +uclear_queue (qdaemon) + struct sdaemon *qdaemon; +{ + int i; + + usysdep_get_work_free (qdaemon->qsys); + + qTlocal = NULL; + qTremote = NULL; + qTsend = NULL; + qTreceive = NULL; + cTchans = 0; + iTchan = 0; + sTsend.qtrans = NULL; + sTreceive.qtrans = NULL; + cTcmdlen = 0; + qTreceive_ack = NULL; + for (i = 0; i < IMAX_CHAN + 1; i++) + { + aqTchan[i] = NULL; + aqTremote[i] = NULL; + } +} + +/* Recheck the work queue during a conversation. This is only called + if it's been more than CCHECKWAIT seconds since the last time the + queue was checked. */ + +static boolean +fcheck_queue (qdaemon) + struct sdaemon *qdaemon; +{ + int cchans; + + /* Only check if we are the master, or if there are multiple + channels, or if we aren't already trying to get the other side to + hang up. Otherwise, there's nothing we can do with any new jobs + we might find. */ + if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0) + cchans = 1; + else + cchans = qdaemon->qproto->cchans; + if (qdaemon->fmaster + || cchans > 1 + || ! qdaemon->frequest_hangup) + { + boolean fany; + + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, + "fcheck_queue: Rechecking work queue"); + if (! fqueue (qdaemon, &fany)) + return FALSE; + + /* If we found something to do, and we're not the master, and we + don't have multiple channels to send new jobs over, try to + get the other side to hang up. */ + if (fany && ! qdaemon->fmaster && cchans <= 1) + qdaemon->frequest_hangup = TRUE; + } + + return TRUE; +} + +/* The main transfer loop. The uucico daemon spends essentially all + its time in this function. */ + +boolean +floop (qdaemon) + struct sdaemon *qdaemon; +{ + int cchans; + boolean fret; + + /* If we are using a half-duplex line, act as though we have only a + single channel; otherwise we might start a send and a receive at + the same time. */ + if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0) + cchans = 1; + else + cchans = qdaemon->qproto->cchans; + + fret = TRUE; + + while (! qdaemon->fhangup) + { + register struct stransfer *q; + +#if DEBUG > 1 + /* If we're doing any debugging, close the log and debugging + files regularly. This will let people copy them off and + remove them while the conversation is in progresss. */ + if (iDebug != 0) + { + ulog_close (); + ustats_close (); + } +#endif + + if (qdaemon->fmaster) + { + boolean fhangup; + + /* We've managed to become the master, so we no longer want + to request a hangup. */ + qdaemon->frequest_hangup = FALSE; + + fhangup = FALSE; + + if (qdaemon->fhangup_requested + && qTsend == NULL) + { + /* The remote system has requested that we transfer + control by sending CYM after receiving a file. */ + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, + "floop: Transferring control at remote request"); + fhangup = TRUE; + } + else if (qTremote == NULL + && qTlocal == NULL + && qTsend == NULL + && qTreceive == NULL) + { + /* We don't have anything to do. Try to find some new + jobs. If we can't, transfer control. */ + if (! fqueue (qdaemon, (boolean *) NULL)) + { + fret = FALSE; + break; + } + if (qTlocal == NULL) + { + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, + "floop: No work for master"); + fhangup = TRUE; + } + } + + if (fhangup) + { + if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, "H", 0, 0)) + { + fret = FALSE; + break; + } + qdaemon->fmaster = FALSE; + } + } + + /* If we are no long the master, clear any requested hangup. We + may have already hung up before checking this variable in the + block above. */ + if (! qdaemon->fmaster) + qdaemon->fhangup_requested = FALSE; + + /* Immediately queue up any remote jobs. We don't need local + channel numbers for them, since we can disambiguate based on + the remote channel number. */ + while (qTremote != NULL) + { + q = qTremote; + utdequeue (q); + utqueue (&qTsend, q, TRUE); + } + + /* If we are the master, or if we have multiple channels, try to + queue up additional local jobs. */ + if (qdaemon->fmaster || cchans > 1) + { + while (qTlocal != NULL && cTchans < cchans) + { + /* We have room for an additional channel. */ + q = qTlocal; + if (! fqueue_send (qdaemon, q)) + { + fret = FALSE; + break; + } + utchanalc (qdaemon, q); + } + if (! fret) + break; + } + + q = qTsend; + + if (q == NULL) + { + ulog_user ((const char *) NULL); + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: Waiting for data"); + if (! (*qdaemon->qproto->pfwait) (qdaemon)) + { + fret = FALSE; + break; + } + } + else + { + ulog_user (q->s.zuser); + + if (! q->fsendfile) + { + if (! ftcharge (qdaemon, q, TRUE, TRUE)) + { + fret = FALSE; + break; + } + + if (! (*q->psendfn) (q, qdaemon)) + { + fret = FALSE; + break; + } + } + else + { + if (! ftcharge (qdaemon, q, TRUE, FALSE)) + { + fret = FALSE; + break; + } + + if (q->zlog != NULL) + { + ulog (LOG_NORMAL, "%s", q->zlog); + ubuffree (q->zlog); + q->zlog = NULL; + } + + /* We can read the file in a tight loop until qTremote + changes or until we have transferred the entire file. + We can disregard any changes to qTlocal since we + already have something to send anyhow. */ + while (qTremote == NULL) + { + char *zdata; + size_t cdata; + long ipos; + + zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); + if (zdata == NULL) + { + fret = FALSE; + break; + } + + if (ffileeof (q->e)) + cdata = 0; + else + { + cdata = cfileread (q->e, zdata, cdata); + if (ffilereaderror (q->e, cdata)) + { + /* There is no way to report a file reading + error, so we just drop the connection. */ + ulog (LOG_ERROR, "read: %s", strerror (errno)); + fret = FALSE; + break; + } + } + + ipos = q->ipos; + q->ipos += cdata; + q->cbytes += cdata; + + if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, + cdata, q->ilocal, + q->iremote, ipos)) + { + fret = FALSE; + break; + } + + /* It is possible that this transfer has just been + cancelled. */ + if (q != qTsend || ! q->fsendfile) + break; + + if (cdata == 0) + { + /* We must update the time now, because this + call may make an entry in the statistics + file. */ + if (! ftcharge (qdaemon, q, TRUE, TRUE)) + fret = FALSE; + q->fsendfile = FALSE; + if (! (*q->psendfn) (q, qdaemon)) + fret = FALSE; + break; + } + } + + if (! fret) + break; + } + } + } + + ulog_user ((const char *) NULL); + + (void) (*qdaemon->qproto->pfshutdown) (qdaemon); + + if (fret) + uwindow_acked (qdaemon, TRUE); + else + ufailed (qdaemon); + + return fret; +} + +/* This is called by the protocol routines when they have received + some data. If pfexit is not NULL, *pfexit should be set to TRUE if + the protocol receive loop should exit back to the main floop + routine, above. It is only important to set *pfexit to TRUE if the + main loop called the pfwait entry point, so we need never set it to + TRUE if we just receive data for a file. This routine never sets + *pfexit to FALSE. */ + +boolean +fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos, + fallacked, pfexit) + 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; +{ + struct stransfer *q; + int cwrote; + boolean fret; + + if (fallacked && qTreceive_ack != NULL) + uwindow_acked (qdaemon, TRUE); + + /* Now we have to decide which transfer structure gets the data. If + ilocal is -1, it means that the protocol does not know where to + route the data. In that case we route it to the first transfer + that is waiting for data, or, if none, as a new command. If + ilocal is 0, we either select based on the remote channel number + or we have a new command. */ + if (ilocal == -1 && qTreceive != NULL) + q = qTreceive; + else if (ilocal == 0 && iremote > 0 && aqTremote[iremote] != NULL) + q = aqTremote[iremote]; + else if (ilocal <= 0) + { + const char *znull; + + ulog_user ((const char *) NULL); + + /* This data is part of a command. If there is no null + character in the data, this string will be continued by the + next packet. Otherwise this must be the last string in the + command, and we don't care about what comes after the null + byte. */ + znull = (const char *) memchr (zfirst, '\0', cfirst); + if (znull != NULL) + fret = ftadd_cmd (qdaemon, zfirst, (size_t) (znull - zfirst), + iremote, TRUE); + else + { + fret = ftadd_cmd (qdaemon, zfirst, cfirst, iremote, FALSE); + if (fret && csecond > 0) + { + znull = (const char *) memchr (zsecond, '\0', csecond); + if (znull != NULL) + fret = ftadd_cmd (qdaemon, zsecond, + (size_t) (znull - zsecond), iremote, TRUE); + else + fret = ftadd_cmd (qdaemon, zsecond, csecond, iremote, FALSE); + } + } + + if (pfexit != NULL && (qdaemon->fhangup || qTremote != NULL)) + *pfexit = TRUE; + + return fret; + } + else + { + /* Get the transfer structure this data is intended for. */ + + q = qtchan (ilocal); + } + +#if DEBUG > 0 + if (q == NULL || q->precfn == NULL) + { + ulog (LOG_ERROR, "Protocol error: %lu bytes remote %d local %d", + (unsigned long) (cfirst + csecond), + iremote, ilocal); + return FALSE; + } +#endif + + ulog_user (q->s.zuser); + + fret = TRUE; + + /* If we're receiving a command, then accumulate it up to the null + byte. */ + if (q->fcmd) + { + const char *znull; + + znull = NULL; + while (cfirst > 0) + { + size_t cnew; + char *znew; + + znull = (const char *) memchr (zfirst, '\0', cfirst); + if (znull != NULL) + cnew = znull - zfirst; + else + cnew = cfirst; + znew = zbufalc (q->ccmd + cnew + 1); + memcpy (znew, q->zcmd, q->ccmd); + memcpy (znew + q->ccmd, zfirst, cnew); + znew[q->ccmd + cnew] = '\0'; + ubuffree (q->zcmd); + q->zcmd = znew; + q->ccmd += cnew; + + if (znull != NULL) + break; + + zfirst = zsecond; + cfirst = csecond; + csecond = 0; + } + + if (znull != NULL) + { + char *zcmd; + size_t ccmd; + + if (! ftcharge (qdaemon, q, FALSE, TRUE)) + fret = FALSE; + zcmd = q->zcmd; + ccmd = q->ccmd; + q->fcmd = FALSE; + q->zcmd = NULL; + q->ccmd = 0; + if (! (*q->precfn) (q, qdaemon, zcmd, ccmd + 1)) + fret = FALSE; + ubuffree (zcmd); + } + else + { + if (! ftcharge (qdaemon, q, FALSE, FALSE)) + fret = FALSE; + } + + if (pfexit != NULL + && (qdaemon->fhangup + || qdaemon->fmaster + || qTsend != NULL)) + *pfexit = TRUE; + } + else if (! q->frecfile || cfirst == 0) + { + /* We're either not receiving a file or the file transfer is + complete. */ + if (! ftcharge (qdaemon, q, FALSE, TRUE)) + fret = FALSE; + q->frecfile = FALSE; + if (! (*q->precfn) (q, qdaemon, zfirst, cfirst)) + fret = FALSE; + if (fret && csecond > 0) + return fgot_data (qdaemon, zsecond, csecond, + (const char *) NULL, (size_t) 0, + ilocal, iremote, ipos + (long) cfirst, + FALSE, pfexit); + if (pfexit != NULL + && (qdaemon->fhangup + || qdaemon->fmaster + || qTsend != NULL)) + *pfexit = TRUE; + } + else + { + if (! ftcharge (qdaemon, q, FALSE, FALSE)) + fret = FALSE; + + if (q->zlog != NULL) + { + ulog (LOG_NORMAL, "%s", q->zlog); + ubuffree (q->zlog); + q->zlog = NULL; + } + + if (ipos != -1 && ipos != q->ipos) + { + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, + "fgot_data: Seeking to %ld", ipos); + if (! ffileseek (q->e, ipos)) + { + ulog (LOG_ERROR, "seek: %s", strerror (errno)); + fret = FALSE; + } + q->ipos = ipos; + } + + if (fret) + { + while (cfirst > 0) + { + cwrote = cfilewrite (q->e, (char *) zfirst, cfirst); + if (cwrote == cfirst) + { +#if FREE_SPACE_DELTA > 0 + long cfree_space; + + /* Check that there is still enough space on the + disk. If there isn't, we drop the connection, + because we have no way to abort a file transfer + in progress. */ + cfree_space = qdaemon->qsys->uuconf_cfree_space; + if (cfree_space > 0 + && ((q->cbytes / FREE_SPACE_DELTA) + != (q->cbytes + cfirst) / FREE_SPACE_DELTA) + && ! frec_check_free (q, cfree_space)) + { + fret = FALSE; + break; + } +#endif + q->cbytes += cfirst; + q->ipos += cfirst; + } + else + { + if (cwrote < 0) + ulog (LOG_ERROR, "write: %s", strerror (errno)); + else + ulog (LOG_ERROR, + "Wrote %d to file when trying to write %lu", + cwrote, (unsigned long) cfirst); + + /* Any write error is almost certainly a temporary + condition, or else UUCP would not be functioning + at all. If we continue to accept the file, we + will wind up rejecting it at the end (what else + could we do?) and the remote system will throw + away the request. We're better off just dropping + the connection, which is what happens when we + return FALSE, and trying again later. */ + fret = FALSE; + break; + } + + zfirst = zsecond; + cfirst = csecond; + csecond = 0; + } + } + + if (pfexit != NULL && qdaemon->fhangup) + *pfexit = TRUE; + } + + return fret; +} + +/* Accumulate a string into a command. If the command is complete, + start up a new transfer. */ + +static boolean +ftadd_cmd (qdaemon, z, clen, iremote, flast) + struct sdaemon *qdaemon; + const char *z; + size_t clen; + int iremote; + boolean flast; +{ + static char *zbuf; + static size_t cbuf; + size_t cneed; + struct scmd s; + + cneed = cTcmdlen + clen + 1; + if (cneed > cbuf) + { + zbuf = (char *) xrealloc ((pointer) zbuf, cneed); + cbuf = cneed; + } + + memcpy (zbuf + cTcmdlen, z, clen); + zbuf[cTcmdlen + clen] = '\0'; + + if (! flast) + { + cTcmdlen += clen; + return TRUE; + } + + /* Don't save this string for next time. */ + cTcmdlen = 0; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, + "ftadd_cmd: Got command \"%s\"", zbuf); + + if (! fparse_cmd (zbuf, &s)) + { + ulog (LOG_ERROR, "Received garbled command \"%s\"", zbuf); + return TRUE; + } + + if (s.bcmd != 'H' && s.bcmd != 'Y' && s.bcmd != 'N') + ulog_user (s.zuser); + else + ulog_user ((const char *) NULL); + + switch (s.bcmd) + { + case 'S': + case 'E': + return fremote_send_file_init (qdaemon, &s, iremote); + case 'R': + return fremote_rec_file_init (qdaemon, &s, iremote); + case 'X': + return fremote_xcmd_init (qdaemon, &s, iremote); + case 'H': + /* This is a remote request for a hangup. We close the log + files so that they may be moved at this point. */ + ulog_close (); + ustats_close (); + { + struct stransfer *q; + + q = qtransalc ((struct scmd *) NULL); + q->psendfn = fremote_hangup_reply; + q->iremote = iremote; + return fqueue_remote (qdaemon, q); + } + case 'N': + /* This means a hangup request is being denied; we just ignore + this and wait for further commands. */ + return TRUE; + case 'Y': + /* This is a remote confirmation of a hangup. We reconfirm. */ + if (qdaemon->fhangup) + return TRUE; +#if DEBUG > 0 + if (qdaemon->fmaster) + ulog (LOG_ERROR, "Got hangup reply as master"); +#endif + /* Don't check errors rigorously here, since the other side + might jump the gun and hang up. The fLog_sighup variable + will get set TRUE again when the port is closed. */ + fLog_sighup = FALSE; + (void) (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, iremote); + qdaemon->fhangup = TRUE; + return TRUE; +#if DEBUG > 0 + default: + ulog (LOG_FATAL, "ftadd_cmd: Can't happen"); + return FALSE; +#endif + } +} + +/* The remote system is requesting a hang up. If we have something to + do, send an HN. Otherwise send two HY commands (the other side is + presumed to send an HY command between the first and second, but we + don't bother to wait for it) and hang up. */ + +static boolean +fremote_hangup_reply (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + boolean fret; + + utransfree (qtrans); + + if (qTremote == NULL + && qTlocal == NULL + && qTsend == NULL + && qTreceive == NULL) + { + if (! fqueue (qdaemon, (boolean *) NULL)) + return FALSE; + + if (qTlocal == NULL) + { + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: No work"); + fret = ((*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0) + && (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0)); + qdaemon->fhangup = TRUE; + return fret; + } + } + + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: Found work"); + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, "HN", 0, 0); + qdaemon->fmaster = TRUE; + return fret; +} + +/* As described in system.h, we need to keep track of which files have + been successfully received for which we do not know that the other + system has received our acknowledgement. This routine is called to + keep a list of such files. */ + +static struct sreceive_ack *qTfree_receive_ack; + +void +usent_receive_ack (qdaemon, qtrans) + struct sdaemon *qdaemon; + struct stransfer *qtrans; +{ + struct sreceive_ack *q; + + if (qTfree_receive_ack == NULL) + q = (struct sreceive_ack *) xmalloc (sizeof (struct sreceive_ack)); + else + { + q = qTfree_receive_ack; + qTfree_receive_ack = q->qnext; + } + + q->qnext = qTreceive_ack; + q->zto = zbufcpy (qtrans->s.zto); + q->ztemp = zbufcpy (qtrans->s.ztemp); + q->fmarked = FALSE; + + qTreceive_ack = q; +} + +/* This routine is called by the protocol code when either all + outstanding data has been acknowledged or one complete window has + passed. It may be called directly by the protocol, or it may be + called via fgot_data. If one complete window has passed, then all + unmarked receives are marked, and we know that all marked ones have + been acked. */ + +void +uwindow_acked (qdaemon, fallacked) + struct sdaemon *qdaemon; + boolean fallacked; +{ + register struct sreceive_ack **pq; + + pq = &qTreceive_ack; + while (*pq != NULL) + { + if (fallacked || (*pq)->fmarked) + { + struct sreceive_ack *q; + + q = *pq; + (void) fsysdep_forget_reception (qdaemon->qsys, q->zto, + q->ztemp); + ubuffree (q->zto); + ubuffree (q->ztemp); + *pq = q->qnext; + q->qnext = qTfree_receive_ack; + qTfree_receive_ack = q; + } + else + { + (*pq)->fmarked = TRUE; + pq = &(*pq)->qnext; + } + } +} + +/* This routine is called when an error occurred and we are crashing + out of the connection. It is used to report statistics on failed + transfers to the statistics file, and it also discards useless + temporary files for file receptions. Note that the number of bytes + we report as having been sent has little or nothing to do with the + number of bytes the remote site actually received. */ + +void +ufailed (qdaemon) + struct sdaemon *qdaemon; +{ + register struct stransfer *q; + + /* Update the transfer times, but avoid looking in the queue. */ + iTchecktime = ixsysdep_process_time ((long *) NULL); + (void) ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, TRUE); + (void) ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, TRUE); + + if (qTsend != NULL) + { + q = qTsend; + do + { + if ((q->fsendfile || q->frecfile) + && q->cbytes > 0) + ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname, + q->fsendfile, q->cbytes, q->isecs, q->imicros, + FALSE); + if (q->frecfile) + (void) frec_discard_temp (qdaemon, q); + q = q->qnext; + } + while (q != qTsend); + } + + if (qTreceive != NULL) + { + q = qTreceive; + do + { + if ((q->fsendfile || q->frecfile) + && q->cbytes > 0) + ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname, + q->fsendfile, q->cbytes, q->isecs, q->imicros, + FALSE); + if (q->frecfile) + (void) frec_discard_temp (qdaemon, q); + q = q->qnext; + } + while (q != qTreceive); + } +} + +/* When a local poll file is found, it is entered on the queue like + any other job. When it is pulled off the queue, this function is + called. It just calls fsysdep_did_work, which will remove the poll + file. This ensures that poll files are only removed if the system + is actually called. */ + +/*ARGSUSED*/ +static boolean +flocal_poll_file (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + boolean fret; + + fret = fsysdep_did_work (qtrans->s.pseq); + utransfree (qtrans); + return fret; +} diff --git a/gnu/libexec/uucp/uucico/uucico.8 b/gnu/libexec/uucp/uucico/uucico.8 new file mode 100644 index 0000000000..fba8bb588f --- /dev/null +++ b/gnu/libexec/uucp/uucico/uucico.8 @@ -0,0 +1,225 @@ +''' $Id: uucico.8,v 1.1 1993/08/04 19:36:33 jtc Exp $ +.TH uucico 8 "Taylor UUCP 1.04" +.SH NAME +uucico \- UUCP file transfer daemon +.SH SYNOPSIS +.B uucico +[ options ] +.SH DESCRIPTION +The +.I uucico +daemon processes file transfer requests queued by +.I uucp +(1) and +.I uux +(1). It is started when +.I uucp +or +.I uux +is run (unless they are given the +.B \-r +option). It is also typically started periodically using +entries in the +.I crontab +table(s). + +When invoked with the +.B \-r1 +option or the +.B \-s +or +.B \-S +option, the daemon will place a call to a remote system, running in +master mode. +Otherwise the daemon will start in slave mode, accepting a +call from a remote system. Typically a special login name will be set +up for UUCP which automatically invokes +.I uucico +when a call is made. + +When +.I uucico +terminates, it invokes the +.I uuxqt +(8) daemon, unless the +.B \-q +option is given; +.I uuxqt +(8) executes any work orders created by +.I uux +(1) on a remote system, and any work orders created locally which have +received remote files for which they were waiting. + +If a call fails, +.I uucico +will normally refuse to retry the +call until a certain (configurable) amount of time +has passed. This may be overriden by the +.B -f +or the +.B -S +option. + +The +.B \-l +or +.B \-e +option may be used to force +.I uucico +to produce its own prompts of "login: " and "Password:". When another +daemon calls in, it will see these prompts and log in as usual; the +login name and password will be checked against a separate list kept +specially for +.I uucico +rather than the +.I /etc/passwd +file. The +.B \-l +option will prompt once and then exit. The +.B \-e +option will prompt again after the first session is over; in this mode +.I uucico +will permanently control a port. + +If +.I uucico +receives a SIGQUIT, SIGTERM or SIGPIPE signal, it will cleanly abort +any current conversation with a remote system and exit. If it +receives a SIGHUP signal it will abort any current conversation, but +will continue to place calls to (if invoked with +.B \-r1) +and accept calls from (if invoked with +.B \-e) +other systems. If it receives a +SIGINT signal it will finish the current conversation, but will not +place or accept any more calls. +.SH OPTIONS +The following options may be given to +.I uucico. +.TP 5 +.B \-r1 +Start in master mode (call out to a system); implied by +.B \-s +or +.B \-S. +If no system is specified, call any system for which work is waiting +to be done. +.TP 5 +.B \-r0 +Start in slave mode. This is the default. +.TP 5 +.B \-s system +Call the named system. +.TP 5 +.B \-S system +Call the named system, ignoring any required wait. +.TP 5 +.B \-f +Ignore any required wait for any systems to be called. +.TP 5 +.B \-l +Prompt for login name and password using "login: " and "Password:". +This allows +.I uucico +to be easily run from +.I inetd +(8). The login name and password are checked against the UUCP +password file, which has no connection to the file +.I /etc/passwd. +.TP 5 +.B \-p port +Specify a port to call out on or to listen to. In slave mode, this +implies +.B \-e. +.TP 5 +.B \-e +Enter endless loop of login/password prompts and slave mode daemon +execution. The program will not stop by itself; you must use +.I kill +(1) to shut it down. +.TP 5 +.B \-w +After calling out (to a particular system when +.B \-s +or +.B \-S +is specifed, or to all systems which have work when +.B \-r1 +is specifed), begin an endless loop as with +.B \-e. +.TP 5 +.B \-q +Do not start the +.I uuxqt +(8) daemon when finished. +.TP 5 +.B \-c +If no calls are permitted at this time, then don't make the call, but +also do not put an error message in the log file and do not update the +system status (as reported by +.I uustat +(1)). This can be convenient for automated polling scripts, which may +want to simply attempt to call every system rather than worry about +which particular systems may be called at the moment. +.TP 5 +.B \-D +Do not detach from the controlling terminal. Normally +.I uucico +detaches from the terminal before each call out to another system and +before invoking +.I uuxqt. +This option prevents this. +.TP 5 +.B \-x type, \-X type +Turn on particular debugging types. The following types are +recognized: abnormal, chat, handshake, uucp-proto, proto, port, +config, spooldir, execute, incoming, outgoing. + +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. + +The debugging output is sent to the debugging file, usually one of +/usr/spool/uucp/Debug, /usr/spool/uucp/DEBUG, or +/usr/spool/uucp/.Admin/audit.local. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I uucico +was compiled. +.TP 5 +.B \-u login +This option is ignored. It is only included because some versions of +uucpd invoke +.I uucico +with it. +.SH FILES +The file names may be changed at compilation time or by the +configuration file, so these are only approximations. + +.br +/usr/lib/uucp/config - Configuration file. +.br +/usr/lib/uucp/passwd - Default UUCP password file. +.br +/usr/spool/uucp - +UUCP spool directory. +.br +/usr/spool/uucp/Log - +UUCP log file. +.br +/usr/spool/uucppublic - +Default UUCP public directory. +.br +/usr/spool/uucp/Debug - +Debugging file. +.SH SEE ALSO +kill(1), uucp(1), uux(1), uustat(1), uuxqt(8) +.SH AUTHOR +Ian Lance Taylor +(ian@airs.com or uunet!airs!ian) diff --git a/gnu/libexec/uucp/uucico/uucico.c b/gnu/libexec/uucp/uucico/uucico.c new file mode 100644 index 0000000000..ecd6c235c8 --- /dev/null +++ b/gnu/libexec/uucp/uucico/uucico.c @@ -0,0 +1,2618 @@ +/* uucico.c + This is the main UUCP communication program. + + 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 uucico_rcsid[] = "$Id: uucico.c,v 1.1 1993/08/04 19:36:34 jtc Exp $"; +#endif + +#include + +#if HAVE_LIMITS_H +#include +#else +#define LONG_MAX 2147483647L +#endif + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "prot.h" +#include "trans.h" +#include "system.h" + +/* The program name. */ +char abProgram[] = "uucico"; + +/* Define the known protocols. */ + +#define TCP_PROTO \ + (UUCONF_RELIABLE_ENDTOEND \ + | UUCONF_RELIABLE_RELIABLE \ + | UUCONF_RELIABLE_EIGHT) + +static const struct sprotocol asProtocols[] = +{ + { 't', TCP_PROTO, 1, + asTproto_params, ftstart, ftshutdown, ftsendcmd, ztgetspace, + ftsenddata, ftwait, ftfile }, + { 'e', TCP_PROTO, 1, + asEproto_params, festart, feshutdown, fesendcmd, zegetspace, + fesenddata, fewait, fefile }, + { 'i', UUCONF_RELIABLE_EIGHT, 7, + asIproto_params, fistart, fishutdown, fisendcmd, zigetspace, + fisenddata, fiwait, NULL }, + { 'a', UUCONF_RELIABLE_EIGHT, 1, + asZproto_params, fzstart, fzshutdown, fzsendcmd, zzgetspace, + fzsenddata, fzwait, fzfile }, + { 'g', UUCONF_RELIABLE_EIGHT, 1, + asGproto_params, fgstart, fgshutdown, fgsendcmd, zggetspace, + fgsenddata, fgwait, NULL }, + { 'G', UUCONF_RELIABLE_EIGHT, 1, + asGproto_params, fbiggstart, fgshutdown, fgsendcmd, zggetspace, + fgsenddata, fgwait, NULL }, + { 'j', UUCONF_RELIABLE_EIGHT, 7, + asIproto_params, fjstart, fjshutdown, fisendcmd, zigetspace, + fisenddata, fiwait, NULL }, + { 'f', UUCONF_RELIABLE_RELIABLE, 1, + asFproto_params, ffstart, ffshutdown, ffsendcmd, zfgetspace, + ffsenddata, ffwait, fffile }, +}; + +#define CPROTOCOLS (sizeof asProtocols / sizeof asProtocols[0]) + +/* Locked system. */ +static boolean fLocked_system; +static struct uuconf_system sLocked_system; + +/* Daemon structure holding information about the remote system (must + be global so the error handler can see it. */ +static struct sdaemon sDaemon; + +/* Open connection. */ +static struct sconnection *qConn; + +/* uuconf global pointer; need to close the connection after a fatal + error. */ +static pointer pUuconf; + +/* This structure is passed to iuport_lock via uuconf_find_port. */ +struct spass +{ + boolean fmatched; + boolean flocked; + struct sconnection *qconn; +}; + +/* Local functions. */ + +static void uusage P((void)); +static void uabort P((void)); +static boolean fcall P((pointer puuconf, + const struct uuconf_system *qsys, + struct uuconf_port *qport, boolean fifwork, + boolean fforce, boolean fdetach, + boolean ftimewarn)); +static boolean fconn_call P((struct sdaemon *qdaemon, + struct uuconf_port *qport, + struct sstatus *qstat, int cretry, + boolean *pfcalled)); +static boolean fdo_call P((struct sdaemon *qdaemon, + struct sstatus *qstat, + const struct uuconf_dialer *qdialer, + boolean *pfcalled, enum tstatus_type *pterr)); +static int iuport_lock P((struct uuconf_port *qport, pointer pinfo)); +static boolean flogin_prompt P((pointer puuconf, + struct sconnection *qconn)); +static boolean faccept_call P((pointer puuconf, const char *zlogin, + struct sconnection *qconn, + const char **pzsystem)); +static void uapply_proto_params P((pointer puuconf, int bproto, + struct uuconf_cmdtab *qcmds, + struct uuconf_proto_param *pas)); +static boolean fsend_uucp_cmd P((struct sconnection *qconn, + const char *z)); +static char *zget_uucp_cmd P((struct sconnection *qconn, + boolean frequired)); +static char *zget_typed_line P((struct sconnection *qconn)); + +/* Long getopt options. */ +static const struct option asLongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -c: Whether to warn if a call is attempted at a bad time. */ + boolean ftimewarn = TRUE; + /* -D: don't detach from controlling terminal. */ + boolean fdetach = TRUE; + /* -e: Whether to do an endless loop of accepting calls. */ + boolean fendless = FALSE; + /* -f: Whether to force a call despite status of previous call. */ + boolean fforce = FALSE; + /* -I file: configuration file name. */ + const char *zconfig = NULL; + /* -l: Whether to give a single login prompt. */ + boolean flogin = FALSE; + /* -P port: port to use; in master mode, call out on this port. In + slave mode, accept logins on this port. If port not specified, + then in master mode figure it out for each system, and in slave + mode use stdin and stdout. */ + const char *zport = NULL; + /* -q: Whether to start uuxqt when done. */ + boolean fuuxqt = TRUE; + /* -r1: Whether we are the master. */ + boolean fmaster = FALSE; + /* -s,-S system: system to call. */ + const char *zsystem = NULL; + /* -w: Whether to wait for a call after doing one. */ + boolean fwait = FALSE; + int iopt; + struct uuconf_port *qport; + struct uuconf_port sport; + boolean fret = TRUE; + pointer puuconf; + int iuuconf; +#if DEBUG > 1 + int iholddebug; +#endif + + while ((iopt = getopt_long (argc, argv, + "cDefI:lp:qr:s:S:u:x:X:w", + asLongopts, (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'c': + /* Don't warn if a call is attempted at a bad time. */ + ftimewarn = FALSE; + break; + + case 'D': + /* Don't detach from controlling terminal. */ + fdetach = FALSE; + break; + + case 'e': + /* Do an endless loop of accepting calls. */ + fendless = TRUE; + break; + + case 'f': + /* Force a call even if it hasn't been long enough since the last + failed call. */ + fforce = TRUE; + break; + + case 'I': + /* Set configuration file name (default is in sysdep.h). */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'l': + /* Prompt for login name and password. */ + flogin = TRUE; + break; + + case 'p': + /* Port to use */ + zport = optarg; + break; + + case 'q': + /* Don't start uuxqt. */ + fuuxqt = FALSE; + break; + + case 'r': + /* Set mode: -r1 for master, -r0 for slave (default) */ + if (strcmp (optarg, "1") == 0) + fmaster = TRUE; + else if (strcmp (optarg, "0") == 0) + fmaster = FALSE; + else + uusage (); + break; + + case 's': + /* Set system name */ + zsystem = optarg; + fmaster = TRUE; + break; + + case 'S': + /* Set system name and force call like -f */ + zsystem = optarg; + fforce = TRUE; + fmaster = TRUE; + break; + + case 'u': + /* Some versions of uucpd invoke uucico with a -u argument + specifying the login name. I'm told it is safe to ignore + this value, although perhaps we should use it rather than + zsysdep_login_name (). */ + break; + + case 'x': + case 'X': +#if DEBUG > 1 + /* Set debugging level */ + iDebug |= idebug_parse (optarg); +#endif + break; + + case 'w': + /* Call out and then wait for a call in */ + fwait = TRUE; + break; + + case 0: + /* Long option found, and flag value set. */ + break; + + default: + uusage (); + break; + } + } + + if (optind != argc) + uusage (); + + if (fwait && zport == NULL) + { + ulog (LOG_ERROR, "-w requires -e"); + uusage (); + } + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + pUuconf = 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 + + /* If a port was named, get its information. */ + if (zport == NULL) + qport = NULL; + else + { + iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0, + (int (*) P((struct uuconf_port *, + pointer))) NULL, + (pointer) NULL, &sport); + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_FATAL, "%s: Port not found", zport); + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + qport = &sport; + } + +#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 + + usysdep_initialize (puuconf, INIT_SUID); + + ulog_to_file (puuconf, TRUE); + ulog_fatal_fn (uabort); + + if (fmaster) + { + if (zsystem != NULL) + { + /* A system was named. Call it. */ + iuuconf = uuconf_system_info (puuconf, zsystem, + &sLocked_system); + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_FATAL, "%s: System not found", zsystem); + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + /* Detach from the controlling terminal for the call. This + probably makes sense only on Unix. We want the modem + line to become the controlling terminal. */ + if (fdetach && + (qport == NULL + || qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)) + usysdep_detach (); + + ulog_system (sLocked_system.uuconf_zname); + +#if DEBUG > 1 + iholddebug = iDebug; + if (sLocked_system.uuconf_zdebug != NULL) + iDebug |= idebug_parse (sLocked_system.uuconf_zdebug); +#endif + + if (! fsysdep_lock_system (&sLocked_system)) + { + ulog (LOG_ERROR, "System already locked"); + fret = FALSE; + } + else + { + fLocked_system = TRUE; + fret = fcall (puuconf, &sLocked_system, qport, FALSE, + fforce, fdetach, ftimewarn); + if (fLocked_system) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + } + } +#if DEBUG > 1 + iDebug = iholddebug; +#endif + ulog_system ((const char *) NULL); + (void) uuconf_system_free (puuconf, &sLocked_system); + } + else + { + char **pznames, **pz; + int c, i; + boolean fdidone; + + /* Call all systems which have work to do. */ + fret = TRUE; + fdidone = FALSE; + + iuuconf = uuconf_system_names (puuconf, &pznames, 0); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + /* Randomize the order in which we call the systems. */ + c = 0; + for (pz = pznames; *pz != NULL; pz++) + c++; + + srand ((unsigned int) ixsysdep_time ((long *) NULL)); + for (i = c - 1; i > 0; i--) + { + int iuse; + char *zhold; + + iuse = rand () % (i + 1); + zhold = pznames[i]; + pznames[i] = pznames[iuse]; + pznames[iuse] = zhold; + } + + for (pz = pznames; *pz != NULL && ! FGOT_SIGNAL (); pz++) + { + iuuconf = uuconf_system_info (puuconf, *pz, + &sLocked_system); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + xfree ((pointer) *pz); + continue; + } + + if (fsysdep_has_work (&sLocked_system)) + { + fdidone = TRUE; + + /* Detach from the controlling terminal. On Unix + this means that we will wind up forking a new + process for each system we call. */ + if (fdetach + && (qport == NULL + || qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)) + usysdep_detach (); + + ulog_system (sLocked_system.uuconf_zname); + +#if DEBUG > 1 + iholddebug = iDebug; + if (sLocked_system.uuconf_zdebug != NULL) + iDebug |= idebug_parse (sLocked_system.uuconf_zdebug); +#endif + + if (! fsysdep_lock_system (&sLocked_system)) + { + ulog (LOG_ERROR, "System already locked"); + fret = FALSE; + } + else + { + fLocked_system = TRUE; + if (! fcall (puuconf, &sLocked_system, qport, TRUE, + fforce, fdetach, ftimewarn)) + fret = FALSE; + + /* Now ignore any SIGHUP that we got. */ + afSignal[INDEXSIG_SIGHUP] = FALSE; + + if (fLocked_system) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + } + } +#if DEBUG > 1 + iDebug = iholddebug; +#endif + ulog_system ((const char *) NULL); + } + + (void) uuconf_system_free (puuconf, &sLocked_system); + xfree ((pointer) *pz); + } + + xfree ((pointer) pznames); + + if (! fdidone) + ulog (LOG_NORMAL, "No work"); + } + + /* If requested, wait for calls after dialing out. */ + if (fwait) + { + fendless = TRUE; + fmaster = FALSE; + } + } + + if (! fmaster) + { + struct sconnection sconn; + boolean flocked; + + /* If a port was specified by name, we go into endless loop + mode. In this mode, we wait for calls and prompt them with + "login:" and "Password:", so that they think we are a regular + UNIX system. If we aren't in endless loop mode, we have been + called by some other system. If flogin is TRUE, we prompt + with "login:" and "Password:" a single time. */ + + fret = TRUE; + zsystem = NULL; + + if (! fconn_init (qport, &sconn)) + fret = FALSE; + + if (qport != NULL) + { + /* We are not using standard input. Detach from the + controlling terminal, so that the port we are about to + use becomes our controlling terminal. */ + if (fdetach + && qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) + usysdep_detach (); + + /* If a port was given, we loop forever. */ + fendless = TRUE; + } + + if (fconn_lock (&sconn, TRUE)) + flocked = TRUE; + else + { + flocked = FALSE; + ulog (LOG_ERROR, "%s: Port already locked", + qport->uuconf_zname); + fret = FALSE; + } + + if (fret) + { + if (! fconn_open (&sconn, (long) 0, (long) 0, TRUE)) + fret = FALSE; + qConn = &sconn; + } + + if (fret) + { + if (fendless) + { + while (! FGOT_SIGNAL () + && flogin_prompt (puuconf, &sconn)) + { + /* Now ignore any SIGHUP that we got. */ + afSignal[INDEXSIG_SIGHUP] = FALSE; + + if (fLocked_system) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + } + if (! fconn_reset (&sconn)) + break; + } + fret = FALSE; + } + else + { + if (flogin) + fret = flogin_prompt (puuconf, &sconn); + else + { +#if DEBUG > 1 + iholddebug = iDebug; +#endif + fret = faccept_call (puuconf, zsysdep_login_name (), + &sconn, &zsystem); +#if DEBUG > 1 + iDebug = iholddebug; +#endif + } + } + } + + if (qConn != NULL) + { + if (! fconn_close (&sconn, puuconf, (struct uuconf_dialer *) NULL, + fret)) + fret = FALSE; + qConn = NULL; + } + + if (flocked) + (void) fconn_unlock (&sconn); + + if (fLocked_system) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + } + + uconn_free (&sconn); + } + + ulog_close (); + ustats_close (); + + /* If we got a SIGTERM, perhaps because the system is going down, + don't run uuxqt. We go ahead and run it for any other signal, + since I think they indicate more temporary conditions. */ + if (afSignal[INDEXSIG_SIGTERM]) + fuuxqt = FALSE; + + if (fuuxqt) + { + /* Detach from the controlling terminal before starting up uuxqt, + so that it runs as a true daemon. */ + if (fdetach) + usysdep_detach (); + if (zsystem == NULL) + { + if (! fsysdep_run ("uuxqt", (const char *) NULL, + (const char *) NULL)) + fret = FALSE; + } + else + { + if (! fsysdep_run ("uuxqt", "-s", zsystem)) + fret = FALSE; + } + } + + usysdep_exit (fret); + + /* Avoid complaints about not returning. */ + return 0; +} + +/* Print out a usage message. */ + +static void +uusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uucico [options]\n"); + fprintf (stderr, + " -s,-S system: Call system (-S implies -f)\n"); + fprintf (stderr, + " -f: Force call despite system status\n"); + fprintf (stderr, + " -r state: 1 for master, 0 for slave (default)\n"); + fprintf (stderr, + " -p port: Specify port (implies -e)\n"); + fprintf (stderr, + " -l: prompt for login name and password\n"); + fprintf (stderr, + " -e: Endless loop of login prompts and daemon execution\n"); + fprintf (stderr, + " -w: After calling out, wait for incoming calls\n"); + fprintf (stderr, + " -q: Don't start uuxqt when done\n"); + fprintf (stderr, + " -x,-X debug: Set debugging level\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 LOG_FATAL error occurs. */ + +static void +uabort () +{ + if (fLocked_system) + ufailed (&sDaemon); + + ulog_user ((const char *) NULL); + + if (qConn != NULL) + { + (void) fconn_close (qConn, pUuconf, (struct uuconf_dialer *) NULL, + FALSE); + (void) fconn_unlock (qConn); + uconn_free (qConn); + } + + if (fLocked_system) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + } + + ulog_system ((const char *) NULL); + + ulog_close (); + ustats_close (); + + usysdep_exit (FALSE); +} + +/* Call another system, trying all the possible sets of calling + instructions. The qsys argument is the system to call. The qport + argument is the port to use, and may be NULL. If the fifwork + argument is TRUE, the call is only placed if there is work to be + done. If the fforce argument is TRUE, a call is forced even if not + enough time has passed since the last failed call. If the + ftimewarn argument is TRUE (the normal case), then a warning is + given if calls are not permitted at this time. */ + +static boolean +fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn) + pointer puuconf; + const struct uuconf_system *qorigsys; + struct uuconf_port *qport; + boolean fifwork; + boolean fforce; + boolean fdetach; + boolean ftimewarn; +{ + struct sstatus sstat; + long inow; + boolean fbadtime, fnevertime; + const struct uuconf_system *qsys; + + if (! fsysdep_get_status (qorigsys, &sstat, (boolean *) NULL)) + return FALSE; + + /* Make sure it's been long enough since the last failed call, and + that we haven't exceeded the maximum number of retries. Even if + we are over the limit on retries, we permit a call to be made if + 24 hours have passed. This 24 hour limit is still controlled by + the retry time. */ + inow = ixsysdep_time ((long *) NULL); + if (! fforce) + { + if (qorigsys->uuconf_cmax_retries > 0 + && sstat.cretries >= qorigsys->uuconf_cmax_retries + && sstat.ilast + 24 * 60 * 60 < inow) + { + ulog (LOG_ERROR, "Too many retries"); + return FALSE; + } + + if (sstat.ttype == STATUS_COMPLETE + ? sstat.ilast + qorigsys->uuconf_csuccess_wait > inow + : sstat.ilast + sstat.cwait > inow) + { + ulog (LOG_NORMAL, "Retry time not reached"); + return FALSE; + } + } + + sDaemon.puuconf = puuconf; + sDaemon.qsys = NULL; + sDaemon.zlocalname = NULL; + sDaemon.qconn = NULL; + sDaemon.qproto = NULL; + sDaemon.clocal_size = -1; + sDaemon.cremote_size = -1; + sDaemon.cmax_ever = -2; + sDaemon.cmax_receive = -1; + sDaemon.ifeatures = 0; + sDaemon.frequest_hangup = FALSE; + sDaemon.fhangup_requested = FALSE; + sDaemon.fhangup = FALSE; + sDaemon.fmaster = TRUE; + sDaemon.fcaller = TRUE; + sDaemon.ireliable = 0; + sDaemon.bgrade = '\0'; + + fbadtime = TRUE; + fnevertime = TRUE; + + for (qsys = qorigsys; qsys != NULL; qsys = qsys->uuconf_qalternate) + { + int cretry; + boolean fany, fret, fcalled; + + if (FGOT_SIGNAL ()) + return FALSE; + + if (! qsys->uuconf_fcall || qsys->uuconf_qtimegrade == NULL) + continue; + + fnevertime = FALSE; + + /* Make sure this is a legal time to call. */ + if (! ftimespan_match (qsys->uuconf_qtimegrade, (long *) NULL, + &cretry)) + continue; + + sDaemon.qsys = qsys; + + /* Queue up any work there is to do. */ + if (! fqueue (&sDaemon, &fany)) + return FALSE; + + /* If we are only supposed to call if there is work, and there + isn't any work, check the next alternates. We can't give up + at this point because there might be some other alternates + with fewer restrictions on grade or file transfer size. */ + if (fifwork && ! fany) + { + uclear_queue (&sDaemon); + continue; + } + + fbadtime = FALSE; + + fret = fconn_call (&sDaemon, qport, &sstat, cretry, &fcalled); + + uclear_queue (&sDaemon); + + if (fret) + return TRUE; + if (fcalled) + return FALSE; + + /* Now we have to dump that port so that we can aquire a new + one. On Unix this means that we will fork and get a new + process ID, so we must unlock and relock the system. */ + if (fdetach) + { + (void) fsysdep_unlock_system (&sLocked_system); + fLocked_system = FALSE; + usysdep_detach (); + if (! fsysdep_lock_system (&sLocked_system)) + return FALSE; + fLocked_system = TRUE; + } + } + + if (fbadtime && ftimewarn) + { + ulog (LOG_NORMAL, "Wrong time to call"); + + /* Update the status, unless the system can never be called. If + the system can never be called, there is little point to + putting in a ``wrong time to call'' message. We don't change + the number of retries, although we do set the wait until the + next retry to 0. */ + if (! fnevertime) + { + sstat.ttype = STATUS_WRONG_TIME; + sstat.ilast = inow; + sstat.cwait = 0; + (void) fsysdep_set_status (qorigsys, &sstat); + } + } + + return FALSE; +} + +/* Find a port to use when calling a system, open a connection, and + dial the system. The actual call is done in fdo_call. This + routine is responsible for opening and closing the connection. */ + +static boolean +fconn_call (qdaemon, qport, qstat, cretry, pfcalled) + struct sdaemon *qdaemon; + struct uuconf_port *qport; + struct sstatus *qstat; + int cretry; + boolean *pfcalled; +{ + pointer puuconf; + const struct uuconf_system *qsys; + struct uuconf_port sport; + struct sconnection sconn; + enum tstatus_type terr; + boolean fret; + + puuconf = qdaemon->puuconf; + qsys = qdaemon->qsys; + + *pfcalled = FALSE; + + /* Ignore any SIGHUP signal we may have received up to this point. + This is needed on Unix because we may have gotten one from the + shell before we detached from the controlling terminal. */ + afSignal[INDEXSIG_SIGHUP] = FALSE; + + /* If no port was specified on the command line, use any port + defined for the system. To select the system port: 1) see if + port information was specified directly; 2) see if a port was + named; 3) get an available port given the baud rate. We don't + change the system status if a port is unavailable; i.e. we don't + force the system to wait for the retry time. */ + if (qport == NULL) + qport = qsys->uuconf_qport; + if (qport != NULL) + { + if (! fconn_init (qport, &sconn)) + return FALSE; + if (! fconn_lock (&sconn, FALSE)) + { + ulog (LOG_ERROR, "%s: Port already locked", + qport->uuconf_zname); + return FALSE; + } + } + else + { + struct spass s; + int iuuconf; + + s.fmatched = FALSE; + s.flocked = FALSE; + s.qconn = &sconn; + iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport, + qsys->uuconf_ibaud, + qsys->uuconf_ihighbaud, + iuport_lock, (pointer) &s, + &sport); + if (iuuconf == UUCONF_NOT_FOUND) + { + if (s.fmatched) + ulog (LOG_ERROR, "All matching ports in use"); + else + ulog (LOG_ERROR, "No matching ports"); + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + if (s.flocked) + { + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + } + return FALSE; + } + } + + if (! fconn_open (&sconn, qsys->uuconf_ibaud, qsys->uuconf_ihighbaud, + FALSE)) + { + terr = STATUS_PORT_FAILED; + fret = FALSE; + } + else + { + struct uuconf_dialer *qdialer; + struct uuconf_dialer sdialer; + enum tdialerfound tdialer; + + if (qsys->uuconf_zalternate == NULL) + ulog (LOG_NORMAL, "Calling system %s (port %s)", qsys->uuconf_zname, + zLdevice == NULL ? (char *) "unknown" : zLdevice); + else + ulog (LOG_NORMAL, "Calling system %s (alternate %s, port %s)", + qsys->uuconf_zname, qsys->uuconf_zalternate, + zLdevice == NULL ? (char *) "unknown" : zLdevice); + + qdialer = NULL; + + if (! fconn_dial (&sconn, puuconf, qsys, qsys->uuconf_zphone, + &sdialer, &tdialer)) + { + terr = STATUS_DIAL_FAILED; + fret = FALSE; + } + else + { + qdaemon->qconn = &sconn; + if (tdialer == DIALERFOUND_FALSE) + qdialer = NULL; + else + qdialer = &sdialer; + fret = fdo_call (qdaemon, qstat, qdialer, pfcalled, &terr); + } + + (void) fconn_close (&sconn, puuconf, qdialer, fret); + + if (tdialer == DIALERFOUND_FREE) + (void) uuconf_dialer_free (puuconf, &sdialer); + } + + if (! fret) + { + DEBUG_MESSAGE2 (DEBUG_HANDSHAKE, "Call failed: %d (%s)", + (int) terr, azStatus[(int) terr]); + qstat->ttype = terr; + qstat->cretries++; + qstat->ilast = ixsysdep_time ((long *) NULL); + if (cretry == 0) + qstat->cwait = CRETRY_WAIT (qstat->cretries); + else + qstat->cwait = cretry * 60; + (void) fsysdep_set_status (qsys, qstat); + } + + (void) fconn_unlock (&sconn); + uconn_free (&sconn); + + if (qport == NULL) + (void) uuconf_port_free (puuconf, &sport); + + return fret; +} + +/* Do the actual work of calling another system. The qsys argument is + the system to call, the qconn argument is the connection to use, + the qstat argument holds the current status of the ssystem, and the + qdialer argument holds the dialer being used (it may be NULL). If + we log in successfully, set *pfcalled to TRUE; this is used to + distinguish a failed dial from a failure during the call. If an + error occurs *pterr is set to the status type to record. */ + +static boolean +fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr) + struct sdaemon *qdaemon; + struct sstatus *qstat; + const struct uuconf_dialer *qdialer; + boolean *pfcalled; + enum tstatus_type *pterr; +{ + pointer puuconf; + const struct uuconf_system *qsys; + struct sconnection *qconn; + const char *zport; + int iuuconf; + char *zstr; + long istart_time; + char *zlog; + + puuconf = qdaemon->puuconf; + qsys = qdaemon->qsys; + qconn = qdaemon->qconn; + + *pterr = STATUS_LOGIN_FAILED; + + if (qconn->qport == NULL) + zport = "unknown"; + else + zport = qconn->qport->uuconf_zname; + if (! fchat (qconn, puuconf, &qsys->uuconf_schat, qsys, + (const struct uuconf_dialer *) NULL, + (const char *) NULL, FALSE, zport, + iconn_baud (qconn))) + return FALSE; + + *pfcalled = TRUE; + istart_time = ixsysdep_time ((long *) NULL); + + *pterr = STATUS_HANDSHAKE_FAILED; + + /* We should now see "Shere" from the other system. Newer systems + send "Shere=foo" where foo is the remote name. */ + zstr = zget_uucp_cmd (qconn, TRUE); + if (zstr == NULL) + return FALSE; + + if (strncmp (zstr, "Shere", 5) != 0) + { + ulog (LOG_ERROR, "Bad initialization string"); + ubuffree (zstr); + return FALSE; + } + + ulog (LOG_NORMAL, "Login successful"); + + qstat->ttype = STATUS_TALKING; + qstat->ilast = ixsysdep_time ((long *) NULL); + qstat->cretries = 0; + qstat->cwait = 0; + if (! fsysdep_set_status (qsys, qstat)) + return FALSE; + + if (zstr[5] == '=') + { + const char *zheresys; + size_t clen; + int icmp; + + /* Some UUCP packages only provide seven characters in the Shere + machine name. Others only provide fourteen. */ + zheresys = zstr + 6; + clen = strlen (zheresys); + if (clen == 7 || clen == 14) + icmp = strncmp (zheresys, qsys->uuconf_zname, clen); + else + icmp = strcmp (zheresys, qsys->uuconf_zname); + if (icmp != 0) + { + if (qsys->uuconf_pzalias != NULL) + { + char **pz; + + for (pz = qsys->uuconf_pzalias; *pz != NULL; pz++) + { + if (clen == 7 || clen == 14) + icmp = strncmp (zheresys, *pz, clen); + else + icmp = strcmp (zheresys, *pz); + if (icmp == 0) + break; + } + } + if (icmp != 0) + { + ulog (LOG_ERROR, "Called wrong system (%s)", zheresys); + ubuffree (zstr); + return FALSE; + } + } + } +#if DEBUG > 1 + else if (zstr[5] != '\0') + DEBUG_MESSAGE1 (DEBUG_HANDSHAKE, + "fdo_call: Strange Shere: %s", zstr); +#endif + + ubuffree (zstr); + + /* We now send "S" name switches, where name is our UUCP name. If + we are using sequence numbers with this system, we send a -Q + argument with the sequence number. If the call-timegrade command + was used, we send a -p argument and a -vgrade= argument with the + grade to send us (we send both argument to make it more likely + that one is recognized). We always send a -N (for new) switch + indicating what new features we support. */ + { + long ival; + char bgrade; + char *zsend; + boolean fret; + + /* Determine the grade we should request of the other system. A + '\0' means that no restrictions have been made. */ + if (! ftimespan_match (qsys->uuconf_qcalltimegrade, &ival, + (int *) NULL)) + bgrade = '\0'; + else + bgrade = (char) ival; + + /* Determine the name we will call ourselves. */ + if (qsys->uuconf_zlocalname != NULL) + qdaemon->zlocalname = qsys->uuconf_zlocalname; + else + { + iuuconf = uuconf_localname (puuconf, &qdaemon->zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + qdaemon->zlocalname = zsysdep_localname (); + if (qdaemon->zlocalname == NULL) + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + } + + zsend = zbufalc (strlen (qdaemon->zlocalname) + 70); + if (! qsys->uuconf_fsequence) + { + if (bgrade == '\0') + sprintf (zsend, "S%s -R -N0%o", qdaemon->zlocalname, + (unsigned int) (FEATURE_SIZES + | FEATURE_EXEC + | FEATURE_RESTART)); + else + sprintf (zsend, "S%s -p%c -vgrade=%c -R -N0%o", + qdaemon->zlocalname, bgrade, bgrade, + (unsigned int) (FEATURE_SIZES + | FEATURE_EXEC + | FEATURE_RESTART)); + } + else + { + long iseq; + + iseq = ixsysdep_get_sequence (qsys); + if (iseq < 0) + return FALSE; + if (bgrade == '\0') + sprintf (zsend, "S%s -Q%ld -R -N0%o", qdaemon->zlocalname, iseq, + (unsigned int) (FEATURE_SIZES + | FEATURE_EXEC + | FEATURE_RESTART)); + else + sprintf (zsend, "S%s -Q%ld -p%c -vgrade=%c -R -N0%o", + qdaemon->zlocalname, iseq, bgrade, bgrade, + (unsigned int) (FEATURE_SIZES + | FEATURE_EXEC + | FEATURE_RESTART)); + } + + fret = fsend_uucp_cmd (qconn, zsend); + ubuffree (zsend); + if (! fret) + return FALSE; + } + + /* Now we should see ROK or Rreason where reason gives a cryptic + reason for failure. If we are talking to a counterpart, we will + get back ROKN, possibly with a feature bitfield attached. */ + zstr = zget_uucp_cmd (qconn, TRUE); + if (zstr == NULL) + return FALSE; + + if (zstr[0] != 'R') + { + ulog (LOG_ERROR, "Bad reponse to handshake string (%s)", + zstr); + ubuffree (zstr); + return FALSE; + } + + if (strncmp (zstr + 1, "OKN", sizeof "OKN" - 1) == 0) + { + if (zstr[sizeof "ROKN" - 1] == '\0') + qdaemon->ifeatures |= FEATURE_SIZES | FEATURE_V103; + else + qdaemon->ifeatures |= (int) strtol (zstr + sizeof "ROKN" - 1, + (char **) NULL, 0); + } + else if (strncmp (zstr + 1, "OK", sizeof "OK" - 1) == 0) + { + if (zstr[sizeof "ROK" - 1] != '\0') + { + char *zopt; + + /* SVR4 UUCP returns options following the ROK string. */ + zopt = zstr + sizeof "ROK" - 1; + while (*zopt != '\0') + { + char b; + long c; + char *zend; + + b = *zopt++; + if (isspace (b) || b != '-') + continue; + switch (*zopt) + { + case 'R': + qdaemon->ifeatures |= (FEATURE_RESTART + | FEATURE_SVR4 + | FEATURE_SIZES); + break; + case 'U': + c = strtol (zopt, &zend, 0); + if (c > 0 && c <= LONG_MAX / (long) 512) + qdaemon->cmax_receive = c * (long) 512; + zopt = zend; + break; + } + while (*zopt != '\0' && ! isspace (*zopt)) + ++zopt; + } + } + } + else if (strcmp (zstr + 1, "CB") == 0) + { + ulog (LOG_NORMAL, "Remote system will call back"); + qstat->ttype = STATUS_COMPLETE; + (void) fsysdep_set_status (qsys, qstat); + ubuffree (zstr); + return TRUE; + } + else + { + ulog (LOG_ERROR, "Handshake failed (%s)", zstr + 1); + ubuffree (zstr); + return FALSE; + } + + ubuffree (zstr); + + /* The slave should now send \020Pprotos\0 where protos is a list of + supported protocols. Each protocol is a single character. */ + zstr = zget_uucp_cmd (qconn, TRUE); + if (zstr == NULL) + return FALSE; + + if (zstr[0] != 'P') + { + ulog (LOG_ERROR, "Bad protocol handshake (%s)", zstr); + ubuffree (zstr); + return FALSE; + } + + /* Determine the reliability characteristics of the connection by + combining information for the port and the dialer. If we have no + information, default to a reliable eight-bit full-duplex + connection. */ + if (qconn->qport != NULL + && (qconn->qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + qdaemon->ireliable = qconn->qport->uuconf_ireliable; + if (qdialer != NULL + && (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + { + if (qdaemon->ireliable != 0) + qdaemon->ireliable &= qdialer->uuconf_ireliable; + else + qdaemon->ireliable = qdialer->uuconf_ireliable; + } + if (qdaemon->ireliable == 0) + qdaemon->ireliable = (UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX + | UUCONF_RELIABLE_SPECIFIED); + + /* Now decide which protocol to use. The system and the port may + have their own list of protocols. */ + { + int i; + char ab[5]; + + i = CPROTOCOLS; + if (qsys->uuconf_zprotocols != NULL + || (qconn->qport != NULL + && qconn->qport->uuconf_zprotocols != NULL)) + { + const char *zproto; + + if (qsys->uuconf_zprotocols != NULL) + zproto = qsys->uuconf_zprotocols; + else + zproto = qconn->qport->uuconf_zprotocols; + for (; *zproto != '\0'; zproto++) + { + if (strchr (zstr + 1, *zproto) != NULL) + { + for (i = 0; i < CPROTOCOLS; i++) + if (asProtocols[i].bname == *zproto) + break; + if (i < CPROTOCOLS) + break; + } + } + } + else + { + /* If neither the system nor the port specified a list of + protocols, we want only protocols that match the known + reliability of the dialer and the port. */ + for (i = 0; i < CPROTOCOLS; i++) + { + int ipr; + + ipr = asProtocols[i].ireliable; + if ((ipr & qdaemon->ireliable) != ipr) + continue; + if (strchr (zstr + 1, asProtocols[i].bname) != NULL) + break; + } + } + + ubuffree (zstr); + + if (i >= CPROTOCOLS) + { + (void) fsend_uucp_cmd (qconn, "UN"); + ulog (LOG_ERROR, "No mutually supported protocols"); + return FALSE; + } + + qdaemon->qproto = &asProtocols[i]; + + sprintf (ab, "U%c", qdaemon->qproto->bname); + if (! fsend_uucp_cmd (qconn, ab)) + return FALSE; + } + + /* Run any protocol parameter commands. */ + if (qdaemon->qproto->qcmds != NULL) + { + if (qsys->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, qdaemon->qproto->bname, + qdaemon->qproto->qcmds, + qsys->uuconf_qproto_params); + if (qconn->qport != NULL + && qconn->qport->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, qdaemon->qproto->bname, + qdaemon->qproto->qcmds, + qconn->qport->uuconf_qproto_params); + if (qdialer != NULL + && qdialer->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, qdaemon->qproto->bname, + qdaemon->qproto->qcmds, + qdialer->uuconf_qproto_params); + } + + /* Turn on the selected protocol. */ + if (! (*qdaemon->qproto->pfstart) (qdaemon, &zlog)) + return FALSE; + if (zlog == NULL) + { + zlog = zbufalc (sizeof "protocol ''" + 1); + sprintf (zlog, "protocol '%c'", qdaemon->qproto->bname); + } + ulog (LOG_NORMAL, "Handshake successful (%s)", zlog); + ubuffree (zlog); + + *pterr = STATUS_FAILED; + + { + boolean fret; + long iend_time; + + fret = floop (qdaemon); + + /* Now send the hangup message. As the caller, we send six O's + and expect to receive seven O's. We send the six O's twice to + help the other side. We don't worry about errors here. */ + if (fsend_uucp_cmd (qconn, "OOOOOO") + && fsend_uucp_cmd (qconn, "OOOOOO")) + { + int i, fdone; + + /* We look for the remote hangup string to ensure that the + modem has sent out our hangup string. This is only + necessary because some versions of UUCP complain if they + don't get the hangup string. The remote site should send 7 + O's, but some versions of UUCP only send 6. We look for + the string several times because supposedly some + implementations send some garbage after the last packet but + before the hangup string. */ + for (i = 0; i < 25; i++) + { + zstr = zget_uucp_cmd (qconn, FALSE); + if (zstr == NULL) + break; + fdone = strstr (zstr, "OOOOOO") != NULL; + ubuffree (zstr); + if (fdone) + break; + } + } + + iend_time = ixsysdep_time ((long *) NULL); + + ulog (LOG_NORMAL, "Call complete (%ld seconds)", + iend_time - istart_time); + + if (fret) + { + qstat->ttype = STATUS_COMPLETE; + qstat->ilast = iend_time; + (void) fsysdep_set_status (qsys, qstat); + } + + return fret; + } +} + +/* This routine is called via uuconf_find_port when a matching port is + found. It tries to lock the port. If it fails, it returns + UUCONF_NOT_FOUND to force uuconf_find_port to continue searching + for the next matching port. */ + +static int +iuport_lock (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + struct spass *q = (struct spass *) pinfo; + + 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 + { + q->flocked = TRUE; + return UUCONF_SUCCESS; + } +} + +/* Prompt for a login name and a password, and run as the slave. */ + +static boolean +flogin_prompt (puuconf, qconn) + pointer puuconf; + struct sconnection *qconn; +{ + char *zuser, *zpass; + boolean fret; + int iuuconf; + + DEBUG_MESSAGE0 (DEBUG_HANDSHAKE, "flogin_prompt: Waiting for login"); + + zuser = NULL; + do + { + ubuffree (zuser); + if (! fconn_write (qconn, "login: ", sizeof "login: " - 1)) + return FALSE; + zuser = zget_typed_line (qconn); + } + while (zuser != NULL && *zuser == '\0'); + + if (zuser == NULL) + return TRUE; + + if (! fconn_write (qconn, "Password:", sizeof "Password:" - 1)) + { + ubuffree (zuser); + return FALSE; + } + + zpass = zget_typed_line (qconn); + if (zpass == NULL) + { + ubuffree (zuser); + return TRUE; + } + + fret = TRUE; + + iuuconf = uuconf_callin (puuconf, zuser, zpass); + ubuffree (zpass); + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_ERROR, "Bad login"); + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + } + else + { +#if DEBUG > 1 + int iholddebug; +#endif + + /* We ignore the return value of faccept_call because we really + don't care whether the call succeeded or not. We are going + to reset the port anyhow. */ +#if DEBUG > 1 + iholddebug = iDebug; +#endif + (void) faccept_call (puuconf, zuser, qconn, (const char **) NULL); +#if DEBUG > 1 + iDebug = iholddebug; +#endif + } + + ubuffree (zuser); + + return fret; +} + +/* Accept a call from a remote system. If pqsys is not NULL, *pqsys + will be set to the system that called in if known. */ + +static boolean +faccept_call (puuconf, zlogin, qconn, pzsystem) + pointer puuconf; + const char *zlogin; + struct sconnection *qconn; + const char **pzsystem; +{ + long istart_time; + const char *zport; + struct uuconf_port *qport; + struct uuconf_port sport; + int iuuconf; + struct uuconf_dialer *qdialer; + struct uuconf_dialer sdialer; + boolean ftcp_port; + char *zsend, *zspace; + boolean fret; + char *zstr; + struct uuconf_system ssys; + const struct uuconf_system *qsys; + const struct uuconf_system *qany; + char *zloc; + struct sstatus sstat; + boolean fgotseq, fgotn; + int i; + char *zlog; + char *zgrade; + + if (pzsystem != NULL) + *pzsystem = NULL; + + ulog (LOG_NORMAL, "Incoming call (login %s port %s)", zlogin, + zLdevice == NULL ? (char *) "unknown" : zLdevice); + + istart_time = ixsysdep_time ((long *) NULL); + + /* Figure out protocol parameters determined by the port. If no + port was specified we're reading standard input, so try to get + the port name and read information from the port file. We only + use the port information to get protocol parameters; we don't + want to start treating the port as though it were a modem, for + example. */ + if (qconn->qport != NULL) + { + qport = qconn->qport; + zport = qport->uuconf_zname; + ftcp_port = FALSE; + } + else + { + zport = zsysdep_port_name (&ftcp_port); + if (zport == NULL) + { + qport = NULL; + zport = "unknown"; + } + else + { + iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0, + (int (*) P((struct uuconf_port *, + pointer pinfo))) NULL, + (pointer) NULL, + &sport); + if (iuuconf == UUCONF_NOT_FOUND) + qport = NULL; + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + else + qport = &sport; + } + } + + /* If we've managed to figure out that this is a modem port, now try + to get protocol parameters from the dialer. */ + qdialer = NULL; + if (qport != NULL) + { + if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) + { + if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) + { + const char *zdialer; + + zdialer = qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]; + iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer); + if (iuuconf == UUCONF_SUCCESS) + qdialer = &sdialer; + } + else + qdialer = qport->uuconf_u.uuconf_smodem.uuconf_qdialer; + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP + || (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI + && (qport->uuconf_ireliable + & UUCONF_RELIABLE_SPECIFIED) == 0)) + ftcp_port = TRUE; + } + + sDaemon.puuconf = puuconf; + sDaemon.qsys = NULL; + sDaemon.zlocalname = NULL; + sDaemon.qconn = qconn; + sDaemon.qproto = NULL; + sDaemon.clocal_size = -1; + sDaemon.cremote_size = -1; + sDaemon.cmax_ever = -2; + sDaemon.cmax_receive = -1; + sDaemon.ifeatures = 0; + sDaemon.frequest_hangup = FALSE; + sDaemon.fhangup_requested = FALSE; + sDaemon.fhangup = FALSE; + sDaemon.fmaster = FALSE; + sDaemon.fcaller = FALSE; + sDaemon.ireliable = 0; + sDaemon.bgrade = UUCONF_GRADE_LOW; + + /* Get the local name to use. If uuconf_login_localname returns a + value, it is not always freed up, although it should be. */ + iuuconf = uuconf_login_localname (puuconf, zlogin, &zloc); + if (iuuconf == UUCONF_SUCCESS) + sDaemon.zlocalname = zloc; + else if (iuuconf == UUCONF_NOT_FOUND) + { + sDaemon.zlocalname = zsysdep_localname (); + if (sDaemon.zlocalname == NULL) + return FALSE; + } + else + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + /* Tell the remote system who we are. */ + zsend = zbufalc (strlen (sDaemon.zlocalname) + sizeof "Shere="); + sprintf (zsend, "Shere=%s", sDaemon.zlocalname); + fret = fsend_uucp_cmd (qconn, zsend); + ubuffree (zsend); + if (! fret) + return FALSE; + + zstr = zget_uucp_cmd (qconn, TRUE); + if (zstr == NULL) + return FALSE; + + if (zstr[0] != 'S') + { + ulog (LOG_ERROR, "Bad introduction string"); + ubuffree (zstr); + return FALSE; + } + + zspace = strchr (zstr, ' '); + if (zspace != NULL) + *zspace = '\0'; + + iuuconf = uuconf_system_info (puuconf, zstr + 1, &ssys); + if (iuuconf == UUCONF_NOT_FOUND) + { + char *zscript; + + /* Run the remote.unknown script, if appropriate. */ + iuuconf = uuconf_remote_unknown (puuconf, &zscript); + if (iuuconf == UUCONF_SUCCESS) + { + if (! fsysdep_unknown_caller (zscript, zstr + 1)) + { + xfree ((pointer) zscript); + (void) fsend_uucp_cmd (qconn, "RYou are unknown to me"); + ubuffree (zstr); + return FALSE; + } + xfree ((pointer) zscript); + } + else if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (zstr); + return FALSE; + } + + if (! funknown_system (puuconf, zstr + 1, &ssys)) + { + (void) fsend_uucp_cmd (qconn, "RYou are unknown to me"); + ulog (LOG_ERROR, "Call from unknown system %s", zstr + 1); + ubuffree (zstr); + return FALSE; + } + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (zstr); + return FALSE; + } + + qany = NULL; + for (qsys = &ssys; qsys != NULL; qsys = qsys->uuconf_qalternate) + { + if (! qsys->uuconf_fcalled) + continue; + + if (qsys->uuconf_zcalled_login == NULL + || strcmp (qsys->uuconf_zcalled_login, "ANY") == 0) + { + if (qany == NULL) + qany = qsys; + } + else if (strcmp (qsys->uuconf_zcalled_login, zlogin) == 0) + break; + } + + if (qsys == NULL && qany != NULL) + { + iuuconf = uuconf_validate (puuconf, qany, zlogin); + if (iuuconf == UUCONF_SUCCESS) + qsys = qany; + else if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (zstr); + return FALSE; + } + } + + if (qsys == NULL) + { + (void) fsend_uucp_cmd (qconn, "RLOGIN"); + ulog (LOG_ERROR, "System %s used wrong login name %s", + zstr + 1, zlogin); + ubuffree (zstr); + return FALSE; + } + + sDaemon.qsys = qsys; + + if (pzsystem != NULL) + *pzsystem = zbufcpy (qsys->uuconf_zname); + + ulog_system (qsys->uuconf_zname); + +#if DEBUG > 1 + if (qsys->uuconf_zdebug != NULL) + iDebug |= idebug_parse (qsys->uuconf_zdebug); +#endif + + /* See if we are supposed to call the system back. This will queue + up an empty command. It would be better to actually call back + directly at this point as well. */ + if (qsys->uuconf_fcallback) + { + (void) fsend_uucp_cmd (qconn, "RCB"); + ulog (LOG_NORMAL, "Will call back"); + + /* Clear any existing status. */ + sstat.ttype = STATUS_COMPLETE; + sstat.cretries = 0; + sstat.ilast = ixsysdep_time ((long *) NULL); + sstat.cwait = 0; + (void) fsysdep_set_status (qsys, &sstat); + + ubuffree (zsysdep_spool_commands (qsys, UUCONF_GRADE_HIGH, 0, + (const struct scmd *) NULL)); + ubuffree (zstr); + return TRUE; + } + + /* We only permit one call at a time from a remote system. Lock it. */ + if (! fsysdep_lock_system (qsys)) + { + (void) fsend_uucp_cmd (qconn, "RLCK"); + ulog (LOG_ERROR, "System already locked"); + ubuffree (zstr); + return FALSE; + } + sLocked_system = *qsys; + fLocked_system = TRUE; + + /* Set the system status. We don't care what the status was before. + We also don't want to kill the conversation just because we can't + output the .Status file, so we ignore any errors. */ + sstat.ttype = STATUS_TALKING; + sstat.cretries = 0; + sstat.ilast = ixsysdep_time ((long *) NULL); + sstat.cwait = 0; + (void) fsysdep_set_status (qsys, &sstat); + + /* Check the arguments of the remote system, if any. */ + fgotseq = FALSE; + fgotn = FALSE; + if (zspace != NULL) + { + char **paz; + char **pzset; + + ++zspace; + + /* Break the introduction line up into arguments. */ + paz = (char **) xmalloc ((strlen (zspace) / 2 + 2) * sizeof (char *)); + pzset = paz; + *pzset++ = NULL; + while (TRUE) + { + while (*zspace != '\0' && isspace (BUCHAR (*zspace))) + ++zspace; + if (*zspace == '\0') + break; + *pzset++ = zspace; + ++zspace; + while (*zspace != '\0' && ! isspace (BUCHAR (*zspace))) + ++zspace; + if (*zspace == '\0') + break; + *zspace++ = '\0'; + } + + if (pzset != paz + 1) + { + int iopt; + + *pzset = NULL; + + /* We are going to use getopt to parse the arguments. We + must clear optind to force getopt to reinitialize, and + clear opterr to prevent getopt from printing an error + message. This approach assumes we are using the GNU + getopt, which is distributed with the program anyhow. */ + optind = 0; + opterr = 0; + + while ((iopt = getopt (pzset - paz, paz, + "N::p:Q:RU:v:x:")) != EOF) + { + long iseq; + long c; + char b; + int iwant; + + switch (iopt) + { + case 'N': + /* This is used to indicate support for Taylor UUCP + extensions. An plain -N mean support for size + negotiation. If -N is followed by a number (with + no intervening space), the number is a bit field + of feature flags as defined in trans.h. Note + that the argument may start with 0x for hex or 0 + for octal. */ + fgotn = TRUE; + if (optarg == NULL) + sDaemon.ifeatures |= FEATURE_SIZES | FEATURE_V103; + else + sDaemon.ifeatures |= (int) strtol (optarg, + (char **) NULL, + 0); + break; + + case 'p': + /* The argument is the lowest grade of work the + local system should send. */ + if (UUCONF_GRADE_LEGAL (optarg[0])) + sDaemon.bgrade = optarg[0]; + break; + + case 'Q': + /* The conversation sequence number. */ + iseq = strtol (optarg, (char **) NULL, 10); + if (qsys->uuconf_fsequence + && iseq != ixsysdep_get_sequence (qsys)) + { + (void) fsend_uucp_cmd (qconn, "RBADSEQ"); + ulog (LOG_ERROR, "Out of sequence call rejected"); + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + xfree ((pointer) paz); + ubuffree (zstr); + return FALSE; + } + fgotseq = TRUE; + break; + + case 'R': + /* The remote system supports file restart. */ + sDaemon.ifeatures |= FEATURE_RESTART; + break; + + case 'U': + /* The maximum file size the remote system is + prepared to received, in blocks where each block + is 512 bytes. */ + c = strtol (optarg, (char **) NULL, 0); + if (c > 0 && c < LONG_MAX / (long) 512) + sDaemon.cmax_receive = c * (long) 512; + break; + + case 'v': + /* -vgrade=X can be used to set the lowest grade of + work the local system should send. */ + if (strncmp (optarg, "grade=", sizeof "grade=" - 1) == 0) + { + b = optarg[sizeof "grade=" - 1]; + if (UUCONF_GRADE_LEGAL (b)) + sDaemon.bgrade = b; + } + break; + + case 'x': + iwant = (int) strtol (optarg, (char **) NULL, 10); +#if DEBUG > 1 + if (iwant <= 9) + iwant = (1 << iwant) - 1; + if (qsys->uuconf_zmax_remote_debug != NULL) + iwant &= idebug_parse (qsys->uuconf_zmax_remote_debug); + if ((iDebug | iwant) != iDebug) + { + iDebug |= iwant; + ulog (LOG_NORMAL, "Setting debugging mode to 0%o", + iDebug); + } +#endif + break; + + default: + break; + } + } + } + + xfree ((pointer) paz); + } + + ubuffree (zstr); + + if (qsys->uuconf_fsequence && ! fgotseq) + { + (void) fsend_uucp_cmd (qconn, "RBADSEQ"); + ulog (LOG_ERROR, "No sequence number (call rejected)"); + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + /* We recognized the system, and the sequence number (if any) was + OK. Send an ROK, and send a list of protocols. If we got the -N + switch, send ROKN to confirm it; if the -N switch was followed by + a feature bitfield, return our own feature bitfield. */ + { + char ab[20]; + const char *zreply; + + if (! fgotn) + { + if ((sDaemon.ifeatures & FEATURE_RESTART) == 0) + zreply = "ROK"; + else + { + /* We got -R without -N, so assume that this is SVR4 UUCP. + SVR4 UUCP expects ROK -R to signal support for file + restart. */ + sDaemon.ifeatures |= FEATURE_SVR4 | FEATURE_SIZES; + zreply = "ROK -R"; + } + } + else if ((sDaemon.ifeatures & FEATURE_V103) != 0) + zreply = "ROKN"; + else + { + sprintf (ab, "ROKN0%o", + (unsigned int) (FEATURE_SIZES + | FEATURE_EXEC + | FEATURE_RESTART)); + zreply = ab; + } + if (! fsend_uucp_cmd (qconn, zreply)) + { + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + } + + /* Determine the reliability of the connection based on the + reliability of the port and the dialer. If we have no + information, default to a reliable eight-bit full-duplex + connection. */ + if (ftcp_port) + sDaemon.ireliable = (UUCONF_RELIABLE_SPECIFIED + | UUCONF_RELIABLE_ENDTOEND + | UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX); + else + { + if (qport != NULL + && (qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + sDaemon.ireliable = qport->uuconf_ireliable; + if (qdialer != NULL + && (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + { + if (sDaemon.ireliable != 0) + sDaemon.ireliable &= qdialer->uuconf_ireliable; + else + sDaemon.ireliable = qdialer->uuconf_ireliable; + } + if (sDaemon.ireliable == 0) + sDaemon.ireliable = (UUCONF_RELIABLE_RELIABLE + | UUCONF_RELIABLE_EIGHT + | UUCONF_RELIABLE_FULLDUPLEX + | UUCONF_RELIABLE_SPECIFIED); + } + + if (qsys->uuconf_zprotocols != NULL || + (qport != NULL && qport->uuconf_zprotocols != NULL)) + { + const char *zprotos; + + if (qsys->uuconf_zprotocols != NULL) + zprotos = qsys->uuconf_zprotocols; + else + zprotos = qport->uuconf_zprotocols; + zsend = zbufalc (strlen (zprotos) + 2); + sprintf (zsend, "P%s", zprotos); + } + else + { + char *zset; + + zsend = zbufalc (CPROTOCOLS + 2); + zset = zsend; + *zset++ = 'P'; + + /* If the system did not specify a list of protocols, we want + only protocols that match the known reliability of the dialer + and the port. */ + for (i = 0; i < CPROTOCOLS; i++) + { + int ipr; + + ipr = asProtocols[i].ireliable; + if ((ipr & sDaemon.ireliable) != ipr) + continue; + *zset++ = asProtocols[i].bname; + } + *zset = '\0'; + } + + fret = fsend_uucp_cmd (qconn, zsend); + ubuffree (zsend); + if (! fret) + { + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + /* The master will now send back the selected protocol. */ + zstr = zget_uucp_cmd (qconn, TRUE); + if (zstr == NULL) + { + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + if (zstr[0] != 'U' || zstr[2] != '\0') + { + ulog (LOG_ERROR, "Bad protocol response string"); + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + ubuffree (zstr); + return FALSE; + } + + if (zstr[1] == 'N') + { + ulog (LOG_ERROR, "No supported protocol"); + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + ubuffree (zstr); + return FALSE; + } + + for (i = 0; i < CPROTOCOLS; i++) + if (asProtocols[i].bname == zstr[1]) + break; + + ubuffree (zstr); + + if (i >= CPROTOCOLS) + { + ulog (LOG_ERROR, "No supported protocol"); + sstat.ttype = STATUS_FAILED; + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + sDaemon.qproto = &asProtocols[i]; + + /* Run the chat script for when a call is received. */ + if (! fchat (qconn, puuconf, &qsys->uuconf_scalled_chat, qsys, + (const struct uuconf_dialer *) NULL, (const char *) NULL, + FALSE, zport, iconn_baud (qconn))) + { + sstat.ttype = STATUS_FAILED; + sstat.ilast = ixsysdep_time ((long *) NULL); + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + /* Run any protocol parameter commands. */ + if (sDaemon.qproto->qcmds != NULL) + { + if (qsys->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, sDaemon.qproto->bname, + sDaemon.qproto->qcmds, + qsys->uuconf_qproto_params); + if (qport != NULL + && qport->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, sDaemon.qproto->bname, + sDaemon.qproto->qcmds, + qport->uuconf_qproto_params); + if (qdialer != NULL + && qdialer->uuconf_qproto_params != NULL) + uapply_proto_params (puuconf, sDaemon.qproto->bname, + sDaemon.qproto->qcmds, + qdialer->uuconf_qproto_params); + } + + /* We don't need the dialer information any more. */ + if (qdialer == &sdialer) + (void) uuconf_dialer_free (puuconf, &sdialer); + + /* Get any jobs queued for the system, and turn on the selected + protocol. */ + if (! fqueue (&sDaemon, (boolean *) NULL) + || ! (*sDaemon.qproto->pfstart) (&sDaemon, &zlog)) + { + uclear_queue (&sDaemon); + sstat.ttype = STATUS_FAILED; + sstat.ilast = ixsysdep_time ((long *) NULL); + (void) fsysdep_set_status (qsys, &sstat); + return FALSE; + } + + if (zlog == NULL) + { + zlog = zbufalc (sizeof "protocol ''" + 1); + sprintf (zlog, "protocol '%c'", sDaemon.qproto->bname); + } + + zgrade = zbufalc (sizeof "grade " + 1); + if (sDaemon.bgrade == UUCONF_GRADE_LOW) + *zgrade = '\0'; + else + sprintf (zgrade, "grade %c ", sDaemon.bgrade); + + /* If we are using HAVE_HDB_LOGGING, then the previous ``incoming + call'' message went to the general log, since we didn't know the + system name at that point. In that case, we repeat the port and + login names. */ +#if HAVE_HDB_LOGGING + ulog (LOG_NORMAL, "Handshake successful (login %s port %s %s%s)", + zlogin, + zLdevice == NULL ? "unknown" : zLdevice, + zgrade, zlog); +#else /* ! HAVE_HDB_LOGGING */ + ulog (LOG_NORMAL, "Handshake successful (%s%s)", zgrade, zlog); +#endif /* ! HAVE_HDB_LOGGING */ + + ubuffree (zlog); + ubuffree (zgrade); + + { + long iend_time; + + fret = floop (&sDaemon); + + /* Hangup. As the answerer, we send seven O's and expect to + receive six O's. We send the seven O's twice to help the other + side. We don't worry about errors here. */ + if (fsend_uucp_cmd (qconn, "OOOOOOO") + && fsend_uucp_cmd (qconn, "OOOOOOO")) + { + int fdone; + + /* We look for the remote hangup string to ensure that the + modem has sent out our hangup string. This is only + necessary because some versions of UUCP complain if they + don't get the hangup string. We look for the string + several times because supposedly some implementations send + some garbage after the last packet but before the hangup + string. */ + for (i = 0; i < 25; i++) + { + zstr = zget_uucp_cmd (qconn, FALSE); + if (zstr == NULL) + break; + fdone = strstr (zstr, "OOOOOO") != NULL; + ubuffree (zstr); + if (fdone) + break; + } + } + + iend_time = ixsysdep_time ((long *) NULL); + + ulog (LOG_NORMAL, "Call complete (%ld seconds)", + iend_time - istart_time); + + uclear_queue (&sDaemon); + + if (fret) + sstat.ttype = STATUS_COMPLETE; + else + sstat.ttype = STATUS_FAILED; + sstat.ilast = iend_time; + (void) fsysdep_set_status (qsys, &sstat); + + (void) uuconf_system_free (puuconf, &ssys); + if (qport == &sport) + (void) uuconf_port_free (puuconf, &sport); + xfree ((pointer) zloc); + + return fret; + } +} + +/* Apply protocol parameters, once we know the protocol. */ + +static void +uapply_proto_params (puuconf, bproto, qcmds, pas) + pointer puuconf; + int bproto; + struct uuconf_cmdtab *qcmds; + struct uuconf_proto_param *pas; +{ + struct uuconf_proto_param *qp; + + for (qp = pas; qp->uuconf_bproto != '\0'; qp++) + { + if (qp->uuconf_bproto == bproto) + { + struct uuconf_proto_param_entry *qe; + + for (qe = qp->uuconf_qentries; qe->uuconf_cargs > 0; qe++) + { + int iuuconf; + + iuuconf = uuconf_cmd_args (puuconf, qe->uuconf_cargs, + qe->uuconf_pzargs, qcmds, + (pointer) NULL, + (uuconf_cmdtabfn) NULL, 0, + (pointer) NULL); + if (UUCONF_ERROR_VALUE (iuuconf) != UUCONF_SUCCESS) + { + ulog (LOG_ERROR, "Error in %c protocol parameters", + bproto); + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + } + } + + break; + } + } +} + +/* Send a string to the other system beginning with a DLE + character and terminated with a null byte. This is only + used when no protocol is in force. */ + +static boolean +fsend_uucp_cmd (qconn, z) + struct sconnection *qconn; + const char *z; +{ + size_t cwrite; + char *zalc; + boolean fret; + + DEBUG_MESSAGE1 (DEBUG_HANDSHAKE, "fsend_uucp_cmd: Sending \"%s\"", z); + + cwrite = strlen (z) + 2; + + zalc = zbufalc (cwrite); + zalc[0] = '\020'; + memcpy (zalc + 1, z, cwrite - 1); + + fret = fconn_write (qconn, zalc, cwrite); + ubuffree (zalc); + return fret; +} + +/* Get a UUCP command beginning with a DLE character and ending with a + null byte. This is only used when no protocol is in force. This + implementation has the potential of being seriously slow. It also + doesn't have any real error recovery. The frequired argument is + passed as TRUE if we need the string; we don't care that much if + we're closing down the connection anyhow. */ + +#define CTIMEOUT (120) +#define CSHORTTIMEOUT (10) +#define CINCREMENT (100) + +static char * +zget_uucp_cmd (qconn, frequired) + struct sconnection *qconn; + boolean frequired; +{ + char *zalc; + size_t calc; + size_t cgot; + boolean fintro; + long iendtime; + int ctimeout; +#if DEBUG > 1 + int cchars; + int iolddebug; +#endif + + iendtime = ixsysdep_time ((long *) NULL); + if (frequired) + iendtime += CTIMEOUT; + else + iendtime += CSHORTTIMEOUT; + +#if DEBUG > 1 + cchars = 0; + iolddebug = iDebug; + if (FDEBUGGING (DEBUG_HANDSHAKE)) + { + ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \""); + iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); + } +#endif + + zalc = NULL; + calc = 0; + cgot = 0; + fintro = FALSE; + while ((ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL))) > 0) + { + int b; + + b = breceive_char (qconn, ctimeout, frequired); + /* Now b == -1 on timeout, -2 on error. */ + if (b < 0) + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_HANDSHAKE)) + { + ulog (LOG_DEBUG_END, "\" (%s)", + b == -1 ? "timeout" : "error"); + iDebug = iolddebug; + } +#endif + if (b == -1 && frequired) + ulog (LOG_ERROR, "Timeout"); + ubuffree (zalc); + return NULL; + } + + /* Apparently some systems use parity on these strings, so we + strip the parity bit. This may need to be configurable at + some point, although only if system names can have eight bit + characters. */ + if (! isprint (BUCHAR (b))) + b &= 0x7f; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_HANDSHAKE)) + { + char ab[5]; + + ++cchars; + if (cchars > 60) + { + ulog (LOG_DEBUG_END, "\""); + ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \""); + cchars = 0; + } + (void) cdebug_char (ab, b); + ulog (LOG_DEBUG_CONTINUE, "%s", ab); + } +#endif + + if (! fintro) + { + if (b == '\020') + fintro = TRUE; + continue; + } + + /* If we see another DLE, something has gone wrong; continue + as though this were the first one we saw. */ + if (b == '\020') + { + cgot = 0; + continue; + } + + /* Some systems send a trailing \n on the Shere line. As far as + I can tell this line can never contain a \n, so this + modification should be safe enough. */ + if (b == '\r' || b == '\n') + b = '\0'; + + if (cgot >= calc) + { + char *znew; + + calc += CINCREMENT; + znew = zbufalc (calc); + memcpy (znew, zalc, cgot); + ubuffree (zalc); + zalc = znew; + } + + zalc[cgot] = (char) b; + ++cgot; + + if (b == '\0') + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_HANDSHAKE)) + { + ulog (LOG_DEBUG_END, "\""); + iDebug = iolddebug; + } +#endif + return zalc; + } + } + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_HANDSHAKE)) + { + ulog (LOG_DEBUG_END, "\" (timeout)"); + iDebug = iolddebug; + } +#endif + + ubuffree (zalc); + + if (frequired) + ulog (LOG_ERROR, "Timeout"); + return NULL; +} + +/* Read a sequence of characters up to a newline or carriage return, and + return the line without the line terminating character. */ + +static char * +zget_typed_line (qconn) + struct sconnection *qconn; +{ + char *zalc; + size_t calc; + size_t cgot; + +#if DEBUG > 1 + int cchars; + int iolddebug; + + cchars = 0; + iolddebug = iDebug; + if (FDEBUGGING (DEBUG_CHAT)) + { + ulog (LOG_DEBUG_START, "zget_typed_line: Got \""); + iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); + } +#endif + + zalc = NULL; + calc = 0; + cgot = 0; + while (TRUE) + { + int b; + + b = breceive_char (qconn, CTIMEOUT, FALSE); + + /* Now b == -1 on timeout, -2 on error. */ + + if (b == -2 || FGOT_SIGNAL ()) + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + ulog (LOG_DEBUG_END, "\" (error)"); + iDebug = iolddebug; + } +#endif + ubuffree (zalc); + return NULL; + } + + if (b == -1) + continue; + +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + char ab[5]; + + ++cchars; + if (cchars > 60) + { + ulog (LOG_DEBUG_END, "\""); + ulog (LOG_DEBUG_START, "zget_typed_line: Got \""); + cchars = 0; + } + (void) cdebug_char (ab, b); + ulog (LOG_DEBUG_CONTINUE, "%s", ab); + } +#endif + + if (cgot >= calc) + { + char *znew; + + calc += CINCREMENT; + znew = zbufalc (calc); + memcpy (znew, zalc, cgot); + ubuffree (zalc); + zalc = znew; + } + + if (b == '\r' || b == '\n') + b = '\0'; + + zalc[cgot] = (char) b; + ++cgot; + + if (b == '\0') + { +#if DEBUG > 1 + if (FDEBUGGING (DEBUG_CHAT)) + { + ulog (LOG_DEBUG_END, "\""); + iDebug = iolddebug; + } +#endif + return zalc; + } + } +} diff --git a/gnu/libexec/uucp/uucico/xcmd.c b/gnu/libexec/uucp/uucico/xcmd.c new file mode 100644 index 0000000000..494fe127ab --- /dev/null +++ b/gnu/libexec/uucp/uucico/xcmd.c @@ -0,0 +1,396 @@ +/* xcmd.c + Routines to handle work requests. + + 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 xcmd_rcsid[] = "$Id: xcmd.c,v 1.1 1993/08/04 19:36:35 jtc Exp $"; +#endif + +#include + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "prot.h" +#include "trans.h" + +/* Local functions. */ + +static boolean flocal_xcmd_request P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); +static boolean flocal_xcmd_await_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon, + const char *zdata, size_t cdata)); +static boolean fremote_xcmd_reply P((struct stransfer *qtrans, + struct sdaemon *qdaemon)); + +/* Handle a local work request. We just set up the request for + transmission. */ + +boolean +flocal_xcmd_init (qdaemon, qcmd) + struct sdaemon *qdaemon; + struct scmd *qcmd; +{ + struct stransfer *qtrans; + + qtrans = qtransalc (qcmd); + qtrans->psendfn = flocal_xcmd_request; + + return fqueue_local (qdaemon, qtrans); +} + +/* Send the execution request to the remote system. */ + +static boolean +flocal_xcmd_request (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + size_t clen; + char *zsend; + boolean fret; + + ulog (LOG_NORMAL, "Requesting work: %s to %s", qtrans->s.zfrom, + qtrans->s.zto); + + /* We send the string + X from to user options + We put a dash in front of options. */ + clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 7); + zsend = zbufalc (clen); + sprintf (zsend, "X %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto, + qtrans->s.zuser, qtrans->s.zoptions); + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, + qtrans->iremote); + ubuffree (zsend); + if (! fret) + { + utransfree (qtrans); + return FALSE; + } + + qtrans->fcmd = TRUE; + qtrans->precfn = flocal_xcmd_await_reply; + + return fqueue_receive (qdaemon, qtrans); +} + +/* Get a reply to an execution request from the remote system. */ + +/*ARGSUSED*/ +static boolean +flocal_xcmd_await_reply (qtrans, qdaemon, zdata, cdata) + struct stransfer *qtrans; + struct sdaemon *qdaemon; + const char *zdata; + size_t cdata; +{ + qtrans->precfn = NULL; + + if (zdata[0] != 'X' + || (zdata[1] != 'Y' && zdata[1] != 'N')) + { + ulog (LOG_ERROR, "Bad response to work request"); + utransfree (qtrans); + return FALSE; + } + + if (zdata[1] == 'N') + { + ulog (LOG_ERROR, "%s: work request denied", qtrans->s.zfrom); + (void) fmail_transfer (FALSE, qtrans->s.zuser, (const char *) NULL, + "work request denied", + qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, + qtrans->s.zto, (const char *) NULL, + (const char *) NULL); + } + + (void) fsysdep_did_work (qtrans->s.pseq); + utransfree (qtrans); + + return TRUE; +} + +/* Handle a remote work request. This just queues up the requests for + later processing. */ + +boolean +fremote_xcmd_init (qdaemon, qcmd, iremote) + struct sdaemon *qdaemon; + struct scmd *qcmd; + int iremote; +{ + const struct uuconf_system *qsys; + const char *zexclam; + const struct uuconf_system *qdestsys; + struct uuconf_system sdestsys; + char *zdestfile; + boolean fmkdirs; + struct stransfer *qtrans; + char *zuser; + char aboptions[5]; + char *zfrom; + boolean fret; + char *zfile; + + ulog (LOG_NORMAL, "Work requested: %s to %s", qcmd->zfrom, + qcmd->zto); + + qsys = qdaemon->qsys; + + zexclam = strchr (qcmd->zto, '!'); + if (zexclam == NULL + || zexclam == qcmd->zto + || strncmp (qdaemon->zlocalname, qcmd->zto, + (size_t) (zexclam - qcmd->zto)) == 0) + { + const char *zconst; + + /* The files are supposed to be copied to the local system. */ + qdestsys = NULL; + if (zexclam == NULL) + zconst = qcmd->zto; + else + zconst = zexclam + 1; + + zdestfile = zsysdep_local_file (zconst, qsys->uuconf_zpubdir); + if (zdestfile == NULL) + return FALSE; + + zuser = NULL; + fmkdirs = strchr (qcmd->zoptions, 'f') != NULL; + } + else + { + size_t clen; + char *zcopy; + int iuuconf; + char *zoptions; + + clen = zexclam - qcmd->zto; + zcopy = zbufalc (clen + 1); + memcpy (zcopy, qcmd->zto, clen); + zcopy[clen] = '\0'; + + iuuconf = uuconf_system_info (qdaemon->puuconf, zcopy, &sdestsys); + if (iuuconf == UUCONF_NOT_FOUND) + { + if (! funknown_system (qdaemon->puuconf, zcopy, &sdestsys)) + { + ulog (LOG_ERROR, "%s: System not found", zcopy); + ubuffree (zcopy); + qtrans = qtransalc (qcmd); + qtrans->psendfn = fremote_xcmd_reply; + qtrans->pinfo = (pointer) "XN"; + qtrans->iremote = iremote; + return fqueue_remote (qdaemon, qtrans); + } + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, qdaemon->puuconf, iuuconf); + ubuffree (zcopy); + return FALSE; + } + + ubuffree (zcopy); + + qdestsys = &sdestsys; + zdestfile = zbufcpy (zexclam + 1); + + zuser = zbufalc (strlen (qdestsys->uuconf_zname) + + strlen (qcmd->zuser) + sizeof "!"); + sprintf (zuser, "%s!%s", qdestsys->uuconf_zname, qcmd->zuser); + zoptions = aboptions; + *zoptions++ = 'C'; + if (strchr (qcmd->zoptions, 'd') != NULL) + *zoptions++ = 'd'; + if (strchr (qcmd->zoptions, 'm') != NULL) + *zoptions++ = 'm'; + *zoptions = '\0'; + fmkdirs = TRUE; + } + + /* At this point we prepare to confirm the remote request. We could + actually fork here and let the child spool up the requests. */ + qtrans = qtransalc (qcmd); + qtrans->psendfn = fremote_xcmd_reply; + qtrans->pinfo = (pointer) "XY"; + qtrans->iremote = iremote; + if (! fqueue_remote (qdaemon, qtrans)) + { + ubuffree (zdestfile); + ubuffree (zuser); + return FALSE; + } + + /* Now we have to process each source file. The source + specification may or may use wildcards. */ + zfrom = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir); + if (zfrom == NULL) + { + ubuffree (zdestfile); + ubuffree (zuser); + return FALSE; + } + + if (! fsysdep_wildcard_start (zfrom)) + { + ubuffree (zfrom); + ubuffree (zdestfile); + ubuffree (zuser); + return FALSE; + } + + fret = TRUE; + + while ((zfile = zsysdep_wildcard (zfrom)) != NULL) + { + char *zto; + char abtname[CFILE_NAME_LEN]; + + if (! fsysdep_file_exists (zfile)) + { + ulog (LOG_ERROR, "%s: no such file", zfile); + continue; + } + + /* Make sure the remote system is permitted to read the + specified file. */ + if (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, + qsys->uuconf_zpubdir, TRUE, TRUE, + (const char *) NULL)) + { + ulog (LOG_ERROR, "%s: not permitted to send", zfile); + break; + } + + if (qdestsys != NULL) + { + /* We really should get the original grade here. */ + zto = zsysdep_data_file_name (qdestsys, qdaemon->zlocalname, + BDEFAULT_UUCP_GRADE, FALSE, + abtname, (char *) NULL, + (char *) NULL); + if (zto == NULL) + { + fret = FALSE; + break; + } + } + else + { + zto = zsysdep_add_base (zdestfile, zfile); + if (zto == NULL) + { + fret = FALSE; + break; + } + /* We only accept a local destination if the remote system + has the right to create files there. */ + if (! fin_directory_list (zto, qsys->uuconf_pzremote_receive, + qsys->uuconf_zpubdir, TRUE, FALSE, + (const char *) NULL)) + { + ulog (LOG_ERROR, "%s: not permitted to receive", zto); + ubuffree (zto); + break; + } + } + + /* Copy the file either to the final destination or to the + spool directory. */ + if (! fcopy_file (zfile, zto, qdestsys == NULL, fmkdirs)) + { + ubuffree (zto); + break; + } + + ubuffree (zto); + + /* If there is a destination system, queue it up. */ + if (qdestsys != NULL) + { + struct scmd ssend; + char *zjobid; + + ssend.bcmd = 'S'; + ssend.pseq = NULL; + ssend.zfrom = zfile; + ssend.zto = zdestfile; + ssend.zuser = zuser; + ssend.zoptions = aboptions; + ssend.ztemp = abtname; + ssend.imode = ixsysdep_file_mode (zfile); + ssend.znotify = ""; + ssend.cbytes = -1; + ssend.zcmd = NULL; + ssend.ipos = 0; + + zjobid = zsysdep_spool_commands (qdestsys, BDEFAULT_UUCP_GRADE, + 1, &ssend); + if (zjobid == NULL) + break; + ubuffree (zjobid); + } + + ubuffree (zfile); + } + + if (zfile != NULL) + ubuffree (zfile); + + (void) fsysdep_wildcard_end (); + + ubuffree (zdestfile); + if (qdestsys != NULL) + (void) uuconf_system_free (qdaemon->puuconf, &sdestsys); + + ubuffree (zfrom); + ubuffree (zuser); + + return fret; +} + +/* Reply to a remote work request. */ + +static boolean +fremote_xcmd_reply (qtrans, qdaemon) + struct stransfer *qtrans; + struct sdaemon *qdaemon; +{ + boolean fret; + + fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, + (const char *) qtrans->pinfo, + qtrans->ilocal, + qtrans->iremote); + utransfree (qtrans); + return fret; +} diff --git a/gnu/libexec/uucp/uuconv/Makefile b/gnu/libexec/uucp/uuconv/Makefile new file mode 100644 index 0000000000..f06c3e274d --- /dev/null +++ b/gnu/libexec/uucp/uuconv/Makefile @@ -0,0 +1,17 @@ +# Makefile for uuconv +# $Id: Makefile,v 1.2 1993/08/05 16:15:08 jtc Exp $ + +BINDIR= $(sbindir) +BINOWN= $(owner) + +PROG= uuconv +SRCS= uuconv.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -I$(.CURDIR)/../libuuconf\ + -DVERSION=\"$(VERSION)\" + +NOMAN= noman + +.include diff --git a/gnu/libexec/uucp/uuconv/uuconv.c b/gnu/libexec/uucp/uuconv/uuconv.c new file mode 100644 index 0000000000..82f4e35f93 --- /dev/null +++ b/gnu/libexec/uucp/uuconv/uuconv.c @@ -0,0 +1,2012 @@ +/* uuconv.c + Convert one type of UUCP configuration file to another. + + 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 "uucnfi.h" + +#if USE_RCS_ID +const char uuconv_rcsid[] = "$Id: uuconv.c,v 1.1 1993/08/04 19:36:39 jtc Exp $"; +#endif + +#include "getopt.h" + +/* Local functions. */ + +static void uvusage P((void)); +static void uvwrite_time P((FILE *e, struct uuconf_timespan *qtime)); +static void uvwrite_string P((FILE *e, const char *zarg, const char *zcmd)); +static void uvwrite_size P((FILE *e, struct uuconf_timespan *qsize, + const char *zcmd)); +static void uvwrite_boolean P((FILE *e, int iarg, const char *zcmd)); +static void uvwrite_string_array P((FILE *e, char **pz, const char *zcmd)); +static void uvwrite_chat_script P((FILE *e, char **pz)); +static void uvwrite_chat P((FILE *e, const struct uuconf_chat *qchat, + const struct uuconf_chat *qlast, + const char *zprefix, boolean fforce)); +static void uvwrite_proto_params P((FILE *e, + const struct uuconf_proto_param *qparam, + const char *zprefix)); +static void uvwrite_taylor_system P((FILE *e, + const struct uuconf_system *qsys)); +static void uvwrite_v2_system P((FILE *e, + const struct uuconf_system *qsys)); +static void uvwrite_hdb_system P((FILE *e, + const struct uuconf_system *qsys)); +static boolean fvperm_string_cmp P((const char *z1, const char *z2)); +static boolean fvperm_array_cmp P((const char **pz1, const char **pz2)); +static void uvadd_perm P((struct shpermissions *qadd)); +static void uvwrite_perms P((void)); +static void uvwrite_perm_array P((FILE *e, const char **pz, + const char *zcmd, size_t *pccol)); +static void uvwrite_perm_boolean P((FILE *e, int f, const char *zcmd, + size_t *pccol, boolean fsendfiles)); +static void uvwrite_perm_rw_array P((FILE *e, const char **pz, + const char *zcmd, size_t *pccol)); +static void uvwrite_perm_string P((FILE *e, const char *z, const char *zcmd, + size_t *pccol)); +static int ivwrite_taylor_port P((struct uuconf_port *qport, + pointer pinfo)); +static int ivwrite_v2_port P((struct uuconf_port *qport, pointer pinfo)); +static int ivwrite_hdb_port P((struct uuconf_port *qport, pointer pinfo)); +static void uvwrite_taylor_port P((FILE *e, struct uuconf_port *qport, + const char *zprefix)); +static void uvwrite_taylor_dialer P((FILE *e, struct uuconf_dialer *qdialer, + const char *zprefix)); +static void uvwrite_hdb_dialer P((FILE *e, struct uuconf_dialer *qdialer)); +static void uvuuconf_error P((pointer puuconf, int iret)); + +/* A list of Permissions entries built when writing out HDB system + information. */ +static struct shpermissions *qVperms; + +/* Type of configuration file. */ +enum tconfig +{ + CONFIG_TAYLOR, + CONFIG_V2, + CONFIG_HDB +}; + +/* Long getopt options. */ +static const struct option asVlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -I: The configuration file name. */ + const char *zconfig = NULL; + /* -i: Input type. */ + const char *zinput = NULL; + /* -o: Output type. */ + const char *zoutput = NULL; + /* -p: Program name. */ + const char *zprogram = NULL; + int iopt; + enum tconfig tinput, toutput; + int iret; + pointer pinput; + + while ((iopt = getopt_long (argc, argv, "i:I:o:p:x:", asVlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'i': + /* Input type. */ + zinput = optarg; + break; + + case 'o': + /* Output type. */ + zoutput = optarg; + break; + + case 'p': + /* Program name. */ + zprogram = optarg; + break; + + case 'I': + /* Set the configuration file name. */ + zconfig = optarg; + break; + + case 'x': + /* Set the debugging level. */ + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + uvusage (); + break; + } + } + + if (optind != argc + || zinput == NULL + || zoutput == NULL) + uvusage (); + + if (strcasecmp (zinput, "taylor") == 0) + tinput = CONFIG_TAYLOR; + else if (strcasecmp (zinput, "v2") == 0) + tinput = CONFIG_V2; + else if (strcasecmp (zinput, "hdb") == 0) + tinput = CONFIG_HDB; + else + { + uvusage (); + tinput = CONFIG_TAYLOR; + } + + if (strcasecmp (zoutput, "taylor") == 0) + toutput = CONFIG_TAYLOR; + else if (strcasecmp (zoutput, "v2") == 0) + toutput = CONFIG_V2; + else if (strcasecmp (zoutput, "hdb") == 0) + toutput = CONFIG_HDB; + else + { + uvusage (); + toutput = CONFIG_TAYLOR; + } + + if (tinput == toutput) + uvusage (); + + iret = UUCONF_SUCCESS; + + /* Initialize the input. */ + pinput = NULL; + switch (tinput) + { + case CONFIG_TAYLOR: + iret = uuconf_taylor_init (&pinput, zprogram, zconfig); + break; + case CONFIG_V2: + iret = uuconf_v2_init (&pinput); + break; + case CONFIG_HDB: + iret = uuconf_hdb_init (&pinput, zprogram); + break; + } + if (iret != UUCONF_SUCCESS) + { + uvuuconf_error (pinput, iret); + exit (EXIT_FAILURE); + } + + { + char **pzsystems; + char *zsys; + char abtaylor[sizeof ZCURDIR + sizeof SYSFILE - 1]; + char abv2[sizeof ZCURDIR + sizeof V2_SYSTEMS - 1]; + char abhdb[sizeof ZCURDIR + sizeof HDB_SYSTEMS - 1]; + FILE *esys; + char **pz; + + /* Get the list of systems. */ + switch (tinput) + { + case CONFIG_TAYLOR: + iret = uuconf_taylor_system_names (pinput, &pzsystems, FALSE); + break; + case CONFIG_V2: + iret = uuconf_v2_system_names (pinput, &pzsystems, FALSE); + break; + case CONFIG_HDB: + iret = uuconf_hdb_system_names (pinput, &pzsystems, FALSE); + break; + } + if (iret != UUCONF_SUCCESS) + uvuuconf_error (pinput, iret); + else + { + /* Open the sys file for the output type. */ + switch (toutput) + { + default: + case CONFIG_TAYLOR: + sprintf (abtaylor, "%s%s", ZCURDIR, SYSFILE); + zsys = abtaylor; + break; + case CONFIG_V2: + sprintf (abv2, "%s%s", ZCURDIR, V2_SYSTEMS); + zsys = abv2; + break; + case CONFIG_HDB: + sprintf (abhdb, "%s%s", ZCURDIR, HDB_SYSTEMS); + zsys = abhdb; + break; + } + esys = fopen (zsys, "w"); + if (esys == NULL) + { + fprintf (stderr, "uuchk:%s: ", zsys); + perror ("fopen"); + exit (EXIT_FAILURE); + } + + fprintf (esys, "# %s file automatically generated by uuconv.\n", + zsys); + + /* Read and write each system. We cheat and call the internal + routines, so that we can easily detect default information and + not write it out. This isn't necessary, but it makes the output + smaller and simpler. */ + for (pz = pzsystems; *pz != NULL; pz++) + { + struct uuconf_system ssys; + + switch (tinput) + { + case CONFIG_TAYLOR: + iret = _uuconf_itaylor_system_internal (pinput, *pz, &ssys); + break; + case CONFIG_V2: + iret = _uuconf_iv2_system_internal (pinput, *pz, &ssys); + break; + case CONFIG_HDB: + iret = _uuconf_ihdb_system_internal (pinput, *pz, &ssys); + break; + } + if (iret != UUCONF_SUCCESS) + uvuuconf_error (pinput, iret); + else + { + switch (toutput) + { + case CONFIG_TAYLOR: + uvwrite_taylor_system (esys, &ssys); + break; + case CONFIG_V2: + uvwrite_v2_system (esys, &ssys); + break; + case CONFIG_HDB: + uvwrite_hdb_system (esys, &ssys); + break; + } + if (toutput != CONFIG_HDB) + (void) uuconf_system_free (pinput, &ssys); + } + } + + if (toutput == CONFIG_HDB) + uvwrite_perms (); + + if (ferror (esys) + || fclose (esys) == EOF) + { + fprintf (stderr, "uuchk:%s: error during output\n", zsys); + exit (EXIT_FAILURE); + } + } + } + + { + /* Open the port file for the output type. */ + char *zport; + char abtaylor[sizeof ZCURDIR + sizeof PORTFILE - 1]; + char abv2[sizeof ZCURDIR + sizeof V2_DEVICES - 1]; + char abhdb[sizeof ZCURDIR + sizeof HDB_DEVICES - 1]; + FILE *eport; + int (*piportfn) P((struct uuconf_port *, pointer)); + struct uuconf_port sport; + + switch (toutput) + { + default: + case CONFIG_TAYLOR: + sprintf (abtaylor, "%s%s", ZCURDIR, PORTFILE); + zport = abtaylor; + piportfn = ivwrite_taylor_port; + break; + case CONFIG_V2: + sprintf (abv2, "%s%s", ZCURDIR, V2_DEVICES); + zport = abv2; + piportfn = ivwrite_v2_port; + break; + case CONFIG_HDB: + sprintf (abhdb, "%s%s", ZCURDIR, HDB_DEVICES); + zport = abhdb; + piportfn = ivwrite_hdb_port; + break; + } + eport = fopen (zport, "w"); + if (eport == NULL) + { + fprintf (stderr, "uuchk:%s: ", zport); + perror ("fopen"); + exit (EXIT_FAILURE); + } + + fprintf (eport, "# %s file automatically generated by uuconv.\n", zport); + + switch (tinput) + { + case CONFIG_TAYLOR: + iret = uuconf_taylor_find_port (pinput, (const char *) NULL, 0L, + 0L, piportfn, (pointer) eport, + &sport); + break; + case CONFIG_V2: + iret = uuconf_v2_find_port (pinput, (const char *) NULL, 0L, 0L, + piportfn, (pointer) eport, &sport); + break; + case CONFIG_HDB: + iret = uuconf_hdb_find_port (pinput, (const char *) NULL, 0L, 0L, + piportfn, (pointer) eport, &sport); + break; + } + + if (iret != UUCONF_NOT_FOUND) + uvuuconf_error (pinput, iret); + + if (ferror (eport) + || fclose (eport) == EOF) + { + fprintf (stderr, "uuchk:%s: error during output\n", zport); + exit (EXIT_FAILURE); + } + } + + /* V2 configuration files don't support dialers. */ + if (tinput != CONFIG_V2 && toutput != CONFIG_V2) + { + char **pzdialers; + char *zdialer; + char abtaylor[sizeof ZCURDIR + sizeof DIALFILE - 1]; + char abhdb[sizeof ZCURDIR + sizeof HDB_DIALERS - 1]; + FILE *edialer; + char **pz; + + /* Get the list of dialers. */ + switch (tinput) + { + default: + case CONFIG_TAYLOR: + iret = uuconf_taylor_dialer_names (pinput, &pzdialers); + break; + case CONFIG_HDB: + iret = uuconf_hdb_dialer_names (pinput, &pzdialers); + break; + } + if (iret != UUCONF_SUCCESS) + uvuuconf_error (pinput, iret); + else + { + /* Open the sys file for the output type. */ + switch (toutput) + { + default: + case CONFIG_TAYLOR: + sprintf (abtaylor, "%s%s", ZCURDIR, DIALFILE); + zdialer = abtaylor; + break; + case CONFIG_HDB: + sprintf (abhdb, "%s%s", ZCURDIR, HDB_DIALERS); + zdialer = abhdb; + break; + } + edialer = fopen (zdialer, "w"); + if (edialer == NULL) + { + fprintf (stderr, "uuchk:%s: ", zdialer); + perror ("fopen"); + exit (EXIT_FAILURE); + } + + fprintf (edialer, "# %s file automatically generated by uuconv.\n", + zdialer); + + /* Read and write each dialer. */ + for (pz = pzdialers; *pz != NULL; pz++) + { + struct uuconf_dialer sdialer; + + switch (tinput) + { + default: + case CONFIG_TAYLOR: + iret = uuconf_taylor_dialer_info (pinput, *pz, &sdialer); + break; + case CONFIG_HDB: + iret = uuconf_hdb_dialer_info (pinput, *pz, &sdialer); + break; + } + if (iret != UUCONF_SUCCESS) + uvuuconf_error (pinput, iret); + else + { + switch (toutput) + { + default: + case CONFIG_TAYLOR: + fprintf (edialer, "# Start of dialer %s\n", + sdialer.uuconf_zname); + fprintf (edialer, "dialer %s\n", sdialer.uuconf_zname); + uvwrite_taylor_dialer (edialer, &sdialer, ""); + break; + case CONFIG_HDB: + uvwrite_hdb_dialer (edialer, &sdialer); + break; + } + (void) uuconf_dialer_free (pinput, &sdialer); + } + } + + if (ferror (edialer) + || fclose (edialer) == EOF) + { + fprintf (stderr, "uuchk:%s: error during output\n", zdialer); + exit (EXIT_FAILURE); + } + } + } + + exit (EXIT_SUCCESS); +} + +/* Print out a usage message and die. */ + +static void +uvusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uuconv -i input -o output [-p program] [-I file]\n"); + fprintf (stderr, + " -i input: Set input type (one of taylor, v2, hdb)\n"); + fprintf (stderr, + " -o output: Set output type (one of taylor, v2, hdb)\n"); + fprintf (stderr, + " -p program: Program to convert (e.g., uucp or cu)\n"); + fprintf (stderr, + " -I file: Set Taylor UUCP configuration file to use\n"); + exit (EXIT_FAILURE); +} + +/* Write out a timespan. */ + +static void +uvwrite_time (e, qtime) + FILE *e; + struct uuconf_timespan *qtime; +{ + if (qtime == NULL) + { + fprintf (e, "Never"); + return; + } + + if (qtime->uuconf_istart == 0 && qtime->uuconf_iend == 7 * 24 * 60) + { + fprintf (e, "Any"); + return; + } + + for (; qtime != NULL; qtime = qtime->uuconf_qnext) + { + int idaystart, idayend; + int ihourstart, ihourend; + int iminutestart, iminuteend; + const char * const zdays = "Su\0Mo\0Tu\0We\0Th\0Fr\0Sa"; + + idaystart = qtime->uuconf_istart / (24 * 60); + ihourstart = (qtime->uuconf_istart % (24 * 60)) / 60; + iminutestart = qtime->uuconf_istart % 60; + if (qtime->uuconf_iend >= 7 * 24 * 60) + qtime->uuconf_iend = 7 * 24 * 60 - 1; + idayend = qtime->uuconf_iend / (24 * 60); + ihourend = (qtime->uuconf_iend % (24 * 60)) / 60; + iminuteend = qtime->uuconf_iend % 60; + if (ihourend == 0 && iminuteend == 0) + --idayend; + + if (idaystart == idayend) + fprintf (e, "%s%02d%02d-%02d%02d", zdays + idaystart * 3, + ihourstart, iminutestart, ihourend, iminuteend); + else + { + int i; + + fprintf (e, "%s%02d%02d-0000", zdays + idaystart * 3, + ihourstart, iminutestart); + for (i = idaystart + 1; i < idayend; i++) + fprintf (e, ",%s", zdays + i * 3); + if (ihourend != 0 || iminuteend != 0) + fprintf (e, ",%s0000-%02d%02d", zdays + idayend * 3, ihourend, + iminuteend); + } + + if (qtime->uuconf_qnext != NULL) + fprintf (e, ","); + } +} + +/* Some subroutines used when writing out Taylor UUCP configuration + files. */ + +/* Write a command with a string argument. */ + +static void +uvwrite_string (e, zarg, zcmd) + FILE *e; + const char *zarg; + const char *zcmd; +{ + if (zarg != (const char *) &_uuconf_unset) + fprintf (e, "%s %s\n", zcmd, zarg == NULL ? (const char *) "" : zarg); +} + +/* Write out a size restriction command. */ + +static void +uvwrite_size (e, qtime, zcmd) + FILE *e; + struct uuconf_timespan *qtime; + const char *zcmd; +{ + if (qtime != (struct uuconf_timespan *) &_uuconf_unset) + { + for (; qtime != NULL; qtime = qtime->uuconf_qnext) + { + fprintf (e, "%s %ld", zcmd, qtime->uuconf_ival); + uvwrite_time (e, qtime); + fprintf (e, "\n"); + } + } +} + +/* Write out a boolean argument with a string command. If the value + is less than zero, than it was uninitialized and we don't write + anything. */ + +static void +uvwrite_boolean (e, fval, zcmd) + FILE *e; + int fval; + const char *zcmd; +{ + if (fval >= 0) + fprintf (e, "%s %s\n", zcmd, fval > 0 ? "true" : "false"); +} + +/* Write out a string array as a single command. */ + +static void +uvwrite_string_array (e, pz, zcmd) + FILE *e; + char **pz; + const char *zcmd; +{ + if (pz != (char **) &_uuconf_unset) + { + fprintf (e, "%s", zcmd); + if (pz != NULL) + for (; *pz != NULL; pz++) + fprintf (e, " %s", *pz); + fprintf (e, "\n"); + } +} + +/* Write out a chat script. Don't separate subsend/subexpect strings + by spaces. */ + +static void +uvwrite_chat_script (e, pzarg) + FILE *e; + char **pzarg; +{ + char **pz; + + if (pzarg == NULL || pzarg == (char **) &_uuconf_unset) + return; + + for (pz = pzarg; *pz != NULL; pz++) + { + if ((*pz)[0] != '-' && pz != pzarg) + fprintf (e, " "); + fprintf (e, *pz); + } +} + +/* Write out chat information. If the qlast argument is not NULL, + then only values that are different from qlast should be written. + The fforce argument is used to get around a peculiar problem: if + the ``chat'' command is used with no arguments for a system, then + uuconf_pzchat will be NULL (not &_uuconf_unset) and the default + chat script will not be used. We must distinguish this case from + the ``chat'' command not appearing at all for a port or dialer, in + which case the value will again be NULL. In the former case we + must output a ``chat'' command, in the latter case we would prefer + not to. */ + +static void +uvwrite_chat (e, q, qlast, zprefix, fforce) + FILE *e; + const struct uuconf_chat *q; + const struct uuconf_chat *qlast; + const char *zprefix; + boolean fforce; +{ + char **pz; + char ab[100]; + + if (q->uuconf_pzchat != (char **) &_uuconf_unset + && (qlast == NULL + ? (fforce || q->uuconf_pzchat != NULL) + : qlast->uuconf_pzchat != q->uuconf_pzchat)) + { + fprintf (e, "%schat ", zprefix); + uvwrite_chat_script (e, q->uuconf_pzchat); + fprintf (e, "\n"); + } + + if (q->uuconf_pzprogram != (char **) &_uuconf_unset + && (qlast == NULL + ? q->uuconf_pzprogram != NULL + : qlast->uuconf_pzprogram != q->uuconf_pzprogram)) + { + sprintf (ab, "%schat-program", zprefix); + uvwrite_string_array (e, q->uuconf_pzprogram, ab); + } + + if (q->uuconf_ctimeout >= 0 + && (qlast == NULL + || qlast->uuconf_ctimeout != q->uuconf_ctimeout)) + fprintf (e, "%schat-timeout %d\n", zprefix, q->uuconf_ctimeout); + + if (q->uuconf_pzfail != NULL + && q->uuconf_pzfail != (char **) &_uuconf_unset + && (qlast == NULL + || qlast->uuconf_pzfail != q->uuconf_pzfail)) + for (pz = q->uuconf_pzfail; *pz != NULL; pz++) + fprintf (e, "%schat-fail %s\n", zprefix, *pz); + + if (qlast == NULL || qlast->uuconf_fstrip != q->uuconf_fstrip) + { + sprintf (ab, "%schat-strip", zprefix); + uvwrite_boolean (e, q->uuconf_fstrip, ab); + } +} + +/* Write out protocol parameters to a Taylor UUCP file. */ + +static void +uvwrite_proto_params (e, qparams, zprefix) + FILE *e; + const struct uuconf_proto_param *qparams; + const char *zprefix; +{ + const struct uuconf_proto_param *qp; + + if (qparams == NULL + || qparams == (struct uuconf_proto_param *) &_uuconf_unset) + return; + + for (qp = qparams; qp->uuconf_bproto != '\0'; qp++) + { + const struct uuconf_proto_param_entry *qe; + + for (qe = qp->uuconf_qentries; qe->uuconf_cargs > 0; qe++) + { + int i; + + fprintf (e, "%sprotocol-parameter %c", zprefix, qp->uuconf_bproto); + for (i = 0; i < qe->uuconf_cargs; i++) + fprintf (e, " %s", qe->uuconf_pzargs[i]); + fprintf (e, "\n"); + } + } +} + +/* Write out Taylor UUCP system information. */ + +static void +uvwrite_taylor_system (e, q) + FILE *e; + const struct uuconf_system *q; +{ + char **pz; + const struct uuconf_system *qlast; + + fprintf (e, "# Start of system %s\n", q->uuconf_zname); + + fprintf (e, "system %s\n", q->uuconf_zname); + if (q->uuconf_pzalias != NULL + && q->uuconf_pzalias != (char **) &_uuconf_unset) + for (pz = q->uuconf_pzalias; *pz != NULL; pz++) + uvwrite_string (e, *pz, "alias"); + + for (qlast = NULL; q != NULL; qlast = q, q = q->uuconf_qalternate) + { + struct uuconf_timespan *qtime; + + if (qlast != NULL) + { + fprintf (e, "alternate"); + if (q->uuconf_zalternate != (char *) &_uuconf_unset + && q->uuconf_zalternate != NULL) + fprintf (e, " %s", q->uuconf_zalternate); + fprintf (e, "\n"); + } + +#define CHANGED(x) (qlast == NULL || qlast->x != q->x) + + if (CHANGED (uuconf_qtimegrade) + && (q->uuconf_qtimegrade + != (struct uuconf_timespan *) &_uuconf_unset)) + { + if (q->uuconf_qtimegrade == NULL) + fprintf (e, "time never\n"); + else + { + for (qtime = q->uuconf_qtimegrade; + qtime != NULL; + qtime = qtime->uuconf_qnext) + { + if ((char) qtime->uuconf_ival == UUCONF_GRADE_LOW) + fprintf (e, "time "); + else + fprintf (e, "timegrade %c ", (char) qtime->uuconf_ival); + uvwrite_time (e, qtime); + if (qtime->uuconf_cretry != 0) + fprintf (e, " %d", qtime->uuconf_cretry); + fprintf (e, "\n"); + } + } + } + + if (CHANGED (uuconf_qcalltimegrade) + && (q->uuconf_qcalltimegrade + != (struct uuconf_timespan *) &_uuconf_unset)) + { + for (qtime = q->uuconf_qcalltimegrade; + qtime != NULL; + qtime = qtime->uuconf_qnext) + { + fprintf (e, "call-timegrade %c ", (char) qtime->uuconf_ival); + uvwrite_time (e, qtime); + fprintf (e, "\n"); + } + } + + if (CHANGED (uuconf_qcall_local_size)) + uvwrite_size (e, q->uuconf_qcall_local_size, "call-local-size"); + + if (CHANGED (uuconf_qcall_remote_size)) + uvwrite_size (e, q->uuconf_qcall_remote_size, "call-remote-size"); + + if (CHANGED (uuconf_qcalled_local_size)) + uvwrite_size (e, q->uuconf_qcalled_local_size, "called-local-size"); + + if (CHANGED (uuconf_qcalled_remote_size)) + uvwrite_size (e, q->uuconf_qcalled_remote_size, "called-remote-size"); + + if (CHANGED (uuconf_ibaud) || CHANGED (uuconf_ihighbaud)) + { + if (q->uuconf_ibaud >= 0) + { + if (q->uuconf_ihighbaud > 0) + fprintf (e, "baud-range %ld %ld\n", q->uuconf_ibaud, + q->uuconf_ihighbaud); + else + fprintf (e, "baud %ld\n", q->uuconf_ibaud); + } + } + + if (CHANGED (uuconf_zport) || CHANGED (uuconf_qport)) + { + if (q->uuconf_zport != NULL + && q->uuconf_zport != (char *) &_uuconf_unset) + uvwrite_string (e, q->uuconf_zport, "port"); + else if (q->uuconf_qport != NULL + && (q->uuconf_qport + != (struct uuconf_port *) &_uuconf_unset)) + uvwrite_taylor_port (e, q->uuconf_qport, "port "); + } + + if (CHANGED (uuconf_zphone)) + { + const char *zcmd; + + if (q->uuconf_qport != NULL + && q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset + && (q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TCP + || q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TLI)) + zcmd = "address"; + else + zcmd = "phone"; + uvwrite_string (e, q->uuconf_zphone, zcmd); + } + + uvwrite_chat (e, &q->uuconf_schat, + (qlast == NULL + ? (struct uuconf_chat *) NULL + : &qlast->uuconf_schat), + "", TRUE); + + if (CHANGED (uuconf_zcall_login)) + uvwrite_string (e, q->uuconf_zcall_login, "call-login"); + + if (CHANGED (uuconf_zcall_password)) + uvwrite_string (e, q->uuconf_zcall_password, "call-password"); + + if (CHANGED (uuconf_zcalled_login)) + uvwrite_string (e, q->uuconf_zcalled_login, "called-login"); + + if (CHANGED (uuconf_fcallback)) + uvwrite_boolean (e, q->uuconf_fcallback, "callback"); + + if (CHANGED (uuconf_fsequence)) + uvwrite_boolean (e, q->uuconf_fsequence, "sequence"); + + if (CHANGED (uuconf_zprotocols)) + uvwrite_string (e, q->uuconf_zprotocols, "protocol"); + + if (CHANGED (uuconf_qproto_params)) + uvwrite_proto_params (e, q->uuconf_qproto_params, ""); + + uvwrite_chat (e, &q->uuconf_scalled_chat, + (qlast == NULL + ? (struct uuconf_chat *) NULL + : &qlast->uuconf_scalled_chat), + "called-", FALSE); + + if (CHANGED (uuconf_zdebug)) + uvwrite_string (e, q->uuconf_zdebug, "debug"); + + if (CHANGED (uuconf_zmax_remote_debug)) + uvwrite_string (e, q->uuconf_zmax_remote_debug, "max-remote-debug"); + + if ((CHANGED (uuconf_fsend_request) + || CHANGED (uuconf_frec_request)) + && (q->uuconf_fsend_request >= 0 + || q->uuconf_frec_request >= 0)) + { + if (q->uuconf_fsend_request >= 0 + && (q->uuconf_fsend_request > 0 + ? q->uuconf_frec_request > 0 + : q->uuconf_frec_request == 0)) + uvwrite_boolean (e, q->uuconf_fsend_request, "request"); + else + { + uvwrite_boolean (e, q->uuconf_fsend_request, "send-request"); + uvwrite_boolean (e, q->uuconf_frec_request, + "receive-request"); + } + } + + if ((CHANGED (uuconf_fcall_transfer) + || CHANGED (uuconf_fcalled_transfer)) + && (q->uuconf_fcall_transfer >= 0 + || q->uuconf_fcalled_transfer >= 0)) + { + if (q->uuconf_fcall_transfer >= 0 + && (q->uuconf_fcall_transfer > 0 + ? q->uuconf_fcalled_transfer > 0 + : q->uuconf_fcalled_transfer == 0)) + uvwrite_boolean (e, q->uuconf_fcall_transfer, "transfer"); + else + { + uvwrite_boolean (e, q->uuconf_fcall_transfer, "call-transfer"); + uvwrite_boolean (e, q->uuconf_fcalled_transfer, + "called-transfer"); + } + } + + if (CHANGED (uuconf_pzlocal_send)) + uvwrite_string_array (e, q->uuconf_pzlocal_send, "local-send"); + + if (CHANGED (uuconf_pzremote_send)) + uvwrite_string_array (e, q->uuconf_pzremote_send, "remote-send"); + + if (CHANGED (uuconf_pzlocal_receive)) + uvwrite_string_array (e, q->uuconf_pzlocal_receive, "local-receive"); + + if (CHANGED (uuconf_pzremote_receive)) + uvwrite_string_array (e, q->uuconf_pzremote_receive, + "remote-receive"); + + if (CHANGED (uuconf_pzpath)) + uvwrite_string_array (e, q->uuconf_pzpath, "command-path"); + + if (CHANGED (uuconf_pzcmds)) + uvwrite_string_array (e, q->uuconf_pzcmds, "commands"); + + if (CHANGED (uuconf_cfree_space) + && q->uuconf_cfree_space >= 0) + fprintf (e, "free-space %ld\n", q->uuconf_cfree_space); + + if (CHANGED (uuconf_pzforward_from)) + uvwrite_string_array (e, q->uuconf_pzforward_from, "forward-from"); + + if (CHANGED (uuconf_pzforward_to)) + uvwrite_string_array (e, q->uuconf_pzforward_to, "forward-to"); + + if (CHANGED (uuconf_zpubdir)) + uvwrite_string (e, q->uuconf_zpubdir, "pubdir"); + + if (CHANGED (uuconf_zlocalname)) + uvwrite_string (e, q->uuconf_zlocalname, "myname"); + } +} + +/* Write out V2 system information. */ + +static void +uvwrite_v2_system (e, q) + FILE *e; + const struct uuconf_system *q; +{ + for (; q != NULL; q = q->uuconf_qalternate) + { + fprintf (e, "%s", q->uuconf_zname); + + if (q->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset) + { + fprintf (e, " "); + uvwrite_time (e, q->uuconf_qtimegrade); + + if (q->uuconf_zport != (char *) &_uuconf_unset + || q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset) + { + struct uuconf_port *qp; + boolean ftcp; + + qp = q->uuconf_qport; + ftcp = (qp != (struct uuconf_port *) &_uuconf_unset + && qp != NULL + && qp->uuconf_ttype == UUCONF_PORTTYPE_TCP); + if (ftcp + || (q->uuconf_zport != NULL + && q->uuconf_zport != (char *) &_uuconf_unset)) + { + if (ftcp) + fprintf (e, " TCP"); + else + fprintf (e, " %s", q->uuconf_zport); + + if (ftcp || q->uuconf_ibaud >= 0) + { + fprintf (e, " "); + if (ftcp) + { + const char *zport; + + zport = qp->uuconf_u.uuconf_stcp.uuconf_zport; + if (zport == NULL) + zport = "uucp"; + fprintf (e, "%s", zport); + } + else + fprintf (e, "%ld", q->uuconf_ibaud); + + if (q->uuconf_zphone != (char *) &_uuconf_unset + && q->uuconf_zphone != NULL) + { + char **pzc; + + fprintf (e, " %s", q->uuconf_zphone); + pzc = q->uuconf_schat.uuconf_pzchat; + if (pzc != (char **) &_uuconf_unset + && pzc != NULL) + { + fprintf (e, " "); + uvwrite_chat_script (e, pzc); + } + } + } + } + } + } + + fprintf (e, "\n"); + + /* Here we should gather information to write out to USERFILE + and L.cmds, and perhaps some day we will. It's much more + likely to happen if somebody else does it, though. */ + } +} + +/* Write out HDB system information. */ + +static void +uvwrite_hdb_system (e, qsys) + FILE *e; + const struct uuconf_system *qsys; +{ + const struct uuconf_system *q; + struct shpermissions sperm; + char *azmachine[2]; + char *azlogname[2]; + + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + { + if (q->uuconf_fcall) + { + fprintf (e, "%s", q->uuconf_zname); + + if (q->uuconf_qtimegrade + != (struct uuconf_timespan *) &_uuconf_unset) + { + const char *zport; + + fprintf (e, " "); + uvwrite_time (e, q->uuconf_qtimegrade); + + zport = q->uuconf_zport; + if (q->uuconf_qport != NULL + && q->uuconf_qport != (struct uuconf_port *) &_uuconf_unset + && q->uuconf_qport->uuconf_ttype == UUCONF_PORTTYPE_TCP) + zport = "TCP"; + if (zport != NULL && zport != (char *) &_uuconf_unset) + { + fprintf (e, " %s", zport); + if (q->uuconf_zprotocols != (char *) &_uuconf_unset + && q->uuconf_zprotocols != NULL) + fprintf (e, ",%s", q->uuconf_zprotocols); + + if (q->uuconf_ibaud >= 0 + || q->uuconf_zphone != (char *) &_uuconf_unset) + { + fprintf (e, " "); + if (q->uuconf_ibaud < 0) + fprintf (e, "Any"); + else + { + fprintf (e, "%ld", q->uuconf_ibaud); + if (q->uuconf_ihighbaud >= 0) + fprintf (e, "-%ld", q->uuconf_ihighbaud); + } + + if (q->uuconf_zphone != (char *) &_uuconf_unset + && q->uuconf_zphone != NULL) + { + char **pzc; + + fprintf (e, " %s", q->uuconf_zphone); + pzc = q->uuconf_schat.uuconf_pzchat; + if (pzc != (char **) &_uuconf_unset + && pzc != NULL) + { + fprintf (e, " "); + uvwrite_chat_script (e, pzc); + } + } + } + } + } + + fprintf (e, "\n"); + } + } + + /* Build a Permissions entry for this system. There will be only + one MACHINE entry for a given system. */ + + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + if (q->uuconf_fcall) + break; + + if (q != NULL) + { + sperm.qnext = NULL; + sperm.pzlogname = NULL; + sperm.pzmachine = NULL; + sperm.frequest = -1; + sperm.fsendfiles = -1; + sperm.pzread = NULL; + sperm.pzwrite = NULL; + sperm.fcallback = -1; + sperm.pzcommands = NULL; + sperm.pzvalidate = NULL; + sperm.zmyname = NULL; + sperm.zpubdir = NULL; + sperm.pzalias = NULL; + + azmachine[0] = q->uuconf_zname; + azmachine[1] = NULL; + sperm.pzmachine = azmachine; + if (q->uuconf_fsend_request >= 0) + sperm.frequest = q->uuconf_fsend_request; + if (q->uuconf_pzremote_send != (char **) &_uuconf_unset + && q->uuconf_pzremote_send != NULL) + sperm.pzread = q->uuconf_pzremote_send; + if (q->uuconf_pzremote_receive != (char **) &_uuconf_unset + && q->uuconf_pzremote_receive != NULL) + sperm.pzwrite = q->uuconf_pzremote_receive; + if (q->uuconf_pzcmds != (char **) &_uuconf_unset + && q->uuconf_pzcmds != NULL) + sperm.pzcommands = q->uuconf_pzcmds; + if (q->uuconf_zlocalname != (char *) &_uuconf_unset + && q->uuconf_zlocalname != NULL) + sperm.zmyname = q->uuconf_zlocalname; + if (q->uuconf_zpubdir != (char *) &_uuconf_unset + && q->uuconf_zpubdir != NULL) + sperm.zpubdir = q->uuconf_zpubdir; + if (q->uuconf_pzalias != (char **) &_uuconf_unset + && q->uuconf_pzalias != NULL) + sperm.pzalias = q->uuconf_pzalias; + + if (q->uuconf_fcalled + && q->uuconf_zcalled_login != (char *) &_uuconf_unset + && q->uuconf_zcalled_login != NULL) + { + azlogname[0] = q->uuconf_zcalled_login; + azlogname[1] = NULL; + sperm.pzlogname = azlogname; + if (q->uuconf_fcalled_transfer >= 0) + sperm.fsendfiles = q->uuconf_fcalled_transfer; + if (q->uuconf_fcallback >= 0) + sperm.fcallback = q->uuconf_fcallback; + sperm.pzvalidate = azmachine; + } + + uvadd_perm (&sperm); + } + + /* Now add a Permissions entry for each alternative that is not used + for calling out. */ + for (q = qsys; q != NULL; q = q->uuconf_qalternate) + { + if (! q->uuconf_fcalled || q->uuconf_fcall) + continue; + + sperm.qnext = NULL; + sperm.pzlogname = NULL; + sperm.pzmachine = NULL; + sperm.frequest = -1; + sperm.fsendfiles = -1; + sperm.pzread = NULL; + sperm.pzwrite = NULL; + sperm.fcallback = -1; + sperm.pzcommands = NULL; + sperm.pzvalidate = NULL; + sperm.zmyname = NULL; + sperm.zpubdir = NULL; + sperm.pzalias = NULL; + + if (q->uuconf_zcalled_login != (char *) &_uuconf_unset + && q->uuconf_zcalled_login != NULL) + azlogname[0] = q->uuconf_zcalled_login; + else + azlogname[0] = (char *) "OTHER"; + azlogname[1] = NULL; + sperm.pzlogname = azlogname; + + if (q->uuconf_fsend_request >= 0) + sperm.frequest = q->uuconf_fsend_request; + if (q->uuconf_fcalled_transfer >= 0) + sperm.fsendfiles = q->uuconf_fcalled_transfer; + if (q->uuconf_pzremote_send != (char **) &_uuconf_unset + && q->uuconf_pzremote_send != NULL) + sperm.pzread = q->uuconf_pzremote_send; + if (q->uuconf_pzremote_receive != (char **) &_uuconf_unset + && q->uuconf_pzremote_receive != NULL) + sperm.pzwrite = q->uuconf_pzremote_receive; + if (q->uuconf_fcallback >= 0) + sperm.fcallback = q->uuconf_fcallback; + if (q->uuconf_zlocalname != (char *) &_uuconf_unset + && q->uuconf_zlocalname != NULL) + sperm.zmyname = q->uuconf_zlocalname; + if (q->uuconf_zpubdir != (char *) &_uuconf_unset + && q->uuconf_zpubdir != NULL) + sperm.zpubdir = q->uuconf_zpubdir; + + uvadd_perm (&sperm); + } +} + +/* Compare two strings from a Permissions entry, returning TRUE if + they are the same. */ +static boolean +fvperm_string_cmp (z1, z2) + const char *z1; + const char *z2; +{ + if (z1 == NULL + ? z2 != NULL + : z2 == NULL) + return FALSE; + + if (z1 == NULL) + return TRUE; + + return strcmp (z1, z2) == 0; +} + +/* Compare two arrays of strings from a Permissions entry, returning + TRUE if they are the same. */ + +static boolean +fvperm_array_cmp (pz1, pz2) + const char **pz1; + const char **pz2; +{ + if (pz1 == NULL + ? pz2 != NULL + : pz2 == NULL) + return FALSE; + + if (pz1 == NULL) + return TRUE; + + for (; *pz1 != NULL && *pz2 != NULL; pz1++, pz2++) + if (strcmp (*pz1, *pz2) != 0) + break; + + return *pz1 == NULL && *pz2 == NULL; +} + +/* Add a Permissions entry to a global list, combining entries where + possible. */ + +static void +uvadd_perm (qadd) + struct shpermissions *qadd; +{ + struct shpermissions *qlook; + struct shpermissions *qnew; + int iret; + + /* If there's no information, don't bother to add this entry. */ + if (qadd->pzlogname == NULL + && qadd->frequest < 0 + && qadd->fsendfiles < 0 + && qadd->pzread == NULL + && qadd->pzwrite == NULL + && qadd->fcallback < 0 + && qadd->pzcommands == NULL + && qadd->pzvalidate == NULL + && qadd->zmyname == NULL + && qadd->zpubdir == NULL + && qadd->pzalias == NULL) + return; + + for (qlook = qVperms; qlook != NULL; qlook = qlook->qnext) + { + /* See if we can merge qadd into qlook. */ + if (qadd->pzlogname == NULL + ? qlook->pzlogname != NULL + : qlook->pzlogname == NULL) + continue; + if (qadd->pzmachine == NULL + ? qlook->pzmachine != NULL + : qlook->pzmachine == NULL) + continue; + if (qadd->frequest != qlook->frequest + || qadd->fsendfiles != qlook->fsendfiles + || qadd->fcallback != qlook->fcallback) + continue; + if (! fvperm_string_cmp (qadd->zmyname, qlook->zmyname) + || ! fvperm_string_cmp (qadd->zpubdir, qlook->zpubdir)) + continue; + if (! fvperm_array_cmp ((const char **) qadd->pzread, + (const char **) qlook->pzread) + || ! fvperm_array_cmp ((const char **) qadd->pzwrite, + (const char **) qlook->pzwrite) + || ! fvperm_array_cmp ((const char **) qadd->pzcommands, + (const char **) qlook->pzcommands)) + continue; + + /* Merge qadd into qlook. */ + if (qadd->pzmachine != NULL) + { + iret = _uuconf_iadd_string ((struct sglobal *) NULL, + qadd->pzmachine[0], FALSE, + TRUE, &qlook->pzmachine, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + uvuuconf_error ((pointer) NULL, iret); + } + if (qadd->pzlogname != NULL) + { + iret = _uuconf_iadd_string ((struct sglobal *) NULL, + qadd->pzlogname[0], FALSE, + TRUE, &qlook->pzlogname, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + uvuuconf_error ((pointer) NULL, iret); + } + if (qadd->pzalias != NULL) + { + char **pz; + + for (pz = qadd->pzalias; *pz != NULL; pz++) + { + iret = _uuconf_iadd_string ((struct sglobal *) NULL, + *pz, FALSE, TRUE, + &qlook->pzalias, (pointer) NULL); + if (iret != UUCONF_SUCCESS) + uvuuconf_error ((pointer) NULL, iret); + } + } + + return; + } + + /* We must add qadd as a new entry on the list, which means we must + copy it into the heap. */ + + qnew = (struct shpermissions *) malloc (sizeof (struct shpermissions)); + if (qnew == NULL) + uvuuconf_error ((pointer) NULL, UUCONF_MALLOC_FAILED); + *qnew = *qadd; + if (qadd->pzmachine != NULL) + { + qnew->pzmachine = NULL; + iret = _uuconf_iadd_string ((struct sglobal *) NULL, + qadd->pzmachine[0], FALSE, + FALSE, &qnew->pzmachine, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + uvuuconf_error ((pointer) NULL, iret); + } + if (qadd->pzlogname != NULL) + { + qnew->pzlogname = NULL; + iret = _uuconf_iadd_string ((struct sglobal *) NULL, + qadd->pzlogname[0], FALSE, + FALSE, &qnew->pzlogname, + (pointer) NULL); + if (iret != UUCONF_SUCCESS) + uvuuconf_error ((pointer) NULL, iret); + } + if (qadd->pzvalidate != NULL) + qnew->pzvalidate = qnew->pzmachine; + + qnew->qnext = qVperms; + qVperms = qnew; +} + +/* Write out the Permissions entries. */ + +static void +uvwrite_perms () +{ + char ab[sizeof ZCURDIR + sizeof HDB_PERMISSIONS - 1]; + FILE *e; + struct shpermissions *q; + + sprintf (ab, "%s%s", ZCURDIR, HDB_PERMISSIONS); + e = fopen (ab, "w"); + if (e == NULL) + { + fprintf (stderr, "uuchk:%s: ", ab); + perror ("fopen"); + exit (EXIT_FAILURE); + } + + fprintf (e, "# Permissions file automatically generated by uuconv.\n"); + + for (q = qVperms; q != NULL; q = q->qnext) + { + size_t ccol; + + ccol = 0; + uvwrite_perm_array (e, (const char **) q->pzlogname, "LOGNAME", &ccol); + uvwrite_perm_array (e, (const char **) q->pzmachine, "MACHINE", &ccol); + uvwrite_perm_boolean (e, q->frequest, "REQUEST", &ccol, FALSE); + uvwrite_perm_boolean (e, q->fsendfiles, "SENDFILES", &ccol, TRUE); + uvwrite_perm_rw_array (e, (const char **) q->pzread, "READ", &ccol); + uvwrite_perm_rw_array (e, (const char **) q->pzwrite, "WRITE", &ccol); + uvwrite_perm_boolean (e, q->fcallback, "CALLBACK", &ccol, FALSE); + uvwrite_perm_array (e, (const char **) q->pzcommands, "COMMANDS", + &ccol); + uvwrite_perm_array (e, (const char **) q->pzvalidate, "VALIDATE", + &ccol); + uvwrite_perm_string (e, q->zmyname, "MYNAME", &ccol); + uvwrite_perm_string (e, q->zpubdir, "PUBDIR", &ccol); + uvwrite_perm_array (e, (const char **) q->pzalias, "ALIAS", &ccol); + + fprintf (e, "\n"); + } + + if (ferror (e) + || fclose (e) == EOF) + { + fprintf (stderr, "uuchk:%s: error during output\n", HDB_PERMISSIONS); + exit (EXIT_FAILURE); + } +} + +/* Write an array out to the Permissions file. */ + +static void +uvwrite_perm_array (e, pzarg, zcmd, pccol) + FILE *e; + const char **pzarg; + const char *zcmd; + size_t *pccol; +{ + size_t c; + const char **pz; + + if (pzarg == NULL) + return; + + c = strlen (zcmd) + 1; + + for (pz = pzarg; *pz != NULL; pz++) + c += strlen (*pz) + 1; + + if (*pccol > 20 && c + *pccol > 75) + { + fprintf (e, " \\\n"); + *pccol = c - 1; + } + else + { + if (*pccol != 0) + fprintf (e, " "); + *pccol += c; + } + + fprintf (e, "%s=", zcmd); + for (pz = pzarg; *pz != NULL; pz++) + { + if (pz != pzarg) + fprintf (e, ":"); + fprintf (e, "%s", *pz); + } +} + +/* Write a boolean value out to the Permissions file. This may be + either a yes/no boolean or a yes/call boolean (the latter is for + SENDFILES). */ + +static void +uvwrite_perm_boolean (e, f, zcmd, pccol, fsendfiles) + FILE *e; + int f; + const char *zcmd; + size_t *pccol; + boolean fsendfiles; +{ + const char *az[2]; + + if (f < 0) + return; + + if (f) + az[0] = "yes"; + else + az[0] = fsendfiles ? "call" : "no"; + az[1] = NULL; + + uvwrite_perm_array (e, az, zcmd, pccol); +} + +/* Write a set of READ or WRITE entries to the Permissions file. We + have to separate out all entries that start with '!'. */ + +static void +uvwrite_perm_rw_array (e, pzarg, zcmd, pccol) + FILE *e; + const char **pzarg; + const char *zcmd; + size_t *pccol; +{ + size_t c; + const char **pz, **pzcopy, **pzset; + + if (pzarg == NULL) + return; + + c = 0; + for (pz = pzarg; *pz != NULL; pz++) + c++; + + pzcopy = (const char **) malloc ((c + 1) * sizeof (char *)); + if (pzcopy == NULL) + uvuuconf_error ((pointer) NULL, UUCONF_MALLOC_FAILED); + + pzset = pzcopy; + for (pz = pzarg; *pz != NULL; pz++) + if ((*pz)[0] != '!') + *pzset++ = *pz; + *pzset = NULL; + + if (pzset != pzcopy) + uvwrite_perm_array (e, (const char **) pzcopy, zcmd, pccol); + + pzset = pzcopy; + for (pz = pzarg; *pz != NULL; pz++) + if ((*pz)[0] == '!') + *pzset++ = *pz; + *pzset = NULL; + + if (pzset != pzcopy) + { + char ab[20]; + + sprintf (ab, "NO%s", zcmd); + uvwrite_perm_array (e, (const char **) pzcopy, ab, pccol); + } +} + +/* Write a string out to the Permissions file. */ + +static void +uvwrite_perm_string (e, z, zcmd, pccol) + FILE *e; + const char *z; + const char *zcmd; + size_t *pccol; +{ + const char *az[2]; + + if (z == NULL) + return; + + az[0] = z; + az[1] = NULL; + + uvwrite_perm_array (e, az, zcmd, pccol); +} + +/* Write out a Taylor UUCP port. This is called via uuconf_find_port; + the pinfo argument is the port file. */ + +static int +ivwrite_taylor_port (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + FILE *e = (FILE *) pinfo; + + fprintf (e, "port %s\n", qport->uuconf_zname); + + uvwrite_taylor_port (e, qport, ""); + + /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking + for ports. */ + return UUCONF_NOT_FOUND; +} + +/* Write a port out to a Taylor UUCP configuration file. This doesn't + output the name, since it is called to output a specially defined + port in the sys file. */ + +static void +uvwrite_taylor_port (e, qport, zprefix) + FILE *e; + struct uuconf_port *qport; + const char *zprefix; +{ + const char *ztype; + char ab[100]; + + switch (qport->uuconf_ttype) + { + default: + case UUCONF_PORTTYPE_UNKNOWN: + fprintf (stderr, "uuconv: Bad port type\n"); + exit (EXIT_FAILURE); + break; + case UUCONF_PORTTYPE_STDIN: + ztype = "stdin"; + break; + case UUCONF_PORTTYPE_MODEM: + ztype = "modem"; + break; + case UUCONF_PORTTYPE_DIRECT: + ztype = "direct"; + break; + case UUCONF_PORTTYPE_TCP: + ztype = "tcp"; + break; + case UUCONF_PORTTYPE_TLI: + ztype = "tli"; + break; + } + + fprintf (e, "%stype %s\n", zprefix, ztype); + + if (qport->uuconf_zprotocols != NULL) + fprintf (e, "%sprotocol %s\n", zprefix, qport->uuconf_zprotocols); + + if (qport->uuconf_qproto_params != NULL) + uvwrite_proto_params (e, qport->uuconf_qproto_params, zprefix); + + if ((qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + { + sprintf (ab, "%sseven-bit", zprefix); + uvwrite_boolean (e, + ((qport->uuconf_ireliable & UUCONF_RELIABLE_EIGHT) + == 0), + ab); + sprintf (ab, "%sreliable", zprefix); + uvwrite_boolean (e, + ((qport->uuconf_ireliable & UUCONF_RELIABLE_RELIABLE) + != 0), + ab); + sprintf (ab, "%shalf-duplex", zprefix); + uvwrite_boolean (e, + ((qport->uuconf_ireliable & UUCONF_RELIABLE_FULLDUPLEX) + == 0), + ab); + } + + if (qport->uuconf_zlockname != NULL) + fprintf (e, "%slockname %s\n", zprefix, qport->uuconf_zlockname); + + switch (qport->uuconf_ttype) + { + default: + break; + case UUCONF_PORTTYPE_MODEM: + { + struct uuconf_modem_port *qm; + + qm = &qport->uuconf_u.uuconf_smodem; + if (qm->uuconf_zdevice != NULL) + fprintf (e, "%sdevice %s\n", zprefix, qm->uuconf_zdevice); + if (qm->uuconf_zdial_device != NULL) + fprintf (e, "%sdial-device %s\n", zprefix, qm->uuconf_zdial_device); + if (qm->uuconf_ibaud != 0) + fprintf (e, "%sbaud %ld\n", zprefix, qm->uuconf_ibaud); + if (qm->uuconf_ilowbaud != 0) + fprintf (e, "%sbaud-range %ld %ld\n", zprefix, qm->uuconf_ilowbaud, + qm->uuconf_ihighbaud); + if (! qm->uuconf_fcarrier) + fprintf (e, "%scarrier false\n", zprefix); + if (qm->uuconf_pzdialer != NULL) + { + if (qm->uuconf_pzdialer[1] == NULL) + fprintf (e, "%sdialer %s\n", zprefix, qm->uuconf_pzdialer[0]); + else + { + sprintf (ab, "%sdialer-sequence", zprefix); + uvwrite_string_array (e, qm->uuconf_pzdialer, zprefix); + } + } + if (qm->uuconf_qdialer != NULL) + { + sprintf (ab, "%sdialer ", zprefix); + uvwrite_taylor_dialer (e, qm->uuconf_qdialer, ab); + } + } + break; + case UUCONF_PORTTYPE_DIRECT: + { + struct uuconf_direct_port *qd; + + qd = &qport->uuconf_u.uuconf_sdirect; + if (qd->uuconf_zdevice != NULL) + fprintf (e, "%sdevice %s\n", zprefix, qd->uuconf_zdevice); + if (qd->uuconf_ibaud != 0) + fprintf (e, "%sbaud %ld\n", zprefix, qd->uuconf_ibaud); + } + break; + case UUCONF_PORTTYPE_TCP: + if (qport->uuconf_u.uuconf_stcp.uuconf_zport != NULL) + fprintf (e, "%sservice %s\n", zprefix, + qport->uuconf_u.uuconf_stcp.uuconf_zport); + break; + case UUCONF_PORTTYPE_TLI: + { + struct uuconf_tli_port *qt; + + qt = &qport->uuconf_u.uuconf_stli; + if (qt->uuconf_zdevice != NULL) + fprintf (e, "%sdevice %s\n", zprefix, qt->uuconf_zdevice); + sprintf (ab, "%sstream", zprefix); + uvwrite_boolean (e, qt->uuconf_fstream, ab); + if (qt->uuconf_pzpush != NULL) + { + sprintf (ab, "%spush", zprefix); + uvwrite_string_array (e, qt->uuconf_pzpush, ab); + } + if (qt->uuconf_pzdialer != NULL) + { + sprintf (ab, "%sdialer-sequence", zprefix); + uvwrite_string_array (e, qt->uuconf_pzdialer, ab); + } + if (qt->uuconf_zservaddr != NULL) + fprintf (e, "%sserver-address %s\n", zprefix, + qt->uuconf_zservaddr); + } + break; + } +} + +/* Write out a port to the V2 L-devices file. This is called via + uuconf_find_port. */ + +static int +ivwrite_v2_port (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + FILE *e = (FILE *) pinfo; + + if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) + { + fprintf (e, "DIR %s - %ld direct", + qport->uuconf_u.uuconf_sdirect.uuconf_zdevice, + qport->uuconf_u.uuconf_sdirect.uuconf_ibaud); + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) + { + fprintf (e, "%s %s ", qport->uuconf_zname, + qport->uuconf_u.uuconf_smodem.uuconf_zdevice); + if (qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL) + fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdial_device); + else + fprintf (e, "-"); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0L) + fprintf (e, "%ld-%ld", + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud, + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud); + else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0L) + fprintf (e, "%ld", qport->uuconf_u.uuconf_smodem.uuconf_ibaud); + else + fprintf (e, "Any"); + if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) + fprintf (e, " %s", + qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]); + } + else + { + fprintf (e, "# Ignoring port %s with unsupported type", + qport->uuconf_zname); + } + + fprintf (e, "\n"); + + /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking + for a port. */ + return UUCONF_NOT_FOUND; +} + +/* Write out a port to the HDB Devices file. This is called via + uuconf_find_port. */ + +static int +ivwrite_hdb_port (qport, pinfo) + struct uuconf_port *qport; + pointer pinfo; +{ + FILE *e = (FILE *) pinfo; + + if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) + { + fprintf (e, "Direct"); + if (qport->uuconf_zprotocols != NULL) + fprintf (e, ",%s", qport->uuconf_zprotocols); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_sdirect.uuconf_zdevice != NULL) + fprintf (e, "%s", qport->uuconf_u.uuconf_sdirect.uuconf_zdevice); + else + fprintf (e, "%s", qport->uuconf_zname); + fprintf (e, " - %ld", qport->uuconf_u.uuconf_sdirect.uuconf_ibaud); + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) + { + fprintf (e, "%s", qport->uuconf_zname); + if (qport->uuconf_zprotocols != NULL) + fprintf (e, ",%s", qport->uuconf_zprotocols); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_smodem.uuconf_zdevice != NULL) + fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdevice); + else + fprintf (e, "%s", qport->uuconf_zname); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL) + fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdial_device); + else + fprintf (e, "-"); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0L) + fprintf (e, "%ld-%ld", + qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud, + qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud); + else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0L) + fprintf (e, "%ld", qport->uuconf_u.uuconf_smodem.uuconf_ibaud); + else + fprintf (e, "Any"); + if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) + { + char **pz; + + for (pz = qport->uuconf_u.uuconf_smodem.uuconf_pzdialer; + *pz != NULL; + pz++) + fprintf (e, " %s", *pz); + } + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP) + { + fprintf (e, "TCP"); + if (qport->uuconf_zprotocols != NULL) + fprintf (e, ",%s", qport->uuconf_zprotocols); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_stcp.uuconf_zport == NULL) + fprintf (e, "uucp"); + else + fprintf (e, "%s", qport->uuconf_u.uuconf_stcp.uuconf_zport); + fprintf (e, " - -"); + } + else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI) + { + char **pz; + + fprintf (e, "%s", qport->uuconf_zname); + if (qport->uuconf_zprotocols != NULL) + fprintf (e, ",%s", qport->uuconf_zprotocols); + fprintf (e, " "); + if (qport->uuconf_u.uuconf_stli.uuconf_zdevice != NULL) + fprintf (e, "%s", qport->uuconf_u.uuconf_smodem.uuconf_zdevice); + else + fprintf (e, "-"); + fprintf (e, " - -"); + pz = qport->uuconf_u.uuconf_stli.uuconf_pzdialer; + if (pz == NULL + || *pz == NULL + || (strcmp (*pz, "TLI") != 0 + && strcmp (*pz, "TLIS") != 0)) + fprintf (e, " TLI%s \\D", + qport->uuconf_u.uuconf_stli.uuconf_fstream ? "S" : ""); + if (pz != NULL) + for (; *pz != NULL; pz++) + fprintf (e, " %s", *pz); + } + else + { + fprintf (e, "# Ignoring port %s with unsupported type", + qport->uuconf_zname); + } + + fprintf (e, "\n"); + + /* Return UUCONF_NOT_FOUND to force uuconf_find_port to keep looking + for a port. */ + return UUCONF_NOT_FOUND; +} + +/* Write a dialer out to a Taylor UUCP configuration file. This + doesn't output the name, since it is called to output a specially + defined dialer in the sys or port file. */ + +static void +uvwrite_taylor_dialer (e, qdialer, zprefix) + FILE *e; + struct uuconf_dialer *qdialer; + const char *zprefix; +{ + char ab[100]; + + /* Reset default values, so we don't output them unnecessarily. */ + if (qdialer->uuconf_schat.uuconf_ctimeout == 60) + qdialer->uuconf_schat.uuconf_ctimeout = -1; + if (qdialer->uuconf_schat.uuconf_fstrip) + qdialer->uuconf_schat.uuconf_fstrip = -1; + if (qdialer->uuconf_scomplete.uuconf_ctimeout == 60) + qdialer->uuconf_scomplete.uuconf_ctimeout = -1; + if (qdialer->uuconf_scomplete.uuconf_fstrip) + qdialer->uuconf_scomplete.uuconf_fstrip = -1; + if (qdialer->uuconf_sabort.uuconf_ctimeout == 60) + qdialer->uuconf_sabort.uuconf_ctimeout = -1; + if (qdialer->uuconf_sabort.uuconf_fstrip) + qdialer->uuconf_sabort.uuconf_fstrip = -1; + + uvwrite_chat (e, &qdialer->uuconf_schat, (struct uuconf_chat *) NULL, + zprefix, FALSE); + if (qdialer->uuconf_zdialtone != NULL + && strcmp (qdialer->uuconf_zdialtone, ",") != 0) + fprintf (e, "%sdialtone %s\n", zprefix, qdialer->uuconf_zdialtone); + if (qdialer->uuconf_zpause != NULL + && strcmp (qdialer->uuconf_zpause, ",") != 0) + fprintf (e, "%spause %s\n", zprefix, qdialer->uuconf_zpause); + if (! qdialer->uuconf_fcarrier) + fprintf (e, "%scarrier false\n", zprefix); + if (qdialer->uuconf_ccarrier_wait != 60) + fprintf (e, "%scarrier-wait %d\n", zprefix, + qdialer->uuconf_ccarrier_wait); + if (qdialer->uuconf_fdtr_toggle) + fprintf (e, "%sdtr-toggle %s %s\n", zprefix, + qdialer->uuconf_fdtr_toggle ? "true" : "false", + qdialer->uuconf_fdtr_toggle_wait ? "true" : "false"); + sprintf (ab, "%scomplete-", zprefix); + uvwrite_chat (e, &qdialer->uuconf_scomplete, (struct uuconf_chat *) NULL, + ab, FALSE); + sprintf (ab, "%sabort-", zprefix); + uvwrite_chat (e, &qdialer->uuconf_sabort, (struct uuconf_chat *) NULL, + ab, FALSE); + if (qdialer->uuconf_qproto_params != NULL) + uvwrite_proto_params (e, qdialer->uuconf_qproto_params, zprefix); + if ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) + { + sprintf (ab, "%sseven-bit", zprefix); + uvwrite_boolean (e, + ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_EIGHT) + == 0), + ab); + sprintf (ab, "%sreliable", zprefix); + uvwrite_boolean (e, + ((qdialer->uuconf_ireliable & UUCONF_RELIABLE_RELIABLE) + != 0), + ab); + sprintf (ab, "%shalf-duplex", zprefix); + uvwrite_boolean (e, + ((qdialer->uuconf_ireliable + & UUCONF_RELIABLE_FULLDUPLEX) == 0), + ab); + } +} + +/* Write a dialer out to an HDB configuration file. */ + +static void +uvwrite_hdb_dialer (e, qdialer) + FILE *e; + struct uuconf_dialer *qdialer; +{ + fprintf (e, "%s ", qdialer->uuconf_zname); + + if (qdialer->uuconf_zdialtone != NULL) + fprintf (e, "=%c", qdialer->uuconf_zdialtone[0]); + if (qdialer->uuconf_zpause != NULL) + fprintf (e, "-%c", qdialer->uuconf_zpause[0]); + + if (qdialer->uuconf_schat.uuconf_pzchat != NULL) + { + if (qdialer->uuconf_zdialtone == NULL + && qdialer->uuconf_zpause == NULL) + fprintf (e, "\"\""); + fprintf (e, " "); + uvwrite_chat_script (e, qdialer->uuconf_schat.uuconf_pzchat); + } + + fprintf (e, "\n"); +} + +/* Display a uuconf error and exit. */ + +static void +uvuuconf_error (puuconf, iret) + pointer puuconf; + int iret; +{ + char ab[512]; + + (void) uuconf_error_string (puuconf, iret, ab, sizeof ab); + if ((iret & UUCONF_ERROR_FILENAME) == 0) + fprintf (stderr, "uuconv: %s\n", ab); + else + fprintf (stderr, "uuconv:%s\n", ab); + if (UUCONF_ERROR_VALUE (iret) != UUCONF_FOPEN_FAILED) + exit (EXIT_FAILURE); +} diff --git a/gnu/libexec/uucp/uucp/Makefile b/gnu/libexec/uucp/uucp/Makefile new file mode 100644 index 0000000000..5e45460617 --- /dev/null +++ b/gnu/libexec/uucp/uucp/Makefile @@ -0,0 +1,16 @@ +# Makefile for uucp +# $Id: Makefile,v 1.2 1993/08/05 16:15:11 jtc Exp $ + +BINDIR= $(bindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uucp +SRCS= uucp.c util.c log.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uucp/uucp.1 b/gnu/libexec/uucp/uucp/uucp.1 new file mode 100644 index 0000000000..0fa81fe653 --- /dev/null +++ b/gnu/libexec/uucp/uucp/uucp.1 @@ -0,0 +1,175 @@ +''' $Id: uucp.1,v 1.1 1993/08/04 19:36:43 jtc Exp $ +.TH uucp 1 "Taylor UUCP 1.04" +.SH NAME +uucp \- Unix to Unix copy +.SH SYNOPSIS +.B uucp +[ options ] source-file destination-file +.PP +.B uucp +[ options ] source-file... destination-directory +.SH DESCRIPTION +The +.I uucp +command copies files between systems. Each +.I file +argument is either a pathname on the local machine or is of the form +.IP +system!path +.LP +which is interpreted as being on a remote system. +In the first form, the contents of the first file are copied to the +second. In the second form, each source file is copied into the +destination directory. + +A file be transferred to or from +.I system2 +via +.I system1 +by using +.IP +system1!system2!path. +.LP + +Any pathname that does not begin with / or ~ will be appended to the +current directory (unless the +.B \-W +option is used); this resulting path will not necessarily exist on a +remote system. A pathname beginning with a simple ~ starts at the +UUCP public directory; a pathname beginning with ~name starts at the +home directory of the named user. The ~ is interpreted on the +appropriate system. Note that some shells will interpret a simple ~ +to the local home directory before +.I uucp +sees it; to avoid this the ~ must be quoted. + +Shell metacharacters ? * [ ] are interpreted on the appropriate +system, assuming they are quoted to prevent the shell from +interpreting them first. + +The copy does not take place immediately, but is queued up for the +.I uucico +(8) daemon; the daemon is started immediately unless the +.B \-r +switch is given. In any case, the next time the remote system is called the +file(s) will be copied. +.SH OPTIONS +The following options may be given to +.I uucp. +.TP 5 +.B \-c +Do not copy local source files to the spool directory. If they are +removed before being processed by the +.I uucico +(8) daemon, the copy will fail. The files must be readable by the +.I uucico +(8) daemon, and by the invoking user. +.TP 5 +.B \-C +Copy local source files to the spool directory. This is the default. +.TP 5 +.B \-d +Create all necessary directories when doing the copy. This is the +default. +.TP 5 +.B \-f +If any necessary directories do not exist for the destination path, +abort the copy. +.TP 5 +.B \-g grade +Set the grade of the file transfer command. Jobs of a higher grade +are executed first. Grades run 0 ... 9 A ... Z a ... z from high to +low. +.TP 5 +.B \-m +Report completion or failure of the file transfer by +.I mail +(1). +.TP 5 +.B \-n user +Report completion or failure of the file transfer by +.I mail +(1) to the named +user on the remote system. +.TP 5 +.B \-r +Do not start +.I uucico +(8) daemon immediately; merely queue up the file transfer for later +execution. +.TP 5 +.B \-j +Print jobid on standard output. The job may be +later cancelled by passing the jobid to the +.B \-k +switch of +.I uustat +(1). +It is possible for some complex operations to produce more than one +jobid, in which case each will be printed on a separate line. For +example +.EX +uucp sys1!~user1/file1 sys2!~user2/file2 /usr/spool/uucppublic +.EE +will generate two separate jobs, one for the system +.I sys1 +and one for the system +.I sys2. +.TP 5 +.B \-W +Do not prepend remote relative path names with the current directory. +.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, config, +spooldir and execute are meaningful for +.I uucp. + +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. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I uucp +was compiled. +.SH FILES +The file names may be changed at compilation time or by the +configuration file, so these are only approximations. + +.br +/usr/lib/uucp/config - Configuration file. +.br +/usr/spool/uucp - +UUCP spool directory. +.br +/usr/spool/uucp/Log - +UUCP log file. +.br +/usr/spool/uucppublic - +Default UUCP public directory. +.SH SEE ALSO +mail(1), uux(1), uustat(1), uucico(8) +.SH BUGS +Some of the options are dependent on the capabilities of the +.I uucico +(8) daemon on the remote system. + +The +.I \-n +and +.I \-m +switches do not work when transferring a file from one remote system +to another. + +File modes are not preserved, except for the execute bit. The +resulting file is owned by the uucp user. +.SH AUTHOR +Ian Lance Taylor +(ian@airs.com or uunet!airs!ian) diff --git a/gnu/libexec/uucp/uucp/uucp.c b/gnu/libexec/uucp/uucp/uucp.c new file mode 100644 index 0000000000..93e9ff4484 --- /dev/null +++ b/gnu/libexec/uucp/uucp/uucp.c @@ -0,0 +1,1181 @@ +/* uucp.c + Prepare to copy a file to or from a remote 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" + +#if USE_RCS_ID +const char uucp_rcsid[] = "$Id: uucp.c,v 1.1 1993/08/04 19:36:44 jtc Exp $"; +#endif + +#include +#include + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* Local functions. */ + +static void ucusage P((void)); +static void ucdirfile P((const char *zdir, const char *zfile, + pointer pinfo)); +static void uccopy P((const char *zfile, const char *zdest)); +static void ucadd_cmd P((const struct uuconf_system *qsys, + const struct scmd *qcmd, const char *zlog)); +static void ucspool_cmds P((boolean fjobid)); +static const char *zcone_system P((boolean *pfany)); +static void ucrecord_file P((const char *zfile)); +static void ucabort P((void)); + +/* The program name. */ +char abProgram[] = "uucp"; + +/* Long getopt options. */ +static const struct option asClongopts[] = { { NULL, 0, NULL, 0 } }; + +/* Local variables. There are a bunch of these, mostly set by the + options and the last (the destination) argument. These have file + scope so that they may be easily passed into uccopy; they could for + the most part also be wrapped up in a structure and passed in. */ + +/* The uuconf global pointer. */ +static pointer pCuuconf; + +/* TRUE if source files should be copied to the spool directory. */ +static boolean fCcopy = TRUE; + +/* Grade to use. */ +static char bCgrade = BDEFAULT_UUCP_GRADE; + +/* Whether to send mail to the requesting user when the copy is + complete. */ +static boolean fCmail = FALSE; + +/* User to notify on remote system. */ +static const char *zCnotify = ""; + +/* TRUE if remote files should be prefixed with the current working + directory. */ +static boolean fCexpand = TRUE; + +/* TRUE if necessary directories should be created on the destination + system. */ +static boolean fCmkdirs = TRUE; + +/* Local name. */ +static const char *zClocalname; + +/* User name. */ +static const char *zCuser = NULL; + +/* TRUE if this is a remote request. */ +static boolean fCremote = FALSE; + +/* TRUE if the destination is this system. */ +static boolean fClocaldest; + +/* Destination system. */ +static struct uuconf_system sCdestsys; + +/* Systems to forward to, if not NULL. */ +static char *zCforward; + +/* Options to use when sending a file. */ +static char abCsend_options[20]; + +/* Options to use when receiving a file. */ +static char abCrec_options[20]; + +/* TRUE if the current file being copied from is in the cwd. */ +static boolean fCneeds_cwd; + +/* The main program. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -I: configuration file name. */ + const char *zconfig = NULL; + /* -j: output job id. */ + boolean fjobid = FALSE; + /* -r: don't start uucico when finished. */ + boolean fuucico = TRUE; + /* -R: copy directories recursively. */ + boolean frecursive = FALSE; + /* -s: report status to named file. */ + const char *zstatus_file = NULL; + /* -t: emulate uuto. */ + boolean fuuto = FALSE; + int iopt; + pointer puuconf; + int iuuconf; + int i; + boolean fgetcwd; + char *zexclam; + char *zdestfile; + const char *zdestsys; + char *zoptions; + boolean fexit; + + while ((iopt = getopt_long (argc, argv, "cCdfg:I:jmn:prRs:tu:Wx:", + asClongopts, (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'c': + /* Do not copy local files to spool directory. */ + fCcopy = FALSE; + break; + + case 'p': + case 'C': + /* Copy local files to spool directory. */ + fCcopy = TRUE; + break; + + case 'd': + /* Create directories if necessary. */ + fCmkdirs = TRUE; + break; + + case 'f': + /* Do not create directories if they don't exist. */ + fCmkdirs = FALSE; + break; + + case 'g': + /* Set job grade. */ + bCgrade = optarg[0]; + break; + + case 'I': + /* Name configuration file. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'j': + /* Output job id. */ + fjobid = TRUE; + break; + + case 'm': + /* Mail to requesting user. */ + fCmail = TRUE; + break; + + case 'n': + /* Notify remote user. */ + zCnotify = optarg; + break; + + case 'r': + /* Don't start uucico when finished. */ + fuucico = FALSE; + break; + + case 'R': + /* Copy directories recursively. */ + frecursive = TRUE; + break; + + case 's': + /* Report status to named file. */ + zstatus_file = optarg; + break; + + case 't': + /* Emulate uuto. */ + fuuto = TRUE; + break; + + case 'u': + /* Set user name. */ + zCuser = optarg; + break; + + case 'W': + /* Expand only local file names. */ + fCexpand = FALSE; + 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: + ucusage (); + break; + } + } + + if (! UUCONF_GRADE_LEGAL (bCgrade)) + { + ulog (LOG_ERROR, "Ignoring illegal grade"); + bCgrade = BDEFAULT_UUCP_GRADE; + } + + /* The user name must contain a '!', which is treated as a remote + name, to avoid spoofing of other users (there is no advantage to + spoofing remote users, except to send them random bits of mail, + which you can do anyhow). */ + if (zCuser != NULL) + { + if (strchr (zCuser, '!') != NULL) + fCremote = TRUE; + else + { + ulog (LOG_ERROR, "Ignoring local user name"); + zCuser = NULL; + } + } + + if (argc - optind < 2) + ucusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + pCuuconf = 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 + + /* See if we are going to need to know the current directory. We + just check each argument to see whether it's an absolute + pathname. We actually aren't going to need the cwd if fCexpand + is FALSE and the file is remote, but so what. */ + fgetcwd = FALSE; + for (i = optind; i < argc; i++) + { + zexclam = strrchr (argv[i], '!'); + if (zexclam == NULL) + zexclam = argv[i]; + else + ++zexclam; + if (fsysdep_needs_cwd (zexclam)) + { + fgetcwd = TRUE; + break; + } + } + +#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 + + usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0)); + + ulog_fatal_fn (ucabort); + + if (zCuser == NULL) + zCuser = zsysdep_login_name (); + + iuuconf = uuconf_localname (puuconf, &zClocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zClocalname = zsysdep_localname (); + if (zClocalname == NULL) + exit (EXIT_FAILURE); + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + /* If we are emulating uuto, translate the destination argument, and + notify the destination user. This had better not turn into + something that requires the current directory, or we may have + passed INIT_GETCWD incorrectly. */ + if (fuuto) + { + if (*zCnotify == '\0') + { + zexclam = strrchr (argv[argc - 1], '!'); + if (zexclam == NULL) + ucusage (); + zCnotify = zexclam + 1; + } + argv[argc - 1] = zsysdep_uuto (argv[argc - 1], zClocalname); + if (argv[argc - 1] == NULL) + ucusage (); + } + + /* Set up the file transfer options. */ + zoptions = abCsend_options; + if (fCcopy) + *zoptions++ = 'C'; + else + *zoptions++ = 'c'; + if (fCmkdirs) + *zoptions++ = 'd'; + else + *zoptions++ = 'f'; + if (fCmail) + *zoptions++ = 'm'; + if (*zCnotify != '\0') + *zoptions++ = 'n'; + *zoptions = '\0'; + + zoptions = abCrec_options; + if (fCmkdirs) + *zoptions++ = 'd'; + else + *zoptions++ = 'f'; + if (fCmail) + *zoptions++ = 'm'; + *zoptions = '\0'; + + zexclam = strchr (argv[argc - 1], '!'); + if (zexclam == NULL) + { + zdestsys = zClocalname; + zdestfile = argv[argc - 1]; + fClocaldest = TRUE; + } + else + { + size_t clen; + char *zcopy; + + clen = zexclam - argv[argc - 1]; + zcopy = zbufalc (clen + 1); + memcpy (zcopy, argv[argc - 1], clen); + zcopy[clen] = '\0'; + zdestsys = zcopy; + + zdestfile = zexclam + 1; + + fClocaldest = FALSE; + } + + iuuconf = uuconf_system_info (puuconf, zdestsys, &sCdestsys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + if (fClocaldest) + { + iuuconf = uuconf_system_local (puuconf, &sCdestsys); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + sCdestsys.uuconf_zname = (char *) zClocalname; + } + else + { + if (! funknown_system (puuconf, zdestsys, &sCdestsys)) + ulog (LOG_FATAL, "%s: System not found", zdestsys); + } + } + + /* Here zdestfile is the destination file name following the + destination system name (if any); it may contain other systems to + forward the files through. Isolate the file from the list of + systems. */ + zexclam = strrchr (zdestfile, '!'); + if (zexclam == NULL) + zCforward = NULL; + else + { + size_t clen; + +#if DEBUG > 0 + if (fClocaldest) + ulog (LOG_FATAL, "Can't happen"); +#endif + clen = zexclam - zdestfile; + zCforward = zbufalc (clen + 1); + memcpy (zCforward, zdestfile, clen); + zCforward[clen] = '\0'; + zdestfile = zexclam + 1; + } + + /* Turn the destination into an absolute path, unless it is on a + remote system and -W was used. */ + if (fClocaldest) + zdestfile = zsysdep_local_file_cwd (zdestfile, sCdestsys.uuconf_zpubdir); + else if (fCexpand) + zdestfile = zsysdep_add_cwd (zdestfile); + if (zdestfile == NULL) + { + ulog_close (); + usysdep_exit (FALSE); + } + + /* Process each source argument. */ + for (i = optind; i < argc - 1 && ! FGOT_SIGNAL (); i++) + { + boolean flocal; + char *zfrom; + + fCneeds_cwd = FALSE; + + if (strchr (argv[i], '!') != NULL) + { + flocal = FALSE; + zfrom = zbufcpy (argv[i]); + } + else + { + /* This is a local file. Make sure we get it out of the + original directory. We don't support local wildcards, + leaving that to the shell. */ + flocal = TRUE; + if (fsysdep_needs_cwd (argv[i])) + fCneeds_cwd = TRUE; + zfrom = zsysdep_local_file_cwd (argv[i], + sCdestsys.uuconf_zpubdir); + if (zfrom == NULL) + ucabort (); + } + + if (! flocal || ! fsysdep_directory (zfrom)) + uccopy (zfrom, zdestfile); + else + { + char *zbase, *zindir; + + if (! frecursive) + ulog (LOG_FATAL, "%s: directory without -R", zfrom); + + zbase = zsysdep_base_name (zfrom); + if (zbase == NULL) + ucabort (); + zindir = zsysdep_in_dir (zdestfile, zbase); + ubuffree (zbase); + if (zindir == NULL) + ucabort (); + usysdep_walk_tree (zfrom, ucdirfile, zindir); + ubuffree (zindir); + } + + ubuffree (zfrom); + } + + /* See if we got an interrupt, presumably from the user. */ + if (FGOT_SIGNAL ()) + ucabort (); + + /* Now push out the actual commands, making log entries for them. */ + ulog_to_file (puuconf, TRUE); + ulog_user (zCuser); + + ucspool_cmds (fjobid); + + ulog_close (); + + if (! fuucico) + fexit = TRUE; + else + { + const char *zsys; + boolean fany; + + zsys = zcone_system (&fany); + if (zsys != NULL) + fexit = fsysdep_run ("uucico", "-s", zsys); + else if (fany) + fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL); + else + fexit = TRUE; + } + + usysdep_exit (fexit); + + /* Avoid error about not returning. */ + return 0; +} + +static void +ucusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uucp [options] file1 [file2 ...] dest\n"); + fprintf (stderr, + " -c: Do not copy local files to spool directory\n"); + fprintf (stderr, + " -C, -p: Copy local files to spool directory (default)\n"); + fprintf (stderr, + " -d: Create necessary directories (default)\n"); + fprintf (stderr, + " -f: Do not create directories (fail if they do not exist)\n"); + fprintf (stderr, + " -g grade: Set job grade (must be alphabetic)\n"); + fprintf (stderr, + " -m: Report status of copy by mail\n"); + fprintf (stderr, + " -n user: Report status of copy by mail to remote user\n"); + fprintf (stderr, + " -R: Copy directories recursively\n"); + fprintf (stderr, + " -r: Do not start uucico daemon\n"); + fprintf (stderr, + " -s file: Report completion status to file\n"); + fprintf (stderr, + " -j: Report job id\n"); + fprintf (stderr, + " -W: Do not add current directory to remote filenames\n"); + fprintf (stderr, + " -t: Emulate uuto\n"); + fprintf (stderr, + " -u name: Set user name\n"); + fprintf (stderr, + " -x debug: Set debugging level\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* This is called for each file in a directory heirarchy. */ + +static void +ucdirfile (zfull, zrelative, pinfo) + const char *zfull; + const char *zrelative; + pointer pinfo; +{ + const char *zdestfile = (const char *) pinfo; + char *zto; + + zto = zsysdep_in_dir (zdestfile, zrelative); + if (zto == NULL) + ucabort (); + + uccopy (zfull, zto); + + ubuffree (zto); +} + +/* Handle the copying of one regular file. The zdest argument is the + destination file; if we are recursively copying a directory, it + will be extended by any subdirectory names. Note that zdest is an + absolute path. */ + +static void +uccopy (zfile, zdest) + const char *zfile; + const char *zdest; +{ + struct scmd s; + char *zexclam; + char *zto; + + zexclam = strchr (zfile, '!'); + + if (zexclam == NULL) + { + openfile_t efrom; + + /* Copy from a local file. Make sure the user has access to + this file, since we are running setuid. */ + if (! fsysdep_access (zfile)) + ucabort (); + + /* If this copy is being requested by a remote system, we may + transfer the file if it needs the current working directory + (meaning, I hope, that it is in the execution directory) or + it is on the permitted transfer list. Note that unlike most + of the other checks, this one is not double-checked by + uucico. */ + if (fCremote + && ! fCneeds_cwd + && ! fin_directory_list (zfile, sCdestsys.uuconf_pzremote_send, + sCdestsys.uuconf_zpubdir, TRUE, + TRUE, (const char *) NULL)) + ulog (LOG_FATAL, "Not permitted to send %s", zfile); + + if (fClocaldest) + { + boolean fok; + + /* Copy one local file to another. */ + + /* Check that we have permission to receive into the desired + directory. */ + if (fCremote) + fok = fin_directory_list (zdest, + sCdestsys.uuconf_pzremote_receive, + sCdestsys.uuconf_zpubdir, TRUE, + FALSE, (const char *) NULL); + else + fok = fin_directory_list (zdest, + sCdestsys.uuconf_pzlocal_receive, + sCdestsys.uuconf_zpubdir, TRUE, + FALSE, zCuser); + if (! fok) + ulog (LOG_FATAL, "Not permitted to receive to %s", zdest); + + zto = zsysdep_add_base (zdest, zfile); + if (zto == NULL) + ucabort (); + + efrom = esysdep_user_fopen (zfile, TRUE, TRUE); + if (! ffileisopen (efrom)) + ucabort (); + if (! fcopy_open_file (efrom, zto, FALSE, fCmkdirs)) + ucabort (); + (void) ffileclose (efrom); + ubuffree (zto); + } + else + { + const char *zloc; + char abtname[CFILE_NAME_LEN]; + unsigned int imode; + char *ztemp; + + /* Copy a local file to a remote file. We may have to + copy the local file to the spool directory. */ + imode = ixsysdep_file_mode (zfile); + if (imode == 0) + ucabort (); + + zloc = sCdestsys.uuconf_zlocalname; + if (zloc == NULL) + zloc = zClocalname; + + ztemp = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade, + FALSE, abtname, (char *) NULL, + (char *) NULL); + if (ztemp == NULL) + ucabort (); + + if (! fCcopy) + { + /* If we are copying the file, we don't actually use the + temporary file; we still want to get a name for the + other system to use as a key for file restart. */ + ubuffree (ztemp); + + /* Make sure the daemon will be permitted to send + this file. */ + if (! fsysdep_daemon_access (zfile)) + ucabort (); + if (! fin_directory_list (zfile, sCdestsys.uuconf_pzlocal_send, + sCdestsys.uuconf_zpubdir, TRUE, TRUE, + (fCremote + ? (const char *) NULL + : zCuser))) + ulog (LOG_FATAL, "Not permitted to send %s", zfile); + } + else + { + efrom = esysdep_user_fopen (zfile, TRUE, TRUE); + if (! ffileisopen (efrom)) + ucabort (); + ucrecord_file (ztemp); + if (! fcopy_open_file (efrom, ztemp, FALSE, TRUE)) + ucabort (); + (void) ffileclose (efrom); + } + + if (zCforward == NULL) + { + /* We're not forwarding. Just send the file. */ + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (zfile); + s.zto = zbufcpy (zdest); + s.zuser = zCuser; + s.zoptions = abCsend_options; + s.ztemp = zbufcpy (abtname); + s.imode = imode; + s.znotify = zCnotify; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ucadd_cmd (&sCdestsys, &s, (const char *) NULL); + } + else + { + char *zbase; + char *zxqt; + char abxtname[CFILE_NAME_LEN]; + char abdname[CFILE_NAME_LEN]; + char abxname[CFILE_NAME_LEN]; + FILE *e; + char *zlog; + + /* We want to forward this file through sCdestsys to + some other system(s). We set up a remote execution + of uucp on sCdestsys to forward the file along. */ + zbase = zsysdep_base_name (zfile); + if (zbase == NULL) + ucabort (); + + zxqt = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade, + TRUE, abxtname, abdname, + abxname); + if (zxqt == NULL) + ucabort (); + e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); + if (e == NULL) + ucabort (); + ucrecord_file (zxqt); + + fprintf (e, "U %s %s\n", zCuser, zloc); + fprintf (e, "F %s %s\n", abdname, zbase); + fprintf (e, "C uucp -C"); + if (fCmkdirs) + fprintf (e, " -d"); + else + fprintf (e, " -f"); + fprintf (e, " -g %c", bCgrade); + if (fCmail) + fprintf (e, " -m"); + if (*zCnotify != '\0') + fprintf (e, " -n %s", zCnotify); + if (! fCexpand) + fprintf (e, " -W"); + fprintf (e, " %s %s!%s\n", zbase, zCforward, zdest); + + ubuffree (zbase); + + if (fclose (e) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + + /* Send the execution file. */ + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (abxtname); + s.zto = zbufcpy (abxname); + s.zuser = zCuser; + s.zoptions = "C"; + s.ztemp = s.zfrom; + s.imode = 0666; + s.znotify = NULL; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + zlog = zbufalc (sizeof "Queuing uucp !" + strlen (zfile) + + strlen (zCforward) + strlen (zdest)); + sprintf (zlog, "Queuing uucp %s %s!%s", zfile, zCforward, + zdest); + + ucadd_cmd (&sCdestsys, &s, zlog); + + /* Send the data file. */ + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (zfile); + s.zto = zbufcpy (abdname); + s.zuser = zCuser; + s.zoptions = fCcopy ? "C" : "c"; + s.ztemp = zbufcpy (abtname); + s.imode = 0666; + s.znotify = NULL; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ucadd_cmd (&sCdestsys, &s, ""); + } + } + } + else + { + char *zfrom; + char *zforward; + size_t clen; + char *zcopy; + struct uuconf_system *qfromsys; + int iuuconf; + const char *zloc; + + /* Copy from a remote file. Get the file name after any systems + we may need to forward the file from. */ + zfrom = strrchr (zfile, '!'); + if (zfrom == zexclam) + zforward = NULL; + else + { + clen = zfrom - zexclam - 1; + zforward = zbufalc (clen + 1); + memcpy (zforward, zexclam + 1, clen); + } + + ++zfrom; + if (fCexpand) + { + /* Add the current directory to the filename if it's not + already there. */ + zfrom = zsysdep_add_cwd (zfrom); + if (zfrom == NULL) + ucabort (); + } + + /* Read the system information. */ + clen = zexclam - zfile; + zcopy = zbufalc (clen + 1); + memcpy (zcopy, zfile, clen); + zcopy[clen] = '\0'; + + qfromsys = ((struct uuconf_system *) + xmalloc (sizeof (struct uuconf_system))); + + iuuconf = uuconf_system_info (pCuuconf, zcopy, qfromsys); + if (iuuconf == UUCONF_NOT_FOUND) + { + if (! funknown_system (pCuuconf, zcopy, qfromsys)) + ulog (LOG_FATAL, "%s: System not found", zcopy); + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, pCuuconf, iuuconf); + ubuffree (zcopy); + + zloc = qfromsys->uuconf_zlocalname; + if (zloc == NULL) + zloc = zClocalname; + + if (zforward == NULL && fClocaldest) + { + boolean fok; + + /* The file is to come directly from qfromsys to the local + system. */ + + /* Check that we have permission to receive into the desired + directory. If we don't have permission, uucico will + fail. */ + if (fCremote) + fok = fin_directory_list (zdest, + qfromsys->uuconf_pzremote_receive, + qfromsys->uuconf_zpubdir, TRUE, + FALSE, (const char *) NULL); + else + fok = fin_directory_list (zdest, + qfromsys->uuconf_pzlocal_receive, + qfromsys->uuconf_zpubdir, TRUE, + FALSE, zCuser); + if (! fok) + ulog (LOG_FATAL, "Not permitted to receive to %s", zdest); + + /* If the remote filespec is wildcarded, we must generate an + 'X' request. We currently check for Unix shell + wildcards. Note that it should do no harm to mistake a + non-wildcard for a wildcard. */ + if (zfrom[strcspn (zfrom, "*?[")] != '\0') + { + s.bcmd = 'X'; + zto = zbufalc (strlen (zloc) + strlen (zdest) + sizeof "!"); + sprintf (zto, "%s!%s", zloc, zdest); + } + else + { + s.bcmd = 'R'; + zto = zbufcpy (zdest); + } + + s.pseq = NULL; + s.zfrom = zfrom; + s.zto = zto; + s.zuser = zCuser; + s.zoptions = abCrec_options; + s.ztemp = ""; + s.imode = 0; + s.znotify = ""; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ucadd_cmd (qfromsys, &s, (const char *) NULL); + } + else + { + char *zxqt; + char abtname[CFILE_NAME_LEN]; + char abxname[CFILE_NAME_LEN]; + FILE *e; + char *zcmd; + char *zlog; + + /* The file either comes from some other system through + qfromsys or is intended for some other system. Send an + execution request to qfromsys to handle everything. */ + zxqt = zsysdep_data_file_name (qfromsys, zloc, bCgrade, TRUE, + abtname, (char *) NULL, + abxname); + if (zxqt == NULL) + ucabort (); + e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); + if (e == NULL) + ucabort (); + ucrecord_file (zxqt); + + fprintf (e, "U %s %s\n", zCuser, zloc); + fprintf (e, "C uucp -C"); + if (fCmkdirs) + fprintf (e, " -d"); + else + fprintf (e, " -f"); + fprintf (e, " -g %c", bCgrade); + if (fCmail) + fprintf (e, " -m"); + if (*zCnotify != '\0') + fprintf (e, " -n %s", zCnotify); + if (! fCexpand) + fprintf (e, " -W"); + + clen = (strlen (zfrom) + strlen (zloc) + + strlen (sCdestsys.uuconf_zname) + strlen (zdest)); + if (zforward != NULL) + clen += strlen (zforward); + if (zCforward != NULL) + clen += strlen (zCforward); + zcmd = zbufalc (sizeof "! !!!" + clen); + *zcmd = '\0'; + if (zforward != NULL) + sprintf (zcmd + strlen (zcmd), "%s!", zforward); + sprintf (zcmd + strlen (zcmd), "%s %s!", zfrom, zloc); + if (! fClocaldest) + sprintf (zcmd + strlen (zcmd), "%s!", sCdestsys.uuconf_zname); + if (zCforward != NULL) + sprintf (zcmd + strlen (zcmd), "%s!", zCforward); + sprintf (zcmd + strlen (zcmd), "%s", zdest); + + fprintf (e, " %s\n", zcmd); + + if (fclose (e) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + + /* Send the execution file. */ + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (abtname); + s.zto = zbufcpy (abxname); + s.zuser = zCuser; + s.zoptions = "C"; + s.ztemp = s.zfrom; + s.imode = 0666; + s.znotify = NULL; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + zlog = zbufalc (sizeof "Queueing uucp " + strlen (zcmd)); + sprintf (zlog, "Queueing uucp %s", zcmd); + + ucadd_cmd (qfromsys, &s, zlog); + + ubuffree (zcmd); + ubuffree (zforward); + } + } +} + +/* We keep a list of jobs for each system. */ + +struct sjob +{ + struct sjob *qnext; + const struct uuconf_system *qsys; + int ccmds; + struct scmd *pascmds; + const char **pazlogs; +}; + +static struct sjob *qCjobs; + +static void +ucadd_cmd (qsys, qcmd, zlog) + const struct uuconf_system *qsys; + const struct scmd *qcmd; + const char *zlog; +{ + struct sjob *qjob; + + if (! qsys->uuconf_fcall_transfer + && ! qsys->uuconf_fcalled_transfer) + ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", + qsys->uuconf_zname); + + for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext) + if (strcmp (qjob->qsys->uuconf_zname, qsys->uuconf_zname) == 0) + break; + + if (qjob == NULL) + { + qjob = (struct sjob *) xmalloc (sizeof (struct sjob)); + qjob->qnext = qCjobs; + qjob->qsys = qsys; + qjob->ccmds = 0; + qjob->pascmds = NULL; + qjob->pazlogs = NULL; + qCjobs = qjob; + } + + qjob->pascmds = ((struct scmd *) + xrealloc ((pointer) qjob->pascmds, + (qjob->ccmds + 1) * sizeof (struct scmd))); + qjob->pascmds[qjob->ccmds] = *qcmd; + qjob->pazlogs = ((const char **) + xrealloc ((pointer) qjob->pazlogs, + (qjob->ccmds + 1) * sizeof (const char *))); + qjob->pazlogs[qjob->ccmds] = zlog; + ++qjob->ccmds; +} + +static void +ucspool_cmds (fjobid) + boolean fjobid; +{ + struct sjob *qjob; + char *zjobid; + + for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext) + { + ulog_system (qjob->qsys->uuconf_zname); + zjobid = zsysdep_spool_commands (qjob->qsys, bCgrade, qjob->ccmds, + qjob->pascmds); + if (zjobid != NULL) + { + int i; + struct scmd *qcmd; + const char **pz; + + for (i = 0, qcmd = qjob->pascmds, pz = qjob->pazlogs; + i < qjob->ccmds; + i++, qcmd++, pz++) + { + if (*pz != NULL) + { + if (**pz != '\0') + ulog (LOG_NORMAL, "%s", *pz); + } + else if (qcmd->bcmd == 'S') + ulog (LOG_NORMAL, "Queuing send of %s to %s", + qcmd->zfrom, qcmd->zto); + else if (qcmd->bcmd == 'R') + ulog (LOG_NORMAL, "Queuing request of %s to %s", + qcmd->zfrom, qcmd->zto); + else + { + const char *zto; + + zto = strrchr (qcmd->zto, '!'); + if (zto != NULL) + ++zto; + else + zto = qcmd->zto; + ulog (LOG_NORMAL, "Queuing request of %s to %s", + qcmd->zfrom, zto); + } + } + + if (fjobid) + printf ("%s\n", zjobid); + + ubuffree (zjobid); + } + } +} + +/* Return the system name for which we have created commands, or NULL + if we've created commands for more than one system. Set *pfany to + FALSE if we didn't create work for any system. */ + +static const char * +zcone_system (pfany) + boolean *pfany; +{ + if (qCjobs == NULL) + { + *pfany = FALSE; + return NULL; + } + + *pfany = TRUE; + + if (qCjobs->qnext == NULL) + return qCjobs->qsys->uuconf_zname; + else + return NULL; +} + +/* Keep track of all files we have created so that we can delete them + if we get a signal. The argument will be on the heap. */ + +static int cCfiles; +static const char **pCaz; + +static void +ucrecord_file (zfile) + const char *zfile; +{ + pCaz = (const char **) xrealloc ((pointer) pCaz, + (cCfiles + 1) * sizeof (const char *)); + pCaz[cCfiles] = zfile; + ++cCfiles; +} + +/* Delete all the files we have recorded and exit. */ + +static void +ucabort () +{ + int i; + + for (i = 0; i < cCfiles; i++) + (void) remove (pCaz[i]); + ulog_close (); + usysdep_exit (FALSE); +} diff --git a/gnu/libexec/uucp/uulog/Makefile b/gnu/libexec/uucp/uulog/Makefile new file mode 100644 index 0000000000..321656f3dc --- /dev/null +++ b/gnu/libexec/uucp/uulog/Makefile @@ -0,0 +1,16 @@ +# Makefile for uulog +# $Id: Makefile,v 1.2 1993/08/05 16:15:14 jtc Exp $ + +BINDIR= $(bindir) + +PROG= uulog +SRCS= uulog.c log.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +NOMAN= noman + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uulog/uulog.c b/gnu/libexec/uucp/uulog/uulog.c new file mode 100644 index 0000000000..9a58fffeb2 --- /dev/null +++ b/gnu/libexec/uucp/uulog/uulog.c @@ -0,0 +1,444 @@ +/* uulog.c + Display the UUCP log 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" + +#if USE_RCS_ID +const char uulog_rcsid[] = "$Id: uulog.c,v 1.1 1993/08/04 19:36:47 jtc Exp $"; +#endif + +#include +#include + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* This is a pretty bad implementation of uulog, which I don't think + is a very useful program anyhow. It only takes a single -s and/or + -u switch. When using HAVE_HDB_LOGGING it requires a system. */ + +/* The program name. */ +char abProgram[] = "uulog"; + +/* Local functions. */ + +static void ulusage P((void)); + +/* Long getopt options. */ +static const struct option asLlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -D: display Debug file */ + boolean fdebug = FALSE; + /* -f: keep displaying lines forever. */ + boolean fforever = FALSE; + /* -n lines: number of lines to display. */ + int cshow = 0; + /* -s: system name. */ + const char *zsystem = NULL; + /* -S: display Stats file */ + boolean fstats = FALSE; + /* -u: user name. */ + const char *zuser = NULL; + /* -I: configuration file name. */ + const char *zconfig = NULL; + /* -x: display uuxqt log file. */ + boolean fuuxqt = FALSE; + int i; + int iopt; + pointer puuconf; + int iuuconf; + const char *zlogfile; + const char *zstatsfile; + const char *zdebugfile; + const char *zfile; + FILE *e; + char **pzshow = NULL; + int ishow = 0; + size_t csystem = 0; + size_t cuser = 0; + char *zline; + size_t cline; + + /* Look for a straight number argument, and convert it to -n before + passing the arguments to getopt. */ + for (i = 0; i < argc; i++) + { + if (argv[i][0] == '-' && isdigit (argv[i][1])) + { + size_t clen; + char *znew; + + clen = strlen (argv[i]); + znew = zbufalc (clen + 2); + znew[0] = '-'; + znew[1] = 'n'; + memcpy (znew + 2, argv[i] + 1, clen); + argv[i] = znew; + } + } + + while ((iopt = getopt_long (argc, argv, "Df:FI:n:s:Su:xX:", asLlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'D': + /* Show debugging file. */ + fdebug = TRUE; + break; + + case 'f': + /* Keep displaying lines forever for a particular system. */ + fforever = TRUE; + zsystem = optarg; + if (cshow == 0) + cshow = 10; + break; + + case 'F': + /* Keep displaying lines forever. */ + fforever = TRUE; + if (cshow == 0) + cshow = 10; + break; + + case 'I': + /* Configuration file name. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'n': + /* Number of lines to display. */ + cshow = (int) strtol (optarg, (char **) NULL, 10); + break; + + case 's': + /* System name. */ + zsystem = optarg; + break; + + case 'S': + /* Show statistics file. */ + fstats = TRUE; + break; + + case 'u': + /* User name. */ + zuser = optarg; + break; + + case 'x': + /* Display uuxqt log file. */ + fuuxqt = TRUE; + 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: + ulusage (); + break; + } + } + + if (optind != argc || (fstats && fdebug)) + ulusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#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 + + iuuconf = uuconf_logfile (puuconf, &zlogfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + iuuconf = uuconf_statsfile (puuconf, &zstatsfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + iuuconf = uuconf_debugfile (puuconf, &zdebugfile); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + usysdep_initialize (puuconf, 0); + + if (zsystem != NULL) + { +#if HAVE_HDB_LOGGING + if (strcmp (zsystem, "ANY") != 0) +#endif + { + struct uuconf_system ssys; + + 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); + } + zsystem = zbufcpy (ssys.uuconf_zname); + (void) uuconf_system_free (puuconf, &ssys); + } + } + + if (fstats) + zfile = zstatsfile; + else if (fdebug) + zfile = zdebugfile; + else + { +#if ! HAVE_HDB_LOGGING + zfile = zlogfile; +#else + const char *zprogram; + char *zalc; + + /* We need a system to find a HDB log file. */ + if (zsystem == NULL) + ulusage (); + + if (fuuxqt) + zprogram = "uuxqt"; + else + zprogram = "uucico"; + + zalc = zbufalc (strlen (zlogfile) + + strlen (zprogram) + + strlen (zsystem) + + 1); + sprintf (zalc, zlogfile, zprogram, zsystem); + zfile = zalc; + + if (strcmp (zsystem, "ANY") == 0) + zsystem = NULL; +#endif + } + + e = fopen (zfile, "r"); + if (e == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); + usysdep_exit (FALSE); + } + + if (cshow > 0) + { + pzshow = (char **) xmalloc (cshow * sizeof (char *)); + for (ishow = 0; ishow < cshow; ishow++) + pzshow[ishow] = NULL; + ishow = 0; + } + + /* Read the log file and output the appropriate lines. */ + if (zsystem != NULL) + csystem = strlen (zsystem); + + if (zuser != NULL) + cuser = strlen (zuser); + + zline = NULL; + cline = 0; + + while (TRUE) + { + while (getline (&zline, &cline, e) > 0) + { + char *zluser, *zlsys, *znext; + size_t cluser, clsys; + + /* Skip any leading whitespace (not that there should be + any). */ + znext = zline + strspn (zline, " \t"); + + if (! fstats) + { +#if ! HAVE_TAYLOR_LOGGING + /* The user name is the first field on the line. */ + zluser = znext; + cluser = strcspn (znext, " \t"); +#endif + + /* Skip the first field. */ + znext += strcspn (znext, " \t"); + znext += strspn (znext, " \t"); + + /* The system is the second field on the line. */ + zlsys = znext; + clsys = strcspn (znext, " \t"); + + /* Skip the second field. */ + znext += clsys; + znext += strspn (znext, " \t"); + +#if HAVE_TAYLOR_LOGGING + /* The user is the third field on the line. */ + zluser = znext; + cluser = strcspn (znext, " \t"); +#endif + } + else + { +#if ! HAVE_HDB_LOGGING + /* The user name is the first field on the line, and the + system name is the second. */ + zluser = znext; + cluser = strcspn (znext, " \t"); + znext += cluser; + znext += strspn (znext, " \t"); + zlsys = znext; + clsys = strcspn (znext, " \t"); +#else + /* The first field is system!user. */ + zlsys = znext; + clsys = strcspn (znext, "!"); + znext += clsys + 1; + zlsys = znext; + clsys = strcspn (znext, " \t"); +#endif + } + + /* See if we should print this line. */ + if (zsystem != NULL + && (csystem != clsys + || strncmp (zsystem, zlsys, clsys) != 0)) + continue; + + if (zuser != NULL + && (cuser != cluser + || strncmp (zuser, zluser, cluser) != 0)) + continue; + + /* Output the line, or save it if we are outputting only a + particular number of lines. */ + if (cshow <= 0) + printf ("%s", zline); + else + { + ubuffree ((pointer) pzshow[ishow]); + pzshow[ishow] = zbufcpy (zline); + ishow = (ishow + 1) % cshow; + } + } + + /* Output the number of lines requested by the -n option. */ + if (cshow > 0) + { + for (i = 0; i < cshow; i++) + { + if (pzshow[ishow] != NULL) + printf ("%s", pzshow[ishow]); + ishow = (ishow + 1) % cshow; + } + } + + /* If -f was not specified, or an error occurred while reading + the file, get out. */ + if (! fforever || ferror (e)) + break; + + clearerr (e); + cshow = 0; + + /* Sleep 1 second before going around the loop again. */ + usysdep_sleep (1); + } + + (void) fclose (e); + + ulog_close (); + + usysdep_exit (TRUE); + + /* Avoid errors about not returning a value. */ + return 0; +} + +/* Print a usage message and die. */ + +static void +ulusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uulog [-n #] [-sf system] [-u user] [-xDSF] [-I file] [-X debug]\n"); + fprintf (stderr, + " -n: show given number of lines from end of log\n"); + fprintf (stderr, + " -s: print entries for named system\n"); + fprintf (stderr, + " -f: follow entries for named system\n"); + fprintf (stderr, + " -u: print entries for named user\n"); +#if HAVE_HDB_LOGGING + fprintf (stderr, + " -x: print uuxqt log rather than uucico log\n"); +#else + fprintf (stderr, + " -F: follow entries for any system\n"); +#endif + fprintf (stderr, + " -S: show statistics file\n"); + fprintf (stderr, + " -D: show debugging file\n"); + fprintf (stderr, + " -X debug: Set debugging level (0 for none, 9 is max)\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} diff --git a/gnu/libexec/uucp/uuname/Makefile b/gnu/libexec/uucp/uuname/Makefile new file mode 100644 index 0000000000..5e7b314ba1 --- /dev/null +++ b/gnu/libexec/uucp/uuname/Makefile @@ -0,0 +1,18 @@ +# Makefile for uuname +# $Id: Makefile,v 1.2 1993/08/05 16:15:16 jtc Exp $ + +BINDIR= $(bindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uuname +SRCS= uuname.c log.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +NOMAN= noman + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uuname/uuname.c b/gnu/libexec/uucp/uuname/uuname.c new file mode 100644 index 0000000000..54a87dfa39 --- /dev/null +++ b/gnu/libexec/uucp/uuname/uuname.c @@ -0,0 +1,192 @@ +/* uuname.c + List the names of known remote UUCP sites. + + 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 uuname_rcsid[] = "$Id: uuname.c,v 1.1 1993/08/04 19:36:52 jtc Exp $"; +#endif + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* The program name. */ +char abProgram[] = "uuname"; + +/* Local functions. */ + +static void unusage P((void)); +static void unuuconf_error P((pointer puuconf, int iuuconf)); + +/* Long getopt options. */ +static const struct option asNlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -a: display aliases. */ + boolean falias = FALSE; + /* -l: if true, output local node name. */ + boolean flocal = FALSE; + /* -I: configuration file name. */ + const char *zconfig = NULL; + int iopt; + pointer puuconf; + int iuuconf; + + while ((iopt = getopt_long (argc, argv, "alI:x:", asNlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'a': + /* Display aliases. */ + falias = TRUE; + break; + + case 'l': + /* Output local node name. */ + flocal = TRUE; + 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: + unusage (); + break; + } + } + + if (optind != argc) + unusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + unuuconf_error (puuconf, iuuconf); + +#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_SUID); + + if (flocal) + { + const char *zlocalname; + + iuuconf = uuconf_localname (puuconf, &zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zlocalname = zsysdep_localname (); + if (zlocalname == NULL) + usysdep_exit (FALSE); + } + else if (iuuconf != UUCONF_SUCCESS) + unuuconf_error (puuconf, iuuconf); + printf ("%s\n", zlocalname); + } + else + { + char **pznames, **pz; + + iuuconf = uuconf_system_names (puuconf, &pznames, falias); + if (iuuconf != UUCONF_SUCCESS) + unuuconf_error (puuconf, iuuconf); + + for (pz = pznames; *pz != NULL; pz++) + printf ("%s\n", *pz); + } + + usysdep_exit (TRUE); + + /* Avoid warnings about not returning a value. */ + return 0; +} + +/* Print a usage message and die. */ + +static void +unusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uuname [-a] [-l] [-I file]\n"); + fprintf (stderr, + " -a: display aliases\n"); + fprintf (stderr, + " -l: print local name\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* Display a uuconf error and exit. */ + +static void +unuuconf_error (puuconf, iret) + pointer puuconf; + int iret; +{ + char ab[512]; + + (void) uuconf_error_string (puuconf, iret, ab, sizeof ab); + if ((iret & UUCONF_ERROR_FILENAME) == 0) + fprintf (stderr, "uuname: %s\n", ab); + else + fprintf (stderr, "uuname:%s\n", ab); + exit (EXIT_FAILURE); +} diff --git a/gnu/libexec/uucp/uupick/Makefile b/gnu/libexec/uucp/uupick/Makefile new file mode 100644 index 0000000000..c9a431219d --- /dev/null +++ b/gnu/libexec/uucp/uupick/Makefile @@ -0,0 +1,16 @@ +# Makefile for uupick +# $Id: Makefile,v 1.2 1993/08/05 16:15:19 jtc Exp $ + +BINDIR= $(bindir) + +PROG= uupick +SRCS= uupick.c log.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +NOMAN= noman + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uupick/uupick.c b/gnu/libexec/uucp/uupick/uupick.c new file mode 100644 index 0000000000..4e1f1b3aff --- /dev/null +++ b/gnu/libexec/uucp/uupick/uupick.c @@ -0,0 +1,323 @@ +/* uupick.c + Get files stored in the public directory by uucp -t. + + 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 uupick_rcsid[] = "$Id: uupick.c,v 1.1 1993/08/04 19:36:56 jtc Exp $"; +#endif + +#include + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* Local functions. */ + +static void upmovedir P((const char *zfull, const char *zrelative, + pointer pinfo)); +static void upmove P((const char *zfrom, const char *zto)); + +/* The program name. */ +char abProgram[] = "uupick"; + +/* Long getopt options. */ +static const struct option asPlongopts[] = { { NULL, 0, NULL, 0 } }; + +/* Local functions. */ + +static void upusage P((void)); + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -s: system name. */ + const char *zsystem = NULL; + /* -I: configuration file name. */ + const char *zconfig = NULL; + int iopt; + pointer puuconf; + int iuuconf; + struct uuconf_system ssys; + const char *zpubdir; + char *zfile, *zfrom, *zfull; + char *zallsys; + char ab[1000]; + boolean fquit; + + while ((iopt = getopt_long (argc, argv, "I:s:x:", asPlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 's': + /* System name to get files from. */ + zsystem = optarg; + break; + + case 'I': + /* Name configuration file. */ + 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: + upusage (); + break; + } + } + + if (argc != optind) + upusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + usysdep_initialize (puuconf, INIT_GETCWD | INIT_NOCHDIR); + + zpubdir = NULL; + if (zsystem != NULL) + { + iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); + if (iuuconf == UUCONF_SUCCESS) + { + zpubdir = zbufcpy (ssys.uuconf_zpubdir); + (void) uuconf_system_free (puuconf, &ssys); + } + else if (iuuconf != UUCONF_NOT_FOUND) + (void) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + if (zpubdir == NULL) + { + iuuconf = uuconf_pubdir (puuconf, &zpubdir); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + + if (! fsysdep_uupick_init (zsystem, zpubdir)) + usysdep_exit (FALSE); + + zallsys = NULL; + fquit = FALSE; + + while (! fquit + && ((zfile = zsysdep_uupick (zsystem, zpubdir, &zfrom, &zfull)) + != NULL)) + { + boolean fdir; + char *zto, *zlocal; + FILE *e; + boolean fcontinue; + + fdir = fsysdep_directory (zfull); + + do + { + fcontinue = FALSE; + + if (zallsys == NULL + || strcmp (zallsys, zfrom) != 0) + { + if (zallsys != NULL) + { + ubuffree (zallsys); + zallsys = NULL; + } + + printf ("from %s: %s %s ?\n", zfrom, fdir ? "dir" : "file", + zfile); + + if (fgets (ab, sizeof ab, stdin) == NULL) + break; + } + + if (ab[0] == 'q') + { + fquit = TRUE; + break; + } + + switch (ab[0]) + { + case '\n': + break; + + case 'd': + if (fdir) + (void) fsysdep_rmdir (zfull); + else + { + if (remove (zfull) != 0) + ulog (LOG_ERROR, "remove (%s): %s", zfull, + strerror(errno)); + } + break; + + case 'm': + case 'a': + zto = ab + 1 + strspn (ab + 1, " \t"); + zto[strcspn (zto, " \t\n")] = '\0'; + zlocal = zsysdep_uupick_local_file (zto); + if (zlocal == NULL) + usysdep_exit (FALSE); + zto = zsysdep_in_dir (zlocal, zfile); + ubuffree (zlocal); + if (zto == NULL) + usysdep_exit (FALSE); + if (! fdir) + upmove (zfull, zto); + else + { + usysdep_walk_tree (zfull, upmovedir, (pointer) zto); + (void) fsysdep_rmdir (zfull); + } + ubuffree (zto); + + if (ab[0] == 'a') + { + zallsys = zbufcpy (zfrom); + ab[0] = 'm'; + } + + break; + + case 'p': + if (fdir) + ulog (LOG_ERROR, "Can't print directory"); + else + { + e = fopen (zfull, "r"); + if (e == NULL) + ulog (LOG_ERROR, "fopen (%s): %s", zfull, + strerror (errno)); + else + { + while (fgets (ab, sizeof ab, e) != NULL) + (void) fputs (ab, stdout); + (void) fclose (e); + } + } + fcontinue = TRUE; + break; + + case '!': + (void) system (ab + 1); + fcontinue = TRUE; + break; + + default: + printf ("uupick commands:\n"); + printf ("q: quit\n"); + printf (": skip file\n"); + printf ("m [dir]: move file to directory\n"); + printf ("a [dir]: move all files from this system to directory\n"); + printf ("p: list file to stdout\n"); + printf ("! command: shell escape\n"); + fcontinue = TRUE; + break; + } + } + while (fcontinue); + + ubuffree (zfull); + ubuffree (zfrom); + ubuffree (zfile); + } + + (void) fsysdep_uupick_free (zsystem, zpubdir); + + usysdep_exit (TRUE); + + /* Avoid error about not returning. */ + return 0; +} + +/* Print usage message. */ + +static void +upusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uupick [-s system] [-I config] [-x debug]\n"); + fprintf (stderr, + " -s system: Only consider files from named system\n"); + fprintf (stderr, + " -x debug: Set debugging level\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* This routine is called by usysdep_walk_tree when moving the + contents of an entire directory. */ + +static void +upmovedir (zfull, zrelative, pinfo) + const char *zfull; + const char *zrelative; + pointer pinfo; +{ + const char *ztodir = (const char *) pinfo; + char *zto; + + zto = zsysdep_in_dir (ztodir, zrelative); + if (zto == NULL) + usysdep_exit (FALSE); + upmove (zfull, zto); + ubuffree (zto); +} + +/* Move a file. */ + +static void +upmove (zfrom, zto) + const char *zfrom; + const char *zto; +{ + (void) fsysdep_move_file (zfrom, zto, TRUE, TRUE, FALSE, + (const char *) NULL); +} diff --git a/gnu/libexec/uucp/uusched/Makefile b/gnu/libexec/uucp/uusched/Makefile new file mode 100644 index 0000000000..ca0aa32d83 --- /dev/null +++ b/gnu/libexec/uucp/uusched/Makefile @@ -0,0 +1,15 @@ +# Makefile for uusched +# $Id: Makefile,v 1.2 1993/08/05 16:14:03 jtc Exp $ + +BINDIR= $(bindir) + +PROG= uusched +SRCS= +NOMAN= +STRIP= + +uusched: uusched.in + sed -e "s|@BINDIR@|$(bindir)|g" -e "s|@SBINDIR@|$(sbindir)|g" \ + $(.CURDIR)/uusched.in > $(.TARGET) + +.include diff --git a/gnu/libexec/uucp/uusched/uusched.in b/gnu/libexec/uucp/uusched/uusched.in new file mode 100644 index 0000000000..e539b902fb --- /dev/null +++ b/gnu/libexec/uucp/uusched/uusched.in @@ -0,0 +1,13 @@ +: +# uusched +# Call all systems which have work in a random order +# +# Copyright (C) 1992 Ian Lance Taylor +# +# Please feel free do whatever you like with this exciting shell +# script. +# +# This is pretty trivial, since all the functionality was moved into +# uucico itself. +# +@SBINDIR@/uucico -r1 $* diff --git a/gnu/libexec/uucp/uustat/Makefile b/gnu/libexec/uucp/uustat/Makefile new file mode 100644 index 0000000000..7451292cea --- /dev/null +++ b/gnu/libexec/uucp/uustat/Makefile @@ -0,0 +1,17 @@ +# Makefile for uustat +# $Id: Makefile,v 1.2 1993/08/05 16:15:22 jtc Exp $ + +BINDIR= $(bindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uustat +SRCS= uustat.c util.c log.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DOWNER=\"$(owner)\"\ + -DVERSION=\"$(VERSION)\" + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uustat/uustat.1 b/gnu/libexec/uucp/uustat/uustat.1 new file mode 100644 index 0000000000..b818521676 --- /dev/null +++ b/gnu/libexec/uucp/uustat/uustat.1 @@ -0,0 +1,380 @@ +''' $Id: uustat.1,v 1.1 1993/08/04 19:37:04 jtc Exp $ +.TH uustat 1 "Taylor UUCP 1.04" +.SH NAME +uustat \- UUCP status inquiry and control +.SH SYNOPSIS +.B uustat \-a +.PP +.B uustat +[ +.B \-eKiMNQ ] [ +.B \-sS +system ] [ +.B \-uU +user ] [ +.B \-cC +command ] [ +.B \-o +hours ] [ +.B \-y +hours ] [ +.B \-B +lines ] +.PP +.B uustat +[ +.B \-k +jobid ] [ +.B \-r +jobid ] +.PP +.B uustat \-q +.PP +.B uustat \-m +.PP +.B uustat \-p +.SH DESCRIPTION +The +.I uustat +command can display various types of status information about the UUCP +system. It can also be used to cancel or rejuvenate requests made by +.I uucp +(1) or +.I uux +(1). + +By default +.I uustat +displays all jobs queued up for the invoking user, as if given the +.B \-u +option with the appropriate argument. + +If any of the +.B \-a, +.B \-e, +.B \-s, +.B \-S, +.B \-u, +.B \-U, +.B \-c, +.B \-C, +.B \-o, +.B \-y +options are given, then all jobs which match the combined +specifications are displayed. + +The +.B \-K +option may be used to kill off a selected group of jobs, such as all +jobs more than 7 days old. +.SH OPTIONS +The following options may be given to +.I uustat. +.TP 5 +.B \-a +List all queued file transfer requests. +.TP 5 +.B \-e +List queued execution requests rather than queued file transfer +requests. Queued execution requests are processed by +.I uuxqt +(8) rather than +.I uucico +(8). Queued execution requests may be waiting for some file to be +transferred from a remote system. They are created by an invocation +of +.I uux +(1). +.TP 5 +.B \-s system +List all jobs queued up for the named system. This option may be +specified multiple times, in which case all jobs for all the systems +will be listed. +.TP 5 +.B \-S system +List all jobs queued for systems other than the one named. This +option may be specified multiple times, in which case no jobs from any +of the specified systems will be listed. This option may not be used +with +.B \-s. +.TP 5 +.B \-u user +List all jobs queued up for the named user. This option may be +specified multiple times, in which case all jobs for all the users +will be listed. +.TP 5 +.B \-U user +List all jobs queued up for users other than the one named. This +option may be specified multiple times, in which case no jobs from any +of the specified users will be listed. This option may not be used +with +.B \-u. +.TP 5 +.B \-c command +List all jobs requesting the execution of the named command. If +.B command +is +.I ALL +this will list all jobs requesting the execution of some command (as +opposed to simply requesting a file transfer). This option may be +specified multiple times, in which case all jobs requesting any of the +commands will be listed. +.TP 5 +.B \-C command +List all jobs requesting execution of some command other than the +named command, or, if +.B command +is +.I ALL, +list all jobs that simply request a file transfer (as opposed to +requesting the execution of some command). This option may be +specified multiple times, in which case no job requesting one of the +specified commands will be listed. This option may not be used with +.B \-c. +.TP 5 +.B \-o hours +List all queued jobs older than the given number of hours. +.TP 5 +.B \-y hours +List all queued jobs younger than the given number of hours. +.TP 5 +.B \-k jobid +Kill the named job. The job id is shown by the default output format, +as well as by the +.B \-j +option to +.I uucp +(1) or +.I uux +(1). A job may only be killed by the user who created the job, or by +the UUCP administrator or the superuser. The +.B \-k +option may be used multiple times on the command line to kill several +jobs. +.TP 5 +.B \-r jobid +Rejuvenate the named job. This will mark it as having been invoked at +the current time, affecting the output of the +.B \-o +or +.B \-y +options and preserving it from any automated cleanup daemon. The job +id is shown by the default output format, as well as by the +.B \-j +option to +.I uucp +(1) or +.I uux +(1). A job may only be rejuvenated by the user who created the job, +or by the UUCP administrator or the superuser. The +.B \-r +option may be used multiple times on the command line to rejuvenate +several jobs. +.TP 5 +.B \-q +Display the status of commands, executions and conversations for all +remote systems for which commands or executions are queued. +.TP 5 +.B \-m +Display the status of conversations for all remote systems. +.TP 5 +.B \-p +Display the status of all processes holding UUCP locks on systems or +ports. +.TP 5 +.B \-i +For each listed job, prompt whether to kill the job or not. If the +first character of the input line is +.I y +or +.I Y +the job will be killed. +.TP 5 +.B \-K +Automatically kill each listed job. This can be useful for automatic +cleanup scripts, in conjunction with the +.B \-M +and +.B \-N +options. +.TP 5 +.B \-M +For each listed job, send mail to the UUCP administrator. If the job +is killed (due to +.B \-K +or +.B \-i +with an affirmative response) the mail will indicate that. A comment +specified by the +.B \-W +option may be included. If the job is an execution, the initial +portion of its standard input will be included in the mail message; +the number of lines to include may be set with the +.B \-B +option (the default is 100). If the standard input contains null +characters, it is assumed to be a binary file and is not included. +.TP 5 +.B \-N +For each listed job, send mail to the user who requested the job. The +mail is identical to that sent by the +.B \-M +option. +.TP 5 +.B \-W +Specify a comment to be included in mail sent with the +.B \-M +or +.B \-N +options. +.TP 5 +.B \-Q +Do not actually list the job, but only take any actions indicated by +the +.B \-i, +.B \-K, +.B \-M, +.B \-N +options. +.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, config, +spooldir and execute are meaningful for +.I uustat. + +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. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I uustat +was compiled. +.SH EXAMPLES +.EX +uustat -a +.EE +Display status of all jobs. A sample output line is as follows: +.EX +bugsA027h bugs ian 04-01 13:50 Executing rmail ian@airs.com (sending 1283 bytes) +.EE +The format is +.EX +jobid system user queue-date command (size) +.EE +The jobid may be passed to the +.B \-k +or +.B \-r +options. +The size indicates how much data is to be transferred to the remote +system, and is absent for a file receive request. +The +.B \-s, +.B \-S, +.B \-u, +.B \-U, +.B \-c, +.B \-C, +.B \-o, +and +.B \-y +options may be used to control which jobs are listed. + +.EX +uustat -e +.EE +Display status of queued up execution requests. A sample output line +is as follows: +.EX +bugs bugs!ian 05-20 12:51 rmail ian +.EE +The format is +.EX +system requestor queue-date command +.EE +The +.B \-s, +.B \-S, +.B \-u, +.B \-U, +.B \-c, +.B \-C, +.B \-o, +and +.B \-y +options may be used to control which requests are listed. + +.EX +uustat -q +.EE +Display status for all systems with queued up commands. A sample +output line is as follows: +.EX +bugs 4C (1 hour) 0X (0 secs) 04-01 14:45 Dial failed +.EE +This indicates the system, the number of queued commands, the age of +the oldest queued command, the number of queued local executions, the +age of the oldest queued execution, the date of the last conversation, +and the status of that conversation. + +.EX +uustat -m +.EE +Display conversation status for all remote systems. A sample output +line is as follows: +.EX +bugs 04-01 15:51 Conversation complete +.EE +This indicates the system, the date of the last conversation, and the +status of that conversation. If the last conversation failed, +.I uustat +will indicate how many attempts have been made to call the system. If +the retry period is currently preventing calls to that system, +.I uustat +also displays the time when the next call will be permitted. + +.EX +uustat -p +.EE +Display the status of all processes holding UUCP locks. The output +format is system dependent, as +.I uustat +simply invokes +.I ps +(1) on each process holding a lock. + +.EX +uustat -c rmail -o 168 -K -Q -M -N -W"Queued for over 1 week" +.EE +This will kill all +.I rmail +commands that have been queued up waiting for delivery for over 1 week +(168 hours). For each such command, mail will be sent both to the +UUCP administrator and to the user who requested the rmail execution. +The mail message sent will include the string given by the +.B \-W +option. The +.B \-Q +option prevents any of the jobs from being listed on the terminal, so +any output from the program will be error messages. +.SH FILES +The file names may be changed at compilation time or by the +configuration file, so these are only approximations. + +.br +/usr/lib/uucp/config - Configuration file. +.br +/usr/spool/uucp - +UUCP spool directory. +.SH SEE ALSO +ps(1), rmail(1), uucp(1), uux(1), uucico(8), uuxqt(8) +.SH AUTHOR +Ian Lance Taylor +(ian@airs.com or uunet!airs!ian) diff --git a/gnu/libexec/uucp/uustat/uustat.c b/gnu/libexec/uucp/uustat/uustat.c new file mode 100644 index 0000000000..3c1352668c --- /dev/null +++ b/gnu/libexec/uucp/uustat/uustat.c @@ -0,0 +1,2241 @@ +/* uustat.c + UUCP status program + + 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 uustat_rcsid[] = "$Id: uustat.c,v 1.1 1993/08/04 19:37:05 jtc Exp $"; +#endif + +#include +#include + +#if HAVE_TIME_H +#include +#endif + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* The uustat program permits various listings and manipulations of + files in the spool directory. This implementation supports the + following switches: + + -a list all jobs + -Blines number of lines of standard input to mail + -ccommand list only executions of specified command + -Ccommand list only jobs other than executions of specified command + -e list execute jobs rather than command requests + -i ask user whether to kill each listed job + -Ifile set configuration file name + -kjobid kill job with specified ID + -K kill each listed job + -m report status for all remote machines + -M mail uucp about each job killed with -K + -N mail requestor about each job killed with -K + -ohour report jobs older than specified number of hours + -p do "ps -flp" on all processes holding lock files (Unix specific) + -q list number of jobs for all systems + -Q don't list jobs, just do -K processing + -rjobid rejuvenate job with specified ID + -ssystem report on all jobs for specified system + -Ssystem report on all jobs other than for specified system + -uuser report on all jobs for specified user + -Uuser report on all jobs other than for specified user + -Wcomment comment to include in mail messages + -xdebug set debugging level + -yhour report jobs younger than specified number of hours */ + +/* The program name. */ +char abProgram[] = "uustat"; + +/* What to do with a job that matches the selection criteria; these + values may be or'red together. */ +#define JOB_SHOW (01) +#define JOB_INQUIRE (02) +#define JOB_KILL (04) +#define JOB_MAIL (010) +#define JOB_NOTIFY (020) + +/* This structure is used to accumulate all the lines in a single + command file, so that they can all be displayed at once and so that + executions can be displayed reasonably. */ + +struct scmdlist +{ + struct scmdlist *qnext; + struct scmd s; + long itime; +}; + +/* Local functions. */ + +static void ususage P((void)); +static boolean fsxqt_file_read P((pointer puuconf, const char *zfile)); +static void usxqt_file_free P((void)); +static int isxqt_cmd P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int isxqt_file P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int isxqt_user P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static boolean fsworkfiles P((pointer puuconf, int icmd, int csystems, + char **pazsystems, boolean fnotsystems, + int cusers, char **pazusers, + boolean fnotusers, long iold, long iyoung, + int ccommands, char **pazcommands, + boolean fnotcommands, const char *zcomment, + int cstdin)); +static boolean fsworkfiles_system P((pointer puuconf,int icmd, + const struct uuconf_system *qsys, + int cusers, char **pazusers, + boolean fnotusers, long iold, + long iyoung, int ccommands, + char **pazcommands, + boolean fnotcommands, + const char *zcomment, int cstdin)); +static boolean fsworkfile_show P((pointer puuconf, int icmd, + const struct uuconf_system *qsys, + const struct scmd *qcmd, + long itime, int ccommands, + char **pazcommands, boolean fnotcommands, + const char *zcomment, int cstdin)); +static void usworkfile_header P((const struct uuconf_system *qsys, + const struct scmd *qcmd, + const char *zjobid, + long itime, boolean ffirst)); +static boolean fsexecutions P((pointer puuconf, int icmd, int csystems, + char **pazsystems, boolean fnotsystems, + int cusers, char **pazusers, + boolean fnotusers, long iold, long iyoung, + int ccommands, char **pazcommands, + boolean fnotcommands, const char *zcomment, + int cstdin)); +static boolean fsnotify P((pointer puuconf, int icmd, const char *zcomment, + int cstdin, boolean fkilled, const char *zcmd, + struct scmdlist *qcmd, const char *zid, + const char *zuser, + const struct uuconf_system *qsys, + const char *zstdin, pointer pstdinseq, + const char *zrequestor)); +static boolean fsquery P((pointer puuconf)); +static int csunits_show P((long idiff)); +static boolean fsmachines P((void)); + +/* Long getopt options. */ +static const struct option asSlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -a: list all jobs. */ + boolean fall = FALSE; + /* -B lines: number of lines of standard input to mail. */ + int cstdin = 100; + /* -c,-C command: list only specified command. */ + int ccommands = 0; + char **pazcommands = NULL; + boolean fnotcommands = FALSE; + /* -e: list execute jobs. */ + boolean fexecute = FALSE; + /* -k jobid: kill specified job. */ + int ckills = 0; + char **pazkills = NULL; + /* -m: report machine status. */ + boolean fmachine = FALSE; + /* -o hour: report jobs older than given number of hours. */ + int ioldhours = -1; + /* -p: report status of jobs holding lock files. */ + boolean fps = FALSE; + /* -q: list number of jobs for each system. */ + boolean fquery = FALSE; + /* -r jobid: rejuvenate specified job. */ + int crejuvs = 0; + char **pazrejuvs = NULL; + /* -s,-S system: list all jobs for specified system. */ + int csystems = 0; + char **pazsystems = NULL; + boolean fnotsystems = FALSE; + /* -u,-U user: list all jobs for specified user. */ + int cusers = 0; + char **pazusers = NULL; + boolean fnotusers = FALSE; + /* -W comment: comment to include in mail messages. */ + const char *zcomment = NULL; + /* -y hour: report jobs younger than given number of hours. */ + int iyounghours = -1; + /* -I file: set configuration file. */ + const char *zconfig = NULL; + /* -Q, -i, -K, -M, -N: what to do with each job. */ + int icmd = JOB_SHOW; + int ccmds; + int iopt; + pointer puuconf; + int iuuconf; + long iold; + long iyoung; + const char *azoneuser[1]; + boolean fret; + + while ((iopt = getopt_long (argc, argv, + "aB:c:C:eiI:k:KmMNo:pqQr:s:S:u:U:W:x:y:", + asSlongopts, (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'a': + /* List all jobs. */ + fall = TRUE; + break; + + case 'B': + /* Number of lines of standard input to mail. */ + cstdin = (int) strtol (optarg, (char **) NULL, 10); + break; + + case 'C': + /* List jobs for other than specified command. */ + fnotcommands = TRUE; + /* Fall through. */ + case 'c': + /* List specified command. */ + ++ccommands; + pazcommands = (char **) xrealloc ((pointer) pazcommands, + ccommands * sizeof (char *)); + pazcommands[ccommands - 1] = optarg; + break; + + case 'e': + /* List execute jobs. */ + fexecute = TRUE; + break; + + case 'i': + /* Prompt the user whether to kill each job. */ + icmd |= JOB_INQUIRE; + break; + + case 'I': + /* Set configuration file name. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'k': + /* Kill specified job. */ + ++ckills; + pazkills = (char **) xrealloc ((pointer) pazkills, + ckills * sizeof (char *)); + pazkills[ckills - 1] = optarg; + break; + + case 'K': + /* Kill each listed job. */ + icmd |= JOB_KILL; + break; + + case 'm': + /* Report machine status. */ + fmachine = TRUE; + break; + + case 'M': + /* Mail to uucp action taken on each job. */ + icmd |= JOB_MAIL; + break; + + case 'N': + /* Mail to requestor action taken on each job. */ + icmd |= JOB_NOTIFY; + break; + + case 'o': + /* Report old jobs. */ + ioldhours = (int) strtol (optarg, (char **) NULL, 10); + break; + + case 'p': + /* Get status of processes holding locks. */ + fps = TRUE; + break; + + case 'q': + /* List number of jobs for each system. */ + fquery = TRUE; + break; + + case 'Q': + /* Don't list jobs, just do -K processing. */ + icmd &=~ JOB_SHOW; + break; + + case 'r': + /* Rejuvenate specified job. */ + ++crejuvs; + pazrejuvs = (char **) xrealloc ((pointer) pazrejuvs, + crejuvs * sizeof (char *)); + pazrejuvs[crejuvs - 1] = optarg; + break; + + case 'S': + /* List jobs for other than specified system. */ + fnotsystems = TRUE; + /* Fall through. */ + case 's': + /* List jobs for specified system. */ + ++csystems; + pazsystems = (char **) xrealloc ((pointer) pazsystems, + csystems * sizeof (char *)); + pazsystems[csystems - 1] = optarg; + break; + + case 'U': + /* List jobs for other than specified user. */ + fnotusers = TRUE; + /* Fall through. */ + case 'u': + /* List jobs for specified user. */ + ++cusers; + pazusers = (char **) xrealloc ((pointer) pazusers, + cusers * sizeof (char *)); + pazusers[cusers - 1] = optarg; + break; + + case 'W': + /* Comment to include in mail messages. */ + zcomment = optarg; + break; + + case 'x': +#if DEBUG > 1 + /* Set debugging level. */ + iDebug |= idebug_parse (optarg); +#endif + break; + + case 'y': + /* List jobs younger than given number of hours. */ + iyounghours = (int) strtol (optarg, (char **) NULL, 10); + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + ususage (); + break; + } + } + + if (optind != argc) + ususage (); + + /* To avoid confusion, most options are only permitted by + themselves. This restriction might be removed later, but it is + imposed by most implementations. We do permit any combination of + -c, -s, -u, -o and -y, and any combination of -k and -r. */ + ccmds = 0; + if (fall) + ++ccmds; + if (ckills > 0 || crejuvs > 0) + ++ccmds; + if (fmachine) + ++ccmds; + if (fps) + ++ccmds; + if (fquery) + ++ccmds; + if (fexecute || csystems > 0 || cusers > 0 || ioldhours != -1 + || iyounghours != -1 || ccommands > 0) + ++ccmds; + + if (ccmds > 1) + { + ulog (LOG_ERROR, "Too many options"); + ususage (); + } + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#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_SUID); + + /* If no commands were specified, we list all commands for the given + user. */ + if (ccmds == 0) + { + cusers = 1; + azoneuser[0] = zsysdep_login_name (); + pazusers = (char **) azoneuser; + } + + /* Canonicalize the system names. */ + if (csystems > 0) + { + int i; + + for (i = 0; i < csystems; i++) + { + struct uuconf_system ssys; + + iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_FATAL, "%s: System not found", pazsystems[i]); + else + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + if (strcmp (pazsystems[i], ssys.uuconf_zname) != 0) + pazsystems[i] = zbufcpy (ssys.uuconf_zname); + (void) uuconf_system_free (puuconf, &ssys); + } + } + + if (ioldhours == -1) + iold = (long) -1; + else + { + iold = (ixsysdep_time ((long *) NULL) + - (long) ioldhours * (long) 60 * (long) 60); + if (iold < 0L) + iold = 0L; + } + if (iyounghours == -1) + iyoung = (long) -1; + else + { + iyoung = (ixsysdep_time ((long *) NULL) + - (long) iyounghours * (long) 60 * (long) 60); + if (iyoung < 0L) + iyoung = 0L; + } + + if (! fexecute + && (fall + || csystems > 0 + || cusers > 0 + || ioldhours != -1 + || iyounghours != -1 + || ccommands > 0)) + fret = fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, + cusers, pazusers, fnotusers, iold, iyoung, + ccommands, pazcommands, fnotcommands, zcomment, + cstdin); + else if (fexecute) + fret = fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, + cusers, pazusers, fnotusers, iold, iyoung, + ccommands, pazcommands, fnotcommands, zcomment, + cstdin); + else if (icmd != JOB_SHOW) + { + ulog (LOG_ERROR, + "-i, -K, -M, -N, -Q not supported with -k, -m, -p, -q, -r"); + ususage (); + fret = FALSE; + } + else if (fquery) + fret = fsquery (puuconf); + else if (fmachine) + fret = fsmachines (); + else if (ckills > 0 || crejuvs > 0) + { + int i; + + fret = TRUE; + for (i = 0; i < ckills; i++) + if (! fsysdep_kill_job (puuconf, pazkills[i])) + fret = FALSE; + + for (i = 0; i < crejuvs; i++) + if (! fsysdep_rejuvenate_job (puuconf, pazrejuvs[i])) + fret = FALSE; + } + else if (fps) + fret = fsysdep_lock_status (); + else + { +#if DEBUG > 0 + ulog (LOG_FATAL, "Can't happen"); +#endif + fret = FALSE; + } + + ulog_close (); + + usysdep_exit (fret); + + /* Avoid errors about not returning a value. */ + return 0; +} + +/* Print a usage message and die. */ + +static void +ususage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uustat [options]\n"); + fprintf (stderr, + " -a: list all UUCP jobs\n"); + fprintf (stderr, + " -B num: number of lines to return in -M or -N mail message\n"); + fprintf (stderr, + " -c command: list requests for named command\n"); + fprintf (stderr, + " -C command: list requests for other than named command\n"); + fprintf (stderr, + " -e: list queued executions rather than job requests\n"); + fprintf (stderr, + " -i: prompt for whether to kill each listed job\n"); + fprintf (stderr, + " -k job: kill specified UUCP job\n"); + fprintf (stderr, + " -K: kill each listed job\n"); + fprintf (stderr, + " -m: report status for all remote machines\n"); + fprintf (stderr, + " -M: mail report on each listed job to UUCP administrator\n"); + fprintf (stderr, + " -N: mail report on each listed job to requestor\n"); + fprintf (stderr, + " -o hours: list all jobs older than given number of hours\n"); + fprintf (stderr, + " -p: show status of all processes holding UUCP locks\n"); + fprintf (stderr, + " -q: list number of jobs for each system\n"); + fprintf (stderr, + " -Q: don't list jobs, just take actions (-i, -K, -M, -N)\n"); + fprintf (stderr, + " -r job: rejuvenate specified UUCP job\n"); + fprintf (stderr, + " -s system: list all jobs for specified system\n"); + fprintf (stderr, + " -S system: list all jobs for other than specified system\n"); + fprintf (stderr, + " -u user: list all jobs for specified user\n"); + fprintf (stderr, + " -U user: list all jobs for other than specified user\n"); + fprintf (stderr, + " -W comment: comment to include in mail messages\n"); + fprintf (stderr, + " -y hours: list all jobs younger than given number of hours\n"); + fprintf (stderr, + " -x debug: Set debugging level (0 for none, 9 is max)\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* We need to be able to read information from an execution file. */ + +/* The user name extracted from an execution file. */ +static char *zSxqt_user; + +/* The system name from an execution file. */ +static char *zSxqt_system; + +/* Address of requesting user (who to send mail to). */ +static const char *zSxqt_requestor; + +/* The command (no arguments) from an execution file. */ +static char *zSxqt_prog; + +/* The full command line from an execution file. */ +static char *zSxqt_cmd; + +/* Number of files associated with an execution file. */ +static int cSxqt_files; + +/* Names of files associated with execution file. */ +static char **pazSxqt_files; + +/* Standard input file name. */ +static const char *zSxqt_stdin; + +/* A command table used to dispatch an execution file. */ +static const struct uuconf_cmdtab asSxqt_cmds[] = +{ + { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_cmd }, + { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_stdin, NULL }, + { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_file }, + { "R", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_requestor, NULL }, + { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, isxqt_user }, + { NULL, 0, NULL, NULL } +}; + +/* Read an execution file, setting the above variables. */ + +static boolean +fsxqt_file_read (puuconf, zfile) + pointer puuconf; + const char *zfile; +{ + FILE *e; + int iuuconf; + boolean fret; + + e = fopen (zfile, "r"); + if (e == NULL) + { + ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); + return FALSE; + } + + zSxqt_user = NULL; + zSxqt_system = NULL; + zSxqt_stdin = NULL; + zSxqt_requestor = NULL; + zSxqt_prog = NULL; + zSxqt_cmd = NULL; + cSxqt_files = 0; + pazSxqt_files = NULL; + + iuuconf = uuconf_cmd_file (puuconf, e, asSxqt_cmds, (pointer) NULL, + (uuconf_cmdtabfn) NULL, + UUCONF_CMDTABFLAG_CASE, (pointer) NULL); + (void) fclose (e); + if (iuuconf == UUCONF_SUCCESS) + fret = TRUE; + else + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + } + + if (zSxqt_user == NULL) + zSxqt_user = zbufcpy ("*unknown*"); + if (zSxqt_system == NULL) + zSxqt_system = zbufcpy ("*unknown*"); + if (zSxqt_prog == NULL) + { + zSxqt_prog = zbufcpy ("*none*"); + zSxqt_cmd = zbufcpy ("*none*"); + } + + return fret; +} + +/* Free up the information read from an execution file. */ + +static void +usxqt_file_free () +{ + int i; + + ubuffree (zSxqt_user); + zSxqt_user = NULL; + ubuffree (zSxqt_system); + zSxqt_system = NULL; + ubuffree (zSxqt_prog); + zSxqt_prog = NULL; + ubuffree (zSxqt_cmd); + zSxqt_cmd = NULL; + for (i = 0; i < cSxqt_files; i++) + ubuffree (pazSxqt_files[i]); + cSxqt_files = 0; + xfree ((pointer) pazSxqt_files); + pazSxqt_files = NULL; + zSxqt_stdin = NULL; + zSxqt_requestor = NULL; +} + +/* Get the command from an execution file. */ + +/*ARGSUSED*/ +static int +isxqt_cmd (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + size_t clen; + int i; + + if (argc <= 1) + return UUCONF_CMDTABRET_CONTINUE; + + zSxqt_prog = zbufcpy (argv[1]); + + clen = 0; + for (i = 1; i < argc; i++) + clen += strlen (argv[i]) + 1; + + zSxqt_cmd = zbufalc (clen); + zSxqt_cmd[0] = '\0'; + for (i = 1; i < argc - 1; i++) + { + strcat (zSxqt_cmd, argv[i]); + strcat (zSxqt_cmd, " "); + } + strcat (zSxqt_cmd, argv[i]); + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Get the associated files from an execution file. */ + +/*ARGSUSED*/ +static int +isxqt_file (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + if (argc != 2 && argc != 3) + return UUCONF_CMDTABRET_CONTINUE; + + /* If this file is not in the spool directory, just ignore it. */ + if (! fspool_file (argv[1])) + return UUCONF_CMDTABRET_CONTINUE; + + ++cSxqt_files; + pazSxqt_files = (char **) xrealloc ((pointer) pazSxqt_files, + cSxqt_files * sizeof (char *)); + + pazSxqt_files[cSxqt_files - 1] = zbufcpy (argv[1]); + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Get the requesting user and system from an execution file. */ + +/*ARGSUSED*/ +static int +isxqt_user (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + zSxqt_user = zbufcpy (argv[1]); + zSxqt_system = zbufcpy (argv[2]); + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle various possible requests to look at work files. */ + +static boolean +fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, + pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, + fnotcommands, zcomment, cstdin) + pointer puuconf; + int icmd; + int csystems; + char **pazsystems; + boolean fnotsystems; + int cusers; + char **pazusers; + boolean fnotusers; + long iold; + long iyoung; + int ccommands; + char **pazcommands; + boolean fnotcommands; + const char *zcomment; + int cstdin; +{ + boolean fret; + int i; + int iuuconf; + struct uuconf_system ssys; + + fret = TRUE; + + if (csystems > 0 && ! fnotsystems) + { + for (i = 0; i < csystems; i++) + { + iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_ERROR, "%s: System not found", pazsystems[i]); + else + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + continue; + } + + if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, + fnotusers, iold, iyoung, ccommands, + pazcommands, fnotcommands, zcomment, + cstdin)) + fret = FALSE; + + (void) uuconf_system_free (puuconf, &ssys); + } + } + else + { + char **pznames, **pz; + + iuuconf = uuconf_system_names (puuconf, &pznames, 0); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + for (pz = pznames; *pz != NULL; pz++) + { + if (csystems > 0) + { + for (i = 0; i < csystems; i++) + if (strcmp (*pz, pazsystems[i]) == 0) + break; + if (i < csystems) + continue; + } + + iuuconf = uuconf_system_info (puuconf, *pz, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + continue; + } + + if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, + fnotusers, iold, iyoung, ccommands, + pazcommands, fnotcommands, zcomment, + cstdin)) + fret = FALSE; + + (void) uuconf_system_free (puuconf, &ssys); + xfree ((pointer) *pz); + } + xfree ((pointer) pznames); + } + + return fret; +} + +/* Look at the work files for a particular system. */ + +static boolean +fsworkfiles_system (puuconf, icmd, qsys, cusers, pazusers, fnotusers, iold, + iyoung, ccommands, pazcommands, fnotcommands, zcomment, + cstdin) + pointer puuconf; + int icmd; + const struct uuconf_system *qsys; + int cusers; + char **pazusers; + boolean fnotusers; + long iold; + long iyoung; + int ccommands; + char **pazcommands; + boolean fnotcommands; + const char *zcomment; + int cstdin; +{ + boolean fret; + + if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) + return FALSE; + + while (TRUE) + { + struct scmd s; + long itime; + + if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) + { + usysdep_get_work_free (qsys); + return FALSE; + } + if (s.bcmd == 'H') + break; + + if (cusers > 0) + { + boolean fmatch; + int i; + + fmatch = fnotusers; + for (i = 0; i < cusers; i++) + { + if (s.zuser != NULL + && strcmp (pazusers[i], s.zuser) == 0) + { + fmatch = ! fmatch; + break; + } + } + if (! fmatch) + continue; + } + + itime = ixsysdep_work_time (qsys, s.pseq); + + if (iold != (long) -1 && itime > iold) + continue; + + if (iyoung != (long) -1 && itime < iyoung) + continue; + + if (! fsworkfile_show (puuconf, icmd, qsys, &s, itime, ccommands, + pazcommands, fnotcommands, zcomment, cstdin)) + { + usysdep_get_work_free (qsys); + return FALSE; + } + } + + fret = fsworkfile_show (puuconf, icmd, qsys, (const struct scmd *) NULL, + 0L, ccommands, pazcommands, fnotcommands, zcomment, + cstdin); + + usysdep_get_work_free (qsys); + + return fret; +} + +/* Show a single workfile. This is actually called once for each line + in the workfile, so we accumulate the lines and show them all at + once. This lets us show an execution in a useful fashion. */ + +static boolean +fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands, + fnotcommands, zcomment, cstdin) + pointer puuconf; + int icmd; + const struct uuconf_system *qsys; + const struct scmd *qcmd; + long itime; + int ccommands; + char **pazcommands; + boolean fnotcommands; + const char *zcomment; + int cstdin; +{ + static struct scmdlist *qlist; + static char *zlistid; + char *zid; + + if (qcmd == NULL) + zid = NULL; + else + { + zid = zsysdep_jobid (qsys, qcmd->pseq); + if (zid == NULL) + return FALSE; + } + + /* If this is the same jobid as the list, put it on the end. */ + + if (qcmd != NULL + && qlist != NULL + && strcmp (zlistid, zid) == 0) + { + struct scmdlist *qnew, **pq; + + ubuffree (zid); + qnew = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); + qnew->qnext = NULL; + qnew->s = *qcmd; + qnew->itime = itime; + for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) + ; + *pq = qnew; + return TRUE; + } + + /* Here we have found a different job ID, so we print the scmd + structures that we have accumulated. We look for the special + case of an execution (an E command, or one of the destination + files begins with X.). We could be more clever about other + situations as well. */ + if (qlist != NULL) + { + boolean fmatch; + const char *zprog, *zcmd, *zrequestor, *zstdin; + char *zfree; + struct scmdlist *qxqt; + struct scmdlist *qfree; + + fmatch = FALSE; + zprog = zcmd = zrequestor = zstdin = NULL; + zfree = NULL; + + for (qxqt = qlist; qxqt != NULL; qxqt = qxqt->qnext) + if (qxqt->s.bcmd == 'E' + || (qxqt->s.bcmd == 'S' + && qxqt->s.zto[0] == 'X' + && qxqt->s.zto[1] == '.' + && fspool_file (qxqt->s.zfrom))) + break; + + if (qxqt == NULL) + { + if (ccommands == 0 + || (fnotcommands + && strcmp (pazcommands[0], "ALL") == 0)) + { + /* Show all the lines in a regular work file. */ + fmatch = TRUE; + + if ((icmd & JOB_SHOW) != 0) + { + struct scmdlist *qshow; + + for (qshow = qlist; qshow != NULL; qshow = qshow->qnext) + { + char *zfile; + long cbytes; + + usworkfile_header (qsys, &qshow->s, zlistid, + qshow->itime, qshow == qlist); + + switch (qshow->s.bcmd) + { + case 'S': + if (strchr (qshow->s.zoptions, 'C') != NULL + || fspool_file (qshow->s.zfrom)) + zfile = zsysdep_spool_file_name (qsys, + qshow->s.ztemp, + qshow->s.pseq); + else + zfile = zbufcpy (qshow->s.zfrom); + if (zfile == NULL) + cbytes = 0; + else + { + cbytes = csysdep_size (zfile); + if (cbytes < 0) + cbytes = 0; + } + printf ("Sending %s (%ld bytes) to %s", + qshow->s.zfrom, cbytes, qshow->s.zto); + ubuffree (zfile); + break; + case 'R': + printf ("Requesting %s to %s", qshow->s.zfrom, + qshow->s.zto); + break; + case 'X': + printf ("Requesting %s to %s", qshow->s.zfrom, + qshow->s.zto); + break; + case 'P': + printf ("(poll file)"); + break; +#if DEBUG > 0 + default: + printf ("Bad line %d", qshow->s.bcmd); + break; +#endif + } + + printf ("\n"); + } + } + } + } + else + { + long csize; + struct scmdlist *qsize; + + /* Show the command for an execution file. */ + if (qxqt->s.bcmd == 'E') + { + zfree = zbufcpy (qxqt->s.zcmd); + zfree[strcspn (zfree, " \t")] = '\0'; + zprog = zfree; + zcmd = qxqt->s.zcmd; + if (strchr (qxqt->s.zoptions, 'R') != NULL) + zrequestor = qxqt->s.znotify; + } + else + { + char *zxqt; + + zxqt = zsysdep_spool_file_name (qsys, qxqt->s.zfrom, + qxqt->s.pseq); + if (zxqt == NULL) + return FALSE; + + if (! fsxqt_file_read (puuconf, zxqt)) + { + ubuffree (zxqt); + return FALSE; + } + + ubuffree (zxqt); + + zprog = zSxqt_prog; + zcmd = zSxqt_cmd; + zrequestor = zSxqt_requestor; + } + + csize = 0L; + for (qsize = qlist; qsize != NULL; qsize = qsize->qnext) + { + if (qsize->s.bcmd == 'S' || qsize->s.bcmd == 'E') + { + char *zfile; + + if (strchr (qsize->s.zoptions, 'C') != NULL + || fspool_file (qsize->s.zfrom)) + zfile = zsysdep_spool_file_name (qsys, qsize->s.ztemp, + qsize->s.pseq); + else + zfile = zbufcpy (qsize->s.zfrom); + if (zfile != NULL) + { + long cbytes; + + cbytes = csysdep_size (zfile); + if (cbytes > 0) + csize += cbytes; + ubuffree (zfile); + } + } + } + + if (ccommands == 0) + fmatch = TRUE; + else + { + int i; + + fmatch = fnotcommands; + for (i = 0; i < ccommands; i++) + { + if (strcmp (pazcommands[i], "ALL") == 0 + || strcmp (pazcommands[i], zprog) == 0) + { + fmatch = ! fmatch; + break; + } + } + } + + /* To get the name of the standard input file on this system + we have to look through the list of file transfers to + find the right one on the remote system. */ + if (fmatch) + { + struct scmdlist *qstdin; + + if (qxqt->s.bcmd == 'E') + qstdin = qxqt; + else if (zSxqt_stdin != NULL) + { + for (qstdin = qlist; + qstdin != NULL; + qstdin = qstdin->qnext) + if (qstdin->s.bcmd == 'S' + && strcmp (qstdin->s.zto, zSxqt_stdin) == 0) + break; + } + else + qstdin = NULL; + + if (qstdin != NULL) + { + if (strchr (qstdin->s.zoptions, 'C') != NULL + || fspool_file (qstdin->s.zfrom)) + zstdin = qstdin->s.ztemp; + else + zstdin = qstdin->s.zfrom; + } + } + + if (fmatch && (icmd & JOB_SHOW) != 0) + { + usworkfile_header (qsys, &qxqt->s, zlistid, qxqt->itime, + TRUE); + printf ("Executing %s (sending %ld bytes)\n", zcmd, csize); + } + } + + if (fmatch) + { + boolean fkill; + + fkill = FALSE; + if ((icmd & JOB_INQUIRE) != 0) + { + int b; + + /* Ask stdin whether this job should be killed. */ + fprintf (stderr, "%s: Kill %s? ", abProgram, zlistid); + (void) fflush (stderr); + b = getchar (); + fkill = b == 'y' || b == 'Y'; + while (b != EOF && b != '\n') + b = getchar (); + } + else if ((icmd & JOB_KILL) != 0) + fkill = TRUE; + + if (fkill + && (qlist->s.zuser == NULL + || strcmp (zsysdep_login_name (), qlist->s.zuser) != 0) + && ! fsysdep_privileged ()) + ulog (LOG_ERROR, "%s: Not submitted by you", zlistid); + else + { + if ((icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) + { + if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill, + zcmd, qlist, zlistid, qlist->s.zuser, + qsys, zstdin, qlist->s.pseq, zrequestor)) + return FALSE; + } + + if (fkill) + { + if (! fsysdep_kill_job (puuconf, zlistid)) + return FALSE; + } + } + } + + if (qxqt != NULL) + { + if (qxqt->s.bcmd == 'E') + ubuffree (zfree); + else + usxqt_file_free (); + } + + /* Free up the list of entries. */ + qfree = qlist; + while (qfree != NULL) + { + struct scmdlist *qnext; + + qnext = qfree->qnext; + xfree ((pointer) qfree); + qfree = qnext; + } + + ubuffree (zlistid); + + qlist = NULL; + zlistid = NULL; + } + + /* Start a new list with the entry we just got. */ + if (qcmd != NULL) + { + qlist = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); + qlist->qnext = NULL; + qlist->s = *qcmd; + qlist->itime = itime; + zlistid = zid; + } + + return TRUE; +} + +/* Show the header of the line describing a workfile. */ + +static void +usworkfile_header (qsys, qcmd, zjobid, itime, ffirst) + const struct uuconf_system *qsys; + const struct scmd *qcmd; + const char *zjobid; + long itime; + boolean ffirst; +{ + const char *zshowid; + struct tm stime; + + if (ffirst) + zshowid = zjobid; + else + zshowid = "-"; + + printf ("%s %s %s ", zshowid, qsys->uuconf_zname, + qcmd->zuser != NULL ? qcmd->zuser : OWNER); + + usysdep_localtime (itime, &stime); + printf ("%02d-%02d %02d:%02d ", + stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); +} + +/* List queued executions that have not been processed by uuxqt for + one reason or another. */ + +static boolean +fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, + pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, + fnotcommands, zcomment, cstdin) + pointer puuconf; + int icmd; + int csystems; + char **pazsystems; + boolean fnotsystems; + int cusers; + char **pazusers; + boolean fnotusers; + long iold; + long iyoung; + int ccommands; + char **pazcommands; + boolean fnotcommands; + const char *zcomment; + int cstdin; +{ + const char *zlocalname; + int iuuconf; + char *zfile; + char *zsystem; + boolean ferr; + + iuuconf = uuconf_localname (puuconf, &zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zlocalname = zsysdep_localname (); + if (zlocalname == NULL) + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + if (! fsysdep_get_xqt_init ()) + return FALSE; + + while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL) + { + boolean fmatch; + int i; + long itime; + + if (csystems > 0) + { + fmatch = fnotsystems; + for (i = 0; i < csystems; i++) + { + if (strcmp (pazsystems[i], zsystem) == 0) + { + fmatch = ! fmatch; + break; + } + } + if (! fmatch) + { + ubuffree (zfile); + ubuffree (zsystem); + continue; + } + } + + itime = ixsysdep_file_time (zfile); + + if ((iold != (long) -1 && itime > iold) + || (iyoung != (long) -1 && itime < iyoung)) + { + ubuffree (zfile); + ubuffree (zsystem); + continue; + } + + /* We need to read the execution file before we can check the + user name. */ + if (! fsxqt_file_read (puuconf, zfile)) + { + ubuffree (zfile); + ubuffree (zsystem); + continue; + } + + if (cusers == 0) + fmatch = TRUE; + else + { + fmatch = fnotusers; + for (i = 0; i < cusers; i++) + { + if (strcmp (zSxqt_user, pazusers[i]) == 0 + || (zSxqt_requestor != NULL + && strcmp (zSxqt_requestor, pazusers[i]) == 0)) + { + fmatch = ! fmatch; + break; + } + } + } + + if (fmatch && ccommands > 0) + { + fmatch = fnotcommands; + for (i = 0; i < ccommands; i++) + { + if (strcmp (pazcommands[i], "ALL") == 0 + || strcmp (pazcommands[i], zSxqt_prog) == 0) + { + fmatch = ! fmatch; + break; + } + } + } + + if (fmatch) + { + boolean fbad, fkill; + struct uuconf_system ssys; + + fbad = FALSE; + + if ((icmd & JOB_SHOW) != 0) + { + struct tm stime; + + printf ("%s %s!", zsystem, zSxqt_system); + if (zSxqt_requestor != NULL) + printf ("%s", zSxqt_requestor); + else + printf ("%s", zSxqt_user); + + usysdep_localtime (itime, &stime); + printf (" %02d-%02d %02d:%02d ", + stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, + stime.tm_min); + + printf ("%s\n", zSxqt_cmd); + } + + fkill = FALSE; + if ((icmd & JOB_INQUIRE) != 0) + { + int b; + + /* Ask stdin whether this job should be killed. */ + fprintf (stderr, "%s: Kill %s? ", abProgram, zSxqt_cmd); + (void) fflush (stderr); + b = getchar (); + fkill = b == 'y' || b == 'Y'; + while (b != EOF && b != '\n') + b = getchar (); + } + else if ((icmd & JOB_KILL) != 0) + fkill = TRUE; + + if (fkill) + { + if ((strcmp (zSxqt_user, zsysdep_login_name ()) != 0 + || strcmp (zsystem, zlocalname) != 0) + && ! fsysdep_privileged ()) + { + ulog (LOG_ERROR, "Job not submitted by you\n"); + fbad = TRUE; + } + } + + if (! fbad) + { + iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fbad = TRUE; + } + else if (strcmp (zsystem, zlocalname) == 0) + { + iuuconf = uuconf_system_local (puuconf, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fbad = TRUE; + } + } + else if (! funknown_system (puuconf, zsystem, &ssys)) + { + ulog (LOG_ERROR, "Job for unknown system %s", + zsystem); + fbad = TRUE; + } + } + } + + if (! fbad && (icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) + { + if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill, + zSxqt_cmd, (struct scmdlist *) NULL, + (const char *) NULL, zSxqt_user, &ssys, + zSxqt_stdin, (pointer) NULL, zSxqt_requestor)) + { + ferr = TRUE; + usxqt_file_free (); + ubuffree (zfile); + ubuffree (zsystem); + break; + } + } + + if (! fbad && fkill) + { + for (i = 0; i < cSxqt_files; i++) + { + char *z; + + z = zsysdep_spool_file_name (&ssys, pazSxqt_files[i], + (pointer) NULL); + if (z != NULL) + { + (void) remove (z); + ubuffree (z); + } + } + if (remove (zfile) != 0) + ulog (LOG_ERROR, "remove (%s): %s", zfile, + strerror (errno)); + } + + if (! fbad) + (void) uuconf_system_free (puuconf, &ssys); + } + + usxqt_file_free (); + ubuffree (zfile); + ubuffree (zsystem); + } + + usysdep_get_xqt_free (); + + return ferr; +} + +/* When a job is killed, send mail to the appropriate people. */ + +static boolean +fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser, + qsys, zstdin, pstdinseq, zrequestor) + pointer puuconf; + int icmd; + const char *zcomment; + int cstdin; + boolean fkilled; + const char *zcmd; + struct scmdlist *qcmd; + const char *zid; + const char *zuser; + const struct uuconf_system *qsys; + const char *zstdin; + pointer pstdinseq; + const char *zrequestor; +{ + const char **pz; + int cgot; + int i, istdin; + const char *zsubject; + boolean fret; + + pz = (const char **) xmalloc (20 * sizeof (const char *)); + cgot = 20; + + i = 0; + if (zid == NULL) + pz[i++] = "A UUCP execution request"; + else + { + pz[i++] = "UUCP job\n\t"; + pz[i++] = zid; + pz[i++] = "\nfor system\n\t"; + pz[i++] = qsys->uuconf_zname; + } + pz[i++] = "\nrequested by\n\t"; + pz[i++] = zuser != NULL ? zuser : OWNER; + if (zid == NULL) + { + pz[i++] = "\non system\n\t"; + pz[i++] = qsys->uuconf_zname; + } + pz[i++] = "\n"; + + if (fkilled) + pz[i++] = "has been killed.\n"; + + if (zcomment != NULL) + { + pz[i++] = zcomment; + pz[i++] = "\n"; + } + + pz[i++] = "The job "; + if (fkilled) + pz[i++] = "was\n"; + else + pz[i++] = "is\n"; + + if (zcmd != NULL) + { + pz[i++] = "\t"; + pz[i++] = zcmd; + } + else + { + struct scmdlist *qshow; + + for (qshow = qcmd; qshow != NULL; qshow = qshow->qnext) + { + if (i + 10 > cgot) + { + cgot += 20; + pz = (const char **) xrealloc ((pointer) pz, + cgot * sizeof (const char *)); + } + + switch (qshow->s.bcmd) + { + case 'S': + pz[i++] = "\tsend "; + break; + default: + case 'R': + case 'X': + pz[i++] = "\trequest "; + break; + case 'P': + pz[i++] = "\tpoll "; +#if DEBUG > 0 + case 'E': + ulog (LOG_FATAL, "fsnotify: Can't happen"); + break; +#endif + } + if (qshow->s.zfrom != NULL && qshow->s.zto != NULL) + { + pz[i++] = qshow->s.zfrom; + pz[i++] = " to "; + pz[i++] = qshow->s.zto; + } + } + } + + istdin = i; + if (cstdin > 0 && zstdin != NULL) + { + boolean fspool; + char *zfile; + FILE *e; + + fspool = fspool_file (zstdin); + if (fspool) + zfile = zsysdep_spool_file_name (qsys, zstdin, pstdinseq); + else + zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir); + + if (zfile != NULL + && (fspool + || fin_directory_list (zfile, qsys->uuconf_pzremote_send, + qsys->uuconf_zpubdir, TRUE, TRUE, + (const char *) NULL))) + { + e = fopen (zfile, "r"); + if (e != NULL) + { + int clines, clen; + char *zline; + size_t cline; + + pz[i++] = "\n"; + istdin = i; + + clines = 0; + + zline = NULL; + cline = 0; + while ((clen = getline (&zline, &cline, e)) > 0) + { + if (memchr (zline, '\0', (size_t) clen) != NULL) + { + int ifree; + + /* A null character means this is probably a + binary file. */ + for (ifree = istdin; ifree < i; ifree++) + ubuffree ((char *) pz[ifree]); + i = istdin - 1; + break; + } + ++clines; + if (clines > cstdin) + break; + if (i >= cgot) + { + cgot += 20; + pz = (const char **) xrealloc ((pointer) pz, + (cgot + * sizeof (char *))); + } + pz[i++] = zbufcpy (zline); + } + xfree ((pointer) zline); + (void) fclose (e); + } + } + + ubuffree (zfile); + } + + if (fkilled) + zsubject = "UUCP job killed"; + else + zsubject = "UUCP notification"; + + fret = TRUE; + + if ((icmd & JOB_MAIL) != 0) + { + if (! fsysdep_mail (OWNER, zsubject, i, pz)) + fret = FALSE; + } + + if ((icmd & JOB_NOTIFY) != 0 + && (zrequestor != NULL || zuser != NULL)) + { + const char *zmail; + char *zfree; + + if (zrequestor != NULL) + zmail = zrequestor; + else + zmail = zuser; + + zfree = NULL; + + if (zid == NULL) + { + int iuuconf; + const char *zloc; + + /* This is an execution request, which may be from another + system. If it is, we must prepend that system name to + the user name extracted from the X. file. */ + iuuconf = uuconf_localname (puuconf, &zloc); + if (iuuconf == UUCONF_NOT_FOUND) + { + zloc = zsysdep_localname (); + if (zloc == NULL) + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + if (strcmp (qsys->uuconf_zname, zloc) != 0 +#if HAVE_INTERNET_MAIL + && strchr (zmail, '@') == NULL +#endif + ) + { + zfree = zbufalc (strlen (qsys->uuconf_zname) + + strlen (zmail) + + sizeof "!"); + sprintf (zfree, "%s!%s", qsys->uuconf_zname, zmail); + zmail = zfree; + } + } + + if (! fsysdep_mail (zmail, zsubject, i, pz)) + fret = FALSE; + + ubuffree (zfree); + } + + while (istdin < i) + { + ubuffree ((char *) pz[istdin]); + istdin++; + } + + xfree ((pointer) pz); + + return fret; +} + +/* Handle the -q option. For each remote system this lists the number + of jobs queued, the number of executions queued, and the current + call status. We get the executions all at once, because they are + not accessed by system. They could be, but it is possible to have + executions pending for an unknown system, so special handling would + still be required. */ + +struct sxqtlist +{ + struct sxqtlist *qnext; + char *zsystem; + int cxqts; + long ifirst; +}; + +/* These local functions need the definition of sxqtlist for the + prototype. */ + +static boolean fsquery_system P((const struct uuconf_system *qsys, + struct sxqtlist **pq, + long inow, const char *zlocalname)); +static boolean fsquery_show P((const struct uuconf_system *qsys, int cwork, + long ifirstwork, + struct sxqtlist *qxqt, + long inow, const char *zlocalname)); + +static boolean +fsquery (puuconf) + pointer puuconf; +{ + int iuuconf; + const char *zlocalname; + struct sxqtlist *qlist; + char *zfile, *zsystem; + boolean ferr; + long inow; + char **pznames, **pz; + boolean fret; + + iuuconf = uuconf_localname (puuconf, &zlocalname); + if (iuuconf == UUCONF_NOT_FOUND) + { + zlocalname = zsysdep_localname (); + if (zlocalname == NULL) + return FALSE; + } + else if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + /* Get a count of all the execution files. */ + if (! fsysdep_get_xqt_init ()) + return FALSE; + + qlist = NULL; + while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL) + { + struct sxqtlist *qlook; + + for (qlook = qlist; qlook != NULL; qlook = qlook->qnext) + if (strcmp (zsystem, qlook->zsystem) == 0) + break; + + if (qlook != NULL) + { + long itime; + + ubuffree (zsystem); + ++qlook->cxqts; + itime = ixsysdep_file_time (zfile); + if (itime < qlook->ifirst) + qlook->ifirst = itime; + } + else + { + struct sxqtlist *qnew; + + qnew = (struct sxqtlist *) xmalloc (sizeof (struct sxqtlist)); + qnew->qnext = qlist; + qnew->zsystem = zsystem; + qnew->cxqts = 1; + qnew->ifirst = ixsysdep_file_time (zfile); + qlist = qnew; + } + + ubuffree (zfile); + } + + usysdep_get_xqt_free (); + + if (ferr) + return FALSE; + + inow = ixsysdep_time ((long *) NULL); + + /* Show the information for each system. */ + iuuconf = uuconf_system_names (puuconf, &pznames, 0); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return FALSE; + } + + fret = TRUE; + + for (pz = pznames; *pz != NULL; pz++) + { + struct uuconf_system ssys; + + iuuconf = uuconf_system_info (puuconf, *pz, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + continue; + } + + if (! fsquery_system (&ssys, &qlist, inow, zlocalname)) + fret = FALSE; + + (void) uuconf_system_free (puuconf, &ssys); + xfree ((pointer) *pz); + } + + /* Check for the local system in the list of execution files. */ + if (qlist != NULL) + { + struct sxqtlist **pq; + + for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) + { + if (strcmp ((*pq)->zsystem, zlocalname) == 0) + { + struct uuconf_system ssys; + struct sxqtlist *qfree; + + iuuconf = uuconf_system_info (puuconf, zlocalname, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + break; + } + + iuuconf = uuconf_system_local (puuconf, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + fret = FALSE; + break; + } + ssys.uuconf_zname = (char *) zlocalname; + } + + if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname)) + fret = FALSE; + (void) uuconf_system_free (puuconf, &ssys); + qfree = *pq; + *pq = qfree->qnext; + ubuffree (qfree->zsystem); + xfree ((pointer) qfree); + break; + } + } + } + + /* Print out information for any unknown systems for which we have + execution files. */ + while (qlist != NULL) + { + struct uuconf_system ssys; + struct sxqtlist *qnext; + + if (! funknown_system (puuconf, qlist->zsystem, &ssys)) + { + ulog (LOG_ERROR, "Executions queued up for unknown systems"); + fret = FALSE; + break; + } + + if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname)) + fret = FALSE; + (void) uuconf_system_free (puuconf, &ssys); + qnext = qlist->qnext; + ubuffree (qlist->zsystem); + xfree ((pointer) qlist); + qlist = qnext; + } + + return fret; +} + +/* Query a single known system. */ + +static boolean +fsquery_system (qsys, pq, inow, zlocalname) + const struct uuconf_system *qsys; + struct sxqtlist **pq; + long inow; + const char *zlocalname; +{ + int cwork; + long ifirstwork; + char *zid; + boolean fret; + + if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) + return FALSE; + + cwork = 0; + ifirstwork = 0L; + zid = NULL; + while (TRUE) + { + struct scmd s; + long itime; + char *zthisid; + + if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) + return FALSE; + if (s.bcmd == 'H') + break; + + zthisid = zsysdep_jobid (qsys, s.pseq); + if (zid != NULL && strcmp (zid, zthisid) == 0) + ubuffree (zthisid); + else + { + ++cwork; + ubuffree (zid); + zid = zthisid; + } + + itime = ixsysdep_work_time (qsys, s.pseq); + if (ifirstwork == 0L || ifirstwork > itime) + ifirstwork = itime; + } + + usysdep_get_work_free (qsys); + ubuffree (zid); + + /* Find the execution information, if any. */ + while (*pq != NULL) + { + if (strcmp ((*pq)->zsystem, qsys->uuconf_zname) == 0) + break; + pq = &(*pq)->qnext; + } + + /* If there are no commands and no executions, don't print any + information for this system. */ + if (cwork == 0 && *pq == NULL) + return TRUE; + + fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow, zlocalname); + + if (*pq != NULL) + { + struct sxqtlist *qfree; + + qfree = *pq; + *pq = qfree->qnext; + ubuffree (qfree->zsystem); + xfree ((pointer) qfree); + } + + return fret; +} + +/* Print out the query information for a single system. We handle the + local system specially. */ + +static boolean +fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname) + const struct uuconf_system *qsys; + int cwork; + long ifirstwork; + struct sxqtlist *qxqt; + long inow; + const char *zlocalname; +{ + boolean flocal; + struct sstatus sstat; + boolean fnostatus; + struct tm stime; + int cpad; + + flocal = strcmp (qsys->uuconf_zname, zlocalname) == 0; + + if (! flocal) + { + if (! fsysdep_get_status (qsys, &sstat, &fnostatus)) + return FALSE; + } + + printf ("%-10s %3dC (", qsys->uuconf_zname, cwork); + + if (cwork == 0) + { + printf ("0 secs"); + cpad = 3; + } + else + cpad = csunits_show (inow - ifirstwork); + + printf (") "); + while (cpad-- != 0) + printf (" "); + + if (qxqt == NULL) + printf (" 0X (0 secs) "); + else + { + printf ("%3dX (", qxqt->cxqts); + cpad = csunits_show (inow - qxqt->ifirst); + printf (")"); + while (cpad-- != 0) + printf (" "); + } + + if (flocal || fnostatus) + { + printf ("\n"); + return TRUE; + } + + usysdep_localtime (sstat.ilast, &stime); + + printf (" %02d-%02d %02d:%02d ", + stime.tm_mon + 1,stime.tm_mday, stime.tm_hour, stime.tm_min); + + printf ("%s\n", azStatus[(int) sstat.ttype]); + + return TRUE; +} + +/* Print a time difference in the largest applicable units. */ + +static int +csunits_show (idiff) + long idiff; +{ + const char *zunit; + long iunits; + int cpad; + + if (idiff > (long) 24 * (long) 60 * (long) 60) + { + iunits = idiff / ((long) 24 * (long) 60 * (long) 60); + zunit = "day"; + cpad = 4; + } + else if (idiff > (long) 60 * 60) + { + iunits = idiff / (long) (60 * 60); + zunit = "hour"; + cpad = 3; + } + else if (idiff > (long) 60) + { + iunits = idiff / (long) 60; + zunit = "min"; + cpad = 4; + } + else + { + iunits = idiff; + zunit = "sec"; + cpad = 4; + } + + printf ("%ld %s%s", iunits, zunit, iunits == 1 ? "" : "s"); + + if (iunits != 1) + --cpad; + if (iunits > 99) + --cpad; + if (iunits > 9) + --cpad; + return cpad; +} + +/* Give a list of all status entries for all machines that we have + status entries for. We need to get a list of status entries in a + system dependent fashion, since we may have status for unknown + systems. */ + +static boolean +fsmachines () +{ + pointer phold; + char *zsystem; + boolean ferr; + struct sstatus sstat; + + if (! fsysdep_all_status_init (&phold)) + return FALSE; + + while ((zsystem = zsysdep_all_status (phold, &ferr, &sstat)) != NULL) + { + struct tm stime; + + usysdep_localtime (sstat.ilast, &stime); + printf ("%-14s %02d-%02d %02d:%02d %s", zsystem, + stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, + stime.tm_min, azStatus[(int) sstat.ttype]); + ubuffree (zsystem); + if (sstat.ttype != STATUS_TALKING + && sstat.cwait > 0) + { + printf (" (%d %s", sstat.cretries, + sstat.cretries == 1 ? "try" : "tries"); + if (sstat.ilast + sstat.cwait > ixsysdep_time ((long *) NULL)) + { + usysdep_localtime (sstat.ilast + sstat.cwait, &stime); + printf (", next after %02d-%02d %02d:%02d", + stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, + stime.tm_min); + } + printf (")"); + } + printf ("\n"); + } + + usysdep_all_status_free (phold); + + return ! ferr; +} diff --git a/gnu/libexec/uucp/uuto/Makefile b/gnu/libexec/uucp/uuto/Makefile new file mode 100644 index 0000000000..7caef8f0a9 --- /dev/null +++ b/gnu/libexec/uucp/uuto/Makefile @@ -0,0 +1,15 @@ +# Makefile for uuto +# $Id: Makefile,v 1.2 1993/08/05 16:14:06 jtc Exp $ + +BINDIR= $(bindir) + +PROG= uuto +SRCS= +NOMAN= +STRIP= + +uuto: uuto.in + sed -e "s|@BINDIR@|$(bindir)|g" -e "s|@SBINDIR@|$(sbindir)|g" \ + $(.CURDIR)/uuto.in > $(.TARGET) + +.include diff --git a/gnu/libexec/uucp/uuto/uuto.in b/gnu/libexec/uucp/uuto/uuto.in new file mode 100644 index 0000000000..2d7d96a958 --- /dev/null +++ b/gnu/libexec/uucp/uuto/uuto.in @@ -0,0 +1,16 @@ +: +# uuto +# Send files to a user on another system. +# +# Copyright (C) 1992 Ian Lance Taylor +# +# Please feel free do whatever you like with this exciting shell +# script. +# +# This is pretty trivial, since all the functionality was moved into +# uucp itself. The -t means to interpret the final argument as +# system!user, the -R means to copy directories recursively, and the +# -c means to not copy the files to the spool directory (may be +# overriden by -C or -p). +# +@BINDIR@/uucp -t -R -c $* diff --git a/gnu/libexec/uucp/uux/Makefile b/gnu/libexec/uucp/uux/Makefile new file mode 100644 index 0000000000..8f1cb4ef63 --- /dev/null +++ b/gnu/libexec/uucp/uux/Makefile @@ -0,0 +1,16 @@ +# Makefile for uux +# $Id: Makefile,v 1.2 1993/08/05 16:15:25 jtc Exp $ + +BINDIR= $(bindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uux +SRCS= uux.c util.c log.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uux/uux.1 b/gnu/libexec/uucp/uux/uux.1 new file mode 100644 index 0000000000..69c85abb51 --- /dev/null +++ b/gnu/libexec/uucp/uux/uux.1 @@ -0,0 +1,234 @@ +''' $Id: uux.1,v 1.1 1993/08/04 19:37:13 jtc Exp $ +.TH uux 1 "Taylor UUCP 1.04" +.SH NAME +uux \- Remote command execution over UUCP +.SH SYNOPSIS +.B uux +[ options ] command +.SH DESCRIPTION +The +.I uux +command is used to execute a command on a remote system, or to execute +a command on the local system using files from remote systems. +The command +is not executed immediately; the request is queued until the +.I uucico +(8) daemon calls the system and executes it. The daemon is +started automatically unless the +.B \-r +switch is given. + +The actual command execution is done by the +.I uuxqt +(8) daemon. + +File arguments can be gathered from remote systems to the execution +system, as can standard input. Standard output may be directed to a +file on a remote system. + +The command name may be preceded by a system name followed by an +exclamation point if it is to be executed on a remote system. An +empty system name is taken as the local system. + +Each argument that contains an exclamation point is treated as naming +a file. The system which the file is on is before the exclamation +point, and the pathname on that system follows it. An empty system +name is taken as the local system; this must be used to transfer a +file to a command being executed on a remote system. If the path is +not absolute, it will be appended to the current working directory on +the local system; the result may not be meaningful on the remote +system. A pathname may begin with ~/, in which case it is relative to +the UUCP public directory (usually /usr/spool/uucppublic) on the +appropriate system. A pathname may begin with ~name/, in which case +it is relative to the home directory of the named user on the +appropriate system. + +Standard input and output may be redirected as usual; the pathnames +used may contain exclamation points to indicate that they are on +remote systems. Note that the redirection characters must be quoted +so that they are passed to +.I uux +rather than interpreted by the shell. Append redirection (>>) does +not work. + +All specified files are gathered together into a single directory +before execution of the command begins. This means that each file +must have a distinct base name. For example, +.EX +uux 'sys1!diff sys2!~user1/foo sys3!~user2/foo >!foo.diff' +.EE +will fail because both files will be copied to sys1 and stored under +the name foo. + +Arguments may be quoted by parentheses to avoid interpretation of +exclamation points. This is useful when executing the +.I uucp +command on a remote system. +.SH OPTIONS +The following options may be given to +.I uux. +.TP 5 +.B \-,\-p +Read standard input and use it as the standard input for the command +to be executed. +.TP 5 +.B \-c +Do not copy local files to the spool directory. This is the default. +If they are +removed before being processed by the +.I uucico +(8) daemon, the copy will fail. The files must be readable by the +.I uucico +(8) daemon, +as well as the by the invoker of +.I uux. +.TP 5 +.B \-C +Copy local files to the spool directory. +.TP 5 +.B \-l +Link local files into the spool directory. If a file can not be +linked because it is on a different device, it will be copied unless +the +.B \-c +option also appears (in other words, use of +.B \-l +switches the default from +.B \-c +to +.B \-C). +If the files are changed before being processed by the +.I uucico +(8) daemon, the changed versions will be used. The files must be +readable by the +.I uucico +(8) daemon, as well as by the invoker of +.I uux. +.TP 5 +.B \-g grade +Set the grade of the file transfer command. Jobs of a higher grade +are executed first. Grades run 0 ... 9 A ... Z a ... z from high to +low. +.TP 5 +.B \-n +Do not send mail about the status of the job, even if it fails. +.TP 5 +.B \-z +Send mail about the status of the job if an error occurs. For many +.I uuxqt +daemons, including the Taylor UUCP +.I uuxqt, +this is the default action; for those, +.B \-z +will have no effect. However, some +.I uuxqt +daemons will send mail if the job succeeds unless the +.B \-z +option is used, and some other +.I uuxqt +daemons will not send mail if the job fails unless the +.B \-z +option is used. +.TP 5 +.B \-r +Do not start the +.I uucico +(8) daemon immediately; merely queue up the execution request for later +processing. +.TP 5 +.B \-j +Print jobids on standard output. A jobid will be generated for each +file copy operation required to perform the operation. These file +copies may be cancelled by +passing the jobid to the +.B \-k +switch of +.I uustat +(1), which will make the execution impossible to complete. +.TP 5 +.B \-a address +Report job status to the specified e-mail address. +.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, config, +spooldir and execute are meaningful for +.I uux. + +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. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I uux +was compiled. +.SH EXAMPLES +.EX +uux -z - sys1!rmail user1 +.EE +Execute the command ``rmail user1'' on the system sys1, giving it as +standard input whatever is given to +.I uux +as standard input. If a failure occurs, send a message using +.I mail +(1). +.EX +uux 'diff -c sys1!~user1/file1 sys2!~user2/file2 >!file.diff' +.EE +Fetch the two named files from system sys1 and system sys2 and execute +.I diff +putting the result in file.diff in the current directory. The current +directory must be writable by the +.I uuxqt +(8) daemon for this to work. +.EX +uux 'sys1!uucp ~user1/file1 (sys2!~user2/file2)' +.EE +Execute +.I uucp +on the system sys1 copying file1 (on system sys1) to sys2. This +illustrates the use of parentheses for quoting. +.SH RESTRICTIONS +The remote system may not permit you to execute certain commands. +Many remote systems only permit the execution of +.I rmail +and +.I rnews. + +Some of the options are dependent on the capabilities of the +.I uuxqt +(8) daemon on the remote system. +.SH FILES +The file names may be changed at compilation time or by the +configuration file, so these are only approximations. + +.br +/usr/lib/uucp/config - Configuration file. +.br +/usr/spool/uucp - +UUCP spool directory. +.br +/usr/spool/uucp/Log - +UUCP log file. +.br +/usr/spool/uucppublic - +Default UUCP public directory. +.SH SEE ALSO +mail(1), uustat(1), uucp(1), uucico(8), uuxqt(8) +.SH BUGS +Files can not be referenced across multiple systems. + +Too many jobids are output by +.B \-j, +and there is no good way to cancel a local execution requiring remote +files. +.SH AUTHOR +Ian Lance Taylor +(ian@airs.com or uunet!airs!ian) diff --git a/gnu/libexec/uucp/uux/uux.c b/gnu/libexec/uucp/uux/uux.c new file mode 100644 index 0000000000..5dc9866148 --- /dev/null +++ b/gnu/libexec/uucp/uux/uux.c @@ -0,0 +1,1502 @@ +/* uux.c + Prepare to execute a command on a remote 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" + +#if USE_RCS_ID +const char uux_rcsid[] = "$Id: uux.c,v 1.1 1993/08/04 19:37:14 jtc Exp $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" +#include "sysdep.h" +#include "getopt.h" + +#include +#include + +/* These character lists should, perhaps, be in sysdep.h. */ + +/* This is the list of shell metacharacters that we check for. If one + of these is present, we request uuxqt to execute the command with + /bin/sh. Otherwise we let it execute using execve. */ + +#define ZSHELLCHARS "\"'`*?[;&()|<>\\$" + +/* This is the list of word separators. We break filename arguments + at these characters. */ +#define ZSHELLSEPS ";&*|<> \t" + +/* This is the list of word separators without the redirection + operators. */ +#define ZSHELLNONREDIRSEPS ";&*| \t" + +/* The program name. */ +char abProgram[] = "uux"; + +/* The name of the execute file. */ +const char *zXxqt_name; + +/* The execute file we are creating. */ +static FILE *eXxqt_file; + +/* A list of commands to be spooled. */ +static struct scmd *pasXcmds; +static int cXcmds; + +/* A file to close if we're forced to exit. */ +static FILE *eXclose; + +/* Local functions. */ +static void uxusage P((void)); +static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2)); +static void uxadd_send_file P((const char *zfrom, const char *zto, + const char *zoptions, const char *ztemp, + const char *zforward, + const struct uuconf_system *qxqtsys, + const char *zxqtloc, + int bgrade)); +static void uxcopy_stdin P((FILE *e)); +static void uxrecord_file P((const char *zfile)); +static void uxabort P((void)); + +/* Long getopt options. */ +static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } }; + +/* The main routine. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + /* -a: requestor address for status reports. */ + const char *zrequestor = NULL; + /* -b: if true, return standard input on error. */ + boolean fretstdin = FALSE; + /* -c,-C: if true, copy to spool directory. */ + boolean fcopy = FALSE; + /* -c: set if -c appears explicitly; if it and -l appear, then if the + link fails we don't copy the file. */ + boolean fdontcopy = FALSE; + /* -I: configuration file name. */ + const char *zconfig = NULL; + /* -j: output job id. */ + boolean fjobid = FALSE; + /* -g: job grade. */ + char bgrade = BDEFAULT_UUX_GRADE; + /* -l: link file to spool directory. */ + boolean flink = FALSE; + /* -n: do not notify upon command completion. */ + boolean fno_ack = FALSE; + /* -p: read standard input for command standard input. */ + boolean fread_stdin = FALSE; + /* -r: do not start uucico when finished. */ + boolean fuucico = TRUE; + /* -s: report status to named file. */ + const char *zstatus_file = NULL; + /* -W: only expand local file names. */ + boolean fexpand = TRUE; + /* -z: report status only on error. */ + boolean ferror_ack = FALSE; + int iopt; + pointer puuconf; + int iuuconf; + const char *zlocalname; + const char *zxqtloc; + int i; + size_t clen; + char *zargs; + char *zarg; + char *zcmd; + const char *zsys; + char *zexclam; + boolean fgetcwd; + const char *zuser; + struct uuconf_system sxqtsys; + boolean fxqtlocal; + char *zforward; + char **pzargs; + int calloc_args; + int cargs; + char abxqt_tname[CFILE_NAME_LEN]; + char abxqt_xname[CFILE_NAME_LEN]; + const char *zinput_from; + const char *zinput_to; + const char *zinput_temp; + boolean finputcopied; + char *zcall_system; + boolean fcall_any; + struct uuconf_system slocalsys; + boolean fneedshell; + char *zfullcmd; + boolean fexit; + + /* We need to be able to read a single - as an option, which getopt + won't do. So that we can still use getopt, we run through the + options looking for an option "-"; if we find one we change it to + "-p", which is equivalent to "-". */ + for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + break; + if (argv[i][1] == '\0') + argv[i] = zbufcpy ("-p"); + else + { + const char *z; + + for (z = argv[i] + 1; *z != '\0'; z++) + { + /* If the option takes an argument, and the argument is + not appended, then skip the next argument. */ + if (*z == 'a' || *z == 'g' || *z == 'I' + || *z == 's' || *z == 'x') + { + if (z[1] == '\0') + i++; + break; + } + } + } + } + + /* The leading + in the getopt string means to stop processing + options as soon as a non-option argument is seen. */ + while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wx:z", + asXlongopts, (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'a': + /* Set requestor name: mail address to which status reports + should be sent. */ + zrequestor = optarg; + break; + + case 'b': + /* Return standard input on error. */ + fretstdin = TRUE; + break; + + case 'c': + /* Do not copy local files to spool directory. */ + fcopy = FALSE; + fdontcopy = TRUE; + break; + + case 'C': + /* Copy local files to spool directory. */ + fcopy = TRUE; + break; + + case 'I': + /* Configuration file name. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 'j': + /* Output jobid. */ + fjobid = TRUE; + break; + + case 'g': + /* Set job grade. */ + bgrade = optarg[0]; + break; + + case 'l': + /* Link file to spool directory. */ + flink = TRUE; + break; + + case 'n': + /* Do not notify upon command completion. */ + fno_ack = TRUE; + break; + + case 'p': + /* Read standard input for command standard input. */ + fread_stdin = TRUE; + break; + + case 'r': + /* Do not start uucico when finished. */ + fuucico = FALSE; + break; + + case 's': + /* Report status to named file. */ + zstatus_file = optarg; + break; + + case 'W': + /* Only expand local file names. */ + fexpand = FALSE; + break; + + case 'x': +#if DEBUG > 1 + /* Set debugging level. */ + iDebug |= idebug_parse (optarg); +#endif + break; + + case 'z': + /* Report status only on error. */ + ferror_ack = TRUE; + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + uxusage (); + break; + } + } + + if (! UUCONF_GRADE_LEGAL (bgrade)) + { + ulog (LOG_ERROR, "Ignoring illegal grade"); + bgrade = BDEFAULT_UUX_GRADE; + } + + if (optind == argc) + uxusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#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 + + /* The command and files arguments could be quoted in any number of + ways, so we split them apart ourselves. We do this before + calling usysdep_initialize because we want to set fgetcwd + correctly. */ + clen = 1; + for (i = optind; i < argc; i++) + clen += strlen (argv[i]) + 1; + + zargs = zbufalc (clen); + *zargs = '\0'; + for (i = optind; i < argc; i++) + { + strcat (zargs, argv[i]); + strcat (zargs, " "); + } + + /* The first argument is the command to execute. */ + clen = strcspn (zargs, ZSHELLSEPS); + zcmd = zbufalc (clen + 1); + strncpy (zcmd, zargs, clen); + zcmd[clen] = '\0'; + zargs += clen; + + /* Split the arguments out into an array. We break the arguments + into alternating sequences of characters not in ZSHELLSEPS + and characters in ZSHELLSEPS. We remove whitespace. We + separate the redirection characters '>' and '<' into their + own arguments to make them easier to process below. */ + calloc_args = 10; + pzargs = (char **) xmalloc (calloc_args * sizeof (char *)); + cargs = 0; + + for (zarg = strtok (zargs, " \t"); + zarg != NULL; + zarg = strtok ((char *) NULL, " \t")) + { + while (*zarg != '\0') + { + if (cargs + 1 >= calloc_args) + { + calloc_args += 10; + pzargs = (char **) xrealloc ((pointer) pzargs, + calloc_args * sizeof (char *)); + } + + clen = strcspn (zarg, ZSHELLSEPS); + if (clen > 0) + { + pzargs[cargs] = zbufalc (clen + 1); + memcpy (pzargs[cargs], zarg, clen); + pzargs[cargs][clen] = '\0'; + ++cargs; + zarg += clen; + } + + /* We deliberately separate '>' and '<' out. */ + if (*zarg != '\0') + { + clen = strspn (zarg, ZSHELLNONREDIRSEPS); + if (clen == 0) + clen = 1; + pzargs[cargs] = zbufalc (clen + 1); + memcpy (pzargs[cargs], zarg, clen); + pzargs[cargs][clen] = '\0'; + ++cargs; + zarg += clen; + } + } + } + + /* Now look through the arguments to see if we are going to need the + current working directory. We don't try to make a precise + determination, just a conservative one. The basic idea is that + we don't want to get the cwd for 'foo!rmail - user' (note that we + don't examine the command itself). */ + fgetcwd = FALSE; + for (i = 0; i < cargs; i++) + { + if (pzargs[i][0] == '(') + continue; + zexclam = strrchr (pzargs[i], '!'); + if (zexclam != NULL && fsysdep_needs_cwd (zexclam + 1)) + { + fgetcwd = TRUE; + break; + } + if ((pzargs[i][0] == '<' || pzargs[i][0] == '>') + && i + 1 < cargs + && strchr (pzargs[i + 1], '!') == NULL + && fsysdep_needs_cwd (pzargs[i + 1])) + { + fgetcwd = TRUE; + break; + } + } + +#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 + + usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0)); + + ulog_fatal_fn (uxabort); + + zuser = zsysdep_login_name (); + + /* Get the local system name. */ + 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); + + /* Get the local system information. */ + iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + iuuconf = uuconf_system_local (puuconf, &slocalsys); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + } + + /* Figure out which system the command is to be executed on. Some + mailers apparently pass local!rmail, so we must explicitly check + for that. */ + zexclam = strchr (zcmd, '!'); + while (zexclam != NULL) + { + *zexclam = '\0'; + if (strcmp (zcmd, zlocalname) == 0) + ; + else if (slocalsys.uuconf_pzalias == NULL) + break; + else + { + char **pzal; + + for (pzal = slocalsys.uuconf_pzalias; *pzal != NULL; pzal++) + if (strcmp (zcmd, *pzal) == 0) + break; + if (*pzal == NULL) + break; + } + zcmd = zexclam + 1; + zexclam = strchr (zcmd, '!'); + } + if (zexclam == NULL) + { + zsys = zlocalname; + fxqtlocal = TRUE; + zforward = NULL; + } + else + { + zsys = zcmd; + zcmd = zexclam + 1; + fxqtlocal = FALSE; + + /* See if we must forward this command through other systems + (e.g. uux a!b!cmd). */ + zexclam = strrchr (zcmd, '!'); + if (zexclam == NULL) + zforward = NULL; + else + { + clen = zexclam - zcmd; + zforward = zbufalc (clen); + memcpy (zforward, zcmd, clen); + zforward[clen] = '\0'; + zcmd = zexclam + 1; + } + } + + if (fxqtlocal) + sxqtsys = slocalsys; + else + { + iuuconf = uuconf_system_info (puuconf, zsys, &sxqtsys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + if (! funknown_system (puuconf, zsys, &sxqtsys)) + ulog (LOG_FATAL, "%s: System not found", zsys); + } + } + + /* Get the local name the remote system know us as. */ + zxqtloc = sxqtsys.uuconf_zlocalname; + if (zxqtloc == NULL) + zxqtloc = zlocalname; + + /* We can send this as an E command if the execution is on a + different, directly connected, system and the only file used is + the standard input and comes from this system. This is true of + the common cases of rmail and rnews. We get an execute file name + here in case we need it. */ + if (fxqtlocal) + zXxqt_name = zsysdep_xqt_file_name (); + else + zXxqt_name = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, TRUE, + abxqt_tname, (char *) NULL, + abxqt_xname); + if (zXxqt_name == NULL) + uxabort (); + + uxrecord_file (zXxqt_name); + + /* Look through the arguments. Any argument containing an + exclamation point character is interpreted as a file name, and is + sent to the appropriate system. */ + zinput_from = NULL; + zinput_to = NULL; + zinput_temp = NULL; + finputcopied = FALSE; + zcall_system = NULL; + fcall_any = FALSE; + + for (i = 0; i < cargs; i++) + { + const char *zsystem; + char *zfile; + char *zforw; + boolean finput, foutput; + boolean flocal, fonxqt; + + /* Check for a parenthesized argument; remove the parentheses + and otherwise ignore it (this is how an exclamation point is + quoted). */ + if (pzargs[i][0] == '(') + { + clen = strlen (pzargs[i]); + if (pzargs[i][clen - 1] != ')') + ulog (LOG_ERROR, "Mismatched parentheses"); + else + pzargs[i][clen - 1] = '\0'; + ++pzargs[i]; + continue; + } + + /* Check whether we are doing a redirection. */ + finput = FALSE; + foutput = FALSE; + if (i + 1 < cargs) + { + if (pzargs[i][0] == '<') + finput = TRUE; + else if (pzargs[i][0] == '>') + foutput = TRUE; + if (finput || foutput) + { + pzargs[i] = NULL; + i++; + } + } + + zexclam = strchr (pzargs[i], '!'); + + /* If there is no exclamation point and no redirection, this + argument is left untouched. */ + if (zexclam == NULL && ! finput && ! foutput) + continue; + + /* Get the system name and file name for this file. */ + if (zexclam == NULL) + { + zsystem = zlocalname; + zfile = pzargs[i]; + flocal = TRUE; + zforw = NULL; + } + else + { + *zexclam = '\0'; + zsystem = pzargs[i]; + if (*zsystem != '\0') + flocal = FALSE; + else + { + zsystem = zlocalname; + flocal = TRUE; + } + zfile = zexclam + 1; + zexclam = strrchr (zfile, '!'); + if (zexclam == NULL) + zforw = NULL; + else + { + if (flocal) + ulog (LOG_FATAL, "!%s: Can't figure out where to get file", + zfile); + *zexclam = '\0'; + zforw = zfile; + zfile = zexclam + 1; + } + } + + /* Check if the file is already on the execution system. */ + if (flocal) + fonxqt = fxqtlocal; + else if (fxqtlocal) + fonxqt = FALSE; + else if (zforward == NULL ? zforw != NULL : zforw == NULL) + fonxqt = FALSE; + else if (zforward != NULL + && zforw != NULL + && strcmp (zforward, zforw) != 0) + fonxqt = FALSE; + else if (strcmp (zsystem, sxqtsys.uuconf_zname) == 0) + fonxqt = TRUE; + else if (sxqtsys.uuconf_pzalias == NULL) + fonxqt = FALSE; + else + { + char **pzal; + + fonxqt = FALSE; + for (pzal = sxqtsys.uuconf_pzalias; *pzal != NULL; pzal++) + { + if (strcmp (zsystem, *pzal) == 0) + { + fonxqt = TRUE; + break; + } + } + } + + /* Turn the file into an absolute path. */ + if (flocal) + zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir); + else if (fexpand) + zfile = zsysdep_add_cwd (zfile); + if (zfile == NULL) + uxabort (); + + /* Check for output redirection. */ + if (foutput) + { + if (flocal) + { + if (! fin_directory_list (zfile, + sxqtsys.uuconf_pzremote_receive, + sxqtsys.uuconf_zpubdir, TRUE, + FALSE, (const char *) NULL)) + ulog (LOG_FATAL, "Not permitted to create %s", zfile); + } + + /* There are various cases of output redirection. + + uux cmd >out: The command is executed on the local + system, and the output file is placed on the local + system (fonxqt is TRUE). + + uux cmd >a!out: The command is executed on the local + system, and the output file is sent to a. + + uux a!cmd >out: The command is executed on a, and the + output file is returned to the local system (flocal + is TRUE). + + uux a!cmd >a!out: The command is executed on a, and the + output file is left on a (fonxqt is TRUE). + + uux a!cmd >b!out: The command is executed on a, and the + output file is sent to b; traditionally, I believe + that b is relative to a, rather than to the local + system. However, this essentially contradicts the + previous two cases, in which the output file is + relative to the local system. + + Now, the cases that we don't handle. + + uux cmd >a!b!out: The command is executed on the local + system, and the output file is sent to b via a. This + requires the local uuxqt to support forwarding of the + output file. + + uux a!b!cmd >out: The command is executed on b, which is + reached via a. Probably the output file is intended + for the local system, in which case the uuxqt on b + must support forwarding of the output file. + + uux a!b!cmd >c!out: Is c relative to b or to the local + system? If it's relative to b this is easy to + handle. Otherwise, we must arrange for the file to + be sent back to the local system and for the local + system to send it on to c. + + There are many variations of the last case. It's not at + all clear to me how they should be handled. */ + if (zforward != NULL || zforw != NULL) + ulog (LOG_FATAL, "May not forward standard output"); + + if (fonxqt) + uxadd_xqt_line ('O', zfile, (const char *) NULL); + else if (flocal) + uxadd_xqt_line ('O', zfile, zxqtloc); + else + uxadd_xqt_line ('O', zfile, zsystem); + pzargs[i] = NULL; + continue; + } + + if (finput) + { + if (fread_stdin) + ulog (LOG_FATAL, "Standard input specified twice"); + pzargs[i] = NULL; + } + + if (flocal) + { + char *zuse; + char *zdata; + char abtname[CFILE_NAME_LEN]; + char abdname[CFILE_NAME_LEN]; + + /* It's a local file. If requested by -C, copy the file to + the spool directory. If requested by -l, link the file + to the spool directory; if the link fails, we copy the + file, unless -c was explictly used. If the execution is + occurring on the local system, we force the copy as well, + because otherwise we would have to have some way to tell + uuxqt not to move the file. If the file is being shipped + to another system, we must set up a transfer request. + First make sure the user has legitimate access, since we + are running setuid. */ + if (! fsysdep_access (zfile)) + uxabort (); + + zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, + abtname, abdname, (char *) NULL); + if (zdata == NULL) + uxabort (); + + if (fcopy || flink || fxqtlocal) + { + boolean fdid; + + uxrecord_file (zdata); + + fdid = FALSE; + if (flink) + { + boolean fworked; + + if (! fsysdep_link (zfile, zdata, &fworked)) + uxabort (); + + if (fworked) + fdid = TRUE; + else if (fdontcopy) + ulog (LOG_FATAL, "%s: Can't link to spool directory", + zfile); + } + + if (! fdid) + { + openfile_t efile; + + efile = esysdep_user_fopen (zfile, TRUE, TRUE); + if (! ffileisopen (efile)) + uxabort (); + if (! fcopy_open_file (efile, zdata, FALSE, TRUE)) + uxabort (); + (void) ffileclose (efile); + } + + zuse = abtname; + } + else + { + /* We don't actually use the spool file name, but we + need a name to use as the destination. */ + ubuffree (zdata); + /* Make sure the daemon can access the file. */ + if (! fsysdep_daemon_access (zfile)) + uxabort (); + if (! fin_directory_list (zfile, sxqtsys.uuconf_pzlocal_send, + sxqtsys.uuconf_zpubdir, TRUE, + TRUE, zuser)) + ulog (LOG_FATAL, "Not permitted to send from %s", + zfile); + + zuse = zfile; + } + + if (fxqtlocal) + { + if (finput) + uxadd_xqt_line ('I', zuse, (char *) NULL); + else + pzargs[i] = zuse; + } + else + { + finputcopied = fcopy || flink; + + if (finput) + { + zinput_from = zuse; + zinput_to = zbufcpy (abdname); + zinput_temp = zbufcpy (abtname); + } + else + { + char *zbase; + + uxadd_send_file (zuse, abdname, + finputcopied ? "C" : "c", + abtname, zforward, &sxqtsys, + zxqtloc, bgrade); + zbase = zsysdep_base_name (zfile); + if (zbase == NULL) + uxabort (); + uxadd_xqt_line ('F', abdname, zbase); + pzargs[i] = zbase; + } + } + } + else if (fonxqt) + { + /* The file is already on the system where the command is to + be executed. */ + if (finput) + uxadd_xqt_line ('I', zfile, (const char *) NULL); + else + pzargs[i] = zfile; + } + else + { + struct uuconf_system sfromsys; + char abtname[CFILE_NAME_LEN]; + struct scmd s; + char *zjobid; + + /* We need to request a remote file. */ + iuuconf = uuconf_system_info (puuconf, zsystem, &sfromsys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + if (! funknown_system (puuconf, zsystem, &sfromsys)) + ulog (LOG_FATAL, "%s: System not found", zsystem); + } + + if (fonxqt) + { + /* The file is already on the system where the command is to + be executed. */ + if (finput) + uxadd_xqt_line ('I', zfile, (const char *) NULL); + else + pzargs[i] = zfile; + } + else + { + char *zdata; + + if (! sfromsys.uuconf_fcall_transfer + && ! sfromsys.uuconf_fcalled_transfer) + ulog (LOG_FATAL, + "Not permitted to transfer files to or from %s", + sfromsys.uuconf_zname); + + if (zforw != NULL) + { + /* This is ``uux cmd a!b!file''. To make this work, + we would have to be able to set up a request to a + to fetch file from b and send it to us. But it + turns out that that will not work, because when a + sends us the file we will put it in a's spool + directory, not the local system spool directory. + So we won't have any way to find it. This is not + a conceptual problem, and it could doubtless be + solved. Please feel free to solve it and send me + the solution. */ + ulog (LOG_FATAL, "File forwarding not supported"); + } + + /* We must request the file from the remote system to + this one. */ + zdata = zsysdep_data_file_name (&slocalsys, zxqtloc, bgrade, + FALSE, abtname, (char *) NULL, + (char *) NULL); + if (zdata == NULL) + uxabort (); + ubuffree (zdata); + + /* Request the file. The special option '9' is a signal + to uucico that it's OK to receive a file into the + spool directory; normally such requests are rejected. + This privilege is easy to abuse. */ + s.bcmd = 'R'; + s.pseq = NULL; + s.zfrom = zfile; + s.zto = zbufcpy (abtname); + s.zuser = zuser; + s.zoptions = "9"; + s.ztemp = ""; + s.imode = 0600; + s.znotify = ""; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + zjobid = zsysdep_spool_commands (&sfromsys, bgrade, 1, &s); + if (zjobid == NULL) + uxabort (); + + if (fjobid) + printf ("%s\n", zjobid); + + ubuffree (zjobid); + + if (fcall_any) + { + ubuffree (zcall_system); + zcall_system = NULL; + } + else + { + fcall_any = TRUE; + zcall_system = zbufcpy (sfromsys.uuconf_zname); + } + + if (fxqtlocal) + { + /* Tell the command execution to wait until the file + has been received, and tell it the real file + name. */ + if (finput) + { + uxadd_xqt_line ('F', abtname, (char *) NULL); + uxadd_xqt_line ('I', abtname, (char *) NULL); + } + else + { + char *zbase; + + zbase = zsysdep_base_name (zfile); + if (zbase == NULL) + uxabort (); + uxadd_xqt_line ('F', abtname, zbase); + pzargs[i] = zbase; + } + } + else + { + char abxtname[CFILE_NAME_LEN]; + char *zbase; + char *zxqt; + FILE *e; + + /* Now we must arrange to forward the file on to the + execution system. We need to get a name to give + the file on the execution system (abxtname). */ + zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, + bgrade, TRUE, abxtname, + (char *) NULL, + (char *) NULL); + if (zdata == NULL) + uxabort (); + ubuffree (zdata); + + zbase = zsysdep_base_name (zfile); + if (zbase == NULL) + uxabort (); + + zxqt = zsysdep_xqt_file_name (); + if (zxqt == NULL) + uxabort (); + e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); + if (e == NULL) + uxabort (); + uxrecord_file (zxqt); + + fprintf (e, "U %s %s\n", zsysdep_login_name (), + zlocalname); + fprintf (e, "F %s %s\n", abtname, zbase); + fprintf (e, "C uucp -C -W -d -g %c %s %s!", bgrade, + zbase, sxqtsys.uuconf_zname); + if (zforward != NULL) + fprintf (e, "%s!", zforward); + fprintf (e, "%s\n", abxtname); + + if (fclose (e) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + + if (finput) + { + uxadd_xqt_line ('F', abxtname, (char *) NULL); + uxadd_xqt_line ('I', abxtname, (char *) NULL); + ubuffree (zbase); + } + else + { + uxadd_xqt_line ('F', abxtname, zbase); + pzargs[i] = zbase; + } + } + } + + (void) uuconf_system_free (puuconf, &sfromsys); + } + } + + /* If standard input is to be read from the stdin of uux, we read it + here into a temporary file and send it to the execute system. */ + if (fread_stdin) + { + char *zdata; + char abtname[CFILE_NAME_LEN]; + char abdname[CFILE_NAME_LEN]; + FILE *e; + + zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, + abtname, abdname, (char *) NULL); + if (zdata == NULL) + uxabort (); + + e = esysdep_fopen (zdata, FALSE, FALSE, TRUE); + if (e == NULL) + uxabort (); + + eXclose = e; + uxrecord_file (zdata); + + uxcopy_stdin (e); + + eXclose = NULL; + if (fclose (e) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + + if (fxqtlocal) + uxadd_xqt_line ('I', abtname, (const char *) NULL); + else + { + zinput_from = zbufcpy (abtname); + zinput_to = zbufcpy (abdname); + zinput_temp = zinput_from; + finputcopied = TRUE; + } + } + + /* If we are returning standard input, or we're putting the status + in a file, we can't use an E command. */ + if (fretstdin) + uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL); + + if (zstatus_file != NULL) + uxadd_xqt_line ('M', zstatus_file, (const char *) NULL); + + /* Get the complete command line, and decide whether the command + needs to be executed by the shell. */ + fneedshell = FALSE; + + if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0') + fneedshell = TRUE; + + clen = strlen (zcmd) + 1; + for (i = 0; i < cargs; i++) + { + if (pzargs[i] != NULL) + { + clen += strlen (pzargs[i]) + 1; + if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0') + fneedshell = TRUE; + } + } + + zfullcmd = zbufalc (clen); + + strcpy (zfullcmd, zcmd); + for (i = 0; i < cargs; i++) + { + if (pzargs[i] != NULL) + { + strcat (zfullcmd, " "); + strcat (zfullcmd, pzargs[i]); + } + } + + /* If we haven't written anything to the execution file yet, and we + have a standard input file, and we're not forwarding, then every + other option can be handled in an E command. */ + if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL) + { + struct scmd s; + char aboptions[10]; + char *zoptions; + + /* Set up an E command. */ + s.bcmd = 'E'; + s.pseq = NULL; + s.zuser = zuser; + s.zfrom = zinput_from; + s.zto = zinput_to; + s.zoptions = aboptions; + zoptions = aboptions; + *zoptions++ = finputcopied ? 'C' : 'c'; + if (fno_ack) + *zoptions++ = 'N'; + if (ferror_ack) + *zoptions++ = 'Z'; + if (zrequestor != NULL) + *zoptions++ = 'R'; + if (fneedshell) + *zoptions++ = 'e'; + *zoptions = '\0'; + s.ztemp = zinput_temp; + s.imode = 0666; + if (zrequestor == NULL) + zrequestor = "\"\""; + s.znotify = zrequestor; + s.cbytes = -1; + s.zcmd = zfullcmd; + s.ipos = 0; + + ++cXcmds; + pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, + cXcmds * sizeof (struct scmd)); + pasXcmds[cXcmds - 1] = s; + } + else + { + /* Finish up the execute file. */ + uxadd_xqt_line ('U', zuser, zxqtloc); + if (zinput_from != NULL) + { + uxadd_xqt_line ('F', zinput_to, (char *) NULL); + uxadd_xqt_line ('I', zinput_to, (char *) NULL); + uxadd_send_file (zinput_from, zinput_to, + finputcopied ? "C" : "c", + zinput_temp, zforward, &sxqtsys, zxqtloc, + bgrade); + } + if (fno_ack) + uxadd_xqt_line ('N', (const char *) NULL, (const char *) NULL); + if (ferror_ack) + uxadd_xqt_line ('Z', (const char *) NULL, (const char *) NULL); + if (zrequestor != NULL) + uxadd_xqt_line ('R', zrequestor, (const char *) NULL); + if (fneedshell) + uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL); + uxadd_xqt_line ('C', zfullcmd, (const char *) NULL); + if (fclose (eXxqt_file) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + eXxqt_file = NULL; + + /* If the execution is to occur on another system, we must now + arrange to copy the execute file to this system. */ + if (! fxqtlocal) + uxadd_send_file (abxqt_tname, abxqt_xname, "C", abxqt_tname, + zforward, &sxqtsys, zxqtloc, bgrade); + } + + /* If we got a signal, get out before spooling anything. */ + if (FGOT_SIGNAL ()) + uxabort (); + + /* From here on in, it's too late. We don't call uxabort. */ + if (cXcmds > 0) + { + char *zjobid; + + if (! sxqtsys.uuconf_fcall_transfer + && ! sxqtsys.uuconf_fcalled_transfer) + ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", + sxqtsys.uuconf_zname); + + zjobid = zsysdep_spool_commands (&sxqtsys, bgrade, cXcmds, pasXcmds); + if (zjobid == NULL) + { + ulog_close (); + usysdep_exit (FALSE); + } + + if (fjobid) + printf ("%s\n", zjobid); + + ubuffree (zjobid); + + if (fcall_any) + { + ubuffree (zcall_system); + zcall_system = NULL; + } + else + { + fcall_any = TRUE; + zcall_system = zbufcpy (sxqtsys.uuconf_zname); + } + } + + /* If all that worked, make a log file entry. All log file reports + up to this point went to stderr. */ + ulog_to_file (puuconf, TRUE); + ulog_system (sxqtsys.uuconf_zname); + ulog_user (zuser); + + ulog (LOG_NORMAL, "Queuing %s", zfullcmd); + + ulog_close (); + + if (! fuucico) + fexit = TRUE; + else + { + if (zcall_system != NULL) + fexit = fsysdep_run ("uucico", "-s", zcall_system); + else if (fcall_any) + fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL); + else + fexit = TRUE; + } + + usysdep_exit (fexit); + + /* Avoid error about not returning a value. */ + return 0; +} + +/* Report command usage. */ + +static void +uxusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uux [options] [-] command\n"); + fprintf (stderr, + " -,-p: Read standard input for standard input of command\n"); + fprintf (stderr, + " -c: Do not copy local files to spool directory (default)\n"); + fprintf (stderr, + " -C: Copy local files to spool directory\n"); + fprintf (stderr, + " -l: link local files to spool directory\n"); + fprintf (stderr, + " -g grade: Set job grade (must be alphabetic)\n"); + fprintf (stderr, + " -n: Do not report completion status\n"); + fprintf (stderr, + " -z: Report completion status only on error\n"); + fprintf (stderr, + " -r: Do not start uucico daemon\n"); + fprintf (stderr, + " -a address: Address to mail status report to\n"); + fprintf (stderr, + " -b: Return standard input with status report\n"); + fprintf (stderr, + " -s file: Report completion status to file\n"); + fprintf (stderr, + " -j: Report job id\n"); + fprintf (stderr, + " -x debug: Set debugging level\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* Add a line to the execute file. */ + +static void +uxadd_xqt_line (bchar, z1, z2) + int bchar; + const char *z1; + const char *z2; +{ + if (eXxqt_file == NULL) + { + eXxqt_file = esysdep_fopen (zXxqt_name, FALSE, FALSE, TRUE); + if (eXxqt_file == NULL) + uxabort (); + } + + if (z1 == NULL) + fprintf (eXxqt_file, "%c\n", bchar); + else if (z2 == NULL) + fprintf (eXxqt_file, "%c %s\n", bchar, z1); + else + fprintf (eXxqt_file, "%c %s %s\n", bchar, z1, z2); +} + +/* Add a file to be sent to the execute system. */ + +static void +uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc, + bgrade) + const char *zfrom; + const char *zto; + const char *zoptions; + const char *ztemp; + const char *zforward; + const struct uuconf_system *qxqtsys; + const char *zxqtloc; + int bgrade; +{ + struct scmd s; + + if (zforward != NULL) + { + char *zbase; + char *zxqt; + char abtname[CFILE_NAME_LEN]; + char abdname[CFILE_NAME_LEN]; + char abxname[CFILE_NAME_LEN]; + FILE *e; + + /* We want to forward this file through the first execution + system to other systems. We set up a remote execution of + uucp to forward the file. */ + zbase = zsysdep_base_name (zfrom); + if (zbase == NULL) + uxabort (); + + zxqt = zsysdep_data_file_name (qxqtsys, zxqtloc, bgrade, TRUE, abtname, + abdname, abxname); + if (zxqt == NULL) + uxabort (); + e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); + if (e == NULL) + uxabort (); + uxrecord_file (zxqt); + + fprintf (e, "U %s %s\n", zsysdep_login_name (), zxqtloc); + fprintf (e, "F %s %s\n", abdname, zbase); + fprintf (e, "C uucp -C -W -d -g %c %s %s!%s\n", + bgrade, zbase, zforward, zto); + + ubuffree (zbase); + + if (fclose (e) != 0) + ulog (LOG_FATAL, "fclose: %s", strerror (errno)); + + /* Send the execution file. */ + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (abtname); + s.zto = zbufcpy (abxname); + s.zuser = zsysdep_login_name (); + s.zoptions = "C"; + s.ztemp = s.zfrom; + s.imode = 0666; + s.znotify = NULL; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ++cXcmds; + pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, + cXcmds * sizeof (struct scmd)); + pasXcmds[cXcmds - 1] = s; + + /* Send the data file to abdname where the execution file will + expect it. */ + zto = abdname; + } + + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = zbufcpy (zfrom); + s.zto = zbufcpy (zto); + s.zuser = zsysdep_login_name (); + s.zoptions = zbufcpy (zoptions); + s.ztemp = zbufcpy (ztemp); + s.imode = 0666; + s.znotify = ""; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ++cXcmds; + pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, + cXcmds * sizeof (struct scmd)); + pasXcmds[cXcmds - 1] = s; +} + +/* Copy stdin to a file. This is a separate function because it may + call setjmp. */ + +static void +uxcopy_stdin (e) + FILE *e; +{ + CATCH_PROTECT size_t cread; + char ab[1024]; + + do + { + size_t cwrite; + + /* I want to use fread here, but there is a bug in some versions + of SVR4 which causes fread to return less than a complete + buffer even if EOF has not been reached. This is not online + time, so speed is not critical, but it's still quite annoying + to have to use an inefficient algorithm. */ + cread = 0; + if (fsysdep_catch ()) + { + usysdep_start_catch (); + + while (cread < sizeof (ab)) + { + int b; + + if (FGOT_SIGNAL ()) + uxabort (); + + /* There's an unimportant race here. If the user hits + ^C between the FGOT_SIGNAL we just did and the time + we enter getchar, we won't know about the signal + (unless we're doing a longjmp, but we normally + aren't). It's not a big problem, because the user + can just hit ^C again. */ + b = getchar (); + if (b == EOF) + break; + ab[cread] = b; + ++cread; + } + } + + usysdep_end_catch (); + + if (FGOT_SIGNAL ()) + uxabort (); + + if (cread > 0) + { + cwrite = fwrite (ab, sizeof (char), cread, e); + if (cwrite != cread) + ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d", + (int) cwrite, (int) cread); + } + } + while (cread == sizeof ab); +} + +/* Keep track of all files we have created so that we can delete them + if we get a signal. The argument will be on the heap. */ + +static int cXfiles; +static const char **pXaz; + +static void +uxrecord_file (zfile) + const char *zfile; +{ + pXaz = (const char **) xrealloc ((pointer) pXaz, + (cXfiles + 1) * sizeof (const char *)); + pXaz[cXfiles] = zfile; + ++cXfiles; +} + +/* Delete all the files we have recorded and exit. */ + +static void +uxabort () +{ + int i; + + if (eXxqt_file != NULL) + (void) fclose (eXxqt_file); + if (eXclose != NULL) + (void) fclose (eXclose); + for (i = 0; i < cXfiles; i++) + (void) remove (pXaz[i]); + ulog_close (); + usysdep_exit (FALSE); +} diff --git a/gnu/libexec/uucp/uuxqt/Makefile b/gnu/libexec/uucp/uuxqt/Makefile new file mode 100644 index 0000000000..ded44bfad8 --- /dev/null +++ b/gnu/libexec/uucp/uuxqt/Makefile @@ -0,0 +1,18 @@ +# Makefile for uuxqt +# $Id: Makefile,v 1.2 1993/08/05 16:15:28 jtc Exp $ + +BINDIR= $(sbindir) +BINOWN= $(owner) +BINMODE= 4555 + +PROG= uuxqt +SRCS= uuxqt.c util.c log.c copy.c +LDADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +DPADD+= $(LIBUNIX) $(LIBUUCONF) $(LIBUUCP) +CFLAGS+= -I$(.CURDIR)/../common_sources\ + -DVERSION=\"$(VERSION)\" + +MAN8= uuxqt.0 + +.include +.PATH: $(.CURDIR)/../common_sources diff --git a/gnu/libexec/uucp/uuxqt/uuxqt.8 b/gnu/libexec/uucp/uuxqt/uuxqt.8 new file mode 100644 index 0000000000..faee1cf7a8 --- /dev/null +++ b/gnu/libexec/uucp/uuxqt/uuxqt.8 @@ -0,0 +1,92 @@ +''' $Id: uuxqt.8,v 1.1 1993/08/04 19:37:18 jtc Exp $ +.TH uuxqt 8 "Taylor UUCP 1.04" +.SH NAME +uuxqt \- UUCP execution daemon +.SH SYNOPSIS +.B uuxqt +[ options ] +.SH DESCRIPTION +The +.I uuxqt +daemon executes commands requested by +.I uux +(1) from either the local system or from remote systems. +It is started automatically by the +.I uucico +(8) daemon (unless +.I uucico +(8) is given the +.B \-q +option). + +There is normally no need to run this command, since it will be +invoked by +.I uucico +(8). However, it can be used to provide greater control over the +processing of the work queue. + +Multiple invocations of +.I uuxqt +may be run at once, as controlled by the +.I max-uuxqts +configuration command. +.SH OPTIONS +The following options may be given to +.I uuxqt. +.TP 5 +.B \-c command +Only execute requests for the specified command. For example: +.EX +uuxqt -c rmail +.EE +.TP 5 +.B \-s system +Only execute requests originating from the specified system. +.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, config, +spooldir and execute are meaningful for +.I uuxqt. + +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. + +The debugging output is sent to the debugging file, usually one of +/usr/spool/uucp/Debug, /usr/spool/uucp/DEBUG, or +/usr/spool/uucp/.Admin/audit.local. +.TP 5 +.B \-I file +Set configuration file to use. This option may not be available, +depending upon how +.I uuxqt +was compiled. +.SH FILES +The file names may be changed at compilation time or by the +configuration file, so these are only approximations. + +.br +/usr/lib/uucp/config - Configuration file. +.br +/usr/spool/uucp - +UUCP spool directory. +.br +/usr/spool/uucp/Log - +UUCP log file. +.br +/usr/spool/uucppublic - +Default UUCP public directory. +.br +/usr/spool/uucp/Debug - +Debugging file. +.SH SEE ALSO +uucp(1), uux(1), uucico(8) +.SH AUTHOR +Ian Lance Taylor +(ian@airs.com or uunet!airs!ian) diff --git a/gnu/libexec/uucp/uuxqt/uuxqt.c b/gnu/libexec/uucp/uuxqt/uuxqt.c new file mode 100644 index 0000000000..919ea7ecd4 --- /dev/null +++ b/gnu/libexec/uucp/uuxqt/uuxqt.c @@ -0,0 +1,1549 @@ +/* uuxqt.c + Run uux commands. + + 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 uuxqt_rcsid[] = "$Id: uuxqt.c,v 1.1 1993/08/04 19:37:19 jtc Exp $"; +#endif + +#include +#include + +#include "getopt.h" + +#include "uudefs.h" +#include "uuconf.h" +#include "system.h" + +/* The program name. */ +char abProgram[] = "uuxqt"; + +/* Static variables used to unlock things if we get a fatal error. */ +static int iQlock_seq = -1; +static const char *zQunlock_cmd; +static const char *zQunlock_file; +static boolean fQunlock_directory; +int cQmaxuuxqts; + +/* Static variables to free in uqcleanup. */ +static char *zQoutput; +static char *zQmail; + +/* Local functions. */ +static void uqusage P((void)); +static void uqabort P((void)); +static void uqdo_xqt_file P((pointer puuconf, const char *zfile, + const char *zbase, + const struct uuconf_system *qsys, + const char *zlocalname, + const char *zcmd, boolean *pfprocessed)); +static void uqcleanup P((const char *zfile, int iflags)); +static boolean fqforward P((const char *zfile, char **pzallowed, + const char *zlog, const char *zmail)); + +/* Long getopt options. */ +static const struct option asQlongopts[] = { { NULL, 0, NULL, 0 } }; + +int +main (argc, argv) + int argc; + char **argv; +{ + /* The type of command to execute (NULL for any type). */ + const char *zcmd = NULL; + /* The configuration file name. */ + const char *zconfig = NULL; + /* The system to execute commands for. */ + const char *zdosys = NULL; + int iopt; + pointer puuconf; + int iuuconf; + const char *zlocalname; + boolean fany; + char *z, *zgetsys; + boolean ferr; + boolean fsys; + struct uuconf_system ssys; + + while ((iopt = getopt_long (argc, argv, "c:I:s:x:", asQlongopts, + (int *) NULL)) != EOF) + { + switch (iopt) + { + case 'c': + /* Set the type of command to execute. */ + zcmd = optarg; + break; + + case 'I': + /* Set the configuration file name. */ + if (fsysdep_other_config (optarg)) + zconfig = optarg; + break; + + case 's': + zdosys = optarg; + break; + + case 'x': +#if DEBUG > 1 + /* Set the debugging level. */ + iDebug |= idebug_parse (optarg); +#endif + break; + + case 0: + /* Long option found and flag set. */ + break; + + default: + uqusage (); + break; + } + } + + if (optind != argc) + uqusage (); + + iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#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 + + iuuconf = uuconf_maxuuxqts (puuconf, &cQmaxuuxqts); + if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + +#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 + + usysdep_initialize (puuconf, INIT_SUID); + + ulog_to_file (puuconf, TRUE); + ulog_fatal_fn (uqabort); + + 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); + + fsys = FALSE; + + /* If we were given a system name, canonicalize it, since the system + dependent layer will not be returning aliases. */ + if (zdosys != NULL) + { + iuuconf = uuconf_system_info (puuconf, zdosys, &ssys); + if (iuuconf == UUCONF_NOT_FOUND) + ulog (LOG_FATAL, "%s: System not found", zdosys); + else if (iuuconf != UUCONF_SUCCESS) + ulog_uuconf (LOG_FATAL, puuconf, iuuconf); + + zdosys = zbufcpy (ssys.uuconf_zname); + fsys = TRUE; + } + + /* Limit the number of uuxqt processes, and make sure we're the only + uuxqt daemon running for this command. */ + iQlock_seq = ixsysdep_lock_uuxqt (zcmd, cQmaxuuxqts); + if (iQlock_seq < 0) + { + ulog_close (); + usysdep_exit (TRUE); + } + zQunlock_cmd = zcmd; + + /* Keep scanning the execute files until we don't process any of + them. */ + do + { + fany = FALSE; + + /* Look for each execute file, and run it. */ + + if (! fsysdep_get_xqt_init ()) + { + ulog_close (); + usysdep_exit (FALSE); + } + + while ((z = zsysdep_get_xqt (&zgetsys, &ferr)) != NULL) + { + const char *zloc; + boolean fprocessed; + char *zbase; + + /* It would be more efficient to pass zdosys down to the + routines which retrieve execute files. */ + if (zdosys != NULL && strcmp (zdosys, zgetsys) != 0) + { + ubuffree (z); + ubuffree (zgetsys); + continue; + } + + if (! fsys || strcmp (ssys.uuconf_zname, zgetsys) != 0) + { + if (fsys) + (void) uuconf_system_free (puuconf, &ssys); + + iuuconf = uuconf_system_info (puuconf, zgetsys, + &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (z); + ubuffree (zgetsys); + continue; + } + else if (strcmp (zgetsys, zlocalname) == 0) + { + iuuconf = uuconf_system_local (puuconf, &ssys); + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + ubuffree (z); + ubuffree (zgetsys); + continue; + } + } + else + { + if (! funknown_system (puuconf, zgetsys, &ssys)) + { + ulog (LOG_ERROR, + "%s: Execute file for unknown system %s", + z, zgetsys); + (void) remove (z); + ubuffree (z); + ubuffree (zgetsys); + continue; + } + } + } + + fsys = TRUE; + } + + /* If we've received a signal, get out of the loop. */ + if (FGOT_SIGNAL ()) + { + ubuffree (z); + ubuffree (zgetsys); + break; + } + + zloc = ssys.uuconf_zlocalname; + if (zloc == NULL) + zloc = zlocalname; + + ulog_system (ssys.uuconf_zname); + zbase = zsysdep_base_name (z); + uqdo_xqt_file (puuconf, z, zbase, &ssys, zloc, zcmd, &fprocessed); + ubuffree (zbase); + ulog_system ((const char *) NULL); + ulog_user ((const char *) NULL); + + if (fprocessed) + fany = TRUE; + ubuffree (z); + ubuffree (zgetsys); + } + + usysdep_get_xqt_free (); + } + while (fany && ! FGOT_SIGNAL ()); + + (void) fsysdep_unlock_uuxqt (iQlock_seq, zcmd, cQmaxuuxqts); + iQlock_seq = -1; + + ulog_close (); + + if (FGOT_SIGNAL ()) + ferr = TRUE; + + usysdep_exit (! ferr); + + /* Avoid errors about not returning a value. */ + return 0; +} + +static void +uqusage () +{ + fprintf (stderr, + "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", + VERSION); + fprintf (stderr, + "Usage: uuxqt [-c cmd] [-I file] [-s system] [-x debug]\n"); + fprintf (stderr, + " -c cmd: Set type of command to execute\n"); + fprintf (stderr, + " -s system: Execute commands only for named system\n"); + fprintf (stderr, + " -x debug: Set debugging level (0 for none, 9 is max)\n"); +#if HAVE_TAYLOR_CONFIG + fprintf (stderr, + " -I file: Set configuration file to use\n"); +#endif /* HAVE_TAYLOR_CONFIG */ + exit (EXIT_FAILURE); +} + +/* This is the abort function called when we get a fatal error. */ + +static void +uqabort () +{ +#if ! HAVE_HDB_LOGGING + /* When using HDB logging, it's a pain to have no system name. */ + ulog_system ((const char *) NULL); +#endif + + ulog_user ((const char *) NULL); + + if (fQunlock_directory) + (void) fsysdep_unlock_uuxqt_dir (iQlock_seq); + + if (zQunlock_file != NULL) + (void) fsysdep_unlock_uuxqt_file (zQunlock_file); + + if (iQlock_seq >= 0) + (void) fsysdep_unlock_uuxqt (iQlock_seq, zQunlock_cmd, cQmaxuuxqts); + + ulog_close (); + + usysdep_exit (FALSE); +} + +/* An execute file is a series of lines. The first character of each + line is a command. The following commands are defined: + + C command-line + I standard-input + O standard-output [ system ] + F required-file filename-to-use + R requestor-address + U user system + Z (acknowledge if command failed; default) + N (no acknowledgement on failure) + n (acknowledge if command succeeded) + B (return command input on error) + e (process with sh) + E (process with exec) + M status-file + # comment + + Unrecognized commands are ignored. We actually do not recognize + the Z command, since it requests default behaviour. We always send + mail on failure, unless the N command appears. We never send mail + on success, unless the n command appears. + + This code does not currently support the B or M commands. */ + +/* Command arguments. */ +static char **azQargs; +/* Command as a complete string. */ +static char *zQcmd; +/* Standard input file name. */ +static char *zQinput; +/* Standard output file name. */ +static char *zQoutfile; +/* Standard output system. */ +static char *zQoutsys; +/* Number of required files. */ +static int cQfiles; +/* Names of required files. */ +static char **azQfiles; +/* Names required files should be renamed to (NULL if original is OK). */ +static char **azQfiles_to; +/* Requestor address (this is where mail should be sent). */ +static char *zQrequestor; +/* User name. */ +static const char *zQuser; +/* System name. */ +static const char *zQsystem; +/* This is set by the N flag, meaning that no acknowledgement should + be mailed on failure. */ +static boolean fQno_ack; +/* This is set by the n flag, meaning that acknowledgement should be + mailed if the command succeeded. */ +static boolean fQsuccess_ack; +/* This is set by the B flag, meaning that command input should be + mailed to the requestor if an error occurred. */ +static boolean fQsend_input; +/* This is set by the E flag, meaning that exec should be used to + execute the command. */ +static boolean fQuse_exec; +/* The status should be copied to this file on the requesting host. */ +static const char *zQstatus_file; +#if ALLOW_SH_EXECUTION +/* This is set by the e flag, meaning that sh should be used to + execute the command. */ +static boolean fQuse_sh; +#endif /* ALLOW_SH_EXECUTION */ + +static int iqcmd P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int iqout P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int iqfile P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int iqrequestor P((pointer puuconf, int argc, char **argv, + pointer pvar, pointer pinfo)); +static int iquser P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); +static int iqset P((pointer puuconf, int argc, char **argv, pointer pvar, + pointer pinfo)); + +static const struct uuconf_cmdtab asQcmds[] = +{ + { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, iqcmd }, + { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zQinput, NULL }, + { "O", UUCONF_CMDTABTYPE_FN | 0, NULL, iqout }, + { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, iqfile }, + { "R", UUCONF_CMDTABTYPE_FN, NULL, iqrequestor }, + { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, iquser }, + { "N", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQno_ack, iqset }, + { "n", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQsuccess_ack, iqset }, + /* Some systems create execution files in which B takes an argument; + I don't know what it means, so I just ignore it. */ + { "B", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsend_input, iqset }, +#if ALLOW_SH_EXECUTION + { "e", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_sh, iqset }, +#endif + { "E", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_exec, iqset }, + { "M", UUCONF_CMDTABTYPE_STRING, (pointer) &zQstatus_file, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Handle the C command: store off the arguments. */ + +/*ARGSUSED*/ +static int +iqcmd (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + int i; + size_t clen; + + if (argc <= 1) + return UUCONF_CMDTABRET_CONTINUE; + + azQargs = (char **) xmalloc (argc * sizeof (char *)); + clen = 0; + for (i = 1; i < argc; i++) + { + azQargs[i - 1] = zbufcpy (argv[i]); + clen += strlen (argv[i]) + 1; + } + azQargs[i - 1] = NULL; + + zQcmd = (char *) xmalloc (clen); + zQcmd[0] = '\0'; + for (i = 1; i < argc - 1; i++) + { + strcat (zQcmd, argv[i]); + strcat (zQcmd, " "); + } + strcat (zQcmd, argv[i]); + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the O command, which may have one or two arguments. */ + +/*ARGSUSED*/ +static int +iqout (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + const char *zbase = (const char *) pinfo; + + if (argc != 2 && argc != 3) + { + ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", + zbase, argv[0]); + return UUCONF_CMDTABRET_CONTINUE; + } + + zQoutfile = zbufcpy (argv[1]); + if (argc == 3) + zQoutsys = zbufcpy (argv[2]); + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the F command, which may have one or two arguments. */ + +/*ARGSUSED*/ +static int +iqfile (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + const char *zbase = (const char *) pinfo; + + if (argc != 2 && argc != 3) + { + ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", + zbase, argv[0]); + return UUCONF_CMDTABRET_CONTINUE; + } + + /* If this file is not in the spool directory, just ignore it. */ + if (! fspool_file (argv[1])) + return UUCONF_CMDTABRET_CONTINUE; + + ++cQfiles; + azQfiles = (char **) xrealloc ((pointer) azQfiles, + cQfiles * sizeof (char *)); + azQfiles_to = (char **) xrealloc ((pointer) azQfiles_to, + cQfiles * sizeof (char *)); + + azQfiles[cQfiles - 1] = zbufcpy (argv[1]); + if (argc == 3) + azQfiles_to[cQfiles - 1] = zbufcpy (argv[2]); + else + azQfiles_to[cQfiles - 1] = NULL; + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the R command, which may have one or two arguments. */ + +/*ARGSUSED*/ +static int +iqrequestor (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + const char *zbase = (const char *) pinfo; + + if (argc != 2 && argc != 3) + { + ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", + zbase, argv[0]); + return UUCONF_CMDTABRET_CONTINUE; + } + + /* We normally have a single argument, which is the ``requestor'' + address, to which we should send any success or error messages. + Apparently the DOS program UUPC sends two arguments, which are + the username and the host. */ + if (argc == 2) + zQrequestor = zbufcpy (argv[1]); + else + { + zQrequestor = zbufalc (strlen (argv[1]) + strlen (argv[2]) + + sizeof "!"); + sprintf (zQrequestor, "%s!%s", argv[2], argv[1]); + } + + return UUCONF_CMDTABRET_CONTINUE; +} + +/* Handle the U command, which takes two arguments. */ + +/*ARGSUSED*/ +static int +iquser (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + zQuser = argv[1]; + zQsystem = argv[2]; + return UUCONF_CMDTABRET_KEEP; +} + +/* Handle various commands which just set boolean variables. */ + +/*ARGSUSED*/ +static int +iqset (puuconf, argc, argv, pvar, pinfo) + pointer puuconf; + int argc; + char **argv; + pointer pvar; + pointer pinfo; +{ + boolean *pf = (boolean *) pvar; + + *pf = TRUE; + return UUCONF_CMDTABRET_CONTINUE; +} + +/* The execution processing does a lot of things that have to be + cleaned up. Rather than try to add the appropriate statements + to each return point, we keep a set of flags indicating what + has to be cleaned up. The actual clean up is done by the + function uqcleanup. */ +#define REMOVE_FILE (01) +#define REMOVE_NEEDED (02) +#define FREE_QINPUT (04) +#define FREE_OUTPUT (010) +#define FREE_MAIL (020) + +/* Process an execute file. The zfile argument is the name of the + execute file. The zbase argument is the base name of zfile. The + qsys argument describes the system it came from. The zcmd argument + is the name of the command we are executing (from the -c option) or + NULL if any command is OK. This sets *pfprocessed to TRUE if the + file is ready to be executed. */ + +static void +uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed) + pointer puuconf; + const char *zfile; + const char *zbase; + const struct uuconf_system *qsys; + const char *zlocalname; + const char *zcmd; + boolean *pfprocessed; +{ + char *zabsolute; + boolean ferr; + FILE *e; + int iuuconf; + int i; + int iclean; + const char *zmail; + char *zoutput; + char *zinput; + char abtemp[CFILE_NAME_LEN]; + char abdata[CFILE_NAME_LEN]; + char *zerror; + struct uuconf_system soutsys; + const struct uuconf_system *qoutsys; + boolean fshell; + size_t clen; + char *zfullcmd; + boolean ftemp; + + *pfprocessed = FALSE; + + e = fopen (zfile, "r"); + if (e == NULL) + return; + + azQargs = NULL; + zQcmd = NULL; + zQinput = NULL; + zQoutfile = NULL; + zQoutsys = NULL; + cQfiles = 0; + azQfiles = NULL; + azQfiles_to = NULL; + zQrequestor = NULL; + zQuser = NULL; + zQsystem = NULL; + fQno_ack = FALSE; + fQsuccess_ack = FALSE; + fQsend_input = FALSE; + fQuse_exec = FALSE; + zQstatus_file = NULL; +#if ALLOW_SH_EXECUTION + fQuse_sh = FALSE; +#endif + + iuuconf = uuconf_cmd_file (puuconf, e, asQcmds, (pointer) zbase, + (uuconf_cmdtabfn) NULL, + UUCONF_CMDTABFLAG_CASE, (pointer) NULL); + (void) fclose (e); + + if (iuuconf != UUCONF_SUCCESS) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + return; + } + + iclean = 0; + + if (azQargs == NULL) + { + ulog (LOG_ERROR, "%s: No command given", zbase); + uqcleanup (zfile, iclean | REMOVE_FILE); + return; + } + + if (zcmd != NULL) + { + if (strcmp (zcmd, azQargs[0]) != 0) + { + uqcleanup (zfile, iclean); + return; + } + } + else + { + /* If there is a lock file for this particular command already, + it means that some other uuxqt is supposed to handle it. */ + if (fsysdep_uuxqt_locked (azQargs[0])) + { + uqcleanup (zfile, iclean); + return; + } + } + + /* Lock this particular file. */ + if (! fsysdep_lock_uuxqt_file (zfile)) + { + uqcleanup (zfile, iclean); + return; + } + + zQunlock_file = zfile; + + /* Now that we have the file locked, make sure it still exists. + Otherwise another uuxqt could have just finished processing it + and removed the lock file. */ + if (! fsysdep_file_exists (zfile)) + { + uqcleanup (zfile, iclean); + return; + } + + if (zQuser != NULL) + ulog_user (zQuser); + else if (zQrequestor != NULL) + ulog_user (zQrequestor); + else + ulog_user ("unknown"); + + /* Make sure that all the required files exist, and get their + full names in the spool directory. */ + for (i = 0; i < cQfiles; i++) + { + char *zreal; + + zreal = zsysdep_spool_file_name (qsys, azQfiles[i], (pointer) NULL); + if (zreal == NULL) + { + uqcleanup (zfile, iclean); + return; + } + if (! fsysdep_file_exists (zreal)) + { + uqcleanup (zfile, iclean); + return; + } + ubuffree (azQfiles[i]); + azQfiles[i] = zbufcpy (zreal); + ubuffree (zreal); + } + + /* Lock the execution directory. */ + if (! fsysdep_lock_uuxqt_dir (iQlock_seq)) + { + ulog (LOG_ERROR, "Could not lock execute directory"); + uqcleanup (zfile, iclean); + return; + } + fQunlock_directory = TRUE; + + iclean |= REMOVE_FILE | REMOVE_NEEDED; + *pfprocessed = TRUE; + + /* Get the address to mail results to. Prepend the system from + which the execute file originated, since mail addresses are + relative to it. */ + zmail = NULL; + if (zQrequestor != NULL) + zmail = zQrequestor; + else if (zQuser != NULL) + zmail = zQuser; + if (zmail != NULL + && zQsystem != NULL +#if HAVE_INTERNET_MAIL + && strchr (zmail, '@') == NULL +#endif + && strcmp (zQsystem, zlocalname) != 0) + { + char *zset; + + zset = zbufalc (strlen (zQsystem) + strlen (zmail) + 2); + sprintf (zset, "%s!%s", zQsystem, zmail); + zmail = zset; + zQmail = zset; + iclean |= FREE_MAIL; + } + + /* The command "uucp" is handled specially. We make sure that the + appropriate forwarding is permitted, and we add a -u argument to + specify the user. */ + if (strcmp (azQargs[0], "uucp") == 0) + { + char *zfrom, *zto; + boolean fmany; + char **azargs; + const char *zuser, *zsystem; + + zfrom = NULL; + zto = NULL; + fmany = FALSE; + + /* Skip all the options, and get the from and to specs. We + don't permit multiple arguments. */ + for (i = 1; azQargs[i] != NULL; i++) + { + if (azQargs[i][0] == '-') + { + char *zopts; + + for (zopts = azQargs[i] + 1; *zopts != '\0'; zopts++) + { + /* The -g, -n, and -s options take an argument. */ + if (*zopts == 'g' || *zopts == 'n' || *zopts == 's') + { + if (zopts[1] == '\0') + ++i; + break; + } + /* The -I, -u and -x options are not permitted. */ + if (*zopts == 'I' || *zopts == 'u' || *zopts == 'x') + { + *zopts = 'r'; + if (zopts[1] != '\0') + zopts[1] = '\0'; + else + { + ++i; + azQargs[i] = zbufcpy ("-r"); + } + break; + } + } + } + else if (zfrom == NULL) + zfrom = azQargs[i]; + else if (zto == NULL) + zto = azQargs[i]; + else + { + fmany = TRUE; + break; + } + } + + /* Add the -u argument. This is required to let uucp do the + correct permissions checking on the file transfer. */ + for (i = 0; azQargs[i] != NULL; i++) + ; + azargs = (char **) xmalloc ((i + 2) * sizeof (char *)); + azargs[0] = azQargs[0]; + zuser = zQuser; + if (zuser == NULL) + zuser = "uucp"; + zsystem = zQsystem; + if (zsystem == NULL) + zsystem = qsys->uuconf_zname; + azargs[1] = zbufalc (strlen (zsystem) + strlen (zuser) + + sizeof "-u!"); + sprintf (azargs[1], "-u%s!%s", zsystem, zuser); + memcpy (azargs + 2, azQargs + 1, i * sizeof (char *)); + xfree ((pointer) azQargs); + azQargs = azargs; + + /* Find the uucp binary. */ + zabsolute = zsysdep_find_command ("uucp", qsys->uuconf_pzcmds, + qsys->uuconf_pzpath, &ferr); + if (zabsolute == NULL && ! ferr) + { + const char *azcmds[2]; + + /* If "uucp" is not a permitted command, then the forwarding + entries must be set. */ + if (! fqforward (zfrom, qsys->uuconf_pzforward_from, "from", zmail) + || ! fqforward (zto, qsys->uuconf_pzforward_to, "to", zmail)) + { + uqcleanup (zfile, iclean); + return; + } + + /* If "uucp" is not a permitted command, then only uucp + requests with a single source are permitted, since that + is all that will be generated by uucp or uux. */ + if (fmany) + { + ulog (LOG_ERROR, "Bad uucp request %s", zQcmd); + + if (zmail != NULL && ! fQno_ack) + { + const char *az[20]; + + i = 0; + az[i++] = "Your execution request failed because it was an"; + az[i++] = " unsupported uucp request.\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + + uqcleanup (zfile, iclean); + return; + } + + azcmds[0] = "uucp"; + azcmds[1] = NULL; + zabsolute = zsysdep_find_command ("uucp", (char **) azcmds, + qsys->uuconf_pzpath, &ferr); + } + if (zabsolute == NULL) + { + if (! ferr) + ulog (LOG_ERROR, "Can't find uucp executable"); + + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + } + else + { + /* Get the pathname to execute. */ + zabsolute = zsysdep_find_command (azQargs[0], qsys->uuconf_pzcmds, + qsys->uuconf_pzpath, + &ferr); + if (zabsolute == NULL) + { + if (ferr) + { + /* If we get an error, try again later. */ + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + + /* Not permitted. Send mail to requestor. */ + ulog (LOG_ERROR, "Not permitted to execute %s", + azQargs[0]); + + if (zmail != NULL && ! fQno_ack) + { + const char *az[20]; + + i = 0; + az[i++] = "Your execution request failed because you are not"; + az[i++] = " permitted to execute\n\t"; + az[i++] = azQargs[0]; + az[i++] = "\non this system.\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + + uqcleanup (zfile, iclean); + return; + } + } + + ubuffree (azQargs[0]); + azQargs[0] = zabsolute; + + for (i = 1; azQargs[i] != NULL; i++) + { + char *zlocal; + + zlocal = zsysdep_xqt_local_file (qsys, azQargs[i]); + if (zlocal != NULL) + { + ubuffree (azQargs[i]); + azQargs[i] = zlocal; + } + } + +#if ! ALLOW_FILENAME_ARGUMENTS + + /* Check all the arguments to make sure they don't try to specify + files they are not permitted to access. */ + for (i = 1; azQargs[i] != NULL; i++) + { + if (! fsysdep_xqt_check_file (qsys, azQargs[i])) + { + if (zmail != NULL && ! fQno_ack) + { + const char *az[20]; + const char *zfailed; + + zfailed = azQargs[i]; + i = 0; + az[i++] = "Your execution request failed because you are not"; + az[i++] = " permitted to refer to file\n\t"; + az[i++] = zfailed; + az[i++] = "\non this system.\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + + uqcleanup (zfile, iclean); + return; + } + } + +#endif /* ! ALLOW_FILENAME_ARGUMENTS */ + + ulog (LOG_NORMAL, "Executing %s (%s)", zbase, zQcmd); + + if (zQinput != NULL) + { + boolean fspool; + char *zreal; + + fspool = fspool_file (zQinput); + if (fspool) + zreal = zsysdep_spool_file_name (qsys, zQinput, (pointer) NULL); + else + zreal = zsysdep_local_file (zQinput, qsys->uuconf_zpubdir); + if (zreal == NULL) + { + /* If we get an error, try again later. */ + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + + zQinput = zreal; + iclean |= FREE_QINPUT; + + if (! fspool + && ! fin_directory_list (zQinput, qsys->uuconf_pzremote_send, + qsys->uuconf_zpubdir, TRUE, TRUE, + (const char *) NULL)) + { + ulog (LOG_ERROR, "Not permitted to read %s", zQinput); + + if (zmail != NULL && ! fQno_ack) + { + const char *az[20]; + + i = 0; + az[i++] = "Your execution request failed because you are"; + az[i++] = " not permitted to read\n\t"; + az[i++] = zQinput; + az[i++] = "\non this system.\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + + uqcleanup (zfile, iclean); + return; + } + } + + zoutput = NULL; + if (zQoutfile == NULL) + qoutsys = NULL; + else if (zQoutsys != NULL + && strcmp (zQoutsys, zlocalname) != 0) + { + char *zdata; + + /* The output file is destined for some other system, so we must + use a temporary file to catch standard output. */ + if (strcmp (zQoutsys, qsys->uuconf_zname) == 0) + qoutsys = qsys; + else + { + iuuconf = uuconf_system_info (puuconf, zQoutsys, &soutsys); + if (iuuconf != UUCONF_SUCCESS) + { + if (iuuconf != UUCONF_NOT_FOUND) + { + ulog_uuconf (LOG_ERROR, puuconf, iuuconf); + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + + if (! funknown_system (puuconf, zQoutsys, &soutsys)) + { + ulog (LOG_ERROR, + "Can't send standard output to unknown system %s", + zQoutsys); + /* We don't send mail to unknown systems, either. + Maybe we should. */ + uqcleanup (zfile, iclean); + return; + } + } + + qoutsys = &soutsys; + } + + zdata = zsysdep_data_file_name (qoutsys, zlocalname, + BDEFAULT_UUX_GRADE, FALSE, abtemp, + abdata, (char *) NULL); + if (zdata == NULL) + { + /* If we get an error, try again later. */ + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + zoutput = zdata; + zQoutput = zoutput; + iclean |= FREE_OUTPUT; + } + else + { + boolean fok; + + qoutsys = NULL; + + /* If we permitted the standard output to be redirected into + the spool directory, people could set up phony commands. */ + if (fspool_file (zQoutfile)) + fok = FALSE; + else + { + zoutput = zsysdep_local_file (zQoutfile, qsys->uuconf_zpubdir); + if (zoutput == NULL) + { + /* If we get an error, try again later. */ + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + ubuffree (zQoutfile); + zQoutfile = zoutput; + + /* Make sure it's OK to receive this file. */ + fok = fin_directory_list (zQoutfile, + qsys->uuconf_pzremote_receive, + qsys->uuconf_zpubdir, TRUE, FALSE, + (const char *) NULL); + } + + if (! fok) + { + ulog (LOG_ERROR, "Not permitted to write to %s", zQoutfile); + + if (zmail != NULL && ! fQno_ack) + { + const char *az[20]; + + i = 0; + az[i++] = "Your execution request failed because you are"; + az[i++] = " not permitted to write to\n\t"; + az[i++] = zQoutfile; + az[i++] = "\non this system.\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + + uqcleanup (zfile, iclean); + return; + } + } + + /* Move the required files to the execution directory if necessary. */ + zinput = zQinput; + if (! fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles, + (const char **) azQfiles_to, + TRUE, iQlock_seq, &zinput)) + { + /* If we get an error, try again later. */ + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + if (zQinput != NULL && strcmp (zQinput, zinput) != 0) + { + if ((iclean & FREE_QINPUT) != 0) + ubuffree (zQinput); + zQinput = zinput; + iclean |= FREE_QINPUT; + } + +#if ALLOW_SH_EXECUTION + fshell = fQuse_sh; +#else + fshell = FALSE; +#endif + + /* Get a shell command which uses the full path of the command to + execute. */ + clen = 0; + for (i = 0; azQargs[i] != NULL; i++) + clen += strlen (azQargs[i]) + 1; + zfullcmd = zbufalc (clen); + strcpy (zfullcmd, azQargs[0]); + for (i = 1; azQargs[i] != NULL; i++) + { + strcat (zfullcmd, " "); + strcat (zfullcmd, azQargs[i]); + } + + if (! fsysdep_execute (qsys, + zQuser == NULL ? (const char *) "uucp" : zQuser, + (const char **) azQargs, zfullcmd, zQinput, + zoutput, fshell, iQlock_seq, &zerror, &ftemp)) + { + ubuffree (zfullcmd); + + if (ftemp) + { + ulog (LOG_NORMAL, "Will retry later (%s)", zbase); + if (zoutput != NULL) + (void) remove (zoutput); + if (zerror != NULL) + { + (void) remove (zerror); + ubuffree (zerror); + } + (void) fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles, + (const char **) azQfiles_to, + FALSE, iQlock_seq, + (char **) NULL); + uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); + *pfprocessed = FALSE; + return; + } + + ulog (LOG_NORMAL, "Execution failed (%s)", zbase); + + if (zmail != NULL && ! fQno_ack) + { + const char **pz; + int cgot; + FILE *eerr; + int istart; + + cgot = 20; + pz = (const char **) xmalloc (cgot * sizeof (const char *)); + i = 0; + pz[i++] = "Execution request failed:\n\t"; + pz[i++] = zQcmd; + pz[i++] = "\n"; + + if (zerror == NULL) + eerr = NULL; + else + eerr = fopen (zerror, "r"); + if (eerr == NULL) + { + pz[i++] = "There was no output on standard error\n"; + istart = i; + } + else + { + char *zline; + size_t cline; + + pz[i++] = "Standard error output was:\n"; + istart = i; + + zline = NULL; + cline = 0; + while (getline (&zline, &cline, eerr) > 0) + { + if (i >= cgot) + { + cgot += 20; + pz = ((const char **) + xrealloc ((pointer) pz, + cgot * sizeof (const char *))); + } + pz[i++] = zbufcpy (zline); + } + + (void) fclose (eerr); + xfree ((pointer) zline); + } + + (void) fsysdep_mail (zmail, "Execution failed", i, pz); + + for (; istart < i; istart++) + ubuffree ((char *) pz[istart]); + xfree ((pointer) pz); + } + + if (qoutsys != NULL) + (void) remove (zoutput); + } + else + { + ubuffree (zfullcmd); + + if (zmail != NULL && fQsuccess_ack) + { + const char *az[20]; + + i = 0; + az[i++] = "\nExecution request succeeded:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution succeded", i, az); + } + + /* Now we may have to uucp the output to some other machine. */ + + if (qoutsys != NULL) + { + struct scmd s; + + /* Fill in the command structure. */ + + s.bcmd = 'S'; + s.pseq = NULL; + s.zfrom = abtemp; + s.zto = zQoutfile; + if (zQuser != NULL) + s.zuser = zQuser; + else + s.zuser = "uucp"; + if (zmail != NULL && fQsuccess_ack) + s.zoptions = "Cn"; + else + s.zoptions = "C"; + s.ztemp = abtemp; + s.imode = 0666; + if (zmail != NULL && fQsuccess_ack) + s.znotify = zmail; + else + s.znotify = ""; + s.cbytes = -1; + s.zcmd = NULL; + s.ipos = 0; + + ubuffree (zsysdep_spool_commands (qoutsys, BDEFAULT_UUX_GRADE, + 1, &s)); + } + } + + if (zerror != NULL) + { + (void) remove (zerror); + ubuffree (zerror); + } + + uqcleanup (zfile, iclean); +} + +/* Clean up the results of uqdo_xqt_file. */ + +static void +uqcleanup (zfile, iflags) + const char *zfile; + int iflags; +{ + int i; + + DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, + "uqcleanup: %s, %d", zfile, iflags); + + if (zQunlock_file != NULL) + { + (void) fsysdep_unlock_uuxqt_file (zQunlock_file); + zQunlock_file = NULL; + } + + if ((iflags & REMOVE_FILE) != 0) + (void) remove (zfile); + + if ((iflags & REMOVE_NEEDED) != 0) + { + for (i = 0; i < cQfiles; i++) + { + if (azQfiles[i] != NULL) + (void) remove (azQfiles[i]); + } + } + + if ((iflags & FREE_QINPUT) != 0) + ubuffree (zQinput); + + if ((iflags & FREE_OUTPUT) != 0) + ubuffree (zQoutput); + if ((iflags & FREE_MAIL) != 0) + ubuffree (zQmail); + + if (fQunlock_directory) + { + (void) fsysdep_unlock_uuxqt_dir (iQlock_seq); + fQunlock_directory = FALSE; + } + + for (i = 0; i < cQfiles; i++) + { + ubuffree (azQfiles[i]); + ubuffree (azQfiles_to[i]); + } + + ubuffree (zQoutfile); + ubuffree (zQoutsys); + ubuffree (zQrequestor); + + if (azQargs != NULL) + { + for (i = 0; azQargs[i] != NULL; i++) + ubuffree (azQargs[i]); + xfree ((pointer) azQargs); + azQargs = NULL; + } + + xfree ((pointer) zQcmd); + zQcmd = NULL; + + xfree ((pointer) azQfiles); + azQfiles = NULL; + + xfree ((pointer) azQfiles_to); + azQfiles_to = NULL; +} + +/* Check whether forwarding is permitted. */ + +static boolean +fqforward (zfile, pzallowed, zlog, zmail) + const char *zfile; + char **pzallowed; + const char *zlog; + const char *zmail; +{ + const char *zexclam; + + zexclam = strchr (zfile, '!'); + if (zexclam != NULL) + { + size_t clen; + char *zsys; + boolean fret; + + clen = zexclam - zfile; + zsys = zbufalc (clen + 1); + memcpy (zsys, zfile, clen); + zsys[clen] = '\0'; + + fret = FALSE; + if (pzallowed != NULL) + { + char **pz; + + for (pz = pzallowed; *pz != NULL; pz++) + { + if (strcmp (*pz, "ANY") == 0 + || strcmp (*pz, zsys) == 0) + { + fret = TRUE; + break; + } + } + } + + if (! fret) + { + ulog (LOG_ERROR, "Not permitted to forward %s %s (%s)", + zlog, zsys, zQcmd); + + if (zmail != NULL && ! fQno_ack) + { + int i; + const char *az[20]; + + i = 0; + az[i++] = "Your execution request failed because you are"; + az[i++] = " not permitted to forward files\n"; + az[i++] = zlog; + az[i++] = " the system\n\t"; + az[i++] = zsys; + az[i++] = "\n"; + az[i++] = "Execution requested was:\n\t"; + az[i++] = zQcmd; + az[i++] = "\n"; + + (void) fsysdep_mail (zmail, "Execution failed", i, az); + } + } + + ubuffree (zsys); + + return fret; + } + + return TRUE; +} -- 2.20.1