summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorconklin <conklin@FreeBSD.org>1993-08-05 18:28:27 +0000
committerconklin <conklin@FreeBSD.org>1993-08-05 18:28:27 +0000
commit9445dd12015987ffafa05df26c1bcd0f39c1dd70 (patch)
tree64cb2831b24d3f5002a9a9ec1426e82c6d6bb5d4
parentf0d11b6bf5fa75bb5f59b57795dcd450a1bf433b (diff)
downloadFreeBSD-src-9445dd12015987ffafa05df26c1bcd0f39c1dd70.zip
FreeBSD-src-9445dd12015987ffafa05df26c1bcd0f39c1dd70.tar.gz
Taylor UUCP 1.04
-rw-r--r--gnu/libexec/uucp/COPYING339
-rw-r--r--gnu/libexec/uucp/ChangeLog3152
-rw-r--r--gnu/libexec/uucp/Makefile8
-rw-r--r--gnu/libexec/uucp/Makefile.inc30
-rw-r--r--gnu/libexec/uucp/README207
-rw-r--r--gnu/libexec/uucp/TODO573
-rw-r--r--gnu/libexec/uucp/VERSION4
-rw-r--r--gnu/libexec/uucp/common_sources/chat.c1429
-rw-r--r--gnu/libexec/uucp/common_sources/conf.h444
-rw-r--r--gnu/libexec/uucp/common_sources/conn.c552
-rw-r--r--gnu/libexec/uucp/common_sources/conn.h312
-rw-r--r--gnu/libexec/uucp/common_sources/copy.c202
-rw-r--r--gnu/libexec/uucp/common_sources/cu.h80
-rw-r--r--gnu/libexec/uucp/common_sources/getopt.h120
-rw-r--r--gnu/libexec/uucp/common_sources/log.c699
-rw-r--r--gnu/libexec/uucp/common_sources/policy.h521
-rw-r--r--gnu/libexec/uucp/common_sources/prot.c237
-rw-r--r--gnu/libexec/uucp/common_sources/prot.h250
-rw-r--r--gnu/libexec/uucp/common_sources/sysdep.h530
-rw-r--r--gnu/libexec/uucp/common_sources/system.h950
-rw-r--r--gnu/libexec/uucp/common_sources/tcp.c470
-rw-r--r--gnu/libexec/uucp/common_sources/tli.c644
-rw-r--r--gnu/libexec/uucp/common_sources/trans.h268
-rw-r--r--gnu/libexec/uucp/common_sources/util.c144
-rw-r--r--gnu/libexec/uucp/common_sources/uuconf.h1496
-rw-r--r--gnu/libexec/uucp/common_sources/uucp.h367
-rw-r--r--gnu/libexec/uucp/common_sources/uudefs.h445
-rw-r--r--gnu/libexec/uucp/contrib/Dial.Hayes108
-rw-r--r--gnu/libexec/uucp/contrib/Hangup.Hayes57
-rw-r--r--gnu/libexec/uucp/contrib/Login.LAT137
-rw-r--r--gnu/libexec/uucp/contrib/Login.PortSel133
-rw-r--r--gnu/libexec/uucp/contrib/Login.VMS96
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.uurt30
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.xchat31
-rw-r--r--gnu/libexec/uucp/contrib/README46
-rw-r--r--gnu/libexec/uucp/contrib/README-UURATE20
-rw-r--r--gnu/libexec/uucp/contrib/README-XCHAT42
-rw-r--r--gnu/libexec/uucp/contrib/savelog.man130
-rwxr-xr-xgnu/libexec/uucp/contrib/savelog.sh247
-rwxr-xr-xgnu/libexec/uucp/contrib/stats.sh27
-rw-r--r--gnu/libexec/uucp/contrib/tstout.c158
-rw-r--r--gnu/libexec/uucp/contrib/uuclean23
-rwxr-xr-xgnu/libexec/uucp/contrib/uuq.sh125
-rw-r--r--gnu/libexec/uucp/contrib/uurate.c657
-rw-r--r--gnu/libexec/uucp/contrib/uurate.man217
-rwxr-xr-xgnu/libexec/uucp/contrib/uureroute91
-rw-r--r--gnu/libexec/uucp/contrib/uusnap.c321
-rw-r--r--gnu/libexec/uucp/contrib/uutraf203
-rw-r--r--gnu/libexec/uucp/contrib/uutry43
-rw-r--r--gnu/libexec/uucp/contrib/xc-conf.h-dist38
-rw-r--r--gnu/libexec/uucp/contrib/xchat.c1444
-rw-r--r--gnu/libexec/uucp/contrib/xchat.man614
-rw-r--r--gnu/libexec/uucp/cu/Makefile16
-rw-r--r--gnu/libexec/uucp/cu/cu.1286
-rw-r--r--gnu/libexec/uucp/cu/cu.c2068
-rw-r--r--gnu/libexec/uucp/libunix/MANIFEST76
-rw-r--r--gnu/libexec/uucp/libunix/Makefile22
-rw-r--r--gnu/libexec/uucp/libunix/access.c83
-rw-r--r--gnu/libexec/uucp/libunix/addbas.c50
-rw-r--r--gnu/libexec/uucp/libunix/app3.c29
-rw-r--r--gnu/libexec/uucp/libunix/app4.c33
-rw-r--r--gnu/libexec/uucp/libunix/basnam.c22
-rw-r--r--gnu/libexec/uucp/libunix/bytfre.c19
-rw-r--r--gnu/libexec/uucp/libunix/chmod.c25
-rw-r--r--gnu/libexec/uucp/libunix/cohtty.c244
-rw-r--r--gnu/libexec/uucp/libunix/cusub.c1163
-rw-r--r--gnu/libexec/uucp/libunix/cwd.c55
-rw-r--r--gnu/libexec/uucp/libunix/detach.c186
-rw-r--r--gnu/libexec/uucp/libunix/dirent.c123
-rw-r--r--gnu/libexec/uucp/libunix/dup2.c69
-rw-r--r--gnu/libexec/uucp/libunix/efopen.c132
-rw-r--r--gnu/libexec/uucp/libunix/epopen.c85
-rw-r--r--gnu/libexec/uucp/libunix/exists.c16
-rw-r--r--gnu/libexec/uucp/libunix/filnam.c376
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.c231
-rw-r--r--gnu/libexec/uucp/libunix/fsusg.h31
-rw-r--r--gnu/libexec/uucp/libunix/ftw.c250
-rw-r--r--gnu/libexec/uucp/libunix/getcwd.c59
-rw-r--r--gnu/libexec/uucp/libunix/indir.c133
-rw-r--r--gnu/libexec/uucp/libunix/init.c394
-rw-r--r--gnu/libexec/uucp/libunix/isdir.c18
-rw-r--r--gnu/libexec/uucp/libunix/isfork.c25
-rw-r--r--gnu/libexec/uucp/libunix/iswait.c159
-rw-r--r--gnu/libexec/uucp/libunix/jobid.c101
-rw-r--r--gnu/libexec/uucp/libunix/lcksys.c41
-rw-r--r--gnu/libexec/uucp/libunix/link.c38
-rw-r--r--gnu/libexec/uucp/libunix/locfil.c95
-rw-r--r--gnu/libexec/uucp/libunix/lock.c477
-rw-r--r--gnu/libexec/uucp/libunix/loctim.c25
-rw-r--r--gnu/libexec/uucp/libunix/mail.c85
-rw-r--r--gnu/libexec/uucp/libunix/mkdir.c58
-rw-r--r--gnu/libexec/uucp/libunix/mkdirs.c49
-rw-r--r--gnu/libexec/uucp/libunix/mode.c33
-rw-r--r--gnu/libexec/uucp/libunix/move.c176
-rw-r--r--gnu/libexec/uucp/libunix/opensr.c244
-rw-r--r--gnu/libexec/uucp/libunix/pause.c96
-rw-r--r--gnu/libexec/uucp/libunix/picksb.c230
-rw-r--r--gnu/libexec/uucp/libunix/portnm.c51
-rw-r--r--gnu/libexec/uucp/libunix/proctm.c197
-rw-r--r--gnu/libexec/uucp/libunix/recep.c197
-rw-r--r--gnu/libexec/uucp/libunix/remove.c13
-rw-r--r--gnu/libexec/uucp/libunix/rename.c27
-rw-r--r--gnu/libexec/uucp/libunix/rmdir.c43
-rw-r--r--gnu/libexec/uucp/libunix/run.c75
-rw-r--r--gnu/libexec/uucp/libunix/seq.c126
-rw-r--r--gnu/libexec/uucp/libunix/serial.c2977
-rw-r--r--gnu/libexec/uucp/libunix/signal.c208
-rw-r--r--gnu/libexec/uucp/libunix/sindir.c26
-rw-r--r--gnu/libexec/uucp/libunix/size.c27
-rw-r--r--gnu/libexec/uucp/libunix/sleep.c14
-rw-r--r--gnu/libexec/uucp/libunix/spawn.c398
-rw-r--r--gnu/libexec/uucp/libunix/splcmd.c115
-rw-r--r--gnu/libexec/uucp/libunix/splnam.c19
-rw-r--r--gnu/libexec/uucp/libunix/spool.c420
-rw-r--r--gnu/libexec/uucp/libunix/srmdir.c112
-rw-r--r--gnu/libexec/uucp/libunix/statsb.c572
-rw-r--r--gnu/libexec/uucp/libunix/status.c212
-rw-r--r--gnu/libexec/uucp/libunix/strerr.c22
-rw-r--r--gnu/libexec/uucp/libunix/time.c32
-rw-r--r--gnu/libexec/uucp/libunix/tmpfil.c83
-rw-r--r--gnu/libexec/uucp/libunix/trunc.c157
-rw-r--r--gnu/libexec/uucp/libunix/uacces.c205
-rw-r--r--gnu/libexec/uucp/libunix/ufopen.c218
-rw-r--r--gnu/libexec/uucp/libunix/ultspl.c21
-rw-r--r--gnu/libexec/uucp/libunix/unknwn.c43
-rw-r--r--gnu/libexec/uucp/libunix/uuto.c31
-rw-r--r--gnu/libexec/uucp/libunix/walk.c59
-rw-r--r--gnu/libexec/uucp/libunix/wldcrd.c212
-rw-r--r--gnu/libexec/uucp/libunix/work.c765
-rw-r--r--gnu/libexec/uucp/libunix/xqtfil.c265
-rw-r--r--gnu/libexec/uucp/libunix/xqtsub.c698
-rw-r--r--gnu/libexec/uucp/libuuconf/COPYING.LIB481
-rw-r--r--gnu/libexec/uucp/libuuconf/MANIFEST92
-rw-r--r--gnu/libexec/uucp/libuuconf/Makefile26
-rw-r--r--gnu/libexec/uucp/libuuconf/README113
-rw-r--r--gnu/libexec/uucp/libuuconf/addblk.c56
-rw-r--r--gnu/libexec/uucp/libuuconf/addstr.c139
-rw-r--r--gnu/libexec/uucp/libuuconf/allblk.c51
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.c82
-rw-r--r--gnu/libexec/uucp/libuuconf/alloc.h71
-rw-r--r--gnu/libexec/uucp/libuuconf/base.c54
-rw-r--r--gnu/libexec/uucp/libuuconf/bool.c64
-rw-r--r--gnu/libexec/uucp/libuuconf/callin.c142
-rw-r--r--gnu/libexec/uucp/libuuconf/calout.c93
-rw-r--r--gnu/libexec/uucp/libuuconf/chatc.c202
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdarg.c185
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdfil.c103
-rw-r--r--gnu/libexec/uucp/libuuconf/cmdlin.c142
-rw-r--r--gnu/libexec/uucp/libuuconf/debfil.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/deblev.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/diacod.c129
-rw-r--r--gnu/libexec/uucp/libuuconf/dial.c61
-rw-r--r--gnu/libexec/uucp/libuuconf/diasub.c63
-rw-r--r--gnu/libexec/uucp/libuuconf/dnams.c103
-rw-r--r--gnu/libexec/uucp/libuuconf/errno.c46
-rw-r--r--gnu/libexec/uucp/libuuconf/errstr.c241
-rw-r--r--gnu/libexec/uucp/libuuconf/filnam.c44
-rw-r--r--gnu/libexec/uucp/libuuconf/freblk.c63
-rw-r--r--gnu/libexec/uucp/libuuconf/fredia.c44
-rw-r--r--gnu/libexec/uucp/libuuconf/free.c68
-rw-r--r--gnu/libexec/uucp/libuuconf/freprt.c44
-rw-r--r--gnu/libexec/uucp/libuuconf/fresys.c44
-rw-r--r--gnu/libexec/uucp/libuuconf/grdcmp.c76
-rw-r--r--gnu/libexec/uucp/libuuconf/hdial.c187
-rw-r--r--gnu/libexec/uucp/libuuconf/hdnams.c109
-rw-r--r--gnu/libexec/uucp/libuuconf/hinit.c295
-rw-r--r--gnu/libexec/uucp/libuuconf/hlocnm.c84
-rw-r--r--gnu/libexec/uucp/libuuconf/hport.c368
-rw-r--r--gnu/libexec/uucp/libuuconf/hrmunk.c55
-rw-r--r--gnu/libexec/uucp/libuuconf/hsinfo.c625
-rw-r--r--gnu/libexec/uucp/libuuconf/hsnams.c142
-rw-r--r--gnu/libexec/uucp/libuuconf/hsys.c49
-rw-r--r--gnu/libexec/uucp/libuuconf/hunk.c142
-rw-r--r--gnu/libexec/uucp/libuuconf/iniglb.c177
-rw-r--r--gnu/libexec/uucp/libuuconf/init.c74
-rw-r--r--gnu/libexec/uucp/libuuconf/int.c59
-rw-r--r--gnu/libexec/uucp/libuuconf/lckdir.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/lineno.c44
-rw-r--r--gnu/libexec/uucp/libuuconf/llocnm.c70
-rw-r--r--gnu/libexec/uucp/libuuconf/local.c70
-rw-r--r--gnu/libexec/uucp/libuuconf/locnm.c46
-rw-r--r--gnu/libexec/uucp/libuuconf/logfil.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/maxuxq.c86
-rw-r--r--gnu/libexec/uucp/libuuconf/mrgblk.c50
-rw-r--r--gnu/libexec/uucp/libuuconf/paramc.c175
-rw-r--r--gnu/libexec/uucp/libuuconf/port.c77
-rw-r--r--gnu/libexec/uucp/libuuconf/prtsub.c54
-rw-r--r--gnu/libexec/uucp/libuuconf/pubdir.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/rdlocs.c305
-rw-r--r--gnu/libexec/uucp/libuuconf/rdperm.c446
-rw-r--r--gnu/libexec/uucp/libuuconf/reliab.c123
-rw-r--r--gnu/libexec/uucp/libuuconf/remunk.c45
-rw-r--r--gnu/libexec/uucp/libuuconf/sinfo.c112
-rw-r--r--gnu/libexec/uucp/libuuconf/snams.c133
-rw-r--r--gnu/libexec/uucp/libuuconf/split.c106
-rw-r--r--gnu/libexec/uucp/libuuconf/spool.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/stafil.c43
-rw-r--r--gnu/libexec/uucp/libuuconf/syshdr.h106
-rw-r--r--gnu/libexec/uucp/libuuconf/syssub.c458
-rw-r--r--gnu/libexec/uucp/libuuconf/tcalou.c201
-rw-r--r--gnu/libexec/uucp/libuuconf/tdial.c227
-rw-r--r--gnu/libexec/uucp/libuuconf/tdialc.c211
-rw-r--r--gnu/libexec/uucp/libuuconf/tdnams.c119
-rw-r--r--gnu/libexec/uucp/libuuconf/tgcmp.c42
-rw-r--r--gnu/libexec/uucp/libuuconf/thread.c70
-rw-r--r--gnu/libexec/uucp/libuuconf/time.c406
-rw-r--r--gnu/libexec/uucp/libuuconf/tinit.c370
-rw-r--r--gnu/libexec/uucp/libuuconf/tlocnm.c112
-rw-r--r--gnu/libexec/uucp/libuuconf/tport.c295
-rw-r--r--gnu/libexec/uucp/libuuconf/tportc.c465
-rw-r--r--gnu/libexec/uucp/libuuconf/tsinfo.c922
-rw-r--r--gnu/libexec/uucp/libuuconf/tsnams.c84
-rw-r--r--gnu/libexec/uucp/libuuconf/tsys.c49
-rw-r--r--gnu/libexec/uucp/libuuconf/tval.c71
-rw-r--r--gnu/libexec/uucp/libuuconf/ugtlin.c110
-rw-r--r--gnu/libexec/uucp/libuuconf/unk.c70
-rw-r--r--gnu/libexec/uucp/libuuconf/uucnfi.h368
-rw-r--r--gnu/libexec/uucp/libuuconf/val.c46
-rw-r--r--gnu/libexec/uucp/libuuconf/vinit.c112
-rw-r--r--gnu/libexec/uucp/libuuconf/vport.c251
-rw-r--r--gnu/libexec/uucp/libuuconf/vsinfo.c575
-rw-r--r--gnu/libexec/uucp/libuuconf/vsnams.c106
-rw-r--r--gnu/libexec/uucp/libuuconf/vsys.c49
-rw-r--r--gnu/libexec/uucp/libuucp/MANIFEST27
-rw-r--r--gnu/libexec/uucp/libuucp/Makefile14
-rw-r--r--gnu/libexec/uucp/libuucp/bsrch.c54
-rw-r--r--gnu/libexec/uucp/libuucp/buffer.c109
-rw-r--r--gnu/libexec/uucp/libuucp/bzero.c15
-rw-r--r--gnu/libexec/uucp/libuucp/crc.c112
-rw-r--r--gnu/libexec/uucp/libuucp/debug.c165
-rw-r--r--gnu/libexec/uucp/libuucp/escape.c98
-rw-r--r--gnu/libexec/uucp/libuucp/getlin.c81
-rw-r--r--gnu/libexec/uucp/libuucp/getop1.c144
-rw-r--r--gnu/libexec/uucp/libuucp/getopt.c621
-rw-r--r--gnu/libexec/uucp/libuucp/memchr.c149
-rw-r--r--gnu/libexec/uucp/libuucp/memcmp.c19
-rw-r--r--gnu/libexec/uucp/libuucp/memcpy.c18
-rw-r--r--gnu/libexec/uucp/libuucp/parse.c207
-rw-r--r--gnu/libexec/uucp/libuucp/spool.c30
-rw-r--r--gnu/libexec/uucp/libuucp/status.c20
-rw-r--r--gnu/libexec/uucp/libuucp/strcas.c33
-rw-r--r--gnu/libexec/uucp/libuucp/strchr.c16
-rw-r--r--gnu/libexec/uucp/libuucp/strdup.c18
-rw-r--r--gnu/libexec/uucp/libuucp/strncs.c39
-rw-r--r--gnu/libexec/uucp/libuucp/strrch.c24
-rw-r--r--gnu/libexec/uucp/libuucp/strstr.c55
-rw-r--r--gnu/libexec/uucp/libuucp/strtol.c175
-rw-r--r--gnu/libexec/uucp/libuucp/xfree.c15
-rw-r--r--gnu/libexec/uucp/libuucp/xmall.c18
-rw-r--r--gnu/libexec/uucp/libuucp/xreall.c23
-rw-r--r--gnu/libexec/uucp/sample/call20
-rw-r--r--gnu/libexec/uucp/sample/config88
-rw-r--r--gnu/libexec/uucp/sample/dial35
-rw-r--r--gnu/libexec/uucp/sample/dialcode19
-rw-r--r--gnu/libexec/uucp/sample/passwd18
-rw-r--r--gnu/libexec/uucp/sample/port41
-rw-r--r--gnu/libexec/uucp/sample/sys144
-rw-r--r--gnu/libexec/uucp/sample/sys251
-rw-r--r--gnu/libexec/uucp/tstuu.c1588
-rw-r--r--gnu/libexec/uucp/uuchk/Makefile16
-rw-r--r--gnu/libexec/uucp/uuchk/uuchk.c856
-rw-r--r--gnu/libexec/uucp/uucico/Makefile20
-rw-r--r--gnu/libexec/uucp/uucico/prote.c387
-rw-r--r--gnu/libexec/uucp/uucico/protf.c842
-rw-r--r--gnu/libexec/uucp/uucico/protg.c1933
-rw-r--r--gnu/libexec/uucp/uucico/proti.c1563
-rw-r--r--gnu/libexec/uucp/uucico/protj.c671
-rw-r--r--gnu/libexec/uucp/uucico/prott.c330
-rw-r--r--gnu/libexec/uucp/uucico/protz.c2626
-rw-r--r--gnu/libexec/uucp/uucico/rec.c1162
-rw-r--r--gnu/libexec/uucp/uucico/send.c1273
-rw-r--r--gnu/libexec/uucp/uucico/time.c130
-rw-r--r--gnu/libexec/uucp/uucico/trans.c1439
-rw-r--r--gnu/libexec/uucp/uucico/uucico.8225
-rw-r--r--gnu/libexec/uucp/uucico/uucico.c2618
-rw-r--r--gnu/libexec/uucp/uucico/xcmd.c396
-rw-r--r--gnu/libexec/uucp/uuconv/Makefile17
-rw-r--r--gnu/libexec/uucp/uuconv/uuconv.c2012
-rw-r--r--gnu/libexec/uucp/uucp/Makefile16
-rw-r--r--gnu/libexec/uucp/uucp/uucp.1175
-rw-r--r--gnu/libexec/uucp/uucp/uucp.c1181
-rw-r--r--gnu/libexec/uucp/uulog/Makefile16
-rw-r--r--gnu/libexec/uucp/uulog/uulog.c444
-rw-r--r--gnu/libexec/uucp/uuname/Makefile18
-rw-r--r--gnu/libexec/uucp/uuname/uuname.c192
-rw-r--r--gnu/libexec/uucp/uupick/Makefile16
-rw-r--r--gnu/libexec/uucp/uupick/uupick.c323
-rw-r--r--gnu/libexec/uucp/uusched/Makefile15
-rw-r--r--gnu/libexec/uucp/uusched/uusched.in13
-rw-r--r--gnu/libexec/uucp/uustat/Makefile17
-rw-r--r--gnu/libexec/uucp/uustat/uustat.1380
-rw-r--r--gnu/libexec/uucp/uustat/uustat.c2241
-rw-r--r--gnu/libexec/uucp/uuto/Makefile15
-rw-r--r--gnu/libexec/uucp/uuto/uuto.in16
-rw-r--r--gnu/libexec/uucp/uux/Makefile16
-rw-r--r--gnu/libexec/uucp/uux/uux.1234
-rw-r--r--gnu/libexec/uucp/uux/uux.c1502
-rw-r--r--gnu/libexec/uucp/uuxqt/Makefile18
-rw-r--r--gnu/libexec/uucp/uuxqt/uuxqt.892
-rw-r--r--gnu/libexec/uucp/uuxqt/uuxqt.c1549
300 files changed, 81211 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/COPYING b/gnu/libexec/uucp/COPYING
new file mode 100644
index 0000000..e77696a
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..48a52b7
--- /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
+ <sys/tli.h>.
+
+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 <sys/ioctl.h>.
+
+ * 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
+ <sys/types.tcp.h>.
+ tcp.c, unix/opensr.c: include <sys/types.tcp.h> 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 <sys/types.h> in uucp.h.
+
+ * configure.in, conf.h.in: check for size_t, renamed checks for
+ time_t.
+
+ * configure.in, conf.h.in: check for <stddef.h>.
+
+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 <sys/select.h>, 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 <unistd.h> 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 <sys/times.h> 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 <poll.h> or
+ <stropts.h>.
+
+ * 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
+ <sys/ioctl.h> 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
+ <sys/types.h> but not <signal.h>.
+
+ * 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 <termios.h> and
+ <sys/ioctl.h> 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 <sys/ioct.h> 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 <sys/ioctl.h> 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 <libc.h> 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 <sys/file.h> instead of <fcntl.h>. 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 <string.h> 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 <errno.h>, 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 <sys/time.h> includes <time.h> but <time.h> 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
+ <limits.h>. 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
+ <unistd.h> but not <stdio.h>.
+
+ * 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 <unistd.h>. Also added
+ externs for all functions from <unistd.h>, 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 <unistd.h>. 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 0000000..e028f7e
--- /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 <bsd.subdir.mk>
diff --git a/gnu/libexec/uucp/Makefile.inc b/gnu/libexec/uucp/Makefile.inc
new file mode 100644
index 0000000..4bdbcaa
--- /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 0000000..bfcd46c
--- /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 0000000..a1cc643
--- /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 <cowan@snark.thyrsus.com> 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 <gordon@sneaky.lonestar.org> warns about modifications
+to the TZ environment variable, to fool uucico into dialing out at an
+inappropriate time.
+
+10.
+
+Gordon Burditt <gordon@sneaky.lonestar.org> 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 <ralf@reswi.ruhr.de> 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 <sysexits.h> 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 0000000..99fd8f0
--- /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 0000000..86a68d9
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/chat.c
@@ -0,0 +1,1429 @@
+/* chat.c
+ Chat routine for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char chat_rcsid[] = "$Id: chat.c,v 1.1 1993/08/04 19:30:29 jtc Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "prot.h"
+#include "system.h"
+
+/* Local functions. */
+
+static int icexpect P((struct sconnection *qconn, int cstrings,
+ char **azstrings, size_t *aclens,
+ int ctimeout, boolean fstrip));
+static boolean fcsend P((struct sconnection *qconn, pointer puuconf,
+ const char *zsend,
+ const struct uuconf_system *qsys,
+ const struct uuconf_dialer *qdial,
+ const char *zphone,
+ boolean ftranslate, boolean fstrip));
+static boolean fcecho_send_strip P((struct sconnection *qconn,
+ const char *z, size_t clen));
+static boolean fcecho_send_nostrip P((struct sconnection *qconn,
+ const char *z, size_t clen));
+static boolean fcecho_send P((struct sconnection *qconn, const char *z,
+ size_t clen, boolean fstrip));
+static boolean fcphone P((struct sconnection *qconn,
+ pointer puuconf,
+ const struct uuconf_dialer *qdial,
+ const char *zphone,
+ boolean (*pfwrite) P((struct sconnection *qc,
+ const char *zwrite,
+ size_t cwrite)),
+ boolean ftranslate, boolean *pfquote));
+static boolean fctranslate P((pointer puuconf, const char *zphone,
+ const char **pzprefix,
+ const char **pzsuffix));
+static boolean fcprogram P((struct sconnection *qconn, pointer puuconf,
+ char **pzprogram,
+ const struct uuconf_system *qsys,
+ const struct uuconf_dialer *qdial,
+ const char *zphone, const char *zport,
+ long ibaud));
+
+/* Run a chat script with the other system. The chat script is a
+ series of expect send pairs. We wait for the expect string to show
+ up, and then we send the send string. The chat string for a system
+ holds the expect and send strings separated by a single space. */
+
+boolean
+fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_chat *qchat;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+ const char *zport;
+ long ibaud;
+{
+ int cstrings;
+ char **azstrings;
+ size_t *aclens;
+ char **pzchat;
+ char *zbuf;
+ size_t cbuflen;
+ boolean fret;
+ int i;
+
+ /* First run the program, if any. */
+ if (qchat->uuconf_pzprogram != NULL)
+ {
+ if (! fcprogram (qconn, puuconf, qchat->uuconf_pzprogram, qsys, qdial,
+ zphone, zport, ibaud))
+ return FALSE;
+ }
+
+ /* If there's no chat script, we're done. */
+ if (qchat->uuconf_pzchat == NULL)
+ return TRUE;
+
+ if (qchat->uuconf_pzfail == NULL)
+ {
+ cstrings = 1;
+ azstrings = (char **) xmalloc (sizeof (char *));
+ aclens = (size_t *) xmalloc (sizeof (size_t));
+ }
+ else
+ {
+ char **pz;
+
+ /* We leave string number 0 for the chat script. */
+ cstrings = 1;
+ for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++)
+ ++cstrings;
+
+ azstrings = (char **) xmalloc (cstrings * sizeof (char *));
+ aclens = (size_t *) xmalloc (cstrings * sizeof (size_t));
+
+ /* Get the strings into the array, and handle all the escape
+ characters. */
+ for (cstrings = 1, pz = qchat->uuconf_pzfail;
+ *pz != NULL;
+ cstrings++, pz++)
+ {
+ azstrings[cstrings] = zbufcpy (*pz);
+ aclens[cstrings] = cescape (azstrings[cstrings]);
+ }
+ }
+
+ cbuflen = 0;
+ zbuf = NULL;
+ fret = TRUE;
+
+ pzchat = qchat->uuconf_pzchat;
+
+ while (*pzchat != NULL)
+ {
+ size_t clen;
+
+ /* Loop over subexpects and subsends. */
+ while (TRUE)
+ {
+ /* Copy the expect string into the buffer so that we can
+ modify it in cescape. */
+ clen = strlen (*pzchat);
+ if (clen >= cbuflen)
+ {
+ ubuffree (zbuf);
+ zbuf = zbufalc (clen + 1);
+ cbuflen = clen;
+ }
+ memcpy (zbuf, *pzchat, clen + 1);
+
+ azstrings[0] = zbuf;
+ if (azstrings[0][0] == '-')
+ ++azstrings[0];
+ aclens[0] = cescape (azstrings[0]);
+
+ if (aclens[0] == 0
+ || (aclens[0] == 2
+ && strcmp (azstrings[0], "\"\"") == 0))
+ {
+ /* There is no subexpect sequence. If there is a
+ subsend sequence we move on to it. Otherwise we let
+ this expect succeed. This is somewhat inconsistent,
+ but it seems to be the traditional approach. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ break;
+ }
+ else
+ {
+ int istr;
+
+ istr = icexpect (qconn, cstrings, azstrings, aclens,
+ qchat->uuconf_ctimeout,
+ qchat->uuconf_fstrip);
+
+ /* If we found the string, break out of the
+ subexpect/subsend loop. */
+ if (istr == 0)
+ break;
+
+ /* If we got an error, return FALSE. */
+ if (istr < -1)
+ {
+ fret = FALSE;
+ break;
+ }
+
+ /* If we found a failure string, log it and get out. */
+ if (istr > 0)
+ {
+ ulog (LOG_ERROR, "Chat script failed: Got \"%s\"",
+ qchat->uuconf_pzfail[istr - 1]);
+ fret = FALSE;
+ break;
+ }
+
+ /* We timed out; look for a send subsequence. If none,
+ the chat script has failed. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ {
+ ulog (LOG_ERROR, "Timed out in chat script");
+ fret = FALSE;
+ break;
+ }
+ }
+
+ /* Send the send subsequence without the leading '-'. A
+ \"\" will send nothing. An empty string will send a
+ carriage return. */
+ ++pzchat;
+ if (! fcsend (qconn, puuconf, *pzchat + 1, qsys, qdial, zphone,
+ ftranslate, qchat->uuconf_fstrip))
+ {
+ fret = FALSE;
+ break;
+ }
+
+ /* If there is no expect subsequence, we are done. */
+ if (pzchat[1] == NULL || pzchat[1][0] != '-')
+ break;
+
+ /* Move on to next expect subsequence. */
+ ++pzchat;
+ }
+
+ if (! fret)
+ break;
+
+ /* Move on to the send string. If there is none, we have
+ succeeded. */
+ do
+ {
+ ++pzchat;
+ }
+ while (*pzchat != NULL && (*pzchat)[0] == '-');
+
+ if (*pzchat == NULL)
+ break;
+
+ if (**pzchat != '\0')
+ {
+ if (! fcsend (qconn, puuconf, *pzchat, qsys, qdial, zphone,
+ ftranslate, qchat->uuconf_fstrip))
+ {
+ fret = FALSE;
+ break;
+ }
+ }
+
+ ++pzchat;
+ }
+
+ ubuffree (zbuf);
+ for (i = 1; i < cstrings; i++)
+ ubuffree (azstrings[i]);
+ xfree ((pointer) azstrings);
+ xfree ((pointer) aclens);
+
+ return fret;
+}
+
+/* Read characters and wait for one of a set of memory strings to come
+ in. This returns the index into the array of the string that
+ arrives, or -1 on timeout, or -2 on error. */
+
+static int
+icexpect (qconn, cstrings, azstrings, aclens, ctimeout, fstrip)
+ struct sconnection *qconn;
+ int cstrings;
+ char **azstrings;
+ size_t *aclens;
+ int ctimeout;
+ boolean fstrip;
+{
+ int i;
+ size_t cmax;
+ char *zhave;
+ size_t chave;
+ long iendtime;
+#if DEBUG > 1
+ int cchars;
+ int iolddebug;
+#endif
+
+ cmax = aclens[0];
+ for (i = 1; i < cstrings; i++)
+ if (cmax < aclens[i])
+ cmax = aclens[i];
+
+ zhave = zbufalc (cmax);
+ chave = 0;
+
+ iendtime = ixsysdep_time ((long *) NULL) + ctimeout;
+
+#if DEBUG > 1
+ cchars = 0;
+ iolddebug = iDebug;
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ udebug_buffer ("icexpect: Looking for", azstrings[0],
+ aclens[0]);
+ ulog (LOG_DEBUG_START, "icexpect: Got \"");
+ iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT);
+ }
+#endif
+
+ while (TRUE)
+ {
+ int bchar;
+
+ /* If we have no more time, get out. */
+ if (ctimeout <= 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ ulog (LOG_DEBUG_END, "\" (timed out)");
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return -1;
+ }
+
+ /* Read one character at a time. We could use a more complex
+ algorithm to read in larger batches, but it's probably not
+ worth it. If the buffer is full, shift it left; we already
+ know that no string matches, and the buffer holds the largest
+ string, so this can't lose a match. */
+ if (chave >= cmax)
+ {
+ size_t imove;
+
+ for (imove = 0; imove < cmax - 1; imove++)
+ zhave[imove] = zhave[imove + 1];
+ --chave;
+ }
+
+ /* The timeout/error return values from breceive_char are the
+ same as for this function. */
+ bchar = breceive_char (qconn, ctimeout, TRUE);
+ if (bchar < 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ /* If there was an error, it will probably be logged in
+ the middle of our string, but this is only debugging
+ so it's not a big deal. */
+ ulog (LOG_DEBUG_END, "\" (%s)",
+ bchar == -1 ? "timed out" : "error");
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return bchar;
+ }
+
+ /* Strip the parity bit if desired. */
+ if (fstrip)
+ bchar &= 0x7f;
+
+ zhave[chave] = (char) bchar;
+ ++chave;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ char ab[5];
+
+ ++cchars;
+ if (cchars > 60)
+ {
+ ulog (LOG_DEBUG_END, "\"");
+ ulog (LOG_DEBUG_START, "icexpect: Got \"");
+ cchars = 0;
+ }
+ (void) cdebug_char (ab, bchar);
+ ulog (LOG_DEBUG_CONTINUE, "%s", ab);
+ }
+#endif
+
+ /* See if any of the strings can be found in the buffer. Since
+ we read one character at a time, the string can only be found
+ at the end of the buffer. */
+ for (i = 0; i < cstrings; i++)
+ {
+ if (aclens[i] <= chave
+ && memcmp (zhave + chave - aclens[i], azstrings[i],
+ aclens[i]) == 0)
+ {
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ if (i == 0)
+ ulog (LOG_DEBUG_END, "\" (found it)");
+ else
+ {
+ ulog (LOG_DEBUG_END, "\"");
+ udebug_buffer ("icexpect: Found", azstrings[i],
+ aclens[i]);
+ }
+ iDebug = iolddebug;
+ }
+#endif
+ ubuffree (zhave);
+ return i;
+ }
+ }
+
+ ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL));
+ }
+}
+
+#if DEBUG > 1
+
+/* Debugging function for fcsend. This takes the fquote variable, the
+ length of the string (0 if this an informational string which can
+ be printed directly) and the string itself. It returns the new
+ value for fquote. The fquote variable is TRUE if the debugging
+ output is in the middle of a quoted string. */
+
+static size_t cCsend_chars;
+static int iColddebug;
+
+static boolean fcsend_debug P((boolean, size_t, const char *));
+
+static boolean
+fcsend_debug (fquote, clen, zbuf)
+ boolean fquote;
+ size_t clen;
+ const char *zbuf;
+{
+ size_t cwas;
+
+ if (! FDEBUGGING (DEBUG_CHAT))
+ return TRUE;
+
+ cwas = cCsend_chars;
+ if (clen > 0)
+ cCsend_chars += clen;
+ else
+ cCsend_chars += strlen (zbuf);
+ if (cCsend_chars > 60 && cwas > 10)
+ {
+ ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : "");
+ fquote = FALSE;
+ ulog (LOG_DEBUG_START, "fcsend: Writing");
+ cCsend_chars = 0;
+ }
+
+ if (clen == 0)
+ {
+ ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf);
+ return FALSE;
+ }
+ else
+ {
+ int i;
+
+ if (! fquote)
+ ulog (LOG_DEBUG_CONTINUE, " \"");
+ for (i = 0; i < clen; i++)
+ {
+ char ab[5];
+
+ (void) cdebug_char (ab, zbuf[i]);
+ ulog (LOG_DEBUG_CONTINUE, "%s", ab);
+ }
+
+ return TRUE;
+ }
+}
+
+/* Finish up the debugging information for fcsend. */
+
+static void ucsend_debug_end P((boolean, boolean));
+
+static void
+ucsend_debug_end (fquote, ferr)
+ boolean fquote;
+ boolean ferr;
+{
+ if (! FDEBUGGING (DEBUG_CHAT))
+ return;
+
+ if (fquote)
+ ulog (LOG_DEBUG_CONTINUE, "\"");
+
+ if (ferr)
+ ulog (LOG_DEBUG_CONTINUE, " (error)");
+
+ ulog (LOG_DEBUG_END, "%s", "");
+
+ iDebug = iColddebug;
+}
+
+#else /* DEBUG <= 1 */
+
+/* Use macro definitions to make fcsend look neater. */
+
+#define fcsend_debug(fquote, clen, zbuf) TRUE
+
+#define ucsend_debug_end(fquote, ferror)
+
+#endif /* DEBUG <= 1 */
+
+/* Send a string out. This has to parse escape sequences as it goes.
+ Note that it handles the dialer escape sequences (\e, \E, \D, \T)
+ although they make no sense for chatting with a system. */
+
+static boolean
+fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const char *z;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+ boolean fstrip;
+{
+ boolean fnocr;
+ boolean (*pfwrite) P((struct sconnection *, const char *, size_t));
+ char *zcallout_login;
+ char *zcallout_pass;
+ boolean fquote;
+
+ if (strcmp (z, "\"\"") == 0)
+ return TRUE;
+
+ fnocr = FALSE;
+ pfwrite = fconn_write;
+ zcallout_login = NULL;
+ zcallout_pass = NULL;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_CHAT))
+ {
+ ulog (LOG_DEBUG_START, "fcsend: Writing");
+ fquote = FALSE;
+ cCsend_chars = 0;
+ iColddebug = iDebug;
+ iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT);
+ }
+#endif
+
+ while (*z != '\0')
+ {
+ const char *zlook;
+ boolean fsend;
+ char bsend;
+
+ zlook = z + strcspn ((char *) z, "\\BE");
+
+ if (zlook > z)
+ {
+ size_t c;
+
+ c = zlook - z;
+ fquote = fcsend_debug (fquote, c, z);
+ if (! (*pfwrite) (qconn, z, c))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+
+ if (*zlook == '\0')
+ break;
+
+ z = zlook;
+
+ fsend = FALSE;
+ switch (*z)
+ {
+ case 'B':
+ if (strncmp (z, "BREAK", 5) == 0)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 0, "break");
+ if (! fconn_break (qconn))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ fnocr = TRUE;
+ z += 5;
+ }
+ else
+ {
+ fsend = TRUE;
+ bsend = 'B';
+ ++z;
+ }
+ break;
+ case 'E':
+ if (strncmp (z, "EOT", 3) == 0)
+ {
+ fsend = TRUE;
+ bsend = '\004';
+ fnocr = TRUE;
+ z += 3;
+ }
+ else
+ {
+ fsend = TRUE;
+ bsend = 'E';
+ ++z;
+ }
+ break;
+ case '\\':
+ ++z;
+ switch (*z)
+ {
+ case '-':
+ fsend = TRUE;
+ bsend = '-';
+ break;
+ case 'b':
+ fsend = TRUE;
+ bsend = '\b';
+ break;
+ case 'c':
+ fnocr = TRUE;
+ break;
+ case 'd':
+ fquote = fcsend_debug (fquote, (size_t) 0, "sleep");
+ usysdep_sleep (2);
+ break;
+ case 'e':
+ fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off");
+ pfwrite = fconn_write;
+ break;
+ case 'E':
+ fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-on");
+ if (fstrip)
+ pfwrite = fcecho_send_strip;
+ else
+ pfwrite = fcecho_send_nostrip;
+ break;
+ case 'K':
+ fquote = fcsend_debug (fquote, (size_t) 0, "break");
+ if (! fconn_break (qconn))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'n':
+ fsend = TRUE;
+ bsend = '\n';
+ break;
+ case 'N':
+ fsend = TRUE;
+ bsend = '\0';
+ break;
+ case 'p':
+ fquote = fcsend_debug (fquote, (size_t) 0, "pause");
+ usysdep_pause ();
+ break;
+ case 'r':
+ fsend = TRUE;
+ bsend = '\r';
+ break;
+ case 's':
+ fsend = TRUE;
+ bsend = ' ';
+ break;
+ case 't':
+ fsend = TRUE;
+ bsend = '\t';
+ break;
+ case '\0':
+ --z;
+ /* Fall through. */
+ case '\\':
+ fsend = TRUE;
+ bsend = '\\';
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ fsend = TRUE;
+ bsend = *z - '0';
+ if (z[1] >= '0' && z[1] <= '7')
+ bsend = (char) (8 * bsend + *++z - '0');
+ if (z[1] >= '0' && z[1] <= '7')
+ bsend = (char) (8 * bsend + *++z - '0');
+ break;
+ case 'x':
+ fsend = TRUE;
+ bsend = 0;
+ while (isxdigit (BUCHAR (z[1])))
+ {
+ if (isdigit (BUCHAR (z[1])))
+ bsend = (char) (16 * bsend + *++z - '0');
+ else if (isupper (BUCHAR (z[1])))
+ bsend = (char) (16 * bsend + *++z - 'A');
+ else
+ bsend = (char) (16 * bsend + *++z - 'a');
+ }
+ break;
+ case 'L':
+ {
+ const char *zlog;
+
+ if (qsys == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\L");
+ return FALSE;
+ }
+ zlog = qsys->uuconf_zcall_login;
+ if (zlog == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No login defined");
+ return FALSE;
+ }
+ if (zlog[0] == '*' && zlog[1] == '\0')
+ {
+ if (zcallout_login == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_login == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No login defined");
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ }
+ zlog = zcallout_login;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "login");
+ fquote = fcsend_debug (fquote, strlen (zlog), zlog);
+ if (! (*pfwrite) (qconn, zlog, strlen (zlog)))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ case 'P':
+ {
+ const char *zpass;
+
+ if (qsys == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\P");
+ return FALSE;
+ }
+ zpass = qsys->uuconf_zcall_password;
+ if (zpass == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No password defined");
+ return FALSE;
+ }
+ if (zpass[0] == '*' && zpass[1] == '\0')
+ {
+ if (zcallout_pass == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_pass == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "No password defined");
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ }
+ zpass = zcallout_pass;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "password");
+ fquote = fcsend_debug (fquote, strlen (zpass), zpass);
+ if (! (*pfwrite) (qconn, zpass, strlen (zpass)))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ case 'D':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\D");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "\\D");
+ if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite,
+ ftranslate, &fquote))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'T':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\T");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "\\T");
+ if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, TRUE,
+ &fquote))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'M':
+ if (qdial == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\M");
+ return FALSE;
+ }
+ fquote = fcsend_debug (fquote, (size_t) 0, "ignore-carrier");
+ if (! fconn_carrier (qconn, FALSE))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ break;
+ case 'm':
+ if (qdial == NULL)
+ {
+ ucsend_debug_end (fquote, TRUE);
+ ulog (LOG_ERROR, "Illegal use of \\m");
+ return FALSE;
+ }
+ if (qdial->uuconf_fcarrier)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 0, "need-carrier");
+ if (! fconn_carrier (qconn, TRUE))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ /* This error message will screw up any debugging
+ information, but it's easily avoidable. */
+ ulog (LOG_ERROR,
+ "Unrecognized escape sequence \\%c in send string",
+ *z);
+ fsend = TRUE;
+ bsend = *z;
+ break;
+ }
+ ++z;
+ break;
+#if DEBUG > 0
+ default:
+ ulog (LOG_FATAL, "fcsend: Can't happen");
+ break;
+#endif
+ }
+
+ if (fsend)
+ {
+ fquote = fcsend_debug (fquote, (size_t) 1, &bsend);
+ if (! (*pfwrite) (qconn, &bsend, (size_t) 1))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+ }
+
+ xfree ((pointer) zcallout_login);
+ xfree ((pointer) zcallout_pass);
+
+ /* Output a final carriage return, unless there was a \c. Don't
+ bother to check for an echo. */
+ if (! fnocr)
+ {
+ char b;
+
+ b = '\r';
+ fquote = fcsend_debug (fquote, (size_t) 1, &b);
+ if (! fconn_write (qconn, &b, (size_t) 1))
+ {
+ ucsend_debug_end (fquote, TRUE);
+ return FALSE;
+ }
+ }
+
+ ucsend_debug_end (fquote, FALSE);
+
+ return TRUE;
+}
+
+/* Write out a phone number with optional dialcode translation. The
+ pfquote argument is only used for debugging. */
+
+static boolean
+fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, pfquote)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite,
+ size_t cwrite));
+ boolean ftranslate;
+ boolean *pfquote;
+{
+ const char *zprefix, *zsuffix;
+
+ if (ftranslate)
+ {
+ if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
+ return FALSE;
+ }
+ else
+ {
+ zprefix = zphone;
+ zsuffix = NULL;
+ }
+
+ while (zprefix != NULL)
+ {
+ while (TRUE)
+ {
+ const char *z;
+ const char *zstr;
+
+ z = zprefix + strcspn ((char *) zprefix, "=-");
+ if (z > zprefix)
+ {
+ size_t clen;
+
+ clen = z - zprefix;
+ *pfquote = fcsend_debug (*pfquote, clen, zprefix);
+ if (! (*pfwrite) (qconn, zprefix, clen))
+ return FALSE;
+ }
+
+ if (*z == '=')
+ zstr = qdial->uuconf_zdialtone;
+ else if (*z == '-')
+ zstr = qdial->uuconf_zpause;
+ else /* *z == '\0' */
+ break;
+
+ if (zstr != NULL)
+ {
+ *pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr);
+ if (! (*pfwrite) (qconn, zstr, strlen (zstr)))
+ return FALSE;
+ }
+
+ zprefix = z + 1;
+ }
+
+ zprefix = zsuffix;
+ zsuffix = NULL;
+ }
+
+ return TRUE;
+}
+
+/* Given a phone number, run it through dial code translation
+ returning two strings. */
+
+static boolean
+fctranslate (puuconf, zphone, pzprefix, pzsuffix)
+ pointer puuconf;
+ const char *zphone;
+ const char **pzprefix;
+ const char **pzsuffix;
+{
+ int iuuconf;
+ char *zdialcode, *zto;
+ const char *zfrom;
+ char *ztrans;
+
+ *pzprefix = zphone;
+ *pzsuffix = NULL;
+
+ zdialcode = zbufalc (strlen (zphone) + 1);
+ zfrom = zphone;
+ zto = zdialcode;
+ while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom)))
+ *zto++ = *zfrom++;
+ *zto = '\0';
+
+ if (*zdialcode == '\0')
+ {
+ ubuffree (zdialcode);
+ return TRUE;
+ }
+
+ iuuconf = uuconf_dialcode (puuconf, zdialcode, &ztrans);
+
+ ubuffree (zdialcode);
+
+ if (iuuconf == UUCONF_NOT_FOUND)
+ return TRUE;
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+ else
+ {
+ /* We really should figure out a way to free up ztrans here. */
+ *pzprefix = ztrans;
+ *pzsuffix = zfrom;
+ return TRUE;
+ }
+}
+
+/* Write out a string making sure the each character is echoed back.
+ There are two versions of this function, one which strips the
+ parity bit from the characters and one which does not. This is so
+ that I can use a single function pointer in fcsend, and to avoid
+ using any static variables so that I can put chat scripts in a
+ library some day. */
+
+static boolean
+fcecho_send_strip (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ return fcecho_send (qconn, zwrite, cwrite, TRUE);
+}
+
+static boolean
+fcecho_send_nostrip (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ return fcecho_send (qconn, zwrite, cwrite, FALSE);
+}
+
+static boolean
+fcecho_send (qconn, zwrite, cwrite, fstrip)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+ boolean fstrip;
+{
+ const char *zend;
+
+ zend = zwrite + cwrite;
+
+ for (; zwrite < zend; zwrite++)
+ {
+ int b;
+ char bwrite;
+
+ bwrite = *zwrite;
+ if (! fconn_write (qconn, &bwrite, (size_t) 1))
+ return FALSE;
+ if (fstrip)
+ bwrite &= 0x7f;
+ do
+ {
+ /* We arbitrarily wait five seconds for the echo. */
+ b = breceive_char (qconn, 5, TRUE);
+ /* Now b == -1 on timeout, -2 on error. */
+ if (b < 0)
+ {
+ if (b == -1)
+ ulog (LOG_ERROR, "Character not echoed");
+ return FALSE;
+ }
+ if (fstrip)
+ b &= 0x7f;
+ }
+ while (b != BUCHAR (bwrite));
+ }
+
+ return TRUE;
+}
+
+/* Run a chat program. Expand any escape sequences and call a system
+ dependent program to run it. */
+
+static boolean
+fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud)
+ struct sconnection *qconn;
+ pointer puuconf;
+ char **pzprogram;
+ const struct uuconf_system *qsys;
+ const struct uuconf_dialer *qdial;
+ const char *zphone;
+ const char *zport;
+ long ibaud;
+{
+ size_t cargs;
+ char **pzpass, **pzarg;
+ char **pz;
+ char *zcallout_login;
+ char *zcallout_pass;
+ boolean fret;
+
+ cargs = 1;
+ for (pz = pzprogram; *pz != NULL; pz++)
+ ++cargs;
+
+ pzpass = (char **) xmalloc (cargs * sizeof (char *));
+
+ zcallout_login = NULL;
+ zcallout_pass = NULL;
+ fret = TRUE;
+
+ /* Copy the string into memory expanding escape sequences. */
+ for (pz = pzprogram, pzarg = pzpass; *pz != NULL; pz++, pzarg++)
+ {
+ const char *zfrom;
+ size_t calc, clen;
+ char *zto;
+
+ if (strchr (*pz, '\\') == NULL)
+ {
+ *pzarg = zbufcpy (*pz);
+ continue;
+ }
+
+ *pzarg = NULL;
+ zto = NULL;
+ calc = 0;
+ clen = 0;
+
+ for (zfrom = *pz; *zfrom != '\0'; zfrom++)
+ {
+ const char *zadd = NULL;
+ size_t cadd;
+ char abadd[15];
+
+ if (*zfrom != '\\')
+ {
+ if (clen + 2 > calc)
+ {
+ char *znew;
+
+ calc = clen + 50;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ *zto++ = *zfrom;
+ ++clen;
+ continue;
+ }
+
+ ++zfrom;
+ switch (*zfrom)
+ {
+ case '\0':
+ --zfrom;
+ /* Fall through. */
+ case '\\':
+ zadd = "\\";
+ break;
+ case 'L':
+ {
+ const char *zlog;
+
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\L");
+ fret = FALSE;
+ break;
+ }
+ zlog = qsys->uuconf_zcall_login;
+ if (zlog == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: No login defined");
+ fret = FALSE;
+ break;
+ }
+ if (zlog[0] == '*' && zlog[1] == '\0')
+ {
+ if (zcallout_login == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_login == NULL)
+ {
+ ulog (LOG_ERROR,
+ "chat-program: No login defined");
+ fret = FALSE;
+ break;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ break;
+ }
+ }
+ zlog = zcallout_login;
+ }
+ zadd = zlog;
+ }
+ break;
+ case 'P':
+ {
+ const char *zpass;
+
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\P");
+ fret = FALSE;
+ break;
+ }
+ zpass = qsys->uuconf_zcall_password;
+ if (zpass == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: No password defined");
+ fret = FALSE;
+ break;
+ }
+ if (zpass[0] == '*' && zpass[1] == '\0')
+ {
+ if (zcallout_pass == NULL)
+ {
+ int iuuconf;
+
+ iuuconf = uuconf_callout (puuconf, qsys,
+ &zcallout_login,
+ &zcallout_pass);
+ if (iuuconf == UUCONF_NOT_FOUND
+ || zcallout_pass == NULL)
+ {
+ ulog (LOG_ERROR,
+ "chat-program: No password defined");
+ fret = FALSE;
+ break;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ break;
+ }
+ }
+ zpass = zcallout_pass;
+ }
+ zadd = zpass;
+ }
+ break;
+ case 'D':
+ if (qdial == NULL || zphone == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\D");
+ fret = FALSE;
+ break;
+ }
+ zadd = zphone;
+ break;
+ case 'T':
+ {
+ const char *zprefix, *zsuffix;
+
+ if (qdial == NULL || zphone == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\T");
+ fret = FALSE;
+ break;
+ }
+
+ if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix))
+ {
+ fret = FALSE;
+ break;
+ }
+
+ if (zsuffix == NULL)
+ zadd = zprefix;
+ else
+ {
+ size_t cprefix;
+
+ cprefix = strlen (zprefix);
+ if (clen + cprefix + 1 > calc)
+ {
+ char *znew;
+
+ calc = clen + cprefix + 20;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ memcpy (zto, zprefix, cprefix);
+ zto += cprefix;
+ clen += cprefix;
+ zadd = zsuffix;
+ }
+ }
+ break;
+ case 'Y':
+ if (zLdevice == NULL && zport == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\Y");
+ fret = FALSE;
+ break;
+ }
+ /* zLdevice will generally make more sense than zport, but
+ it might not be set yet. */
+ zadd = zLdevice;
+ if (zadd == NULL)
+ zadd = zport;
+ break;
+ case 'Z':
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\Z");
+ fret = FALSE;
+ break;
+ }
+ zadd = qsys->uuconf_zname;
+ break;
+ case 'S':
+ {
+ if (ibaud == 0)
+ {
+ ulog (LOG_ERROR, "chat-program: Illegal use of \\S");
+ fret = FALSE;
+ break;
+ }
+ sprintf (abadd, "%ld", ibaud);
+ zadd = abadd;
+ }
+ break;
+ default:
+ {
+ ulog (LOG_ERROR,
+ "chat-program: Unrecognized escape sequence \\%c",
+ *zfrom);
+ abadd[0] = *zfrom;
+ abadd[1] = '\0';
+ zadd = abadd;
+ }
+ break;
+ }
+
+ if (! fret)
+ break;
+
+ cadd = strlen (zadd);
+ if (clen + cadd + 1 > calc)
+ {
+ char *znew;
+
+ calc = clen + cadd + 20;
+ znew = zbufalc (calc);
+ memcpy (znew, *pzarg, clen);
+ ubuffree (*pzarg);
+ *pzarg = znew;
+ zto = znew + clen;
+ }
+ memcpy (zto, zadd, cadd + 1);
+ zto += cadd;
+ clen += cadd;
+ }
+
+ if (! fret)
+ break;
+
+ *zto++ = '\0';
+ ++clen;
+ }
+
+ *pzarg = NULL;
+
+ if (fret)
+ fret = fconn_run_chat (qconn, pzpass);
+
+ for (pz = pzpass; *pz != NULL; pz++)
+ ubuffree (*pz);
+ xfree ((pointer) pzpass);
+ xfree ((pointer) zcallout_login);
+ xfree ((pointer) zcallout_pass);
+
+ return fret;
+}
diff --git a/gnu/libexec/uucp/common_sources/conf.h b/gnu/libexec/uucp/common_sources/conf.h
new file mode 100644
index 0000000..431ba4d
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/conf.h
@@ -0,0 +1,444 @@
+/* conf.h. Generated automatically by configure. */
+/* Configuration header file for Taylor UUCP. -*- C -*- */
+
+/* Set MAIL_PROGRAM to a program which takes a mail address as an
+ argument and accepts a mail message to send to that address on
+ stdin (e.g. "/bin/mail"). */
+#define MAIL_PROGRAM "/usr/bin/mail"
+
+/* Set ECHO_PROGRAM to a program which echoes its arguments; if echo
+ is a shell builtin you can just use "echo". */
+#define ECHO_PROGRAM "echo"
+
+/* The following macros indicate what header files you have. Set the
+ macro to 1 if you have the corresponding header file, or 0 if you
+ do not. */
+#define HAVE_STDDEF_H 1 /* <stddef.h> */
+#define HAVE_STRING_H 1 /* <string.h> */
+#define HAVE_STRINGS_H 1 /* <strings.h> */
+#define HAVE_UNISTD_H 1 /* <unistd.h> */
+#define HAVE_STDLIB_H 1 /* <stdlib.h> */
+#define HAVE_LIMITS_H 1 /* <limits.h> */
+#define HAVE_TIME_H 1 /* <time.h> */
+#define HAVE_SYS_WAIT_H 1 /* <sys/wait.h> */
+#define HAVE_SYS_IOCTL_H 1 /* <sys/ioctl.h> */
+#define HAVE_DIRENT_H 1 /* <dirent.h> */
+#define HAVE_MEMORY_H 1 /* <memory.h> */
+#define HAVE_SYS_PARAM_H 1 /* <sys/param.h> */
+#define HAVE_UTIME_H 1 /* <utime.h> */
+#define HAVE_FCNTL_H 1 /* <fcntl.h> */
+#define HAVE_SYS_FILE_H 1 /* <sys/file.h> */
+#define HAVE_SYS_TIMES_H 1 /* <sys/times.h> */
+#define HAVE_LIBC_H 0 /* <libc.h> */
+#define HAVE_SYSEXITS_H 1 /* <sysexits.h> */
+#define HAVE_POLL_H 0 /* <poll.h> */
+#define HAVE_TIUSER_H 0 /* <tiuser.h> */
+#define HAVE_XTI_H 0 /* <xti.h> */
+#define HAVE_SYS_TLI_H 0 /* <sys/tli.h> */
+#define HAVE_STROPTS_H 0 /* <stropts.h> */
+#define HAVE_FTW_H 0 /* <ftw.h> */
+#define HAVE_GLOB_H 1 /* <glob.h> */
+#define HAVE_SYS_SELECT_H 0 /* <sys/select.h> */
+#define HAVE_SYS_TYPES_TCP_H 0 /* <sys/types.tcp.h> */
+
+/* If major and minor are not defined in <sys/types.h>, but are in
+ <sys/mkdev.h>, set MAJOR_IN_MKDEV to 1. If they are in
+ <sys/sysmacros.h>, set MAJOR_IN_SYSMACROS to 1. */
+#define MAJOR_IN_MKDEV 0
+#define MAJOR_IN_SYSMACROS 0
+
+/* If the macro offsetof is not defined in <stddef.h>, you may give it
+ a definition here. If you do not, the code will use a definition
+ (in uucp.h) that should be fairly portable. */
+/* #define offsetof */
+
+/* Set RETSIGTYPE to the return type of a signal handler. On newer
+ systems this will be void; some older systems use int. */
+#define RETSIGTYPE void
+
+/* Set HAVE_SYS_TIME_AND_TIME_H to 1 if <time.h> and <sys/time.h> can both
+ be included in a single source file; if you don't have either or both of
+ them, it doesn't matter what you set this to. */
+#define HAVE_SYS_TIME_AND_TIME_H 1
+
+/* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if <termios.h> and <sys/ioctl.h>
+ can both be included in a single source file; if you don't have either
+ or both of them, it doesn't matter what you set this to. */
+#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1
+
+/* If you are configuring by hand, you should set one of the terminal
+ driver options in policy.h. If you are autoconfiguring, the script
+ will check whether your system defines CBREAK, which is a terminal
+ setting; if your system supports CBREAK, and you don't set a terminal
+ driver in policy.h, the code will assume that you have a BSD style
+ terminal driver. */
+#define HAVE_CBREAK 1
+
+/* The package needs several standard types. If you are using the
+ configure script, it will look in standard places for these types,
+ and give default definitions for them here if it doesn't find them.
+ The default definitions should work on most systems, but you may
+ want to check them. If you are configuring by hand, you will have
+ to figure out whether the types are defined on your system, and
+ what they should be defined to.
+
+ Any type that is not defined on your system should get a macro
+ definition. The definition should be of the name of the type in
+ all capital letters. For example, #define PID_T int. If the type
+ is defined in a standard header file, the macro name should not be
+ defined. */
+
+/* The type pid_t is used to hold a process ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the
+ functions fork or getpid. Usually int will work fine. */
+#undef PID_T
+
+/* The type uid_t is used to hold a user ID number. It is normally
+ defined in <sys/types.h>. This is the type returned by the getuid
+ function. Usually int will work fine. */
+#undef UID_T
+
+/* The type gid_t is used to hold a group ID number. It is sometimes
+ defined in <sys/types.h>. This is the type returned by the getgid
+ function. Usually int will work fine. */
+#undef GID_T
+
+/* The type off_t is used to hold an offset in a file. It is sometimes
+ defined in <sys/types.h>. This is the type of the second argument to
+ the lseek function. Usually long will work fine. */
+#undef OFF_T
+
+/* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined
+ in <signal.h> as required by ANSI C. */
+#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 1
+
+/* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined
+ in <sys/types.h>. This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is
+ set to 1. */
+#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0
+
+/* The type sig_atomic_t is used to hold a value which may be
+ referenced in a single atomic operation. If it is not defined in
+ either <signal.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use char. If your
+ compiler does not support sig_atomic_t, there is no type which is
+ really correct; fortunately, for this package it does not really
+ matter very much. */
+#undef SIG_ATOMIC_T
+
+/* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in
+ <stddef.h> as required by ANSI C. */
+#define HAVE_SIZE_T_IN_STDDEF_H 1
+
+/* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in
+ <sys/types.h>. This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set
+ to 1. */
+#define HAVE_SIZE_T_IN_TYPES_H 1
+
+/* The type size_t is used to hold the size of an object. In
+ particular, an argument of this type is passed as the size argument
+ to the malloc and realloc functions. If size_t is not defined in
+ either <stddef.h> or <sys/types.h>, you may want to give it a
+ definition here. If you don't, the code will use unsigned. */
+#undef SIZE_T
+
+/* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in
+ <time.h>, as required by the ANSI C standard. */
+#define HAVE_TIME_T_IN_TIME_H 1
+
+/* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in
+ <sys/types.h>. This is ignored if HAVE_TIME_T_IN_TIME_H is set to
+ 1. */
+#define HAVE_TIME_T_IN_TYPES_H 1
+
+/* When Taylor UUCP is talking to another instance of itself, it will
+ tell the other side the size of a file before it is transferred.
+ If the package can determine how much disk space is available, it
+ will use this information to avoid filling up the disk. Define one
+ of the following macros to tell the code how to determine the
+ amount of available disk space. It is possible that none of these
+ are appropriate; it will do no harm to use none of them, but, of
+ course, nothing will then prevent the package from filling up the
+ disk. Note that this space check is only useful when talking to
+ another instance of Taylor UUCP.
+
+ STAT_STATVFS statvfs function
+ STAT_STATFS2_BSIZE two argument statfs function with f_bsize field
+ STAT_STATFS2_FSIZE two argument statfs function with f_fsize field
+ STAT_STATFS2_FS_DATA two argument statfs function with fd_req field
+ STAT_STATFS4 four argument statfs function
+ STAT_USTAT the ustat function with 512 byte blocks. */
+#define STAT_STATVFS 0
+#define STAT_STATFS2_BSIZE 0
+#define STAT_STATFS2_FSIZE 1
+#define STAT_STATFS2_FS_DATA 0
+#define STAT_STATFS4 0
+#define STAT_USTAT 0
+
+/* Set HAVE_VOID to 1 if the compiler supports declaring functions with
+ a return type of void and casting values to void. */
+#define HAVE_VOID 1
+
+/* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned
+ char. */
+#define HAVE_UNSIGNED_CHAR 1
+
+/* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in <errno.h>. */
+#define HAVE_ERRNO_DECLARATION 1
+
+/* There are now a number of functions to check for. For each of
+ these, the macro HAVE_FUNC should be set to 1 if your system has
+ FUNC. For example, HAVE_VFPRINTF should be set to 1 if your system
+ has vfprintf, 0 otherwise. */
+
+/* Taylor UUCP will take advantage of the following functions if they
+ are available, but knows how to deal with their absence. */
+#define HAVE_VFPRINTF 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_LTRUNC 0
+#define HAVE_WAITPID 1
+#define HAVE_WAIT4 1
+#define HAVE_GLOB 1
+#define HAVE_SETREUID 1
+
+/* There are several functions which are replaced in the subdirectory
+ lib. If they are missing, the configure script will automatically
+ add them to lib/Makefile to force them to be recompiled. If you
+ are configuring by hand, you will have to do this yourself. The
+ string @LIBOBJS@ in lib/Makefile.in should be replaced by a list of
+ object files in lib/Makefile. The following comments tell you
+ which object file names to add (they are generally fairly obvious,
+ given that the file names have no more than six characters before
+ the period). */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to lib/Makefile. */
+#define HAVE_BSEARCH 1 /* bsrch.o */
+#define HAVE_GETLINE 0 /* getlin.o */
+#define HAVE_MEMCHR 1 /* memchr.o */
+#define HAVE_STRDUP 1 /* strdup.o */
+#define HAVE_STRSTR 1 /* strstr.o */
+#define HAVE_STRTOL 1 /* strtol.o */
+
+/* If neither of these functions exists, you should add bzero.o to
+ lib/Makefile. */
+#define HAVE_BZERO 1
+#define HAVE_MEMSET 1
+
+/* If neither of these functions exists, you should add memcmp.o to
+ lib/Makefile. */
+#define HAVE_MEMCMP 1
+#define HAVE_BCMP 1
+
+/* If neither of these functions exists, you should add memcpy.o to
+ lib/Makefile. */
+#define HAVE_MEMCPY 1
+#define HAVE_BCOPY 1
+
+/* If neither of these functions exists, you should add strcas.o to
+ lib/Makefile. */
+#define HAVE_STRCASECMP 1
+#define HAVE_STRICMP 0
+
+/* If neither of these functions exists, you should add strncs.o to
+ lib/Makefile. */
+#define HAVE_STRNCASECMP 1
+#define HAVE_STRNICMP 0
+
+/* If neither of these functions exists, you should add strchr.o to
+ lib/Makefile. */
+#define HAVE_STRCHR 1
+#define HAVE_INDEX 1
+
+/* If neither of these functions exists, you should add strrch.o to
+ lib/Makefile. */
+#define HAVE_STRRCHR 1
+#define HAVE_RINDEX 1
+
+/* There are also Unix specific functions which are replaced in the
+ subdirectory unix. If they are missing, the configure script will
+ automatically add them to unix/Makefile to force them to be
+ recompiled. If you are configuring by hand, you will have to do
+ this yourself. The string @UNIXOBJS@ in unix/Makefile.in should be
+ replaced by a list of object files in unix/Makefile. The following
+ comments tell you which object file names to add. */
+
+/* For each of these functions, if it does not exist, the indicated
+ object file should be added to unix/Makefile. */
+#define HAVE_OPENDIR 1 /* dirent.o */
+#define HAVE_DUP2 1 /* dup2.o */
+#define HAVE_FTW 0 /* ftw.o */
+#define HAVE_REMOVE 1 /* remove.o */
+#define HAVE_RENAME 1 /* rename.o */
+#define HAVE_STRERROR 1 /* strerr.o */
+
+/* The code needs to know how to create directories. If you have the
+ mkdir function, set HAVE_MKDIR to 1 and replace @UUDIR@ in
+ Makefile.in with '# ' (the configure script will set @UUDIR@
+ according to the variable UUDIR). Otherwise, set HAVE_MKDIR to 0,
+ remove @UUDIR@ from Makefile.in, set MKDIR_PROGRAM to the name of
+ the program which will create a directory named on the command line
+ (e.g., "/bin/mkdir"), and add mkdir.o to the @UNIXOBJS@ string in
+ unix/Makefile.in. */
+#define HAVE_MKDIR 1
+#define MKDIR_PROGRAM unused
+
+/* The code also needs to know how to remove directories. If you have
+ the rmdir function, set HAVE_RMDIR to 1. Otherwise, set
+ RMDIR_PROGRAM to the name of the program which will remove a
+ directory named on the command line (e.g., "/bin/rmdir") and add
+ rmdir.o to the @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_RMDIR 1
+#define RMDIR_PROGRAM unused
+
+/* The code needs to know to how to get the name of the current
+ directory. If getcwd is available it will be used, otherwise if
+ getwd is available it will be used. Otherwise, set PWD_PROGRAM to
+ the name of the program which will print the name of the current
+ working directory (e.g., "/bin/pwd") and add getcwd.o to the
+ @UNIXOBJS@ string in unix/Makefile.in. */
+#define HAVE_GETCWD 1
+#define HAVE_GETWD 1
+#define PWD_PROGRAM unused
+
+/* If you have either sigsetjmp or setret, it will be used instead of
+ setjmp. These functions will only be used if your system restarts
+ system calls after interrupts (see HAVE_RESTARTABLE_SYSCALLS,
+ below). */
+#define HAVE_SIGSETJMP 0
+#define HAVE_SETRET 0
+
+/* The code needs to know what function to use to set a signal
+ handler. If will try to use each of the following functions in
+ turn. If none are available, it will use signal, which is assumed
+ to always exist. */
+#define HAVE_SIGACTION 1
+#define HAVE_SIGVEC 1
+#define HAVE_SIGSET 0
+
+/* If the code is going to use sigvec (HAVE_SIGACTION is 0 and
+ HAVE_SIGVEC is 1), then HAVE_SIGVEC_SV_FLAGS must be set to 1 if
+ the sigvec structure contains the sv_flags field, or 0 if the
+ sigvec structure contains the sv_onstack field. If the code is not
+ going to use sigvec, it doesn't matter what this is set to. */
+#define HAVE_SIGVEC_SV_FLAGS 1
+
+/* The code will try to use each of the following functions in turn
+ when blocking signals from delivery. If none are available, a
+ relatively unimportant race condition will exist. */
+#define HAVE_SIGPROCMASK 1
+#define HAVE_SIGBLOCK 1
+#define HAVE_SIGHOLD 0
+
+/* If you have either of the following functions, it will be used to
+ determine the number of file descriptors which may be open.
+ Otherwise, the code will use OPEN_MAX if defined, then NOFILE if
+ defined, then 20. */
+#define HAVE_GETDTABLESIZE 1
+#define HAVE_SYSCONF 0
+
+/* The code will use one of the following functions when detaching
+ from a terminal. One of these must exist. */
+#define HAVE_SETPGRP 1
+#define HAVE_SETSID 1
+
+/* If you do not specify the local node name in the main configuration
+ file, Taylor UUCP will try to use each of the following functions
+ in turn. If neither is available, you must specify the local node
+ name in the configuration file. */
+#define HAVE_GETHOSTNAME 1
+#define HAVE_UNAME 0
+
+/* The code will try to use each of the following functions in turn to
+ determine the current time. If none are available, it will use
+ time, which is assumed to always exist. */
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_FTIME 0
+
+/* If neither gettimeofday nor ftime is available, the code will use
+ times (if available) to measure a span of time. See also the
+ discussion of TIMES_TICK in policy.h. */
+#define HAVE_TIMES 1
+
+/* When a chat script requests a pause of less than a second with \p,
+ Taylor UUCP will try to use each of the following functions in
+ turn. If none are available, it will sleep for a full second.
+ Also, the (non-portable) tstuu program requires either select or
+ poll. */
+#define HAVE_NAPMS 0
+#define HAVE_NAP 0
+#define HAVE_USLEEP 1
+#define HAVE_POLL 0
+#define HAVE_SELECT 1
+
+/* If the getgrent function is available, it will be used to determine
+ all the groups a user belongs to when checking file access
+ permissions. */
+#define HAVE_GETGRENT 1
+
+/* If the socket function is available, TCP support code will be
+ compiled in. */
+#define HAVE_SOCKET 1
+
+/* If the t_open function is available, TLI support code will be
+ compiled in. This may require adding a library, such as -lnsl or
+ -lxti, to the Makefile variables LIBS. */
+#define HAVE_T_OPEN 0
+
+/* That's the end of the list of the functions. Now there are a few
+ last miscellaneous items. */
+
+/* On some systems the following functions are declared in such a way
+ that the code cannot make a simple extern. On other systems, these
+ functions are not declared at all, and the extern is required. If
+ a declaration of the function, as shown, compiles on your system,
+ set the value to 1. Not all functions declared externally are
+ listed here, only the ones with which I have had trouble. */
+/* extern long times (); */
+#define TIMES_DECLARATION_OK 0
+/* extern struct passwd *getpwnam (); */
+#define GETPWNAM_DECLARATION_OK 1
+/* extern struct passwd *getpwuid (); */
+#define GETPWUID_DECLARATION_OK 0
+/* extern struct group *getgrent (); */
+#define GETGRENT_DECLARATION_OK 1
+
+/* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and
+ your setpgrp calls takes 2 arguments (on System V they generally
+ take no arguments). You can safely set this to 1 on System V,
+ provided the call will compile without any errors. */
+#define HAVE_BSD_PGRP 0
+
+/* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header
+ file <sys/wait.h>. */
+#define HAVE_UNION_WAIT 1
+
+/* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names
+ longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* If slow system calls are restarted after interrupts, set
+ HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION
+ is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and
+ SV_INTERRUPT is defined in <signal.h>. In both of these cases
+ system calls can be prevented from restarting. */
+#define HAVE_RESTARTABLE_SYSCALLS 1
+
+/* Some systems supposedly need the following macros to be defined.
+ These are handled by the configure script (it will turn #undef into
+ #define when appropriate, which is why the peculiar #ifndef #undef
+ construction is used). If you are configuring by hand, you may add
+ appropriate definitions here, or just add them to CFLAGS when
+ running make. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+#ifndef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+#ifndef _MINIX
+#undef _MINIX
+#endif
+#ifndef _POSIX_1_SOURCE
+#undef _POSIX_1_SOURCE
+#endif
diff --git a/gnu/libexec/uucp/common_sources/conn.c b/gnu/libexec/uucp/common_sources/conn.c
new file mode 100644
index 0000000..df35e82
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/conn.c
@@ -0,0 +1,552 @@
+/* conn.c
+ Connection routines for the Taylor UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char conn_rcsid[] = "$Id: conn.c,v 1.1 1993/08/04 19:30:39 jtc Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+
+static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ const char *zphone, boolean ftranslate));
+
+/* Create a new connection. This relies on system dependent functions
+ to set the qcmds and psysdep fields. If qport is NULL, it opens a
+ standard input port. */
+
+boolean
+fconn_init (qport, qconn)
+ struct uuconf_port *qport;
+ struct sconnection *qconn;
+{
+ qconn->qport = qport;
+ switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype)
+ {
+ case UUCONF_PORTTYPE_STDIN:
+ return fsysdep_stdin_init (qconn);
+ case UUCONF_PORTTYPE_MODEM:
+ return fsysdep_modem_init (qconn);
+ case UUCONF_PORTTYPE_DIRECT:
+ return fsysdep_direct_init (qconn);
+#if HAVE_TCP
+ case UUCONF_PORTTYPE_TCP:
+ return fsysdep_tcp_init (qconn);
+#endif
+#if HAVE_TLI
+ case UUCONF_PORTTYPE_TLI:
+ return fsysdep_tli_init (qconn);
+#endif
+ default:
+ ulog (LOG_ERROR, "Unknown port type");
+ return FALSE;
+ }
+}
+
+/* Connection dispatch routines. */
+
+/* Free a connection. */
+
+void
+uconn_free (qconn)
+ struct sconnection *qconn;
+{
+ (*qconn->qcmds->pufree) (qconn);
+}
+
+/* Lock a connection. */
+
+boolean
+fconn_lock (qconn, fin)
+ struct sconnection *qconn;
+ boolean fin;
+{
+ boolean (*pflock) P((struct sconnection *, boolean));
+
+ pflock = qconn->qcmds->pflock;
+ if (pflock == NULL)
+ return TRUE;
+ return (*pflock) (qconn, fin);
+}
+
+/* Unlock a connection. */
+
+boolean
+fconn_unlock (qconn)
+ struct sconnection *qconn;
+{
+ boolean (*pfunlock) P((struct sconnection *));
+
+ pfunlock = qconn->qcmds->pfunlock;
+ if (pfunlock == NULL)
+ return TRUE;
+ return (*pfunlock) (qconn);
+}
+
+/* Open a connection. */
+
+boolean
+fconn_open (qconn, ibaud, ihighbaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ long ihighbaud;
+ boolean fwait;
+{
+ boolean fret;
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_PORT))
+ {
+ char abspeed[20];
+
+ if (ibaud == (long) 0)
+ strcpy (abspeed, "default speed");
+ else
+ sprintf (abspeed, "speed %ld", ibaud);
+
+ if (qconn->qport == NULL)
+ ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)",
+ abspeed);
+ else if (qconn->qport->uuconf_zname == NULL)
+ ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)",
+ abspeed);
+ else
+ ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)",
+ qconn->qport->uuconf_zname, abspeed);
+ }
+#endif
+
+ /* If the system provides a range of baud rates, we select the
+ highest baud rate supported by the port. */
+ if (ihighbaud != 0 && qconn->qport != NULL)
+ {
+ struct uuconf_port *qport;
+
+ qport = qconn->qport;
+ ibaud = ihighbaud;
+ if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM)
+ {
+ if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0)
+ {
+ if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud)
+ ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud;
+ }
+ else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0)
+ ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
+ }
+ else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT)
+ {
+ if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0)
+ ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
+ }
+ }
+
+ /* This will normally be overridden by the port specific open
+ routine. */
+ if (qconn->qport == NULL)
+ ulog_device ("stdin");
+ else
+ ulog_device (qconn->qport->uuconf_zname);
+
+ fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait);
+
+ if (! fret)
+ ulog_device ((const char *) NULL);
+
+ return fret;
+}
+
+/* Close a connection. */
+
+boolean
+fconn_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ boolean fret;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection");
+
+ /* Don't report hangup signals while we're closing. */
+ fLog_sighup = FALSE;
+
+ fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess);
+
+ /* Make sure any signal reporting has been done before we set
+ fLog_sighup back to TRUE. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ fLog_sighup = TRUE;
+
+ ulog_device ((const char *) NULL);
+
+ return fret;
+}
+
+/* Reset the connection. */
+
+boolean
+fconn_reset (qconn)
+ struct sconnection *qconn;
+{
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection");
+
+ return (*qconn->qcmds->pfreset) (qconn);
+}
+
+/* Dial out on the connection. */
+
+boolean
+fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ struct uuconf_dialer sdialer;
+ enum tdialerfound tfound;
+ boolean (*pfdial) P((struct sconnection *, pointer,
+ const struct uuconf_system *, const char *,
+ struct uuconf_dialer *, enum tdialerfound *));
+
+ if (qdialer == NULL)
+ qdialer = &sdialer;
+ if (ptdialerfound == NULL)
+ ptdialerfound = &tfound;
+
+ qdialer->uuconf_zname = NULL;
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ pfdial = qconn->qcmds->pfdial;
+ if (pfdial == NULL)
+ return TRUE;
+ return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound);
+}
+
+/* Read data from the connection. */
+
+boolean
+fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ boolean fret;
+
+ fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout,
+ freport);
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_INCOMING))
+ udebug_buffer ("fconn_read: Read", zbuf, *pclen);
+ else if (FDEBUGGING (DEBUG_PORT))
+ ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen);
+#endif
+
+ return fret;
+}
+
+/* Write data to the connection. */
+
+boolean
+fconn_write (qconn, zbuf, clen)
+ struct sconnection *qconn;
+ const char *zbuf;
+ size_t clen;
+{
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_OUTGOING))
+ udebug_buffer ("fconn_write: Writing", zbuf, clen);
+ else if (FDEBUGGING (DEBUG_PORT))
+ ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen);
+#endif
+
+ return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen);
+}
+
+/* Read and write data. */
+
+boolean
+fconn_io (qconn, zwrite, pcwrite, zread, pcread)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t *pcwrite;
+ char *zread;
+ size_t *pcread;
+{
+ boolean fret;
+#if DEBUG > 1
+ size_t cwrite = *pcwrite;
+ size_t cread = *pcread;
+
+ if (cread == 0 || cwrite == 0)
+ ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu",
+ (unsigned long) cread, (unsigned long) cwrite);
+#endif
+
+#if DEBUG > 1
+ if (FDEBUGGING (DEBUG_OUTGOING))
+ udebug_buffer ("fconn_io: Writing", zwrite, cwrite);
+#endif
+
+ fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread);
+
+ DEBUG_MESSAGE4 (DEBUG_PORT,
+ "fconn_io: Wrote %lu of %lu, read %lu of %lu",
+ (unsigned long) *pcwrite, (unsigned long) cwrite,
+ (unsigned long) *pcread, (unsigned long) cread);
+
+#if DEBUG > 1
+ if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING))
+ udebug_buffer ("fconn_io: Read", zread, *pcread);
+#endif
+
+ return fret;
+}
+
+/* Send a break character to a connection. Some port types may not
+ support break characters, in which case we just return TRUE. */
+
+boolean
+fconn_break (qconn)
+ struct sconnection *qconn;
+{
+ boolean (*pfbreak) P((struct sconnection *));
+
+ pfbreak = *qconn->qcmds->pfbreak;
+ if (pfbreak == NULL)
+ return TRUE;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character");
+
+ return (*pfbreak) (qconn);
+}
+
+/* Change the setting of a connection. Some port types may not
+ support this, in which case we just return TRUE. */
+
+boolean
+fconn_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ boolean (*pfset) P((struct sconnection *, enum tparitysetting,
+ enum tstripsetting, enum txonxoffsetting));
+
+ pfset = qconn->qcmds->pfset;
+ if (pfset == NULL)
+ return TRUE;
+
+ DEBUG_MESSAGE3 (DEBUG_PORT,
+ "fconn_set: Changing setting to %d, %d, %d",
+ (int) tparity, (int) tstrip, (int) txonxoff);
+
+ return (*pfset) (qconn, tparity, tstrip, txonxoff);
+}
+
+/* Require or ignore carrier on a connection. */
+
+boolean
+fconn_carrier (qconn, fcarrier)
+ struct sconnection *qconn;
+ boolean fcarrier;
+{
+ boolean (*pfcarrier) P((struct sconnection *, boolean));
+
+ pfcarrier = qconn->qcmds->pfcarrier;
+ if (pfcarrier == NULL)
+ return TRUE;
+ return (*pfcarrier) (qconn, fcarrier);
+}
+
+/* Run a chat program on a connection. */
+
+boolean
+fconn_run_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ return (*qconn->qcmds->pfchat) (qconn, pzprog);
+}
+
+/* Get the baud rate of a connection. */
+
+long
+iconn_baud (qconn)
+ struct sconnection *qconn;
+{
+ long (*pibaud) P((struct sconnection *));
+
+ pibaud = qconn->qcmds->pibaud;
+ if (pibaud == NULL)
+ return 0;
+ return (*pibaud) (qconn);
+}
+
+/* Modem dialing routines. */
+
+/*ARGSUSED*/
+boolean
+fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ {
+ char **pz;
+ boolean ffirst;
+
+ /* The pzdialer field is a sequence of dialer/token pairs. The
+ dialer portion names a dialer to use. The token portion is
+ what \D and \T in the chat script expand to. If there is no
+ token for the last dialer, the phone number for the system is
+ used. */
+ ffirst = TRUE;
+ pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer;
+ while (*pz != NULL)
+ {
+ int iuuconf;
+ struct uuconf_dialer *q;
+ struct uuconf_dialer s;
+ const char *ztoken;
+ boolean ftranslate;
+
+ if (! ffirst)
+ q = &s;
+ else
+ q = qdialer;
+
+ iuuconf = uuconf_dialer_info (puuconf, *pz, q);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ulog (LOG_ERROR, "%s: Dialer not found", *pz);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+
+ ++pz;
+ ztoken = *pz;
+
+ ftranslate = FALSE;
+ if (ztoken == NULL
+ || strcmp (ztoken, "\\D") == 0)
+ ztoken = zphone;
+ else if (strcmp (ztoken, "\\T") == 0)
+ {
+ ztoken = zphone;
+ ftranslate = TRUE;
+ }
+
+ if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate))
+ {
+ (void) uuconf_dialer_free (puuconf, q);
+ if (! ffirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+ return FALSE;
+ }
+
+ if (ffirst)
+ {
+ *ptdialerfound = DIALERFOUND_FREE;
+ ffirst = FALSE;
+ }
+ else
+ (void) uuconf_dialer_free (puuconf, q);
+
+ if (*pz != NULL)
+ ++pz;
+ }
+
+ return TRUE;
+ }
+ else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL)
+ {
+ struct uuconf_dialer *q;
+
+ q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
+ *qdialer = *q;
+ *ptdialerfound = DIALERFOUND_TRUE;
+ return fcdo_dial (qconn, puuconf, q, zphone, FALSE);
+ }
+ else
+ {
+ ulog (LOG_ERROR, "No dialer information");
+ return FALSE;
+ }
+}
+
+/* Actually use a dialer. We set up the modem (which may include
+ opening the dialer device), run the chat script, and finish dealing
+ with the modem. */
+
+static boolean
+fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdial;
+ const char *zphone;
+ boolean ftranslate;
+{
+ const char *zname;
+
+ if (! fsysdep_modem_begin_dial (qconn, qdial))
+ return FALSE;
+
+ if (qconn->qport == NULL)
+ zname = NULL;
+ else
+ zname = qconn->qport->uuconf_zname;
+
+ if (! fchat (qconn, puuconf, &qdial->uuconf_schat,
+ (const struct uuconf_system *) NULL, qdial,
+ zphone, ftranslate, zname, iconn_baud (qconn)))
+ return FALSE;
+
+ return fsysdep_modem_end_dial (qconn, qdial);
+}
diff --git a/gnu/libexec/uucp/common_sources/conn.h b/gnu/libexec/uucp/common_sources/conn.h
new file mode 100644
index 0000000..59d4881
--- /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 0000000..6956bb3
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/copy.c
@@ -0,0 +1,202 @@
+/* copy.c
+ Copy one file to another for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char copy_rcsid[] = "$Id: copy.c,v 1.1 1993/08/04 19:30:44 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+/* Copy one file to another. */
+
+#if USE_STDIO
+
+boolean
+fcopy_file (zfrom, zto, fpublic, fmkdirs)
+ const char *zfrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ FILE *efrom;
+ boolean fret;
+
+ efrom = fopen (zfrom, BINREAD);
+ if (efrom == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zfrom, strerror (errno));
+ return FALSE;
+ }
+
+ fret = fcopy_open_file (efrom, zto, fpublic, fmkdirs);
+ (void) fclose (efrom);
+ return fret;
+}
+
+boolean
+fcopy_open_file (efrom, zto, fpublic, fmkdirs)
+ FILE *efrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ FILE *eto;
+ char ab[8192];
+ int c;
+
+ eto = esysdep_fopen (zto, fpublic, FALSE, fmkdirs);
+ if (eto == NULL)
+ return FALSE;
+
+ while ((c = fread (ab, sizeof (char), sizeof ab, efrom)) != 0)
+ {
+ if (fwrite (ab, sizeof (char), (size_t) c, eto) != c)
+ {
+ ulog (LOG_ERROR, "fwrite: %s", strerror (errno));
+ (void) fclose (eto);
+ (void) remove (zto);
+ return FALSE;
+ }
+ }
+
+ if (fclose (eto) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#else /* ! USE_STDIO */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+boolean
+fcopy_file (zfrom, zto, fpublic, fmkdirs)
+ const char *zfrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ int ofrom;
+ boolean fret;
+
+ ofrom = open (zfrom, O_RDONLY | O_NOCTTY, 0);
+ if (ofrom < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfrom, strerror (errno));
+ return FALSE;
+ }
+
+ fret = fcopy_open_file (ofrom, zto, fpublic, fmkdirs);
+ (void) close (ofrom);
+ return fret;
+}
+
+boolean
+fcopy_open_file (ofrom, zto, fpublic, fmkdirs)
+ int ofrom;
+ const char *zto;
+ boolean fpublic;
+ boolean fmkdirs;
+{
+ int oto;
+ char ab[8192];
+ int c;
+
+ /* These file mode arguments are from the UNIX version of sysdep.h;
+ each system dependent header file will need their own
+ definitions. */
+ oto = creat (zto, fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE);
+ if (oto < 0)
+ {
+ if (errno == ENOENT && fmkdirs)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ return FALSE;
+ oto = creat (zto,
+ fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE);
+ }
+ if (oto < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zto, strerror (errno));
+ return FALSE;
+ }
+ }
+
+ while ((c = read (ofrom, ab, sizeof ab)) > 0)
+ {
+ if (write (oto, ab, (size_t) c) != c)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ (void) close (oto);
+ (void) remove (zto);
+ return FALSE;
+ }
+ }
+
+ if (close (oto) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ if (c < 0)
+ {
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ (void) remove (zto);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* ! USE_STDIO */
diff --git a/gnu/libexec/uucp/common_sources/cu.h b/gnu/libexec/uucp/common_sources/cu.h
new file mode 100644
index 0000000..5a514ee
--- /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 0000000..1a70e02
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/getopt.h
@@ -0,0 +1,120 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file was modified slightly by Ian Lance Taylor, November 1992,
+ for Taylor UUCP. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ian Lance Taylor <ian@airs.com> added the following defines for
+ Taylor UUCP. This avoids reported conflicts with system getopt
+ definitions. */
+#define getopt gnu_getopt
+#define optarg gnu_optarg
+#define optind gnu_optind
+#define opterr gnu_opterr
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+ const char *name;
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+enum _argtype
+{
+ no_argument,
+ required_argument,
+ optional_argument
+};
+
+extern int getopt P((int argc, char *const *argv, const char *shortopts));
+extern int getopt_long P((int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind));
+extern int getopt_long_only P((int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind));
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal P((int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/libexec/uucp/common_sources/log.c b/gnu/libexec/uucp/common_sources/log.c
new file mode 100644
index 0000000..b55ca8b
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/log.c
@@ -0,0 +1,699 @@
+/* log.c
+ Routines to add entries to the log files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char log_rcsid[] = "$Id: log.c,v 1.1 1993/08/04 19:30:50 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+#if ANSI_C
+#include <stdarg.h>
+#endif
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+
+/* Local functions. */
+
+static const char *zldate_and_time P((void));
+
+/* Log file name. */
+static const char *zLogfile;
+
+/* The function to call when a LOG_FATAL error occurs. */
+static void (*pfLfatal) P((void));
+
+/* Whether to go to a file. */
+static boolean fLfile;
+
+/* ID number. */
+static int iLid;
+
+/* The current user name. */
+static char *zLuser;
+
+/* The current system name. */
+static char *zLsystem;
+
+/* The current device name. */
+char *zLdevice;
+
+/* The open log file. */
+static FILE *eLlog;
+
+/* Whether we have tried to open the log file. We need this because
+ we don't want to keep trying to open the log file if we failed the
+ first time. It can't be static because under HAVE_HDB_LOGGING we
+ may have to write to various different log files. */
+static boolean fLlog_tried;
+
+#if DEBUG > 1
+/* Debugging file name. */
+static const char *zLdebugfile;
+
+/* The open debugging file. */
+static FILE *eLdebug;
+
+/* Whether we've tried to open the debugging file. */
+static boolean fLdebug_tried;
+
+/* Whether we've written out any debugging information. */
+static boolean fLdebugging;
+#endif
+
+/* Statistics file name. */
+static const char *zLstatsfile;
+
+/* The open statistics file. */
+static FILE *eLstats;
+
+/* Whether we've tried to open the statistics file. */
+static boolean fLstats_tried;
+
+/* The array of signals. The elements are only set to TRUE by the
+ default signal handler. They are only set to FALSE if we don't
+ care whether we got the signal or not. */
+volatile sig_atomic_t afSignal[INDEXSIG_COUNT];
+
+/* The array of signals to log. The elements are only set to TRUE by
+ the default signal handler. They are set to FALSE when the signal
+ is logged in ulog. This means that if a signal comes in at just
+ the right time we won't log it (or, rather, we'll log it once
+ instead of twice), but that is not a catatrophe. */
+volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
+
+/* Flag that indicates SIGHUP is worth logging. */
+boolean fLog_sighup = TRUE;
+
+/* Signal names to use when logging signals. */
+static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES;
+
+/* If not NULL, ulog calls this function before outputting anything.
+ This is used to support cu. */
+void (*pfLstart) P((void));
+
+/* If not NULL, ulog calls this function after outputting everything.
+ This is used to support cu. */
+void (*pfLend) P((void));
+
+/* Set the function to call on a LOG_FATAL error. */
+
+void
+ulog_fatal_fn (pfn)
+ void (*pfn) P((void));
+{
+ pfLfatal = pfn;
+}
+
+/* Decide whether to send log message to the file or not. */
+
+void
+ulog_to_file (puuconf, ffile)
+ pointer puuconf;
+ boolean ffile;
+{
+ int iuuconf;
+
+ iuuconf = uuconf_logfile (puuconf, &zLogfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+#if DEBUG > 1
+ iuuconf = uuconf_debugfile (puuconf, &zLdebugfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+#endif
+
+ iuuconf = uuconf_statsfile (puuconf, &zLstatsfile);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ fLfile = ffile;
+}
+
+/* Set the ID number. This will be called by the usysdep_initialize
+ if there is something sensible to set it to. */
+
+void
+ulog_id (i)
+ int i;
+{
+ iLid = i;
+}
+
+/* Set the user we are making log entries for. The arguments will be
+ copied into memory. */
+
+void
+ulog_user (zuser)
+ const char *zuser;
+{
+ ubuffree (zLuser);
+ zLuser = zbufcpy (zuser);
+}
+
+/* Set the system name we are making log entries for. The name is copied
+ into memory. */
+
+void
+ulog_system (zsystem)
+ const char *zsystem;
+{
+ if (zsystem == NULL
+ || zLsystem == NULL
+ || strcmp (zsystem, zLsystem) != 0)
+ {
+ ubuffree (zLsystem);
+ zLsystem = zbufcpy (zsystem);
+#if HAVE_HDB_LOGGING
+ /* Under HDB logging we now must write to a different log file. */
+ ulog_close ();
+#endif /* HAVE_HDB_LOGGING */
+ }
+}
+
+/* Set the device name. This is copied into memory. */
+
+void
+ulog_device (zdevice)
+ const char *zdevice;
+{
+ ubuffree (zLdevice);
+ zLdevice = zbufcpy (zdevice);
+}
+
+/* Make a log entry. We make a token concession to non ANSI_C systems,
+ but it clearly won't always work. */
+
+#if ! ANSI_C
+#undef HAVE_VFPRINTF
+#endif
+
+/*VARARGS2*/
+#if HAVE_VFPRINTF
+void
+ulog (enum tlog ttype, const char *zmsg, ...)
+#else
+void
+ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
+ enum tlog ttype;
+ const char *zmsg;
+#endif
+{
+#if HAVE_VFPRINTF
+ va_list parg;
+#endif
+ FILE *e, *edebug;
+ boolean fstart, fend;
+ const char *zhdr, *zstr;
+
+ /* Log any received signal. We do it this way to avoid calling ulog
+ from the signal handler. A few routines call ulog to get this
+ message out with zmsg == NULL. */
+ {
+ static boolean fdoing_sigs;
+
+ if (! fdoing_sigs)
+ {
+ int isig;
+
+ fdoing_sigs = TRUE;
+ for (isig = 0; isig < INDEXSIG_COUNT; isig++)
+ {
+ if (afLog_signal[isig])
+ {
+ afLog_signal[isig] = FALSE;
+
+ /* Apparently SunOS sends SIGINT rather than SIGHUP
+ when hanging up, so we don't log either signal if
+ fLog_sighup is FALSE. */
+ if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT)
+ || fLog_sighup)
+ ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]);
+ }
+ }
+ fdoing_sigs = FALSE;
+ }
+ }
+
+ if (zmsg == NULL)
+ return;
+
+#if DEBUG > 1
+ /* If we've had a debugging file open in the past, then we want to
+ write all log file entries to the debugging file even if it's
+ currently closed. */
+ if (fLfile
+ && eLdebug == NULL
+ && ! fLdebug_tried
+ && (fLdebugging || (int) ttype >= (int) LOG_DEBUG))
+ {
+ fLdebug_tried = TRUE;
+ eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE);
+ fLdebugging = TRUE;
+ }
+#endif /* DEBUG > 1 */
+
+ if (! fLfile)
+ e = stderr;
+#if DEBUG > 1
+ else if ((int) ttype >= (int) LOG_DEBUG)
+ {
+ e = eLdebug;
+
+ /* If we can't open the debugging file, don't output any
+ debugging messages. */
+ if (e == NULL)
+ return;
+ }
+#endif /* DEBUG > 1 */
+ else
+ {
+ if (eLlog == NULL && ! fLlog_tried)
+ {
+ fLlog_tried = TRUE;
+#if ! HAVE_HDB_LOGGING
+ eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE);
+#else /* HAVE_HDB_LOGGING */
+ {
+ const char *zsys;
+ char *zfile;
+
+ /* We want to write to .Log/program/system, e.g.
+ .Log/uucico/uunet. The system name may not be set. */
+ if (zLsystem == NULL)
+ zsys = "ANY";
+ else
+ zsys = zLsystem;
+
+ zfile = zbufalc (strlen (zLogfile)
+ + strlen (abProgram)
+ + strlen (zsys)
+ + 1);
+ sprintf (zfile, zLogfile, abProgram, zsys);
+ eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE);
+ ubuffree (zfile);
+ }
+#endif /* HAVE_HDB_LOGGING */
+
+ if (eLlog == NULL)
+ {
+ /* We can't open the log file. We don't even have a
+ safe way to report this problem, since we may not be
+ able to write to stderr (it may, for example, be
+ attached to the incoming call). */
+ if (pfLfatal != NULL)
+ (*pfLfatal) ();
+ usysdep_exit (FALSE);
+ }
+ }
+
+ e = eLlog;
+
+ /* eLlog might be NULL here because we might try to open the log
+ file recursively via esysdep_fopen. */
+ if (e == NULL)
+ return;
+ }
+
+ if (pfLstart != NULL)
+ (*pfLstart) ();
+
+ edebug = NULL;
+#if DEBUG > 1
+ if ((int) ttype < (int) LOG_DEBUG)
+ edebug = eLdebug;
+#endif
+
+ fstart = TRUE;
+ fend = TRUE;
+
+ switch (ttype)
+ {
+ case LOG_NORMAL:
+ zhdr = "";
+ break;
+ case LOG_ERROR:
+ zhdr = "ERROR: ";
+ break;
+ case LOG_FATAL:
+ zhdr = "FATAL: ";
+ break;
+#if DEBUG > 1
+ case LOG_DEBUG:
+ zhdr = "DEBUG: ";
+ break;
+ case LOG_DEBUG_START:
+ zhdr = "DEBUG: ";
+ fend = FALSE;
+ break;
+ case LOG_DEBUG_CONTINUE:
+ zhdr = NULL;
+ fstart = FALSE;
+ fend = FALSE;
+ break;
+ case LOG_DEBUG_END:
+ zhdr = NULL;
+ fstart = FALSE;
+ break;
+#endif
+ default:
+ zhdr = "???: ";
+ break;
+ }
+
+ if (fstart)
+ {
+ if (! fLfile)
+ {
+ fprintf (e, "%s: ", abProgram);
+ if (edebug != NULL)
+ fprintf (edebug, "%s: ", abProgram);
+ }
+ else
+ {
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, "%s ", abProgram);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", abProgram);
+#else /* ! HAVE_TAYLOR_LOGGING */
+ fprintf (e, "%s ", zLuser == NULL ? "uucp" : zLuser);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLuser == NULL ? "uucp" : zLuser);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+ fprintf (e, "%s ", zLsystem == NULL ? "-" : zLsystem);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLsystem == NULL ? "-" : zLsystem);
+
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, "%s ", zLuser == NULL ? "-" : zLuser);
+ if (edebug != NULL)
+ fprintf (edebug, "%s ", zLuser == NULL ? "-" : zLuser);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+ zstr = zldate_and_time ();
+ fprintf (e, "(%s", zstr);
+ if (edebug != NULL)
+ fprintf (edebug, "(%s", zstr);
+
+ if (iLid != 0)
+ {
+#if ! HAVE_HDB_LOGGING
+#if HAVE_TAYLOR_LOGGING
+ fprintf (e, " %d", iLid);
+ if (edebug != NULL)
+ fprintf (edebug, " %d", iLid);
+#else /* ! HAVE_TAYLOR_LOGGING */
+ fprintf (e, "-%d", iLid);
+ if (edebug != NULL)
+ fprintf (edebug, "-%d", iLid);
+#endif /* ! HAVE_TAYLOR_LOGGING */
+#else /* HAVE_HDB_LOGGING */
+
+ /* I assume that the second number here is meant to be
+ some sort of file sequence number, and that it should
+ correspond to the sequence number in the statistics
+ file. I don't have any really convenient way to do
+ this, so I won't unless somebody thinks it's very
+ important. */
+ fprintf (e, ",%d,%d", iLid, 0);
+ if (edebug != NULL)
+ fprintf (edebug, ",%d,%d", iLid, 0);
+#endif /* HAVE_HDB_LOGGING */
+ }
+
+ fprintf (e, ") ");
+ if (edebug != NULL)
+ fprintf (edebug, ") ");
+
+ fprintf (e, "%s", zhdr);
+ if (edebug != NULL)
+ fprintf (edebug, "%s", zhdr);
+ }
+ }
+
+#if HAVE_VFPRINTF
+ va_start (parg, zmsg);
+ vfprintf (e, zmsg, parg);
+ va_end (parg);
+ if (edebug != NULL)
+ {
+ va_start (parg, zmsg);
+ vfprintf (edebug, zmsg, parg);
+ va_end (parg);
+ }
+#else /* ! HAVE_VFPRINTF */
+ fprintf (e, zmsg, a, b, c, d, f, g, h, i, j);
+ if (edebug != NULL)
+ fprintf (edebug, zmsg, a, b, c, d, f, g, h, i, j);
+#endif /* ! HAVE_VFPRINTF */
+
+ if (fend)
+ {
+ fprintf (e, "\n");
+ if (edebug != NULL)
+ fprintf (edebug, "\n");
+ }
+
+ (void) fflush (e);
+ if (edebug != NULL)
+ (void) fflush (edebug);
+
+ if (pfLend != NULL)
+ (*pfLend) ();
+
+ if (ttype == LOG_FATAL)
+ {
+ if (pfLfatal != NULL)
+ (*pfLfatal) ();
+ usysdep_exit (FALSE);
+ }
+
+#if CLOSE_LOGFILES
+ ulog_close ();
+#endif
+}
+
+/* Log a uuconf error. */
+
+void
+ulog_uuconf (ttype, puuconf, iuuconf)
+ enum tlog ttype;
+ pointer puuconf;
+ int iuuconf;
+{
+ char ab[512];
+
+ (void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab);
+ ulog (ttype, "%s", ab);
+}
+
+/* Close the log file. There's nothing useful we can do with errors,
+ so we don't check for them. */
+
+void
+ulog_close ()
+{
+ /* Make sure we logged any signal we received. */
+ ulog (LOG_ERROR, (const char *) NULL);
+
+ if (eLlog != NULL)
+ {
+ (void) fclose (eLlog);
+ eLlog = NULL;
+ fLlog_tried = FALSE;
+ }
+
+#if DEBUG > 1
+ if (eLdebug != NULL)
+ {
+ (void) fclose (eLdebug);
+ eLdebug = NULL;
+ fLdebug_tried = FALSE;
+ }
+#endif
+}
+
+/* Add an entry to the statistics file. We may eventually want to put
+ failed file transfers in here, but we currently do not. */
+
+/*ARGSUSED*/
+void
+ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster)
+ boolean fsucceeded;
+ const char *zuser;
+ const char *zsystem;
+ boolean fsent;
+ long cbytes;
+ long csecs;
+ long cmicros;
+ boolean fmaster;
+{
+ long cbps;
+
+ /* The seconds and microseconds are now counted independently, so
+ they may be out of synch. */
+ if (cmicros < 0)
+ {
+ csecs -= ((- cmicros) / 1000000L) + 1;
+ cmicros = 1000000L - ((- cmicros) % 1000000L);
+ }
+ if (cmicros >= 1000000L)
+ {
+ csecs += cmicros / 10000000L;
+ cmicros = cmicros % 1000000L;
+ }
+
+ /* On a system which can determine microseconds we might very well
+ have both csecs == 0 and cmicros == 0. */
+ if (csecs == 0 && cmicros < 1000)
+ cbps = 0;
+ else
+ {
+ long cmillis;
+
+ /* This computation will not overflow provided csecs < 2147483
+ and cbytes and cbps both fit in a long. */
+ cmillis = csecs * 1000 + cmicros / 1000;
+ cbps = ((cbytes / cmillis) * 1000
+ + ((cbytes % cmillis) * 1000) / cmillis);
+ }
+
+ if (eLstats == NULL)
+ {
+ if (fLstats_tried)
+ return;
+ fLstats_tried = TRUE;
+ eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE);
+ if (eLstats == NULL)
+ return;
+ }
+
+#if HAVE_TAYLOR_LOGGING
+ fprintf (eLstats,
+ "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec)\n",
+ zuser, zsystem, zldate_and_time (),
+ fsucceeded ? "" : "failed after ",
+ fsent ? "sent" : "received",
+ cbytes, csecs, cmicros / 1000, cbps);
+#endif /* HAVE_TAYLOR_LOGGING */
+#if HAVE_V2_LOGGING
+ fprintf (eLstats,
+ "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n",
+ zuser, zsystem, zldate_and_time (),
+ (long) time ((time_t *) NULL),
+ fsent ? "sent" : "received",
+ fsucceeded ? "data" : "failed after",
+ cbytes, csecs + cmicros / 500000);
+#endif /* HAVE_V2_LOGGING */
+#if HAVE_HDB_LOGGING
+ {
+ static int iseq;
+
+ /* I don't know what the 'C' means. The sequence number should
+ probably correspond to the sequence number in the log file, but
+ that is currently always 0; using this fake sequence number
+ will still at least reveal which transfers are from different
+ calls. We don't report a failed data transfer with this
+ format. */
+ if (! fsucceeded)
+ return;
+ ++iseq;
+ fprintf (eLstats,
+ "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld %s\n",
+ zsystem, zuser, fmaster ? 'M' : 'S', zldate_and_time (),
+ iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
+ fsent ? "->" : "<-",
+ cbytes, csecs, cmicros / 1000, cbps,
+ "bytes/sec");
+ }
+#endif /* HAVE_HDB_LOGGING */
+
+ (void) fflush (eLstats);
+
+#if CLOSE_LOGFILES
+ ustats_close ();
+#endif
+}
+
+/* Close the statistics file. */
+
+void
+ustats_close ()
+{
+ if (eLstats != NULL)
+ {
+ if (fclose (eLstats) != 0)
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ eLstats = NULL;
+ fLstats_tried = FALSE;
+ }
+}
+
+/* Return the date and time in a form used for a log entry. */
+
+static const char *
+zldate_and_time ()
+{
+ long isecs, imicros;
+ struct tm s;
+#if HAVE_TAYLOR_LOGGING
+ static char ab[sizeof "1991-12-31 12:00:00.00"];
+#endif
+#if HAVE_V2_LOGGING
+ static char ab[sizeof "12/31-12:00"];
+#endif
+#if HAVE_HDB_LOGGING
+ static char ab[sizeof "12/31-12:00:00"];
+#endif
+
+ isecs = ixsysdep_time (&imicros);
+ usysdep_localtime (isecs, &s);
+
+#if HAVE_TAYLOR_LOGGING
+ sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d",
+ s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour,
+ s.tm_min, s.tm_sec, (int) (imicros / 10000));
+#endif
+#if HAVE_V2_LOGGING
+ sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday,
+ s.tm_hour, s.tm_min);
+#endif
+#if HAVE_HDB_LOGGING
+ sprintf (ab, "%d/%d-%02d:%02d:%02d", s.tm_mon + 1, s.tm_mday,
+ s.tm_hour, s.tm_min, s.tm_sec);
+#endif
+
+ return ab;
+}
diff --git a/gnu/libexec/uucp/common_sources/policy.h b/gnu/libexec/uucp/common_sources/policy.h
new file mode 100644
index 0000000..4c829bf
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/policy.h
@@ -0,0 +1,521 @@
+/* policy.h
+ Configuration file for policy decisions. To be edited on site.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* This header file contains macro definitions which must be set by
+ each site before compilation. The first few are system
+ characteristics that can not be easily discovered by the
+ configuration script. Most are configuration decisions that must
+ be made by the local administrator. */
+
+/* System characteristics. */
+
+/* This code tries to use several ANSI C features, including
+ prototypes, stdarg.h, the const qualifier and the types void
+ (including void * pointers) and unsigned char. By default it will
+ use these features if the compiler defines __STDC__. If your
+ compiler supports these features but does not define __STDC__, you
+ should set ANSI_C to 1. If your compiler does not support these
+ features but defines __STDC__ (no compiler should do this, in my
+ opinion), you should set ANSI_C to 0. In most cases (or if you're
+ not sure) just leave the line below commented out. */
+/* #define ANSI_C 1 */
+
+/* Set USE_STDIO to 1 if data files should be read using the stdio
+ routines (fopen, fread, etc.) rather than the UNIX unbuffered I/O
+ calls (open, read, etc.). Unless you know your stdio is really
+ rotten, you should leave this as 1. */
+#define USE_STDIO 1
+
+/* Exactly one of the following macros must be set to 1. Many modern
+ systems support more than one of these choices through some form of
+ compilation environment, in which case the setting will depend on
+ the compilation environment you use. If you have a reasonable
+ choice between options, I suspect that TERMIO or TERMIOS will be
+ more efficient than TTY, but I have not done any head to head
+ comparisons.
+
+ If you don't set any of these macros, the code below will guess.
+ It will doubtless be wrong on some systems.
+
+ HAVE_BSD_TTY -- Use the 4.2BSD tty routines
+ HAVE_SYSV_TERMIO -- Use the System V termio routines
+ HAVE_POSIX_TERMIOS -- Use the POSIX termios routines
+ */
+#define HAVE_BSD_TTY 0
+#define HAVE_SYSV_TERMIO 0
+#define HAVE_POSIX_TERMIOS 1
+
+/* This code tries to guess which terminal driver to use if you did
+ not make a choice above. It is in this file to make it easy to
+ figure out what's happening if something goes wrong. */
+
+#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS == 0
+#if HAVE_CBREAK
+#undef HAVE_BSD_TTY
+#define HAVE_BSD_TTY 1
+#else
+#undef HAVE_SYSV_TERMIO
+#define HAVE_SYSV_TERMIO 1
+#endif
+#endif
+
+/* On some systems a write to a serial port will block even if the
+ file descriptor has been set to not block. File transfer can be
+ more efficient if the package knows that a write to the serial port
+ will not block; however, if the write does block unexpectedly then
+ data loss is possible at high speeds.
+
+ If writes to a serial port always block even when requested not to,
+ you should set HAVE_UNBLOCKED_WRITES to 0; otherwise you should set
+ it to 1. In general on System V releases without STREAMS-based
+ ttys (e.g., before SVR4) HAVE_UNBLOCKED_WRITES should be 0 and on
+ BSD or SVR4 it should be 1.
+
+ If HAVE_UNBLOCKED_WRITES is set to 1 when it should be 0 you may
+ see an unexpectedly large number of transmission errors, or, if you
+ have hardware handshaking, transfer times may be lower than
+ expected (but then, they always are). If HAVE_UNBLOCKED_WRITES is
+ set to 0 when it should be 1, file transfer will use more CPU time
+ than necessary. If you are unsure, setting HAVE_UNBLOCKED_WRITES
+ to 0 should always be safe. */
+#define HAVE_UNBLOCKED_WRITES 1
+
+/* When the code does do a blocking write, it wants to write the
+ largest amount of data which the kernel will accept as a single
+ unit. On BSD this is typically the value of OBUFSIZ in
+ <sys/tty.h>, usually 100. On System V before SVR4 this is
+ typically the size of a clist, CLSIZE in <sys/tty.h>, which is
+ usually 64. On SVR4, which uses STREAMS-based ttys, 2048 is
+ reasonable. Define SINGLE_WRITE to the correct value for your
+ system. If SINGLE_WRITE is too large, data loss may occur. If
+ SINGLE_WRITE is too small, file transfer will use more CPU time
+ than necessary. If you have no idea, 64 should work on most modern
+ systems. */
+#define SINGLE_WRITE 100
+
+/* Some tty drivers, such as those from SCO and AT&T's Unix PC, have a
+ bug in the implementation of ioctl() that causes CLOCAL to be
+ ineffective until the port is opened a second time. If
+ HAVE_CLOCAL_BUG is set to 1, code will be added to do this second
+ open on the port. Set this if you are getting messages that say
+ "Line disconnected" while in the dial chat script after only
+ writing the first few characters to the port. This bug causes the
+ resetting of CLOCAL to have no effect, so the "\m" (require
+ carrier) escape sequence won't function properly in dialer chat
+ scripts. */
+#define HAVE_CLOCAL_BUG 0
+
+/* On some systems, such as SCO Xenix, resetting DTR on a port
+ apparently prevents getty from working on the port, and thus
+ prevents anybody from dialing in. If HAVE_RESET_BUG is set to 1,
+ DTR will not be reset when a serial port is closed. */
+#define HAVE_RESET_BUG 0
+
+/* The Sony NEWS reportedly handles no parity by clearing both the odd
+ and even parity bits in the sgtty structure, unlike most BSD based
+ systems in which no parity is indicated by setting both the odd and
+ even parity bits. Setting HAVE_PARITY_BUG to 1 will handle this
+ correctly. */
+#define HAVE_PARITY_BUG 0
+
+#if HAVE_BSD_TTY
+#ifdef sony
+#undef HAVE_PARITY_BUG
+#define HAVE_PARITY_BUG 1
+#endif
+#endif
+
+/* On Ultrix 4.0, at least, setting CBREAK causes input characters to
+ be stripped, regardless of the setting of LPASS8 and LLITOUT. This
+ can be worked around by using the termio call to reset ISTRIP.
+ This probably does not apply to any other operating system.
+ Setting HAVE_STRIP_BUG to 1 will use this workaround. */
+#define HAVE_STRIP_BUG 0
+
+#if HAVE_BSD_TTY
+#ifdef ultrix
+#undef HAVE_STRIP_BUG
+#define HAVE_STRIP_BUG 1
+#endif
+#endif
+
+/* TIMES_TICK is the fraction of a second which times(2) returns (for
+ example, if times returns 100ths of a second TIMES_TICK should be
+ set to 100). On a true POSIX system (one which has the sysconf
+ function and also has _SC_CLK_TCK defined in <unistd.h>) TIMES_TICK
+ may simply be left as 0. On some systems the environment variable
+ HZ is what you want for TIMES_TICK, but on some other systems HZ
+ has the wrong value; check the man page. If you leave this set to
+ 0, the code will try to guess; it will doubtless be wrong on some
+ non-POSIX systems. If TIMES_TICK is wrong the code may report
+ incorrect file transfer times in the statistics file, but on many
+ systems times(2) will actually not be used and this value will not
+ matter at all. */
+#define TIMES_TICK 0
+
+/* If your system does not support saved set user ID, set
+ HAVE_SAVED_SETUID to 0. However, this is ignored if your system
+ has the setreuid function. Most modern Unixes have one or the
+ other. If your system has the setreuid function, don't worry about
+ this define, or about the following discussion.
+
+ If you set HAVE_SAVED_SETUID to 0, you will not be able to use uucp
+ to transfer files that the uucp user can not read. Basically, you
+ will only be able to use uucp on world-readable files. If you set
+ HAVE_SAVED_SETUID to 1, but your system does not have saved set
+ user ID, uucp will fail with an error message whenever anybody
+ other than the uucp user uses it. */
+#define HAVE_SAVED_SETUID 1
+
+/* On some systems, such as the DG Aviion and, possibly, the RS/6000,
+ the setreuid function is broken. It should be possible to use
+ setreuid to swap the real and effective user ID's, but on some
+ systems it will not change the real user ID (I believe this is due
+ to a misreading of the POSIX standard). On such a system you must
+ set HAVE_BROKEN_SETREUID to 1; if you do not, you will get error
+ messages from setreuid. Systems on which setreuid exists but is
+ broken pretty much always have saved setuid. */
+#define HAVE_BROKEN_SETREUID 0
+
+/* On the 3B2, and possibly other systems, nap takes an argument in
+ hundredths of a second rather than milliseconds. I don't know of
+ any way to test for this. Set HAVE_HUNDREDTHS_NAP to 1 if this is
+ true on your system. This does not matter if your system does not
+ have the nap function. */
+#define HAVE_HUNDREDTHS_NAP 0
+
+/* Set PS_PROGRAM to the program to run to get a process status,
+ including the arguments to pass it. This is used by ``uustat -p''.
+ Set HAVE_PS_MULTIPLE to 1 if a comma separated list of process
+ numbers may be appended (e.g. ``ps -flp1,10,100''). Otherwise ps
+ will be invoked several times, with a single process number append
+ each time. The default definitions should work on most systems,
+ although some (such as the NeXT) will complain about the 'p'
+ option; for those, use the second set of definitions. The third
+ set of definitions are appropriate for System V. To use the second
+ or third set of definitions, change the ``#if 1'' to ``#if 0'' and
+ change the appropriate ``#if 0'' to ``#if 1''. */
+#if 1
+#define PS_PROGRAM "/bin/ps -lp"
+#define HAVE_PS_MULTIPLE 0
+#endif
+#if 0
+#define PS_PROGRAM "/bin/ps -l"
+#define HAVE_PS_MULTIPLE 0
+#endif
+#if 0
+#define PS_PROGRAM "/bin/ps -flp"
+#define HAVE_PS_MULTIPLE 1
+#endif
+
+/* If you use other programs that also lock devices, such as cu or
+ uugetty, the other programs and UUCP must agree on whether a device
+ is locked. This is typically done by creating a lock file in a
+ specific directory; the lock files are generally named
+ LCK..something or LK.something. If the LOCKDIR macro is defined,
+ these lock files will be placed in the named directory; otherwise
+ they will be placed in the default spool directory. On some HDB
+ systems the lock files are placed in /etc/locks. On some they are
+ placed in /usr/spool/locks. On the NeXT they are placed in
+ /usr/spool/uucp/LCK. */
+/* #define LOCKDIR "/usr/spool/uucp" */
+/* #define LOCKDIR "/etc/locks" */
+/* #define LOCKDIR "/usr/spool/locks" */
+/* #define LOCKDIR "/usr/spool/uucp/LCK" */
+#define LOCKDIR "/var/spool/lock"
+
+/* You must also specify the format of the lock files by setting
+ exactly one of the following macros to 1. Check an existing lock
+ file to decide which of these choices is more appropriate.
+
+ The HDB style is to write the locking process ID in ASCII, passed
+ to ten characters, followed by a newline.
+
+ The V2 style is to write the locking process ID as four binary
+ bytes in the host byte order. Many BSD derived systems use this
+ type of lock file, including the NeXT.
+
+ SCO lock files are similar to HDB lock files, but always lock the
+ lowercase version of the tty (i.e., LCK..tty2a is created if you
+ are locking tty2A). They are appropriate if you are using Taylor
+ UUCP on an SCO Unix, SCO Xenix, or SCO Open Desktop system.
+
+ SVR4 lock files are also similar to HDB lock files, but they use a
+ different naming convention. The filenames are LK.xxx.yyy.zzz,
+ where xxx is the major device number of the device holding the
+ special device file, yyy is the major device number of the port
+ device itself, and zzz is the minor device number of the port
+ device.
+
+ Coherent use a completely different method of terminal locking.
+ See unix/cohtty for details. For locks other than for terminals,
+ HDB type lock files are used. */
+#define HAVE_V2_LOCKFILES 0
+#define HAVE_HDB_LOCKFILES 1
+#define HAVE_SCO_LOCKFILES 0
+#define HAVE_SVR4_LOCKFILES 0
+#define HAVE_COHERENT_LOCKFILES 0
+
+/* If your system supports Internet mail addresses (which look like
+ user@host.domain rather than system!user), HAVE_INTERNET_MAIL
+ should be set to 1. This is checked by uuxqt when sending error
+ (or success, if requested) notifications to the person who
+ submitted the job. */
+#define HAVE_INTERNET_MAIL 1
+
+/* Adminstrative decisions. */
+
+/* Set USE_RCS_ID to 1 if you want the RCS ID strings compiled into
+ the executable. Leaving them out will decrease the executable
+ size. Leaving them in will make it easier to determine which
+ version you are running. */
+#define USE_RCS_ID 1
+
+/* DEBUG controls how much debugging information is compiled into the
+ code. If DEBUG is defined as 0, no sanity checks will be done and
+ no debugging messages will be compiled in. If DEBUG is defined as
+ 1 sanity checks will be done but there will still be no debugging
+ messages. If DEBUG is 2 than debugging messages will be compiled
+ in. When initially testing, DEBUG should be 2, and you should
+ probably leave it at 2 unless a small reduction in the executable
+ file size will be very helpful. */
+#define DEBUG 2
+
+/* Set the default grade to use for a uucp command if the -g option is
+ not used. The grades, from highest to lowest, are 0 to 9, A to Z,
+ a to z. */
+#define BDEFAULT_UUCP_GRADE ('N')
+
+/* Set the default grade to use for a uux command if the -g option is
+ not used. */
+#define BDEFAULT_UUX_GRADE ('N')
+
+/* To compile in use of the new style of configuration files described
+ in the documentation, set HAVE_TAYLOR_CONFIG to 1. */
+#define HAVE_TAYLOR_CONFIG 1
+
+/* To compile in use of V2 style configuration files (L.sys, L-devices
+ and so on), set HAVE_V2_CONFIG to 1. To compile in use of HDB
+ style configuration files (Systems, Devices and so on) set
+ HAVE_HDB_CONFIG to 1. The files will be looked up in the
+ oldconfigdir directory as defined in the Makefile.
+
+ You may set any or all of HAVE_TAYLOR_CONFIG, HAVE_V2_CONFIG and
+ HAVE_HDB_CONFIG to 1 (you must set at least one of the macros).
+ When looking something up (a system, a port, etc.) the new style
+ configuration files will be read first, followed by the V2
+ configuration files, followed by the HDB configuration files. */
+#define HAVE_V2_CONFIG 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 0000000..4cc224e
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/prot.c
@@ -0,0 +1,237 @@
+/* prot.c
+ Protocol support routines to move commands and data around.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char prot_rcsid[] = "$Id: prot.c,v 1.1 1993/08/04 19:30:55 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+#include "uudefs.h"
+#include "system.h"
+#include "conn.h"
+#include "prot.h"
+
+/* Variables visible to the protocol-specific routines. */
+
+/* Buffer to hold received data. */
+char abPrecbuf[CRECBUFLEN];
+
+/* Index of start of data in abPrecbuf. */
+int iPrecstart;
+
+/* Index of end of data (first byte not included in data) in abPrecbuf. */
+int iPrecend;
+
+/* We want to output and input at the same time, if supported on this
+ machine. If we have something to send, we send it all while
+ accepting a large amount of data. Once we have sent everything we
+ look at whatever we have received. If data comes in faster than we
+ can send it, we may run out of buffer space. */
+
+boolean
+fsend_data (qconn, zsend, csend, fdoread)
+ struct sconnection *qconn;
+ const char *zsend;
+ size_t csend;
+ boolean fdoread;
+{
+ if (! fdoread)
+ return fconn_write (qconn, zsend, csend);
+
+ while (csend > 0)
+ {
+ size_t crec, csent;
+
+ if (iPrecend < iPrecstart)
+ crec = iPrecstart - iPrecend - 1;
+ else
+ {
+ crec = CRECBUFLEN - iPrecend;
+ if (iPrecstart == 0)
+ --crec;
+ }
+
+ csent = csend;
+
+ if (! fconn_io (qconn, zsend, &csent, abPrecbuf + iPrecend, &crec))
+ return FALSE;
+
+ csend -= csent;
+ zsend += csent;
+
+ iPrecend = (iPrecend + crec) % CRECBUFLEN;
+ }
+
+ return TRUE;
+}
+
+/* Read data from the other system when we have nothing to send. The
+ argument cneed is the amount of data the caller wants, and ctimeout
+ is the timeout in seconds. The function sets *pcrec to the amount
+ of data which was actually received, which may be less than cneed
+ if there isn't enough room in the receive buffer. If no data is
+ received before the timeout expires, *pcrec will be returned as 0.
+ If an error occurs, the function returns FALSE. If the freport
+ argument is FALSE, no error should be reported. */
+
+boolean
+freceive_data (qconn, cneed, pcrec, ctimeout, freport)
+ struct sconnection *qconn;
+ size_t cneed;
+ size_t *pcrec;
+ int ctimeout;
+ boolean freport;
+{
+ /* Set *pcrec to the maximum amount of data we can read. fconn_read
+ expects *pcrec to be the buffer size, and sets it to the amount
+ actually received. */
+ if (iPrecend < iPrecstart)
+ *pcrec = iPrecstart - iPrecend - 1;
+ else
+ {
+ *pcrec = CRECBUFLEN - iPrecend;
+ if (iPrecstart == 0)
+ --(*pcrec);
+ }
+
+#if DEBUG > 0
+ /* If we have no room in the buffer, we're in trouble. The
+ protocols must be written to ensure that this can't happen. */
+ if (*pcrec == 0)
+ ulog (LOG_FATAL, "freceive_data: No room in buffer");
+#endif
+
+ /* If we don't have room for all the data the caller wants, we
+ simply have to expect less. We'll get the rest later. */
+ if (*pcrec < cneed)
+ cneed = *pcrec;
+
+ if (! fconn_read (qconn, abPrecbuf + iPrecend, pcrec, cneed, ctimeout,
+ freport))
+ return FALSE;
+
+ iPrecend = (iPrecend + *pcrec) % CRECBUFLEN;
+
+ return TRUE;
+}
+
+/* Read a single character. Get it out of the receive buffer if it's
+ there, otherwise ask freceive_data for at least one character.
+ This is used because as a protocol is shutting down freceive_data
+ may read ahead and eat characters that should be read outside the
+ protocol routines. We call freceive_data rather than fconn_read
+ with an argument of 1 so that we can get all the available data in
+ a single system call. The ctimeout argument is the timeout in
+ seconds; the freport argument is FALSE if no error should be
+ reported. This returns a character, or -1 on timeout or -2 on
+ error. */
+
+int
+breceive_char (qconn, ctimeout, freport)
+ struct sconnection *qconn;
+ int ctimeout;
+ boolean freport;
+{
+ char b;
+
+ if (iPrecstart == iPrecend)
+ {
+ size_t crec;
+
+ if (! freceive_data (qconn, sizeof (char), &crec, ctimeout, freport))
+ return -2;
+ if (crec == 0)
+ return -1;
+ }
+
+ b = abPrecbuf[iPrecstart];
+ iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
+ return BUCHAR (b);
+}
+
+/* Send mail about a file transfer. We send to the given mailing
+ address if there is one, otherwise to the user. */
+
+boolean
+fmail_transfer (fsuccess, zuser, zmail, zwhy, zfromfile, zfromsys,
+ ztofile, ztosys, zsaved)
+ boolean fsuccess;
+ const char *zuser;
+ const char *zmail;
+ const char *zwhy;
+ const char *zfromfile;
+ const char *zfromsys;
+ const char *ztofile;
+ const char *ztosys;
+ const char *zsaved;
+{
+ const char *zsendto;
+ const char *az[20];
+ int i;
+
+ if (zmail != NULL && *zmail != '\0')
+ zsendto = zmail;
+ else
+ zsendto = zuser;
+
+ i = 0;
+ az[i++] = "The file\n\t";
+ if (zfromsys != NULL)
+ {
+ az[i++] = zfromsys;
+ az[i++] = "!";
+ }
+ az[i++] = zfromfile;
+ if (fsuccess)
+ az[i++] = "\nwas successfully transferred to\n\t";
+ else
+ az[i++] = "\ncould not be transferred to\n\t";
+ if (ztosys != NULL)
+ {
+ az[i++] = ztosys;
+ az[i++] = "!";
+ }
+ az[i++] = ztofile;
+ az[i++] = "\nas requested by\n\t";
+ az[i++] = zuser;
+ if (! fsuccess)
+ {
+ az[i++] = "\nfor the following reason:\n\t";
+ az[i++] = zwhy;
+ az[i++] = "\n";
+ }
+ if (zsaved != NULL)
+ {
+ az[i++] = zsaved;
+ az[i++] = "\n";
+ }
+
+ return fsysdep_mail (zsendto,
+ fsuccess ? "UUCP succeeded" : "UUCP failed",
+ i, az);
+}
diff --git a/gnu/libexec/uucp/common_sources/prot.h b/gnu/libexec/uucp/common_sources/prot.h
new file mode 100644
index 0000000..4e2bb58
--- /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 0000000..47675ac
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/sysdep.h
@@ -0,0 +1,530 @@
+/* sysh.unx -*- C -*-
+ The header file for the UNIX system dependent routines.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef SYSH_UNX_H
+
+#define SYSH_UNX_H
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct uuconf_system;
+struct sconnection;
+#endif
+
+/* Make sure the defines do not conflict. These are in this file
+ because they are Unix dependent. */
+#if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_COHERENT_LOCKFILES != 1
+ #error LOCKFILES define not set or duplicated
+#endif
+
+/* SCO and SVR4 lockfiles are basically just like HDB lockfiles. */
+#if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES
+#undef HAVE_HDB_LOCKFILES
+#define HAVE_HDB_LOCKFILES 1
+#endif
+
+#if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS != 1
+ #error Terminal driver define not set or duplicated
+#endif
+
+#if SPOOLDIR_V2 + SPOOLDIR_BSD42 + SPOOLDIR_BSD43 + SPOOLDIR_HDB + SPOOLDIR_ULTRIX + SPOOLDIR_SVR4 + SPOOLDIR_TAYLOR != 1
+ #error Spool directory define not set or duplicated
+#endif
+
+/* If setreuid is broken, don't use it. */
+#if HAVE_BROKEN_SETREUID
+#undef HAVE_SETREUID
+#define HAVE_SETREUID 0
+#endif
+
+/* Get some standard types from the configuration header file. */
+#ifdef PID_T
+typedef PID_T pid_t;
+#endif
+
+#ifdef UID_T
+typedef UID_T uid_t;
+#endif
+
+#ifdef GID_T
+typedef GID_T gid_t;
+#endif
+
+#ifdef OFF_T
+typedef OFF_T off_t;
+#endif
+
+/* On Unix, binary files are the same as text files. */
+#define BINREAD "r"
+#define BINWRITE "w"
+
+/* If we have sigaction, we can force system calls to not be
+ restarted. */
+#if HAVE_SIGACTION
+#undef HAVE_RESTARTABLE_SYSCALLS
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+
+/* If we have sigvec, and we have HAVE_SIGVEC_SV_FLAGS, and
+ SV_INTERRUPT is defined, we can force system calls to not be
+ restarted (signal.h is included by uucp.h before this point, so
+ SV_INTERRUPT will be defined by now if it it ever is). */
+#if HAVE_SIGVEC && HAVE_SIGVEC_SV_FLAGS
+#ifdef SV_INTERRUPT
+#undef HAVE_RESTARTABLE_SYSCALLS
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+#endif
+
+/* If we were cross-configured, we will have a value of -1 for
+ HAVE_RESTARTABLE_SYSCALLS. In this case, we try to guess what the
+ correct value should be. Yuck. If we have sigvec, but neither of
+ the above cases applied (which we know because they would have
+ changed HAVE_RESTARTABLE_SYSCALLS) then we are probably on 4.2BSD
+ and system calls are automatically restarted. Otherwise, assume
+ that they are not. */
+#if HAVE_RESTARTABLE_SYSCALLS == -1
+#undef HAVE_RESTARTABLE_SYSCALLS
+#if HAVE_SIGVEC
+#define HAVE_RESTARTABLE_SYSCALLS 1
+#else
+#define HAVE_RESTARTABLE_SYSCALLS 0
+#endif
+#endif /* HAVE_RESTARTABLE_SYSCALLS == -1 */
+
+/* We don't handle sigset in combination with restartable system
+ calls, so we check for it although this combination will never
+ happen. */
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && HAVE_SIGSET
+#if HAVE_RESTARTABLE_SYSCALLS
+#undef HAVE_SIGSET
+#define HAVE_SIGSET 0
+#endif
+#endif
+
+/* If we don't have restartable system calls, we can ignore
+ fsysdep_catch, usysdep_start_catch and usysdep_end_catch.
+ Otherwise fsysdep_catch has to do a setjmp. */
+
+#if ! HAVE_RESTARTABLE_SYSCALLS
+
+#define fsysdep_catch() (TRUE)
+#define usysdep_start_catch()
+#define usysdep_end_catch()
+#define CATCH_PROTECT
+
+#else /* HAVE_RESTARTABLE_SYSCALLS */
+
+#if HAVE_SETRET && ! HAVE_SIGSETJMP
+#include <setret.h>
+#define setjmp setret
+#define longjmp longret
+#define jmp_buf ret_buf
+#else /* ! HAVE_SETRET || HAVE_SIGSETJMP */
+#include <setjmp.h>
+#if HAVE_SIGSETJMP
+#undef setjmp
+#undef longjmp
+#undef jmp_buf
+#define setjmp(s) sigsetjmp ((s), TRUE)
+#define longjmp siglongjmp
+#define jmp_buf sigjmp_buf
+#endif /* HAVE_SIGSETJMP */
+#endif /* ! HAVE_SETRET || HAVE_SIGSETJMP */
+
+extern volatile sig_atomic_t fSjmp;
+extern volatile jmp_buf sSjmp_buf;
+
+#define fsysdep_catch() (setjmp (sSjmp_buf) == 0)
+
+#define usysdep_start_catch() (fSjmp = TRUE)
+
+#define usysdep_end_catch() (fSjmp = FALSE)
+
+#define CATCH_PROTECT volatile
+
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+
+/* Get definitions for the terminal driver. */
+
+#if HAVE_BSD_TTY
+#include <sgtty.h>
+struct sbsd_terminal
+{
+ struct sgttyb stty;
+ struct tchars stchars;
+ struct ltchars sltchars;
+};
+typedef struct sbsd_terminal sterminal;
+#define fgetterminfo(o, q) \
+ (ioctl ((o), TIOCGETP, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCGETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCGLTC, &(q)->sltchars) == 0)
+#define fsetterminfo(o, q) \
+ (ioctl ((o), TIOCSETN, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0)
+#define fsetterminfodrain(o, q) \
+ (ioctl ((o), TIOCSETP, &(q)->stty) == 0 \
+ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \
+ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0)
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+#include <termio.h>
+typedef struct termio sterminal;
+#define fgetterminfo(o, q) (ioctl ((o), TCGETA, (q)) == 0)
+#define fsetterminfo(o, q) (ioctl ((o), TCSETA, (q)) == 0)
+#define fsetterminfodrain(o, q) (ioctl ((o), TCSETAW, (q)) == 0)
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+#include <termios.h>
+typedef struct termios sterminal;
+#define fgetterminfo(o, q) (tcgetattr ((o), (q)) == 0)
+#define fsetterminfo(o, q) (tcsetattr ((o), TCSANOW, (q)) == 0)
+#define fsetterminfodrain(o, q) (tcsetattr ((o), TCSADRAIN, (q)) == 0)
+
+/* On some systems it is not possible to include both <sys/ioctl.h>
+ and <termios.h> in the same source files; I don't really know why.
+ On such systems, we pretend that we don't have <sys/ioctl.h>. */
+#if ! HAVE_TERMIOS_AND_SYS_IOCTL_H
+#undef HAVE_SYS_IOCTL_H
+#define HAVE_SYS_IOCTL_H 0
+#endif
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+/* The root directory (this is needed by the system independent stuff
+ as the default for local-send). */
+#define ZROOTDIR "/"
+
+/* The name of the execution directory within the spool directory
+ (this is need by the system independent uuxqt.c). */
+#define XQTDIR ".Xqtdir"
+
+/* The name of the directory in which we preserve file transfers that
+ failed. */
+#define PRESERVEDIR ".Preserve"
+
+/* The length of the sequence number used in a file name. */
+#define CSEQLEN (4)
+
+/* Get some standard definitions. Avoid including the files more than
+ once--some might have been included by uucp.h. */
+#if USE_STDIO && HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if ! USE_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+
+/* Get definitions for the file permission bits. */
+
+#ifndef S_IRWXU
+#define S_IRWXU 0700
+#endif
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR 0200
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+
+#ifndef S_IRWXG
+#define S_IRWXG 0070
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0020
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+
+#ifndef S_IRWXO
+#define S_IRWXO 0007
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0002
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+#ifndef S_ISDIR
+#ifdef S_IFDIR
+#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR)
+#else /* ! defined (S_IFDIR) */
+#define S_ISDIR(i) (((i) & 0170000) == 040000)
+#endif /* ! defined (S_IFDIR) */
+#endif /* ! defined (S_ISDIR) */
+
+/* We need the access macros. */
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define F_OK 0
+#endif /* ! defined (R_OK) */
+
+/* We create files with these modes (should this be configurable?). */
+#define IPRIVATE_FILE_MODE (S_IRUSR | S_IWUSR)
+#define IPUBLIC_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+
+/* We create directories with this mode (should this be configurable?). */
+#define IDIRECTORY_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+#define IPUBLIC_DIRECTORY_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
+
+#if ! HAVE_OPENDIR
+
+/* Define some structures to use if we don't have opendir, etc. These
+ will only work if we have the old Unix filesystem, with a 2 byte
+ inode and a 14 byte filename. */
+
+#include <sys/dir.h>
+
+struct dirent
+{
+ char d_name[DIRSIZ + 1];
+};
+
+typedef struct
+{
+ int o;
+ struct dirent s;
+} DIR;
+
+extern DIR *opendir P((const char *zdir));
+extern struct dirent *readdir P((DIR *));
+extern int closedir P((DIR *));
+
+#endif /* ! HAVE_OPENDIR */
+
+#if ! HAVE_FTW_H
+
+/* If there is no <ftw.h>, define the ftw constants. */
+
+#define FTW_F (0)
+#define FTW_D (1)
+#define FTW_DNR (2)
+#define FTW_NS (3)
+
+#endif /* ! HAVE_FTW_H */
+
+/* This structure holds the system dependent information we keep for a
+ connection. This is used by the TCP and TLI code. */
+
+struct ssysdep_conn
+{
+ /* File descriptor. */
+ int o;
+ /* Device name. */
+ char *zdevice;
+ /* File status flags. */
+ int iflags;
+ /* File status flags for descriptor 1 (-1 if not standard input). */
+ int istdout_flags;
+ /* Hold the real descriptor when using a dialer device. */
+ int ohold;
+ /* TRUE if this is a terminal and the remaining fields are valid. */
+ boolean fterminal;
+ /* TRUE if this is a TLI descriptor. */
+ boolean ftli;
+ /* Baud rate. */
+ long ibaud;
+ /* Original terminal settings. */
+ sterminal sorig;
+ /* Current terminal settings. */
+ sterminal snew;
+#if HAVE_COHERENT_LOCKFILES
+ /* On Coherent we need to hold on to the real port name which will
+ be used to enable the port. Ick. */
+ char *zenable;
+#endif
+};
+
+/* These functions do I/O and chat scripts to a port. They are called
+ by the TCP and TLI routines. */
+extern boolean fsysdep_conn_read P((struct sconnection *qconn,
+ char *zbuf, size_t *pclen,
+ size_t cmin, int ctimeout,
+ boolean freport));
+extern boolean fsysdep_conn_write P((struct sconnection *qconn,
+ const char *zbuf, size_t clen));
+extern boolean fsysdep_conn_io P((struct sconnection *qconn,
+ const char *zwrite, size_t *pcwrite,
+ char *zread, size_t *pcread));
+extern boolean fsysdep_conn_chat P((struct sconnection *qconn,
+ char **pzprog));
+
+/* Set a signal handler. */
+extern void usset_signal P((int isig, RETSIGTYPE (*pfn) P((int)),
+ boolean fforce, boolean *pfignored));
+
+/* Default signal handler. This sets the appropriate element of the
+ afSignal array. If system calls are automatically restarted, it
+ may do a longjmp to an fsysdep_catch. */
+extern RETSIGTYPE ussignal P((int isig));
+
+/* Try to fork, repeating several times. */
+extern pid_t ixsfork P((void));
+
+/* Spawn a job. Returns the process ID of the spawned job or -1 on
+ error. The following macros may be passed in aidescs. */
+
+/* Set descriptor to /dev/null. */
+#define SPAWN_NULL (-1)
+/* Set element of aidescs to a pipe for caller to read from. */
+#define SPAWN_READ_PIPE (-2)
+/* Set element of aidescs to a pipe for caller to write to. */
+#define SPAWN_WRITE_PIPE (-3)
+
+extern pid_t ixsspawn P((const char **pazargs, int *aidescs,
+ boolean fkeepuid, boolean fkeepenv,
+ const char *zchdir, boolean fnosigs,
+ boolean fshell, const char *zpath,
+ const char *zuu_machine,
+ const char *zuu_user));
+
+/* Do a form of popen using ixsspawn. */
+extern FILE *espopen P((const char **pazargs, boolean frd,
+ pid_t *pipid));
+
+/* Wait for a particular process to finish, returning the exit status.
+ The process ID should be pid_t, but we can't put that in a
+ prototype. */
+extern int ixswait P((unsigned long ipid, const char *zreport));
+
+/* Find a spool file in the spool directory. For a local file, the
+ bgrade argument is the grade of the file. This is needed for
+ SPOOLDIR_SVR4. */
+extern char *zsfind_file P((const char *zsimple, const char *zsystem,
+ int bgrade));
+
+/* Return the grade given a sequence number. */
+extern char bsgrade P((pointer pseq));
+
+/* Lock a string. */
+extern boolean fsdo_lock P((const char *, boolean fspooldir,
+ boolean *pferr));
+
+/* Unlock a string. */
+extern boolean fsdo_unlock P((const char *, boolean fspooldir));
+
+/* Check access for a particular user name, or NULL to check access
+ for any user. */
+extern boolean fsuser_access P((const struct stat *, int imode,
+ const char *zuser));
+
+/* Stick two directories and a file name together. */
+extern char *zsappend3 P((const char *zdir1, const char *zdir2,
+ const char *zfile));
+
+/* Stick three directories and a file name together. */
+extern char *zsappend4 P((const char *zdir1, const char *zdir2,
+ const char *zdir3, const char *zfile));
+
+/* Get a temporary file name. */
+extern char *zstemp_file P((const struct uuconf_system *qsys));
+
+/* Get a command file name. */
+extern char *zscmd_file P((const struct uuconf_system *qsys, int bgrade));
+
+/* Get a jobid from a system, a file name, and a grade. */
+extern char *zsfile_to_jobid P((const struct uuconf_system *qsys,
+ const char *zfile,
+ int bgrade));
+
+/* Get a file name from a jobid. This also returns the associated system
+ in *pzsystem and the grade in *pbgrade. */
+extern char *zsjobid_to_file P((const char *zid, char **pzsystem,
+ char *pbgrade));
+
+/* See whether there is a spool directory for a system when using
+ SPOOLDIR_ULTRIX. */
+extern boolean fsultrix_has_spool P((const char *zsystem));
+
+#if HAVE_COHERENT_LOCKFILES
+/* Lock a coherent tty. */
+extern boolean lockttyexist P((const char *z));
+extern boolean fscoherent_disable_tty P((const char *zdevice,
+ char **pzenable));
+#endif
+
+/* Some replacements for standard Unix functions. */
+
+#if ! HAVE_DUP2
+extern int dup2 P((int oold, int onew));
+#endif
+
+#if ! HAVE_FTW
+extern int ftw P((const char *zdir,
+ int (*pfn) P((const char *zfile,
+ const struct stat *qstat,
+ int iflag)),
+ int cdescriptors));
+#endif
+
+#if ! HAVE_GETCWD && ! HAVE_GETWD
+extern char *getcwd P((char *zbuf, size_t cbuf));
+#endif
+
+#if ! HAVE_MKDIR
+extern int mkdir P((const char *zdir, int imode));
+#endif
+
+#if ! HAVE_RENAME
+extern int rename P((const char *zold, const char *znew));
+#endif
+
+#if ! HAVE_RMDIR
+extern int rmdir P((const char *zdir));
+#endif
+
+/* The working directory from which the program was run (this is set
+ by usysdep_initialize if called with INIT_GETCWD). */
+extern char *zScwd;
+
+/* The spool directory name. */
+extern const char *zSspooldir;
+
+/* The lock directory name. */
+extern const char *zSlockdir;
+
+/* The local UUCP name (needed for some spool directory stuff). */
+extern const char *zSlocalname;
+
+#endif /* ! defined (SYSH_UNX_H) */
diff --git a/gnu/libexec/uucp/common_sources/system.h b/gnu/libexec/uucp/common_sources/system.h
new file mode 100644
index 0000000..aa9d2a4
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/system.h
@@ -0,0 +1,950 @@
+/* system.h
+ Header file for system dependent stuff in the Taylor UUCP package.
+ This file is not itself system dependent.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef SYSTEM_H
+
+#define SYSTEM_H
+
+#if ANSI_C
+/* These structures are used in prototypes but are not defined in this
+ header file. */
+struct tm;
+struct uuconf_system;
+struct uuconf_port;
+struct sconnection;
+struct sstatus;
+struct scmd;
+#endif
+
+/* Any function which returns an error should also report an error
+ message, unless otherwise indicated.
+
+ Any function that returns a char *, rather than a const char *, is
+ returning a pointer to a buffer allocated by zbufalc which must be
+ freed using ubuffree, unless otherwise indicated. */
+
+/* The maximum length of a remote system name. */
+extern size_t cSysdep_max_name_len;
+
+/* Initialize. If something goes wrong, this routine should just
+ exit. The flag argument is 0, or a combination of any of the
+ following flags. */
+
+/* This program needs to know the current working directory. This is
+ used because on Unix it can be expensive to determine the current
+ working directory (some versions of getcwd fork a process), but in
+ most cases we don't need to know it. However, we are going to
+ chdir to the spool directory (unless INIT_CHDIR is set), so we have
+ to get the cwd now if we are ever going to get it. Both uucp and
+ uux use the function fsysdep_needs_cwd to determine whether they
+ will need the current working directory, and pass the argument to
+ usysdep_initialize appropriately. There's probably a cleaner way
+ to handle this, but this will suffice for now. */
+#define INIT_GETCWD (01)
+
+/* This program should not chdir to the spool directory. This may
+ only make sense on Unix. It is set by cu. */
+#define INIT_NOCHDIR (02)
+
+/* This program needs special access to the spool directories. That
+ means, on Unix, this program is normally installed setuid. */
+#define INIT_SUID (04)
+
+extern void usysdep_initialize P((pointer puuconf, int iflags));
+
+/* Exit the program. The fsuccess argument indicates whether to
+ return an indication of success or failure to the outer
+ environment. This routine should not return. */
+extern void usysdep_exit P((boolean fsuccess));
+
+/* Called when a non-standard configuration file is being used, to
+ avoid handing out privileged access. If it returns FALSE, default
+ configuration file will be used. This is called before the
+ usysdep_initialize function is called. */
+extern boolean fsysdep_other_config P((const char *));
+
+/* Detach from the controlling terminal. This probably only makes
+ sense on Unix. It is called by uucico to try to get the modem port
+ as a controlling terminal. It is also called by uucico before it
+ starts up uuxqt, so that uuxqt will be a complete daemon. */
+extern void usysdep_detach P((void));
+
+/* Get the local node name if it is not specified in the configuration
+ files. Returns NULL on error; otherwise the return value should
+ point to a static buffer. */
+extern const char *zsysdep_localname P((void));
+
+/* Get the login name. This is used when uucico is started up with no
+ arguments in slave mode, which causes it to assume that somebody
+ has logged in. It also used by uucp and uux for recording the user
+ name. This may not return NULL. The return value should point to
+ a static buffer. */
+extern const char *zsysdep_login_name P((void));
+
+/* Set a signal handler for a signal. If the signal occurs, the
+ appropriate element of afSignal should be set to the signal number
+ (see the declaration of afSignal in uucp.h). This routine might be
+ able to just use signal, but Unix requires more complex handling.
+ This is called before usysdep_initialize. */
+extern void usysdep_signal P((int isig));
+
+/* Catch a signal. This is actually defined as a macro in the system
+ dependent header file, and the prototype here just indicates how it
+ should be called. It is called before a routine which must exit if
+ a signal occurs, and is expected to set do a setjmp (which is why
+ it must be a macro). It is actually only called in one place in
+ the system independent code, before the call to read stdin in uux.
+ This is needed to handle 4.2 BSD restartable system calls, which
+ require a longjmp. On systems which don't need to do
+ setjmp/longjmp around system calls, this can be redefined in
+ sysdep.h to TRUE. It should return TRUE if the routine should
+ proceed, or FALSE if a signal occurred. After having this return
+ TRUE, usysdep_start_catch should be used to start catching the
+ signal; this basically tells the signal handler that it's OK to do
+ the longjmp, if fsysdep_catch did not already do so. */
+#ifndef fsysdep_catch
+extern boolean fsysdep_catch P((void));
+#endif
+
+/* Start catching a signal. This is called after fsysdep_catch to
+ tell the signal handler to go ahead and do the longjmp. This may
+ be implemented as a macro in sysdep.h. */
+#ifndef usysdep_start_catch
+extern void usysdep_start_catch P((void));
+#endif
+
+/* Stop catching a signal. This is called when it is no longer
+ necessary for fsysdep_catch to handle signals. This may be
+ implemented as a macro in sysdep.h. */
+#ifndef usysdep_end_catch
+extern void usysdep_end_catch P((void));
+#endif
+
+/* Link two files. On Unix this should attempt the link. If it
+ succeeds it should return TRUE with *pfworked set to TRUE. If the
+ link fails because it must go across a device, it should return
+ TRUE with *pfworked set to FALSE. If the link fails for some other
+ reason, it should log an error message and return FALSE. On a
+ system which does not support links to files, this should just
+ return TRUE with *pfworked set to FALSE. */
+extern boolean fsysdep_link P((const char *zfrom, const char *zto,
+ boolean *pfworked));
+
+/* Get the port name. This is used when uucico is started up in slave
+ mode to figure out which port was used to call in so that it can
+ determine any appropriate protocol parameters. This may return
+ NULL if the port cannot be determined, which will just mean that no
+ protocol parameters are applied. The name returned should be the
+ sort of name that would appear in the port file. This should set
+ *pftcp_port to TRUE if it can determine that the port is a TCP
+ connection rather than a normal serial port. The return value (if
+ not NULL) should point to a static buffer. */
+extern const char *zsysdep_port_name P((boolean *pftcp_port));
+
+/* Expand a file name on the local system. On Unix, if the zfile
+ argument begins with ~user/ it goes in that users home directory,
+ and if it begins with ~/ it goes in the public directory (the
+ public directory is passed to this routine, since each system may
+ have its own public directory). Similar conventions may be
+ desirable on other systems. This should always return an absolute
+ path name, probably in the public directory. It should return NULL
+ on error; otherwise the return value should be allocated using
+ zbufcpy or zbufalc. */
+extern char *zsysdep_local_file P((const char *zname,
+ const char *zpubdir));
+
+/* Return whether a file name is in a directory, and check for read or
+ write access. This should check whether zfile is within zdir (or
+ is zdir itself). If it is not, it should return FALSE. If zfile
+ is in zdir, then fcheck indicates whether further checking should
+ be done. If fcheck is FALSE, no further checking is done.
+ Otherwise, if freadable is TRUE the user zuser should have search
+ access to all directories from zdir down to zfile and should have
+ read access on zfile itself (if zfile does not exist, or is not a
+ regular file, this function may return FALSE but does not have to).
+ If freadable is FALSE, the user zuser should have search access to
+ all directories from zdir down to zfile and should have write
+ access on zfile (which may be a directory, or may not actually
+ exist, which is acceptable). The zuser argument may be NULL, in
+ which case the check should be made for any user, not just zuser.
+ There is no way for this function to return error. */
+extern boolean fsysdep_in_directory P((const char *zfile,
+ const char *zdir,
+ boolean fcheck,
+ boolean freadable,
+ const char *zuser));
+
+/* Return TRUE if a file exists, FALSE otherwise. There is no way to
+ return error. */
+extern boolean fsysdep_file_exists P((const char *zfile));
+
+/* Start up a program. The code expects fsysdep_run to return after
+ doing a fork, but at least for now everything will work fine if it
+ does not (on a system which does not support forking). The three
+ string arguments may be catenated together to form the program to
+ execute; I did it this way to make it easy to call execl(2), and
+ because I never needed more than two arguments. The program will
+ always be "uucico" or "uuxqt". The return value will be passed
+ directly to usysdep_exit, and should be TRUE on success, FALSE on
+ error. */
+extern boolean fsysdep_run P((const char *zprogram, const char *zarg1,
+ const char *zarg2));
+
+/* Send a mail message. This function will be passed an array of
+ strings. All necessary newlines are already included; the strings
+ should simply be concatenated together to form the mail message.
+ It should return FALSE on error, although the return value is often
+ ignored. */
+extern boolean fsysdep_mail P((const char *zto, const char *zsubject,
+ int cstrs, const char **paz));
+
+/* Get the time in seconds since some epoch. The actual epoch is
+ unimportant, so long as the time values are consistent across
+ program executions and the value is never negative. If the
+ pimicros argument is not NULL, it should be set to the number of
+ microseconds (if this is not available, *pimicros should be set to
+ zero). */
+extern long ixsysdep_time P((long *pimicros));
+
+/* Get the time in seconds and microseconds (millionths of a second)
+ since some epoch. The actual epoch is not important, and it may
+ change in between program invocations; this is provided because on
+ Unix the times function may be used. If microseconds can not be
+ determined, *pimicros can just be set to zero. */
+extern long ixsysdep_process_time P((long *pimicros));
+
+/* Parse the value returned by ixsysdep_time into a struct tm. I
+ assume that this structure is defined in <time.h>. This is
+ basically just localtime, except that the ANSI function takes a
+ time_t which may not be what is returned by ixsysdep_time. */
+extern void usysdep_localtime P((long itime, struct tm *q));
+
+/* Sleep for a number of seconds. */
+extern void usysdep_sleep P((int cseconds));
+
+/* Pause for half a second, or 1 second if subsecond sleeps are not
+ possible. */
+extern void usysdep_pause P((void));
+
+/* Lock a remote system. This should return FALSE if the system is
+ already locked (no error should be reported). */
+extern boolean fsysdep_lock_system P((const struct uuconf_system *qsys));
+
+/* Unlock a remote system. This should return FALSE on error
+ (although the return value is generally ignored). */
+extern boolean fsysdep_unlock_system P((const struct uuconf_system *qsys));
+
+/* Get the conversation sequence number for a remote system, and
+ increment it for next time. This should return -1 on error. */
+extern long ixsysdep_get_sequence P((const struct uuconf_system *qsys));
+
+/* Get the status of a remote system. This should return FALSE on
+ error. Otherwise it should set *qret to the status. If no status
+ information is available, this should set *qret to sensible values
+ and return TRUE. If pfnone is not NULL, then it should be set to
+ TRUE if no status information was available or FALSE otherwise. */
+extern boolean fsysdep_get_status P((const struct uuconf_system *qsys,
+ struct sstatus *qret,
+ boolean *pfnone));
+
+/* Set the status of a remote system. This should return FALSE on
+ error. The system will be locked before this call is made. */
+extern boolean fsysdep_set_status P((const struct uuconf_system *qsys,
+ const struct sstatus *qset));
+
+/* See whether a remote system is permitted to log in. This is just
+ to support the remote.unknown shell script for HDB. The zscript
+ argument is the script name, as return by uuconf_remote_unknown.
+ The zsystem argument is the name given by the remote system. If
+ the system is not permitted to log in, this function should log an
+ error and return FALSE. */
+extern boolean fsysdep_unknown_caller P((const char *zscript,
+ const char *zsystem));
+
+/* Check whether there is work for a remote system. It should return
+ TRUE if there is work, FALSE otherwise; there is no way to indicate
+ an error. */
+extern boolean fsysdep_has_work P((const struct uuconf_system *qsys));
+
+/* Initialize the work scan. This will be called before
+ fsysdep_get_work. The bgrade argument is the minimum grade of
+ execution files that should be considered (e.g. a bgrade of 'd'
+ will allow all grades from 'A' to 'Z' and 'a' to 'd'). This
+ function should return FALSE on error. */
+extern boolean fsysdep_get_work_init P((const struct uuconf_system *qsys,
+ int bgrade));
+
+/* Get the next command to be executed for a remote system. The
+ bgrade argument will be the same as for fsysdep_get_work_init;
+ probably only one of these functions will use it, namely the
+ function for which it is more convenient. This should return FALSE
+ on error. The structure pointed to by qcmd should be filled in.
+ The strings may point into a static buffer; they will be copied out
+ if necessary. If there is no more work, this should set qcmd->bcmd
+ to 'H' and return TRUE. This should set qcmd->pseq to something
+ which can be passed to fsysdep_did_work to remove the job from the
+ queue when it has been completed. This may set qcmd->bcmd to 'P'
+ to represent a poll file; the main code will just pass the pseq
+ element of such a structure to fsysdep_did_work if the system is
+ called. */
+extern boolean fsysdep_get_work P((const struct uuconf_system *qsys,
+ int bgrade, struct scmd *qcmd));
+
+/* Remove a job from the work queue. This must also remove the
+ temporary file used for a send command, if there is one. It should
+ return FALSE on error. */
+extern boolean fsysdep_did_work P((pointer pseq));
+
+/* Save the temporary file for a send command. This function should
+ return a string that will be put into a mail message. On success
+ this string should say something like ``The file has been saved as
+ ...''. On failure it could say something like ``The file could not
+ be saved because ...''. If there is no temporary file, or for some
+ reason it's not appropriate to include a message, this function
+ should just return NULL. This function is used when a file send
+ fails for some reason, to make sure that we don't completely lost
+ the file. */
+extern const char *zsysdep_save_temp_file P((pointer pseq));
+
+/* Cleanup anything left over by fsysdep_get_work_init and
+ fsysdep_get_work. This may be called even though
+ fsysdep_get_work_init has not been. */
+extern void usysdep_get_work_free P((const struct uuconf_system *qsys));
+
+/* Add a base name to a file if it is a directory. If zfile names a
+ directory, then return a string naming a file within the directory
+ with the base file name of zname. This should return NULL on
+ error. */
+extern char *zsysdep_add_base P((const char *zfile,
+ const char *zname));
+
+/* Get a file name from the spool directory. This should return NULL
+ on error. The pseq argument is TRUE if the file was found from
+ searching the work directory; this is, unfortunately, needed to
+ support SVR4 spool directories. */
+extern char *zsysdep_spool_file_name P((const struct uuconf_system *qsys,
+ const char *zfile,
+ pointer pseq));
+
+/* Make necessary directories. This should create all non-existent
+ directories for a file. If the fpublic argument is TRUE, anybody
+ should be permitted to create and remove files in the directory;
+ otherwise anybody can list the directory, but only the UUCP system
+ can create and remove files. It should return FALSE on error. */
+extern boolean fsysdep_make_dirs P((const char *zfile, boolean fpublic));
+
+/* Create a stdio file, setting appropriate protection. If the
+ fpublic argument is TRUE, the file is made publically accessible;
+ otherwise it is treated as a private data file. If the fappend
+ argument is TRUE, the file is opened in append mode; otherwise any
+ previously existing file of the same name is removed. If the
+ fmkdirs argument is TRUE, then any necessary directories should
+ also be created. On a system in which file protections are
+ unimportant and the necessary directories exist, this may be
+ implemented as
+
+ fopen (zfile, fappend ? "a" : "w");
+
+ */
+extern FILE *esysdep_fopen P((const char *zfile, boolean fpublic,
+ boolean fappend, boolean fmkdirs));
+
+/* Open a file, using the access permission of the user who invoked
+ the program. The frd argument is TRUE if the file should be opened
+ for reading, and the fbinary argument is TRUE if the file should be
+ opened as a binary file (this is ignored on Unix, since there all
+ files are binary files). This returns an openfile_t, not a FILE *.
+ This is supposed to be able to open a file even if it can not be
+ read by the uucp user. This is not possible on some older Unix
+ systems. */
+extern openfile_t esysdep_user_fopen P((const char *zfile,
+ boolean frd, boolean fbinary));
+
+/* Open a file to send to another system; the qsys argument is the
+ system the file is being sent to. If fcheck is TRUE, it should
+ make sure that the file is readable by zuser (if zuser is NULL the
+ file must be readable by anybody). This is to eliminate a window
+ between fsysdep_in_directory and esysdep_open_send. If an error
+ occurs, it should return EFILECLOSED. */
+extern openfile_t esysdep_open_send P((const struct uuconf_system *qsys,
+ const char *zname,
+ boolean fcheck,
+ const char *zuser));
+
+/* Return a temporary file name to receive into. This file will be
+ opened by esysdep_open_receive. The qsys argument is the system
+ the file is coming from, the zto argument is the name the file will
+ have after it has been fully received, and the ztemp argument, if
+ it is not NULL, is from the command sent by the remote system. The
+ return value must be freed using ubuffree. The function should
+ return NULL on error. */
+extern char *zsysdep_receive_temp P((const struct uuconf_system *qsys,
+ const char *zfile,
+ const char *ztemp));
+
+/* Open a file to receive from another system. The zreceive argument
+ is the return value of zsysdep_receive_temp with the same qsys,
+ zfile and ztemp arguments. If the function can determine that this
+ file has already been partially received, it should set *pcrestart
+ to the number of bytes that have been received. If the file has
+ not been partially received, *pcrestart should be set to -1. The
+ function should return EFILECLOSED on error. After the file is
+ written, fsysdep_move_file will be called to move the file to its
+ final destination, and to set the correct file mode. */
+extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp,
+ const char *zreceive,
+ long *pcrestart));
+
+/* Move a file. This is used to move a received file to its final
+ location. The zto argument is the file to create. The zorig
+ argument is the name of the file to move. If fmkdirs is TRUE, then
+ any necessary directories are created; fpublic indicates whether
+ they should be publically writeable or not. If fcheck is TRUE,
+ this should make sure the directory is writeable by the user zuser
+ (if zuser is NULL, then it must be writeable by any user); this is
+ to avoid a window of vulnerability between fsysdep_in_directory and
+ fsysdep_move_file. This function should return FALSE on error; the
+ zorig file should be removed even if an error occurs. */
+extern boolean fsysdep_move_file P((const char *zorig, const char *zto,
+ boolean fmkdirs, boolean fpublic,
+ boolean fcheck, const char *zuser));
+
+/* Change the mode of a file. The imode argument is a Unix mode.
+ This should return FALSE on error. */
+extern boolean fsysdep_change_mode P((const char *zfile,
+ unsigned int imode));
+
+/* Truncate a file which we are receiving into. This may be done by
+ closing the original file, removing it and reopening it. This
+ should return FALSE on error. */
+extern openfile_t esysdep_truncate P((openfile_t e, const char *zname));
+
+/* It is possible for the acknowledgement of a received file to be
+ lost. The sending system will then now know that the file was
+ correctly received, and will send it again. This can be a problem
+ particularly with protocols which support channels, since they may
+ send several small files in a single window, all of which may be
+ received correctly although the sending system never sees the
+ acknowledgement. If these files involve an execution, the
+ execution will happen twice, which will be bad.
+
+ This function is called when a file is completely received. It is
+ supposed to try and remember the reception, in case the connection
+ is lost. It is passed the system, the file name to receive to, and
+ the temporary file name from the sending system. It should return
+ FALSE on error. */
+extern boolean fsysdep_remember_reception P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* This function is called to see if a file has already been received
+ successfully. It gets the same arguments as
+ fsysdep_remember_reception. It should return TRUE if the file was
+ already received, FALSE otherwise. There is no way to report
+ error. */
+extern boolean fsysdep_already_received P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* This function is called when it is no longer necessary to remember
+ that a file has been received. This will be called when the
+ protocol knows that the receive message has been acknowledged. It
+ gets the same arguments as fsysdep_remember_reception. it should
+ return FALSE on error. */
+extern boolean fsysdep_forget_reception P((const struct uuconf_system *qsys,
+ const char *zto,
+ const char *ztemp));
+
+/* Start expanding a wildcarded file name. This should return FALSE
+ on error; otherwise subsequent calls to zsysdep_wildcard should
+ return file names. */
+extern boolean fsysdep_wildcard_start P((const char *zfile));
+
+/* Get the next wildcard name. This should return NULL when there are
+ no more names to return. The return value should be freed using
+ ubuffree. The argument should be the same as that to
+ fsysdep_wildcard_start. There is no way to return error. */
+extern char *zsysdep_wildcard P((const char *zfile));
+
+/* Finish getting wildcard names. This may be called before or after
+ zsysdep_wildcard has returned NULL. It should return FALSE on
+ error. */
+extern boolean fsysdep_wildcard_end P((void));
+
+/* Prepare to execute a bunch of file transfer requests. This should
+ make an entry in the spool directory so that the next time uucico
+ is started up it will transfer these files. The bgrade argument
+ specifies the grade of the commands. The commands themselves are
+ in the pascmds array, which has ccmds entries. The function should
+ return NULL on error, or the jobid on success. The jobid is a
+ string that may be printed or passed to fsysdep_kill_job and
+ related functions, but is otherwise uninterpreted. */
+extern char *zsysdep_spool_commands P((const struct uuconf_system *qsys,
+ int bgrade, int ccmds,
+ const struct scmd *pascmds));
+
+/* Get a file name to use for a data file to be copied to another
+ system. The ztname, zdname and zxname arguments will all either be
+ NULL or point to an array of CFILE_NAME_LEN characters in length.
+ The ztname array should be set to a temporary file name that could
+ be passed to zsysdep_spool_file_name to retrieve the return value
+ of this function; this will be appropriate for the temporary name
+ in a send request. The zdname array should be set to a data file
+ name that is appropriate for the spool directory of the other
+ system; this will be appropriate for the name of the destination
+ file in a send request of a data file for an execution of some
+ sort. The zxname array should be set to an execute file name that
+ is appropriate for the other system. The zlocalname argument is
+ the name of the local system as seen by the remote system, the
+ bgrade argument is the grade, and fxqt is TRUE if this file is
+ going to become an execution file. This should return NULL on
+ error. */
+#define CFILE_NAME_LEN (15)
+
+extern char *zsysdep_data_file_name P((const struct uuconf_system *qsys,
+ const char *zlocalname,
+ int bgrade, boolean fxqt,
+ char *ztname, char *zdname,
+ char *zxname));
+
+/* Get a name for a local execute file. This is used by uux for a
+ local command with remote files. Returns NULL on error. */
+extern char *zsysdep_xqt_file_name P((void));
+
+/* Beginning getting execute files. To get a list of execute files,
+ first fsysdep_get_xqt_init is called, then zsysdep_get_xqt is
+ called several times until it returns NULL, then finally
+ usysdep_get_xqt_free is called. */
+extern boolean fsysdep_get_xqt_init P((void));
+
+/* Get the next execute file. This should return NULL when finished
+ (with *pferr set to FALSE). On an error this should return NULL
+ with *pferr set to TRUE. This should set *pzsystem to the name of
+ the system for which the execute file was created. Both the return
+ value and *pzsystem should be freed using ubuffree. */
+extern char *zsysdep_get_xqt P((char **pzsystem,
+ boolean *pferr));
+
+/* Clean up after getting execute files. */
+extern void usysdep_get_xqt_free P((void));
+
+/* Get the absolute pathname of a command to execute. This is given
+ the legal list of commands (which may be the special case "ALL")
+ and the path. It must return an absolute pathname to the command.
+ If it gets an error it should set *pferr to TRUE and return NULL;
+ if the command is not found it should set *pferr to FALSE and
+ return NULL. */
+extern char *zsysdep_find_command P((const char *zcmd, char **pzcmds,
+ char **pzpath, boolean *pferr));
+
+/* Expand file names for uuxqt. This exists because uuxqt on Unix has
+ to expand file names which begin with a ~. It does not want to
+ expand any other type of file name, and it turns a double ~ into a
+ single one without expanding. If this returns NULL, the file does
+ not need to be changed; otherwise it returns a zbufalc'ed string.
+ There is no way to report error. */
+extern char *zsysdep_xqt_local_file P((const struct uuconf_system *qsys,
+ const char *zfile));
+
+#if ! ALLOW_FILENAME_ARGUMENTS
+/* Check an argument to an execution command to make sure that it
+ doesn't refer to a file name that may not be accessed. This should
+ check the argument to see if it is a filename. If it is, it should
+ either reject it out of hand or it should call fin_directory_list
+ on the file with both qsys->zremote_receive and qsys->zremote_send.
+ If the file is rejected, it should log an error and return FALSE.
+ Otherwise it should return TRUE. */
+extern boolean fsysdep_xqt_check_file P((const struct uuconf_system *qsys,
+ const char *zfile));
+#endif /* ! ALLOW_FILENAME_ARGUMENTS */
+
+/* Run an execute file. The arguments are:
+
+ qsys -- system for which execute file was created
+ zuser -- user who requested execution
+ pazargs -- list of arguments to command (element 0 is command)
+ zfullcmd -- command and arguments stuck together in one string
+ zinput -- file name for standard input (may be NULL)
+ zoutput -- file name for standard output (may be NULL)
+ fshell -- if TRUE, use /bin/sh to execute file
+ ilock -- return value of ixsysdep_lock_uuxqt
+ pzerror -- set to name of standard error file
+ pftemp -- set to TRUE if error is temporary, FALSE otherwise
+
+ If fshell is TRUE, the command should be executed with /bin/sh
+ (obviously, this can only really be done on Unix systems). If an
+ error occurs this should return FALSE and set *pftemp
+ appropriately. *pzerror should be freed using ubuffree. */
+extern boolean fsysdep_execute P((const struct uuconf_system *qsys,
+ const char *zuser,
+ const char **pazargs,
+ const char *zfullcmd,
+ const char *zinput,
+ const char *zoutput,
+ boolean fshell,
+ int ilock,
+ char **pzerror,
+ boolean *pftemp));
+
+/* Lock for uuxqt execution. If the cmaxuuxqts argument is not zero,
+ this should make sure that no more than cmaxuuxqts uuxqt processes
+ are running at once. Also, only one uuxqt may execute a particular
+ command (specified by the -c option) at a time. If zcmd is not
+ NULL, it is a command that must be locked. This should return a
+ nonnegative number which will be passed to other routines,
+ including fsysdep_unlock_uuxqt, or -1 on error. */
+extern int ixsysdep_lock_uuxqt P((const char *zcmd,
+ int cmaxuuxqts));
+
+/* Unlock a uuxqt process. This is passed the return value of
+ ixsysdep_lock_uuxqt, as well as the arguments passed to
+ ixsysdep_lock_uuxqt. It may return FALSE on error, but at present
+ the return value is ignored. */
+extern boolean fsysdep_unlock_uuxqt P((int iseq, const char *zcmd,
+ int cmaxuuxqts));
+
+/* See whether a particular uuxqt command is locked. This should
+ return TRUE if the command is locked (because ixsysdep_lock_uuxqt
+ was called with it as an argument), FALSE otherwise. There is no
+ way to return error. */
+extern boolean fsysdep_uuxqt_locked P((const char *zcmd));
+
+/* Lock an execute file in order to execute it. This should return
+ FALSE if the execute file is already locked. There is no way to
+ return error. */
+extern boolean fsysdep_lock_uuxqt_file P((const char *zfile));
+
+/* Unlock an execute file. This should return FALSE on error. */
+extern boolean fsysdep_unlock_uuxqt_file P((const char *zfile));
+
+/* Lock the execution directory. The ilock argument is the return
+ value of ixsysdep_lock_uuxqt. This should return FALSE if the
+ directory is already locked. There is no way to return error. */
+extern boolean fsysdep_lock_uuxqt_dir P((int ilock));
+
+/* Remove all files in the execution directory, and unlock it. This
+ should return FALSE on error. */
+extern boolean fsysdep_unlock_uuxqt_dir P((int ilock));
+
+/* Move files into or out of the execution directory. The code will
+ already have checked that all the files exist. The elements in the
+ pzfrom array will be complete filenames, and the elements in the
+ pzto array will be either NULL (in which case the file should not
+ be moved) or simple base names. If fto is TRUE, the files in
+ pzfrom should be moved to pzto; otherwise, the files in pzto should
+ be moved to pzfrom (this is used if a temporary failure occurs, in
+ which case the execution will be retried later). If pzinput and
+ *pzinput are not NULL, then it is the name of the standard input
+ file; if it is the same as any element of pzfrom, then *pzinput
+ should be set to the zbufcpy of the corresponding pzto value, if
+ any. */
+extern boolean fsysdep_move_uuxqt_files P((int cfiles,
+ const char *const *pzfrom,
+ const char *const *pzto,
+ boolean fto, int ilock,
+ char **pzinput));
+
+/* Expand a file name on the local system, defaulting to the current
+ directory. This is just like zsysdep_local_file, except that
+ relative files are placed in the working directory the program
+ started in rather than in the public directory. This should return
+ NULL on error. */
+extern char *zsysdep_local_file_cwd P((const char *zname,
+ const char *zpubdir));
+
+/* Add the working directory to a file name. The named file is
+ actually on a remote system. If the file already has a directory,
+ it should not be changed. This should return NULL on error. */
+extern char *zsysdep_add_cwd P((const char *zfile));
+
+/* See whether a file name will need the current working directory
+ when zsysdep_local_file_cwd or zsysdep_add_cwd is called on it.
+ This will be called before usysdep_initialize. It should just
+ check whether the argument is an absolute path. See the comment
+ above usysdep_initialize in this file for an explanation of why
+ things are done this way. */
+extern boolean fsysdep_needs_cwd P((const char *zfile));
+
+/* Get the base name of a file. The file will be a local file name,
+ and this function should return the base file name, ideally in a
+ form which will make sense on most systems; it will be used if the
+ destination of a uucp is a directory. */
+extern char *zsysdep_base_name P((const char *zfile));
+
+/* Return a filename within a directory. */
+extern char *zsysdep_in_dir P((const char *zdir, const char *zfile));
+
+/* Get the mode of a file. This should return a Unix style file mode.
+ It should return 0 on error. */
+extern unsigned int ixsysdep_file_mode P((const char *zfile));
+
+/* See whether the user has access to a file. This is called by uucp
+ and uux to prevent copying of a file which uucp can read but the
+ user cannot. If access is denied, this should log an error message
+ and return FALSE. */
+extern boolean fsysdep_access P((const char *zfile));
+
+/* See whether the daemon has access to a file. This is called by
+ uucp and uux when a file is queued up for transfer without being
+ copied into the spool directory. It is merely an early error
+ check, as the daemon would of course discover the error itself when
+ it tried the transfer. If access would be denied, this should log
+ an error message and return FALSE. */
+extern boolean fsysdep_daemon_access P((const char *zfile));
+
+/* Translate a destination from system!user to a place in the public
+ directory where uupick will get the file. On Unix this produces
+ system!~/receive/user/localname, and that's probably what it has to
+ produce on any other system as well. Returns NULL on a usage
+ error, or otherwise returns string allocated by zbufcpy. */
+extern char *zsysdep_uuto P((const char *zdest,
+ const char *zlocalname));
+
+/* Return TRUE if a pathname exists and is a directory. */
+extern boolean fsysdep_directory P((const char *zpath));
+
+/* Walk a directory tree. The zdir argument is the directory to walk.
+ The pufn argument is a function to call on each regular file in the
+ tree. The first argument to pufn should be the full filename; the
+ second argument to pufn should be the filename relative to zdir;
+ the third argument to pufn should be the pinfo argument to
+ usysdep_walk_tree. The usysdep_walk_tree function should return
+ FALSE on error. */
+extern boolean usysdep_walk_tree P((const char *zdir,
+ void (*pufn) P((const char *zfull,
+ const char *zrelative,
+ pointer pinfo)),
+ pointer pinfo));
+
+/* Return the jobid of a work file, given the sequence value. On
+ error this should log an error and return NULL. The jobid is a
+ string which may be printed out and read in and passed to
+ fsysdep_kill_job, etc., but is not otherwise interpreted. */
+extern char *zsysdep_jobid P((const struct uuconf_system *qsys,
+ pointer pseq));
+
+/* See whether the current user is permitted to kill jobs submitted by
+ another user. This should return TRUE if permission is granted,
+ FALSE otherwise. */
+extern boolean fsysdep_privileged P((void));
+
+/* Kill a job, given the jobid. This should remove all associated
+ files and in general eliminate the job completely. On error it
+ should log an error message and return FALSE. */
+extern boolean fsysdep_kill_job P((pointer puuconf,
+ const char *zjobid));
+
+/* Rejuvenate a job, given the jobid. If possible, this should update
+ the time associated with the job such that it will not be
+ eliminated by uustat -K or similar programs that check the creation
+ time. This should affect the return value of ixsysdep_work_time.
+ On error it should log an error message and return FALSE. */
+extern boolean fsysdep_rejuvenate_job P((pointer puuconf,
+ const char *zjobid));
+
+/* Get the time a job was queued, given the sequence number. There is
+ no way to indicate error. The return value must use the same epoch
+ as ixsysdep_time. */
+extern long ixsysdep_work_time P((const struct uuconf_system *qsys,
+ pointer pseq));
+
+/* Get the time a file was created. This is called by uustat on
+ execution files. There is no way to indicate error. The return
+ value must use the same epoch as ixsysdep_time. */
+extern long ixsysdep_file_time P((const char *zfile));
+
+/* Get the size in bytes of a file. If this file does not exist, this
+ should not give an error message, but should return -1. If some
+ other error occurs, this should return -2. */
+extern long csysdep_size P((const char *zfile));
+
+/* Return the amount of free space on the containing the given file
+ name (the file may or may not exist). If the amount of free space
+ cannot be determined, the function should return -1. */
+extern long csysdep_bytes_free P((const char *zfile));
+
+/* Start getting status information for all systems with available
+ status information. There may be status information for unknown
+ systems, which is why this series of functions is used. The phold
+ argument is used to pass information around, to possibly avoid the
+ use of static variables. On error this should log an error and
+ return FALSE. */
+extern boolean fsysdep_all_status_init P((pointer *phold));
+
+/* Get status information for the next system. This should return the
+ system name and fill in the qstat argument. The phold argument
+ will be that set by fsysdep_all_status_init. On error this should
+ log an error, set *pferr to TRUE, and return NULL. */
+extern char *zsysdep_all_status P((pointer phold, boolean *pferr,
+ struct sstatus *qstat));
+
+/* Free up anything allocated by fsysdep_all_status_init and
+ zsysdep_all_status. The phold argument is that set by
+ fsysdep_all_status_init. */
+extern void usysdep_all_status_free P((pointer phold));
+
+/* Display the process status of all processes holding lock files.
+ This is uustat -p. The return value is passed to usysdep_exit. */
+extern boolean fsysdep_lock_status P((void));
+
+/* Return TRUE if the user has legitimate access to the port. This is
+ used by cu to control whether the user can open a port directly,
+ rather than merely being able to dial out on it. Opening a port
+ directly allows the modem to be reprogrammed. */
+extern boolean fsysdep_port_access P((struct uuconf_port *qport));
+
+/* Return whether the given port could be named by the given line. On
+ Unix, the line argument would be something like "ttyd0", and this
+ function should return TRUE if the named port is "/dev/ttyd0". */
+extern boolean fsysdep_port_is_line P((struct uuconf_port *qport,
+ const char *zline));
+
+/* Set the terminal into raw mode. In this mode no input characters
+ should be treated specially, and characters should be made
+ available as they are typed. The original terminal mode should be
+ saved, so that it can be restored by fsysdep_terminal_restore. If
+ flocalecho is TRUE, then local echoing should still be done;
+ otherwise echoing should be disabled. This function returns FALSE
+ on error. */
+extern boolean fsysdep_terminal_raw P((boolean flocalecho));
+
+/* Restore the terminal back to the original setting, before
+ fsysdep_terminal_raw was called. Returns FALSE on error. */
+extern boolean fsysdep_terminal_restore P((void));
+
+/* Read a line from the terminal. The fsysdep_terminal_raw function
+ will have been called. This should print the zprompt argument
+ (unless it is NULL) and return the line, allocated by zbufcpy, or
+ NULL on error. */
+extern char *zsysdep_terminal_line P((const char *zprompt));
+
+/* Write a line to the terminal, ending with a newline. This is
+ basically just puts (zline, stdout), except that the terminal will
+ be in raw mode, so on ASCII Unix systems the line needs to end with
+ \r\n. */
+extern boolean fsysdep_terminal_puts P((const char *zline));
+
+/* If faccept is TRUE, permit the user to generate signals from the
+ terminal. If faccept is FALSE, turn signals off again. After
+ fsysdep_terminal_raw is called, signals should be off. Return
+ FALSE on error. */
+extern boolean fsysdep_terminal_signals P((boolean faccept));
+
+/* The cu program expects the system dependent code to handle the
+ details of copying data from the communications port to the
+ terminal. This should be set up by fsysdep_cu_init, and done while
+ fsysdep_cu is called. It is permissible to do it on a continual
+ basis (on Unix a subprocess handles it) so long as the copying can
+ be stopped by the fsysdep_cu_copy function.
+
+ The fsysdep_cu_init function does any system dependent
+ initialization needed for this. */
+extern boolean fsysdep_cu_init P((struct sconnection *qconn));
+
+/* Copy all data from the communications port to the terminal, and all
+ data from the terminal to the communications port. Keep this up
+ until the escape character *zCuvar_escape is seen. Set *pbcmd to
+ the character following the escape character; after the escape
+ character, zlocalname should be printed, possibly after a delay.
+ If two escape characters are entered in sequence, this function
+ should send a single escape character to the port, and not return.
+ Returns FALSE on error. */
+extern boolean fsysdep_cu P((struct sconnection *qconn,
+ char *pbcmd,
+ const char *zlocalname));
+
+/* If fcopy is TRUE, start copying data from the communications port
+ to the terminal. If fcopy is FALSE, stop copying data. This
+ function may be called several times during a cu session. It
+ should return FALSE on error. */
+extern boolean fsysdep_cu_copy P((boolean fcopy));
+
+/* Stop copying data from the communications port to the terminal, and
+ generally clean up after fsysdep_cu_init and fsysdep_cu. Returns
+ FALSE on error. */
+extern boolean fsysdep_cu_finish P((void));
+
+/* Run a shell command. If zcmd is NULL, or *zcmd == '\0', just
+ start up a shell. The second argument is one of the following
+ values. This should return FALSE on error. */
+enum tshell_cmd
+{
+ /* Attach stdin and stdout to the terminal. */
+ SHELL_NORMAL,
+ /* Attach stdout to the communications port, stdin to the terminal. */
+ SHELL_STDOUT_TO_PORT,
+ /* Attach stdin to the communications port, stdout to the terminal. */
+ SHELL_STDIN_FROM_PORT,
+ /* Attach both stdin and stdout to the communications port. */
+ SHELL_STDIO_ON_PORT
+};
+
+extern boolean fsysdep_shell P((struct sconnection *qconn,
+ const char *zcmd,
+ enum tshell_cmd tcmd));
+
+/* Change directory. If zdir is NULL, or *zdir == '\0', change to the
+ user's home directory. Return FALSE on error. */
+extern boolean fsysdep_chdir P((const char *zdir));
+
+/* Suspend the current process. This is only expected to work on Unix
+ versions that support SIGTSTP. In general, people can just shell
+ out. */
+extern boolean fsysdep_suspend P((void));
+
+/* Start getting files for uupick. The zsystem argument may be NULL
+ to get files from all systems, or it may specify a particular
+ system. The zpubdir argument is the public directory to use. This
+ returns FALSE on error. */
+extern boolean fsysdep_uupick_init P((const char *zsystem,
+ const char *zpubdir));
+
+/* Get the next file for uupick. This returns the basic file name.
+ It sets *pzfull to the full name, and *pzfrom to the name of the
+ system which sent this file over; both should be freed using
+ ubuffree. *pzfull should be passed to ubuffree after it is no
+ longer needed. The zsystem and zpubdir arguments should be the
+ same as the arguments to fsysdep_uupick_init. This returns NULL
+ when all files been returned. */
+extern char *zsysdep_uupick P((const char *zsystem, const char *zpubdir,
+ char **pzfrom, char **pzfull));
+
+/* Clean up after getting files for uupick. */
+extern boolean fsysdep_uupick_free P((const char *zsystem,
+ const char *zpubdir));
+
+/* Translate a local file name for uupick. On Unix this is just like
+ zsysdep_local_file_cwd except that a file beginning with ~/ is
+ placed in the user's home directory rather than in the public
+ directory. */
+extern char *zsysdep_uupick_local_file P((const char *zfile));
+
+/* Remove a directory and all the files in it. */
+extern boolean fsysdep_rmdir P((const char *zdir));
+
+#endif /* ! defined (SYSTEM_H) */
diff --git a/gnu/libexec/uucp/common_sources/tcp.c b/gnu/libexec/uucp/common_sources/tcp.c
new file mode 100644
index 0000000..c38760d
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/tcp.c
@@ -0,0 +1,470 @@
+/* tcp.c
+ Code to handle TCP connections.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char tcp_rcsid[] = "$Id: tcp.c,v 1.1 1993/08/04 19:31:06 jtc Exp $";
+#endif
+
+#if HAVE_TCP
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "conn.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_TYPES_TCP_H
+#include <sys/types.tcp.h>
+#endif
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* This code handles TCP connections. It assumes a Berkeley socket
+ interface. */
+
+/* The normal "uucp" port number. */
+#define IUUCP_PORT (540)
+
+/* Local functions. */
+static void utcp_free P((struct sconnection *qconn));
+static boolean ftcp_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean ftcp_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean ftcp_reset P((struct sconnection *qconn));
+static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialer));
+static int itcp_port_number P((const char *zport));
+
+/* The command table for a TCP connection. */
+static const struct sconncmds stcpcmds =
+{
+ utcp_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ ftcp_open,
+ ftcp_close,
+ ftcp_reset,
+ ftcp_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ NULL, /* pfbreak */
+ NULL, /* pfset */
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ NULL /* pibaud */
+};
+
+/* Initialize a TCP connection. */
+
+boolean
+fsysdep_tcp_init (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ q->o = -1;
+ q->zdevice = NULL;
+ q->iflags = -1;
+ q->istdout_flags = -1;
+ q->fterminal = FALSE;
+ q->ftli = FALSE;
+ q->ibaud = 0;
+
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = &stcpcmds;
+ return TRUE;
+}
+
+/* Free a TCP connection. */
+
+static void
+utcp_free (qconn)
+ struct sconnection *qconn;
+{
+ xfree (qconn->psysdep);
+}
+
+/* Open a TCP connection. If the fwait argument is TRUE, we are
+ running as a server. Otherwise we are just trying to reach another
+ system. */
+
+static boolean
+ftcp_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *qsysdep;
+ struct sockaddr_in s;
+ const char *zport;
+ uid_t iuid, ieuid;
+
+ ulog_device ("TCP");
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ qsysdep->o = socket (AF_INET, SOCK_STREAM, 0);
+ if (qsysdep->o < 0)
+ {
+ ulog (LOG_ERROR, "socket: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
+ if (qsysdep->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ /* If we aren't waiting for a connection, we're done. */
+ if (! fwait)
+ return TRUE;
+
+ /* Run as a server and wait for a new connection. The code in
+ uucico.c has already detached us from our controlling terminal.
+ From this point on if the server gets an error we exit; we only
+ return if we have received a connection. It would be more robust
+ to respawn the server if it fails; someday. */
+ bzero ((pointer) &s, sizeof s);
+ s.sin_family = AF_INET;
+ zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
+ s.sin_port = itcp_port_number (zport);
+ s.sin_addr.s_addr = htonl (INADDR_ANY);
+
+ /* Swap to our real user ID when doing the bind call. This will
+ permit the server to use privileged TCP ports when invoked by
+ root. We only swap if our effective user ID is not root, so that
+ the program can also be made suid root in order to get privileged
+ ports when invoked by anybody. */
+ iuid = getuid ();
+ ieuid = geteuid ();
+ if (ieuid != 0)
+ {
+#if HAVE_SETREUID
+ /* Swap the effective user id and the real user id. We can then
+ swap them back again when we want to return to the uucp
+ user's permissions. */
+ if (setreuid (ieuid, iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) ieuid, (long) iuid, strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set the effective user id to the real user id. Since the
+ effective user id is the saved setuid we will able to set
+ back to it later. If the real user id is root we will not be
+ able to switch back and forth, but that doesn't matter since
+ we only want to switch once. */
+ if (setuid (iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid,
+ strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* There's no way to switch between real permissions and
+ effective permissions. Just try the bind with the uucp
+ permissions. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+ }
+
+ if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
+ ulog (LOG_FATAL, "bind: %s", strerror (errno));
+
+ /* Now swap back to the uucp user ID. */
+ if (ieuid != 0)
+ {
+#if HAVE_SETREUID
+ if (setreuid (iuid, ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) iuid, (long) ieuid, strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set ourselves back to our original effective user id. */
+ if (setuid ((uid_t) ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid,
+ strerror (errno));
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* We didn't switch, no need to switch back. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+ }
+
+ if (listen (qsysdep->o, 5) < 0)
+ ulog (LOG_FATAL, "listen: %s", strerror (errno));
+
+ while (! FGOT_SIGNAL ())
+ {
+ size_t clen;
+ int onew;
+ pid_t ipid;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftcp_open: Waiting for connections");
+
+ clen = sizeof s;
+ onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen);
+ if (onew < 0)
+ ulog (LOG_FATAL, "accept: %s", strerror (errno));
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftcp_open: Got connection; forking");
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+ if (ipid == 0)
+ {
+ (void) close (qsysdep->o);
+ qsysdep->o = onew;
+
+ /* Now we fork and let our parent die, so that we become
+ a child of init. This lets the main server code wait
+ for its child and then continue without accumulating
+ zombie children. */
+ ipid = ixsfork ();
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ ulog_id (getpid ());
+
+ return TRUE;
+ }
+
+ (void) close (onew);
+
+ /* Now wait for the child. */
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ }
+
+ /* We got a signal. */
+ usysdep_exit (FALSE);
+
+ /* Avoid compiler warnings. */
+ return FALSE;
+}
+
+/* Close the port. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ fret = TRUE;
+ if (qsysdep->o >= 0 && close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->o = -1;
+ return fret;
+}
+
+/* Reset the port. This will be called by a child which was forked
+ off in ftcp_open, above. We don't want uucico to continue looping
+ and giving login prompts, so we pretend that we received a SIGINT
+ signal. This should probably be handled more cleanly. The signal
+ will not be recorded in the log file because we don't set
+ afLog_signal[INDEXSIG_SIGINT]. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_reset (qconn)
+ struct sconnection *qconn;
+{
+ afSignal[INDEXSIG_SIGINT] = TRUE;
+ return TRUE;
+}
+
+/* Dial out on a TCP port, so to speak: connect to a remote computer. */
+
+/*ARGSUSED*/
+static boolean
+ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialer;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *zhost;
+ struct hostent *q;
+ struct sockaddr_in s;
+ const char *zport;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ *ptdialer = DIALERFOUND_FALSE;
+
+ zhost = zphone;
+ if (zhost == NULL)
+ {
+ if (qsys == NULL)
+ {
+ ulog (LOG_ERROR, "No address for TCP connection");
+ return FALSE;
+ }
+ zhost = qsys->uuconf_zname;
+ }
+
+ errno = 0;
+ q = gethostbyname ((char *) zhost);
+ if (q == NULL)
+ {
+ if (errno == 0)
+ ulog (LOG_ERROR, "%s: unknown host name", zhost);
+ else
+ ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno));
+ return FALSE;
+ }
+
+ s.sin_family = q->h_addrtype;
+ zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport;
+ s.sin_port = itcp_port_number (zport);
+ memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length);
+
+ if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0)
+ {
+ ulog (LOG_ERROR, "connect: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Get the port number given a name. The argument will almost always
+ be "uucp" so we cache that value. The return value is always in
+ network byte order. This returns -1 on error. */
+
+static int
+itcp_port_number (zname)
+ const char *zname;
+{
+ boolean fuucp;
+ static int iuucp;
+ int i;
+ char *zend;
+ struct servent *q;
+
+ fuucp = strcmp (zname, "uucp") == 0;
+ if (fuucp && iuucp != 0)
+ return iuucp;
+
+ /* Try it as a number first. */
+ i = strtol ((char *) zname, &zend, 10);
+ if (i != 0 && *zend == '\0')
+ return htons (i);
+
+ q = getservbyname ((char *) zname, (char *) "tcp");
+ if (q == NULL)
+ {
+ /* We know that the "uucp" service should be 540, even if isn't
+ in /etc/services. */
+ if (fuucp)
+ {
+ iuucp = htons (IUUCP_PORT);
+ return iuucp;
+ }
+ ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno));
+ return -1;
+ }
+
+ if (fuucp)
+ iuucp = q->s_port;
+
+ return q->s_port;
+}
+
+#endif /* HAVE_TCP */
diff --git a/gnu/libexec/uucp/common_sources/tli.c b/gnu/libexec/uucp/common_sources/tli.c
new file mode 100644
index 0000000..6958b80
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/tli.c
@@ -0,0 +1,644 @@
+/* tli.c
+ Code to handle TLI connections.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char tli_rcsid[] = "$Id: tli.c,v 1.1 1993/08/04 19:31:09 jtc Exp $";
+#endif
+
+#if HAVE_TLI
+
+#include "sysdep.h"
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_TIUSER_H
+#include <tiuser.h>
+#else
+#if HAVE_XTI_H
+#include <xti.h>
+#else
+#if HAVE_SYS_TLI_H
+#include <sys/tli.h>
+#endif
+#endif
+#endif
+
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* The arguments to t_alloca have two different names. I want the
+ SVID ones, not the XPG3 ones. */
+#ifndef T_BIND
+#define T_BIND T_BIND_STR
+#endif
+#ifndef T_CALL
+#define T_CALL T_CALL_STR
+#endif
+
+/* Hopefully these externs will not cause any trouble. This is how
+ they are shown in the SVID. */
+extern int t_errno;
+extern char *t_errlist[];
+extern int t_nerr;
+
+#ifndef t_alloc
+extern pointer t_alloc ();
+#endif
+
+/* This code handles TLI connections. It's Unix specific. It's
+ largely based on code from Unix Network Programming, by W. Richard
+ Stevens. */
+
+/* Local functions. */
+static const char *ztlierror P((void));
+static void utli_free P((struct sconnection *qconn));
+static boolean ftli_push P((struct sconnection *qconn));
+static boolean ftli_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean ftli_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean ftli_reset P((struct sconnection *qconn));
+static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf,
+ const struct uuconf_system *qsys,
+ const char *zphone,
+ struct uuconf_dialer *qdialer,
+ enum tdialerfound *ptdialer));
+
+/* The command table for a TLI connection. */
+static const struct sconncmds stlicmds =
+{
+ utli_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ ftli_open,
+ ftli_close,
+ ftli_reset,
+ ftli_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ NULL, /* pfbreak */
+ NULL, /* pfset */
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ NULL /* pibaud */
+};
+
+/* Get a TLI error string. */
+
+static const char *
+ztlierror ()
+{
+ if (t_errno == TSYSERR)
+ return strerror (errno);
+ if (t_errno < 0 || t_errno >= t_nerr)
+ return "Unknown TLI error";
+ return t_errlist[t_errno];
+}
+
+/* Initialize a TLI connection. */
+
+boolean
+fsysdep_tli_init (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ q->o = -1;
+ q->zdevice = NULL;
+ q->iflags = -1;
+ q->istdout_flags = -1;
+ q->fterminal = FALSE;
+ q->ftli = TRUE;
+ q->ibaud = 0;
+
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = &stlicmds;
+ return TRUE;
+}
+
+/* Free a TLI connection. */
+
+static void
+utli_free (qconn)
+ struct sconnection *qconn;
+{
+ xfree (qconn->psysdep);
+}
+
+/* Push all desired modules onto a TLI stream. If the user requests a
+ STREAMS connection without giving a list of modules, we just push
+ tirdwr. If the I_PUSH ioctl is not defined on this system, we just
+ ignore any list of modules. */
+
+static boolean
+ftli_push (qconn)
+ struct sconnection *qconn;
+{
+#ifdef I_PUSH
+
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL)
+ {
+ char **pz;
+
+ for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush;
+ *pz != NULL;
+ pz++)
+ {
+ if (ioctl (qsysdep->o, I_PUSH, *pz) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz,
+ strerror (errno));
+ return FALSE;
+ }
+ }
+ }
+ else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
+ {
+ if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+ /* If we have just put the connection into stream mode, we must turn
+ off the TLI flag to avoid using TLI calls on it. */
+ if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream)
+ qsysdep->ftli = FALSE;
+
+#endif /* defined (I_PUSH) */
+
+ return TRUE;
+}
+
+/* Open a TLI connection. If the fwait argument is TRUE, we are
+ running as a server. Otherwise we are just trying to reach another
+ system. */
+
+static boolean
+ftli_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *zdevice;
+ char *zfreedev;
+ const char *zservaddr;
+ char *zfreeaddr;
+ struct t_bind *qtbind;
+ struct t_call *qtcall;
+
+ /* Unlike most other device types, we don't bother to call
+ ulog_device here, because fconn_open calls it with the name of
+ the port anyhow. */
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice;
+ if (zdevice == NULL)
+ zdevice = qconn->qport->uuconf_zname;
+
+ zfreedev = NULL;
+ if (*zdevice != '/')
+ {
+ zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice));
+ sprintf (zfreedev, "/dev/%s", zdevice);
+ zdevice = zfreedev;
+ }
+
+ qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
+ if (qsysdep->o < 0)
+ {
+ ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ());
+ ubuffree (zfreedev);
+ return FALSE;
+ }
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ubuffree (zfreedev);
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0);
+ if (qsysdep->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ ubuffree (zfreedev);
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+
+ /* If we aren't waiting for a connection, we can bind to any local
+ address, and then we're finished. */
+ if (! fwait)
+ {
+ ubuffree (zfreedev);
+ if (t_bind (qsysdep->o, (struct t_bind *) NULL,
+ (struct t_bind *) NULL) < 0)
+ {
+ ulog (LOG_ERROR, "t_bind: %s", ztlierror ());
+ (void) t_close (qsysdep->o);
+ qsysdep->o = -1;
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ /* Run as a server and wait for a new connection. The code in
+ uucico.c has already detached us from our controlling terminal.
+ From this point on if the server gets an error we exit; we only
+ return if we have received a connection. It would be more robust
+ to respawn the server if it fails; someday. */
+ qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL);
+ if (qtbind == NULL)
+ ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ());
+
+ zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr;
+ if (zservaddr == NULL)
+ ulog (LOG_FATAL, "Can't run as TLI server; no server address");
+
+ zfreeaddr = zbufcpy (zservaddr);
+ qtbind->addr.len = cescape (zfreeaddr);
+ if (qtbind->addr.len > qtbind->addr.maxlen)
+ ulog (LOG_FATAL, "%s: TLI server address too long (max %d)",
+ zservaddr, qtbind->addr.maxlen);
+ memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len);
+ ubuffree (zfreeaddr);
+
+ qtbind->qlen = 5;
+
+ if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0)
+ ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ());
+
+ (void) t_free ((pointer) qtbind, T_BIND);
+
+ qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL);
+ if (qtcall == NULL)
+ ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ());
+
+ while (! FGOT_SIGNAL ())
+ {
+ int onew;
+ pid_t ipid;
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftli_open: Waiting for connections");
+
+ if (t_listen (qsysdep->o, qtcall) < 0)
+ ulog (LOG_FATAL, "t_listen: %s", ztlierror ());
+
+ onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL);
+ if (onew < 0)
+ ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ());
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+
+ if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0)
+ ulog (LOG_FATAL, "t_bind: %s", ztlierror ());
+
+ if (t_accept (qsysdep->o, onew, qtcall) < 0)
+ {
+ /* We may have received a disconnect. */
+ if (t_errno != TLOOK)
+ ulog (LOG_FATAL, "t_accept: %s", ztlierror ());
+ if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
+ ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ());
+ (void) t_close (onew);
+ continue;
+ }
+
+ DEBUG_MESSAGE0 (DEBUG_PORT,
+ "ftli_open: Got connection; forking");
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+ if (ipid == 0)
+ {
+ ulog_close ();
+
+ (void) t_close (qsysdep->o);
+ qsysdep->o = onew;
+
+ /* Push any desired modules. */
+ if (! ftli_push (qconn))
+ _exit (EXIT_FAILURE);
+
+ /* Now we fork and let our parent die, so that we become
+ a child of init. This lets the main server code wait
+ for its child and then continue without accumulating
+ zombie children. */
+ ipid = ixsfork ();
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ ulog_id (getpid ());
+
+ return TRUE;
+ }
+
+ (void) t_close (onew);
+
+ /* Now wait for the child. */
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ }
+
+ /* We got a signal. */
+ usysdep_exit (FALSE);
+
+ /* Avoid compiler warnings. */
+ return FALSE;
+}
+
+/* Close the port. */
+
+/*ARGSUSED*/
+static boolean
+ftli_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ fret = TRUE;
+ if (qsysdep->o >= 0)
+ {
+ if (qsysdep->ftli)
+ {
+ if (t_close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "t_close: %s", ztlierror ());
+ fret = FALSE;
+ }
+ }
+ else
+ {
+ if (close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ }
+
+ qsysdep->o = -1;
+ }
+
+ return fret;
+}
+
+/* Reset the port. This will be called by a child which was forked
+ off in ftli_open, above. We don't want uucico to continue looping
+ and giving login prompts, so we pretend that we received a SIGINT
+ signal. This should probably be handled more cleanly. The signal
+ will not be recorded in the log file because we don't set
+ afLog_signal[INDEXSIG_SIGINT]. */
+
+/*ARGSUSED*/
+static boolean
+ftli_reset (qconn)
+ struct sconnection *qconn;
+{
+ afSignal[INDEXSIG_SIGINT] = TRUE;
+ return TRUE;
+}
+
+/* Dial out on a TLI port, so to speak: connect to a remote computer. */
+
+/*ARGSUSED*/
+static boolean
+ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound)
+ struct sconnection *qconn;
+ pointer puuconf;
+ const struct uuconf_system *qsys;
+ const char *zphone;
+ struct uuconf_dialer *qdialer;
+ enum tdialerfound *ptdialerfound;
+{
+ struct ssysdep_conn *qsysdep;
+ char **pzdialer;
+ const char *zaddr;
+ struct t_call *qtcall;
+ char *zescape;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ *ptdialerfound = DIALERFOUND_FALSE;
+
+ pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer;
+ if (*pzdialer == NULL)
+ pzdialer = NULL;
+
+ /* If the first dialer is "TLI" or "TLIS", we use the first token
+ (pzdialer[1]) as the address to connect to. */
+ zaddr = zphone;
+ if (pzdialer != NULL
+ && (strcmp (pzdialer[0], "TLI") == 0
+ || strcmp (pzdialer[0], "TLIS") == 0))
+ {
+ if (pzdialer[1] == NULL)
+ ++pzdialer;
+ else
+ {
+ if (strcmp (pzdialer[1], "\\D") != 0
+ && strcmp (pzdialer[1], "\\T") != 0)
+ zaddr = pzdialer[1];
+ pzdialer += 2;
+ }
+ }
+
+ if (zaddr == NULL)
+ {
+ ulog (LOG_ERROR, "No address for TLI connection");
+ return FALSE;
+ }
+
+ qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR);
+ if (qtcall == NULL)
+ {
+ ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ());
+ return FALSE;
+ }
+
+ zescape = zbufcpy (zaddr);
+ qtcall->addr.len = cescape (zescape);
+ if (qtcall->addr.len > qtcall->addr.maxlen)
+ {
+ ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr,
+ qtcall->addr.maxlen);
+ ubuffree (zescape);
+ return FALSE;
+ }
+ memcpy (qtcall->addr.buf, zescape, qtcall->addr.len);
+ ubuffree (zescape);
+
+ if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0)
+ {
+ if (t_errno != TLOOK)
+ ulog (LOG_ERROR, "t_connect: %s", ztlierror ());
+ else
+ {
+ if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0)
+ ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ());
+ else
+ ulog (LOG_ERROR, "Connection refused");
+ }
+ return FALSE;
+ }
+
+ /* We've connected to the remote. Push any desired modules. */
+ if (! ftli_push (qconn))
+ return FALSE;
+
+ /* Handle the rest of the dialer sequence. This is similar to
+ fmodem_dial, and they should, perhaps, be combined somehow. */
+ if (pzdialer != NULL)
+ {
+ boolean ffirst;
+
+ ffirst = TRUE;
+ while (*pzdialer != NULL)
+ {
+ int iuuconf;
+ struct uuconf_dialer *q;
+ struct uuconf_dialer s;
+ const char *ztoken;
+ boolean ftranslate;
+
+ if (! ffirst)
+ q = &s;
+ else
+ q = qdialer;
+
+ iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ return FALSE;
+ }
+
+ ++pzdialer;
+ ztoken = *pzdialer;
+
+ ftranslate = FALSE;
+ if (ztoken == NULL
+ || strcmp (ztoken, "\\D") == 0)
+ ztoken = zphone;
+ else if (strcmp (ztoken, "\\T") == 0)
+ {
+ ztoken = zphone;
+ ftranslate = TRUE;
+ }
+
+ if (! fchat (qconn, puuconf, &q->uuconf_schat,
+ (const struct uuconf_system *) NULL, q,
+ zphone, ftranslate, qconn->qport->uuconf_zname,
+ (long) 0))
+ {
+ (void) uuconf_dialer_free (puuconf, q);
+ if (! ffirst)
+ (void) uuconf_dialer_free (puuconf, qdialer);
+ return FALSE;
+ }
+
+ if (ffirst)
+ {
+ *ptdialerfound = DIALERFOUND_FREE;
+ ffirst = FALSE;
+ }
+ else
+ (void) uuconf_dialer_free (puuconf, q);
+
+ if (*pzdialer != NULL)
+ ++pzdialer;
+ }
+ }
+
+ return TRUE;
+}
+
+#endif /* HAVE_TLI */
diff --git a/gnu/libexec/uucp/common_sources/trans.h b/gnu/libexec/uucp/common_sources/trans.h
new file mode 100644
index 0000000..79c380e
--- /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 0000000..2ddc260
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/util.c
@@ -0,0 +1,144 @@
+/* util.c
+ A couple of UUCP utility functions.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char util_rcsid[] = "$Id: util.c,v 1.1 1993/08/04 19:31:13 jtc Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+
+/* Get information for an unknown system. This will leave the name
+ allocated on the heap. We could fix this by breaking the
+ abstraction and adding the name to qsys->palloc. It makes sure the
+ name is not too long, but takes no other useful action. */
+
+boolean
+funknown_system (puuconf, zsystem, qsys)
+ pointer puuconf;
+ const char *zsystem;
+ struct uuconf_system *qsys;
+{
+ char *z;
+ int iuuconf;
+
+ if (strlen (zsystem) <= cSysdep_max_name_len)
+ z = zbufcpy (zsystem);
+ else
+ {
+ char **pznames, **pz;
+ boolean ffound;
+
+ z = zbufalc (cSysdep_max_name_len + 1);
+ memcpy (z, zsystem, cSysdep_max_name_len);
+ z[cSysdep_max_name_len] = '\0';
+
+ iuuconf = uuconf_system_names (puuconf, &pznames, TRUE);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ ffound = FALSE;
+ for (pz = pznames; *pz != NULL; pz++)
+ {
+ if (strcmp (*pz, z) == 0)
+ ffound = TRUE;
+ xfree ((pointer) *pz);
+ }
+ xfree ((pointer) pznames);
+
+ if (ffound)
+ {
+ ubuffree (z);
+ return FALSE;
+ }
+ }
+
+ iuuconf = uuconf_system_unknown (puuconf, qsys);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ ubuffree (z);
+ return FALSE;
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
+ qsys->uuconf_zname = z;
+
+ return TRUE;
+}
+
+/* See whether a file is in a directory list, and make sure the user
+ has appropriate access. */
+
+boolean
+fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser)
+ const char *zfile;
+ char **pzdirs;
+ const char *zpubdir;
+ boolean fcheck;
+ boolean freadable;
+ const char *zuser;
+{
+ boolean fmatch;
+ char **pz;
+
+ fmatch = FALSE;
+
+ for (pz = pzdirs; *pz != NULL; pz++)
+ {
+ char *zuse;
+
+ if (pz[0][0] == '!')
+ {
+ zuse = zsysdep_local_file (*pz + 1, zpubdir);
+ if (zuse == NULL)
+ return FALSE;
+
+ if (fsysdep_in_directory (zfile, zuse, FALSE,
+ FALSE, (const char *) NULL))
+ fmatch = FALSE;
+ }
+ else
+ {
+ zuse = zsysdep_local_file (*pz, zpubdir);
+ if (zuse == NULL)
+ return FALSE;
+
+ if (fsysdep_in_directory (zfile, zuse, fcheck,
+ freadable, zuser))
+ fmatch = TRUE;
+ }
+
+ ubuffree (zuse);
+ }
+
+ return fmatch;
+}
diff --git a/gnu/libexec/uucp/common_sources/uuconf.h b/gnu/libexec/uucp/common_sources/uuconf.h
new file mode 100644
index 0000000..4bf6bcc
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/uuconf.h
@@ -0,0 +1,1496 @@
+/* uuconf.h
+ Header file for UUCP configuration routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The use of an object file which uses material from this header
+ file, and from no other portion of the uuconf library, is
+ unrestricted, as described in paragraph 4 of section 5 of version 2
+ of the GNU Library General Public License (this sentence is merely
+ informative, and does not modify the License in any way).
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#ifndef UUCONF_H
+
+#define UUCONF_H
+
+#include <stdio.h>
+
+/* The macro UUCONF_ANSI_C may be used to override __STDC__. */
+#ifndef UUCONF_ANSI_C
+#ifdef __STDC__
+#define UUCONF_ANSI_C 1
+#else /* ! defined (__STDC__) */
+#define UUCONF_ANSI_C 0
+#endif /* ! defined (__STDC__) */
+#endif /* ! defined (UUCONF_ANSI_C) */
+
+#if UUCONF_ANSI_C
+#define UUCONF_CONST const
+typedef void *UUCONF_POINTER;
+#include <stddef.h>
+typedef size_t UUCONF_SIZE_T;
+#else
+#define UUCONF_CONST
+typedef char *UUCONF_POINTER;
+typedef unsigned int UUCONF_SIZE_T;
+#endif
+
+/* The field names of each of the following structures begin with
+ "uuconf_". This is to avoid any conflicts with user defined
+ macros. The first character following the "uuconf_" string
+ indicates the type of the field.
+
+ z -- a string (char *)
+ c -- a count (normally int)
+ i -- an integer value (normally int)
+ f -- a boolean value (normally int)
+ b -- a single character value (char or int)
+ t -- an enum (enum XX)
+ s -- a structure (struct XX)
+ u -- a union (union XX)
+ q -- a pointer to a structure (struct XX *)
+ p -- a pointer to something other than a string
+ */
+
+/* The information which is kept for a chat script. */
+
+struct uuconf_chat
+{
+ /* The script itself. This is a NULL terminated list of expect/send
+ pairs. The first string is an expect string. A string starting
+ with a '-' indicates subsend string; the following strings which
+ start with '-' are subexpect/subsend strings. This field may be
+ NULL, in which case there is no chat script (but pzprogram may
+ hold a program to run). */
+ char **uuconf_pzchat;
+ /* The chat program to run. This is a NULL terminated list of
+ arguments; element 0 if the program. May be NULL, in which case
+ there is no program. */
+ char **uuconf_pzprogram;
+ /* The timeout in seconds to use for expect strings in the chat
+ script. */
+ int uuconf_ctimeout;
+ /* The NULL terminated list of failure strings. If any of these
+ strings appear, the chat script is aborted. May be NULL, in
+ which case there are no failure strings. */
+ char **uuconf_pzfail;
+ /* Non-zero if incoming characters should be stripped to seven bits
+ (by anding with 0x7f). */
+ int uuconf_fstrip;
+};
+
+/* The information which is kept for a time specification. This is a
+ linked list of structures. Each element of the list represents a
+ span of time, giving a starting time and an ending time. The time
+ only depends on the day of the week, not on the day of the month or
+ of the year. The time is only specified down to the minute, not
+ down to the second or below. The list is sorted by starting time.
+
+ The starting and ending time are expressed in minutes since the
+ beginning of the week, which is considered to be 12 midnight on
+ Sunday. Thus 60 is 1 am on Sunday, 1440 (== 60 * 24) is 12
+ midnight on Monday, and the largest possible value is 10080 (== 60
+ * 24 * 7) which is 12 midnight on the following Sunday.
+
+ Each span of time has a value associated with it. This is the
+ lowest grade or the largest file size that may be transferred
+ during that time, depending on the source of the time span. When
+ time specifications overlap, the value used for the overlap is the
+ higher grade or the smaller file size. Thus specifying
+ ``call-timegrade z Any'' and ``call-timegrade Z Mo'' means that
+ only grade Z or higher may be sent on Monday, since Z is the higer
+ grade of the overlapping spans. The final array wil have no
+ overlaps.
+
+ Each span also has a retry time associated with it. This permits
+ different retry times to be used at different times of day. The
+ retry time is only relevant if the span came from a ``time'' or
+ ``timegrade'' command for a system. */
+
+struct uuconf_timespan
+{
+ /* Next element in list. */
+ struct uuconf_timespan *uuconf_qnext;
+ /* Starting minute (-1 at the end of the array). */
+ int uuconf_istart;
+ /* Ending minute. */
+ int uuconf_iend;
+ /* Value for this span (lowest grade or largest file that may be
+ transferred at this time). */
+ long uuconf_ival;
+ /* Retry time. */
+ int uuconf_cretry;
+};
+
+/* The information which is kept for protocol parameters. Protocol
+ parameter information is stored as an array of the following
+ structures. */
+
+struct uuconf_proto_param
+{
+ /* The name of the protocol to which this entry applies. This is
+ '\0' for the last element of the array. */
+ int uuconf_bproto;
+ /* Specific entries for this protocol. This points to an array
+ ending in an element with a uuconf_cargs field of 0. */
+ struct uuconf_proto_param_entry *uuconf_qentries;
+};
+
+/* Each particular protocol parameter entry is one of the following
+ structures. */
+
+struct uuconf_proto_param_entry
+{
+ /* The number of arguments to the ``protocol-parameter'' command
+ (not counting ``protocol-parameter'' itself). This is 0 for the
+ last element of the array. */
+ int uuconf_cargs;
+ /* The actual arguments to the ``protocol-parameter'' command; this
+ is an array with cargs entries. */
+ char **uuconf_pzargs;
+};
+
+/* The information which is kept for a system. The zname and zalias
+ fields will be the same for all alternates. Every other fields is
+ specific to the particular alternate in which it appears (although
+ most will be the same for all alternates). */
+
+struct uuconf_system
+{
+ /* The name of the system. */
+ char *uuconf_zname;
+ /* A list of aliases for the system. This is a NULL terminated list
+ of strings. May be NULL, in which case there are no aliases. */
+ char **uuconf_pzalias;
+ /* A linked list of alternate call in or call out information. Each
+ alternative way to call this system occupies an element of this
+ list. May be NULL, in which case there are no alternates. */
+ struct uuconf_system *uuconf_qalternate;
+ /* The name for this particular alternate. May be NULL, in which
+ case this alternate does not have a name. */
+ char *uuconf_zalternate;
+ /* If non-zero, this alternate may be used for calling out. */
+ int uuconf_fcall;
+ /* If non-zero, this alternate may be used for accepting a call. */
+ int uuconf_fcalled;
+ /* The times at which this system may be called. The ival field of
+ each uuconf_timespan structure is the lowest grade which may be
+ transferred at that time. The cretry field is the number of
+ minutes to wait before retrying the call, or 0 if it was not
+ specified. May be NULL, in which case the system may never be
+ called. */
+ struct uuconf_timespan *uuconf_qtimegrade;
+ /* The times at which to request a particular grade of the system
+ when calling it, and the grades to request. The ival field of
+ each uuconf_timespan structure is the lowest grade which the
+ other system should transfer at that time. May be NULL, in which
+ case there are no grade restrictions. */
+ struct uuconf_timespan *uuconf_qcalltimegrade;
+ /* The maximum number of times to retry calling this system. If
+ this is 0, there is no limit. */
+ int uuconf_cmax_retries;
+ /* The number of minutes to wait between successful calls to a
+ system. */
+ int uuconf_csuccess_wait;
+ /* The size restrictions by time for local requests during a locally
+ placed call. The ival field of each uuconf_timespan structure is
+ the size in bytes of the largest file which may be transferred at
+ that time. May be NULL, in which case there are no size
+ restrictions. */
+ struct uuconf_timespan *uuconf_qcall_local_size;
+ /* The size restrictions by time for remote requests during a
+ locally placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcall_remote_size;
+ /* The size restrictions by time for local requests during a
+ remotely placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcalled_local_size;
+ /* The size restrictions by time for remote requests during a
+ remotely placed call. May be NULL. */
+ struct uuconf_timespan *uuconf_qcalled_remote_size;
+ /* Baud rate, or speed. Zero means any baud rate. If ihighbaud is
+ non-zero, this is the low baud rate of a range. */
+ long uuconf_ibaud;
+ /* If non-zero, ibaud is the low baud rate of a range and ihighbaud
+ is the high baud rate. */
+ long uuconf_ihighbaud;
+ /* Port name to use. May be NULL. If an HDB configuration file
+ contains a modem class (alphabetic characters preceeding the baud
+ rate), the class is appended to the port name. */
+ char *uuconf_zport;
+ /* Specific port information, if the system entry includes port
+ information. May be NULL. */
+ struct uuconf_port *uuconf_qport;
+ /* Phone number to call, or address to use for a TCP connection.
+ May be NULL, in which case a dialer script may not use \D or \T
+ for this system, and a TCP port will use the system name. */
+ char *uuconf_zphone;
+ /* Chat script to use when logging in to the system. */
+ struct uuconf_chat uuconf_schat;
+ /* Login name to use for \L in the login chat script. This should
+ normally be accessed via uuconf_callout. If it is "*",
+ uuconf_callout will look it up in the call out file. This may be
+ NULL, in which case the login script may not use \L. */
+ char *uuconf_zcall_login;
+ /* Password to use for \P in the login chat script. This should
+ normally be accessed via uuconf_callout. If it is "*",
+ uuconf_callout will look it up in the call out file. This may be
+ NULL, in which case the login script may not use \P. */
+ char *uuconf_zcall_password;
+ /* The login name this system must use when calling in. This may be
+ different for different alternates. This should only be examined
+ if uuconf_fcalled is TRUE. If this is NULL or "ANY" then
+ uuconf_validate must be called to make sure that whatever login
+ name was used is permitted for this machine. */
+ char *uuconf_zcalled_login;
+ /* If non-zero, then when this system calls in the call should not
+ be allowed to proceed and the system should be called back. */
+ int uuconf_fcallback;
+ /* If non-zero, then conversation sequence numbers should be used
+ with this system. */
+ int uuconf_fsequence;
+ /* A list of protocols to use with this system. Each protocol has a
+ single character name. May be NULL, in which case any known
+ protocol may be used. */
+ char *uuconf_zprotocols;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* Chat script to run when called by this system. */
+ struct uuconf_chat uuconf_scalled_chat;
+ /* Debugging level to set during a conversation. May be NULL. */
+ char *uuconf_zdebug;
+ /* Maximum remote debugging level this system may request. May be
+ NULL. */
+ char *uuconf_zmax_remote_debug;
+ /* Non-zero if the remote system may request us to send files from
+ the local system to the remote. */
+ int uuconf_fsend_request;
+ /* Non-zero if the remote system may request us to receive files
+ from the remote system to the local. */
+ int uuconf_frec_request;
+ /* Non-zero if local requests are permitted when calling this
+ system. */
+ int uuconf_fcall_transfer;
+ /* Non-zero if local requests are permitted when this system calls
+ in. */
+ int uuconf_fcalled_transfer;
+ /* NULL terminated list of directories from which files may be sent
+ by local request. */
+ char **uuconf_pzlocal_send;
+ /* NULL terminated list of directories from which files may be sent
+ by remote request. */
+ char **uuconf_pzremote_send;
+ /* NULL terminated list of directories into which files may be
+ received by local request. */
+ char **uuconf_pzlocal_receive;
+ /* NULL terminated list of directories into which files may be
+ received by remote request. */
+ char **uuconf_pzremote_receive;
+ /* Path to use for command execution. This is a NULL terminated
+ list of directories. */
+ char **uuconf_pzpath;
+ /* NULL terminated List of commands that may be executed. */
+ char **uuconf_pzcmds;
+ /* Amount of free space to leave when accepting a file from this
+ system, in bytes. */
+ long uuconf_cfree_space;
+ /* NULL terminated list of systems that this system may forward
+ from. May be NULL if there are no systems from which files may
+ be forwarded. The list may include "ANY". */
+ char **uuconf_pzforward_from;
+ /* NULL terminated list of systems that this system may forward to.
+ May be NULL if there are no systems to which files may be
+ forwarded. The list may include "ANY". */
+ char **uuconf_pzforward_to;
+ /* The public directory to use for this sytem. */
+ const char *uuconf_zpubdir;
+ /* The local name to use for this remote system. May be NULL if the
+ usual local name should be used. */
+ char *uuconf_zlocalname;
+ /* Memory allocation block for the system. */
+ UUCONF_POINTER uuconf_palloc;
+};
+
+/* Types of ports. */
+
+enum uuconf_porttype
+{
+ /* Unknown port type. A port of this type should never be returned
+ by the uuconf functions. */
+ UUCONF_PORTTYPE_UNKNOWN,
+ /* Read from standard input and write to standard output. Not
+ normally used. */
+ UUCONF_PORTTYPE_STDIN,
+ /* A modem port. */
+ UUCONF_PORTTYPE_MODEM,
+ /* A direct connect port. */
+ UUCONF_PORTTYPE_DIRECT,
+ /* A TCP port. Not supported on all systems. */
+ UUCONF_PORTTYPE_TCP,
+ /* A TLI port. Not supported on all systems. */
+ UUCONF_PORTTYPE_TLI
+};
+
+/* Additional information for a stdin port (there is none). */
+
+struct uuconf_stdin_port
+{
+ int uuconf_idummy;
+};
+
+/* Additional information for a modem port. */
+
+struct uuconf_modem_port
+{
+ /* The device name. May be NULL, in which case the port name is
+ used instead. */
+ char *uuconf_zdevice;
+ /* The device name to send the dialer chat script to. May be NULL,
+ in which case the chat script is sent to the usual device. */
+ char *uuconf_zdial_device;
+ /* The default baud rate (speed). If zero, there is no default. */
+ long uuconf_ibaud;
+ /* The low baud rate, if a range is used. If zero, a range is not
+ used and ihighbaud should be ignored. */
+ long uuconf_ilowbaud;
+ /* The high baud rate, if ilowbaud is non-zero. */
+ long uuconf_ihighbaud;
+ /* Non-zero if the port supports carrier detect. */
+ int uuconf_fcarrier;
+ /* A NULL terminated sequence of dialer/token pairs (element 0 is a
+ dialer name, element 1 is a token, etc.) May be NULL, in which
+ case qdialer should not be NULL. */
+ char **uuconf_pzdialer;
+ /* Specific dialer information. Only used if pzdialer is NULL. */
+ struct uuconf_dialer *uuconf_qdialer;
+};
+
+/* Additional information for a direct connect port. */
+
+struct uuconf_direct_port
+{
+ /* The device name. May be NULL, in which case the port name is
+ used instead. */
+ char *uuconf_zdevice;
+ /* The baud rate (speed). */
+ long uuconf_ibaud;
+};
+
+/* Additional information for a TCP port. */
+
+struct uuconf_tcp_port
+{
+ /* The TCP port number to use. May be a name or a number. May be
+ NULL, in which case "uucp" is looked up using getservbyname. */
+ char *uuconf_zport;
+};
+
+/* Additional information for a TLI port. */
+
+struct uuconf_tli_port
+{
+ /* Device name to open. May be NULL, in which case the port name is
+ used. */
+ char *uuconf_zdevice;
+ /* Whether this port should be turned into a stream, permitting the
+ read and write calls instead of the t_rcv and t_send calls. */
+ int uuconf_fstream;
+ /* A NULL terminated list of modules to push after making the
+ connection. May be NULL, in which case if fstream is non-zero,
+ then "tirdwr" is pushed onto the stream, and otherwise nothing is
+ pushed. */
+ char **uuconf_pzpush;
+ /* A NULL terminated sequence of dialer/token pairs (element 0 is a
+ dialer name, element 1 is a token, etc.) May be NULL. If
+ element 0 is TLI or TLIS, element 1 is used as the address to
+ connect to; otherwise uuconf_zphone from the system information
+ is used. */
+ char **uuconf_pzdialer;
+ /* Address to use when operating as a server. This may contain
+ escape sequences. */
+ char *uuconf_zservaddr;
+};
+
+/* Information kept for a port. */
+
+struct uuconf_port
+{
+ /* The name of the port. */
+ char *uuconf_zname;
+ /* The type of the port. */
+ enum uuconf_porttype uuconf_ttype;
+ /* The list of protocols supported by the port. The name of each
+ protocol is a single character. May be NULL, in which case any
+ protocol is permitted. */
+ char *uuconf_zprotocols;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* The set of reliability bits. */
+ int uuconf_ireliable;
+ /* The lock file name to use. */
+ char *uuconf_zlockname;
+ /* Memory allocation block for the port. */
+ UUCONF_POINTER uuconf_palloc;
+ /* The type specific information. */
+ union
+ {
+ struct uuconf_stdin_port uuconf_sstdin;
+ struct uuconf_modem_port uuconf_smodem;
+ struct uuconf_direct_port uuconf_sdirect;
+ struct uuconf_tcp_port uuconf_stcp;
+ struct uuconf_tli_port uuconf_stli;
+ } uuconf_u;
+};
+
+/* Information kept about a dialer. */
+
+struct uuconf_dialer
+{
+ /* The name of the dialer. */
+ char *uuconf_zname;
+ /* The chat script to use when dialing out. */
+ struct uuconf_chat uuconf_schat;
+ /* The string to send when a `=' appears in the phone number. */
+ char *uuconf_zdialtone;
+ /* The string to send when a `-' appears in the phone number. */
+ char *uuconf_zpause;
+ /* Non-zero if the dialer supports carrier detect. */
+ int uuconf_fcarrier;
+ /* The number of seconds to wait for carrier after the chat script
+ is complete. Only used if fcarrier is non-zero. Only supported
+ on some systems. */
+ int uuconf_ccarrier_wait;
+ /* If non-zero, DTR should be toggled before dialing. Only
+ supported on some systems. */
+ int uuconf_fdtr_toggle;
+ /* If non-zero, sleep for 1 second after toggling DTR. Ignored if
+ fdtr_toggle is zero. */
+ int uuconf_fdtr_toggle_wait;
+ /* The chat script to use when a call is complete. */
+ struct uuconf_chat uuconf_scomplete;
+ /* The chat script to use when a call is aborted. */
+ struct uuconf_chat uuconf_sabort;
+ /* Array of protocol parameters. Ends in an entry with a
+ uuconf_bproto field of '\0'. May be NULL. */
+ struct uuconf_proto_param *uuconf_qproto_params;
+ /* The set of reliability bits. */
+ int uuconf_ireliable;
+ /* Memory allocation block for the dialer. */
+ UUCONF_POINTER uuconf_palloc;
+};
+
+/* Reliability bits for the ireliable field of ports and dialers.
+ These bits are used to decide which protocol to run. A given
+ protocol will have a set of these bits, and each of them must be
+ turned on for the port before we will permit that protocol to be
+ used. This will be overridden by the zprotocols field. */
+
+/* Whether a set of reliability bits is given. If this bit is not
+ set, then there is no reliability information. */
+#define UUCONF_RELIABLE_SPECIFIED (01)
+
+/* Set if the connection is eight bit transparent. */
+#define UUCONF_RELIABLE_EIGHT (02)
+
+/* Set if the connection is error-free. */
+#define UUCONF_RELIABLE_RELIABLE (04)
+
+/* Set if the connection is end-to-end reliable (e.g. TCP). */
+#define UUCONF_RELIABLE_ENDTOEND (010)
+
+/* Set if the connection is full-duplex; that is, no time consuming
+ line turnaround is required before sending data in the reverse
+ direction. If the connection is truly half-duplex, in the sense
+ that communication can only flow in one direction, UUCP can not be
+ used. */
+#define UUCONF_RELIABLE_FULLDUPLEX (020)
+
+/* UUCP grades range from 0 to 9, A to Z, a to z in order from highest
+ to lowest (work of higher grades is done before work of lower
+ grades). */
+
+/* The highest grade. */
+#define UUCONF_GRADE_HIGH ('0')
+
+/* The lowest grade. */
+#define UUCONF_GRADE_LOW ('z')
+
+/* Whether a character is a legal grade (requires <ctype.h>). */
+#define UUCONF_GRADE_LEGAL(b) (isalnum ((unsigned) (b)))
+
+/* Return < 0 if the first grade should be done before the second
+ grade, == 0 if they are the same, or > 0 if the first grade should
+ be done after the second grade. On an ASCII system, this can just
+ be b1 - b2. */
+#define UUCONF_GRADE_CMP(b1, b2) (uuconf_grade_cmp ((b1), (b2)))
+
+/* Most of the uuconf functions returns an error code. A value of
+ zero (UUCONF_SUCCESS) indicates success. */
+
+/* If this bit is set in the returned error code, then the
+ uuconf_errno function may be used to obtain the errno value as set
+ by the function which caused the failure. */
+#define UUCONF_ERROR_ERRNO (0x100)
+
+/* If this bit is set in the returned error code, then the
+ uuconf_filename function may be used to get the name of a file
+ associated with the error. */
+#define UUCONF_ERROR_FILENAME (0x200)
+
+/* If this bit is set in the returned error code, then the
+ uuconf_lineno function may be used to get a line number associated
+ with the error; normally if this is set UUCONF_ERROR_FILENAME will
+ also be set. */
+#define UUCONF_ERROR_LINENO (0x400)
+
+/* There are two UUCONF_CMDTABRET bits that may be set in the return
+ value of uuconf_cmd_line or uuconf_cmd_args, described below. They
+ do not indicate an error, but instead give instructions to the
+ calling function, often uuconf_cmd_file. They may also be set in
+ the return value of a user function listed in a uuconf_cmdtab
+ table, in which case they will be honored by uuconf_cmd_file. */
+
+/* This bit means that the memory occupied by the arguments passed to
+ the function should be preserved, and not overwritten or freed. It
+ refers only to the contents of the arguments; the contents of the
+ argv array itself may always be destroyed. If this bit is set in
+ the return value of uuconf_cmd_line or uuconf_cmd_args, it must be
+ honored. It will be honored by uuconf_cmd_file. This may be
+ combined with an error code or with UUCONF_CMDTABRET_EXIT, although
+ neither uuconf_cmd_file or uuconf_cmd_line will do so. */
+#define UUCONF_CMDTABRET_KEEP (0x800)
+
+/* This bit means that uuconf_cmd_file should exit, rather than go on
+ to read and process the next line. If uuconf_cmd_line or
+ uuconf_cmd_args encounter an error, the return value will have this
+ bit set along with the error code. A user function may set this
+ bit with or without an error; the return value of the user function
+ will be returned by uuconf_cmd_file, except that the
+ UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT bits will be
+ cleared. */
+#define UUCONF_CMDTABRET_EXIT (0x1000)
+
+/* This macro may be used to extract the specific error value. */
+#define UUCONF_ERROR_VALUE(i) ((i) & 0xff)
+
+/* UUCONF_ERROR_VALUE will return one of the following values. */
+
+/* Function succeeded. */
+#define UUCONF_SUCCESS (0)
+/* Named item not found. */
+#define UUCONF_NOT_FOUND (1)
+/* A call to fopen failed. */
+#define UUCONF_FOPEN_FAILED (2)
+/* A call to fseek failed. */
+#define UUCONF_FSEEK_FAILED (3)
+/* A call to malloc or realloc failed. */
+#define UUCONF_MALLOC_FAILED (4)
+/* Syntax error in file. */
+#define UUCONF_SYNTAX_ERROR (5)
+/* Unknown command. */
+#define UUCONF_UNKNOWN_COMMAND (6)
+
+#if UUCONF_ANSI_C
+
+/* For each type of configuration file (Taylor, V2, HDB), there are
+ separate routines to read various sorts of information. There are
+ also generic routines, which call on the appropriate type specific
+ routines. The library can be compiled to read any desired
+ combination of the configuration file types. This affects only the
+ generic routines, as it determines which type specific routines
+ they call. Thus, on a system which, for example, does not have any
+ V2 configuration files, there is no need to include the overhead of
+ the code to parse the files and the time to look for them.
+ However, a program which specifically wants to be able to parse
+ them can call the V2 specific routines.
+
+ The uuconf functions all take as an argument a pointer to uuconf
+ global information. This must be initialized by any the
+ initialization routines (the generic one and the three file type
+ specific ones) before any of the other uuconf functions may be
+ called. */
+
+/* Initialize the configuration file reading routines. The ppglobal
+ argument should point to a generic pointer (a void *, or, on older
+ compilers, a char *) which will be initialized and may then be
+ passed to the other uuconf routines. The zprogram argument is the
+ name of the program for which files should be read. A NULL is
+ taken as "uucp", and reads the standard UUCP configuration files.
+ The only other common argument is "cu", but any string is
+ permitted. The zname argument is the name of the Taylor UUCP
+ config file; if it is NULL, the default config file will be read.
+ If not reading Taylor UUCP configuration information, the argument
+ is ignored. This function must be called before any of the other
+ uuconf functions.
+
+ Note that if the zname argument is obtained from the user running
+ the program, the program should be careful to revoke any special
+ privileges it may have (e.g. on Unix call setuid (getuid ()) and
+ setgid (getgid ())). Otherwise various sorts of spoofing become
+ possible. */
+extern int uuconf_init (void **uuconf_ppglobal,
+ const char *uuconf_zprogram,
+ const char *uuconf_zname);
+
+/* Adjust the configuration file global pointer for a new thread. The
+ library is fully reentrant (with the exception of the function
+ uuconf_error_string, which calls strerror, which on some systems is
+ not reentrant), provided that each new thread that wishes to call
+ the library calls this function and uses the new global pointer
+ value. The ppglobal argument should be set to the address of the
+ global pointer set by any of the init functions; it will be
+ modified to become a new global pointer. */
+extern int uuconf_init_thread (void **uuconf_ppglobal);
+
+/* Get the names of all known systems. This sets sets *ppzsystems to
+ point to an array of system names. The list of names is NULL
+ terminated. The array is allocated using malloc, as is each
+ element of the array, and they may all be passed to free when they
+ are no longer needed. If the falias argument is 0, the list will
+ not include any aliases; otherwise, it will. */
+extern int uuconf_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for the system zsystem. This sets the fields
+ in *qsys. This will work whether zsystem is the official name of
+ the system or merely an alias. */
+extern int uuconf_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for an unknown (anonymous) system. The
+ uuconf_zname field of the returned system information will be NULL.
+ If no information is available for unknown systems, this will
+ return UUCONF_NOT_FOUND. This does not run the HDB remote.unknown
+ shell script. */
+extern int uuconf_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for the local system. Normally the local system
+ name should first be looked up using uuconf_system_info. If that
+ returns UUCONF_NOT_FOUND, this function may be used to get an
+ appropriate set of defaults. The uuconf_zname field of the
+ returned system information may be NULL. */
+extern int uuconf_system_local (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Free the memory occupied by system information returned by
+ uuconf_system_info, uuconf_system_unknown, uuconf_system_local, or
+ any of the configuration file type specific routines described
+ below. After this is called, the contents of the structure shall
+ not be referred to. */
+extern int uuconf_system_free (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+#ifdef __OPTIMIZE__
+#define uuconf_system_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Find a matching port. This will consider each port in turn.
+
+ If the zname argument is not NULL, the port's uuconf_zname field
+ must match it.
+
+ If the ibaud argument is not zero and the ihighbaud argument is
+ zero, the port's baud rate, if defined, must be the same (if the
+ port has a range of baud rates, ibaud must be within the range).
+ If ibaud and ihighbaud are both not zero, the port's baud rate, if
+ defined, must be between ibaud and ihighbaud inclusive (if the port
+ has a range of baud rates, the ranges must intersect). If the port
+ has no baud rate, either because it is a type of port for which
+ baud rate is not defined (e.g. a TCP port) or because the
+ uuconf_ibaud field is 0, the ibaud and ihighbaud arguments are
+ ignored.
+
+ If the pifn argument is not NULL, the port is passed to pifn, along
+ with the pinfo argument (which is otherwise ignored). If pifn
+ returns UUCONF_SUCCESS, the port matches. If pifn returns
+ UUCONF_NOT_FOUND, a new port is sought. Otherwise the return value
+ of pifn is returned from uuconf_find_port. The pifn function may
+ be used to further restrict the port, such as by modem class or
+ device name. It may also be used to lock the port, if appropriate;
+ in this case, if the lock fails, pifn may return UUCONF_NOT_FOUND
+ to force uuconf_find_port to continue searching for a port.
+
+ If the port matches, the information is set into uuconf_qport, and
+ uuconf_find_port returns UUCONF_SUCCESS. */
+extern int uuconf_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Free the memory occupied by system information returned by
+ uuconf_find_port (or any of the configuration file specific
+ routines described below). After this is called, the contents of
+ the structure shall not be referred to. */
+extern int uuconf_port_free (void *uuconf_pglobal,
+ struct uuconf_port *uuconf_qport);
+
+#ifdef __OPTIMIZE__
+#define uuconf_port_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Get the names of all known dialers. This sets sets *ppzdialers to
+ point to an array of dialer names. The list of names is NULL
+ terminated. The array is allocated using malloc, as is each
+ element of the array, and they may all be passed to free when they
+ are no longer needed. */
+extern int uuconf_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer. This sets the fields
+ in *qdialer. */
+extern int uuconf_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Free the memory occupied by system information returned by
+ uuconf_dialer_info (or any of the configuration file specific
+ routines described below). After this is called, the contents of
+ the structure shall not be referred to. */
+extern int uuconf_dialer_free (void *uuconf_pglobal,
+ struct uuconf_dialer *uuconf_qsys);
+
+#ifdef __OPTIMIZE__
+#define uuconf_dialer_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+/* Get the local node name. If the node name is not specified
+ (because no ``nodename'' command appeared in the config file) this
+ will return UUCONF_NOT_FOUND, and some system dependent function
+ must be used to determine the node name. Otherwise it will return
+ a pointer to a constant string, which should not be freed. */
+extern int uuconf_localname (void *uuconf_pglobal,
+ const char **pzname);
+
+/* Get the local node name that should be used, given a login name.
+ This function will check for any special local name that may be
+ associated with the login name zlogin (as set by the ``myname''
+ command in a Taylor configuration file, or the MYNAME field in a
+ Permissions entry). This will set *pzname to the node name. If no
+ node name can be determined, *pzname will be set to NULL and the
+ function will return UUCONF_NOT_FOUND; in this case some system
+ dependent function must be used to determine the node name. If the
+ function returns UUCONF_SUCCESS, *pzname will be point to an
+ malloced buffer. */
+extern int uuconf_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the name of the UUCP spool directory. This will set *pzspool
+ to a constant string, which should not be freed. */
+extern int uuconf_spooldir (void *uuconf_pglobal,
+ const char **uuconf_pzspool);
+
+/* Get the name of the default UUCP public directory. This will set
+ *pzpub to a constant string, which should not be freed. Note that
+ particular systems may use a different public directory. */
+extern int uuconf_pubdir (void *uuconf_pglobal,
+ const char **uuconf_pzpub);
+
+/* Get the name of the UUCP lock directory. This will set *pzlock to
+ a constant string, which should not be freed. */
+extern int uuconf_lockdir (void *uuconf_pglobal,
+ const char **uuconf_pzlock);
+
+/* Get the name of the UUCP log file. This will set *pzlog to a
+ constant string, which should not be freed. */
+extern int uuconf_logfile (void *uuconf_pglobal,
+ const char **uuconf_pzlog);
+
+/* Get the name of the UUCP statistics file. This will set *pzstats
+ to a constant string, which should not be freed. */
+extern int uuconf_statsfile (void *uuconf_pglobal,
+ const char **uuconf_pzstats);
+
+/* Get the name of the UUCP debugging file. This will set *pzdebug to
+ a constant string, which should not be freed. */
+extern int uuconf_debugfile (void *uuconf_pglobal,
+ const char **uuconf_pzdebug);
+
+/* Get the default debugging level to use. This basically gets the
+ argument of the ``debug'' command from the Taylor UUCP config file.
+ It will set *pzdebug to a constant string, which should not be
+ freed. */
+extern int uuconf_debuglevel (void *uuconf_pglobal,
+ const char **uuconf_pzdebug);
+
+/* Get the maximum number of simultaneous uuxqt executions. This will
+ set *pcmaxuuxqt to the number. Zero indicates no maximum. */
+extern int uuconf_maxuuxqts (void *uuconf_pglobal,
+ int *uuconf_pcmaxuuxqt);
+
+/* Check a login name and password. This checks the Taylor UUCP
+ password file (not /etc/passwd). It will work even if
+ uuconf_taylor_init was not called. If the login name exists and
+ the password is correct, this returns UUCONF_SUCCESS. If the login
+ does not exist, or the password is wrong, this returns
+ UUCONF_NOT_FOUND. Other errors are also possible. */
+extern int uuconf_callin (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ const char *uuconf_zpassword);
+
+/* Get the callout login name and password for a system. This will
+ set both *pzlog and *pzpass to a string allocated by malloc, or to
+ NULL if the value is not found. If neither value is found, the
+ function will return UUCONF_NOT_FOUND. */
+extern int uuconf_callout (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ char **uuconf_pzlog,
+ char **uuconf_pzpass);
+
+/* See if a login name is permitted for a system. This will return
+ UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is
+ invalid. This simply calls uuconf_taylor_validate or returns
+ UUCONF_SUCCESS, depending on the value of HAVE_TAYLOR_CONFIG. */
+extern int uuconf_validate (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ const char *uuconf_zlogin);
+
+/* Get the name of the HDB remote.unknown shell script, if using
+ HAVE_HDB_CONFIG. This does not actually run the shell script. If
+ the function returns UUCONF_SUCCESS, the name will be in *pzname,
+ which will point to an malloced buffer. If it returns
+ UUCONF_NOT_FOUND, then there is no script to run. */
+extern int uuconf_remote_unknown (void *uuconf_pglobal,
+ char **pzname);
+
+/* Translate a dial code. This sets *pznum to an malloced string.
+ This will look up the entire zdial string in the dialcode file, so
+ for normal use the alphabetic prefix should be separated. */
+extern int uuconf_dialcode (void *uuconf_pglobal,
+ const char *uuconf_zdial,
+ char **uuconf_pznum);
+
+/* Compare two grades, returning < 0 if b1 should be executed before
+ b2, == 0 if they are the same, or > 0 if b1 should be executed
+ after b2. This can not fail, and does not return a standard uuconf
+ error code; it is normally called via the macro UUCONF_GRADE_CMP,
+ defined above. */
+extern int uuconf_grade_cmp (int uuconf_b1, int uuconf_b2);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_init ();
+extern int uuconf_init_thread ();
+extern int uuconf_system_names ();
+extern int uuconf_system_info ();
+extern int uuconf_system_unknown ();
+extern int uuconf_system_local ();
+extern int uuconf_system_free ();
+extern int uuconf_find_port ();
+extern int uuconf_port_free ();
+extern int uuconf_dialer_names ();
+extern int uuconf_dialer_info ();
+extern int uuconf_dialer_free ();
+extern int uuconf_localname ();
+extern int uuconf_login_localname ();
+extern int uuconf_spooldir ();
+extern int uuconf_lockdir ();
+extern int uuconf_pubdir ();
+extern int uuconf_logfile ();
+extern int uuconf_statsfile ();
+extern int uuconf_debugfile ();
+extern int uuconf_debuglevel ();
+extern int uuconf_maxuuxqts ();
+extern int uuconf_callin ();
+extern int uuconf_callout ();
+extern int uuconf_remote_unknown ();
+extern int uuconf_validate ();
+extern int uuconf_grade_cmp ();
+
+#ifdef __OPTIMIZE__
+#define uuconf_system_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#define uuconf_port_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#define uuconf_dialer_free(qglob, q) \
+ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS)
+#endif
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the Taylor UUCP configuration file reading routines.
+ This must be called before calling any of the Taylor UUCP
+ configuration file specific routines. The ppglobal argument should
+ point to a generic pointer. Moreover, before calling this function
+ the pointer either must be set to NULL, or must have been passed to
+ one of the other uuconf init routines. The zprogram argument is
+ the name of the program for which files should be read. If NULL,
+ it is taken as "uucp", which means to read the standard UUCP files.
+ The zname argument is the name of the config file. If it is NULL,
+ the default config file will be used.
+
+ Note that if the zname argument is obtained from the user running
+ the program, the program should be careful to revoke any special
+ privileges it may have (e.g. on Unix call setuid (getuid ()) and
+ setgid (getgid ())). Otherwise various sorts of spoofing become
+ possible. */
+extern int uuconf_taylor_init (void **uuconf_pglobal,
+ const char *uuconf_zprogram,
+ const char *uuconf_zname);
+
+/* Get the names of all systems listed in the Taylor UUCP
+ configuration files. This sets *ppzsystems to point to an array of
+ system names. The list of names is NULL terminated. The array is
+ allocated using malloc, as is each element of the array. If the
+ falias argument is 0, the list will not include any aliases;
+ otherwise, it will. */
+extern int uuconf_taylor_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the Taylor UUCP
+ configuration files. This will set *qsys. */
+extern int uuconf_taylor_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Get information for an unknown (anonymous) system. This returns
+ the values set by the ``unknown'' command in the main configuration
+ file. If the ``unknown'' command was not used, this will return
+ UUCONF_NOT_FOUND. */
+extern int uuconf_taylor_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the Taylor UUCP configuration files. The
+ arguments and return values are identical to those of
+ uuconf_find_port. */
+extern int uuconf_taylor_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Get the names of all dialers listed in the Taylor UUCP
+ configuration files. This sets *ppzdialers to point to an array of
+ dialer names. The list of names is NULL terminated. The array is
+ allocated using malloc, as is each element of the array. */
+extern int uuconf_taylor_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer from the Taylor UUCP
+ configuration files. This sets the fields in *qdialer. */
+extern int uuconf_taylor_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Get the local node name that should be used, given a login name,
+ considering only the ``myname'' command in the Taylor UUCP
+ configuration files. If the function returns UUCONF_SUCCESS,
+ *pzname will point to an malloced buffer. */
+extern int uuconf_taylor_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the callout login name and password for a system from the
+ Taylor UUCP configuration files. This will set both *pzlog and
+ *pzpass to a string allocated by malloc, or to NULL if the value is
+ not found. If neither value is found, the function will return
+ UUCONF_NOT_FOUND. */
+extern int uuconf_taylor_callout (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ char **uuconf_pzlog,
+ char **uuconf_pzpass);
+
+/* See if a login name is permitted for a system. This will return
+ UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is
+ invalid. This checks whether the login name appears in a
+ called-login command with a list of system which does not include
+ the system qsys. */
+extern int uuconf_taylor_validate (void *uuconf_pglobal,
+ const struct uuconf_system *uuconf_qsys,
+ const char *uuconf_zlogin);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_taylor_init ();
+extern int uuconf_taylor_system_names ();
+extern int uuconf_taylor_system_info ();
+extern int uuconf_taylor_system_unknown ();
+extern int uuconf_taylor_find_port ();
+extern int uuconf_taylor_dialer_names ();
+extern int uuconf_taylor_dialer_info ();
+extern int uuconf_taylor_login_localname ();
+extern int uuconf_taylor_callout ();
+extern int uuconf_taylor_validate ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the V2 configuration file reading routines. This must
+ be called before any of the other V2 routines are called. The
+ ppglobal argument should point to a generic pointer. Moreover,
+ before calling this function the pointer either must be set to
+ NULL, or must have been passed to one of the other uuconf init
+ routines. */
+extern int uuconf_v2_init (void **uuconf_ppglobal);
+
+/* Get the names of all systems listed in the V2 configuration files.
+ This sets *ppzsystems to point to an array of system names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. If the falias argument is
+ 0, the list will not include any aliases; otherwise, it will. */
+extern int uuconf_v2_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the V2 configuration
+ files. This will set *qsys. */
+extern int uuconf_v2_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the V2 configuration files. The arguments and
+ return values are identical to those of uuconf_find_port. */
+extern int uuconf_v2_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_v2_init ();
+extern int uuconf_v2_system_names ();
+extern int uuconf_v2_system_info ();
+extern int uuconf_v2_find_port ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* Initialize the HDB configuration file reading routines. This
+ should be called before any of the other HDB routines are called.
+ The ppglobal argument should point to a generic pointer. Moreover,
+ before calling this function the pointer either must be set to
+ NULL, or must have been passed to one of the other uuconf init
+ routines. The zprogram argument is used to match against a
+ "services" string in Sysfiles. A NULL or "uucp" argument is taken
+ as "uucico". */
+extern int uuconf_hdb_init (void **uuconf_ppglobal,
+ const char *uuconf_zprogram);
+
+/* Get the names of all systems listed in the HDB configuration files.
+ This sets *ppzsystems to point to an array of system names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. If the falias argument is
+ 0, the list will not include any aliases; otherwise, it will (an
+ alias is created by using the ALIAS= keyword in the Permissions
+ file). */
+extern int uuconf_hdb_system_names (void *uuconf_pglobal,
+ char ***uuconf_ppzsystems,
+ int uuconf_falias);
+
+/* Get the information for system zsystem from the HDB configuration
+ files. This will set *qsys. */
+extern int uuconf_hdb_system_info (void *uuconf_pglobal,
+ const char *uuconf_zsystem,
+ struct uuconf_system *uuconf_qsys);
+
+
+/* Get information for an unknown (anonymous) system. If no
+ information is available for unknown systems, this will return
+ UUCONF_NOT_FOUND. This does not run the remote.unknown shell
+ script. */
+extern int uuconf_hdb_system_unknown (void *uuconf_pglobal,
+ struct uuconf_system *uuconf_qsys);
+
+/* Find a port from the HDB configuration files. The arguments and
+ return values are identical to those of uuconf_find_port. */
+extern int uuconf_hdb_find_port (void *uuconf_pglobal,
+ const char *uuconf_zname,
+ long uuconf_ibaud,
+ long uuconf_ihighbaud,
+ int (*uuconf_pifn) (struct uuconf_port *,
+ void *uuconf_pinfo),
+ void *uuconf_pinfo,
+ struct uuconf_port *uuconf_qport);
+
+/* Get the names of all dialers listed in the HDB configuration files.
+ This sets *ppzdialers to point to an array of dialer names. The
+ list of names is NULL terminated. The array is allocated using
+ malloc, as is each element of the array. */
+extern int uuconf_hdb_dialer_names (void *uuconf_pglobal,
+ char ***uuconf_ppzdialers);
+
+/* Get the information for the dialer zdialer from the HDB
+ configuration files. This sets the fields in *qdialer. */
+extern int uuconf_hdb_dialer_info (void *uuconf_pglobal,
+ const char *uuconf_zdialer,
+ struct uuconf_dialer *uuconf_qdialer);
+
+/* Get the local node name that should be used, given a login name,
+ considering only the MYNAME field in the HDB Permissions file. If
+ the function returns UUCONF_SUCCESS, *pzname will point to an
+ malloced buffer. */
+extern int uuconf_hdb_login_localname (void *uuconf_pglobal,
+ const char *uuconf_zlogin,
+ char **pzname);
+
+/* Get the name of the HDB remote.unknown shell script. This does not
+ actually run the shell script. If the function returns
+ UUCONF_SUCCESS, the name will be in *pzname, which will point to an
+ malloced buffer. */
+extern int uuconf_hdb_remote_unknown (void *uuconf_pglobal,
+ char **pzname);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_hdb_init ();
+extern int uuconf_hdb_system_names ();
+extern int uuconf_hdb_system_info ();
+extern int uuconf_hdb_system_unknown ();
+extern int uuconf_hdb_find_port ();
+extern int uuconf_hdb_dialer_names ();
+extern int uuconf_hdb_dialer_info ();
+extern int uuconf_hdb_localname ();
+extern int uuconf_hdb_remote_unknown ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* This function will set an appropriate error message into the buffer
+ zbuf, given a uuconf error code. The buffer will always be null
+ terminated, and will never be accessed beyond the length cbuf.
+ This function will return the number of characters needed for the
+ complete message, including the null byte. If this is less than
+ the cbytes argument, the buffer holds a truncated string. */
+extern int uuconf_error_string (void *uuconf_pglobal, int ierror,
+ char *zbuf, UUCONF_SIZE_T cbuf);
+
+/* If UUCONF_ERROR_ERRNO is set in a return value, this function may
+ be used to retrieve the errno value. This will be the value of
+ errno as set by the system function which failed. However, some
+ system functions, notably some stdio routines, may not set errno,
+ in which case the value will be meaningless. This function does
+ not return a uuconf error code, and it cannot fail. */
+extern int uuconf_error_errno (void *uuconf_pglobal);
+
+/* If UUCONF_ERROR_FILENAME is set in a return value, this function
+ may be used to retrieve the file name. This function does not
+ return a uuconf error code, and it cannot fail. The string that it
+ returns a pointer to is not guaranteed to remain allocated across
+ the next call to a uuconf function (other than one of the three
+ error retrieving functions). */
+extern const char *uuconf_error_filename (void *uuconf_pglobal);
+
+/* If UUCONF_ERROR_LINENO is set in a return value, this function may
+ be used to retrieve the line number. This function does not return
+ a uuconf error code, and it cannot fail. */
+extern int uuconf_error_lineno (void *uuconf_pglobal);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_error_string ();
+extern int uuconf_error_errno ();
+extern UUCONF_CONST char *uuconf_error_filename ();
+extern int uuconf_error_lineno ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+/* The uuconf package also provides a few functions which can accept
+ commands and parcel them out according to a table. These are
+ publically visible, partially in the hopes that they will be
+ useful, but mostly because the rest of the Taylor UUCP package uses
+ them. */
+
+/* The types of entries allowed in a command table (struct
+ uuconf_cmdtab). Each type defines how a particular command is
+ interpreted. Each type will either assign a value to a variable or
+ call a function. In all cases, a line of input is parsed into
+ separate fields, separated by whitespace; comments beginning with
+ '#' are discarded, except that a '#' preceeded by a backslash is
+ retained. The first field is taken as the command to execute, and
+ the remaining fields are its arguments. */
+
+/* A boolean value. Used for a command which accepts a single
+ argument, which must begin with 'y', 'Y', 't', or 'T' for true (1)
+ or 'n', 'N', 'f', or 'F' for false (0). The corresponding variable
+ must be an int. */
+#define UUCONF_CMDTABTYPE_BOOLEAN (0x12)
+
+/* An integer value. Used for a command which accepts a single
+ argument, which must be an integer. The corresponding variable
+ must be an int. */
+#define UUCONF_CMDTABTYPE_INT (0x22)
+
+/* A long value. Used for a command which accepts a single value,
+ which must be an integer. The corresponding variable must be a
+ long. */
+#define UUCONF_CMDTABTYPE_LONG (0x32)
+
+/* A string value. Used for a command which accepts a string
+ argument. If there is no argument, the variable will be set to
+ point to a zero byte. Otherwise the variable will be set to point
+ to the string. The corresponding variable must be a char *. The
+ memory pointed to by the variable after it is set must not be
+ modified. */
+#define UUCONF_CMDTABTYPE_STRING (0x40)
+
+/* A full string value. Used for a command which accepts a series of
+ string arguments separated by whitespace. The corresponding
+ variable must be a char **. It will be set to an NULL terminated
+ array of the arguments. The memory occupied by the array itself,
+ and by the strings within it, must not be modified. */
+#define UUCONF_CMDTABTYPE_FULLSTRING (0x50)
+
+/* A function. If this command is encountered, the command and its
+ arguments are passed to the corresponding function. They are
+ passed as an array of strings, in which the first string is the
+ command itself, along with a count of strings. This value may be
+ or'red with a specific number of required arguments;
+ UUCONF_CMDTABTYPE_FN | 1 accepts no additional arguments besides
+ the command itself, UUCONF_CMDTABTYPE_FN | 2 accepts 1 argument,
+ etc. UUCONF_CMDTABTYPE_FN | 0, accepts any number of additional
+ arguments. */
+#define UUCONF_CMDTABTYPE_FN (0x60)
+
+/* A prefix function. The string in the table is a prefix; if a
+ command is encountered with the same prefix, the corresponding
+ function will be called as for UUCONF_CMDTABTYPE_FN. The number of
+ arguments may be or'red in as with UUCONF_CMDTABTYPE_FN. */
+#define UUCONF_CMDTABTYPE_PREFIX (0x70)
+
+/* This macro will return the particular type of a CMDTABTYPE. */
+#define UUCONF_TTYPE_CMDTABTYPE(i) ((i) & 0x70)
+
+/* This macro will return the required number of arguments of a
+ CMDTABTYPE. If it is zero, there is no restriction. */
+#define UUCONF_CARGS_CMDTABTYPE(i) ((i) & 0x0f)
+
+/* When a function is called via UUCONF_CMDTABTYPE_FN or
+ UUCONF_CMDTABTYPE_PREFIX, it may return any uuconf error code (see
+ above). However, it will normally return one of the following:
+
+ UUCONF_CMDTABRET_CONTINUE: Take no special action. In particular,
+ the arguments passed to the function may be overwritten or freed.
+
+ UUCONF_CMDTABRET_KEEP: The memory occupied by the arguments passed
+ to the function must be preserved. Continue processing commands.
+
+ UUCONF_CMDTABRET_EXIT: If reading commands from a file, stop
+ processing. The arguments passed to the function may be
+ overwritten or freed.
+
+ UUCONF_CMDTABRET_KEEP_AND_EXIT: Stop processing any file. The
+ memory occupied by the arguments passed to the function must be
+ preserved.
+
+ These values are interpreted by uuconf_cmd_file. The
+ uuconf_cmd_line and uuconf_cmd_args functions may return
+ UUCONF_CMDTABRET_KEEP. It they get an error, they will return an
+ error code with UUCONF_CMDTABRET_EXIT set. Also, of course, they
+ may return any value that is returned by one of the user functions
+ in the uuconf_cmdtab table. */
+
+/* UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT are defined above,
+ with the error codes. */
+
+#define UUCONF_CMDTABRET_CONTINUE UUCONF_SUCCESS
+#define UUCONF_CMDTABRET_KEEP_AND_EXIT \
+ (UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT)
+
+/* When a function is called via CMDTABTYPE_FN or CMDTABTYPE_PREFIX,
+ it is passed five arguments. This is the type of a pointer to such
+ a function. The uuconf global information structure is passed in
+ for convenience in calling another uuconf function. The arguments
+ to the command are passed in (the command itself is the first
+ argument) along with a count and the value of the pvar field from
+ the uuconf_cmdtab structure in which the function pointer was
+ found. The pinfo argument to the function is taken from the
+ argument to uuconf_cmd_*. */
+
+#if UUCONF_ANSI_C
+typedef int (*uuconf_cmdtabfn) (void *uuconf_pglobal,
+ int uuconf_argc,
+ char **uuconf_argv,
+ void *uuconf_pvar,
+ void *uuconf_pinfo);
+#else
+typedef int (*uuconf_cmdtabfn) ();
+#endif
+
+/* A table of commands is an array of the following structures. The
+ final element of the table should have uuconf_zcmd == NULL. */
+
+struct uuconf_cmdtab
+{
+ /* Command name. */
+ UUCONF_CONST char *uuconf_zcmd;
+ /* Command type (one of CMDTABTYPE_*). */
+ int uuconf_itype;
+ /* If not CMDTABTYPE_FN or CMDTABTYPE_PREFIX, the address of the
+ associated variable. Otherwise, a pointer value to pass to the
+ function pifn. */
+ UUCONF_POINTER uuconf_pvar;
+ /* The function to call if CMDTABTYPE_FN or CMDTABTYPE_PREFIX. */
+ uuconf_cmdtabfn uuconf_pifn;
+};
+
+/* Bit flags to pass to uuconf_processcmds. */
+
+/* If set, case is significant when checking commands. Normally case
+ is ignored. */
+#define UUCONF_CMDTABFLAG_CASE (0x1)
+
+/* If set, a backslash at the end of a line may be used to include the
+ next physical line in the logical line. */
+#define UUCONF_CMDTABFLAG_BACKSLASH (0x2)
+
+#if UUCONF_ANSI_C
+
+/* Read commands from a file, look them up in a table, and take the
+ appropriate action. This continues reading lines from the file
+ until EOF, or until a function returns with UUCONF_CMDTABRET_EXIT
+ set, or until an error occurs. The qtab argument must point to a
+ table of struct uuconf_cmdtab; the last element in the table should
+ have uuconf_zcmd == NULL. When a UUCONF_CMDTABTYPE_FN or
+ UUCONF_CMDTABTYPE_PREFIX command is found, the pinfo argument will
+ be passed to the called function. If an a command is found that is
+ not in the table, then if pfiunknownfn is NULL the unknown command
+ is ignored; otherwise it is passed to pfiunknownfn, which should
+ return a uuconf return code which is handled as for any other
+ function (the pvar argument to pfiunknownfn will always be NULL).
+ The iflags argument is any combination of the above
+ UUCONF_CMDTABFLAG bits. The pblock argument may also be a memory
+ block, as returned by uuconf_malloc_block (described below), in
+ which case all memory preserved because of UUCONF_CMDTABRET_KEEP
+ will be added to the block so that it may be freed later; it may
+ also be NULL, in which case any such memory is permanently lost.
+
+ This function initially sets the internal line number to 0, and
+ then increments it as each line is read. It is permitted for any
+ called function to use the uuconf_lineno function to obtain it. If
+ this function is called when not at the start of a file, the value
+ returned by uuconf_lineno (which is, in any case, only valid if an
+ error code with UUCONF_ERROR_LINENO set is returned) must be
+ adjusted by the caller.
+
+ This returns a normal uuconf return value, as described above. */
+extern int uuconf_cmd_file (void *uuconf_pglobal,
+ FILE *uuconf_e,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+/* This utility function is just like uuconf_cmd_file, except that it
+ only operates on a single string. If a function is called via
+ qtab, its return value will be the return value of this function.
+ UUCONF_CMDTABFLAG_BACKSLASH is ignored in iflags. The string z is
+ modified in place. The return value may include the
+ UUCONF_CMDTABRET_KEEP and, on error, the UUCONF_CMDTABRET_EXIT
+ bits, which should be honored by the calling code. */
+extern int uuconf_cmd_line (void *uuconf_pglobal,
+ char *uuconf_z,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+/* This utility function is just like uuconf_cmd_line, except it is
+ given a list of already parsed arguments. */
+extern int uuconf_cmd_args (void *uuconf_pglobal,
+ int uuconf_cargs,
+ char **uuconf_pzargs,
+ const struct uuconf_cmdtab *uuconf_qtab,
+ void *uuconf_pinfo,
+ uuconf_cmdtabfn uuconf_pfiunknownfn,
+ int uuconf_iflags,
+ void *pblock);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern int uuconf_cmd_file ();
+extern int uuconf_cmd_line ();
+extern int uuconf_cmd_args ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#if UUCONF_ANSI_C
+
+/* The uuconf_cmd_file function may allocate memory permanently, as
+ for setting a UUCONF_CMDTABTYPE_STRING value, in ways which are
+ difficult to free up. A memory block may be used to record all
+ allocated memory, so that it can all be freed up at once at some
+ later time. These functions do not take a uuconf global pointer,
+ and are independent of the rest of the uuconf library. */
+
+/* Allocate a block of memory. If this returns NULL, then malloc
+ returned NULL, and errno is whatever malloc set it to. */
+extern void *uuconf_malloc_block (void);
+
+/* Allocate memory within a memory block. If this returns NULL, then
+ malloc returned NULL, and errno is whatever malloc set it to. */
+extern void *uuconf_malloc (void *uuconf_pblock,
+ UUCONF_SIZE_T uuconf_cbytes);
+
+/* Add a block returned by the generic malloc routine to a memory
+ block. This returns zero on success, non-zero on failure. If this
+ fails (returns non-zero), then malloc returned NULL, and errno is
+ whatever malloc set it to. */
+extern int uuconf_add_block (void *uuconf_pblock, void *uuconf_padd);
+
+/* Free a value returned by uuconf_malloc from a memory block. In the
+ current implementation, this will normally not do anything, but it
+ doesn't hurt. No errors can occur. */
+extern void uuconf_free (void *uuconf_pblock, void *uuconf_pfree);
+
+/* Free an entire memory block, including all values returned by
+ uuconf_malloc from it and all values added to it with
+ uuconf_add_block. No errors can occur. */
+extern void uuconf_free_block (void *uuconf_pblock);
+
+#else /* ! UUCONF_ANSI_C */
+
+extern UUCONF_POINTER uuconf_malloc_block ();
+extern UUCONF_POINTER uuconf_malloc ();
+extern int uuconf_add_block ();
+extern /* void */ uuconf_free ();
+extern /* void */ uuconf_free_block ();
+
+#endif /* ! UUCONF_ANSI_C */
+
+#endif /* ! defined (UUCONF_H) */
diff --git a/gnu/libexec/uucp/common_sources/uucp.h b/gnu/libexec/uucp/common_sources/uucp.h
new file mode 100644
index 0000000..8df3ec4
--- /dev/null
+++ b/gnu/libexec/uucp/common_sources/uucp.h
@@ -0,0 +1,367 @@
+/* uucp.h
+ Header file for the UUCP package.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+/* Get the system configuration parameters. */
+#include "conf.h"
+#include "policy.h"
+
+/* Get a definition for ANSI_C if we weren't given one. */
+#ifndef ANSI_C
+#ifdef __STDC__
+#define ANSI_C 1
+#else /* ! defined (__STDC__) */
+#define ANSI_C 0
+#endif /* ! defined (__STDC__) */
+#endif /* ! defined (ANSI_C) */
+
+/* Pass this definition into uuconf.h. */
+#define UUCONF_ANSI_C ANSI_C
+
+/* We always include some standard header files. We need <signal.h>
+ to define sig_atomic_t. */
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+/* On some systems we need <sys/types.h> to get sig_atomic_t or
+ size_t or time_t. */
+#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && HAVE_SIG_ATOMIC_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#else
+#if ! HAVE_SIZE_T_IN_STDDEF_H && HAVE_SIZE_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#else
+#if ! HAVE_TIME_T_IN_TIME_H && HAVE_TIME_T_IN_TYPES_H
+#define USE_TYPES_H 1
+#endif
+#endif
+#endif
+
+#ifndef USE_TYPES_H
+#define USE_TYPES_H 0
+#endif
+
+#if USE_TYPES_H
+#include <sys/types.h>
+#endif
+
+/* Make sure we have sig_atomic_t. */
+#if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H
+#ifndef SIG_ATOMIC_T
+/* There is no portable definition for sig_atomic_t. */
+#define SIG_ATOMIC_T char
+#endif /* ! defined (SIG_ATOMIC_T) */
+typedef SIG_ATOMIC_T sig_atomic_t;
+#endif /* ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H */
+
+/* Make sure we have size_t. We use int as the default because the
+ main use of this type is to provide an argument to malloc and
+ realloc. On a system which does not define size_t, int is
+ certainly the correct type to use. */
+#if ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H
+#ifndef SIZE_T
+#define SIZE_T unsigned
+#endif /* ! defined (SIZE_T) */
+typedef SIZE_T size_t;
+#endif /* ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H */
+
+/* Make sure we have time_t. We use long as the default. We don't
+ bother to let conf.h override this, since on a system which doesn't
+ define time_t long must be correct. */
+#if ! HAVE_TIME_T_IN_TIME_H && ! HAVE_TIME_T_IN_TYPES_H
+typedef long time_t;
+#endif
+
+/* Set up some definitions for both ANSI C and Classic C.
+
+ P() -- for function prototypes (e.g. extern int foo P((int)) ).
+ pointer -- for a generic pointer (i.e. void *).
+ constpointer -- for a generic pointer to constant data.
+ BUCHAR -- to convert a character to unsigned. */
+#if ANSI_C
+#if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR
+ #error ANSI C compiler without void or unsigned char
+#endif
+#define P(x) x
+typedef void *pointer;
+typedef const void *constpointer;
+#define BUCHAR(b) ((unsigned char) (b))
+#else /* ! ANSI_C */
+/* Handle uses of const, volatile and void in Classic C. */
+#define const
+#define volatile
+#if ! HAVE_VOID
+#define void int
+#endif
+#define P(x) ()
+typedef char *pointer;
+typedef const char *constpointer;
+#if HAVE_UNSIGNED_CHAR
+#define BUCHAR(b) ((unsigned char) (b))
+#else /* ! HAVE_UNSIGNED_CHAR */
+/* This should work on most systems, but not necessarily all. */
+#define BUCHAR(b) ((b) & 0xff)
+#endif /* ! HAVE_UNSIGNED_CHAR */
+#endif /* ! ANSI_C */
+
+/* Make sure we have a definition for offsetof. */
+#ifndef offsetof
+#define offsetof(type, field) \
+ ((size_t) ((char *) &(((type *) 0)->field) - (char *) (type *) 0))
+#endif
+
+/* Only use inline with gcc. */
+#ifndef __GNUC__
+#define __inline__
+#endif
+
+/* Get the string functions, which are used throughout the code. */
+#if HAVE_MEMORY_H
+#include <memory.h>
+#else
+/* We really need a definition for memchr, and this should not
+ conflict with anything in <string.h>. I hope. */
+extern pointer memchr ();
+#endif
+
+#if HAVE_STRING_H
+#include <string.h>
+#else /* ! HAVE_STRING_H */
+#if HAVE_STRINGS_H
+#include <strings.h>
+#else /* ! HAVE_STRINGS_H */
+extern char *strcpy (), *strncpy (), *strchr (), *strrchr (), *strtok ();
+extern char *strcat (), *strerror (), *strstr ();
+extern size_t strlen (), strspn (), strcspn ();
+#if ! HAVE_MEMORY_H
+extern pointer memcpy (), memchr ();
+#endif /* ! HAVE_MEMORY_H */
+#endif /* ! HAVE_STRINGS_H */
+#endif /* ! HAVE_STRING_H */
+
+/* Get what we need from <stdlib.h>. */
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#else /* ! HAVE_STDLIB_H */
+extern pointer malloc (), realloc (), bsearch ();
+extern long strtol ();
+extern char *getenv ();
+#endif /* ! HAVE_STDLIB_H */
+
+/* NeXT uses <libc.h> to declare a bunch of functions. */
+#if HAVE_LIBC_H
+#include <libc.h>
+#endif
+
+/* Make sure we have the EXIT_ macros. */
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS (0)
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE (1)
+#endif
+
+/* If we need to declare errno, do so. I don't want to always do
+ this, because some system might theoretically have a different
+ declaration for errno. On a POSIX system this is sure to work. */
+#if ! HAVE_ERRNO_DECLARATION
+extern int errno;
+#endif
+
+/* If the system has the socket call, guess that we can compile the
+ TCP code. */
+#define HAVE_TCP HAVE_SOCKET
+
+/* If the system has the t_open call, guess that we can compile the
+ TLI code. */
+#define HAVE_TLI HAVE_T_OPEN
+
+/* The boolean type holds boolean values. */
+typedef int boolean;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+
+/* The openfile_t type holds an open file. This depends on whether we
+ are using stdio or not. */
+#if USE_STDIO
+
+typedef FILE *openfile_t;
+#define EFILECLOSED ((FILE *) NULL)
+#define ffileisopen(e) ((e) != NULL)
+#define ffileeof(e) feof (e)
+#define cfileread(e, z, c) fread ((z), 1, (c), (e))
+#define ffilereaderror(e, c) ferror (e)
+#define cfilewrite(e, z, c) fwrite ((z), 1, (c), (e))
+#ifdef SEEK_SET
+#define ffileseek(e, i) (fseek ((e), (long) (i), SEEK_SET) == 0)
+#define ffilerewind(e) (fseek ((e), (long) 0, SEEK_SET) == 0)
+#else
+#define ffileseek(e, i) (fseek ((e), (long) (i), 0) == 0)
+#define ffilerewind(e) (fseek ((e), (long) 0, 0) == 0)
+#endif
+#define ffileclose(e) (fclose (e) == 0)
+
+#else /* ! USE_STDIO */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef int openfile_t;
+#define EFILECLOSED (-1)
+#define ffileisopen(e) ((e) >= 0)
+#define ffileeof(e) (FALSE)
+#define cfileread(e, z, c) read ((e), (z), (c))
+#define ffilereaderror(e, c) ((c) < 0)
+#define cfilewrite(e, z, c) write ((e), (z), (c))
+#ifdef SEEK_SET
+#define ffileseek(e, i) (lseek ((e), (long) i, SEEK_SET) >= 0)
+#define ffilerewind(e) (lseek ((e), (long) 0, SEEK_SET) >= 0)
+#else
+#define ffileseek(e, i) (lseek ((e), (long) i, 0) >= 0)
+#define ffilerewind(e) (lseek ((e), (long) 0, 0) >= 0)
+#endif
+#define ffileclose(e) (close (e) >= 0)
+
+#endif /* ! USE_STDIO */
+
+/* A prototype for main to avoid warnings from gcc 2.0
+ -Wmissing-prototype option. */
+extern int main P((int argc, char **argv));
+
+/* Some standard routines which we only define if they are not present
+ on the system we are compiling on. */
+
+#if ! HAVE_GETLINE
+/* Read a line from a file. */
+extern int getline P((char **pz, size_t *pc, FILE *e));
+#endif
+
+#if ! HAVE_REMOVE
+/* Erase a file. */
+#undef remove
+extern int remove P((const char *zfile));
+#endif
+
+#if ! HAVE_STRDUP
+/* Copy a string into memory. */
+extern char *strdup P((const char *z));
+#endif
+
+#if ! HAVE_STRSTR
+/* Look for one string within another. */
+extern char *strstr P((const char *zouter, const char *zinner));
+#endif
+
+#if ! HAVE_STRCASECMP
+#if HAVE_STRICMP
+#define strcasecmp stricmp
+#else /* ! HAVE_STRICMP */
+/* Rename strcasecmp to avoid ANSI C name space. */
+#define strcasecmp xstrcasecmp
+extern int strcasecmp P((const char *z1, const char *z2));
+#endif /* ! HAVE_STRICMP */
+#endif /* ! HAVE_STRCASECMP */
+
+#if ! HAVE_STRNCASECMP
+#if HAVE_STRNICMP
+#define strncasecmp strnicmp
+#else /* ! HAVE_STRNICMP */
+/* Rename strncasecmp to avoid ANSI C name space. */
+#define strncasecmp xstrncasecmp
+extern int strncasecmp P((const char *z1, const char *z2, size_t clen));
+#endif /* ! HAVE_STRNICMP */
+#endif /* ! HAVE_STRNCASECMP */
+
+#if ! HAVE_STRERROR
+/* Get a string corresponding to an error message. */
+#undef strerror
+extern char *strerror P((int ierr));
+#endif
+
+/* Get the appropriate definitions for memcmp, memcpy, memchr and
+ bzero. */
+#if ! HAVE_MEMCMP
+#if HAVE_BCMP
+#define memcmp(p1, p2, c) bcmp ((p1), (p2), (c))
+#else /* ! HAVE_BCMP */
+extern int memcmp P((constpointer p1, constpointer p2, size_t c));
+#endif /* ! HAVE_BCMP */
+#endif /* ! HAVE_MEMCMP */
+
+#if ! HAVE_MEMCPY
+#if HAVE_BCOPY
+#define memcpy(pto, pfrom, c) bcopy ((pfrom), (pto), (c))
+#else /* ! HAVE_BCOPY */
+extern pointer memcpy P((pointer pto, constpointer pfrom, size_t c));
+#endif /* ! HAVE_BCOPY */
+#endif /* ! HAVE_MEMCPY */
+
+#if ! HAVE_MEMCHR
+extern pointer memchr P((constpointer p, int b, size_t c));
+#endif
+
+#if ! HAVE_BZERO
+#if HAVE_MEMSET
+#define bzero(p, c) memset ((p), 0, (c))
+#else /* ! HAVE_MEMSET */
+extern void bzero P((pointer p, int c));
+#endif /* ! HAVE_MEMSET */
+#endif /* ! HAVE_BZERO */
+
+/* Look up a character in a string. */
+#if ! HAVE_STRCHR
+#if HAVE_INDEX
+#define strchr index
+extern char *index ();
+#else /* ! HAVE_INDEX */
+extern char *strchr P((const char *z, int b));
+#endif /* ! HAVE_INDEX */
+#endif /* ! HAVE_STRCHR */
+
+#if ! HAVE_STRRCHR
+#if HAVE_RINDEX
+#define strrchr rindex
+extern char *rindex ();
+#else /* ! HAVE_RINDEX */
+extern char *strrchr P((const char *z, int b));
+#endif /* ! HAVE_RINDEX */
+#endif /* ! HAVE_STRRCHR */
+
+/* Turn a string into a long integer. */
+#if ! HAVE_STRTOL
+extern long strtol P((const char *, char **, int));
+#endif
+
+/* Lookup a key in a sorted array. */
+#if ! HAVE_BSEARCH
+extern pointer bsearch P((constpointer pkey, constpointer parray,
+ size_t celes, size_t cbytes,
+ int (*pficmp) P((constpointer, constpointer))));
+#endif
diff --git a/gnu/libexec/uucp/common_sources/uudefs.h b/gnu/libexec/uucp/common_sources/uudefs.h
new file mode 100644
index 0000000..47d2c89
--- /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 0000000..32eef82
--- /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 0000000..c111c00
--- /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 0000000..d557f97
--- /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 0000000..d8c3a66
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.PortSel
@@ -0,0 +1,133 @@
+#!xchat
+# @(#) Login.PortSelUnix V1.0 Tue Sep 1 14:57:05 1992 (Bob Denny)
+#
+# NOTE: Untested with xchat V1.1. Taken from DECUS UUCP.
+#
+# From: "Kent C. Brodie" <moocow!brodie@CSD4.MILW.WISC.EDU>
+# uucp: {uunet!marque,csd4.milw.wisc.edu}!moocow!brodie
+# special script for "uwmcsd4", have to go through a port selector (and then
+# log in via standard Unix procedures).
+#
+# Also included is the ability to wait in the port selector queue.
+# Be forwarned that the debug log can get pretty big depending on
+# how many times you "wait" in the queue.
+# (C) 1989 Kent C. Brodie - Medical College of Wisconsin
+
+# P0 is systemname , P1 is username, P2 is password.
+
+ zero
+
+# send a CR to get the selector's attention. Sleep a little bit
+# due to large login text of selector. It sends "Which System?"
+# when it's ready.
+
+getprtslct:
+ count
+ ifgtr noprtslct 6
+ break
+ send \r
+ sleep 2000
+ flush
+ expect prtslctok ystem?
+ timeout getprtslct 15000
+
+noprtslct:
+ logerr Sent cr, no "Which System?" from port selector
+ failed
+
+# Send the system name. We either get "OK" (connected), or we
+# get "No ports available, would you like to wait?" (wait in queue)
+
+prtslctok:
+ zero
+ sendstr 0
+ send \r
+ expect connected OK
+ expect prtslctwait wait?
+ timeout noconnect 10000
+
+# Usually we get "nn Your place in queue" messages. JUST in case we
+# get a free port right away, check for 'Are you ready?' as well.
+
+prtslctwait:
+ zero
+ send Y\r
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout prtwaitbad 70000
+
+prtwaitbad:
+ logerr Sent "Y" to wait in queue, did not get valid response.
+ failed
+
+# Here's where we wait in the queue. The port selector sends us a status
+# message about once a minute. We either get "nn Your place in queue"
+# or we get "System Available. Are you Ready?".
+# If something goes wrong, we time out waiting for either response.
+# The reason we don't sleep for 40-50 seconds is because as SOON as the
+# port is ready, it informs us. If we wait too long, it drops us.
+# This setup is laid out for a maximum of 20 "tries" which is ABOUT
+# 20 minutes. Note: This constant retrying can make log files
+# kind of big....
+
+prtslctque:
+ count
+ ifgtr prtslcttry 20
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout noportwait 70000
+
+prtslcttry:
+ logerr Too many (20) wait/retries -- queue too busy.
+ failed
+
+prtslctrdy:
+ send Y\r
+ expect connected OK
+ timeout noconnect 20000
+
+
+noportwait:
+ logerr Timed out awaiting place in port queue
+ failed
+
+noconnect:
+ logerr Sent system name, no "OK" from selector
+ failed
+
+# standard Unix login stuff. Send cr, expect "ogin:", if no, send a break
+# (which tells Unix to try the next bit rate) and try again.
+
+connected:
+ send \r
+ zero
+ goto waitlogin
+
+sendbreak:
+ count
+ ifgtr nolgi 6
+ flush
+ break
+
+waitlogin:
+ expect gotlogin ogin:
+ timeout sendbreak 5000
+
+nolgi:
+ logerr No login: prompt
+ failed
+
+gotlogin:
+ sendstr 1
+ send \r
+ expect gotword word:
+ timeout nopwd 10000
+
+nopwd:
+ logerr No password: prompt
+ failed
+
+gotword:
+ sendstr 2
+ send \r
+ success
diff --git a/gnu/libexec/uucp/contrib/Login.VMS b/gnu/libexec/uucp/contrib/Login.VMS
new file mode 100644
index 0000000..d6196cb
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.VMS
@@ -0,0 +1,96 @@
+#!xchat
+# @(#) Login.VMS V1.1 Tue Sep 1 13:24:54 1992 (Bob Denny)
+#
+#
+# xchat script for logging into a VMS system. If no VMS password
+# parameter supplied, skips password phase of VMS login. If syspass
+# parameter given, will go through steps needed to log into a VMS
+# system where a "system password" was set on the port.
+#
+# Cannot handle situation where system password is required but
+# no password needed.
+#
+#
+# Usage:
+# xchat Login.VMS username [ password [ syspass ] ]
+#
+# Uncomment the lines starting with "###" to get debug logging.
+#
+start:
+### dbgfile Login.Log
+### dbgset 15
+ sleep 2000 # Wait 2 seconds
+ zero
+ flush # Flush typeahead
+ ifnstr login 2 # Skip sys passwd if not given
+#
+# Need system password. Send <CR> to get bell.
+# Try 5 times at 2 sec. intervals. Skip to do
+# username if we see "Username:".
+#
+syspass:
+ count
+ ifgtr nobell 5 # Fail after 5 tries
+ send \r
+ timeout syspass 2000 # Wait 2 sec. and try again
+ expect gotbell \007
+ expect gotlogin Username:
+#
+# Got the bell. Send the system password. Repeat 5 times
+# at 2 sec. intervals. Fail if we don't get Username:
+#
+gotbell:
+ zero
+ sleep 2000
+l1:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ sendstr 2
+ send \r
+ timeout l1 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Start here if no system password supplied.
+# Send <CR> until we get Username: Try 5 times at 2 sec. intervals.
+#
+login:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ send \r
+ timeout login 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Got VMS "Username:" prompt. Send the username. If a password
+# was given, wait for the "Password:" prompt. Die after 10 seconds.
+# if no password was given, we're done!
+#
+gotlogin:
+ sendstr 0
+ send \r
+ ifnstr done 1
+ timeout nopasswd 10000
+ expect gotpasswd Password:
+#
+# Got VMS "Password:" prompt. Send the password and we're done!
+#
+gotpasswd:
+ sendstr 1
+ send \r
+#
+# Success!
+#
+done:
+ success
+#
+# ERROR HANDLERS
+#
+nobell:
+ logerr No VMS system password prompt (bell)
+ failed
+nologin:
+ logerr No VMS Username: prompt
+ failed
+nopasswd:
+ logerr No VMS Password: prompt.
+ failed
+
diff --git a/gnu/libexec/uucp/contrib/Makefile.uurt b/gnu/libexec/uucp/contrib/Makefile.uurt
new file mode 100644
index 0000000..235fcca
--- /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 0000000..5e9aaa8
--- /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 0000000..c4105ed
--- /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 0000000..2cc361c
--- /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 0000000..5f93a28
--- /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 0000000..919b94f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.man
@@ -0,0 +1,130 @@
+.\" @(#)man/man8/savelog.an 1.2 24 Oct 1990 05:18:46
+.de pP
+.if n .sp 1
+.if t .sp .4
+..
+.de tP
+.pP
+.ta \\n(pDu
+.ti -\\n(pDu
+..
+.TH SAVELOG X_MAN8_EXT_X "31 January 1988" "Local"
+.SH NAME
+savelog \- cycle and truncate log files
+.SH SYNOPSIS
+.na
+.B X_UTIL_BIN_DIR_X/savelog
+[
+.B \-m
+.I mode
+] [
+.B \-u
+.I user
+] [
+.B \-g
+.I group
+] [
+.B \-c
+.I cycle
+] [
+.B \-t
+] [
+.B \-l
+]
+.I logfile
+.br
+.ad
+.SH DESCRIPTION
+The
+.I savelog
+command renames and optionally compresses a log file and cycles it
+through a set of names based on the original log file, removing the
+last name in the cycle.
+.SH OPTIONS
+The
+.I savelog
+command accepts the following options:
+.TP
+\fB\-m\fP \fImode\fP
+Change the permissions mode for renamed log files to
+.IR mode .
+By default the mode is unchanged.
+.TP
+\fB\-u\fP \fIuser\fP
+Change the owner for renamed log files to
+.IR user .
+By default the owner is unchanged.
+.TP
+\fB\-g\fP \fIgroup\fP
+Change the group for renamed log files to
+.IR group .
+By default the group is unchanged.
+.TP
+\fB\-c\fP \fIcycle\fP
+Save
+.I cycle
+versions of the logfile, where
+.I cycle
+is a decimal number. The default value is 7.
+.TP
+.B \-l
+Do not compress log files. By default, a compression program is used,
+if one is available.
+.TP
+.B \-t
+Ensure that a new logfile exists when the savelog operation is
+complete. Use of
+.BR \-m ,
+.BR \-u
+or
+.BR \-g
+imply this, ensuring that the logfile will have the designated mode.
+.SH "OPERATION"
+The given logfile is cycled through files named:
+.RS
+
+OLD/\fIfile\fP.\fInumber\fP
+
+.RE
+where
+.I file
+is the basename for the logfile and where
+.I number
+ranges from 0 to one less then the
+.I cycle
+count specified for the command.
+The
+.I OLD
+dirctory is created, as necessary, and is under the same directory as
+the logfile itself.
+.PP
+This cycle operation is accomplished by renaming the file numbered
+.IR cycle -2
+to a file numbered
+.IR cycle -1
+and so on until the file numbered 0 is renamed to the file numbered 1.
+If compression is being used, the first cycle file is compressed after
+being renamed to cycle 1. After the cycle files are moved through the
+various names, the filefile itself is moved to the cycle 0 file.
+This cycle normally occurs once every time
+.I savelog
+is executed.
+If the log file does not exist, savelog ignores it and does
+not cycle the OLD files.
+.PP
+If compression is being used, then compressed log files will have an
+additional suffix appropriate for the compression program that is
+used.
+.SH "SEE ALSO"
+.IR smail (X_MAN5_EXT_X)
+and
+.IR smail (X_MAN8_EXT_X).
+.SH COPYRIGHT
+Copyright(C)1987, 1988 Ronald S. Karr and Landon Curt Noll
+.br
+See a file COPYING,
+distributed with the source code,
+or type
+.I "smail \-bc"
+for distribution rights and restrictions
+associated with this software.
diff --git a/gnu/libexec/uucp/contrib/savelog.sh b/gnu/libexec/uucp/contrib/savelog.sh
new file mode 100755
index 0000000..64c989f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.sh
@@ -0,0 +1,247 @@
+#! /bin/sh
+# @(#)util/savelog.sh 1.4 26 Oct 1991 22:49:39
+#
+# savelog - save a log file
+#
+# Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
+#
+# See the file COPYING, distributed with smail, for restriction
+# and warranty information.
+#
+# usage: savelog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-l] file...
+#
+# -m mode - chmod log files to mode
+# -u user - chown log files to user
+# -g group - chgrp log files to group
+# -c cycle - save cycle versions of the logfile (default: 7)
+# -t - touch file
+# -l - don't compress any log files (default: compress)
+# file - log file names
+#
+# The savelog command saves and optionally compresses old copies of files
+# into an 'dir'/OLD sub-directory. The 'dir' directory is determined from
+# the directory of each 'file'.
+#
+# Older version of 'file' are named:
+#
+# OLD/'file'.<number><compress_suffix>
+#
+# where <number> is the version number, 0 being the newest. By default,
+# version numbers > 0 are compressed (unless -l prevents it). The
+# version number 0 is never compressed on the off chance that a process
+# still has 'file' opened for I/O.
+#
+# If the 'file' does not exist or if it is zero length, no further processing
+# is performed. However if -t was also given, it will be created.
+#
+# For files that do exist and have lengths greater than zero, the following
+# actions are performed.
+#
+# 1) Version numered files are cycled. That is version 6 is moved to
+# version 7, version is moved to becomes version 6, ... and finally
+# version 0 is moved to version 1. Both compressed names and
+# uncompressed names are cycled, regardless of -t. Missing version
+# files are ignored.
+#
+# 2) The new OLD/file.1 is compressed and is changed subject to
+# the -m, -u and -g flags. This step is skipped if the -t flag
+# was given.
+#
+# 3) The main file is moved to OLD/file.0.
+#
+# 4) If the -m, -u, -g or -t flags are given, then file is created
+# (as an empty file) subject to the given flags.
+#
+# 5) The new OLD/file.0 is chanegd subject to the -m, -u and -g flags.
+#
+# Note: If the OLD sub-directory does not exist, it will be created
+# with mode 0755.
+#
+# Note: If no -m, -u or -g flag is given, then the primary log file is
+# not created.
+#
+# Note: Since the version numbers start with 0, version number <cycle>
+# is never formed. The <cycle> count must be at least 2.
+#
+# Bugs: If a process is still writing to the file.0 and savelog
+# moved it to file.1 and compresses it, data could be lost.
+# Smail does not have this problem in general because it
+# restats files often.
+
+# common location
+PATH="X_UTIL_PATH_X:X_SECURE_PATH_X"; export PATH
+COMPRESS="X_COMPRESS_X"
+COMP_FLAG="X_COMP_FLAG_X"
+DOT_Z="X_DOT_Z_X"
+CHOWN="X_CHOWN_X"
+GETOPT="X_UTIL_BIN_DIR_X/getopt"
+
+# parse args
+exitcode=0 # no problems to far
+prog=$0
+mode=
+user=
+group=
+touch=
+count=7
+set -- `$GETOPT m:u:g:c:lt $*`
+if [ $# -eq 0 -o $? -ne 0 ]; then
+ echo "usage: $prog [-m mode][-u user][-g group][-t][-c cycle][-l] file ..." 1>&2
+ exit 1
+fi
+for i in $*; do
+ case $i in
+ -m) mode=$2; shift 2;;
+ -u) user=$2; shift 2;;
+ -g) group=$2; shift 2;;
+ -c) count=$2; shift 2;;
+ -t) touch=1; shift;;
+ -l) COMPRESS=""; shift;;
+ --) shift; break;;
+ esac
+done
+if [ "$count" -lt 2 ]; then
+ echo "$prog: count must be at least 2" 1>&2
+ exit 2
+fi
+
+# cycle thru filenames
+while [ $# -gt 0 ]; do
+
+ # get the filename
+ filename=$1
+ shift
+
+ # catch bogus files
+ if [ -b "$filename" -o -c "$filename" -o -d "$filename" ]; then
+ echo "$prog: $filename is not a regular file" 1>&2
+ exitcode=3
+ continue
+ fi
+
+ # if not a file or empty, do nothing major
+ if [ ! -s $filename ]; then
+ # if -t was given and it does not exist, create it
+ if [ ! -z "$touch" -a ! -f $filename ]; then
+ touch $filename
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not touch $filename" 1>&2
+ exitcode=4
+ continue
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+ fi
+ continue
+ fi
+
+ # be sure that the savedir exists and is writable
+ savedir=`expr "$filename" : '\(.*\)/'`
+ if [ -z "$savedir" ]; then
+ savedir=./OLD
+ else
+ savedir=$savedir/OLD
+ fi
+ if [ ! -s $savedir ]; then
+ mkdir $savedir
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not mkdir $savedir" 1>&2
+ exitcode=5
+ continue
+ fi
+ chmod 0755 $savedir
+ fi
+ if [ ! -d $savedir ]; then
+ echo "$prog: $savedir is not a directory" 1>&2
+ exitcode=6
+ continue
+ fi
+ if [ ! -w $savedir ]; then
+ echo "$prog: directory $savedir is not writable" 1>&2
+ exitcode=7
+ continue
+ fi
+
+ # deterine our uncompressed file names
+ newname=`expr "$filename" : '.*/\(.*\)'`
+ if [ -z "$newname" ]; then
+ newname=$savedir/$filename
+ else
+ newname=$savedir/$newname
+ fi
+
+ # cycle the old compressed log files
+ cycle=`expr $count - 1`
+ rm -f $newname.$cycle $newname.$cycle$DOT_Z
+ while [ "$cycle" -gt 1 ]; do
+ # --cycle
+ oldcycle=$cycle
+ cycle=`expr $cycle - 1`
+ # cycle log
+ if [ -f $newname.$cycle$DOT_Z ]; then
+ mv -f $newname.$cycle$DOT_Z $newname.$oldcycle$DOT_Z
+ fi
+ if [ -f $newname.$cycle ]; then
+ # file was not compressed for some reason move it anyway
+ mv -f $newname.$cycle $newname.$oldcycle
+ fi
+ done
+
+ # compress the old uncompressed log if needed
+ if [ -f $newname.0 ]; then
+ if [ -z "$COMPRESS" ]; then
+ newfile=$newname.1
+ mv $newname.0 $newfile
+ else
+ newfile=$newname.1$DOT_Z
+ $COMPRESS $COMP_FLAG < $newname.0 > $newfile
+ rm -f $newname.0
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newfile
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newfile
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newfile
+ fi
+ fi
+
+ # move the file into the file.0 holding place
+ mv -f $filename $newname.0
+
+ # replace file if needed
+ if [ ! -z "$touch" -o ! -z "$user" -o \
+ ! -z "$group" -o ! -z "$mode" ]; then
+ touch $filename
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+
+ # fix the permissions on the holding place file.0 file
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newname.0
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newname.0
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newname.0
+ fi
+done
+exit $exitcode
diff --git a/gnu/libexec/uucp/contrib/stats.sh b/gnu/libexec/uucp/contrib/stats.sh
new file mode 100755
index 0000000..ac1d0f5
--- /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 0000000..dd82633
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/tstout.c
@@ -0,0 +1,158 @@
+/* tstout.c
+ Put together by Ian Lance Taylor <ian@airs.com>
+
+ This program is used to logout a program run by the tstuu program.
+ I needed this because on Ultrix 4.0 I can't get the uucp program
+ to run without invoking it via /bin/login and having it start up
+ as a shell. If I don't do it this way, it gets a SIGSEGV trap
+ for some reason. Most systems probably don't need to do things
+ this way. It will only work on BSD systems anyhow, I suspect.
+
+ The code for this comes from "UNIX Network Programming" by W.
+ Richard Stevens, Prentice-Hall 1990. Most of it is from 4.3BSD, as
+ noted in the comments.
+
+ This program must run suid to root.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <utmp.h>
+
+static int logout P((const char *zdev));
+static void logwtmp P((const char *zdev, const char *zname,
+ const char *zhost));
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *z;
+
+ if (argc != 2
+ || strncmp (argv[1], "/dev/", sizeof "/dev/" - 1) != 0)
+ {
+ fprintf (stderr, "Usage: tstout device\n");
+ exit (EXIT_FAILURE);
+ }
+
+ z = argv[1] + 5;
+
+ if (logout (z))
+ logwtmp (z, "", "");
+
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ *z = 'p';
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ exit (EXIT_SUCCESS);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logout.c 5.2 (Berkeley) 2/17/89";
+#endif /* LIBC_SCCS and not lint */
+
+#define UTMPFILE "/etc/utmp"
+
+/* 0 on failure, 1 on success */
+
+static int
+logout(line)
+ register const char *line;
+{
+ register FILE *fp;
+ struct utmp ut;
+ int rval;
+ time_t time();
+
+ if (!(fp = fopen(UTMPFILE, "r+")))
+ return(0);
+ rval = 0;
+ while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) {
+ if (!ut.ut_name[0] ||
+ strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
+ continue;
+ bzero(ut.ut_name, sizeof(ut.ut_name));
+ bzero(ut.ut_host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR);
+ (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp);
+ (void)fseek(fp, (long)0, L_INCR);
+ rval = 1;
+ }
+ (void)fclose(fp);
+ return(rval);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88";
+#endif /* LIBC_SCCS and not lint */
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+static void
+logwtmp(line, name, host)
+ const char *line, *name, *host;
+{
+ struct utmp ut;
+ struct stat buf;
+ int fd;
+ time_t time();
+ char *strncpy();
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ (void)close(fd);
+}
diff --git a/gnu/libexec/uucp/contrib/uuclean b/gnu/libexec/uucp/contrib/uuclean
new file mode 100644
index 0000000..e9c631c
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuclean
@@ -0,0 +1,23 @@
+# This is a sample uuclean shell script
+# Copyright (C) 1992 Ian Lance Taylor
+# Do whatever you like with this script.
+#
+# Set some variables
+bindir=/usr/local/bin
+spooldir=/usr/spool/uucp
+#
+# Warn about all mail over two days old
+$(bindir)/uustat -c rmail -o 48 -N -Q -W"Unable to deliver; will try up to one week"
+# Return all mail over a week old
+$(bindir)/uustat -c rmail -o 168 -K -M -N -Q -W"Could not be delivered for over one week"
+# Throw away other requests over a week old
+$(bindir)/uustat -o 168 -K -M -N -Q -W"Over one week old"
+# Throw away any executions over three days old
+$(bindir)/uustat -o 72 -M -N -Q -W"Unable to execute for three days"
+#
+# Now delete any old spool files
+find $(spooldir) -ctime +8 -name '[CDX].*' -print -exec rm -f \{\} \;
+# Delete any old temporary files
+find $(spooldir) -atime +1 -ctime +1 -name 'TM.*' -print -exec rm -f \{\} \;
+# Delete any old preserved files
+find $(spooldir)/.Preserve -atime +14 -ctime +14 -print -exec rm -f \{\} \;
diff --git a/gnu/libexec/uucp/contrib/uuq.sh b/gnu/libexec/uucp/contrib/uuq.sh
new file mode 100755
index 0000000..a5d88e9
--- /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 0000000..ceab41c
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.c
@@ -0,0 +1,657 @@
+/*
+ * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992
+ *
+ * This program digests log and stats files in the "Taylor" format
+ * and outputs various statistical data to standard out.
+ *
+ * Author:
+ * Bob Denny (denny@alisa.com)
+ * Fri Feb 7 13:38:36 1992
+ *
+ * Original author:
+ * Mark Pizzolato mark@infopiz.UUCP
+ *
+ * Edits:
+ * Bob Denny - Fri Feb 7 15:04:54 1992
+ * Heavy rework for Taylor UUCP. This was the (very old) uurate from
+ * DECUS UUCP, which had a single logfile for activity and stats.
+ * Personally, I would have done things differently, with tables
+ * and case statements, but in the interest of time, I preserved
+ * Mark Pizzolato's techniques and style.
+ *
+ * Bob Denny - Sun Aug 30 14:18:50 1992
+ * Changes to report format suggested by Francois Pinard and others.
+ * Add summary report, format from uutraf.pl (perl script), again
+ * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
+ */
+
+char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2";
+
+#include <ctype.h> /* Character Classification */
+#include <string.h>
+#include <math.h>
+
+#include "uucp.h"
+
+
+#define _DEBUG_ 0
+
+/*
+ * Direction of Calling and Data Transmission
+ */
+#define IN 0 /* Inbound */
+#define OUT 1 /* Outbound */
+
+/*
+ * Data structures used to collect information
+ */
+struct File_Stats
+ {
+ int files; /* Files Transferred */
+ unsigned long bytes; /* Data Size Transferred*/
+ double time; /* Transmission Time */
+ };
+
+struct Phone_Call
+ {
+ int calls; /* Call Count */
+ int succs; /* Successful calls */
+ double connect_time; /* Connect Time Spent */
+ struct File_Stats flow[2]; /* Rcvd & Sent Data */
+ };
+
+struct Execution_Command
+ {
+ struct Execution_Command *next;
+ char Commandname[64];
+ int count;
+ };
+
+struct Host_entry
+ {
+ struct Host_entry *next;
+ char Hostname[32];
+ struct Execution_Command *cmds; /* Local Activities */
+ struct Phone_Call call[2]; /* In & Out Activities */
+ };
+
+/*
+ * Stuff for getopt()
+ */
+extern int optind; /* GETOPT : Option Index */
+extern char *optarg; /* GETOPT : Option Value */
+extern void *calloc();
+
+static void fmtime();
+static void fmbytes();
+
+/*
+ * Default files to read. Taken from Taylor compile-time configuration.
+ * Must look like an argvec, hence the dummy argv[0].
+ */
+static char *(def_logs[3]) = { "", LOGFILE, STATFILE };
+
+/*
+ * Misc. strings for reports
+ */
+static char *(file_hdr[2]) = { "\nReceived file statistics:\n",
+ "\nSent file statistics\n" };
+
+/*
+ * BEGIN EXECUTION
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char c;
+ char *p, *s;
+ struct Host_entry *hosts = NULL;
+ struct Host_entry *cur = NULL;
+ struct Host_entry *e;
+ struct Execution_Command *cmd;
+ struct Execution_Command *ec;
+ char Hostname[64];
+ FILE *Log = NULL;
+ char logline[1024];
+ char *logmsg;
+ int sent;
+ int called;
+ int show_files = 0; /* I prefer boolean, but... */
+ int show_calls = 0;
+ int show_commands = 0;
+ int show_efficiency = 0;
+ int show_summary = 0;
+ int have_files = 0;
+ int have_calls = 0;
+ int have_commands = 0;
+ int use_stdin = 0;
+ Hostname[0] = '\0';
+
+ /*
+ * I wish the compiler had the #error directive!
+ */
+#if !HAVE_TAYLOR_LOGGING
+ fprintf(stderr, "uurate cannot be used with your configuration of\n");
+ fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n");
+ fprintf(stderr, "TAYLOR_LOGGING configuration.\n");
+ exit(1);
+#endif
+
+ /*
+ * Process the command line arguments
+ */
+ while((c = getopt(argc, argv, "h:cfexai")) != EOF)
+ {
+ switch(c)
+ {
+ case 'h':
+ strcpy(Hostname, optarg);
+ break;
+ case 'c':
+ show_calls = 1;
+ break;
+ case 'f':
+ show_files = 1;
+ break;
+ case 'x':
+ show_commands = 1;
+ break;
+ case 'e':
+ show_efficiency = 1;
+ break;
+ case 'a':
+ show_calls = show_files = show_commands = show_efficiency = 1;
+ break;
+ case 'i':
+ use_stdin = 1;
+ break;
+ default :
+ goto usage;
+ }
+ }
+
+ /*
+ * If no report switches given, show summary report.
+ */
+ if (show_calls == 0 && show_files == 0
+ && show_efficiency == 0 && show_commands == 0)
+ show_summary = 1;
+
+ /*
+ * Adjust argv and argc to account for the args processed above.
+ */
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * If further args present, Assume rest are logfiles for us to process,
+ * otherwise, take input from Log and Stat files provided in the
+ * compilation environment of Taylor UUCP. If -i was given, Log already
+ * points to stdin and no file args are accepted.
+ */
+ if(argc == 1) /* No file arguments */
+ {
+ if (use_stdin) /* If -i, read from stdin */
+ {
+ argc = 2;
+ Log = stdin;
+ }
+ else /* Read from current logs */
+ {
+ argc = 3; /* Bash argvec to default log/stat files */
+ argv = &def_logs[0];
+ }
+ }
+ else if (use_stdin) /* File args with -i is an error */
+ {
+ fprintf(stderr, "uurate (error): file args given with '-i'\n");
+ goto usage;
+ }
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * MAIN LOGFILE PROCESSING LOOP
+ */
+ while (argc > 1)
+ {
+
+ if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ return;
+ }
+
+#if _DEBUG_
+ printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1]));
+#endif
+
+ /*
+ * Read each line of the logfile and collect information
+ */
+ while (fgets(logline, sizeof(logline), Log))
+ {
+ /*
+ * The host name of the other end of the connection is
+ * always the second field of the log line, whether we
+ * are reading a Log file or a Stats file. Set 'p' to
+ * point to the second field, null-terminated. Skip
+ * the line if something is funny.
+ */
+ if (NULL == (p = strchr(logline, ' ')))
+ continue;
+ ++p;
+ if (NULL != (s = strchr(p, ' ')))
+ *s = '\0';
+ for (s = p; *s; ++s)
+ if (isupper(*s))
+ *s = tolower(*s);
+ /*
+ * Skip this line if we got -h <host> and
+ * this line does not contain that host name.
+ */
+ if (Hostname[0] != '\0')
+ if (0 != strcmp(p, Hostname))
+ continue;
+ /*
+ * We are within a call block now. If this line is a file
+ * transfer record, determine the direction. If not then
+ * skip the line if it is not interesting.
+ */
+ if ((s = strchr(++s, ')')) == NULL)
+ continue;
+ logmsg = s + 2; /* Message is 2 characters after ')' */
+ if (0 == strncmp(logmsg, "sent", 4))
+ sent = OUT;
+ else
+ if (0 == strncmp(logmsg, "received", 8))
+ sent = IN;
+ else
+ if ((0 != strncmp(logmsg, "Call complete", 13)) &&
+ (0 != strncmp(logmsg, "Calling system", 14)) &&
+ (0 != strncmp(logmsg, "Incoming call", 13)) &&
+ (0 != strncmp(logmsg, "Executing", 9)))
+ continue;
+ /*
+ * Find the Host_entry for this host, or create a new
+ * one and link it on to the list.
+ */
+ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
+ {
+ for (cur = hosts; cur != NULL ; cur = cur->next)
+ if (0 == strcmp(cur->Hostname, p))
+ break;
+ if (cur == NULL)
+ {
+ cur = (struct Host_entry *)calloc(1, sizeof(*hosts));
+ strcpy(cur->Hostname, p);
+ if (hosts == NULL)
+ hosts = cur;
+ else
+ {
+ for (e = hosts; e->next != NULL; e = e->next);
+ e->next = cur;
+ }
+ }
+ }
+ /*
+ * OK, if this is a uuxqt record, find the Execution_Command
+ * structure for the command being executed, or create a new
+ * one. Then count an execution of this command.
+ */
+ if (0 == strncmp(logmsg, "Executing", 9))
+ {
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if ((s = strpbrk(++p, " )")) == NULL)
+ continue;
+ *s = '\0';
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ if (0 == strcmp(cmd->Commandname, p))
+ break;
+ if (cmd == NULL)
+ {
+ cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd));
+ strcpy(cmd->Commandname, p);
+ if (cur->cmds == NULL)
+ cur->cmds = cmd;
+ else
+ {
+ for (ec = cur->cmds; ec->next != NULL; ec = ec->next);
+ ec->next = cmd;
+ }
+ }
+ ++cmd->count;
+ have_commands = 1;
+ continue;
+ }
+ /*
+ * Count start of outgoing call.
+ */
+ if (0 == strncmp(logmsg, "Calling system", 14))
+ {
+ called = OUT;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Count start of incoming call.
+ */
+ if (0 == strncmp(logmsg, "Incoming call", 13))
+ {
+ called = IN;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Handle end of call. Pick up the connect time.
+ */
+ if (0 == strncmp(logmsg, "Call complete", 13))
+ {
+ cur->call[called].succs += 1;
+ if (NULL == (s = strchr(logmsg, '(')))
+ continue;
+ cur->call[called].connect_time += atof(s+1);
+ continue;
+ }
+ /*
+ * If we reached here, this must have been a file transfer
+ * record. Count it in the field corresponding to the
+ * direction of the transfer. Count bytes transferred and
+ * the time to transfer as well.
+ */
+ have_files = 1;
+ cur->call[called].flow[sent].files += 1;
+ if (NULL == (s = strchr(logmsg, ' ')))
+ continue;
+ cur->call[called].flow[sent].bytes += atol(++s);
+ if (NULL == (s = strchr(s, ' ')))
+ continue;
+ if (NULL == (s = strpbrk(s, "0123456789")))
+ continue;
+ cur->call[called].flow[sent].time += atof(s);
+ }
+ argc -= 1;
+ argv += 1;
+ if(Log != stdin)
+ fclose(Log);
+ }
+
+ /*
+ * ***********
+ * * REPORTS *
+ * ***********
+ */
+
+ /*
+ * Truncate the Hostnames to 8 characters at most.
+ */
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ cur->Hostname[8] = '\0';
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * Summary report
+ *
+ * I know, this code could be tightened (rbd)...
+ */
+ if(show_summary)
+ {
+ char t1[32], t2[32], t3[32], t4[32], t5[32];
+ long ib, ob, b, rf, sf;
+ long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0;
+ double it, ot, ir, or;
+ double t_it=0.0, t_ot=0.0;
+ int nhosts = 0;
+
+ printf("\n\
+ Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n");
+ printf("\
+ Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n");
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ ib = (cur->call[IN].flow[IN].bytes +
+ cur->call[OUT].flow[IN].bytes);
+ fmbytes(ib, t1);
+ t_ib += ib;
+
+ ob = (cur->call[IN].flow[OUT].bytes +
+ cur->call[OUT].flow[OUT].bytes);
+ fmbytes(ob, t2);
+ t_ob += ob;
+
+ b = ib + ob;
+ fmbytes(b, t3);
+ t_b += b;
+
+ it = cur->call[IN].flow[IN].time +
+ cur->call[OUT].flow[IN].time;
+ fmtime(it, t4);
+ t_it += it;
+
+ ot = cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(ot, t5);
+ t_ot += ot;
+
+ rf = cur->call[IN].flow[IN].files +
+ cur->call[OUT].flow[IN].files;
+ t_rf += rf;
+
+ sf = cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[OUT].files;
+ t_sf += sf;
+
+ ir = (it == 0.0) ? 0.0 : (ib / it);
+ or = (ot == 0.0) ? 0.0 : (ob / ot);
+
+ printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ cur->Hostname,
+ t1, t2, t3, t4, t5,
+ ir, or, rf, sf);
+ }
+
+ if(nhosts > 1)
+ {
+ fmbytes(t_ib, t1);
+ fmbytes(t_ob, t2);
+ fmbytes(t_b, t3);
+ fmtime(t_it, t4);
+ fmtime(t_ot, t5);
+ ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it);
+ or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot);
+
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ printf("\
+Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ t1, t2, t3, t4, t5,
+ ir, or, t_rf, t_sf);
+ }
+ }
+
+
+ /*
+ * Call statistics report
+ */
+ if(show_calls && have_calls)
+ {
+ char t1[32], t2[32];
+
+ printf("\nCall statistics:\n");
+ printf("\
+ sysname callto failto totime callfm failfm fmtime\n");
+ printf("\
+ -------- ------ ------ -------- ------ ------ --------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ fmtime(cur->call[OUT].connect_time, t1);
+ fmtime(cur->call[IN].connect_time, t2),
+ printf(" %-8s %6d %6d %8s %6d %6d %8s\n",
+ cur->Hostname,
+ cur->call[OUT].calls,
+ cur->call[OUT].calls - cur->call[OUT].succs,
+ t1,
+ cur->call[IN].calls,
+ cur->call[IN].calls - cur->call[IN].succs,
+ t2);
+ }
+ }
+
+ /*
+ * File statistics report
+ */
+ if(show_files && have_files)
+ {
+ char t1[32], t2[32];
+
+ for (sent = IN; sent <= OUT; ++sent)
+ {
+ printf(file_hdr[sent]);
+ printf(" sysname files bytes xfr time byte/s\n");
+ printf(" -------- ------ -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ double rate;
+ double time;
+
+ time = cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time;
+ if (time == 0.0)
+ continue;
+ rate = (cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes) / time;
+ fmbytes((cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes), t1);
+ fmtime((cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time), t2);
+ printf(" %-8s %6d %8s %8s %6.1f\n",
+ cur->Hostname,
+ cur->call[IN].flow[sent].files +
+ cur->call[OUT].flow[sent].files,
+ t1, t2, rate);
+ }
+ }
+ }
+
+ /*
+ * Efficiency report
+ */
+ if (show_efficiency && have_files)
+ {
+ char t1[32], t2[32], t3[32];
+ double total, flow;
+
+ printf("\nEfficiency:\n");
+ printf(" sysname conntime flowtime ovhdtime eff. %%\n");
+ printf(" -------- -------- -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ total = cur->call[IN].connect_time + cur->call[OUT].connect_time;
+ flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time;
+ fmtime(total, t1);
+ fmtime(flow, t2);
+ fmtime((total-flow), t3);
+ printf(" %-8s %8s %8s %8s %5.1f%%\n",
+ cur->Hostname, t1, t2, t3, ((flow / total) * 100.0));
+ }
+ }
+
+ /*
+ * Command execution report
+ */
+ if (show_commands & have_commands)
+ {
+ printf("\nCommand executions:\n");
+ printf(" sysname rmail rnews other\n");
+ printf(" -------- ------ ------ ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ int rmail, rnews, other;
+
+ if (cur->cmds == NULL)
+ continue;
+ rmail = rnews = other = 0;
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ {
+ if (strcmp(cmd->Commandname, "rmail") == 0)
+ rmail += cmd->count;
+ else if (strcmp(cmd->Commandname, "rnews") == 0)
+ rnews += cmd->count;
+ else
+ other += cmd->count;
+ }
+ printf(" %-8s %6d %6d %6d\n", cur->Hostname,
+ rmail, rnews, other);
+ }
+ }
+ return;
+
+ usage:
+ fprintf(stderr,
+ "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n");
+ fprintf(stderr,"where:\t-c\tReport call statistics\n");
+ fprintf(stderr, "\t-f\tReport file transfer statistics\n");
+ fprintf(stderr, "\t-e\tReport efficiency statistics\n");
+ fprintf(stderr, "\t-x\tReport command execution statistics\n");
+ fprintf(stderr, "\t-a\tAll of the above reports\n");
+ fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n");
+ fprintf(stderr, "\t-i\tRead log info from standard input\n");
+ fprintf(stderr,
+ "If no report options given, a compact summary report is given.\n");
+ fprintf(stderr,
+ "If neither -i nor logfiles given, defaults to reading from\n");
+ fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE);
+}
+
+/*
+ * fmtime() - Format time in hours & minutes;
+ */
+static void fmtime(dsec, buf)
+ double dsec;
+ char *buf;
+{
+ long hrs, min, lsec;
+
+ lsec = dsec;
+ hrs = lsec / 3600L;
+ min = (lsec - (hrs * 3600L)) / 60L;
+
+ sprintf(buf, "%02ld:%02ld", hrs, min);
+}
+
+/*
+ * fmbytes - Format size in bytes
+ */
+static void fmbytes(n, buf)
+ unsigned long n;
+ char *buf;
+{
+ char t;
+ double s = n;
+
+ if(s >= 10239897.6) /* More than 9999.9K ? */
+ {
+ s = (double)n / 1048576.0; /* Yes, display in Megabytes */
+ t = 'M';
+ }
+ else
+ {
+ s = (double)n / 1024.0; /* Display in Kilobytes */
+ t = 'K';
+ }
+
+ sprintf(buf, "%.1f%c", s, t);
+}
+
diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man
new file mode 100644
index 0000000..9f33ef3
--- /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 100755
index 0000000..3eeb654
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uureroute
@@ -0,0 +1,91 @@
+#!/usr/local/bin/perl
+eval ' exec /usr/local/bin/perl $0 "$@" '
+ if $running_under_some_shell;
+
+# From a script by <Bill.Campbell@celestial.com>
+# Newsgroups: comp.sources.misc
+# Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01
+# Date: 26 Feb 92 02:28:37 GMT
+#
+# This is a Honey DanBer specific routine written in perl to reroute all
+# mail queued up for a specific host. It needs to be run as "root" since
+# uucp will not allow itself to remove others requests.
+#
+# Revision *** 92/21/09: Francois Pinard <pinard@iro.umontreal.ca>
+# 1. adapted for Taylor UUCP
+#
+# Revision 1.3 91/10/08 09:01:21 src
+# 1. Rewritten in perl
+# 2. Add -v option for debugging.
+#
+# Revision 1.2 91/10/07 23:57:42 root
+# 1. Fix mail program path.
+# 2. Truncate directory name to 7 characters
+
+($progname = $0) =~ s!.*/!!; # save this very early
+
+$USAGE = "
+# Reroute uucp mail
+#
+# Usage: $progname [-v] host [host...]
+#
+# Options Argument Description
+# -v Verbose (doesn't execute /bin/sh)
+#
+";
+
+$UUSTAT = "/usr/local/bin/uustat";
+$SHELL = "/bin/sh";
+$SMAIL = "/bin/smail";
+
+sub usage
+{
+ die join ("\n", @_) . "\n$USAGE\n";
+}
+
+do "getopts.pl";
+
+&usage ("Invalid Option") unless do Getopts ("vV");
+
+$verbose = ($opt_v ? '-v' : ());
+$suffix = ($verbose ? '' : $$);
+
+&usage ("No system specified") if $#ARGV < 0;
+
+if (!$verbose)
+{
+ open (SHELL, "| $SHELL");
+ select SHELL;
+}
+
+while ($system = shift)
+{
+ $sysprefix = substr ($system, 0, 7);
+ $directory = "/usr/spool/uucp/$sysprefix";
+ open (UUSTAT, "$UUSTAT -s $system -c rmail |");
+ print "set -ex\n";
+ while (<UUSTAT>)
+ {
+ ($jobid, ) = split;
+ ($cfile) = substr ($jobid, length ($jobid) - 5);
+ $cfilename = "$directory/C./C.$cfile";
+ open (CFILE, $cfilename) || die "Cannot open $cfilename\n";
+ $_ = <CFILE>;
+ close CFILE;
+ if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/)
+ {
+ $datafile = "$directory/D./D.$1";
+ $address = $2;
+ }
+ else
+ {
+ print STDERR;
+ die "Cannot parse previous line from $cfilename\n";
+ }
+ print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n";
+ }
+ close UUSTAT;
+}
+close SHELL unless $verbose;
+
+exit 0;
diff --git a/gnu/libexec/uucp/contrib/uusnap.c b/gnu/libexec/uucp/contrib/uusnap.c
new file mode 100644
index 0000000..0f878c1
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uusnap.c
@@ -0,0 +1,321 @@
+/* uusnap.c
+ (c) 1992 Heiko W.Rupp hwr@pilhuhn.ka.sub.org
+ uusnap is a tool to display the activities of the connected
+ systems.
+
+ Put a file uusnap.systems in NEWCONFIGDIR (see Makefile), in which
+ the systems, you want to monitor are listed, one on a single line.
+ The sequence of the files there determine the sequence of the
+ listing.
+
+ At the moment it only works with taylor config and taylor dirs
+
+ compile it form the Makefile or:
+ cc -c -g -pipe -O -I. -I. -DNEWCONFIGLIB=\"/usr/local/lib/uucp\" uusnap.c
+ cc -o uusnap uusnap.o
+ For this, uusnap.[ch] must be in the same directory as uucp.h and so.
+
+ uusnap must have read access to SPOOLDIR/.Status in order to work.
+*/
+
+#define MAXSYS 30 /* maximum number of systems */
+#define WAIT_NORMAL 10 /* wait period if noone is talking */
+#define WAIT_TALKING 2 /* refresh display every second if */
+ /* someone is talking with us */
+
+#include "uucp.h"
+#if USE_RCS_ID
+char uusnap_rcsid[] = "$Id: uusnap.c,v 1.1 1993/08/04 19:31:43 jtc Exp $";
+#endif
+
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+extern char *ctime(time_t*);
+
+struct sysInfo {
+ char sysname[10]; /* name of the system to watch */
+ char *statfile; /* name of its status file */
+ char *spooldir; /* root of its spooldir */
+ int in; /* number of unprocessed in-files */
+ int out; /* number of files to send them */
+ time_t last; /* last poll time */
+ time_t next; /* time of next poll */
+ time_t lastidir; /* time of last in-spooldir access */
+ time_t lastodir; /* time of last outgoing spd acc */
+ time_t laststat; /* time of last status file access */
+ int status; /* status of the system */
+ int num_retries; /* number of retries */
+};
+
+struct sysInfo Systems[MAXSYS];
+
+
+/* I have extend the system status. If time for the specified system
+ is Never, I say so. To get this to work, one also should extend
+ uucico.c. It is not important to do this. With the normal uucico,
+ one only gets no status.
+*/
+
+const char *azStatus[] = /* Status codes as defined by uucico */
+{ /* listing them here instead of */
+ "Conversation complete", /* including the appropriate file */
+ "Port unavailable", /* reduces the size of the executable */
+ "Dial failed",
+ "Login failed",
+ "Handshake failed",
+ "Call failed",
+ "Talking",
+ "Wrong time to call",
+ "Time to call = Never !"
+};
+
+main()
+{
+ int i;
+ i=get_systems();
+ display_info(i);
+
+ exit(0);
+}
+
+int
+get_systems()
+{
+ char filename[1024];
+ char fn[1024];
+ char line[80];
+ FILE *fp;
+ int i=0;
+ int j;
+ struct stat stbuf;
+ struct sysInfo sys;
+
+ strcpy(filename,NEWCONFIGLIB);
+ strcat(filename,"/uusnap.systems");
+ if ((fp=fopen(filename,"r"))!=NULL) {
+ while (fgets(line,80,fp)!=NULL) {
+ *(rindex(line,'\n'))='\0';
+ strcpy(sys.sysname,line); /* get the name of the system */
+ strcpy(fn,SPOOLDIR); /* get the name of the statusfile */
+ strcat(fn,"/.Status/");
+ strcat(fn,line);
+ sys.statfile=malloc(strlen(fn)+1);
+ strcpy(sys.statfile,fn);
+ strcpy(fn,SPOOLDIR); /* get the name of the spooldir */
+ strcat(fn,"/");
+ strcat(fn,line);
+ sys.spooldir=malloc(strlen(fn)+1);
+ strcpy(sys.spooldir,fn);
+ sys.laststat=0;
+ sys.lastidir=sys.lastodir=0;
+ Systems[i]=sys; /* get_stat_for_system needs it */
+ get_stat_for_system(i); /* now get the system status */
+ get_inq_num(i,TRUE); /* number of unprocessed files */
+ get_outq_num(i,TRUE); /* number of files to send */
+ i++;
+ }
+ fclose(fp);
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ return i;
+}
+
+
+
+display_info(int numSys)
+{
+ char *filename;
+ int sysnum;
+ FILE *fp;
+ char contentline[80];
+ char isTalking=FALSE;
+ struct stat stbuf;
+ struct sysInfo sys;
+ time_t time;
+
+ filename = (char*)malloc(1024);
+ if (filename == NULL) {
+ fprintf(stderr, "Can't malloc 1024 bytes");
+ exit(1);
+ }
+
+ while(TRUE) {
+ display_headline();
+ for (sysnum=0;sysnum<numSys;sysnum++) {
+ sys = Systems[sysnum];
+ stat(sys.statfile,&stbuf);
+ if ((time=stbuf.st_atime) > sys.laststat) {
+ get_stat_for_system(sysnum);
+ }
+ if(display_status_line(sysnum)==1)
+ isTalking=TRUE;
+ }
+ if (isTalking) {
+ sleep(WAIT_TALKING);
+ isTalking = FALSE;
+ }
+ else
+ sleep(WAIT_NORMAL); /* wait a bit */
+ }
+ return 0;
+}
+
+int
+display_status_line(int sn)
+{
+ char *time_s;
+
+ int sys_stat,num_retries,wait;
+ int i;
+ time_t last_time;
+ time_t next_time;
+
+ struct sysInfo sys;
+
+ sys = Systems[sn];
+
+ printf("%10s ",sys.sysname);
+ get_inq_num(sn);
+ if (sys.in==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.in);
+ get_outq_num(sn);
+ if (sys.out==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.out);
+ time_s = ctime(&sys.last);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ printf("%8s ",time_s); /* time of last poll */
+ time_s = ctime(&sys.next);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ if (sys.last == sys.next)
+ printf(" ");
+ else
+ printf("%8s ",time_s); /* time of next poll */
+ if (sys.num_retries==0)
+ printf(" ");
+ else
+ printf("%2d ",sys.num_retries);
+ if (sys_stat==6) /* system is talking */
+ printf("\E[7m"); /* reverse video on */
+ printf("%s",azStatus[sys.status]);
+ if (sys.status==6) {
+ printf("\E[m\n"); /* reverse video off */
+ return 1;
+ }
+ else {
+ printf("\n");
+ return 0;
+ }
+}
+
+
+display_headline()
+{
+ printf("\E[;H\E[2J"); /* clear screen */
+ printf("\E[7muusnap (press CTRL-C to escape)\E[m \n\n");
+ printf(" System #in #out last next #ret Status\n");
+ return 0;
+}
+
+get_inq_num(int num,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[num].spooldir);
+ strcat(filename,"/X./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[num].lastidir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[num].lastidir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[num].in=i;
+ }
+ return 0;
+}
+
+get_outq_num(int sys,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[sys].spooldir);
+ strcat(filename,"/C./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[sys].lastodir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[sys].lastodir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[sys].out=i;
+ }
+ return 0;
+}
+
+get_stat_for_system(int i)
+{
+ char fn[80];
+ struct sysInfo sys;
+ struct stat stbuf;
+ FILE *fp;
+ time_t wait;
+
+ sys = Systems[i];
+ stat(sys.statfile,&stbuf);
+ if (stbuf.st_atime > sys.laststat) {
+ if ((fp=fopen(sys.statfile,"r"))!=NULL) {
+ fgets(fn,80,fp);
+ fclose(fp);
+ sscanf(fn,"%d %d %ld %d",
+ &sys.status,
+ &sys.num_retries,
+ &sys.last,
+ &wait);
+ sys.next=sys.last+wait;
+ }
+ else {
+ sys.status=0;
+ sys.num_retries=0;
+ sys.last=0;
+ sys.next=0;
+ }
+ stat(sys.statfile,&stbuf);
+ sys.laststat=stbuf.st_atime;
+ }
+ Systems[i] = sys;
+ return 0;
+}
diff --git a/gnu/libexec/uucp/contrib/uutraf b/gnu/libexec/uucp/contrib/uutraf
new file mode 100644
index 0000000..8b56d0f
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uutraf
@@ -0,0 +1,203 @@
+#!/usr/local/bin/perl
+# uutraf.pl -- UUCP Traffic Analyzer
+# SCCS Status : @(#)@ uutraf 1.7
+# Author : Johan Vromans
+# Created On : ***
+# Last Modified By: Johan Vromans
+# Last Modified On: Wed Feb 26 08:52:56 1992
+# Update Count : 4
+# Status : OK
+# Requires: : Perl V4 or later
+
+# Reads UUCP syslog, and generates a report from it.
+#
+# Created by Johan Vromans <jv@mh.nl>
+# Loosely based on an idea by Greg Hackney (hack@texbell.swbt.com)
+
+# Usage: uutraf [-taylor|-hdb|-bnu|-bsd] [syslog]
+
+# Logfile formats:
+#
+# BSD:
+#
+# jv mhres (2/23-5:18) (698818735) received 135 b 2 secs
+# root mhres (2/23-5:19) (698818742) sent 2365 b 3 secs, Pk: 38, Rxmt: 0
+#
+# HDB:
+#
+# uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, \
+# 474 bytes/sec
+#
+# Taylor:
+#
+# jv mhres (1992-02-24 20:49:04.06) sent 16234 bytes in 148.780 seconds \
+# (109 bytes/sec)
+# jv mhres (1992-02-24 21:04:05.76) received 449 bytes in 6.550 seconds \
+# (68 bytes/sec)
+
+$uucp_type = "gnu";
+
+%hosts = (); # hosts seen
+%bytes_in = (); # of bytes received from host
+%bytes_out = (); # of bytes sent to host
+%secs_in = (); # of seconds connect for recving
+%secs_out = (); # of seconds connect for sending
+%files_in = (); # of input requests
+%files_out = (); # of output requests
+
+# read info, break the lines and tally
+
+if ( $ARGV[0] =~ /^-/ ) {
+ ($uucp_type = substr (shift (@ARGV), 1)) =~ tr/A-Z/a-z/;
+}
+
+if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) {
+ @ARGV = ("/usr/spool/uucp/Stats") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " .
+ "(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds";
+ $uucp_type = 0;
+ $recv = "received";
+}
+elsif ( $uucp_type eq "hdb" || $uucp_type eq "bnu" ) {
+ @ARGV = ("/usr/spool/uucp/.Admin/xferstats") unless $#ARGV >= 0;
+ $pat = "^([^!]+)![^(]+\\(([-0-9:\\/]+)\\).+([<>])-? " .
+ "(\\d+) \\/ (\\d+)\\.(\\d+) secs";
+ $uucp_type = 1;
+ $recv = "<";
+}
+elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) {
+ @ARGV = ("/usr/spool/uucp/SYSLOG") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/]+)\\) \\([^)]+\\) " .
+ "(sent|received) (\\d+) b (\\d+) secs";
+ $uucp_type = 2;
+ $recv = "received";
+}
+else {
+ die ("Unknown UUCP type: $uucp_type\n");
+}
+
+$garbage = 0;
+
+while ( <> ) {
+ unless ( /$pat/o ) {
+ print STDERR "Possible garbage: $_";
+ if ( $garbage++ > 10 ) {
+ die ("Too much garbage; wrong UUCP type?\n");
+ }
+ next;
+ }
+
+ # gather timestamps
+ $last_date = $2;
+ $first_date = $last_date unless defined $first_date;
+
+ # initialize new hosts
+ unless ( defined $hosts{$1} ) {
+ $hosts{$1} = $files_in{$1} = $files_out{$1} =
+ $bytes_in{$1} = $bytes_out{$1} =
+ $secs_in{$1} = $secs_out{$1} = 0;
+ }
+
+ # Taylor and HDB have milliseconds, BSD has not.
+ $secs = ($uucp_type == 2) ? ($5 + ($5 == 0 ? 0.5 : 0)) : ($5 + $6/1000);
+
+ # tally
+ if ( $3 eq $recv ) { # recv
+ $bytes_in{$1} += $4;
+ $files_in{$1}++;
+ $secs_in{$1} += $secs;
+ }
+ else { # xmit
+ $bytes_out{$1} += $4;
+ $files_out{$1}++;
+ $secs_out{$1} += $secs;
+ }
+ $garbage = 0;
+}
+
+@hosts = keys (%hosts);
+die ("No info found, stopped\n") if $#hosts < 0;
+
+################ report section ################
+
+$thishost = &gethostname();
+$thishost = (defined $thishost) ? "on node $thishost" : "report";
+
+if ( $uucp_type eq 0 ) { # Taylor UUCP
+ substr ($first_date, 16) = "";
+ substr ($last_date, 16) = "";
+}
+
+format std_head =
+@|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+"UUCP traffic $thishost from $first_date to $last_date"
+
+Remote -----------K-Bytes----------- ----Hours---- --Avg CPS-- --Files--
+ Host Recv Sent Total Recv Sent Recv Sent Recv Sent
+.
+format std_out =
+@<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>> @>>>>> @>>>> @>>>> @>>> @>>>
+$Zhost, $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs, $Zi_acps, $Zo_acps, $Zi_count, $Zo_count
+.
+
+$^ = "std_head";
+$~ = "std_out";
+
+&print_dashes ();
+
+reset "T"; # reset totals
+
+foreach $host (@hosts) {
+ &print_line ($host, $bytes_in{$host}, $bytes_out{$host},
+ $secs_in{$host}, $secs_out{$host},
+ $files_in{$host}, $files_out{$host});
+
+}
+
+&print_dashes ();
+&print_line ("Total", $Ti_bytes, $To_bytes,
+ $Ti_secs, $To_secs, $Ti_count, $To_count);
+
+################ that's it ################
+
+sub print_line {
+ reset "Z"; # reset print fields
+ local ($Zhost,
+ $Zi_bytes, $Zo_bytes,
+ $Zi_secs, $Zo_secs,
+ $Zi_count, $Zo_count) = @_;
+ $Ti_bytes += $Zi_bytes;
+ $To_bytes += $Zo_bytes;
+ $Zt_bytes = $Zi_bytes + $Zo_bytes;
+ $Tt_bytes += $Zt_bytes;
+ $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) : "0";
+ $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) : "0";
+ $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000);
+ $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000);
+ $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000);
+ $Zi_hrs = sprintf ("%.1f", $Zi_secs/3600);
+ $Zo_hrs = sprintf ("%.1f", $Zo_secs/3600);
+ $Ti_secs += $Zi_secs;
+ $To_secs += $Zo_secs;
+ $Ti_count += $Zi_count;
+ $To_count += $Zo_count;
+ write;
+}
+
+sub print_dashes {
+ $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes =
+ $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
+ "------------";
+ write;
+ # easy, isn't it?
+}
+
+################ missing ################
+
+sub gethostname {
+ $ENV{"SHELL"} = "/bin/sh";
+ $try = `uuname -l 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ return undef;
+}
diff --git a/gnu/libexec/uucp/contrib/uutry b/gnu/libexec/uucp/contrib/uutry
new file mode 100644
index 0000000..bc0cf29
--- /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 0000000..8810dd7
--- /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 0000000..cfb4d35
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xchat.c
@@ -0,0 +1,1444 @@
+/*
+ * ***********
+ * * XCHAT.C *
+ * ***********
+ *
+ * Extended chat processor for Taylor UUCP. See accompanying documentation.
+ *
+ * Written by:
+ * Bob Denny (denny@alisa.com)
+ * Based on code in DECUS UUCP (for VAX/VMS)
+ *
+ * History:
+ * Version 1.0 shipped with Taylor 1.03. No configuration info inside.
+ *
+ * Bob Denny - Sun Aug 30 18:41:30 1992
+ * V1.1 - long overdue changes for other systems. Rip out interval
+ * timer code, use timer code from Taylor UUCP, use select()
+ * for timed reads. Use Taylor UUCP "conf.h" file to set
+ * configuration for this program. Add defaulting of script
+ * and log file paths.
+ *
+ * Bugs:
+ * Does not support BSD terminal I/O. Anyone care to add it?
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/termio.h>
+
+#include "xc-conf.h"
+
+/*
+ * Pick a timing routine to use, as done in Taylor UUCP.
+ */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#define USE_SELECT_TIMER 0
+#else
+#define USE_SELECT_TIMER HAVE_SELECT
+#if USE_SELECT_TIMER
+#include <sys/time.h>
+#endif
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+static int ttblind();
+static int ttcd();
+
+/* script entry -- "compiled" form of dial, hangup, or login script */
+
+struct script {
+ struct script *next; /* pointer to next entry, or null */
+ int opcode; /* numeric opcode */
+ char *strprm; /* pointer to string param */
+ long intprm; /* integer parameter */
+ char *newstate; /* new state name */
+};
+
+/* opcode definition array element -- one for each possible opcode */
+
+struct script_opdef {
+ char *opname;
+ int opcode; /* numeric opcode -- same as array index */
+ int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */
+ int newstate; /* one of SC_NONE, SC_NWST */
+};
+
+ /* values for opcode */
+
+#define SC_LABEL 0 /* "label" (state name) */
+#define SC_CDLY 1 /* set char output delay in msec */
+#define SC_PCHR 2 /* pause char for dial string (from P in input) */
+#define SC_PTIM 3 /* seconds to allow for pause char */
+#define SC_WCHR 4 /* wait char for dial string (from W in input) */
+#define SC_WTIM 5 /* seconds to allow for wait char */
+#define SC_ZERO 6 /* zero counter */
+#define SC_INCR 7 /* increment counter */
+#define SC_IFGT 8 /* change state if counter > int param */
+#define SC_WAIT 9 /* wait for int param seconds */
+#define SC_GOTO 10 /* unconditional change to new state */
+#define SC_SEND 11 /* send strparam (after sprintf substitutions) */
+#define SC_BRK 12 /* send a break */
+#define SC_HANG 13 /* drop DTR */
+#define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */
+#define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */
+ /* default = 100 (one tenth second) */
+#define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */
+ /* default = 45 seconds */
+#define SC_EXIT 17 /* script done, success */
+#define SC_FAIL 18 /* script done, failure */
+#define SC_LOG 19 /* write strparam to uucp.log */
+#define SC_LOGE 20 /* write strparam to uucp.log w/error ind */
+#define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */
+#define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */
+#define SC_DBST 23 /* 'or' intparam into debug mask */
+#define SC_DBCL 24 /* 'bicl' intparam into debug mask */
+#define SC_TIMO 25 /* newstate if no match in intparam secs */
+ /* (uses calculated dial time if intparam is 0) */
+#define SC_XPCT 26 /* wait for strparam, goto _newstate if found */
+#define SC_CARR 27 /* goto _newstate if carrier detected */
+#define SC_FLSH 28 /* flush typeahead buffer */
+#define SC_IFBL 29 /* change state if controller is blind w/o CD */
+#define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */
+#define SC_SNDP 31 /* send parameter n */
+#define SC_IF1P 32 /* if parameter n present */
+#define SC_IF0P 33 /* if parameter n absent */
+#define SC_DBOF 34 /* open debugging file */
+#define SC_TELN 35 /* Set telno from parameter n */
+#define SC_7BIT 36 /* Set port to 7-bit stripping */
+#define SC_8BIT 37 /* Set port for 8-bit characters */
+#define SC_PNON 38 /* Set port for 8-bit, no parity */
+#define SC_PEVN 39 /* Set port for 7-bit, even parity */
+#define SC_PODD 40 /* Set port for 7-bit, odd parity */
+#define SC_HUPS 41 /* Change state on HUP signal */
+#define SC_END 42 /* end of array */
+
+ /* values for prmtype, prm2type */
+
+#define SC_NONE 0 /* no parameter */
+#define SC_STR 1 /* simple string */
+#define SC_INT 2 /* integer */
+#define SC_NWST 3 /* new state name */
+#define SC_XSTR 4 /* translated string */
+
+/* opcode definition table for dial/login/hangup scripts */
+
+static struct script_opdef sc_opdef[] =
+ {
+ {"label", SC_LABEL, SC_NONE, SC_NONE},
+ {"chrdly", SC_CDLY, SC_INT, SC_NONE},
+ {"pchar", SC_PCHR, SC_STR, SC_NONE},
+ {"ptime", SC_PTIM, SC_INT, SC_NONE},
+ {"wchar", SC_WCHR, SC_STR, SC_NONE},
+ {"wtime", SC_WTIM, SC_INT, SC_NONE},
+ {"zero", SC_ZERO, SC_NONE, SC_NONE},
+ {"count", SC_INCR, SC_NONE, SC_NONE},
+ {"ifgtr", SC_IFGT, SC_INT, SC_NWST},
+ {"sleep", SC_WAIT, SC_INT, SC_NONE},
+ {"goto", SC_GOTO, SC_NONE, SC_NWST},
+ {"send", SC_SEND, SC_XSTR, SC_NONE},
+ {"break", SC_BRK, SC_NONE, SC_NONE},
+ {"hangup", SC_HANG, SC_NONE, SC_NONE},
+ {"7bit", SC_7BIT, SC_NONE, SC_NONE},
+ {"8bit", SC_8BIT, SC_NONE, SC_NONE},
+ {"nopar", SC_PNON, SC_NONE, SC_NONE},
+ {"evenpar", SC_PEVN, SC_NONE, SC_NONE},
+ {"oddpar", SC_PODD, SC_NONE, SC_NONE},
+ {"telno", SC_TELN, SC_INT, SC_NONE},
+ {"dial", SC_DIAL, SC_NONE, SC_NONE},
+ {"dgttime", SC_DTIM, SC_INT, SC_NONE},
+ {"ctime", SC_CTIM, SC_INT, SC_NONE},
+ {"success", SC_EXIT, SC_NONE, SC_NONE},
+ {"failed", SC_FAIL, SC_NONE, SC_NONE},
+ {"log", SC_LOG, SC_XSTR, SC_NONE},
+ {"logerr", SC_LOGE, SC_XSTR, SC_NONE},
+ {"debug", SC_DBG, SC_XSTR, SC_NONE},
+ {"debuge", SC_DBGE, SC_XSTR, SC_NONE},
+ {"dbgset", SC_DBST, SC_INT, SC_NONE},
+ {"dbgclr", SC_DBCL, SC_INT, SC_NONE},
+ {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE},
+ {"timeout", SC_TIMO, SC_INT, SC_NWST},
+ {"expect", SC_XPCT, SC_XSTR, SC_NWST},
+ {"ifcarr", SC_CARR, SC_NONE, SC_NWST},
+ {"ifhang", SC_HUPS, SC_NONE, SC_NWST},
+ {"flush", SC_FLSH, SC_NONE, SC_NONE},
+ {"ifblind", SC_IFBL, SC_NONE, SC_NWST},
+ {"ifblgtr", SC_IFBG, SC_INT, SC_NWST},
+ {"sendstr", SC_SNDP, SC_INT, SC_NONE},
+ {"ifstr", SC_IF1P, SC_INT, SC_NWST},
+ {"ifnstr", SC_IF0P, SC_INT, SC_NWST},
+ {"table end", SC_END, SC_NONE, SC_NONE}
+ };
+
+#define SUCCESS 0
+#define FAIL 1
+#define ERROR -1
+#define MAX_SCLINE 255 /* max length of a line in a script file */
+#define MAX_EXPCT 127 /* max length of an expect string */
+#define CTL_DELIM " \t\n\r" /* Delimiters for tokens */
+#define SAME 0 /* if (strcmp(a,b) == SAME) ... */
+#define SLOP 10 /* Slop space on arrays */
+#define MAX_STRING 200 /* Max length string to send/expect */
+
+#define DEBUG_LEVEL(level) \
+ (Debug & (1 << level))
+
+#define DB_LOG 0 /* error messages and a copy of the LOGFILE output */
+#define DB_LGIE 1 /* dial,login,init trace -- errors only */
+#define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */
+#define DB_LGII 3 /* script processing internals */
+
+#define TRUE 1
+#define FALSE 0
+
+#define NONE 0
+#define EVEN 1
+#define ODD 2
+
+#define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1)
+
+static char **paramv; /* Parameter vector */
+static int paramc; /* Parameter count */
+static char telno[64]; /* Telephone number w/meta-chars */
+static int Debug;
+static int fShangup = FALSE; /* TRUE if HUP signal received */
+static FILE *dbf = NULL;
+static struct termio old, new;
+
+extern int usignal();
+extern int uhup();
+
+static struct siglist
+{
+ int signal;
+ int (*o_catcher) ();
+ int (*n_catcher) ();
+} sigtbl[] = {
+ { SIGHUP, NULL, uhup },
+ { SIGINT, NULL, usignal },
+ { SIGIOT, NULL, usignal },
+ { SIGQUIT, NULL, usignal },
+ { SIGTERM, NULL, usignal },
+ { SIGALRM, NULL, usignal },
+ { 0, NULL, NULL } /* Table end */
+ };
+
+extern struct script *read_script();
+extern void msleep();
+extern char xgetc();
+extern void charlog();
+extern void setup_tty();
+extern void restore_tty();
+extern void ttoslow();
+extern void ttflui();
+extern void tthang();
+extern void ttbreak();
+extern void tt7bit();
+extern void ttpar();
+extern void DEBUG();
+
+extern void *malloc();
+
+
+/*
+ * **********************************
+ * * BEGIN EXECUTION - MAIN PROGRAM *
+ * **********************************
+ *
+ * This program is called by Taylor UUCP with a list of
+ * arguments in argc/argv, and stdin/stdout mapped to the
+ * tty device, and stderr mapped to the Taylor logfile, where
+ * anything written to stdout will be logged as an error.
+ *
+ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, stat;
+ FILE *sf;
+ char sfname[256];
+ struct script *script;
+ struct siglist *sigs;
+
+ /*
+ * The following is needed because my cpp does not have the
+ * #error directive...
+ */
+#if ! HAVE_SELECT
+ no_select_sorry(); /* Sad way to fail make */
+#endif
+
+ paramv = &argv[2]; /* Parameters start at 2nd arg */
+ paramc = argc - 2; /* Number of live parameters */
+
+ telno[0] = '\0';
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "%s: no script file supplied\n", argv[0]);
+ exit(FAIL);
+ }
+
+ /*
+ * If the script file argument begins with '/', then we assume
+ * it is an absolute pathname, otherwise, we prepend the
+ * SCRIPT_DIR path.
+ */
+ *sfname = '\0'; /* Empty name string */
+ if(argv[1][0] != '/') /* If relative path */
+ strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */
+ strcat(sfname, argv[1]); /* Add the script file name */
+
+ /*
+ * Now open the script file.
+ */
+ if ((sf = fopen(sfname, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname);
+ perror(" ");
+ exit(FAIL);
+ }
+
+ /*
+ * COMPILE SCRIPT
+ */
+ if ((script = read_script(sf)) == NULL)
+ {
+ fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]);
+ exit(FAIL);
+ }
+
+ /*
+ * Set up a signal catcher so the line can be returned to
+ * it's current state if something nasty happens.
+ */
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ {
+ sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher);
+ sigs += 1;
+ }
+
+ /*
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+ setup_tty();
+
+ /*
+ * EXECUTE SCRIPT
+ */
+ if ((stat = do_script(script)) != SUCCESS)
+ fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]);
+
+ /*
+ * Clean up and exit.
+ */
+ restore_tty();
+#ifdef FIXSIGS
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ if(sigs->o_catcher != -1)
+ signal(sigs->signal, sigs->o_catcher);
+#endif
+ exit(stat);
+}
+
+/*
+ * deal_script - deallocate a script and all strings it points to
+ */
+int deal_script(loc)
+struct script *loc;
+{
+ /*
+ * If pointer is null, just exit
+ */
+ if (loc == (struct script *)NULL)
+ return SUCCESS;
+
+ /*
+ * Deallocate the rest of the script
+ */
+ deal_script(loc->next);
+
+ /*
+ * Deallocate the string parameter, if any
+ */
+ if (loc->strprm != (char *)NULL)
+ free(loc->strprm);
+
+ /*
+ * Deallocate the new state name parameter, if any
+ */
+ if (loc->newstate != (char *)NULL)
+ free(loc->newstate);
+
+ /*
+ * Deallocate this entry
+ */
+ free(loc);
+
+ return SUCCESS;
+}
+
+
+/*
+ * read_script
+ *
+ * Read & compile a script, return pointer to first entry, or null if bad
+ */
+struct script *read_script(fd)
+ FILE *fd;
+{
+ struct script *this = NULL;
+ struct script *prev = NULL;
+ struct script *first = NULL;
+ long len, i;
+ char inpline[MAX_SCLINE];
+ char inpcopy[MAX_SCLINE];
+ char *c, *cln, *opc, *cp;
+
+ /*
+ * MAIN COMPILATION LOOP
+ */
+ while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL)
+ {
+ /*
+ * Skip comments and blank lines
+ */
+ if (*c == '#' || *c == '\n')
+ continue;
+
+ /*
+ * Get rid of the trailing newline, and copy the string
+ */
+ inpline[strlen(inpline)-1] = '\0';
+ strcpy(inpcopy, inpline);
+
+ /*
+ * Look for text starting in the first col (a label)
+ */
+ if ((!isspace(inpline[0])) &&
+ (cln = strchr (inpline, ':')) != (char *)NULL) {
+ this = (struct script *)malloc (sizeof (struct script));
+ if (prev != (struct script *)NULL)
+ prev->next = this;
+ prev = this;
+ if (first == (struct script *)NULL)
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ len = cln - c;
+ this->strprm = (char *)malloc(len+1);
+ strncpy(this->strprm, c, len);
+ (this->strprm)[len] = '\0';
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ c = cln + 1;
+ }
+
+ /*
+ * Now handle the opcode. Fold it to lower case.
+ */
+ opc = strtok(c, CTL_DELIM);
+ if (opc == (char *)NULL) /* If no opcode... */
+ continue; /* ...read the next line */
+ cp = opc;
+ while(*cp)
+ tolower(*cp++);
+
+ /*
+ * If we have an opcode but we haven't seen anything
+ * else (like a label) yet, i.e., this is the first
+ * entry, and there was no label. We need to
+ * cobble up a label so that read_script is happy
+ */
+ if (first == (struct script *)NULL)
+ {
+ this = (struct script *)malloc (sizeof (struct script));
+ prev = this;
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ this->strprm = (char *)malloc(2);
+ strcpy(this->strprm, ":");
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ }
+
+ /*
+ * Find opcode - ndex through the opcode definition table
+ */
+ for (i=1; sc_opdef[i].opcode != SC_END; i++)
+ if (strcmp(opc, sc_opdef[i].opname) == SAME)
+ break;
+ if ((sc_opdef[i].opcode) == SC_END)
+ {
+ logit ("Bad opcode in script", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+
+ /*
+ * Found opcode. Allocate a new command node and initialize
+ */
+ this = (struct script *)malloc(sizeof (struct script));
+ prev->next = this;
+ prev = this;
+ this->next = (struct script *)NULL;
+ this->opcode = sc_opdef[i].opcode;
+ this->strprm = (char *)NULL;
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+
+ /*
+ * Pick up new state parameter, if any
+ */
+ if (sc_opdef[i].newstate == SC_NWST)
+ {
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing new state", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ else
+ {
+ this->newstate = (char *)malloc(strlen(c)+1);
+ strcpy(this->newstate, c);
+ }
+ }
+
+ /*
+ * Pick up the string or integer parameter. Handle missing
+ * parameter gracefully.
+ */
+ switch (sc_opdef[i].prmtype)
+ {
+ /*
+ * INT parameter - convert and store in node
+ */
+ case SC_INT:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * If this is the parameter to DBST or DBCL, force
+ * base-10 conversion, else convert per parameter.
+ */
+ if (sc_opdef[i].opcode == SC_DBST ||
+ sc_opdef[i].opcode == SC_DBCL)
+ this->intprm = strtol(c, (char **)NULL, 0);
+ else
+ this->intprm = strtol(c, (char **)NULL, 10);
+ break;
+
+ /*
+ * STR/XSTR strings.
+ */
+ case SC_STR:
+ case SC_XSTR:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * For XSTR opcode, use c to find out where
+ * the string param begins in the copy of the
+ * input line, and pick up all that's left of
+ * the line (to allow imbedded blanks, etc.).
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ c = &inpcopy[0] + (c - &inpline[0]);
+
+ /*
+ * Allocate a buffer for the string parameter
+ */
+ this->strprm = (char *)malloc(strlen(c)+1);
+
+ /*
+ * For XSTR, Translate the string and store its
+ * length. Note that, after escape sequences are
+ * compressed, the resulting string may well be a
+ * few bytes shorter than the input string (whose
+ * length was the basis for the malloc above),
+ * but it will never be longer.
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ {
+ this->intprm = xlat_str(this->strprm, c);
+ this->strprm[this->intprm] = '\0';
+ }
+ else
+ strcpy(this->strprm, c);
+ break;
+
+ }
+ }
+
+ /*
+ * EOF
+ */
+ return first;
+}
+
+
+/*
+ * xlat_str
+ *
+ * Translate embedded escape characters in a "send" or "expect" string.
+ *
+ * Called by read_script(), above.
+ *
+ * Returns the actual length of the resulting string. Note that imbedded
+ * nulls (specified by \000 in the input) ARE allowed in the result.
+ */
+xlat_str(out, in)
+ char *out, *in;
+{
+ register int i = 0, j = 0;
+ int byte, k;
+
+ while (in[i])
+ {
+ if (in[i] != '\\')
+ {
+ out[j++] = in[i++];
+ }
+ else
+ {
+ switch (in[++i])
+ {
+ case 'd': /* EOT */
+ out[j++] = 0x04;
+ break;
+ case 'N': /* null */
+ out[j++] = 0x00;
+ break;
+ case 'n': /* line feed */
+ out[j++] = 0x0a;
+ break;
+ case 'r': /* carriage return */
+ out[j++] = 0x0d;
+ break;
+ case 's': /* space */
+ out[j++] = ' ';
+ break;
+ case 't': /* tab */
+ out[j++] = '\t';
+ break;
+ case '-': /* hyphen */
+ out[j++] = '-';
+ break;
+ case '\\': /* back slash */
+ out[j++] = '\\';
+ break;
+ case '0': /* '\nnn' format */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ byte = in[i] - '0';
+ k = 0;
+
+ while (3 > ++k)
+ if ((in[i+1] < '0') || (in[i+1] > '7'))
+ break;
+ else
+ {
+ byte = (byte<<3) + in[i+1] - '0';
+ ++i;
+ }
+ out[j++] = byte;
+ break;
+ default: /* don't know so skip it */
+ break;
+ }
+ ++i;
+ }
+ }
+ return j;
+}
+
+
+/* find a state within a script */
+
+struct script *
+ find_state(begin, newstate)
+struct script *begin;
+char *newstate;
+{
+ struct script *here;
+
+ for (here=begin; here != (struct script *)NULL; here=here->next) {
+ if (here->opcode == SC_LABEL &&
+ strcmp(here->strprm, newstate) == SAME)
+ return here;
+ }
+ return (struct script *)NULL;
+}
+
+
+/*
+ * do_script() - execute a script
+ */
+int do_script(begin)
+ struct script *begin;
+{
+ struct script *curstate, *newstate, *curscr;
+ int dbgsave;
+ char tempstr[MAX_SCLINE];
+ char dfname[256];
+ char *c, chr;
+ int prmlen;
+ int dbfd;
+
+ time_t sc_carrtime = 45000; /* time to wf carr after dial */
+ time_t sc_chrdly = 100; /* delay time for ttoslow */
+ time_t sc_ptime = 2000; /* time to allow for pause char */
+ time_t sc_wtime = 10000; /* time to allow for wait char */
+ time_t sc_dtime = 100; /* time to allow for each digit */
+ time_t sc_dtmo; /* total time to dial number */
+ int sc_counter; /* random counter */
+ char sc_pchar = ','; /* modem pause character */
+ char sc_wchar = 'W'; /* modem wait-for-dialtone character */
+ time_t sc_begwait; /* time at beg of wait */
+ time_t sc_secs; /* timeout period */
+
+ int expcnt;
+ int expin;
+ static char expbuf[MAX_EXPCT];
+
+ dbgsave = Debug;
+ curstate = begin;
+
+ if (curstate == (struct script *)NULL)
+ return SUCCESS;
+
+ _newstate:
+ /*
+ * do all of curstate's actions. Enter with curstate pointing
+ * to a label entry
+ */
+ expin = 0;
+
+ for (curscr = curstate->next; /* point to 1st scr after label */
+ (curscr != (struct script *)NULL) && /* do until end of scr */
+ (curscr->opcode != SC_LABEL); /* or next label */
+ curscr = curscr->next)
+ {
+ expcnt = 0;
+ switch (curscr->opcode)
+ {
+ case SC_LABEL:
+ logit("Script proc err", curstate->strprm);
+ return FAIL;
+
+ case SC_FLSH:
+ DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0);
+ ttflui();
+ break;
+
+ case SC_CDLY:
+ sc_chrdly = curscr->intprm;
+ DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly);
+ break;
+
+ case SC_PCHR:
+ sc_pchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar);
+ break;
+
+ case SC_PTIM:
+ sc_ptime = curscr->intprm;
+ DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime);
+ break;
+
+ case SC_WCHR:
+ sc_wchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar);
+ break;
+
+ case SC_WTIM:
+ sc_wtime = curscr->intprm;
+ DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime);
+ break;
+
+ case SC_ZERO:
+ sc_counter = 0;
+ DEBUG(DB_LGII, "Set counter to %d\n", sc_counter);
+ break;
+
+ case SC_INCR:
+ sc_counter++;
+ DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter);
+ break;
+
+ case SC_WAIT:
+ DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm);
+ msleep(curscr->intprm);
+ break;
+
+ case SC_DTIM:
+ sc_dtime = curscr->intprm;
+ DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime);
+ break;
+
+ case SC_CTIM:
+ sc_carrtime = curscr->intprm;
+ DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime);
+ break;
+
+ case SC_EXIT:
+ Debug = dbgsave;
+ DEBUG(DB_LGI, "Script ended successfully\n", 0);
+ return SUCCESS;
+
+ case SC_FAIL:
+ Debug = dbgsave;
+ if (DEBUG_LEVEL(DB_LGI) && dbf != NULL)
+ fprintf(dbf, "Script failed\n");
+ else if (expin)
+ charlog(expbuf, expin, DB_LOG,
+ "Script failed. Last received data");
+ return FAIL;
+
+ case SC_LOG:
+ logit(curscr->strprm, "");
+ break;
+
+ case SC_LOGE:
+ logit("ERROR: ", curscr->strprm);
+ break;
+
+ case SC_DBOF:
+ /*
+ * If the debug file name does not begin with "/", then
+ * we prepend the LOG_DIR to the string. Then CREATE the
+ * file. This WIPES OUT previous logs.
+ */
+ *dfname = '\0'; /* Zero name string */
+ if(curscr->strprm[0] != '/')
+ strcat(dfname, LOG_DIR); /* Prepend default directory */
+ strcat(dfname, curscr->strprm); /* Add given string */
+ DEBUG(DB_LGII, "Open debug file %s\n", dfname);
+ if ((dbfd = creat (dfname, 0600)) <= 0)
+ {
+ logit("Failed to create debug log %s", dfname);
+ perror("");
+ return FAIL;
+ }
+ if ((dbf = fdopen(dbfd, "w")) == NULL)
+ {
+ logit("Failed to open debug log fildes.", "");
+ perror("");
+ return FAIL;
+ }
+ break;
+
+ case SC_DBG:
+ DEBUG(DB_LGI, "<%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBGE:
+ DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBST:
+ Debug |= curscr->intprm;
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_DBCL:
+ Debug &= ~(curscr->intprm);
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_BRK:
+ DEBUG(DB_LGI, "Sending break\n", 0);
+ ttbreak();
+ break;
+
+ case SC_HANG:
+ DEBUG(DB_LGI, "Dropping DTR\n", 0);
+ tthang();
+ break;
+
+ case SC_7BIT:
+ DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0);
+ tt7bit(TRUE);
+ break;
+
+ case SC_8BIT:
+ DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0);
+ tt7bit(FALSE);
+ break;
+
+ case SC_PNON:
+ DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0);
+ ttpar(NONE);
+ break;
+
+ case SC_PEVN:
+ DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0);
+ ttpar(EVEN);
+ break;
+
+ case SC_PODD:
+ DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0);
+ ttpar(ODD);
+ break;
+
+ case SC_IFBL:
+ if (ttblind())
+ {
+ DEBUG(DB_LGI, "Blind mux,\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFBG:
+ if (ttblind() && sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Blind mux & ctr > %d\n",
+ curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFGT:
+ if (sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_GOTO:
+ _chgstate:
+ DEBUG(DB_LGI, "Changing to state %s\n",
+ curscr->newstate);
+ curstate = find_state(begin, curscr->newstate);
+ if (curstate == NULL)
+ {
+ logit("New state not found",
+ curscr->newstate);
+ return FAIL;
+ }
+ goto _newstate;
+
+ case SC_SEND:
+ ttoslow(curscr->strprm, curscr->intprm, sc_chrdly);
+ break;
+
+ case SC_TELN:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "telno - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ strcpy(telno, paramv[curscr->intprm]);
+ DEBUG(DB_LGII, "telno set to %s\n", telno);
+ break;
+
+ case SC_SNDP:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "sendstr - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ prmlen = xlat_str(tempstr, paramv[curscr->intprm]);
+ ttoslow(tempstr, prmlen, sc_chrdly);
+ break;
+
+ case SC_IF1P:
+ if (curscr->intprm < paramc)
+ goto _chgstate;
+ break;
+
+ case SC_IF0P:
+ if (curscr->intprm >= paramc)
+ goto _chgstate;
+ break;
+
+ case SC_DIAL:
+ if(telno[0] == '\0')
+ {
+ logit("telno not set", "");
+ return(FAIL);
+ }
+ /*
+ * Compute and set a default timeout for the 'timeout'
+ * command. Some parameters in this computation may be
+ * changed by the script. See the man page xchat(8) for
+ * details.
+ */
+ sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno)
+ + sc_carrtime;
+ c=strcpy(tempstr, telno);
+ for (; *c!='\0'; c++)
+ {
+ if (*c == 'W')
+ {
+ *c = sc_wchar;
+ sc_dtmo += sc_wtime;
+ }
+ else if (*c == 'P')
+ {
+ *c = sc_pchar;
+ sc_dtmo += sc_ptime;
+ }
+ }
+ DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo);
+ ttoslow(tempstr, 0, sc_chrdly);
+ break;
+
+ case SC_TIMO: /* these are "expects", don't bother */
+ case SC_XPCT: /* with them yet, other than noting that */
+ case SC_CARR: /* they exist */
+ expcnt++;
+ break;
+ }
+
+ }
+
+ /* we've done the current state's actions, now do its expects, if any */
+
+ if (expcnt == 0)
+ {
+ if (curscr != (struct script *)NULL &&
+ (curscr->opcode == SC_LABEL))
+ {
+ curstate = curscr;
+ DEBUG(DB_LGI, "Fell through to state %s\n",
+ curstate->strprm);
+ goto _newstate;
+ }
+ else
+ {
+ logit("No way out of state", curstate->strprm);
+ return FAIL;
+ }
+ }
+
+ time(&sc_begwait); /* log time at beg of expect */
+ DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm);
+ charlog((char *)NULL, 0, DB_LGI, "Received");
+
+ while (1)
+ {
+ chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */
+
+ charlog(&chr, 1, DB_LGI, (char *)NULL);
+
+ if (chr != EOF)
+ {
+ if (expin < MAX_EXPCT)
+ {
+ expbuf[expin++] = chr & 0x7f;
+ }
+ else
+ {
+ strncpy(expbuf, &expbuf[1], MAX_EXPCT-1);
+ expbuf[MAX_EXPCT-1] = chr & 0x7f;
+ }
+ }
+
+ /* for each entry in the current state... */
+
+ for (curscr = curstate->next;
+ (curscr != (struct script *)NULL) &&
+ (curscr->opcode != SC_LABEL);
+ curscr = curscr->next)
+ {
+
+ switch (curscr->opcode)
+ {
+ case SC_TIMO:
+ sc_secs = curscr->intprm;
+ if (sc_secs == 0)
+ sc_secs = sc_dtmo;
+ sc_secs /= 1000;
+ if (time(NULL)-sc_begwait > sc_secs)
+ {
+ DEBUG(DB_LGI,
+ "\nTimed out (%d secs)\n", sc_secs);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_CARR:
+ if (ttcd())
+ {
+ DEBUG(DB_LGI, "\nGot carrier\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_HUPS:
+ if (fShangup)
+ {
+ DEBUG(DB_LGI, "\nGot data set hangup\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_XPCT:
+ if ((expin >= curscr->intprm) &&
+ (strncmp(curscr->strprm,
+ &expbuf[expin - curscr->intprm],
+ curscr->intprm) == SAME))
+ {
+ charlog(curscr->strprm, curscr->intprm,
+ DB_LGI, "Matched");
+ goto _chgstate;
+ }
+ break;
+
+ }
+ }
+ }
+}
+
+/*
+ * SIGNAL HANDLERS
+ */
+
+/*
+ * usignal - generic signal catcher
+ */
+static int usignal(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig);
+ restore_tty();
+ exit(FAIL);
+}
+
+/*
+ * uhup - HUP catcher
+ */
+static int uhup(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Data set hangup.\n");
+ fShangup = TRUE;
+}
+
+/*
+ * TERMINAL I/O ROUTINES
+ */
+
+/*
+ * xgetc - get a character with timeout
+ *
+ * Assumes that stdin is opened on a terminal or TCP socket
+ * with O_NONBLOCK.
+ */
+static char xgetc(tmo)
+int tmo; /* Timeout, seconds */
+{
+ char c;
+ struct timeval s;
+ int f = 1; /* Select on stdin */
+ int result;
+
+ if(read(0, &c, 1) <= 0) /* If no data available */
+ {
+ s.tv_sec = (long)tmo;
+ s.tv_usec = 0L;
+ if(select (1, &f, (int *) NULL, &f, &s) == 1)
+ read(0, &c, 1);
+ else
+ c = '\377';
+ }
+
+ return(c);
+}
+
+/*
+ * Pause for an interval in milliseconds
+ */
+void msleep(msec)
+long msec;
+{
+
+#if HAVE_USLEEP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ usleep (msec * (long)1000);
+#endif /* HAVE_USLEEP */
+
+#if HAVE_NAPMS
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ napms (msec);
+#endif /* HAVE_NAPMS */
+
+#if HAVE_NAP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ nap (msec);
+#endif /* HAVE_NAP */
+
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ if(msec == 0)
+ return;
+ /*
+ * We need to pass an unused pollfd structure because poll checks
+ * the address before checking the number of elements.
+ */
+ poll (&sdummy, 0, msec);
+#endif /* HAVE_POLL */
+
+#if USE_SELECT_TIMER
+ struct timeval s;
+
+ if(msec == 0)
+ return;
+ s.tv_sec = msec / 1000L;
+ s.tv_usec = (msec % 1000L) * 1000L;
+ select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \
+ ! HAVE_POLL && ! USE_SELECT_TIMER
+ if(msec == 0)
+ return;
+ sleep (1); /* Sleep for a whole second (UGH!) */
+#endif /* HAVE_ and USE_ nothing */
+}
+
+/*
+ * Debugging output
+ */
+static void DEBUG(level, msg1, msg2)
+int level;
+char *msg1, *msg2;
+{
+ if ((dbf != NULL) && DEBUG_LEVEL(level))
+ fprintf(dbf, msg1, msg2);
+}
+
+/*
+ * charlog - log a string of characters
+ *
+ * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged
+ * when read does its 1 sec. timeout. Log "<1 sec.>"
+ * so user can see elapsed time
+ */
+static void charlog(buf, len, mask, msg)
+char *buf;
+int len, mask;
+char *msg;
+{
+ char tbuf[256];
+
+ if (DEBUG_LEVEL(mask) && dbf != NULL)
+ {
+ if(msg == (char *)NULL)
+ msg = "";
+ strncpy(tbuf, buf, len);
+ tbuf[len] = '\0';
+ if(len == 1 && tbuf[0] == '\377')
+ strcpy(tbuf, "<1 sec.>");
+ fprintf(dbf, "%s %s\n", msg, tbuf);
+ }
+}
+
+/*
+ * setup_tty()
+ *
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+static void setup_tty()
+{
+ register int i;
+
+ ioctl(0, TCGETA, &old);
+
+ new = old;
+
+ for(i = 0; i < 7; i++)
+ new.c_cc[i] = '\0';
+ new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */
+ new.c_cc[VTIME] = 10; /* TIME = 1 sec. */
+ new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */
+ new.c_lflag = 0; /* No special line discipline */
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * restore_tty() - restore signal handlers and tty modes on exit.
+ */
+static void restore_tty(sig)
+int sig;
+{
+ ioctl(0, TCSETA, &old);
+ return;
+}
+
+/*
+ * ttoslow() - Send characters with pacing delays
+ */
+static void ttoslow(s, len, delay)
+ char *s;
+ int len;
+ time_t delay;
+{
+ int i;
+
+ if (len == 0)
+ len = strlen(s);
+
+ charlog (s, len, DB_LGI, "Sending slowly");
+
+ for (i = 0; i < len; i++, s++)
+ {
+ write(1, s, 1);
+ msleep(delay);
+ }
+}
+
+/*
+ * ttflui - flush input buffer
+ */
+static void ttflui()
+{
+ if(isatty(0))
+ (void) ioctl ( 0, TCFLSH, 0);
+}
+
+/*
+ * ttcd - Test if carrier is present
+ *
+ * NOT IMPLEMENTED. I don't know how!!!
+ */
+static int ttcd()
+{
+ return TRUE;
+}
+
+/*
+ * tthang - Force DTR low for 1-2 sec.
+ */
+static void tthang()
+{
+ if(!isatty())
+ return;
+
+#ifdef TCCLRDTR
+ (void) ioctl (1, TCCLRDTR, 0);
+ sleep (2);
+ (void) ioctl (1, TCSETDTR, 0);
+#endif
+
+ return;
+}
+
+/*
+ * ttbreak - Send a "break" on the line
+ */
+static void ttbreak()
+{
+ (void) ioctl (1, TCSBRK, 0);
+}
+
+/*
+ * ttblind - return TRUE if tty is "blind"
+ *
+ * NOT IMPLEMENTED - Don't know how!!!
+ */
+static int ttblind()
+{
+ return FALSE;
+}
+
+/*
+ * tt7bit - enable/disable 7-bit stripping on line
+ */
+static void tt7bit(enable)
+ int enable;
+{
+ if(enable)
+ new.c_iflag |= ISTRIP;
+ else
+ new.c_iflag &= ~ISTRIP;
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * ttpar - Set parity mode on line. Ignore parity errors on input.
+ */
+static void ttpar(mode)
+ int mode;
+{
+ switch(mode)
+ {
+ case NONE:
+ new.c_iflag &= ~(INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARENB | PARODD);
+ new.c_cflag |= CS8;
+ break;
+
+ case EVEN:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARODD);
+ new.c_cflag |= (CS7 | PARENB);
+
+ break;
+
+ case ODD:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE);
+ new.c_cflag |= (CS7 | PARENB | PARODD);
+ break;
+ }
+
+ ioctl(0, TCSETA, &new);
+}
+
+
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/xchat.man b/gnu/libexec/uucp/contrib/xchat.man
new file mode 100644
index 0000000..c980e20
--- /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 0000000..5b1ba03d
--- /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 <bsd.prog.mk>
+.PATH: $(.CURDIR)/../common_sources
diff --git a/gnu/libexec/uucp/cu/cu.1 b/gnu/libexec/uucp/cu/cu.1
new file mode 100644
index 0000000..56409a0
--- /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 0000000..72d60a6
--- /dev/null
+++ b/gnu/libexec/uucp/cu/cu.c
@@ -0,0 +1,2068 @@
+/* cu.c
+ Call up a remote system.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cu_rcsid[] = "$Id: cu.c,v 1.1 1993/08/04 19:31:54 jtc Exp $";
+#endif
+
+#include "cu.h"
+#include "uudefs.h"
+#include "uuconf.h"
+#include "conn.h"
+#include "prot.h"
+#include "system.h"
+#include "sysdep.h"
+#include "getopt.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* Here are the user settable variables. The user is permitted to
+ change these while running the program, using ~s. */
+
+/* The escape character used to introduce a special command. The
+ escape character is the first character of this string. */
+const char *zCuvar_escape = "~";
+
+/* Whether to delay for a second before printing the host name after
+ seeing an escape character. */
+boolean fCuvar_delay = TRUE;
+
+/* The input characters which finish a line. The escape character is
+ only recognized following one of these characters. The default is
+ carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the
+ Ultrix /etc/remote file. */
+const char *zCuvar_eol = "\r\025\003\017\004\023\021\022";
+
+/* Whether to transfer binary data (nonprintable characters other than
+ newline and tab) when sending a file. If this is FALSE, then
+ newline is changed to carriage return. */
+boolean fCuvar_binary = FALSE;
+
+/* A prefix string to use before sending a binary character from a
+ file; this is only used if fCuvar_binary is TRUE. The default is
+ ^Z. */
+const char *zCuvar_binary_prefix = "\026";
+
+/* Whether to check for echoes of characters sent when sending a file.
+ This is ignored if fCuvar_binary is TRUE. */
+boolean fCuvar_echocheck = FALSE;
+
+/* A character to look for after each newline is sent when sending a
+ file. The character is the first character in this string, except
+ that a '\0' means that no echo check is done. */
+const char *zCuvar_echonl = "\r";
+
+/* The timeout to use when looking for an character. */
+int cCuvar_timeout = 30;
+
+/* The character to use to kill a line if an echo check fails. The
+ first character in this string is sent. The default is ^U. */
+const char *zCuvar_kill = "\025";
+
+/* The number of times to try resending a line if the echo check keeps
+ failing. */
+int cCuvar_resend = 10;
+
+/* The string to send at the end of a file sent with ~>. The default
+ is ^D. */
+const char *zCuvar_eofwrite = "\004";
+
+/* The string to look for to finish a file received with ~<. For tip
+ this is a collection of single characters, but I don't want to do
+ that because it means that there are characters which cannot be
+ received. The default is a guess at a typical shell prompt. */
+const char *zCuvar_eofread = "$";
+
+/* Whether to provide verbose information when sending or receiving a
+ file. */
+boolean fCuvar_verbose = TRUE;
+
+/* The table used to give a value to a variable, and to print all the
+ variable values. */
+
+static const struct uuconf_cmdtab asCuvars[] =
+{
+ { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL },
+ { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL },
+ { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL },
+ { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL },
+ { "binary-prefix", UUCONF_CMDTABTYPE_STRING,
+ (pointer) &zCuvar_binary_prefix, NULL },
+ { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN,
+ (pointer) &fCuvar_echocheck, NULL },
+ { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL },
+ { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL },
+ { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL },
+ { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL },
+ { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL },
+ { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL },
+ { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL },
+ { NULL, 0, NULL, NULL}
+};
+
+/* The program name. */
+char abProgram[] = "cu";
+
+/* The string printed at the initial connect. */
+#if ANSI_C
+#define ZCONNMSG "\aConnected."
+#else
+#define ZCONNMSG "Connected."
+#endif
+
+/* The string printed when disconnecting. */
+#if ANSI_C
+#define ZDISMSG "\aDisconnected."
+#else
+#define ZDISMSG "Disconnected."
+#endif
+
+/* Local variables. */
+
+/* The string we print when the user is once again connected to the
+ port after transferring a file or taking some other action. */
+static const char abCuconnected[]
+#if ANSI_C
+ = "\a[connected]";
+#else
+ = "[connected]";
+#endif
+
+/* Global uuconf pointer. */
+static pointer pCuuuconf;
+
+/* Connection. */
+static struct sconnection *qCuconn;
+
+/* Whether to close the connection. */
+static boolean fCuclose_conn;
+
+/* Dialer used to dial out. */
+static struct uuconf_dialer *qCudialer;
+
+/* Whether we need to restore the terminal. */
+static boolean fCurestore_terminal;
+
+/* Whether we are doing local echoing. */
+static boolean fCulocalecho;
+
+/* Whether we need to call fsysdep_cu_finish. */
+static boolean fCustarted;
+
+/* A structure used to pass information to icuport_lock. */
+struct sconninfo
+{
+ boolean fmatched;
+ boolean flocked;
+ struct sconnection *qconn;
+ const char *zline;
+};
+
+/* Local functions. */
+
+static void ucuusage P((void));
+static void ucuabort P((void));
+static void uculog_start P((void));
+static void uculog_end P((void));
+static int icuport_lock P((struct uuconf_port *qport, pointer pinfo));
+static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn,
+ int bcmd));
+static boolean fcuset_var P((pointer puuconf, char *zline));
+static int icuunrecogvar P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static int icuunrecogfn P((pointer puuconf, int argc, char **argv,
+ pointer pvar, pointer pinfo));
+static void uculist_vars P((void));
+static void uculist_fns P((const char *zescape));
+static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn,
+ char *zline));
+static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf,
+ size_t cbuf));
+
+#define ucuputs(zline) \
+ do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0)
+
+/* Long getopt options. */
+static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } };
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ /* -c: phone number. */
+ char *zphone = NULL;
+ /* -e: even parity. */
+ boolean feven = FALSE;
+ /* -l: line. */
+ char *zline = NULL;
+ /* -n: prompt for phone number. */
+ boolean fprompt = FALSE;
+ /* -o: odd parity. */
+ boolean fodd = FALSE;
+ /* -p: port name. */
+ const char *zport = NULL;
+ /* -s: speed. */
+ long ibaud = 0L;
+ /* -t: map cr to crlf. */
+ boolean fmapcr = FALSE;
+ /* -z: system. */
+ const char *zsystem = NULL;
+ /* -I: configuration file name. */
+ const char *zconfig = NULL;
+ int iopt;
+ pointer puuconf;
+ int iuuconf;
+ const char *zlocalname;
+ int i;
+ struct uuconf_system ssys;
+ const struct uuconf_system *qsys = NULL;
+ boolean flooped;
+ struct uuconf_port sport;
+ struct sconnection sconn;
+ struct sconninfo sinfo;
+ long ihighbaud;
+ struct uuconf_dialer sdialer;
+ struct uuconf_dialer *qdialer;
+ char bcmd;
+
+ /* We want to accept -# as a speed. It's easiest to look through
+ the arguments, replace -# with -s#, and let getopt handle it. */
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-'
+ && isdigit (BUCHAR (argv[i][1])))
+ {
+ size_t clen;
+ char *z;
+
+ clen = strlen (argv[i]);
+ z = zbufalc (clen + 2);
+ z[0] = '-';
+ z[1] = 's';
+ memcpy (z + 2, argv[i] + 1, clen);
+ argv[i] = z;
+ }
+ }
+
+ while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:",
+ asCulongopts, (int *) NULL)) != EOF)
+ {
+ switch (iopt)
+ {
+ case 'c':
+ /* Phone number. */
+ zphone = optarg;
+ break;
+
+ case 'd':
+ /* Set debugging level to maximum. */
+#if DEBUG > 1
+ iDebug = DEBUG_MAX;
+#endif
+ break;
+
+ case 'e':
+ /* Even parity. */
+ feven = TRUE;
+ break;
+
+ case 'h':
+ /* Local echo. */
+ fCulocalecho = TRUE;
+ break;
+
+ case 'n':
+ /* Prompt for phone number. */
+ fprompt = TRUE;
+ break;
+
+ case 'l':
+ /* Line name. */
+ zline = optarg;
+ break;
+
+ case 'o':
+ /* Odd parity. */
+ fodd = TRUE;
+ break;
+
+ case 'p':
+ case 'a':
+ /* Port name (-a is for compatibility). */
+ zport = optarg;
+ break;
+
+ case 's':
+ /* Speed. */
+ ibaud = strtol (optarg, (char **) NULL, 10);
+ break;
+
+ case 't':
+ /* Map cr to crlf. */
+ fmapcr = TRUE;
+ break;
+
+ case 'z':
+ /* System name. */
+ zsystem = optarg;
+ break;
+
+ case 'I':
+ /* Configuration file name. */
+ if (fsysdep_other_config (optarg))
+ zconfig = optarg;
+ break;
+
+ case 'x':
+#if DEBUG > 1
+ /* Set debugging level. */
+ iDebug |= idebug_parse (optarg);
+#endif
+ break;
+
+ case 0:
+ /* Long option found and flag set. */
+ break;
+
+ default:
+ ucuusage ();
+ break;
+ }
+ }
+
+ /* There can be one more argument, which is either a system name, a
+ phone number, or "dir". We decide which it is based on the first
+ character. To call a UUCP system whose name begins with a digit,
+ or one which is named "dir", you must use -z. */
+ if (optind != argc)
+ {
+ if (optind != argc - 1
+ || zsystem != NULL
+ || zphone != NULL)
+ ucuusage ();
+ if (strcmp (argv[optind], "dir") != 0)
+ {
+ if (isdigit (BUCHAR (argv[optind][0])))
+ zphone = argv[optind];
+ else
+ zsystem = argv[optind];
+ }
+ }
+
+ /* If the user doesn't give a system, port, line or speed, then
+ there's no basis on which to select a port. */
+ if (zsystem == NULL
+ && zport == NULL
+ && zline == NULL
+ && ibaud == 0L)
+ ucuusage ();
+
+ if (fprompt)
+ {
+ size_t cphone;
+
+ printf ("Phone number: ");
+ (void) fflush (stdout);
+ zphone = NULL;
+ cphone = 0;
+ if (getline (&zphone, &cphone, stdin) <= 0
+ || *zphone == '\0')
+ {
+ fprintf (stderr, "%s: No phone number entered\n", abProgram);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ iuuconf = uuconf_init (&puuconf, "cu", zconfig);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ pCuuuconf = puuconf;
+
+#if DEBUG > 1
+ {
+ const char *zdebug;
+
+ iuuconf = uuconf_debuglevel (puuconf, &zdebug);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ if (zdebug != NULL)
+ iDebug |= idebug_parse (zdebug);
+ }
+#endif
+
+ usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID);
+
+ iuuconf = uuconf_localname (puuconf, &zlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ zlocalname = zsysdep_localname ();
+ if (zlocalname == NULL)
+ exit (EXIT_FAILURE);
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ ulog_fatal_fn (ucuabort);
+ pfLstart = uculog_start;
+ pfLend = uculog_end;
+
+#ifdef SIGINT
+ usysdep_signal (SIGINT);
+#endif
+#ifdef SIGHUP
+ usysdep_signal (SIGHUP);
+#endif
+#ifdef SIGQUIT
+ usysdep_signal (SIGQUIT);
+#endif
+#ifdef SIGTERM
+ usysdep_signal (SIGTERM);
+#endif
+#ifdef SIGPIPE
+ usysdep_signal (SIGPIPE);
+#endif
+
+ if (zsystem != NULL)
+ {
+ iuuconf = uuconf_system_info (puuconf, zsystem, &ssys);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ ulog (LOG_FATAL, "%s: System not found", zsystem);
+ }
+ qsys = &ssys;
+ }
+
+ /* This loop is used if a system is specified. It loops over the
+ various alternates until it finds one for which the dial
+ succeeds. This is an ugly spaghetti construction, and it should
+ be broken up into different functions someday. */
+ flooped = FALSE;
+ while (TRUE)
+ {
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+
+ /* The uuconf_find_port function only selects directly on a port
+ name and a speed. To select based on the line name, we use a
+ function. If we can't find any defined port, and the user
+ specified a line name but did not specify a port name or a
+ system or a phone number, then we fake a direct port with
+ that line name (we don't fake a port if a system or phone
+ number were given because if we fake a port we have no way to
+ place a call; perhaps we should automatically look up a
+ particular dialer). This permits users to say cu -lttyd0
+ without having to put ttyd0 in the ports file, provided they
+ have read and write access to the port. */
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ sinfo.zline = zline;
+ if (zport != NULL || zline != NULL || ibaud != 0L)
+ {
+ iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L,
+ icuport_lock, (pointer) &sinfo,
+ &sport);
+ if (iuuconf != UUCONF_SUCCESS)
+ {
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ if (zline == NULL
+ || zport != NULL
+ || zphone != NULL
+ || qsys != NULL)
+ {
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "All matching ports in use");
+ else
+ ulog (LOG_FATAL, "No matching ports");
+ }
+
+ sport.uuconf_zname = zline;
+ sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT;
+ sport.uuconf_zprotocols = NULL;
+ sport.uuconf_qproto_params = NULL;
+ sport.uuconf_ireliable = 0;
+ sport.uuconf_zlockname = NULL;
+ sport.uuconf_palloc = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL;
+ sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud;
+
+ if (! fsysdep_port_access (&sport))
+ ulog (LOG_FATAL, "%s: Permission denied", zline);
+
+ if (! fconn_init (&sport, &sconn))
+ ucuabort ();
+
+ if (! fconn_lock (&sconn, FALSE))
+ ulog (LOG_FATAL, "%s: Line in use", zline);
+
+ qCuconn = &sconn;
+ }
+ ihighbaud = 0L;
+ }
+ else
+ {
+ for (; qsys != NULL; qsys = qsys->uuconf_qalternate)
+ {
+ if (! qsys->uuconf_fcall)
+ continue;
+ if (qsys->uuconf_qport != NULL)
+ {
+ if (fconn_init (qsys->uuconf_qport, &sconn))
+ {
+ if (fconn_lock (&sconn, FALSE))
+ {
+ qCuconn = &sconn;
+ break;
+ }
+ uconn_free (&sconn);
+ }
+ }
+ else
+ {
+ sinfo.fmatched = FALSE;
+ sinfo.flocked = FALSE;
+ sinfo.qconn = &sconn;
+ iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport,
+ qsys->uuconf_ibaud,
+ qsys->uuconf_ihighbaud,
+ icuport_lock,
+ (pointer) &sinfo,
+ &sport);
+ if (iuuconf == UUCONF_SUCCESS)
+ break;
+ if (iuuconf != UUCONF_NOT_FOUND)
+ {
+ if (sinfo.flocked)
+ {
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+ }
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+ }
+ }
+ }
+
+ if (qsys == NULL)
+ {
+ const char *zrem;
+
+ if (flooped)
+ zrem = "remaining ";
+ else
+ zrem = "";
+ if (sinfo.fmatched)
+ ulog (LOG_FATAL, "%s: All %smatching ports in use",
+ zsystem, zrem);
+ else
+ ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem);
+ }
+
+ ibaud = qsys->uuconf_ibaud;
+ ihighbaud = qsys->uuconf_ihighbaud;
+ }
+
+ /* Here we have locked a connection to use. */
+ if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE))
+ ucuabort ();
+
+ fCuclose_conn = TRUE;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Set up the connection. */
+ if (fodd && feven)
+ {
+ tparity = PARITYSETTING_NONE;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (fodd)
+ {
+ tparity = PARITYSETTING_ODD;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else if (feven)
+ {
+ tparity = PARITYSETTING_EVEN;
+ tstrip = STRIPSETTING_SEVENBITS;
+ }
+ else
+ {
+ tparity = PARITYSETTING_DEFAULT;
+ tstrip = STRIPSETTING_DEFAULT;
+ }
+
+ if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON))
+ ucuabort ();
+
+ if (qsys != NULL)
+ zphone = qsys->uuconf_zphone;
+
+ if (qsys != NULL || zphone != NULL)
+ {
+ enum tdialerfound tdialer;
+
+ if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer,
+ &tdialer))
+ {
+ if (zport != NULL
+ || zline != NULL
+ || ibaud != 0L
+ || qsys == NULL)
+ ucuabort ();
+
+ if (qsys->uuconf_qalternate == NULL)
+ ulog (LOG_FATAL, "%s: No remaining alternates", zsystem);
+
+ fCuclose_conn = FALSE;
+ (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE);
+ qCuconn = NULL;
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ /* Loop around and try another alternate. */
+ flooped = TRUE;
+ continue;
+ }
+ if (tdialer == DIALERFOUND_FALSE)
+ qdialer = NULL;
+ else
+ qdialer = &sdialer;
+ }
+ else
+ {
+ /* If no system or phone number was specified, we connect
+ directly to the modem. We only permit this if the user
+ has access to the port, since it permits various
+ shenanigans such as reprogramming the automatic
+ callbacks. */
+ if (! fsysdep_port_access (sconn.qport))
+ ulog (LOG_FATAL, "Access to port denied");
+ qdialer = NULL;
+ if (! fconn_carrier (&sconn, FALSE))
+ ulog (LOG_FATAL, "Can't turn off carrier");
+ }
+
+ break;
+ }
+
+ qCudialer = qdialer;
+
+ if (FGOT_SIGNAL ())
+ ucuabort ();
+
+ /* Here we have connected, and can start the main cu protocol. The
+ program spends most of its time in system dependent code, and
+ only comes out when a special command is received from the
+ terminal. */
+ printf ("%s\n", ZCONNMSG);
+
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+
+ fCurestore_terminal = TRUE;
+
+ if (! fsysdep_cu_init (&sconn))
+ ucuabort ();
+
+ fCustarted = TRUE;
+
+ while (fsysdep_cu (&sconn, &bcmd, zlocalname))
+ if (! fcudo_cmd (puuconf, &sconn, bcmd))
+ break;
+
+ fCustarted = FALSE;
+ if (! fsysdep_cu_finish ())
+ ucuabort ();
+
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+
+ (void) fconn_close (&sconn, puuconf, qdialer, TRUE);
+ (void) fconn_unlock (&sconn);
+ uconn_free (&sconn);
+
+ printf ("\n%s\n", ZDISMSG);
+
+ ulog_close ();
+
+ usysdep_exit (TRUE);
+
+ /* Avoid errors about not returning a value. */
+ return 0;
+}
+
+/* Print a usage message and die. */
+
+static void
+ucuusage ()
+{
+ fprintf (stderr,
+ "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n",
+ VERSION);
+ fprintf (stderr,
+ "Usage: cu [options] [system or phone-number]\n");
+ fprintf (stderr,
+ " -a port, -p port: Use named port\n");
+ fprintf (stderr,
+ " -l line: Use named device (e.g. tty0)\n");
+ fprintf (stderr,
+ " -s speed, -#: Use given speed\n");
+ fprintf (stderr,
+ " -c phone: Phone number to call\n");
+ fprintf (stderr,
+ " -z system: System to call\n");
+ fprintf (stderr,
+ " -e: Set even parity\n");
+ fprintf (stderr,
+ " -o: Set odd parity\n");
+ fprintf (stderr,
+ " -h: Echo locally\n");
+ fprintf (stderr,
+ " -t: Map carriage return to carriage return/linefeed\n");
+ fprintf (stderr,
+ " -n: Prompt for phone number\n");
+ fprintf (stderr,
+ " -d: Set maximum debugging level\n");
+ fprintf (stderr,
+ " -x debug: Set debugging type\n");
+#if HAVE_TAYLOR_CONFIG
+ fprintf (stderr,
+ " -I file: Set configuration file to use\n");
+#endif /* HAVE_TAYLOR_CONFIG */
+
+ exit (EXIT_FAILURE);
+}
+
+/* This function is called when a fatal error occurs. */
+
+static void
+ucuabort ()
+{
+ if (fCustarted)
+ {
+ fCustarted = FALSE;
+ (void) fsysdep_cu_finish ();
+ }
+
+ if (fCurestore_terminal)
+ {
+ fCurestore_terminal = FALSE;
+ (void) fsysdep_terminal_restore ();
+ }
+
+ if (qCuconn != NULL)
+ {
+ struct sconnection *qconn;
+
+ if (fCuclose_conn)
+ {
+ fCuclose_conn = FALSE;
+ (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE);
+ }
+ qconn = qCuconn;
+ qCuconn = NULL;
+ (void) fconn_unlock (qconn);
+ uconn_free (qconn);
+ }
+
+ ulog_close ();
+
+ printf ("\n%s\n", ZDISMSG);
+
+ usysdep_exit (FALSE);
+}
+
+/* This variable is just used to communicate between uculog_start and
+ uculog_end. */
+static boolean fCulog_restore;
+
+/* This function is called by ulog before it output anything. We use
+ it to restore the terminal, if necessary. ulog is only called for
+ errors or debugging in cu, so it's not too costly to do this. If
+ we didn't do it, then at least on Unix each line would leave the
+ cursor in the same column rather than wrapping back to the start,
+ since CRMOD will not be on. */
+
+static void
+uculog_start ()
+{
+ if (! fCurestore_terminal)
+ fCulog_restore = FALSE;
+ else
+ {
+ fCulog_restore = TRUE;
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_terminal_restore ())
+ ucuabort ();
+ }
+}
+
+/* This function is called by ulog after everything is output. It
+ sets the terminal back, if necessary. */
+
+static void
+uculog_end ()
+{
+ if (fCulog_restore)
+ {
+ if (! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ }
+}
+
+/* Check to see if this port has the desired line, to handle the -l
+ option. If it does, or if no line was specified, set up a
+ connection and lock it. */
+
+static int
+icuport_lock (qport, pinfo)
+ struct uuconf_port *qport;
+ pointer pinfo;
+{
+ struct sconninfo *q = (struct sconninfo *) pinfo;
+
+ if (q->zline != NULL
+ && ! fsysdep_port_is_line (qport, q->zline))
+ return UUCONF_NOT_FOUND;
+
+ q->fmatched = TRUE;
+
+ if (! fconn_init (qport, q->qconn))
+ return UUCONF_NOT_FOUND;
+ else if (! fconn_lock (q->qconn, FALSE))
+ {
+ uconn_free (q->qconn);
+ return UUCONF_NOT_FOUND;
+ }
+ else
+ {
+ qCuconn = q->qconn;
+ q->flocked = TRUE;
+ return UUCONF_SUCCESS;
+ }
+}
+
+/* Execute a cu escape command. Return TRUE if the connection should
+ continue, or FALSE if the connection should be terminated. */
+
+static boolean
+fcudo_cmd (puuconf, qconn, bcmd)
+ pointer puuconf;
+ struct sconnection *qconn;
+ int bcmd;
+{
+ char *zline;
+ char *z;
+ char abescape[5];
+ boolean fret;
+ size_t clen;
+ char abbuf[100];
+
+ /* Some commands take a string up to the next newline character. */
+ switch (bcmd)
+ {
+ default:
+ zline = NULL;
+ break;
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ case '%':
+ case 'c':
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ case 's':
+ {
+ zline = zsysdep_terminal_line ((const char *) NULL);
+ if (zline == NULL)
+ ucuabort ();
+ zline[strcspn (zline, "\n")] = '\0';
+ }
+ break;
+ }
+
+ switch (bcmd)
+ {
+ default:
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]",
+ abescape, abescape, abescape);
+ ucuputs (abbuf);
+ return TRUE;
+
+ case '.':
+ /* Hangup. */
+ return FALSE;
+
+ case '!':
+ case '$':
+ case '|':
+ case '+':
+ /* Shell out. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ {
+ enum tshell_cmd t;
+
+ switch (bcmd)
+ {
+ default:
+ case '!': t = SHELL_NORMAL; break;
+ case '$': t = SHELL_STDOUT_TO_PORT; break;
+ case '|': t = SHELL_STDIN_FROM_PORT; break;
+ case '+': t = SHELL_STDIO_ON_PORT; break;
+ }
+
+ (void) fsysdep_shell (qconn, zline, t);
+ }
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ ubuffree (zline);
+ return TRUE;
+
+ case '%':
+ fret = fcudo_subcmd (puuconf, qconn, zline);
+ ubuffree (zline);
+ return fret;
+
+ case '#':
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return TRUE;
+
+ case 'c':
+ (void) fsysdep_chdir (zline);
+ ubuffree (zline);
+ return TRUE;
+
+ case '>':
+ case '<':
+ case 'p':
+ case 't':
+ clen = strlen (zline);
+ z = zbufalc (clen + 3);
+ z[0] = bcmd;
+ z[1] = ' ';
+ memcpy (z + 2, zline, clen + 1);
+ ubuffree (zline);
+ fret = fcudo_subcmd (puuconf, qconn, z);
+ ubuffree (z);
+ return fret;
+
+ case 'z':
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_restore ())
+ ucuabort ();
+ fCurestore_terminal = FALSE;
+ if (! fsysdep_suspend ())
+ ucuabort ();
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_raw (fCulocalecho))
+ ucuabort ();
+ fCurestore_terminal = TRUE;
+ return TRUE;
+
+ case 's':
+ fret = fcuset_var (puuconf, zline);
+ ubuffree (zline);
+ return fret;
+
+ case 'v':
+ uculist_vars ();
+ return TRUE;
+
+ case '?':
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ucuputs ("");
+ ucuputs ("[Escape sequences]");
+ sprintf (abbuf,
+ "[%s. hangup] [%s!CMD run shell]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s$CMD stdout to remote] [%s|CMD stdin from remote]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s+CMD stdin and stdout to remote]",
+ abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s# send break] [%scDIR change directory]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s> send file] [%s< receive file]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ssVAR VAL set variable] [%ssVAR set boolean]",
+ abescape, abescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%ss!VAR unset boolean] [%sv list variables]",
+ abescape, abescape);
+ ucuputs (abbuf);
+#ifdef SIGTSTP
+ sprintf (abbuf,
+ "[%sz suspend]",
+ abescape);
+ ucuputs (abbuf);
+#endif
+ uculist_fns (abescape);
+ return TRUE;
+ }
+}
+
+/* List ~% functions. */
+
+static void
+uculist_fns (zescape)
+ const char *zescape;
+{
+ char abbuf[100];
+
+ sprintf (abbuf,
+ "[%s%%break send break] [%s%%cd DIR change directory]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]",
+ zescape, zescape);
+ ucuputs (abbuf);
+ sprintf (abbuf,
+ "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]",
+ zescape, zescape);
+ ucuputs (abbuf);
+}
+
+/* Set a variable. */
+
+static boolean
+fcuset_var (puuconf, zline)
+ pointer puuconf;
+ char *zline;
+{
+ char *zvar, *zval;
+ char *azargs[2];
+ char azbool[2];
+ int iuuconf;
+
+ zvar = strtok (zline, "= \t");
+ if (zvar == NULL)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ zval = strtok ((char *) NULL, " \t");
+
+ if (zval == NULL)
+ {
+ azargs[0] = zvar;
+ if (azargs[0][0] != '!')
+ azbool[0] = 't';
+ else
+ {
+ ++azargs[0];
+ azbool[0] = 'f';
+ }
+ azbool[1] = '\0';
+ azargs[1] = azbool;
+ }
+ else
+ {
+ azargs[0] = zvar;
+ azargs[1] = zval;
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars,
+ (pointer) NULL, icuunrecogvar, 0,
+ (pointer) NULL);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown variable. */
+
+/*ARGSUSED*/
+static int
+icuunrecogvar (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* List all the variables with their values. */
+
+static void
+uculist_vars ()
+{
+ const struct uuconf_cmdtab *q;
+ char abbuf[100];
+
+ ucuputs ("");
+ for (q = asCuvars; q->uuconf_zcmd != NULL; q++)
+ {
+ switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype))
+ {
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN):
+ if (*(boolean *) q->uuconf_pvar)
+ sprintf (abbuf, "%s true", q->uuconf_zcmd);
+ else
+ sprintf (abbuf, "%s false", q->uuconf_zcmd);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT):
+ sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG):
+ sprintf (abbuf, "%s %ld", q->uuconf_zcmd,
+ *(long *) q->uuconf_pvar);
+ break;
+
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING):
+ case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING):
+ {
+ const char *z;
+ char abchar[5];
+ size_t clen;
+
+ sprintf (abbuf, "%s ", q->uuconf_zcmd);
+ clen = strlen (abbuf);
+ for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++)
+ {
+ int cchar;
+
+ if (! isprint (*z))
+ {
+ sprintf (abchar, "\\%03o", (unsigned int) *z);
+ cchar = 4;
+ }
+ else
+ {
+ abchar[0] = *z;
+ abchar[1] = '\0';
+ cchar = 1;
+ }
+ if (clen + cchar < sizeof (abbuf))
+ strcat (abbuf, abchar);
+ clen += cchar;
+ }
+ }
+ break;
+
+ default:
+ sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd);
+ break;
+ }
+
+ ucuputs (abbuf);
+ }
+}
+
+/* Subcommands. These are commands that begin with ~%. */
+
+/* This variable is only used so that we can pass a non-NULL address
+ in pvar. It is never assigned to or examined. */
+
+static char bCutype;
+
+/* The command table for the subcommands. */
+
+static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar,
+ pointer pinfo));
+
+static const struct uuconf_cmdtab asCucmds[] =
+{
+ { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak },
+ { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir },
+ { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug },
+ { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop },
+ { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop },
+ { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput },
+ { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake },
+ { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput },
+ { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake },
+ { NULL, 0, NULL, NULL }
+};
+
+/* Do a subcommand. This is called by commands beginning with ~%. */
+
+static boolean
+fcudo_subcmd (puuconf, qconn, zline)
+ pointer puuconf;
+ struct sconnection *qconn;
+ char *zline;
+{
+ char *azargs[3];
+ int iarg;
+ int iuuconf;
+
+ for (iarg = 0; iarg < 3; iarg++)
+ {
+ azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n");
+ if (azargs[iarg] == NULL)
+ break;
+ }
+
+ if (iarg == 0)
+ {
+ ucuputs (abCuconnected);
+ return TRUE;
+ }
+
+ iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds,
+ (pointer) qconn, icuunrecogfn,
+ 0, (pointer) NULL);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+
+ return TRUE;
+}
+
+/* Warn about an unknown function. */
+
+/*ARGSUSED*/
+static int
+icuunrecogfn (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ char abescape[5];
+
+ if (! isprint (*zCuvar_escape))
+ sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape);
+ else
+ {
+ abescape[0] = *zCuvar_escape;
+ abescape[1] = '\0';
+ }
+ if (argv[0][0] == '?')
+ uculist_fns (abescape);
+ else
+ ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)",
+ argv[0], abescape);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a break. */
+
+/*ARGSUSED*/
+static int
+icubreak (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_break (qconn))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Change directories. */
+
+/*ARGSUSED*/
+static int
+icuchdir (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ const char *zarg;
+
+ if (argc <= 1)
+ zarg = NULL;
+ else
+ zarg = argv[1];
+ (void) fsysdep_chdir (zarg);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Toggle debugging. */
+
+/*ARGSUSED*/
+static int
+icudebug (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+#if DEBUG > 1
+ if (iDebug != 0)
+ iDebug = 0;
+ else
+ iDebug = DEBUG_MAX;
+#else
+ ucuputs ("[compiled without debugging]");
+#endif
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Control whether the port does xon/xoff handshaking. If pvar is not
+ NULL, this is "stop"; otherwise it is "nostop". */
+
+/*ARGSUSED*/
+static int
+icunostop (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+
+ if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT,
+ pvar == NULL ? XONXOFF_OFF : XONXOFF_ON))
+ ucuabort ();
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a file to the remote system. The first argument is the file
+ to send. If that argument is not present, it is prompted for. The
+ second argument is to file name to use on the remote system. If
+ that argument is not present, the basename of the local filename is
+ used. If pvar is not NULL, then this is ~>, which is used to send
+ a command to a non-Unix system. We treat is the same as ~%put,
+ except that we assume the user has already entered the appropriate
+ command (for ~%put, we force ``cat >to'' to the other side). */
+
+/*ARGSUSED*/
+static int
+icuput (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ char *zfrom;
+ char *zto = NULL;
+ char *zalc;
+ openfile_t e;
+ int cline;
+ char *zbuf;
+ size_t cbuf;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("File to send: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (pvar == NULL)
+ {
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Remote file name []: " +
+ strlen (zbase));
+ sprintf (zprompt, "Remote file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+ }
+
+ e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ if (pvar == NULL)
+ ubuffree (zto);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s", zfrom, zerrstr);
+ ubuffree (zfrom);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ ubuffree (zfrom);
+
+ /* Tell the system dependent layer to stop copying data from the
+ port to the terminal. We want to read the echoes ourself. Also
+ permit the local user to generate signals. */
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ /* If pvar is NULL, then we are sending a file to a Unix system. We
+ send over the command "cat > TO" to prepare it to receive. If
+ pvar is not NULL, the user is assumed to have set up whatever
+ action was needed to receive the file. */
+ if (pvar == NULL)
+ {
+ boolean fret;
+
+ zalc = zbufalc (sizeof "cat > \n" + strlen (zto));
+ sprintf (zalc, "cat > %s\n", zto);
+ ubuffree (zto);
+ fret = fcusend_buf (qconn, zalc, strlen (zalc));
+ ubuffree (zalc);
+ if (! fret)
+ {
+ (void) ffileclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ cline = 0;
+
+ zbuf = NULL;
+ cbuf = 0;
+
+ while (TRUE)
+ {
+ char abbuf[512];
+ size_t c;
+
+#if USE_STDIO
+ if (fCuvar_binary)
+#endif
+ {
+ if (ffileeof (e))
+ break;
+ c = cfileread (e, abbuf, sizeof abbuf);
+ if (ffilereaderror (e, c))
+ {
+ ucuputs ("[file read error]");
+ break;
+ }
+ if (c == 0)
+ break;
+ zbuf = abbuf;
+ }
+#if USE_STDIO
+ else
+ {
+ if (getline (&zbuf, &cbuf, e) <= 0)
+ {
+ xfree ((pointer) zbuf);
+ break;
+ }
+ c = strlen (zbuf);
+ }
+#endif
+
+ if (fCuvar_verbose)
+ {
+ ++cline;
+ printf ("%d ", cline);
+ (void) fflush (stdout);
+ }
+
+ if (! fcusend_buf (qconn, zbuf, c))
+ {
+ if (! fCuvar_binary)
+ xfree ((pointer) zbuf);
+ (void) fclose (e);
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ (void) ffileclose (e);
+
+ if (pvar == NULL)
+ {
+ char beof;
+
+ beof = '\004';
+ if (! fconn_write (qconn, &beof, 1))
+ ucuabort ();
+ }
+ else
+ {
+ if (*zCuvar_eofwrite != '\0')
+ {
+ if (! fconn_write (qconn, zCuvar_eofwrite,
+ strlen (zCuvar_eofwrite)))
+ ucuabort ();
+ }
+ }
+
+ if (fCuvar_verbose)
+ ucuputs ("");
+
+ ucuputs ("[file transfer complete]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Get a file from the remote side. This is ~%take, or ~t, or ~<.
+ The first two are assumed to be taking the file from a Unix system,
+ so we force the command "cat FROM; echo */
+
+/*ARGSUSED*/
+static int
+icutake (puuconf, argc, argv, pvar, pinfo)
+ pointer puuconf;
+ int argc;
+ char **argv;
+ pointer pvar;
+ pointer pinfo;
+{
+ struct sconnection *qconn = (struct sconnection *) pinfo;
+ const char *zeof;
+ char *zfrom, *zto, *zcmd;
+ char *zalc;
+ openfile_t e;
+ char bcr;
+ size_t ceoflen;
+ char *zlook = NULL;
+ size_t ceofhave;
+ boolean ferr;
+
+ if (argc > 1)
+ zfrom = zbufcpy (argv[1]);
+ else
+ {
+ zfrom = zsysdep_terminal_line ("Remote file to retreive: ");
+ if (zfrom == NULL)
+ ucuabort ();
+ zfrom[strcspn (zfrom, " \t\n")] = '\0';
+ if (*zfrom == '\0')
+ {
+ ubuffree (zfrom);
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+
+ if (argc > 2)
+ zto = zbufcpy (argv[2]);
+ else
+ {
+ char *zbase;
+ char *zprompt;
+
+ zbase = zsysdep_base_name (zfrom);
+ if (zbase == NULL)
+ ucuabort ();
+
+ zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase));
+ sprintf (zprompt, "Local file name [%s]: ", zbase);
+ zto = zsysdep_terminal_line (zprompt);
+ ubuffree (zprompt);
+ if (zto == NULL)
+ ucuabort ();
+
+ zto[strcspn (zto, " \t\n")] = '\0';
+ if (*zto != '\0')
+ ubuffree (zbase);
+ else
+ {
+ ubuffree (zto);
+ zto = zbase;
+ }
+ }
+
+ if (pvar != NULL)
+ {
+ zcmd = zsysdep_terminal_line ("Remote command to execute: ");
+ if (zcmd == NULL)
+ ucuabort ();
+ zcmd[strcspn (zcmd, "\n")] = '\0';
+ zeof = zCuvar_eofread;
+ }
+ else
+ {
+ zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////"
+ + strlen (zfrom));
+ sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom);
+ zeof = "\n////cuend////\n";
+ }
+
+ ubuffree (zfrom);
+
+ e = esysdep_user_fopen (zto, FALSE, fCuvar_binary);
+ if (! ffileisopen (e))
+ {
+ const char *zerrstr;
+
+ ubuffree (zcmd);
+ zerrstr = strerror (errno);
+ zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr));
+ sprintf (zalc, "%s: %s\n", zto, zerrstr);
+ ucuputs (zalc);
+ ubuffree (zalc);
+ ucuputs (abCuconnected);
+ ubuffree (zto);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+
+ ubuffree (zto);
+
+ if (! fsysdep_cu_copy (FALSE)
+ || ! fsysdep_terminal_signals (TRUE))
+ ucuabort ();
+
+ if (! fconn_write (qconn, zcmd, strlen (zcmd)))
+ ucuabort ();
+ bcr = '\r';
+ if (! fconn_write (qconn, &bcr, 1))
+ ucuabort ();
+
+ ubuffree (zcmd);
+
+ /* Eliminated any previously echoed data to avoid confusion. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* If we're dealing with a Unix system, we can reliably discard the
+ command. Otherwise, the command will probably wind up in the
+ file; too bad. */
+ if (pvar == NULL)
+ {
+ int b;
+
+ while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n')
+ {
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ ucuputs ("[timed out waiting for newline]");
+ ucuputs (abCuconnected);
+ return UUCONF_CMDTABRET_CONTINUE;
+ }
+ }
+ }
+
+ ceoflen = strlen (zeof);
+ zlook = zbufalc (ceoflen);
+ ceofhave = 0;
+ ferr = FALSE;
+
+ while (TRUE)
+ {
+ int b;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file receive aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ break;
+ }
+
+ b = breceive_char (qconn, cCuvar_timeout, TRUE);
+ if (b == -2)
+ ucuabort ();
+ if (b < 0)
+ {
+ if (ceofhave > 0)
+ (void) fwrite (zlook, sizeof (char), ceofhave, e);
+ ucuputs ("[timed out]");
+ break;
+ }
+
+ if (ceoflen == 0)
+ {
+ if (cfilewrite (e, &b, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ zlook[ceofhave] = b;
+ ++ceofhave;
+ if (ceofhave == ceoflen)
+ {
+ size_t cmove;
+ char *zmove;
+
+ if (memcmp (zeof, zlook, ceoflen) == 0)
+ {
+ ucuputs ("[file transfer complete]");
+ break;
+ }
+
+ if (cfilewrite (e, zlook, 1) != 1)
+ {
+ ferr = TRUE;
+ break;
+ }
+
+ zmove = zlook;
+ for (cmove = ceoflen - 1, zmove = zlook;
+ cmove > 0;
+ cmove--, zmove++)
+ zmove[0] = zmove[1];
+
+ --ceofhave;
+ }
+ }
+ }
+
+ ubuffree (zlook);
+
+ if (! ffileclose (e))
+ ferr = TRUE;
+ if (ferr)
+ ucuputs ("[file write error]");
+
+ if (! fsysdep_cu_copy (TRUE)
+ || ! fsysdep_terminal_signals (FALSE))
+ ucuabort ();
+
+ ucuputs (abCuconnected);
+
+ return UUCONF_CMDTABRET_CONTINUE;
+}
+
+/* Send a buffer to the remote system. If fCuvar_binary is FALSE,
+ each buffer passed in will be a single line; in this case we can
+ check the echoed characters and kill the line if they do not match.
+ This returns FALSE if an echo check fails. If a port error
+ occurrs, it calls ucuabort. */
+
+static boolean
+fcusend_buf (qconn, zbufarg, cbufarg)
+ struct sconnection *qconn;
+ const char *zbufarg;
+ size_t cbufarg;
+{
+ const char *zbuf;
+ size_t cbuf;
+ int ctries;
+ size_t cbplen;
+ char *zsendbuf;
+
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ ctries = 0;
+
+ if (fCuvar_binary)
+ cbplen = strlen (zCuvar_binary_prefix);
+ else
+ cbplen = 1;
+ zsendbuf = zbufalc (64 * (cbplen + 1));
+
+ /* Loop while we still have characters to send. The value of cbuf
+ will be reset to cbufarg if an echo failure occurs while sending
+ a line in non-binary mode. */
+ while (cbuf > 0)
+ {
+ int csend;
+ char *zput;
+ const char *zget;
+ boolean fnl;
+ int i;
+
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not confuse us in
+ the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ /* Discard anything we've read from the port up to now, to avoid
+ confusing the echo checking. */
+ iPrecstart = 0;
+ iPrecend = 0;
+
+ /* Send all characters up to a newline before actually sending
+ the newline. This makes it easier to handle the special
+ newline echo checking. Send up to 64 characters at a time
+ before doing echo checking. */
+ if (*zbuf == '\n')
+ csend = 1;
+ else
+ {
+ const char *znl;
+
+ znl = memchr (zbuf, '\n', cbuf);
+ if (znl == NULL)
+ csend = cbuf;
+ else
+ csend = znl - zbuf;
+ if (csend > 64)
+ csend = 64;
+ }
+
+ /* Translate this part of the buffer. If we are not in binary
+ mode, we translate \n to \r, and ignore any nonprintable
+ characters. */
+ zput = zsendbuf;
+ fnl = FALSE;
+ for (i = 0, zget = zbuf; i < csend; i++, zget++)
+ {
+ if (isprint (*zget)
+ || *zget == '\t')
+ *zput++ = *zget;
+ else if (*zget == '\n')
+ {
+ if (fCuvar_binary)
+ *zput++ = '\n';
+ else
+ *zput++ = '\r';
+ fnl = TRUE;
+ }
+ else if (fCuvar_binary)
+ {
+ strcpy (zput, zCuvar_binary_prefix);
+ zput += cbplen;
+ *zput++ = *zget;
+ }
+ }
+
+ zbuf += csend;
+ cbuf -= csend;
+
+ if (zput == zsendbuf)
+ continue;
+
+ /* Send the data over the port. */
+ if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE))
+ ucuabort ();
+
+ /* We do echo checking if requested, unless we are in binary
+ mode. Echo checking of a newline is different from checking
+ of normal characters; when we send a newline we look for
+ *zCuvar_echonl. */
+ if ((fCuvar_echocheck && ! fCuvar_binary)
+ || (fnl && *zCuvar_echonl != '\0'))
+ {
+ long iend;
+
+ iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout;
+ for (zget = zsendbuf; zget < zput; zget++)
+ {
+ int bread;
+ int bwant;
+
+ if (fCuvar_binary ? *zget == '\n' : *zget == '\r')
+ {
+ bwant = *zCuvar_echonl;
+ if (bwant == '\0')
+ continue;
+ }
+ else
+ {
+ if (! fCuvar_echocheck || ! isprint (*zget))
+ continue;
+ bwant = *zget;
+ }
+
+ do
+ {
+ if (FGOT_SIGNAL ())
+ {
+ /* Make sure the signal is logged. */
+ ubuffree (zsendbuf);
+ ulog (LOG_ERROR, (const char *) NULL);
+ ucuputs ("[file send aborted]");
+ /* Reset the SIGINT flag so that it does not
+ confuse us in the future. */
+ afSignal[INDEXSIG_SIGINT] = FALSE;
+ return FALSE;
+ }
+
+ bread = breceive_char (qconn,
+ iend - ixsysdep_time ((long *) NULL),
+ TRUE);
+ if (bread < 0)
+ {
+ if (bread == -2)
+ ucuabort ();
+
+ /* If we timed out, and we're not in binary
+ mode, we kill the line and try sending it
+ again from the beginning. */
+ if (! fCuvar_binary && *zCuvar_kill != '\0')
+ {
+ ++ctries;
+ if (ctries < cCuvar_resend)
+ {
+ if (fCuvar_verbose)
+ {
+ printf ("R ");
+ (void) fflush (stdout);
+ }
+ if (! fsend_data (qconn, zCuvar_kill, 1,
+ TRUE))
+ ucuabort ();
+ zbuf = zbufarg;
+ cbuf = cbufarg;
+ break;
+ }
+ }
+ ubuffree (zsendbuf);
+ ucuputs ("[timed out looking for echo]");
+ return FALSE;
+ }
+ }
+ while (bread != *zget);
+
+ if (bread < 0)
+ break;
+ }
+ }
+ }
+
+ ubuffree (zsendbuf);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/MANIFEST b/gnu/libexec/uucp/libunix/MANIFEST
new file mode 100644
index 0000000..d64e799
--- /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 0000000..a2cb537
--- /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 <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libunix/access.c b/gnu/libexec/uucp/libunix/access.c
new file mode 100644
index 0000000..c2c0eef
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/access.c
@@ -0,0 +1,83 @@
+/* access.c
+ Check access to files by the user and by the daemon. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See if the user has access to a file, to prevent the setuid uucp
+ and uux programs handing out unauthorized access. */
+
+boolean
+fsysdep_access (zfile)
+ const char *zfile;
+{
+ if (access (zfile, R_OK) == 0)
+ return TRUE;
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (errno));
+ return FALSE;
+}
+
+/* See if the daemon has access to a file. This is called if a file
+ is not being transferred to the spool directory, since if the
+ daemon does not have access the later transfer will fail. We
+ assume that the daemon will have the same euid (or egid) as the one
+ we are running under. If our uid (gid) and euid (egid) are the
+ same, we assume that we have access. Note that is not important
+ for security, since the check will be (implicitly) done again when
+ the daemon tries to transfer the file. This routine should work
+ whether the UUCP programs are installed setuid or setgid. */
+
+boolean
+fsysdep_daemon_access (zfile)
+ const char *zfile;
+{
+ struct stat s;
+ uid_t ieuid, iuid, iegid, igid;
+ boolean fok;
+
+ ieuid = geteuid ();
+ if (ieuid == 0)
+ return TRUE;
+ iuid = getuid ();
+ iegid = getegid ();
+ igid = getgid ();
+
+ /* If our effective uid and gid are the same as our real uid and
+ gid, we assume the daemon will have access to the file. */
+ if (ieuid == iuid && iegid == igid)
+ return TRUE;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+
+ /* If our euid is not our uid, but it is the file's uid, see if the
+ owner has read access. Otherwise, if our egid is not our gid,
+ but it is the file's gid, see if the group has read access.
+ Otherwise, see if the world has read access. We know from the
+ above check that at least one of our euid and egid are different,
+ so that is the only one we want to check. This check could fail
+ if the UUCP programs were both setuid and setgid, but why would
+ they be? */
+ if (ieuid != iuid && ieuid == s.st_uid)
+ fok = (s.st_mode & S_IRUSR) != 0;
+ else if (iegid != igid && iegid == s.st_gid)
+ fok = (s.st_mode & S_IRGRP) != 0;
+ else
+ fok = (s.st_mode & S_IROTH) != 0;
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "%s: cannot be read by daemon", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/addbas.c b/gnu/libexec/uucp/libunix/addbas.c
new file mode 100644
index 0000000..8597918
--- /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 0000000..5c0b589
--- /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 0000000..a3b3787
--- /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 0000000..c61fcaa
--- /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 0000000..568eebe
--- /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 0000000..cf69f3e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/chmod.c
@@ -0,0 +1,25 @@
+/* chmod.c
+ Change the mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Change the mode of a file. */
+
+boolean
+fsysdep_change_mode (zfile, imode)
+ const char *zfile;
+ unsigned int imode;
+{
+ if (chmod ((char *) zfile, imode) < 0)
+ {
+ ulog (LOG_ERROR, "chmod (%s): %s", zfile, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/cohtty.c b/gnu/libexec/uucp/libunix/cohtty.c
new file mode 100644
index 0000000..a7aec1c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cohtty.c
@@ -0,0 +1,244 @@
+/* Coherent tty locking support. This file was contributed by Bob
+ Hemedinger <bob@dalek.mwc.com> of Mark Williams Corporation and
+ lightly edited by Ian Lance Taylor. */
+
+/* The bottom part of this file is lock.c.
+ * This is a hacked lock.c. A full lock.c can be found in the libmisc sources
+ * under /usr/src/misc.tar.Z.
+ *
+ * These are for checking for the existence of locks:
+ * lockexist(resource)
+ * lockttyexist(ttyname)
+ */
+
+#include "uucp.h"
+
+#if HAVE_COHERENT_LOCKFILES
+
+/* cohtty.c: Given a serial device name, read /etc/ttys and determine if
+ * the device is already enabled. If it is, disable the
+ * device and return a string so that it can be re-enabled
+ * at the completion of the uucico session as part of the
+ * function that resets the serial device before uucico
+ * terminates.
+ *
+ */
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <access.h>
+
+/* fscoherent_disable_tty() is a COHERENT specific function. It takes the name
+ * of a serial device and then scans /etc/ttys for a match. If it finds one,
+ * it checks the first field of the entry. If it is a '1', then it will disable
+ * the port and set a flag. The flag will be checked later when uucico wants to
+ * reset the serial device to see if the device needs to be re-enabled.
+ */
+
+boolean
+fscoherent_disable_tty (zdevice, pzenable)
+ const char *zdevice;
+ char **pzenable;
+{
+
+
+struct ttyentry{ /* this is an /etc/ttys entry */
+ char enable_disable[1];
+ char remote_local[1];
+ char baud_rate[1];
+ char tty_device[16];
+};
+
+struct ttyentry sought_tty;
+
+int x,y,z; /* dummy */
+FILE * infp; /* this will point to /etc/ttys */
+char disable_command[66]; /* this will be the disable command
+ * passed to the system.
+ */
+char enable_device[16]; /* this will hold our device name
+ * to enable.
+ */
+
+ *pzenable = NULL;
+
+ strcpy(enable_device,""); /* initialize our strings */
+ strcpy(sought_tty.tty_device,"");
+
+ if( (infp = fopen("/etc/ttys","r")) == NULL){
+ ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n");
+ return FALSE;
+ }
+
+ while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){
+ sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0';
+ strcpy(enable_device,sought_tty.tty_device);
+
+ /* we must strip away the suffix to the com port name or
+ * we will never find a match. For example, if we are passed
+ * /dev/com4l to call out with and the port is already enabled,
+ * 9/10 the port enabled will be com4r. After we strip away the
+ * suffix of the port found in /etc/ttys, then we can test
+ * if the base port name appears in the device name string
+ * passed to us.
+ */
+
+ for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){
+ if(isdigit(sought_tty.tty_device[z])){
+ break;
+ }
+ }
+ y = strlen(sought_tty.tty_device);
+ for(x = z+1 ; x <= y; x++){
+ sought_tty.tty_device[x] = '\0';
+ }
+
+
+/* ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */
+ if(strstr(zdevice, sought_tty.tty_device)){
+ if(sought_tty.enable_disable[0] == '1'){
+ ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n",
+ zdevice, sought_tty.tty_device);
+ sprintf(disable_command, "/etc/disable %s",enable_device);
+ {
+ pid_t ipid;
+ const char *azargs[3];
+ int aidescs[3];
+
+ azargs[0] = "/etc/disable";
+ azargs[1] = enable_device;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+ ipid = ixsspawn (azargs, aidescs, TRUE,
+ FALSE,
+ (const char *) NULL, TRUE,
+ TRUE,
+ (const char *) NULL,
+ (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ x = 1;
+ else
+ x = ixswait ((unsigned long) ipid,
+ (const char *) NULL);
+ }
+ *pzenable = zbufalc (sizeof "/dev/"
+ + strlen (enable_device));
+ sprintf(*pzenable,"/dev/%s", enable_device);
+/* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */
+ return(x==0? TRUE : FALSE); /* disable either failed
+ or succeded */
+ }else{
+ return FALSE; /* device in tty entry not enabled */
+ }
+ }
+ }
+ return FALSE; /* no ttys entry found */
+}
+
+/* The following is COHERENT 4.0 specific. It is used to test for any
+ * existing lockfiles on a port which would have been created by init
+ * when a user logs into a port.
+ */
+
+#define LOCKSIG 9 /* Significant Chars of Lockable Resources. */
+#define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */
+
+#define LOCKPRE "LCK.."
+#define PIDLEN 6 /* Maximum length of string representing a pid. */
+
+#ifndef LOCKDIR
+#define LOCKDIR SPOOLDIR
+#endif
+
+/* There is a special version of DEVMASK for the PE multiport driver
+ * because of the peculiar way it uses the minor device number. For
+ * all other drivers, the lower 5 bits describe the physical port--
+ * the upper 3 bits give attributes for the port.
+ */
+
+#define PE_DRIVER 21 /* Major device number for the PE driver. */
+#define PE_DEVMASK 0x3f /* PE driver minor device mask. */
+#define DEVMASK 0x1f /* Minor device mask. */
+
+/*
+ * Generates a resource name for locking, based on the major number
+ * and the lower 4 bits of the minor number of the tty device.
+ *
+ * Builds the name in buff as two "." separated decimal numbers.
+ * Returns NULL on failure, buff on success.
+ */
+static char *
+gen_res_name(path, buff)
+char *path;
+char *buff;
+{
+ struct stat sbuf;
+ int status;
+
+ if (0 != (status = stat(path, &sbuf))) {
+ /* Can't stat the file. */
+ return (NULL);
+ }
+
+ if (PE_DRIVER == major(sbuf.st_rdev)) {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ PE_DEVMASK & minor(sbuf.st_rdev));
+ } else {
+ sprintf(buff, "%d.%d", major(sbuf.st_rdev),
+ DEVMASK & minor(sbuf.st_rdev));
+ }
+
+ return(buff);
+} /* gen_res_name */
+
+/*
+ * lockexist(resource) char *resource;
+ *
+ * Test for existance of a lock on the given resource.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+
+static boolean
+lockexist(resource)
+const char *resource;
+{
+ char lockfn[LOKFLEN];
+
+ if ( resource == NULL )
+ return(0);
+ sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource);
+
+ return (!access(lockfn, AEXISTS));
+} /* lockexist() */
+
+/*
+ * lockttyexist(ttyname) char *ttyname;
+ *
+ * Test for existance of a lock on the given tty.
+ *
+ * Returns: (1) Resource is locked.
+ * (0) Resource is not locked.
+ */
+boolean
+lockttyexist(ttyn)
+const char *ttyn;
+{
+ char resource[LOKFLEN];
+ char filename[LOKFLEN];
+
+ sprintf(filename, "/dev/%s", ttyn);
+ if (NULL == gen_res_name(filename, resource)){
+ return(0); /* Non-existent tty can not be locked :-) */
+ }
+
+ return(lockexist(resource));
+} /* lockttyexist() */
+
+#endif /* HAVE_COHERENT_LOCKFILES */
diff --git a/gnu/libexec/uucp/libunix/cusub.c b/gnu/libexec/uucp/libunix/cusub.c
new file mode 100644
index 0000000..4cee888
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/cusub.c
@@ -0,0 +1,1163 @@
+/* cusub.c
+ System dependent routines for cu.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 1993/08/04 19:32:09 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+#include "cu.h"
+#include "conn.h"
+#include "prot.h"
+
+#include <errno.h>
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Local variables. */
+
+/* The EOF character, as set by fsysdep_terminal_raw. */
+static char bSeof;
+
+/* The SUSP character, as set by fsysdep_terminal_raw. */
+static char bStstp;
+
+/* Local functions. */
+
+static const char *zsport_line P((const struct uuconf_port *qport));
+static void uscu_child P((struct sconnection *qconn, int opipe));
+static RETSIGTYPE uscu_alarm P((int isig));
+static int cscu_escape P((char *pbcmd, const char *zlocalname));
+static RETSIGTYPE uscu_alarm_kill P((int isig));
+
+/* Return the device name for a port, or NULL if none. */
+
+static const char *
+zsport_line (qport)
+ const struct uuconf_port *qport;
+{
+ const char *zline;
+
+ if (qport == NULL)
+ return NULL;
+
+ switch (qport->uuconf_ttype)
+ {
+ default:
+ case UUCONF_PORTTYPE_STDIN:
+ return NULL;
+ case UUCONF_PORTTYPE_MODEM:
+ zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_DIRECT:
+ zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice;
+ break;
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ return NULL;
+ }
+
+ if (zline == NULL)
+ zline = qport->uuconf_zname;
+ return zline;
+}
+
+/* Check whether the user has legitimate access to a port. */
+
+boolean
+fsysdep_port_access (qport)
+ struct uuconf_port *qport;
+{
+ const char *zline;
+ char *zfree;
+ boolean fret;
+
+ zline = zsport_line (qport);
+ if (zline == NULL)
+ return TRUE;
+
+ zfree = NULL;
+ if (*zline != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree, "/dev/%s", zline);
+ zline = zfree;
+ }
+
+ fret = access (zline, R_OK | W_OK) == 0;
+ ubuffree (zfree);
+ return fret;
+}
+
+/* Return whether the given port is named by the given line. */
+
+boolean
+fsysdep_port_is_line (qport, zline)
+ struct uuconf_port *qport;
+ const char *zline;
+{
+ const char *zpline;
+ char *zfree1, *zfree2;
+ boolean fret;
+
+ zpline = zsport_line (qport);
+ if (zpline == NULL)
+ return FALSE;
+
+ if (strcmp (zline, zpline) == 0)
+ return TRUE;
+
+ zfree1 = NULL;
+ zfree2 = NULL;
+ if (*zline != '/')
+ {
+ zfree1 = zbufalc (sizeof "/dev/" + strlen (zline));
+ sprintf (zfree1, "/dev/%s", zline);
+ zline = zfree1;
+ }
+ if (*zpline != '/')
+ {
+ zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline));
+ sprintf (zfree2, "/dev/%s", zpline);
+ zpline = zfree2;
+ }
+
+ fret = strcmp (zline, zpline) == 0;
+ ubuffree (zfree1);
+ ubuffree (zfree2);
+ return fret;
+}
+
+/* The cu program wants the system dependent layer to handle the
+ details of copying data from the communications port to the
+ terminal. This copying need only be done while executing
+ fsysdep_cu. On Unix, however, we set up a subprocess to do it all
+ the time. This subprocess must be controllable via the
+ fsysdep_cu_copy function.
+
+ We keep a pipe open to the subprocess. When we want it to stop we
+ send it a signal, and then wait for it to write a byte to us over
+ the pipe. */
+
+/* The subprocess pid. */
+static volatile pid_t iSchild;
+
+/* The pipe from the subprocess. */
+static int oSpipe;
+
+/* When we tell the child to stop, it sends this. */
+#define CHILD_STOPPED ('S')
+
+/* When we tell the child to start, it sends this. */
+#define CHILD_STARTED ('G')
+
+/* Initialize the subprocess, and have it start copying data. */
+
+boolean
+fsysdep_cu_init (qconn)
+ struct sconnection *qconn;
+{
+ int ai[2];
+
+ /* Write out anything we may have buffered up during the chat
+ script. We do this before forking the child only to make it easy
+ to move the child into a separate executable. */
+ while (iPrecend != iPrecstart)
+ {
+ char *z;
+ int c;
+
+ z = abPrecbuf + iPrecstart;
+ if (iPrecend > iPrecstart)
+ c = iPrecend - iPrecstart;
+ else
+ c = CRECBUFLEN - iPrecstart;
+
+ iPrecstart = (iPrecstart + c) % CRECBUFLEN;
+
+ while (c > 0)
+ {
+ int cwrote;
+
+ cwrote = write (1, z, c);
+ if (cwrote <= 0)
+ {
+ if (cwrote < 0)
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ c -= cwrote;
+ z += cwrote;
+ }
+ }
+
+ if (pipe (ai) < 0)
+ {
+ ulog (LOG_ERROR, "pipe: %s", strerror (errno));
+ return FALSE;
+ }
+
+ iSchild = ixsfork ();
+ if (iSchild < 0)
+ {
+ ulog (LOG_ERROR, "fork: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (iSchild == 0)
+ {
+ (void) close (ai[0]);
+ uscu_child (qconn, ai[1]);
+ /*NOTREACHED*/
+ }
+
+ (void) close (ai[1]);
+
+ oSpipe = ai[0];
+
+ return TRUE;
+}
+
+/* Copy all data from the terminal to the communications port. If we
+ see an escape character following a newline character, read the
+ next character and return it. */
+
+boolean
+fsysdep_cu (qconn, pbcmd, zlocalname)
+ struct sconnection *qconn;
+ char *pbcmd;
+ const char *zlocalname;
+{
+ boolean fstart;
+ char b;
+ int c;
+
+ fstart = TRUE;
+
+ while (TRUE)
+ {
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+ else
+ {
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ c = read (0, &b, 1);
+
+ usysdep_end_catch ();
+
+ if (c <= 0)
+ break;
+
+ if (fstart && b == *zCuvar_escape)
+ {
+ c = cscu_escape (pbcmd, zlocalname);
+ if (c <= 0)
+ break;
+ if (*pbcmd != b)
+ {
+ write (1, pbcmd, 1);
+
+ /* For Unix, we let the eof character be the same as
+ '.', and we let the suspend character (if any) be the
+ same as 'z'. */
+ if (*pbcmd == bSeof)
+ *pbcmd = '.';
+ if (*pbcmd == bStstp)
+ *pbcmd = 'z';
+ return TRUE;
+ }
+ }
+ if (! fconn_write (qconn, &b, (size_t) 1))
+ return FALSE;
+ fstart = strchr (zCuvar_eol, b) != NULL;
+ }
+
+ if (c < 0)
+ {
+ if (errno != EINTR)
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ else
+ ulog (LOG_ERROR, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* I'm not sure what's best in this case. */
+ ulog (LOG_ERROR, "End of file on terminal");
+ return FALSE;
+}
+
+/* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */
+
+volatile sig_atomic_t fScu_alarm;
+
+static RETSIGTYPE
+uscu_alarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm);
+#endif
+
+ fScu_alarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif
+}
+
+/* We've just seen an escape character. We print the host name,
+ optionally after a 1 second delay. We read the next character from
+ the terminal and return it. The 1 second delay on the host name is
+ mostly to be fancy; it lets ~~ look smoother. */
+
+static int
+cscu_escape (pbcmd, zlocalname)
+ char *pbcmd;
+ const char *zlocalname;
+{
+ CATCH_PROTECT int c;
+
+ write (1, zCuvar_escape, 1);
+
+ fScu_alarm = FALSE;
+ usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL);
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ alarm (1);
+ }
+
+ c = 0;
+
+ while (TRUE)
+ {
+ if (fScu_alarm)
+ {
+ char b;
+
+ fScu_alarm = FALSE;
+ b = '[';
+ write (1, &b, 1);
+ write (1, zlocalname, strlen (zlocalname));
+ b = ']';
+ write (1, &b, 1);
+ }
+
+ if (c <= 0)
+ c = read (0, pbcmd, 1);
+ if (c >= 0 || errno != EINTR)
+ {
+ usysdep_end_catch ();
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ return c;
+ }
+ }
+}
+
+/* A SIGALRM handler which does nothing but send a signal to the child
+ process and schedule another alarm. POSIX.1 permits kill and alarm
+ from a signal handler. The reference to static data may or may not
+ be permissible. */
+
+static volatile sig_atomic_t iSsend_sig;
+
+static RETSIGTYPE
+uscu_alarm_kill (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_alarm_kill);
+#endif
+
+ (void) kill (iSchild, iSsend_sig);
+
+ alarm (1);
+}
+
+/* Start or stop copying data from the communications port to the
+ terminal. We send a signal to the child process to tell it what to
+ do. Unfortunately, there are race conditions in the child, so we
+ keep sending it a signal once a second until it responds. We send
+ SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */
+
+boolean
+fsysdep_cu_copy (fcopy)
+ boolean fcopy;
+{
+ int ierr;
+ int c;
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ if (fcopy)
+ iSsend_sig = SIGUSR1;
+ else
+ iSsend_sig = SIGUSR2;
+
+ uscu_alarm_kill (SIGALRM);
+
+ alarm (1);
+
+ while (TRUE)
+ {
+ char b;
+
+ c = read (oSpipe, &b, 1);
+
+#if DEBUG > 1
+ if (c > 0)
+ DEBUG_MESSAGE1 (DEBUG_INCOMING,
+ "fsysdep_cu_copy: Got '%d'", b);
+#endif
+
+ if ((c < 0 && errno != EINTR)
+ || c == 0
+ || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED)))
+ break;
+
+ /* If none of the above conditions were true, then we either got
+ an EINTR error, in which case we probably timed out and the
+ SIGALRM handler resent the signal, or we read the wrong
+ character, in which case we will just read again from the
+ pipe. */
+ }
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ if (c > 0)
+ return TRUE;
+
+ if (c == 0)
+ ulog (LOG_ERROR, "EOF on child pipe");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+
+ return FALSE;
+}
+
+/* Shut down cu by killing the child process. */
+
+boolean
+fsysdep_cu_finish ()
+{
+ (void) close (oSpipe);
+
+ /* We hit the child with SIGTERM, give it two seconds to die, and
+ then send a SIGKILL. */
+ if (kill (iSchild, SIGTERM) < 0)
+ {
+ /* Don't give an error if the child has already died. */
+ if (errno != ESRCH)
+ ulog (LOG_ERROR, "kill: %s", strerror (errno));
+ }
+
+ usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL);
+ iSsend_sig = SIGKILL;
+ alarm (2);
+
+ (void) ixswait ((unsigned long) iSchild, "child");
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+
+ return TRUE;
+}
+
+/* Code for the child process. */
+
+/* This signal handler just records the signal. In this case we only
+ care about which signal we received most recently. */
+
+static volatile sig_atomic_t iSchild_sig;
+
+static RETSIGTYPE
+uscu_child_handler (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, uscu_child_handler);
+#endif
+
+ iSchild_sig = isig;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* The child process. This copies the port to the terminal, except
+ when it is stopped by a signal. It would be reasonable to write a
+ separate program for this, probably passing it the port on stdin.
+ This would reduce the memory requirements, since we wouldn't need a
+ second process holding all the configuration stuff, and also let it
+ work reasonably on 680x0 versions of MINIX. */
+
+static void
+uscu_child (qconn, opipe)
+ struct sconnection *qconn;
+ int opipe;
+{
+ CATCH_PROTECT int oport;
+ CATCH_PROTECT boolean fstopped, fgot;
+ CATCH_PROTECT int cwrite;
+ CATCH_PROTECT char abbuf[1024];
+
+ /* It would be nice if we could just use fsserial_read, but that
+ will log signals that we don't want logged. There should be a
+ generic way to extract the file descriptor from the port. */
+ if (qconn->qport == NULL)
+ oport = 0;
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+#if DEBUG > 0
+ default:
+ ulog (LOG_FATAL, "uscu_child: Can't happen");
+ oport = -1;
+ break;
+#endif
+ case UUCONF_PORTTYPE_STDIN:
+ oport = 0;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oport = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL);
+ usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL);
+ usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL);
+ usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL);
+
+ fstopped = FALSE;
+ fgot = FALSE;
+ iSchild_sig = 0;
+ cwrite = 0;
+
+ if (fsysdep_catch ())
+ usysdep_start_catch ();
+
+ while (TRUE)
+ {
+ int isig;
+ int c;
+
+ /* There is a race condition here between checking the signal
+ and receiving a new and possibly different one. This is
+ solved by having the parent resend the signal until it gets a
+ response. */
+ isig = iSchild_sig;
+ iSchild_sig = 0;
+ if (isig != 0)
+ {
+ char b;
+
+ if (isig == SIGTERM)
+ exit (EXIT_SUCCESS);
+
+ if (isig == SIGUSR1)
+ {
+ fstopped = FALSE;
+ b = CHILD_STARTED;
+ }
+ else
+ {
+ fstopped = TRUE;
+ b = CHILD_STOPPED;
+ cwrite = 0;
+ }
+
+ c = write (opipe, &b, 1);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (fstopped)
+ pause ();
+ else if (cwrite > 0)
+ {
+ char *zbuf;
+
+ zbuf = abbuf;
+ while (cwrite > 0)
+ {
+ c = write (1, zbuf, cwrite);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN
+ || errno == EWOULDBLOCK
+ || errno == ENODATA))
+ c = 0;
+
+ if (c < 0 && errno == EINTR)
+ break;
+ if (c <= 0)
+ {
+ /* Should we give an error message here? */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_FAILURE);
+ }
+ cwrite -= c;
+ zbuf += c;
+ }
+ }
+ else
+ {
+ /* On some systems apparently read will return 0 until
+ something has been written to the port. We therefore
+ accept a 0 return until after we have managed to read
+ something. Setting errno to 0 apparently avoids a
+ problem on Coherent. */
+ errno = 0;
+ c = read (oport, abbuf, sizeof abbuf);
+
+ /* Apparently on some systems we can get EAGAIN here. */
+ if (c < 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA))
+ c = 0;
+
+ if ((c == 0 && fgot)
+ || (c < 0 && errno != EINTR))
+ {
+ /* This can be a normal way to exit, depending on just
+ how the connection is dropped. */
+ (void) kill (getppid (), SIGHUP);
+ exit (EXIT_SUCCESS);
+ }
+ if (c > 0)
+ {
+ fgot = TRUE;
+ cwrite = c;
+ }
+ }
+ }
+}
+
+/* Terminal control routines. */
+
+/* Whether file descriptor 0 is attached to a terminal or not. */
+static boolean fSterm;
+
+/* Whether we are doing local echoing. */
+static boolean fSlocalecho;
+
+/* The original state of the terminal. */
+static sterminal sSterm_orig;
+
+/* The new state of the terminal. */
+static sterminal sSterm_new;
+
+#if ! HAVE_BSD_TTY
+#ifdef SIGTSTP
+/* Whether SIGTSTP is being ignored. */
+static boolean fStstp_ignored;
+#endif
+#endif
+
+/* Set the terminal into raw mode. */
+
+boolean
+fsysdep_terminal_raw (flocalecho)
+ boolean flocalecho;
+{
+ fSlocalecho = flocalecho;
+
+ /* This defaults may be overriden below. */
+ bSeof = '\004';
+ bStstp = '\032';
+
+ if (! fgetterminfo (0, &sSterm_orig))
+ {
+ fSterm = FALSE;
+ return TRUE;
+ }
+
+ fSterm = TRUE;
+
+ sSterm_new = sSterm_orig;
+
+#if HAVE_BSD_TTY
+
+ /* We use CBREAK mode rather than RAW mode, because RAW mode turns
+ off all output processing, which we don't want to do. This means
+ that we have to disable the interrupt characters, which we do by
+ setting them to -1. */
+ bSeof = sSterm_orig.stchars.t_eofc;
+
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ sSterm_new.stchars.t_startc = -1;
+ sSterm_new.stchars.t_stopc = -1;
+ sSterm_new.stchars.t_eofc = -1;
+ sSterm_new.stchars.t_brkc = -1;
+
+ bStstp = sSterm_orig.sltchars.t_suspc;
+
+ sSterm_new.sltchars.t_suspc = -1;
+ sSterm_new.sltchars.t_dsuspc = -1;
+ sSterm_new.sltchars.t_rprntc = -1;
+ sSterm_new.sltchars.t_flushc = -1;
+ sSterm_new.sltchars.t_werasc = -1;
+ sSterm_new.sltchars.t_lnextc = -1;
+
+ if (! flocalecho)
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP);
+ sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM);
+ }
+ else
+ {
+ sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO);
+ sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM);
+ }
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ bSeof = sSterm_new.c_cc[VEOF];
+ bStstp = sSterm_new.c_cc[VSUSP];
+ if (! flocalecho)
+ sSterm_new.c_lflag &=~
+ (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL);
+ else
+ sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG);
+ sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL);
+ sSterm_new.c_oflag &=~ (OPOST);
+ sSterm_new.c_cc[VMIN] = 1;
+ sSterm_new.c_cc[VTIME] = 0;
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Restore the terminal to its original setting. */
+
+boolean
+fsysdep_terminal_restore ()
+{
+ if (! fSterm)
+ return TRUE;
+
+ if (! fsetterminfo (0, &sSterm_orig))
+ {
+ ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Read a line from the terminal. This will be called after
+ fsysdep_terminal_raw has been called. */
+
+char *
+zsysdep_terminal_line (zprompt)
+ const char *zprompt;
+{
+ CATCH_PROTECT size_t cbuf = 0;
+ CATCH_PROTECT char *zbuf = NULL;
+ CATCH_PROTECT size_t cgot = 0;
+
+ if (zprompt != NULL && *zprompt != '\0')
+ (void) write (1, zprompt, strlen (zprompt));
+
+ /* Forgot about any previous SIGINT or SIGQUIT signals we may have
+ received. We don't worry about the race condition here, since we
+ can't get these signals from the terminal at the moment and it's
+ not too likely that somebody else will be sending them to us. */
+ afSignal[INDEXSIG_SIGINT] = 0;
+ afSignal[INDEXSIG_SIGQUIT] = 0;
+
+ if (! fsysdep_terminal_restore ())
+ return NULL;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ cbuf = 0;
+ zbuf = NULL;
+ cgot = 0;
+ }
+
+ while (TRUE)
+ {
+ char b;
+ int c;
+
+ if (afSignal[INDEXSIG_SIGINT]
+ || afSignal[INDEXSIG_SIGQUIT])
+ {
+ usysdep_end_catch ();
+ /* Make sure the signal is logged. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ /* Return an empty string. */
+ cgot = 0;
+ break;
+ }
+
+ /* There's a race here between checking the signals and calling
+ read. It just means that the user will have to hit ^C more
+ than once. */
+
+ c = read (0, &b, 1);
+ if (c < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+ if (c == 0)
+ {
+ /* I'm not quite sure what to do here. */
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "EOF on terminal");
+ (void) fsysdep_terminal_raw (fSlocalecho);
+ return NULL;
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ cbuf += 64;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = b;
+
+ ++cgot;
+
+ if (b == '\n')
+ {
+ usysdep_end_catch ();
+ break;
+ }
+ }
+
+ if (cgot >= cbuf)
+ {
+ char *znew;
+
+ ++cbuf;
+ znew = zbufalc (cbuf);
+ if (zbuf != NULL)
+ {
+ memcpy (znew, zbuf, cgot);
+ ubuffree (zbuf);
+ }
+ zbuf = znew;
+ }
+
+ zbuf[cgot] = '\0';
+
+ if (! fsysdep_terminal_raw (fSlocalecho))
+ return NULL;
+
+ return zbuf;
+}
+
+/* Write a line to the terminal with a trailing newline. */
+
+boolean
+fsysdep_terminal_puts (zline)
+ const char *zline;
+{
+ char *zalc, *zprint;
+ size_t clen;
+
+ if (zline == NULL)
+ {
+ zalc = zbufalc (2);
+ clen = 0;
+ }
+ else
+ {
+ clen = strlen (zline);
+ zalc = zbufalc (clen + 2);
+ memcpy (zalc, zline, clen);
+ }
+
+ if (fSterm)
+ {
+ zalc[clen] = '\r';
+ ++clen;
+ }
+ zalc[clen] = '\n';
+ ++clen;
+
+ zprint = zalc;
+ while (clen > 0)
+ {
+ int c;
+
+ c = write (1, zprint, clen);
+ if (c <= 0)
+ {
+ ubuffree (zalc);
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ clen -= c;
+ zprint += c;
+ }
+
+ ubuffree (zalc);
+
+ return TRUE;
+}
+
+/* Allow or disallow signals from the terminal. */
+
+boolean
+fsysdep_terminal_signals (faccept)
+ boolean faccept;
+{
+#if HAVE_BSD_TTY
+
+ if (faccept)
+ {
+ sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc;
+ sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc;
+ }
+ else
+ {
+ sSterm_new.stchars.t_intrc = -1;
+ sSterm_new.stchars.t_quitc = -1;
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ if (faccept)
+ sSterm_new.c_lflag |= ISIG;
+ else
+ sSterm_new.c_lflag &=~ ISIG;
+
+#ifdef SIGTSTP
+ /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This
+ function will be called with faccept TRUE before it is called
+ with faccept FALSE, so fStstp_ignored will be correctly
+ initialized. */
+ if (faccept)
+ usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored);
+ else if (! fStstp_ignored)
+ usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL);
+#endif
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (! fsetterminfo (0, &sSterm_new))
+ {
+ ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Start up a command, or possibly just a shell. Optionally attach
+ stdin or stdout to the port. We attach directly to the port,
+ rather than copying the data ourselves. */
+
+boolean
+fsysdep_shell (qconn, zcmd, tcmd)
+ struct sconnection *qconn;
+ const char *zcmd;
+ enum tshell_cmd tcmd;
+{
+ const char *azargs[4];
+ int oread, owrite;
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/bin/sh";
+ if (zcmd == NULL || *zcmd == '\0')
+ azargs[1] = NULL;
+ else
+ {
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+ }
+
+ if (qconn->qport == NULL)
+ {
+ oread = 0;
+ owrite = 1;
+ }
+ else
+ {
+ switch (qconn->qport->uuconf_ttype)
+ {
+ default:
+ oread = owrite = -1;
+ break;
+ case UUCONF_PORTTYPE_STDIN:
+ oread = 0;
+ owrite = 1;
+ break;
+ case UUCONF_PORTTYPE_MODEM:
+ case UUCONF_PORTTYPE_DIRECT:
+ case UUCONF_PORTTYPE_TCP:
+ case UUCONF_PORTTYPE_TLI:
+ oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o;
+ break;
+ }
+ }
+
+ aidescs[0] = 0;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[0] = oread;
+ if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT)
+ aidescs[1] = owrite;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL,
+ FALSE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, "shell") == 0;
+}
+
+/* Change directories. */
+
+boolean
+fsysdep_chdir (zdir)
+ const char *zdir;
+{
+ if (zdir == NULL || *zdir == '\0')
+ {
+ zdir = getenv ("HOME");
+ if (zdir == NULL)
+ {
+ ulog (LOG_ERROR, "HOME not defined");
+ return FALSE;
+ }
+ }
+ if (chdir (zdir) < 0)
+ {
+ ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Suspend the current process. */
+
+boolean
+fsysdep_suspend ()
+{
+#ifndef SIGTSTP
+ return fsysdep_terminal_puts ("[process suspension not supported]");
+#else
+ return kill (getpid (), SIGTSTP) == 0;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/cwd.c b/gnu/libexec/uucp/libunix/cwd.c
new file mode 100644
index 0000000..433025d
--- /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 0000000..41e1969
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/detach.c
@@ -0,0 +1,186 @@
+/* detach.c
+ Detach from the controlling terminal.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef TIOCNOTTY
+#define HAVE_TIOCNOTTY 1
+#else
+#define HAVE_TIOCNOTTY 0
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+/* Detach from the controlling terminal. This is called by uucico if
+ it is calling out to another system, so that it can receive SIGHUP
+ signals from the port it calls out on. It is also called by uucico
+ just before it starts uuxqt, so that uuxqt is completely
+ independent of the terminal. */
+
+void
+usysdep_detach ()
+{
+#if ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY
+
+ pid_t igrp;
+
+ /* First make sure we are not a process group leader. If we have
+ TIOCNOTTY, this doesn't matter, since TIOCNOTTY sets our process
+ group to 0 anyhow. */
+
+#if HAVE_BSD_PGRP
+ igrp = getpgrp (0);
+#else
+ igrp = getpgrp ();
+#endif
+
+ if (igrp == getpid ())
+ {
+ boolean fignored;
+ pid_t ipid;
+
+ /* Ignore SIGHUP, since our process group leader is about to
+ die. */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored);
+
+ ipid = ixsfork ();
+ if (ipid < 0)
+ ulog (LOG_FATAL, "fork: %s", strerror (errno));
+
+ if (ipid != 0)
+ _exit (EXIT_SUCCESS);
+
+ /* We'll always wind up as a child of process number 1, right?
+ Right? We have to wait for our parent to die before
+ reenabling SIGHUP. */
+ while (getppid () != 1)
+ sleep (1);
+
+ ulog_id (getpid ());
+
+ /* Restore SIGHUP catcher if it wasn't being ignored. */
+ if (! fignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+#endif /* ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY */
+
+#if HAVE_TIOCNOTTY
+ /* Lose the original controlling terminal. If standard input has
+ been reopened to /dev/null, this will do no harm. If another
+ port has been opened to become the controlling terminal, it
+ should have been detached when it was closed. */
+ (void) ioctl (0, TIOCNOTTY, (char *) NULL);
+#endif
+
+ /* Close stdin, stdout and stderr and reopen them on /dev/null, to
+ make sure we have no connection at all to the terminal. */
+ (void) close (0);
+ (void) close (1);
+ (void) close (2);
+ if (open ((char *) "/dev/null", O_RDONLY) != 0
+ || open ((char *) "/dev/null", O_WRONLY) != 1
+ || open ((char *) "/dev/null", O_WRONLY) != 2)
+ ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno));
+
+#if HAVE_BSD_PGRP
+
+ /* Make sure our process group ID is set to 0. On BSD TIOCNOTTY
+ should already have set it 0, so this will do no harm. On System
+ V we presumably did not execute the TIOCNOTTY call, but the
+ System V setpgrp will detach the controlling terminal anyhow.
+ This lets us use the same code on both BSD and System V, provided
+ it compiles correctly, which life easier for the configure
+ script. We don't output an error if we got EPERM because some
+ BSD variants don't permit this usage of setpgrp (which means they
+ don't provide any way to pick up a new controlling terminal). */
+
+ if (setpgrp (0, 0) < 0)
+ {
+ if (errno != EPERM)
+ ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
+ }
+
+#else /* ! HAVE_BSD_PGRP */
+
+#if HAVE_SETSID
+
+ /* Under POSIX the setsid call creates a new session for which we
+ are the process group leader. It also detaches us from our
+ controlling terminal. I'm using the BSD setpgrp call first
+ because they should be equivalent for my purposes, but it turns
+ out that on Ultrix 4.0 setsid prevents us from ever acquiring
+ another controlling terminal (it does not change our process
+ group, and Ultrix 4.0 prevents us from setting our process group
+ to 0). */
+ (void) setsid ();
+
+#else /* ! HAVE_SETSID */
+
+#if HAVE_SETPGRP
+
+ /* Now we assume we have the System V setpgrp, which takes no
+ arguments, and we couldn't compile the HAVE_BSD_PGRP code above
+ because there was a prototype somewhere in scope. On System V
+ setpgrp makes us the leader of a new process group and also
+ detaches the controlling terminal. */
+
+ if (setpgrp () < 0)
+ ulog (LOG_ERROR, "setpgrp: %s", strerror (errno));
+
+#else /* ! HAVE_SETPGRP */
+
+ #error Must detach from controlling terminal
+
+#endif /* HAVE_SETPGRP */
+#endif /* ! HAVE_SETSID */
+#endif /* ! HAVE_BSD_PGRP */
+
+ /* At this point we have completely detached from our controlling
+ terminal. The next terminal device we open will probably become
+ our controlling terminal. */
+}
diff --git a/gnu/libexec/uucp/libunix/dirent.c b/gnu/libexec/uucp/libunix/dirent.c
new file mode 100644
index 0000000..83db496c
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dirent.c
@@ -0,0 +1,123 @@
+/* dirent.c
+ Replacements for opendir, readdir and closedir for the original
+ Unix filesystem only.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Simple emulations of opendir/readdir/closedir for systems which
+ have the original format of Unix directories. It's probably better
+ to get Doug Gwyn's public domain set of emulation functions. */
+
+DIR *
+opendir (zdir)
+ const char *zdir;
+{
+ int o;
+ struct stat s;
+ DIR *qret;
+
+ o = open ((char *) zdir, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ return NULL;
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0
+ || fstat (o, &s) < 0)
+ {
+ int isave;
+
+ isave = errno;
+ (void) close (o);
+ errno = isave;
+ return NULL;
+ }
+ if (! S_ISDIR (s.st_mode))
+ {
+ (void) close (o);
+ errno = ENOTDIR;
+ return NULL;
+ }
+ qret = (DIR *) xmalloc (sizeof (DIR));
+ qret->o = o;
+ return qret;
+}
+
+struct dirent *
+readdir (q)
+ DIR *q;
+{
+ struct direct sdir;
+ int cgot;
+
+ do
+ {
+ cgot = read (q->o, &sdir, sizeof (struct direct));
+ if (cgot <= 0)
+ return NULL;
+ if (cgot != sizeof (struct direct))
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ while (sdir.d_ino == 0);
+
+ strncpy (q->s.d_name, sdir.d_name, DIRSIZ);
+ q->s.d_name[DIRSIZ] = '\0';
+ return &q->s;
+}
+
+int
+closedir (q)
+ DIR *q;
+{
+ int o;
+
+ o = q->o;
+ xfree (q);
+ return close (o);
+}
diff --git a/gnu/libexec/uucp/libunix/dup2.c b/gnu/libexec/uucp/libunix/dup2.c
new file mode 100644
index 0000000..6a7359f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/dup2.c
@@ -0,0 +1,69 @@
+/* dup2.c
+ The Unix dup2 function, for systems which only have dup.
+
+ Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* I basically took this from the emacs 18.57 distribution, although I
+ cleaned it up a bit and made it POSIX compliant. */
+
+int
+dup2 (oold, onew)
+ int oold;
+ int onew;
+{
+ if (oold == onew)
+ return onew;
+ (void) close (onew);
+
+#ifdef F_DUPFD
+ return fcntl (oold, F_DUPFD, onew);
+#else
+ {
+ int onext, oret, isave;
+
+ onext = dup (oold);
+ if (onext == onew)
+ return onext;
+ if (onext < 0)
+ return -1;
+ oret = dup2 (oold, onew);
+ isave = errno;
+ (void) close (onext);
+ errno = isave;
+ return oret;
+ }
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/efopen.c b/gnu/libexec/uucp/libunix/efopen.c
new file mode 100644
index 0000000..7e360b6
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/efopen.c
@@ -0,0 +1,132 @@
+/* efopen.c
+ Open a stdio file with appropriate permissions. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_APPEND
+#ifdef FAPPEND
+#define O_APPEND FAPPEND
+#endif
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+FILE *
+esysdep_fopen (zfile, fpublic, fappend, fmkdirs)
+ const char *zfile;
+ boolean fpublic;
+ boolean fappend;
+ boolean fmkdirs;
+{
+ int imode;
+ int o;
+ FILE *e;
+
+ if (fpublic)
+ imode = IPUBLIC_FILE_MODE;
+ else
+ imode = IPRIVATE_FILE_MODE;
+
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = open ((char *) zfile, O_WRONLY | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ o = creat ((char *) zfile, imode);
+#endif /* ! defined (O_CREAT) */
+ }
+
+ if (o < 0)
+ {
+ if (errno == ENOENT && fmkdirs)
+ {
+ if (! fsysdep_make_dirs (zfile, fpublic))
+ return NULL;
+ if (! fappend)
+ o = creat ((char *) zfile, imode);
+ else
+ {
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY,
+ imode);
+#else
+ o = creat ((char *) zfile, imode);
+#endif
+ }
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ }
+
+#ifndef O_CREAT
+#ifdef O_APPEND
+ if (fappend)
+ {
+ if (fcntl (o, F_SETFL, O_APPEND) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+ }
+#endif /* defined (O_APPEND) */
+#endif /* ! defined (O_CREAT) */
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile,
+ strerror (errno));
+ (void) close (o);
+ return NULL;
+ }
+
+ if (fappend)
+ e = fdopen (o, (char *) "a");
+ else
+ e = fdopen (o, (char *) "w");
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (o);
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/epopen.c b/gnu/libexec/uucp/libunix/epopen.c
new file mode 100644
index 0000000..dec1b39
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/epopen.c
@@ -0,0 +1,85 @@
+/* epopen.c
+ A version of popen that goes through ixsspawn.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* A version of popen that goes through ixsspawn. This actually takes
+ an array of arguments rather than a string, and takes a boolean
+ read/write value rather than a string. It sets *pipid to the
+ process ID of the child. */
+
+FILE *
+espopen (pazargs, frd, pipid)
+ const char **pazargs;
+ boolean frd;
+ pid_t *pipid;
+{
+ int aidescs[3];
+ pid_t ipid;
+ FILE *eret;
+
+ if (frd)
+ {
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_READ_PIPE;
+ }
+ else
+ {
+ aidescs[0] = SPAWN_WRITE_PIPE;
+ aidescs[1] = SPAWN_NULL;
+ }
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ return NULL;
+
+ if (frd)
+ eret = fdopen (aidescs[1], (char *) "r");
+ else
+ eret = fdopen (aidescs[0], (char *) "w");
+ if (eret == NULL)
+ {
+ int ierr;
+
+ ierr = errno;
+ (void) close (frd ? aidescs[1] : aidescs[0]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ errno = ierr;
+ return NULL;
+ }
+
+ *pipid = ipid;
+
+ return eret;
+}
diff --git a/gnu/libexec/uucp/libunix/exists.c b/gnu/libexec/uucp/libunix/exists.c
new file mode 100644
index 0000000..9473922
--- /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 0000000..6205476
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/filnam.c
@@ -0,0 +1,376 @@
+/* filnam.c
+ Get names to use for UUCP files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+/* We need a definition for SEEK_SET. */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+#define ZCHARS \
+ "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+/* Local functions. */
+
+static boolean fscmd_seq P((const char *zsystem, char *zseq));
+static char *zsfile_name P((int btype, const char *zsystem,
+ const char *zlocalname, int bgrade,
+ boolean fxqt, char *ztname, char *zdname,
+ char *zxname));
+
+/* Get a new command sequence number (this is not a sequence number to
+ be used for communicating with another system, but a sequence
+ number to be used when generating the name of a command file).
+ The sequence number is placed into zseq, which should be five
+ characters long. */
+
+static boolean
+fscmd_seq (zsystem, zseq)
+ const char *zsystem;
+ char *zseq;
+{
+ boolean ferr;
+ char *zfree;
+ const char *zfile;
+ int o;
+ int i;
+
+ /* Lock the sequence file. This may not be correct for all systems,
+ but it only matters if the system UUCP and this UUCP are running
+ at the same time. */
+ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr))
+ {
+ if (ferr || FGOT_SIGNAL ())
+ return FALSE;
+ sleep (5);
+ }
+
+ zfree = NULL;
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ zfile = "SEQF";
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zfree = zsysdep_in_dir (".Sequence", zsystem);
+ zfile = zfree;
+#endif
+#if SPOOLDIR_ULTRIX
+ if (! fsultrix_has_spool (zsystem))
+ zfile = "sys/DEFAULT/.SEQF";
+ else
+ {
+ zfree = zsappend3 ("sys", zsystem, ".SEQF");
+ zfile = zfree;
+ }
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ zfree = zsysdep_in_dir (zsystem, "SEQF");
+ zfile = zfree;
+#endif /* SPOOLDIR_TAYLOR */
+
+#ifdef O_CREAT
+ o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE);
+#else
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ if (o < 0 && errno == ENOENT)
+ {
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+ }
+#endif
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zfile, FALSE))
+ {
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+#ifdef O_CREAT
+ o = open ((char *) zfile,
+ O_RDWR | O_CREAT | O_NOCTTY,
+ IPUBLIC_FILE_MODE);
+#else
+ o = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ if (o >= 0)
+ {
+ (void) close (o);
+ o = open ((char *) zfile, O_RDWR | O_NOCTTY);
+ }
+#endif
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+ }
+
+ if (read (o, zseq, CSEQLEN) != CSEQLEN)
+ strcpy (zseq, "0000");
+ zseq[CSEQLEN] = '\0';
+
+ /* We must add one to the sequence number and return the new value.
+ On Ultrix, arbitrary characters are allowed in the sequence
+ number. On other systems, the sequence number apparently must be
+ in hex. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_HDB || SPOOLDIR_SVR4
+ i = (int) strtol (zseq, (char **) NULL, 16);
+ ++i;
+ if (i > 0xffff)
+ i = 0;
+ /* The sprintf argument has CSEQLEN built into it. */
+ sprintf (zseq, "%04x", (unsigned int) i);
+#endif
+#if SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR
+ for (i = CSEQLEN - 1; i >= 0; i--)
+ {
+ const char *zdig;
+
+ zdig = strchr (ZCHARS, zseq[i]);
+ if (zdig == NULL || zdig[0] == '\0' || zdig[1] == '\0')
+ zseq[i] = '0';
+ else
+ {
+ zseq[i] = zdig[1];
+ break;
+ }
+ }
+#endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */
+
+ if (lseek (o, (off_t) 0, SEEK_SET) < 0
+ || write (o, zseq, CSEQLEN) != CSEQLEN
+ || close (o) < 0)
+ {
+ ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno));
+ (void) close (o);
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+ return FALSE;
+ }
+
+ (void) fsdo_unlock ("LCK..SEQ", TRUE);
+
+ return TRUE;
+}
+
+/* Get the name of a command or data file for a remote system. The
+ btype argument should be C for a command file or D for a data file.
+ If the grade of a data file is X, it is assumed that this is going
+ to become an execute file on some other system. The zsystem
+ argument is the system that the file will be transferred to. The
+ ztname argument will be set to a file name that could be passed to
+ zsysdep_spool_file_name. The zdname argument, if not NULL, will be
+ set to a data file name appropriate for the remote system. The
+ zxname argument, if not NULL, will be set to the name of an execute
+ file on the remote system. None of the names will be more than 14
+ characters long. */
+
+/*ARGSUSED*/
+static char *
+zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname)
+ int btype;
+ const char *zsystem;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ char abseq[CSEQLEN + 1];
+ char absimple[11 + CSEQLEN];
+ char *zname;
+
+ if (zlocalname == NULL)
+ zlocalname = zSlocalname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zsystem, abseq))
+ return NULL;
+
+ if (btype == 'C')
+ {
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq);
+#else
+ sprintf (absimple, "C.%c%s", bgrade, abseq);
+#endif
+ }
+ else if (btype == 'D')
+ {
+ /* This name doesn't really matter that much; it's just the
+ name we use on the local system. The name we use on the
+ remote system, which we return in zdname, should contain
+ our system name so that remote UUCP's running SPOOLDIR_V2
+ and the like can distinguish while files come from which
+ systems. */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq);
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+#if ! SPOOLDIR_TAYLOR
+ sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+#else /* SPOOLDIR_TAYLOR */
+ if (fxqt)
+ sprintf (absimple, "D.X%s", abseq);
+ else
+ sprintf (absimple, "D.%s", abseq);
+#endif /* SPOOLDIR_TAYLOR */
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+ }
+#if DEBUG > 0
+ else
+ ulog (LOG_FATAL, "zsfile_name: Can't happen");
+#endif
+
+ zname = zsfind_file (absimple, zsystem, bgrade);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ if (ztname != NULL)
+ strcpy (ztname, absimple);
+
+ if (zdname != NULL)
+ sprintf (zdname, "D.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ if (zxname != NULL)
+ sprintf (zxname, "X.%.7s%c%s", zlocalname, bgrade, abseq);
+
+ return zname;
+}
+
+/* Return a name to use for a data file to be copied to another
+ system. The name returned will be for a real file. The zlocalname
+ argument is the local name as seen by the remote system, the bgrade
+ argument is the file grade, and the fxqt argument is TRUE if this
+ file will become an execution file. The ztname argument, if not
+ NULL, will be set to a name that could be passed to
+ zsysdep_spool_file_name to get back the return value of this
+ function. The zdname argument, if not NULL, will be set to a name
+ that the file could be given on another system. The zxname
+ argument, if not NULL, will be set to a name for an execute file on
+ another system. */
+
+char *
+zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname,
+ zxname)
+ const struct uuconf_system *qsys;
+ const char *zlocalname;
+ int bgrade;
+ boolean fxqt;
+ char *ztname;
+ char *zdname;
+ char *zxname;
+{
+ return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt,
+ ztname, zdname, zxname);
+}
+
+/* Get a command file name. */
+
+char *
+zscmd_file (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL,
+ bgrade, FALSE, (char *) NULL, (char *) NULL,
+ (char *) NULL);
+}
+
+/* Return a name for an execute file to be created locally. This is
+ used by uux to execute a command locally with remote files. */
+
+char *
+zsysdep_xqt_file_name ()
+{
+ char abseq[CSEQLEN + 1];
+ char absx[11 + CSEQLEN];
+ char *zname;
+
+ while (TRUE)
+ {
+ if (! fscmd_seq (zSlocalname, abseq))
+ return NULL;
+
+ sprintf (absx, "X.%.7sX%s", zSlocalname, abseq);
+
+ zname = zsfind_file (absx, zSlocalname, -1);
+ if (zname == NULL)
+ return NULL;
+
+ if (! fsysdep_file_exists (zname))
+ break;
+
+ ubuffree (zname);
+ }
+
+ return zname;
+}
diff --git a/gnu/libexec/uucp/libunix/fsusg.c b/gnu/libexec/uucp/libunix/fsusg.c
new file mode 100644
index 0000000..e2b40a8
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/fsusg.c
@@ -0,0 +1,231 @@
+/* fsusage.c -- return space usage of mounted filesystems
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file was modified slightly by Ian Lance Taylor, December 1992,
+ for use with Taylor UUCP. */
+
+#include "uucp.h"
+#include "sysdep.h"
+#include "fsusg.h"
+
+int statfs ();
+
+#if STAT_STATFS2_BSIZE
+#ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */
+#include <sys/vfs.h>
+#endif
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+#include <sys/mount.h>
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if STAT_USTAT /* SVR2 and others. */
+#include <ustat.h>
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+#include <sys/statfs.h>
+#endif
+#ifdef _AIX
+#ifdef _IBMR2 /* AIX RS6000. */
+#include <sys/statfs.h>
+#endif
+#endif
+
+#ifdef _AIX
+#ifdef _I386 /* AIX PS/2. */
+#include <sys/stat.h>
+#include <sys/dustat.h>
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+#include <sys/statvfs.h>
+int statvfs ();
+#endif
+
+#define STAT_NONE 0
+
+#if ! STAT_STATVFS
+#if ! STAT_STATFS2_BSIZE
+#if ! STAT_STATFS2_FSIZE
+#if ! STAT_STATFS2_FS_DATA
+#if ! STAT_STATFS4
+#if ! STAT_USTAT
+#undef STAT_NONE
+#define STAT_NONE 1
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+#if ! STAT_NONE
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding up. */
+
+static long
+adjust_blocks (blocks, fromsize, tosize)
+ long blocks;
+ int fromsize, tosize;
+{
+ if (fromsize == tosize) /* E.g., from 512 to 512. */
+ return blocks;
+ else if (fromsize > tosize) /* E.g., from 2048 to 512. */
+ return blocks * (fromsize / tosize);
+ else /* E.g., from 256 to 512. */
+ return (blocks + 1) / (tosize / fromsize);
+}
+
+#endif
+
+/* Fill in the fields of FSP with information about space usage for
+ the filesystem on which PATH resides.
+ DISK is the device on which PATH is mounted, for space-getting
+ methods that need to know it.
+ Return 0 if successful, -1 if not. */
+
+int
+get_fs_usage (path, disk, fsp)
+ char *path, *disk;
+ struct fs_usage *fsp;
+{
+#if STAT_NONE
+ return -1;
+#endif
+
+#if STAT_STATFS2_FS_DATA /* Ultrix. */
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
+ fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
+ fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
+ fsp->fsu_files = fsd.fd_req.gtot;
+ fsp->fsu_ffree = fsd.fd_req.gfree;
+#endif
+
+#if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
+#endif
+
+#if STAT_STATFS2_FSIZE /* 4.4BSD. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
+#endif
+
+#if STAT_STATFS4 /* SVR3, Dynix, Irix. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+#define convert_blocks(b) (b)
+#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
+#define f_bavail f_bfree
+#endif
+#endif
+
+#if STAT_STATVFS /* SVR4. */
+ struct statvfs fsd;
+
+ if (statvfs (path, &fsd) < 0)
+ return -1;
+ /* f_frsize isn't guaranteed to be supported. */
+#define convert_blocks(b) \
+ adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+#endif
+
+#if STAT_USTAT
+ {
+ struct stat sstat;
+ struct ustat s;
+
+ if (stat (path, &sstat) < 0
+ || ustat (sstat.st_dev, &s) < 0)
+ return -1;
+ fsp->fsu_blocks = -1;
+ fsp->fsu_bfree = f_tfree;
+ fsp->fsu_bavail = f_tfree;
+ fsp->fsu_files = -1;
+ fsp->fsu_ffree = -1;
+ }
+#endif
+
+#if ! STAT_STATFS2_FS_DATA /* ! Ultrix */
+#if ! STAT_USTAT
+#if ! STAT_NONE
+ fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
+ fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
+ fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
+ fsp->fsu_files = fsd.f_files;
+ fsp->fsu_ffree = fsd.f_ffree;
+#endif
+#endif
+#endif
+
+ return 0;
+}
+
+#ifdef _AIX
+#ifdef _I386
+/* AIX PS/2 does not supply statfs. */
+
+int
+statfs (path, fsb)
+ char *path;
+ struct statfs *fsb;
+{
+ struct stat stats;
+ struct dustat fsd;
+
+ if (stat (path, &stats))
+ return -1;
+ if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+ return -1;
+ fsb->f_type = 0;
+ fsb->f_bsize = fsd.du_bsize;
+ fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+ fsb->f_bfree = fsd.du_tfree;
+ fsb->f_bavail = fsd.du_tfree;
+ fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
+ fsb->f_ffree = fsd.du_tinode;
+ fsb->f_fsid.val[0] = fsd.du_site;
+ fsb->f_fsid.val[1] = fsd.du_pckno;
+ return 0;
+}
+#endif
+#endif /* _AIX && _I386 */
diff --git a/gnu/libexec/uucp/libunix/fsusg.h b/gnu/libexec/uucp/libunix/fsusg.h
new file mode 100644
index 0000000..8d4d054
--- /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 0000000..c3372b5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ftw.c
@@ -0,0 +1,250 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ian Lance Taylor (ian@airs.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+/* Traverse one level of a directory tree. */
+
+static int
+ftw_dir (dirs, level, descriptors, dir, len, func)
+ DIR **dirs;
+ int level;
+ int descriptors;
+ char *dir;
+ size_t len;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+{
+ int got;
+ struct dirent *entry;
+
+ got = 0;
+
+ errno = 0;
+
+ while ((entry = readdir (dirs[level])) != NULL)
+ {
+ size_t namlen;
+ struct stat s;
+ int flag, ret, newlev;
+
+ ++got;
+
+ namlen = strlen (entry->d_name);
+ if (entry->d_name[0] == '.'
+ && (namlen == 1 ||
+ (namlen == 2 && entry->d_name[1] == '.')))
+ {
+ errno = 0;
+ continue;
+ }
+
+ if (namlen + len + 1 > PATH_MAX)
+ {
+#ifdef ENAMETOOLONG
+ errno = ENAMETOOLONG;
+#else
+ errno = ENOMEM;
+#endif
+ return -1;
+ }
+
+ dir[len] = '/';
+ memcpy ((dir + len + 1), entry->d_name, namlen + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ newlev = (level + 1) % descriptors;
+
+ if (dirs[newlev] != NULL)
+ closedir (dirs[newlev]);
+
+ dirs[newlev] = opendir (dir);
+ if (dirs[newlev] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ return -1;
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (dir, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, newlev, descriptors, dir,
+ namlen + len + 1, func);
+ if (dirs[newlev] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[newlev]);
+ errno = save;
+ dirs[newlev] = NULL;
+ }
+ }
+
+ if (ret != 0)
+ return ret;
+
+ if (dirs[level] == NULL)
+ {
+ int skip;
+
+ dir[len] = '\0';
+ dirs[level] = opendir (dir);
+ if (dirs[level] == NULL)
+ return -1;
+ skip = got;
+ while (skip-- != 0)
+ {
+ errno = 0;
+ if (readdir (dirs[level]) == NULL)
+ return errno == 0 ? 0 : -1;
+ }
+ }
+
+ errno = 0;
+ }
+
+ return errno == 0 ? 0 : -1;
+}
+
+/* Call a function on every element in a directory tree. */
+
+int
+ftw (dir, func, descriptors)
+ const char *dir;
+ int (*func) P((const char *file, const struct stat *status, int flag));
+ int descriptors;
+{
+ DIR **dirs;
+ int c;
+ DIR **p;
+ size_t len;
+ char buf[PATH_MAX + 1];
+ struct stat s;
+ int flag, ret;
+
+ if (descriptors <= 0)
+ descriptors = 1;
+
+ dirs = (DIR **) malloc (descriptors * sizeof (DIR *));
+ if (dirs == NULL)
+ return -1;
+ c = descriptors;
+ p = dirs;
+ while (c-- != 0)
+ *p++ = NULL;
+
+ len = strlen (dir);
+ memcpy (buf, dir, len + 1);
+
+ if (stat (dir, &s) < 0)
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_NS;
+ }
+ else if (S_ISDIR (s.st_mode))
+ {
+ dirs[0] = opendir (dir);
+ if (dirs[0] != NULL)
+ flag = FTW_D;
+ else
+ {
+ if (errno != EACCES)
+ {
+ free ((pointer) dirs);
+ return -1;
+ }
+ flag = FTW_DNR;
+ }
+ }
+ else
+ flag = FTW_F;
+
+ ret = (*func) (buf, &s, flag);
+
+ if (flag == FTW_D)
+ {
+ if (ret == 0)
+ ret = ftw_dir (dirs, 0, descriptors, buf, len, func);
+ if (dirs[0] != NULL)
+ {
+ int save;
+
+ save = errno;
+ closedir (dirs[0]);
+ errno = save;
+ }
+ }
+
+ free ((pointer) dirs);
+ return ret;
+}
diff --git a/gnu/libexec/uucp/libunix/getcwd.c b/gnu/libexec/uucp/libunix/getcwd.c
new file mode 100644
index 0000000..d3623bd
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/getcwd.c
@@ -0,0 +1,59 @@
+/* getcwd.c
+ Replacement for the getcwd function that just calls /bin/pwd. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+char *
+getcwd (zbuf, cbuf)
+ char *zbuf;
+ size_t cbuf;
+{
+ const char *azargs[2];
+ FILE *e;
+ pid_t ipid;
+ int cread;
+ int ierr;
+
+ azargs[0] = PWD_PROGRAM;
+ azargs[1] = NULL;
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ return NULL;
+
+ ierr = 0;
+
+ cread = fread (zbuf, sizeof (char), cbuf, e);
+ if (cread == 0)
+ ierr = errno;
+
+ (void) fclose (e);
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ ierr = EACCES;
+ cread = 0;
+ }
+
+ if (cread != 0)
+ {
+ if (zbuf[cread - 1] == '\n')
+ zbuf[cread - 1] = '\0';
+ else
+ {
+ ierr = ERANGE;
+ cread = 0;
+ }
+ }
+
+ if (cread == 0)
+ {
+ errno = ierr;
+ return NULL;
+ }
+
+ return zbuf;
+}
diff --git a/gnu/libexec/uucp/libunix/indir.c b/gnu/libexec/uucp/libunix/indir.c
new file mode 100644
index 0000000..2484ec2
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/indir.c
@@ -0,0 +1,133 @@
+/* indir.c
+ See if a file is in a directory.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* See whether a file is in a directory, and optionally check access. */
+
+boolean
+fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser)
+ const char *zfile;
+ const char *zdir;
+ boolean fcheck;
+ boolean freadable;
+ const char *zuser;
+{
+ size_t c;
+ char *zcopy, *zslash;
+ struct stat s;
+
+ if (*zfile != '/')
+ return FALSE;
+ c = strlen (zdir);
+ if (c > 0 && zdir[c - 1] == '/')
+ c--;
+ if (strncmp (zfile, zdir, c) != 0
+ || (zfile[c] != '/' && zfile[c] != '\0'))
+ return FALSE;
+ if (strstr (zfile + c, "/../") != NULL)
+ return FALSE;
+
+ /* If we're not checking access, get out now. */
+ if (! fcheck)
+ return TRUE;
+
+ zcopy = zbufcpy (zfile);
+
+ /* Start checking directories after zdir. Otherwise, we would
+ require that all directories down to /usr/spool/uucppublic be
+ publically searchable; they probably are but it should not be a
+ requirement. */
+ zslash = zcopy + c;
+ do
+ {
+ char b;
+ struct stat shold;
+
+ b = *zslash;
+ *zslash = '\0';
+
+ shold = s;
+ if (stat (zcopy, &s) != 0)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If this is the top directory, any problems will be caught
+ later when we try to open it. */
+ if (zslash == zcopy + c)
+ {
+ ubuffree (zcopy);
+ return TRUE;
+ }
+
+ /* Go back and check the last directory for read or write
+ access. */
+ s = shold;
+ break;
+ }
+
+ /* If this is not a directory, get out of the loop. */
+ if (! S_ISDIR (s.st_mode))
+ break;
+
+ /* Make sure the directory is searchable. */
+ if (! fsuser_access (&s, X_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ /* If we've reached the end of the string, get out. */
+ if (b == '\0')
+ break;
+
+ *zslash = b;
+ }
+ while ((zslash = strchr (zslash + 1, '/')) != NULL);
+
+ /* At this point s holds a stat on the last component of the path.
+ We must check it for readability or writeability. */
+ if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+
+ ubuffree (zcopy);
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/init.c b/gnu/libexec/uucp/libunix/init.c
new file mode 100644
index 0000000..d4a1377
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/init.c
@@ -0,0 +1,394 @@
+/* init.c
+ Initialize the system dependent routines.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#if ! HAVE_GETHOSTNAME && HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+/* Use getcwd in preference to getwd; if we have neither, we will be
+ using a getcwd replacement. */
+#if HAVE_GETCWD
+#undef HAVE_GETWD
+#define HAVE_GETWD 0
+#else /* ! HAVE_GETCWD */
+#if ! HAVE_GETWD
+#undef HAVE_GETCWD
+#define HAVE_GETCWD 1
+#endif /* ! HAVE_GETWD */
+#endif /* ! HAVE_GETCWD */
+
+#if HAVE_GETWD
+/* Get a value for MAXPATHLEN. */
+#if HAVE_SYS_PARAMS_H
+#include <sys/params.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef MAXPATHLEN
+#ifdef PATH_MAX
+#define MAXPATHLEN PATH_MAX
+#else /* ! defined (PATH_MAX) */
+#define MAXPATHLEN 1024
+#endif /* ! defined (PATH_MAX) */
+#endif /* ! defined (MAXPATHLEN) */
+#endif /* HAVE_GETWD */
+
+/* External functions. */
+#ifndef getlogin
+extern char *getlogin ();
+#endif
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+#if HAVE_GETCWD
+#ifndef getcwd
+extern char *getcwd ();
+#endif
+#endif
+#if HAVE_GETWD
+#ifndef getwd
+extern char *getwd ();
+#endif
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Initialize the system dependent routines. We will probably be running
+ suid to uucp, so we make sure that nothing is obviously wrong. We
+ save the login name since we will be losing the real uid. */
+static char *zSlogin;
+
+/* The UUCP spool directory. */
+const char *zSspooldir;
+
+/* The UUCP lock directory. */
+const char *zSlockdir;
+
+/* The local UUCP name. */
+const char *zSlocalname;
+
+/* We save the current directory since we will do a chdir to the
+ spool directory. */
+char *zScwd;
+
+/* The maximum length of a system name is controlled by the type of spool
+ directory we use. */
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+size_t cSysdep_max_name_len = 7;
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+size_t cSysdep_max_name_len = 14;
+#endif
+#if SPOOLDIR_TAYLOR
+#if HAVE_LONG_FILE_NAMES
+size_t cSysdep_max_name_len = 255;
+#else /* ! HAVE_LONG_FILE_NAMES */
+size_t cSysdep_max_name_len = 14;
+#endif /* ! HAVE_LONG_FILE_NAMES */
+#endif /* SPOOLDIR_TAYLOR */
+
+/* Initialize the system dependent routines. */
+
+void
+usysdep_initialize (puuconf,iflags)
+ pointer puuconf;
+ int iflags;
+{
+ int cdescs;
+ int o;
+ int iuuconf;
+ char *z;
+ struct passwd *q;
+
+ ulog_id (getpid ());
+
+ /* Close everything but stdin, stdout and stderr. */
+#if HAVE_GETDTABLESIZE
+ cdescs = getdtablesize ();
+#else
+#if HAVE_SYSCONF
+ cdescs = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ cdescs = OPEN_MAX;
+#else
+#ifdef NOFILE
+ cdescs = NOFILE;
+#else
+ cdescs = 20;
+#endif /* ! defined (NOFILE) */
+#endif /* ! defined (OPEN_MAX) */
+#endif /* ! HAVE_SYSCONF */
+#endif /* ! HAVE_GETDTABLESIZE */
+
+ for (o = 3; o < cdescs; o++)
+ (void) close (o);
+
+ /* Make sure stdin, stdout and stderr are open. */
+ if (fcntl (0, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_RDONLY, 0) != 0)
+ exit (EXIT_FAILURE);
+ if (fcntl (1, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 1)
+ exit (EXIT_FAILURE);
+ if (fcntl (2, F_GETFD, 0) < 0
+ && open ((char *) "/dev/null", O_WRONLY, 0) != 2)
+ exit (EXIT_FAILURE);
+
+ iuuconf = uuconf_spooldir (puuconf, &zSspooldir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_lockdir (puuconf, &zSlockdir);
+ if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ iuuconf = uuconf_localname (puuconf, &zSlocalname);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+#if HAVE_GETHOSTNAME
+ char ab[256];
+
+ if (gethostname (ab, sizeof ab - 1) < 0)
+ ulog (LOG_FATAL, "gethostname: %s", strerror (errno));
+ ab[sizeof ab - 1] = '\0';
+ ab[strcspn (ab, ".")] = '\0';
+ zSlocalname = zbufcpy (ab);
+#else /* ! HAVE_GETHOSTNAME */
+#if HAVE_UNAME
+ struct utsname s;
+
+ if (uname (&s) < 0)
+ ulog (LOG_FATAL, "uname: %s", strerror (errno));
+ zSlocalname = zbufcpy (s.nodename);
+#else /* ! HAVE_UNAME */
+ ulog (LOG_FATAL, "Don't know how to get local node name");
+#endif /* ! HAVE_UNAME */
+#endif /* ! HAVE_GETHOSTNAME */
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
+
+ /* We always set our file modes to exactly what we want. */
+ umask (0);
+
+ /* Get the login name, making sure that it matches the uid. Many
+ systems truncate the getlogin return value to 8 characters, but
+ keep the full name in the password file, so we prefer the name in
+ the password file. */
+ z = getenv ("LOGNAME");
+ if (z == NULL)
+ z = getenv ("USER");
+ if (z == NULL)
+ z = getlogin ();
+ if (z == NULL)
+ q = NULL;
+ else
+ {
+ q = getpwnam (z);
+ if (q != NULL)
+ z = q->pw_name;
+ }
+ if (q == NULL || q->pw_uid != getuid ())
+ {
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ z = NULL;
+ else
+ z = q->pw_name;
+ }
+ if (z != NULL)
+ zSlogin = zbufcpy (z);
+
+ /* On some old systems, an suid program run by root is started with
+ an euid of 0. If this happens, we look up the uid we should have
+ and set ourselves to it manually. This means that on such a
+ system root will not be able to uucp or uux files that are not
+ readable by uucp. */
+ if ((iflags & INIT_SUID) != 0
+ && geteuid () == 0)
+ {
+ q = getpwnam (OWNER);
+ if (q != NULL)
+ setuid (q->pw_uid);
+ }
+
+ if ((iflags & INIT_GETCWD) != 0)
+ {
+ const char *zenv;
+ struct stat senv, sdot;
+
+ /* Get the current working directory. We have to get it now,
+ since we're about to do a chdir. We use PWD if it's defined
+ and if it really names the working directory, since if it's
+ not the same as whatever getcwd returns it's probably more
+ appropriate. */
+ zenv = getenv ("PWD");
+ if (zenv != NULL
+ && stat ((char *) zenv, &senv) == 0
+ && stat ((char *) ".", &sdot) == 0
+ && senv.st_ino == sdot.st_ino
+ && senv.st_dev == sdot.st_dev)
+ zScwd = zbufcpy (zenv);
+ else
+ {
+
+#if HAVE_GETCWD
+ {
+ size_t c;
+
+ c = 128;
+ while (TRUE)
+ {
+ zScwd = (char *) xmalloc (c);
+ if (getcwd (zScwd, c) != NULL)
+ break;
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ if (errno != ERANGE)
+ break;
+ c <<= 1;
+ }
+ }
+#endif /* HAVE_GETCWD */
+
+#if HAVE_GETWD
+ zScwd = (char *) xmalloc (MAXPATHLEN);
+ if (getwd (zScwd) == NULL)
+ {
+ xfree ((pointer) zScwd);
+ zScwd = NULL;
+ }
+#endif /* HAVE_GETWD */
+
+ if (zScwd != NULL)
+ zScwd = (char *) xrealloc ((pointer) zScwd,
+ strlen (zScwd) + 1);
+ }
+ }
+
+ if ((iflags & INIT_NOCHDIR) == 0)
+ {
+ /* Connect to the spool directory, and create it if it doesn't
+ exist. */
+ if (chdir (zSspooldir) < 0)
+ {
+ if (errno == ENOENT
+ && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0)
+ ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir,
+ strerror (errno));
+ if (chdir (zSspooldir) < 0)
+ ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir,
+ strerror (errno));
+ }
+ }
+}
+
+/* Exit the program. */
+
+void
+usysdep_exit (fsuccess)
+ boolean fsuccess;
+{
+ exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/* This is called when a non-standard configuration file is used, to
+ make sure the program doesn't hand out privileged file access.
+ This means that to test non-standard configuration files, you
+ should be logged in as uucp. This is called before
+ usysdep_initialize. It ensures that someone can't simply use an
+ alternate configuration file to steal UUCP transfers from other
+ systems. This will still permit people to set up their own
+ configuration file and pretend to be whatever system they choose.
+ The only real security is to use a high level of protection on the
+ modem ports. */
+
+/*ARGSUSED*/
+boolean fsysdep_other_config (z)
+ const char *z;
+{
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ return TRUE;
+}
+
+/* Get the node name to use if it was not specified in the configuration
+ file. */
+
+const char *
+zsysdep_localname ()
+{
+ return zSlocalname;
+}
+
+/* Get the login name. We actually get the login name in
+ usysdep_initialize, because after that we may switch away from the
+ real uid. */
+
+const char *
+zsysdep_login_name ()
+{
+ if (zSlogin == NULL)
+ ulog (LOG_FATAL, "Can't get login name");
+ return zSlogin;
+}
diff --git a/gnu/libexec/uucp/libunix/isdir.c b/gnu/libexec/uucp/libunix/isdir.c
new file mode 100644
index 0000000..fc95e52
--- /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 0000000..f067d07
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/isfork.c
@@ -0,0 +1,25 @@
+/* isfork.c
+ Retry fork several times before giving up. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+pid_t
+ixsfork ()
+{
+ int i;
+ pid_t iret;
+
+ for (i = 0; i < 10; i++)
+ {
+ iret = fork ();
+ if (iret >= 0 || errno != EAGAIN)
+ return iret;
+ sleep (5);
+ }
+
+ return iret;
+}
diff --git a/gnu/libexec/uucp/libunix/iswait.c b/gnu/libexec/uucp/libunix/iswait.c
new file mode 100644
index 0000000..d2610aa
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/iswait.c
@@ -0,0 +1,159 @@
+/* iswait.c
+ Wait for a process to finish.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/* We use a typedef wait_status for wait (waitpid, wait4) to put
+ results into. We define the POSIX examination functions we need if
+ they are not already defined (if they aren't defined, I assume that
+ we have a standard wait status). */
+
+#if HAVE_UNION_WAIT
+typedef union wait wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(u) ((u).w_termsig == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(u) ((u).w_retcode)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(u) ((u).w_termsig)
+#endif
+#else /* ! HAVE_UNION_WAIT */
+typedef int wait_status;
+#ifndef WIFEXITED
+#define WIFEXITED(i) (((i) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(i) ((i) & 0x7f)
+#endif
+#endif /* ! HAVE_UNION_WAIT */
+
+/* Wait for a particular process to finish. The ipid argument should
+ be pid_t, but then we couldn't have a prototype. If the zreport
+ argument is not NULL, then a wait error will be logged, and if the
+ exit status is non-zero it will be logged with zreport as the
+ header of the log message. If the zreport argument is NULL, no
+ errors will be logged. This function returns the exit status if
+ the process exited normally, or -1 on error or if the process was
+ killed by a signal (I don't just always return the exit status
+ because then the calling code would have to prepared to handle
+ union wait status vs. int status, and none of the callers care
+ which signal killed the program anyhow).
+
+ This functions keeps waiting until the process finished, even if it
+ is interrupted by a signal. I think this is right for all uses.
+ The controversial one would be when called from uuxqt to wait for a
+ requested process. Hitting uuxqt with SIGKILL will approximate the
+ actions taken if we return from here with an error anyhow. If we
+ do get a signal, we call ulog with a NULL argument to get it in the
+ log file at about the right time. */
+
+int
+ixswait (ipid, zreport)
+ unsigned long ipid;
+ const char *zreport;
+{
+ wait_status istat;
+
+#if HAVE_WAITPID
+ while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "waitpid: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAITPID */
+#if HAVE_WAIT4
+ while (wait4 ((pid_t) ipid, (pointer) &istat, 0,
+ (struct rusage *) NULL) < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait4: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+#else /* ! HAVE_WAIT4 */
+ pid_t igot;
+
+ /* We could theoretically get the wrong child here if we're in some
+ kind of weird pipeline, so we don't give any error messages for
+ it. */
+ while ((igot = wait ((pointer) &istat)) != (pid_t) ipid)
+ {
+ if (igot < 0)
+ {
+ if (errno != EINTR)
+ {
+ if (zreport != NULL)
+ ulog (LOG_ERROR, "wait: %s", strerror (errno));
+ return -1;
+ }
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ }
+#endif /* ! HAVE_WAIT4 */
+#endif /* ! HAVE_WAITPID */
+
+ DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d",
+ WIFEXITED (istat) ? "Exit status" : "Signal",
+ WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat));
+
+ if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0)
+ return 0;
+
+ if (zreport != NULL)
+ {
+ if (! WIFEXITED (istat))
+ ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat));
+ else
+ ulog (LOG_ERROR, "%s: Exit status %d", zreport,
+ WEXITSTATUS (istat));
+ }
+
+ if (WIFEXITED (istat))
+ return WEXITSTATUS (istat);
+ else
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/jobid.c b/gnu/libexec/uucp/libunix/jobid.c
new file mode 100644
index 0000000..7f22f1d
--- /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 0000000..4ece16a
--- /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 0000000..4550c76
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/link.c
@@ -0,0 +1,38 @@
+/* link.c
+ Link two files. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_link (zfrom, zto, pfworked)
+ const char *zfrom;
+ const char *zto;
+ boolean *pfworked;
+{
+ *pfworked = FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, TRUE))
+ return FALSE;
+ if (link (zfrom, zto) == 0)
+ {
+ *pfworked = TRUE;
+ return TRUE;
+ }
+ }
+ if (errno == EXDEV)
+ return TRUE;
+ ulog (LOG_ERROR, "link (%s, %s): %s", zfrom, zto, strerror (errno));
+ return FALSE;
+}
diff --git a/gnu/libexec/uucp/libunix/locfil.c b/gnu/libexec/uucp/libunix/locfil.c
new file mode 100644
index 0000000..0e05af9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/locfil.c
@@ -0,0 +1,95 @@
+/* locfil.c
+ Expand a file name on the local system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <pwd.h>
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Turn a file name into an absolute path, by doing tilde expansion
+ and moving any other type of file into the public directory. */
+
+char *
+zsysdep_local_file (zfile, zpubdir)
+ const char *zfile;
+ const char *zpubdir;
+{
+ const char *zdir;
+
+ if (*zfile == '/')
+ return zbufcpy (zfile);
+
+ if (*zfile != '~')
+ zdir = zpubdir;
+ else
+ {
+ if (zfile[1] == '\0')
+ return zbufcpy (zpubdir);
+
+ if (zfile[1] == '/')
+ {
+ zdir = zpubdir;
+ zfile += 2;
+ }
+ else
+ {
+ size_t cuserlen;
+ char *zcopy;
+ struct passwd *q;
+
+ ++zfile;
+ cuserlen = strcspn ((char *) zfile, "/");
+ zcopy = zbufalc (cuserlen + 1);
+ memcpy (zcopy, zfile, cuserlen);
+ zcopy[cuserlen] = '\0';
+
+ q = getpwnam (zcopy);
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "User %s not found", zcopy);
+ ubuffree (zcopy);
+ return NULL;
+ }
+ ubuffree (zcopy);
+
+ if (zfile[cuserlen] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ zdir = q->pw_dir;
+ zfile += cuserlen + 1;
+ }
+ }
+
+ return zsysdep_in_dir (zdir, zfile);
+}
diff --git a/gnu/libexec/uucp/libunix/lock.c b/gnu/libexec/uucp/libunix/lock.c
new file mode 100644
index 0000000..c43e31d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/lock.c
@@ -0,0 +1,477 @@
+/* lock.c
+ Lock and unlock a file name.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char lock_rcsid[] = "$Id: lock.c,v 1.1 1993/08/04 19:32:33 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* Lock something. If the fspooldir argument is TRUE, the argument is
+ a file name relative to the spool directory; otherwise the argument
+ is a simple file name which should be created in the system lock
+ directory (under HDB this is /etc/locks). */
+
+boolean
+fsdo_lock (zlock, fspooldir, pferr)
+ const char *zlock;
+ boolean fspooldir;
+ boolean *pferr;
+{
+ char *zfree;
+ const char *zpath, *zslash;
+ size_t cslash;
+ pid_t ime;
+ char *ztempfile;
+ char abtempfile[sizeof "TMP1234567890"];
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cwrote;
+ const char *zerr;
+ boolean fret;
+
+ if (pferr != NULL)
+ *pferr = TRUE;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ ime = getpid ();
+
+ /* We do the actual lock by creating a file and then linking it to
+ the final file name we want. This avoids race conditions due to
+ one process checking the file before we have finished writing it,
+ and also works even if we are somehow running as root.
+
+ First, create the file in the right directory (we must create the
+ file in the same directory since otherwise we might attempt a
+ cross-device link). */
+ zslash = strrchr (zpath, '/');
+ if (zslash == NULL)
+ cslash = 0;
+ else
+ cslash = zslash - zpath + 1;
+
+ sprintf (abtempfile, "TMP%010lx", (unsigned long) ime);
+ ztempfile = zbufalc (cslash + sizeof abtempfile);
+ memcpy (ztempfile, zpath, cslash);
+ memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile);
+
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (ztempfile, FALSE))
+ {
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ o = creat (ztempfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno));
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ zerr = NULL;
+ if (cwrote < 0)
+ zerr = "write";
+ if (close (o) < 0)
+ zerr = "close";
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno));
+ (void) remove (ztempfile);
+ ubuffree (zfree);
+ ubuffree (ztempfile);
+ return FALSE;
+ }
+
+ /* Now try to link the file we just created to the lock file that we
+ want. If it fails, try reading the existing file to make sure
+ the process that created it still exists. We do this in a loop
+ to make it easy to retry if the old locking process no longer
+ exists. */
+ fret = TRUE;
+ if (pferr != NULL)
+ *pferr = FALSE;
+ o = -1;
+ zerr = NULL;
+
+ while (link (ztempfile, zpath) != 0)
+ {
+ int cgot;
+ int ipid;
+ boolean freadonly;
+
+ fret = FALSE;
+
+ if (errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath,
+ strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ break;
+ }
+
+ freadonly = FALSE;
+ o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno == EACCES)
+ {
+ freadonly = TRUE;
+ o = open ((char *) zpath, O_RDONLY, 0);
+ }
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /* The file was presumably removed between the link
+ and the open. Try the link again. */
+ fret = TRUE;
+ continue;
+ }
+ zerr = "open";
+ break;
+ }
+ }
+
+ /* The race starts here. See below for a discussion. */
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ /* On NFS, the link might have actually succeeded even though we
+ got a failure return. This can happen if the original
+ acknowledgement was lost or delayed and the operation was
+ retried. In this case the pid will be our own. This
+ introduces a rather improbable race condition: if a stale
+ lock was left with our process ID in it, and another process
+ just did the kill, below, but has not yet changed the lock
+ file to hold its own process ID, we could start up and make
+ it all the way to here and think we have the lock. I'm not
+ going to worry about this possibility. */
+ if (ipid == ime)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* If the process still exists, we will get EPERM rather than
+ ESRCH. We then return FALSE to indicate that we cannot make
+ the lock. */
+ if (kill (ipid, 0) == 0 || errno == EPERM)
+ break;
+
+ ulog (LOG_ERROR, "Found stale lock %s held by process %d",
+ zpath, ipid);
+
+ /* This is a stale lock, created by a process that no longer
+ exists.
+
+ Now we could remove the file (and, if the file mode disallows
+ writing, that's what we have to do), but we try to avoid
+ doing so since it causes a race condition. If we remove the
+ file, and are interrupted any time after we do the read until
+ we do the remove, another process could get in, open the
+ file, find that it was a stale lock, remove the file and
+ create a new one. When we regained control we would remove
+ the file the other process just created.
+
+ These files are being generated partially for the benefit of
+ cu, and it would be nice to avoid the race however cu avoids
+ it, so that the programs remain compatible. Unfortunately,
+ nobody seems to know how cu avoids the race, or even if it
+ tries to avoid it at all.
+
+ There are a few ways to avoid the race. We could use kernel
+ locking primitives, but they may not be available. We could
+ link to a special file name, but if that file were left lying
+ around then no stale lock could ever be broken (Henry Spencer
+ would think this was a good thing).
+
+ Instead I've implemented the following procedure: seek to the
+ start of the file, write our pid into it, sleep for five
+ seconds, and then make sure our pid is still there. Anybody
+ who checks the file while we're asleep will find our pid
+ there and fail the lock. The only race will come from
+ another process which has done the read by the time we do our
+ write. That process will then have five seconds to do its
+ own write. When we wake up, we'll notice that our pid is no
+ longer in the file, and retry the lock from the beginning.
+
+ This relies on the atomicity of write(2). If it possible for
+ the writes of two processes to be interleaved, the two
+ processes could livelock. POSIX unfortunately leaves this
+ case explicitly undefined; however, given that the write is
+ of less than a disk block, it's difficult to imagine an
+ interleave occurring.
+
+ Note that this is still a race. If it takes the second
+ process more than five seconds to do the kill, the lseek, and
+ the write, both processes will think they have the lock.
+ Perhaps the length of time to sleep should be configurable.
+ Even better, perhaps I should add a configuration option to
+ use a permanent lock file, which eliminates any race and
+ forces the installer to be aware of the existence of the
+ permanent lock file.
+
+ We stat the file after the sleep, to make sure some other
+ program hasn't deleted it for us. */
+ if (freadonly)
+ {
+ (void) close (o);
+ o = -1;
+ (void) remove (zpath);
+ continue;
+ }
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ i = ime;
+ cwrote = write (o, &i, sizeof i);
+#else
+ sprintf (ab, "%10d\n", (int) ime);
+ cwrote = write (o, ab, strlen (ab));
+#endif
+
+ if (cwrote < 0)
+ {
+ zerr = "write";
+ break;
+ }
+
+ (void) sleep (5);
+
+ if (lseek (o, (off_t) 0, SEEK_SET) != 0)
+ {
+ zerr = "lseek";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cgot = read (o, &i, sizeof i);
+#else
+ cgot = read (o, ab, sizeof ab - 1);
+#endif
+
+ if (cgot < 0)
+ {
+ zerr = "read";
+ break;
+ }
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cgot] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ if (ipid == ime)
+ {
+ struct stat sfile, sdescriptor;
+
+ /* It looks like we have the lock. Do the final stat
+ check. */
+ if (stat ((char *) zpath, &sfile) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ zerr = "stat";
+ break;
+ }
+ /* Loop around and try again. */
+ }
+ else
+ {
+ if (fstat (o, &sdescriptor) < 0)
+ {
+ zerr = "fstat";
+ break;
+ }
+
+ if (sfile.st_ino == sdescriptor.st_ino
+ && sfile.st_dev == sdescriptor.st_dev)
+ {
+ /* Close the file before assuming we've succeeded to
+ pick up any trailing errors. */
+ if (close (o) < 0)
+ {
+ zerr = "close";
+ break;
+ }
+
+ o = -1;
+
+ /* We have the lock. */
+ fret = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Loop around and try the lock again. We keep doing this until
+ the lock file holds a pid that exists. */
+ (void) close (o);
+ o = -1;
+ fret = TRUE;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno));
+ if (pferr != NULL)
+ *pferr = TRUE;
+ }
+
+ if (o >= 0)
+ (void) close (o);
+
+ ubuffree (zfree);
+
+ /* It would be nice if we could leave the temporary file around for
+ future calls, but considering that we create lock files in
+ various different directories it's probably more trouble than
+ it's worth. */
+ if (remove (ztempfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno));
+
+ ubuffree (ztempfile);
+
+ return fret;
+}
+
+/* Unlock something. The fspooldir argument is as in fsdo_lock. */
+
+boolean
+fsdo_unlock (zlock, fspooldir)
+ const char *zlock;
+ boolean fspooldir;
+{
+ char *zfree;
+ const char *zpath;
+
+ if (fspooldir)
+ {
+ zfree = NULL;
+ zpath = zlock;
+ }
+ else
+ {
+ zfree = zsysdep_in_dir (zSlockdir, zlock);
+ zpath = zfree;
+ }
+
+ if (remove (zpath) == 0
+ || errno == ENOENT)
+ {
+ ubuffree (zfree);
+ return TRUE;
+ }
+ else
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+}
diff --git a/gnu/libexec/uucp/libunix/loctim.c b/gnu/libexec/uucp/libunix/loctim.c
new file mode 100644
index 0000000..da5f32e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/loctim.c
@@ -0,0 +1,25 @@
+/* loctim.c
+ Turn a time epoch into a struct tm. This is trivial on Unix. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef localtime
+extern struct tm *localtime ();
+#endif
+
+void
+usysdep_localtime (itime, q)
+ long itime;
+ struct tm *q;
+{
+ time_t i;
+
+ i = (time_t) itime;
+ *q = *localtime (&i);
+}
diff --git a/gnu/libexec/uucp/libunix/mail.c b/gnu/libexec/uucp/libunix/mail.c
new file mode 100644
index 0000000..74c1aa9
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mail.c
@@ -0,0 +1,85 @@
+/* mail.c
+ Send mail to a user.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifndef ctime
+extern char *ctime ();
+#endif
+
+/* Mail a message to a user. */
+
+boolean
+fsysdep_mail (zto, zsubject, cstrs, paz)
+ const char *zto;
+ const char *zsubject;
+ int cstrs;
+ const char **paz;
+{
+ const char *az[3];
+ FILE *e;
+ pid_t ipid;
+ time_t itime;
+ int i;
+
+ az[0] = MAIL_PROGRAM;
+ az[1] = zto;
+ az[2] = NULL;
+
+ e = espopen (az, FALSE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM,
+ strerror (errno));
+ return FALSE;
+ }
+
+ fprintf (e, "Subject: %s\n", zsubject);
+ fprintf (e, "To: %s\n", zto);
+
+ fprintf (e, "\n");
+
+ (void) time (&itime);
+ /* Remember that ctime includes a \n, so this skips a line. */
+ fprintf (e, "Message from UUCP on %s %s\n", zSlocalname,
+ ctime (&itime));
+
+ for (i = 0; i < cstrs; i++)
+ fputs (paz[i], e);
+
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, MAIL_PROGRAM) == 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdir.c b/gnu/libexec/uucp/libunix/mkdir.c
new file mode 100644
index 0000000..f59ad5d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdir.c
@@ -0,0 +1,58 @@
+/* mkdir.c
+ Create a directory. We must go through a subsidiary program to
+ force our real uid to be the uucp owner before invoking the setuid
+ /bin/mkdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+mkdir (zdir, imode)
+ const char *zdir;
+ int imode;
+{
+ struct stat s;
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ /* Make sure the directory does not exist, since we will otherwise
+ get the wrong errno value. */
+ if (stat (zdir, &s) == 0)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ /* /bin/mkdir will create the directory with mode 777, so we set our
+ umask to get the mode we want. */
+ (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO));
+
+ azargs[0] = UUDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL,
+ TRUE, FALSE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ (void) umask (0);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EACCES;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/mkdirs.c b/gnu/libexec/uucp/libunix/mkdirs.c
new file mode 100644
index 0000000..a4e0b67
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mkdirs.c
@@ -0,0 +1,49 @@
+/* mkdirs.c
+ Create any directories needed for a file name. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+boolean
+fsysdep_make_dirs (zfile, fpublic)
+ const char *zfile;
+ boolean fpublic;
+{
+ char *zcopy, *z;
+ int imode;
+
+ zcopy = zbufcpy (zfile);
+
+ if (fpublic)
+ imode = IPUBLIC_DIRECTORY_MODE;
+ else
+ imode = IDIRECTORY_MODE;
+
+ for (z = zcopy; *z != '\0'; z++)
+ {
+ if (*z == '/' && z != zcopy)
+ {
+ *z = '\0';
+ if (! fsysdep_directory (zcopy))
+ {
+ if (mkdir (zcopy, imode) != 0)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zcopy,
+ strerror (errno));
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ }
+ *z = '/';
+ }
+ }
+
+ ubuffree (zcopy);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/mode.c b/gnu/libexec/uucp/libunix/mode.c
new file mode 100644
index 0000000..53f74ec
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/mode.c
@@ -0,0 +1,33 @@
+/* mode.c
+ Get the Unix file mode of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+unsigned int
+ixsysdep_file_mode (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return 0;
+ }
+
+#if S_IRWXU != 0700
+ #error Files modes need to be translated
+#endif
+
+ /* We can't return 0, since that indicate an error. */
+ if ((s.st_mode & 0777) == 0)
+ return 0400;
+
+ return s.st_mode & 0777;
+}
diff --git a/gnu/libexec/uucp/libunix/move.c b/gnu/libexec/uucp/libunix/move.c
new file mode 100644
index 0000000..ccfe6d4
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/move.c
@@ -0,0 +1,176 @@
+/* move.c
+ Move a file.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+/* Move (rename) a file from one name to another. This routine will
+ optionally create necessary directories, and fpublic indicates
+ whether the new directories should be publically accessible or not.
+ If fcheck is true, it will try to determine whether the named user
+ has write access to the new file. */
+
+boolean
+fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser)
+ const char *zorig;
+ const char *zto;
+ boolean fmkdirs;
+ boolean fpublic;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ int o;
+
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "fsysdep_move_file: Moving %s to %s", zorig, zto);
+
+ /* Optionally make sure that zuser has write access on the
+ directory. */
+ if (fcheck)
+ {
+ char *zcopy;
+ char *zslash;
+
+ zcopy = zbufcpy (zto);
+ zslash = strrchr (zcopy, '/');
+ if (zslash == zcopy)
+ zslash[1] = '\0';
+ else
+ *zslash = '\0';
+
+ if (stat (zcopy, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ if (! fsuser_access (&s, W_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES));
+ (void) remove (zorig);
+ ubuffree (zcopy);
+ return FALSE;
+ }
+ ubuffree (zcopy);
+
+ /* A malicious user now has a few milliseconds to change a
+ symbolic link to a directory uucp has write permission on but
+ the user does not (the obvious choice being /usr/lib/uucp).
+ The only certain method I can come up with to close this race
+ is to fork an suid process which takes on the users identity
+ and does the actual copy. This is sufficiently high overhead
+ that I'm not going to do it. */
+ }
+
+ /* We try to use rename to move the file. */
+
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ if (rename (zorig, zto) == 0)
+ return TRUE;
+ }
+
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to copy the
+ file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ /* If we can't link across devices, we must copy the file by hand. */
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto,
+ strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Copy the file. */
+ if (stat ((char *) zorig, &s) < 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ /* Make sure the file gets the right mode by creating it before we
+ call fcopy_file. */
+ (void) remove (zto);
+ o = creat ((char *) zto, s.st_mode);
+ if (o < 0)
+ {
+ if (fmkdirs && errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zto, fpublic))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+ o = creat ((char *) zto, s.st_mode);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno));
+ (void) remove (zorig);
+ return FALSE;
+ }
+ }
+ (void) close (o);
+
+ if (! fcopy_file (zorig, zto, fpublic, fmkdirs))
+ {
+ (void) remove (zorig);
+ return FALSE;
+ }
+
+ if (remove (zorig) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno));
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/opensr.c b/gnu/libexec/uucp/libunix/opensr.c
new file mode 100644
index 0000000..3a8ca7a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/opensr.c
@@ -0,0 +1,244 @@
+/* opensr.c
+ Open files for sending and receiving.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Open a file to send to another system, and return the mode and
+ the size. */
+
+openfile_t
+esysdep_open_send (qsys, zfile, fcheck, zuser)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+ boolean fcheck;
+ const char *zuser;
+{
+ struct stat s;
+ openfile_t e;
+ int o;
+
+ if (fsysdep_directory (zfile))
+ {
+ ulog (LOG_ERROR, "%s: is a directory", zfile);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fopen (zfile, BINREAD);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ return NULL;
+ }
+ o = fileno (e);
+#else
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ if (e == -1)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
+ return -1;
+ }
+ o = e;
+#endif
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (fstat (o, &s) == -1)
+ {
+ ulog (LOG_ERROR, "fstat: %s", strerror (errno));
+ s.st_mode = 0666;
+ }
+
+ /* We have to recheck the file permission, although we probably
+ checked it already, because otherwise there would be a window in
+ which somebody could change the contents of a symbolic link to
+ point to some file which was only readable by uucp. */
+ if (fcheck)
+ {
+ if (! fsuser_access (&s, R_OK, zuser))
+ {
+ ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+ }
+
+ return e;
+}
+
+/* Get a temporary file name to receive into. We use the ztemp
+ argument to pick the file name, so that we relocate the file if the
+ transmission is aborted. */
+
+char *
+zsysdep_receive_temp (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Temp", qsys->uuconf_zname, ztemp);
+ else
+ return zstemp_file (qsys);
+}
+
+/* Open a temporary file to receive into. This should, perhaps, check
+ that we have write permission on the receiving directory, but it
+ doesn't. */
+
+openfile_t
+esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+ const char *zreceive;
+ long *pcrestart;
+{
+ int o;
+ openfile_t e;
+
+ /* If we used the ztemp argument in zsysdep_receive_temp, above,
+ then we will have a name consistent across conversations. In
+ that case, we may have already received some portion of this
+ file. */
+ o = -1;
+ *pcrestart = -1;
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ {
+ o = open ((char *) zreceive, O_WRONLY);
+ if (o >= 0)
+ {
+ struct stat s;
+
+ /* For safety, we insist on the file being less than 1 week
+ old. This can still catch people, unfortunately. I
+ don't know of any good solution to the problem of old
+ files hanging around. If anybody has a file they want
+ restarted, and they know about this issue, they can touch
+ it to bring it up to date. */
+ if (fstat (o, &s) < 0
+ || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL))
+ {
+ (void) close (o);
+ o = -1;
+ }
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "esysdep_open_receive: Reusing %s",
+ zreceive);
+ *pcrestart = (long) s.st_size;
+ }
+ }
+ }
+
+ if (o < 0)
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (zreceive, FALSE))
+ return EFILECLOSED;
+ o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zreceive, strerror (errno));
+ return EFILECLOSED;
+ }
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno));
+ (void) close (o);
+ (void) remove (zreceive);
+ return EFILECLOSED;
+ }
+#else
+ e = o;
+#endif
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/pause.c b/gnu/libexec/uucp/libunix/pause.c
new file mode 100644
index 0000000..e774e08
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/pause.c
@@ -0,0 +1,96 @@
+/* pause.c
+ Pause for half a second. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+/* Pick a timing routine to use. I somewhat arbitrarily picked usleep
+ above nap above napms above poll above select. */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#undef HAVE_SELECT
+#define HAVE_SELECT 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+#if HAVE_SELECT
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_POLL
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#if ! HAVE_STROPTS_H && ! HAVE_POLL_H
+/* We need a definition for struct pollfd, although it doesn't matter
+ what it contains. */
+struct pollfd
+{
+ int idummy;
+};
+#endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */
+#endif /* HAVE_POLL */
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER
+#include <time.h>
+#endif
+#endif
+
+void
+usysdep_pause ()
+{
+#if HAVE_NAPMS
+ napms (500);
+#endif /* HAVE_NAPMS */
+#if HAVE_NAP
+#if HAVE_HUNDREDTHS_NAP
+ nap (50L);
+#else
+ nap (500L);
+#endif /* ! HAVE_HUNDREDTHS_NAP */
+#endif /* HAVE_NAP */
+#if HAVE_USLEEP
+ usleep (500 * (long) 1000);
+#endif /* HAVE_USLEEP */
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ /* We need to pass an unused pollfd structure because poll checks
+ the address before checking the number of elements. */
+ poll (&sdummy, 0, 500);
+#endif /* HAVE_POLL */
+#if HAVE_SELECT
+ struct timeval s;
+
+ s.tv_sec = 0;
+ s.tv_usec = 500 * (long) 1000;
+ select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP
+#if ! USE_SELECT_TIMER && ! HAVE_POLL
+ sleep (1);
+#endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */
+#endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */
+}
diff --git a/gnu/libexec/uucp/libunix/picksb.c b/gnu/libexec/uucp/libunix/picksb.c
new file mode 100644
index 0000000..3fe5c6f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/picksb.c
@@ -0,0 +1,230 @@
+/* picksb.c
+ System dependent routines for uupick.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char picksb_rcsid[] = "$Id: picksb.c,v 1.1 1993/08/04 19:32:42 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <pwd.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if GETPWUID_DECLARATION_OK
+#ifndef getpwuid
+extern struct passwd *getpwuid ();
+#endif
+#endif
+
+/* Local variables. */
+
+/* Directory of ~/receive/USER. */
+static DIR *qStopdir;
+
+/* Name of ~/receive/USER. */
+static char *zStopdir;
+
+/* Directory of ~/receive/USER/SYSTEM. */
+static DIR *qSsysdir;
+
+/* Name of system. */
+static char *zSsysdir;
+
+/* Prepare to get a list of all the file to uupick for this user. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_init (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ const char *zuser;
+
+ zuser = zsysdep_login_name ();
+
+ zStopdir = (char *) xmalloc (strlen (zpubdir)
+ + sizeof "/receive/"
+ + strlen (zuser));
+ sprintf (zStopdir, "%s/receive/%s", zpubdir, zuser);
+
+ qStopdir = opendir (zStopdir);
+ if (qStopdir == NULL && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zStopdir,
+ strerror (errno));
+ return FALSE;
+ }
+
+ qSsysdir = NULL;
+
+ return TRUE;
+}
+
+/* Return the next file from the uupick directories. */
+
+/*ARGSUSED*/
+char *
+zsysdep_uupick (zsysarg, zpubdir, pzfrom, pzfull)
+ const char *zsysarg;
+ const char *zpubdir;
+ char **pzfrom;
+ char **pzfull;
+{
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ while (qSsysdir == NULL)
+ {
+ const char *zsystem;
+ char *zdir;
+
+ if (qStopdir == NULL)
+ return NULL;
+
+ if (zsysarg != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ zsystem = zsysarg;
+ }
+ else
+ {
+ do
+ {
+ qentry = readdir (qStopdir);
+ if (qentry == NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ return NULL;
+ }
+ }
+ while (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0);
+
+ zsystem = qentry->d_name;
+ }
+
+ zdir = zbufalc (strlen (zStopdir) + strlen (zsystem) + sizeof "/");
+ sprintf (zdir, "%s/%s", zStopdir, zsystem);
+
+ qSsysdir = opendir (zdir);
+ if (qSsysdir == NULL)
+ {
+ if (errno != ENOENT && errno != ENOTDIR)
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ }
+ else
+ {
+ ubuffree (zSsysdir);
+ zSsysdir = zbufcpy (zsystem);
+ }
+
+ ubuffree (zdir);
+ }
+
+ qentry = readdir (qSsysdir);
+ if (qentry == NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ continue;
+ }
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+
+ *pzfrom = zbufcpy (zSsysdir);
+ *pzfull = zsappend3 (zStopdir, zSsysdir, qentry->d_name);
+ return zbufcpy (qentry->d_name);
+ }
+}
+
+/*ARGSUSED*/
+boolean
+fsysdep_uupick_free (zsystem, zpubdir)
+ const char *zsystem;
+ const char *zpubdir;
+{
+ xfree ((pointer) zStopdir);
+ if (qStopdir != NULL)
+ {
+ closedir (qStopdir);
+ qStopdir = NULL;
+ }
+ ubuffree (zSsysdir);
+ zSsysdir = NULL;
+ if (qSsysdir != NULL)
+ {
+ closedir (qSsysdir);
+ qSsysdir = NULL;
+ }
+
+ return TRUE;
+}
+
+/* Expand a local file name for uupick. */
+
+char *
+zsysdep_uupick_local_file (zfile)
+ const char *zfile;
+{
+ struct passwd *q;
+
+ /* If this does not start with a simple ~, pass it to
+ zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd
+ only uses the zpubdir argument if the file starts with a simple
+ ~, so it doesn't really matter what we pass for zpubdir. */
+ if (zfile[0] != '~'
+ || (zfile[1] != '/' && zfile[1] != '\0'))
+ return zsysdep_local_file_cwd (zfile, (const char *) NULL);
+
+ q = getpwuid (getuid ());
+ if (q == NULL)
+ {
+ ulog (LOG_ERROR, "Can't get home directory");
+ return NULL;
+ }
+
+ if (zfile[1] == '\0')
+ return zbufcpy (q->pw_dir);
+
+ return zsysdep_in_dir (q->pw_dir, zfile + 2);
+}
diff --git a/gnu/libexec/uucp/libunix/portnm.c b/gnu/libexec/uucp/libunix/portnm.c
new file mode 100644
index 0000000..9eda4ab
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/portnm.c
@@ -0,0 +1,51 @@
+/* portnm.c
+ Get the port name of stdin. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_TCP
+#if HAVE_SYS_TYPES_TCP_H
+#include <sys/types.tcp.h>
+#endif
+#include <sys/socket.h>
+#endif
+
+#ifndef ttyname
+extern char *ttyname ();
+#endif
+
+/* Get the port name of standard input. I assume that Unix systems
+ generally support ttyname. If they don't, this function can just
+ return NULL. It uses getsockname to see whether standard input is
+ a TCP connection. */
+
+const char *
+zsysdep_port_name (ftcp_port)
+ boolean *ftcp_port;
+{
+ const char *z;
+
+ *ftcp_port = FALSE;
+
+#if HAVE_TCP
+ {
+ size_t clen;
+ struct sockaddr s;
+
+ clen = sizeof (struct sockaddr);
+ if (getsockname (0, &s, &clen) == 0)
+ *ftcp_port = TRUE;
+ }
+#endif /* HAVE_TCP */
+
+ z = ttyname (0);
+ if (z == NULL)
+ return NULL;
+ if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0)
+ return z + sizeof "/dev/" - 1;
+ else
+ return z;
+}
diff --git a/gnu/libexec/uucp/libunix/proctm.c b/gnu/libexec/uucp/libunix/proctm.c
new file mode 100644
index 0000000..55cf96f
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/proctm.c
@@ -0,0 +1,197 @@
+/* proctm.c
+ Get the time spent in the process.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+/* Prefer gettimeofday to ftime to times. */
+
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+#undef HAVE_TIMES
+#define HAVE_TIMES 0
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#undef HAVE_FTIME
+#define HAVE_FTIME 0
+#endif
+
+#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY)
+#include <time.h>
+#endif
+
+#if HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+
+#if HAVE_FTIME
+#include <sys/timeb.h>
+#endif
+
+#if HAVE_TIMES
+
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+
+#if TIMES_DECLARATION_OK
+/* We use a macro to protect this because times really returns clock_t
+ and on some systems, such as Ultrix 4.0, clock_t is int. We don't
+ leave it out entirely because on some systems, such as System III,
+ the declaration is necessary for correct compilation. */
+#ifndef times
+extern long times ();
+#endif
+#endif /* TIMES_DECLARATION_OK */
+
+#ifdef _SC_CLK_TCK
+#define HAVE_SC_CLK_TCK 1
+#else
+#define HAVE_SC_CLK_TCK 0
+#endif
+
+/* TIMES_TICK may have been set in policy.h, or we may be able to get
+ it using sysconf. If neither is the case, try to find a useful
+ definition from the system header files. */
+#if TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK)
+#ifdef CLK_TCK
+#undef TIMES_TICK
+#define TIMES_TICK CLK_TCK
+#else /* ! defined (CLK_TCK) */
+#ifdef HZ
+#undef TIMES_TICK
+#define TIMES_TICK HZ
+#endif /* defined (HZ) */
+#endif /* ! defined (CLK_TCK) */
+#endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */
+
+#endif /* HAVE_TIMES */
+
+#ifndef time
+extern time_t time ();
+#endif
+#if HAVE_SYSCONF
+#ifndef sysconf
+extern long sysconf ();
+#endif
+#endif
+
+/* Get the time in seconds and microseconds; this need only work
+ within the process when called from the system independent code.
+ It is also called by ixsysdep_time. */
+
+long
+ixsysdep_process_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY
+ struct timeval stime;
+ struct timezone stz;
+
+ (void) gettimeofday (&stime, &stz);
+ if (pimicros != NULL)
+ *pimicros = (long) stime.tv_usec;
+ return (long) stime.tv_sec;
+#endif /* HAVE_GETTIMEOFDAY */
+
+#if HAVE_FTIME
+ static boolean fbad;
+
+ if (! fbad)
+ {
+ struct timeb stime;
+ static struct timeb slast;
+
+ (void) ftime (&stime);
+
+ /* On some systems, such as SCO 3.2.2, ftime can go backwards in
+ time. If we detect this, we switch to using time. */
+ if (slast.time != 0
+ && (stime.time < slast.time
+ || (stime.time == slast.time &&
+ stime.millitm < slast.millitm)))
+ fbad = TRUE;
+ else
+ {
+ slast = stime;
+ if (pimicros != NULL)
+ *pimicros = (long) stime.millitm * (long) 1000;
+ return (long) stime.time;
+ }
+ }
+
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* HAVE_FTIME */
+
+#if HAVE_TIMES
+ struct tms s;
+ long i;
+ static int itick;
+
+ if (itick == 0)
+ {
+#if TIMES_TICK == 0
+#if HAVE_SYSCONF && HAVE_SC_CLK_TCK
+ itick = (int) sysconf (_SC_CLK_TCK);
+#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+ const char *z;
+
+ z = getenv ("HZ");
+ if (z != NULL)
+ itick = (int) strtol (z, (char **) NULL, 10);
+
+ /* If we really couldn't get anything, just use 60. */
+ if (itick == 0)
+ itick = 60;
+#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */
+#else /* TIMES_TICK != 0 */
+ itick = TIMES_TICK;
+#endif /* TIMES_TICK == 0 */
+ }
+
+ i = (long) times (&s);
+ if (pimicros != NULL)
+ *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick);
+ return i / (long) itick;
+#endif /* HAVE_TIMES */
+
+#if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */
+}
diff --git a/gnu/libexec/uucp/libunix/recep.c b/gnu/libexec/uucp/libunix/recep.c
new file mode 100644
index 0000000..84a211a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/recep.c
@@ -0,0 +1,197 @@
+/* recep.c
+ See whether a file has already been received.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+static char *zsreceived_name P((const struct uuconf_system *qsys,
+ const char *ztemp));
+
+/* These routines are used to see whether we have already received a
+ file in a previous UUCP connection. It is possible for the
+ acknowledgement of a received file to be lost. The sending system
+ will then now know that the file was correctly received, and will
+ send it again. This can be a problem particularly with protocols
+ which support channels, since they may send several small files in
+ a single window, all of which may be received correctly although
+ the sending system never sees the acknowledgement. If these files
+ involve an execution, the execution will happen twice, which will
+ be bad.
+
+ We use a simple system. For each file we want to remember, we
+ create an empty file names .Received/SYS/TEMP, where SYS is the
+ name of the system and TEMP is the name of the temporary file used
+ by the sender. If no temporary file is used by the sender, we
+ don't remember that we received the file. This is not perfect, but
+ execution files will always have a temporary file, so the most
+ important case is handled. Also, any file received from Taylor
+ UUCP 1.04 or greater will always have a temporary file. */
+
+/* Return the name we are going use for the marker, or NULL if we have
+ no name. */
+
+static char *
+zsreceived_name (qsys, ztemp)
+ const struct uuconf_system *qsys;
+ const char *ztemp;
+{
+ if (ztemp != NULL
+ && *ztemp == 'D'
+ && strcmp (ztemp, "D.0") != 0)
+ return zsappend3 (".Received", qsys->uuconf_zname, ztemp);
+ else
+ return NULL;
+}
+
+/* Remember that we have already received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_remember_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ int o;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ if (o < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (fsysdep_make_dirs (zfile, TRUE))
+ {
+ ubuffree (zfile);
+ return FALSE;
+ }
+ o = creat (zfile, IPUBLIC_FILE_MODE);
+ }
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ }
+
+ ubuffree (zfile);
+
+ /* We don't have to actually put anything in the file; we just use
+ the name. This is more convenient than keeping a file with a
+ list of names. */
+ if (close (o) < 0)
+ {
+ ulog (LOG_ERROR, "fsysdep_remember_reception: close: %s",
+ strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* See if we have already received a file. Note that don't delete the
+ marker file here, because we need to know that the sending system
+ has received our denial first. This function returns TRUE if the
+ file has already been received, FALSE if it has not. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_already_received (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+ struct stat s;
+ boolean fret;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return FALSE;
+ if (stat (zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+
+ /* Ignore the file (return FALSE) if it is over one week old. */
+ fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL);
+
+ if (fret)
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s",
+ zfile);
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Forget that we have received a file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_forget_reception (qsys, zto, ztemp)
+ const struct uuconf_system *qsys;
+ const char *zto;
+ const char *ztemp;
+{
+ char *zfile;
+
+ zfile = zsreceived_name (qsys, ztemp);
+ if (zfile == NULL)
+ return TRUE;
+ if (remove (zfile) < 0
+ && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ ubuffree (zfile);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/remove.c b/gnu/libexec/uucp/libunix/remove.c
new file mode 100644
index 0000000..b695888
--- /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 0000000..0947ef5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rename.c
@@ -0,0 +1,27 @@
+/* rename.c
+ Rename a file to a new name (Unix specific implementation). */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+/* This implementation will not work on directories, but fortunately
+ we never want to rename directories. */
+
+int
+rename (zfrom, zto)
+ const char *zfrom;
+ const char *zto;
+{
+ if (link (zfrom, zto) < 0)
+ {
+ if (errno != EEXIST)
+ return -1;
+ if (unlink (zto) < 0
+ || link (zfrom, zto) < 0)
+ return -1;
+ }
+ return unlink (zfrom);
+}
diff --git a/gnu/libexec/uucp/libunix/rmdir.c b/gnu/libexec/uucp/libunix/rmdir.c
new file mode 100644
index 0000000..12a7b9e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/rmdir.c
@@ -0,0 +1,43 @@
+/* rmdir.c
+ Remove a directory on a system which doesn't have the rmdir system
+ call. This is only called by uupick, which is not setuid, so we
+ don't have to worry about the problems of invoking the setuid
+ /bin/rmdir program. */
+
+#include "uucp.h"
+
+#include "sysdep.h"
+
+#include <errno.h>
+
+int
+rmdir (zdir)
+ const char *zdir;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = RMDIR_PROGRAM;
+ azargs[1] = zdir;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ TRUE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+
+ if (ipid < 0)
+ return -1;
+
+ if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0)
+ {
+ /* Make up an errno value. */
+ errno = EBUSY;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/run.c b/gnu/libexec/uucp/libunix/run.c
new file mode 100644
index 0000000..e219196
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/run.c
@@ -0,0 +1,75 @@
+/* run.c
+ Run a program.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Start up a new program and end the current one. We don't have to
+ worry about SIGHUP because the current process is either not a
+ process group leader (uucp, uux) or it does not have a controlling
+ terminal (uucico). */
+
+boolean
+fsysdep_run (zprogram, zarg1, zarg2)
+ const char *zprogram;
+ const char *zarg1;
+ const char *zarg2;
+{
+ char *zlib;
+ const char *azargs[4];
+ int aidescs[3];
+ pid_t ipid;
+
+ zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram));
+ sprintf (zlib, "%s/%s", SBINDIR, zprogram);
+
+ azargs[0] = zlib;
+ azargs[1] = zarg1;
+ azargs[2] = zarg2;
+ azargs[3] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ /* We pass fsetuid and fshell as TRUE, which permits uucico and
+ uuxqt to be replaced by (non-setuid) shell scripts. */
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL,
+ FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ ubuffree (zlib);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/seq.c b/gnu/libexec/uucp/libunix/seq.c
new file mode 100644
index 0000000..2e01233
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/seq.c
@@ -0,0 +1,126 @@
+/* seq.c
+ Get and increment the conversation sequence number for a system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Get the current conversation sequence number for a remote system,
+ and increment it for next time. The conversation sequence number
+ is kept in a file named for the system in the directory .Sequence
+ in the spool directory. This is not compatible with other versions
+ of UUCP, but it makes more sense to me. The sequence file is only
+ used if specified in the information for that system. */
+
+long
+ixsysdep_get_sequence (qsys)
+ const struct uuconf_system *qsys;
+{
+ FILE *e;
+ char *zname;
+ struct stat s;
+ long iseq;
+
+ /* This will only be called when the system is locked anyhow, so there
+ is no need to use a separate lock for the conversation sequence
+ file. */
+ zname = zsysdep_in_dir (".Sequence", qsys->uuconf_zname);
+
+ iseq = 0;
+ if (stat (zname, &s) == 0)
+ {
+ boolean fok;
+ char *zline;
+ size_t cline;
+
+ /* The file should only be readable and writable by uucp. */
+ if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ {
+ ulog (LOG_ERROR,
+ "Bad file protection for conversation sequence file");
+ ubuffree (zname);
+ return -1;
+ }
+
+ e = fopen (zname, "r+");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return -1;
+ }
+
+ ubuffree (zname);
+
+ fok = TRUE;
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ fok = FALSE;
+ else
+ {
+ char *zend;
+
+ iseq = strtol (zline, &zend, 10);
+ if (zend == zline)
+ fok = FALSE;
+ }
+
+ xfree ((pointer) zline);
+
+ if (! fok)
+ {
+ ulog (LOG_ERROR, "Bad format for conversation sequence file");
+ (void) fclose (e);
+ return -1;
+ }
+
+ rewind (e);
+ }
+ else
+ {
+ e = esysdep_fopen (zname, FALSE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return -1;
+ }
+
+ ++iseq;
+
+ fprintf (e, "%ld", iseq);
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return -1;
+ }
+
+ return iseq;
+}
diff --git a/gnu/libexec/uucp/libunix/serial.c b/gnu/libexec/uucp/libunix/serial.c
new file mode 100644
index 0000000..2b02cd5
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/serial.c
@@ -0,0 +1,2977 @@
+/* serial.c
+ The serial port communication routines for Unix.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char serial_rcsid[] = "$Id: serial.c,v 1.1 1993/08/04 19:32:52 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "conn.h"
+#include "sysdep.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if HAVE_TLI
+#if HAVE_TIUSER_H
+#include <tiuser.h>
+#else /* ! HAVE_TIUSER_H */
+#if HAVE_XTI_H
+#include <xti.h>
+#endif /* HAVE_XTI_H */
+#endif /* ! HAVE_TIUSER_H */
+#endif /* HAVE_TLI */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_BSD_TTY
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_TIME_H
+#if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY
+#include <time.h>
+#endif
+#endif
+
+#if HAVE_STRIP_BUG && HAVE_BSD_TTY
+#include <termio.h>
+#endif
+
+#if HAVE_SVR4_LOCKFILES
+/* Get the right definitions for major and minor. */
+#if MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif /* MAJOR_IN_MKDEV */
+#if MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif /* MAJOR_IN_SYSMACROS */
+#if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS
+#ifndef major
+#define major(i) (((i) >> 8) & 0xff)
+#endif
+#ifndef minor
+#define minor(i) ((i) & 0xff)
+#endif
+#endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
+#endif /* HAVE_SVR4_LOCKFILES */
+
+/* Get definitions for both O_NONBLOCK and O_NDELAY. */
+#ifndef O_NDELAY
+#ifdef FNDELAY
+#define O_NDELAY FNDELAY
+#else /* ! defined (FNDELAY) */
+#define O_NDELAY 0
+#endif /* ! defined (FNDELAY) */
+#endif /* ! defined (O_NDELAY) */
+
+#ifndef O_NONBLOCK
+#ifdef FNBLOCK
+#define O_NONBLOCK FNBLOCK
+#else /* ! defined (FNBLOCK) */
+#define O_NONBLOCK 0
+#endif /* ! defined (FNBLOCK) */
+#endif /* ! defined (O_NONBLOCK) */
+
+#if O_NDELAY == 0 && O_NONBLOCK == 0
+ #error No way to do nonblocking I/O
+#endif
+
+/* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */
+#ifndef EAGAIN
+#ifndef EWOULDBLOCK
+#define EAGAIN (-1)
+#define EWOULDBLOCK (-1)
+#else /* defined (EWOULDBLOCK) */
+#define EAGAIN EWOULDBLOCK
+#endif /* defined (EWOULDBLOCK) */
+#else /* defined (EAGAIN) */
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif /* ! defined (EWOULDBLOCK) */
+#endif /* defined (EAGAIN) */
+
+#ifndef ENODATA
+#define ENODATA EAGAIN
+#endif
+
+/* Make sure we have a definition for MAX_INPUT. */
+#ifndef MAX_INPUT
+#define MAX_INPUT (256)
+#endif
+
+/* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
+ Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
+ terminal before we know that it is unlocked. */
+#ifdef TIOCSINUSE
+#define HAVE_TIOCSINUSE 1
+#else
+#ifdef TIOCEXCL
+#define HAVE_TIOCEXCL 1
+#endif
+#endif
+
+#if HAVE_TLI
+extern int t_errno;
+extern char *t_errlist[];
+extern int t_nerr;
+#endif
+
+/* Determine bits to clear for the various terminal control fields for
+ HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */
+#if HAVE_SYSV_TERMIO
+#define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
+ | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
+ | IXON | IXANY | IXOFF)
+#define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
+ | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
+ | VTDLY | FFDLY)
+#define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
+ | ECHONL | NOFLSH)
+#endif
+#if HAVE_POSIX_TERMIOS
+#define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
+ | INLCR | INPCK | ISTRIP | IXOFF | IXON \
+ | PARMRK)
+#define ICLEAR_OFLAG (OPOST)
+#define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD)
+#define ISET_CFLAG (CS8 | CREAD | HUPCL)
+#define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
+ | ISIG | NOFLSH | TOSTOP)
+#endif
+
+/* Local functions. */
+
+static RETSIGTYPE usalarm P((int isig));
+static boolean fsserial_init P((struct sconnection *qconn,
+ const struct sconncmds *qcmds,
+ const char *zdevice));
+static void usserial_free P((struct sconnection *qconn));
+static boolean fsserial_lockfile P((boolean flok,
+ const struct sconnection *));
+static boolean fsserial_lock P((struct sconnection *qconn,
+ boolean fin));
+static boolean fsserial_unlock P((struct sconnection *qconn));
+static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsdirect_open P((struct sconnection *qconn, long ibaud,
+ boolean fwait));
+static boolean fsblock P((struct ssysdep_conn *q, boolean fblock));
+static boolean fsserial_close P((struct ssysdep_conn *q));
+static boolean fsstdin_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsmodem_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsdirect_close P((struct sconnection *qconn,
+ pointer puuconf,
+ struct uuconf_dialer *qdialer,
+ boolean fsuccess));
+static boolean fsserial_reset P((struct sconnection *qconn));
+static boolean fsstdin_reset P((struct sconnection *qconn));
+static boolean fsstdin_read P((struct sconnection *qconn,
+ char *zbuf, size_t *pclen, size_t cmin,
+ int ctimeout, boolean freport));
+static boolean fsstdin_write P((struct sconnection *qconn,
+ const char *zwrite, size_t cwrite));
+static boolean fsserial_break P((struct sconnection *qconn));
+static boolean fsstdin_break P((struct sconnection *qconn));
+static boolean fsserial_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsstdin_set P((struct sconnection *qconn,
+ enum tparitysetting tparity,
+ enum tstripsetting tstrip,
+ enum txonxoffsetting txonxoff));
+static boolean fsmodem_carrier P((struct sconnection *qconn,
+ boolean fcarrier));
+static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
+static boolean fsstdin_chat P((struct sconnection *qconn,
+ char **pzprog));
+static long isserial_baud P((struct sconnection *qconn));
+
+/* The command table for standard input ports. */
+
+static const struct sconncmds sstdincmds =
+{
+ usserial_free,
+ NULL, /* pflock */
+ NULL, /* pfunlock */
+ fsstdin_open,
+ fsstdin_close,
+ fsstdin_reset,
+ NULL, /* pfdial */
+ fsstdin_read,
+ fsstdin_write,
+ fsysdep_conn_io,
+ fsstdin_break,
+ fsstdin_set,
+ NULL, /* pfcarrier */
+ fsstdin_chat,
+ isserial_baud
+};
+
+/* The command table for modem ports. */
+
+static const struct sconncmds smodemcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsmodem_open,
+ fsmodem_close,
+ fsserial_reset,
+ fmodem_dial,
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ fsmodem_carrier,
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* The command table for direct ports. */
+
+static const struct sconncmds sdirectcmds =
+{
+ usserial_free,
+ fsserial_lock,
+ fsserial_unlock,
+ fsdirect_open,
+ fsdirect_close,
+ fsserial_reset,
+ NULL, /* pfdial */
+ fsysdep_conn_read,
+ fsysdep_conn_write,
+ fsysdep_conn_io,
+ fsserial_break,
+ fsserial_set,
+ NULL, /* pfcarrier */
+ fsysdep_conn_chat,
+ isserial_baud
+};
+
+/* If the system will let us set both O_NDELAY and O_NONBLOCK, we do
+ so. This is because some ancient drivers on some systems appear to
+ look for one but not the other. Some other systems will give an
+ EINVAL error if we attempt to set both, so we use a static global
+ to hold the value we want to set. If we get EINVAL, we change the
+ global and try again (if some system gives an error other than
+ EINVAL, the code will have to be modified). */
+static int iSunblock = O_NDELAY | O_NONBLOCK;
+
+/* This code handles SIGALRM. See the discussion above
+ fsysdep_conn_read. Normally we ignore SIGALRM, but the handler
+ will temporarily be set to this function, which should set fSalarm
+ and then either longjmp or schedule another SIGALRM. fSalarm is
+ never referred to outside of this file, but we don't make it static
+ to try to fool compilers which don't understand volatile. */
+
+volatile sig_atomic_t fSalarm;
+
+static RETSIGTYPE
+usalarm (isig)
+ int isig;
+{
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, usalarm);
+#endif
+
+ fSalarm = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ longjmp (sSjmp_buf, 1);
+#else
+ alarm (1);
+#endif
+}
+
+/* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
+ SIGPIPE and another to restore the original state. When these
+ functions are called (in fsysdep_modem_close) SIGHUP is being
+ ignored. The routines are isblocksigs, which returns a value of
+ type HELD_SIG_MASK and usunblocksigs which takes a single argument
+ of type HELD_SIG_MASK. */
+
+#if HAVE_SIGPROCMASK
+
+/* Use the POSIX sigprocmask call. */
+
+#define HELD_SIG_MASK sigset_t
+
+static sigset_t isblocksigs P((void));
+
+static sigset_t
+isblocksigs ()
+{
+ sigset_t sblock, sold;
+
+ /* These expressions need an extra set of parentheses to avoid a bug
+ in SCO 3.2.2. */
+ (void) (sigemptyset (&sblock));
+ (void) (sigaddset (&sblock, SIGINT));
+ (void) (sigaddset (&sblock, SIGQUIT));
+ (void) (sigaddset (&sblock, SIGTERM));
+ (void) (sigaddset (&sblock, SIGPIPE));
+
+ (void) sigprocmask (SIG_BLOCK, &sblock, &sold);
+ return sold;
+}
+
+#define usunblocksigs(s) \
+ ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
+
+#else /* ! HAVE_SIGPROCMASK */
+#if HAVE_SIGBLOCK
+
+/* Use the BSD sigblock and sigsetmask calls. */
+
+#define HELD_SIG_MASK int
+
+#ifndef sigmask
+#define sigmask(i) (1 << ((i) - 1))
+#endif
+
+#define isblocksigs() \
+ sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
+ | sigmask (SIGTERM) | sigmask (SIGPIPE))
+
+#define usunblocksigs(i) ((void) sigsetmask (i))
+
+#else /* ! HAVE_SIGBLOCK */
+
+#if HAVE_SIGHOLD
+
+/* Use the SVR3 sighold and sigrelse calls. */
+
+#define HELD_SIG_MASK int
+
+static int isblocksigs P((void));
+
+static int
+isblocksigs ()
+{
+ sighold (SIGINT);
+ sighold (SIGQUIT);
+ sighold (SIGTERM);
+ sighold (SIGPIPE);
+ return 0;
+}
+
+static void usunblocksigs P((int));
+
+/*ARGSUSED*/
+static void
+usunblocksigs (i)
+ int i;
+{
+ sigrelse (SIGINT);
+ sigrelse (SIGQUIT);
+ sigrelse (SIGTERM);
+ sigrelse (SIGPIPE);
+}
+
+#else /* ! HAVE_SIGHOLD */
+
+/* We have no way to block signals. This system will suffer from a
+ race condition in fsysdep_modem_close. */
+
+#define HELD_SIG_MASK int
+
+#define isblocksigs() 0
+
+#define usunblocksigs(i)
+
+#endif /* ! HAVE_SIGHOLD */
+#endif /* ! HAVE_SIGBLOCK */
+#endif /* ! HAVE_SIGPROCMASK */
+
+/* Initialize a connection for use on a serial port. */
+
+static boolean
+fsserial_init (qconn, qcmds, zdevice)
+ struct sconnection *qconn;
+ const struct sconncmds *qcmds;
+ const char *zdevice;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
+ if (zdevice == NULL
+ && qconn->qport != NULL
+ && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ zdevice = qconn->qport->uuconf_zname;
+ if (zdevice == NULL)
+ q->zdevice = NULL;
+ else if (*zdevice == '/')
+ q->zdevice = zbufcpy (zdevice);
+ else
+ {
+ size_t clen;
+
+ clen = strlen (zdevice);
+ q->zdevice = zbufalc (sizeof "/dev/" + clen);
+ memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1);
+ memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen);
+ q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
+ }
+ q->o = -1;
+ q->ftli = FALSE;
+ qconn->psysdep = (pointer) q;
+ qconn->qcmds = qcmds;
+ return TRUE;
+}
+
+/* Initialize a connection for use on standard input. */
+
+boolean
+fsysdep_stdin_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sstdincmds, (const char *) NULL);
+}
+
+/* Initialize a connection for use on a modem port. */
+
+boolean
+fsysdep_modem_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &smodemcmds,
+ qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
+}
+
+/* Initialize a connection for use on a direct port. */
+
+boolean
+fsysdep_direct_init (qconn)
+ struct sconnection *qconn;
+{
+ return fsserial_init (qconn, &sdirectcmds,
+ qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
+}
+
+/* Free up a serial port. */
+
+static void
+usserial_free (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ ubuffree (qsysdep->zdevice);
+ xfree ((pointer) qsysdep);
+ qconn->psysdep = NULL;
+}
+
+/* This routine is used for both locking and unlocking. It is the
+ only routine which knows how to translate a device name into the
+ name of a lock file. If it can't figure out a name, it does
+ nothing and returns TRUE. */
+
+static boolean
+fsserial_lockfile (flok, qconn)
+ boolean flok;
+ const struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+ char *zalc;
+ boolean fret;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qconn->qport == NULL)
+ z = NULL;
+ else
+ z = qconn->qport->uuconf_zlockname;
+ zalc = NULL;
+ if (z == NULL)
+ {
+#if ! HAVE_SVR4_LOCKFILES
+ {
+ const char *zbase;
+ size_t clen;
+
+ zbase = strrchr (qsysdep->zdevice, '/') + 1;
+ clen = strlen (zbase);
+ zalc = zbufalc (sizeof "LCK.." + clen);
+ memcpy (zalc, "LCK..", sizeof "LCK.." - 1);
+ memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1);
+#if HAVE_SCO_LOCKFILES
+ {
+ char *zl;
+
+ for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++)
+ if (isupper (*zl))
+ *zl = tolower (*zl);
+ }
+#endif
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+#if HAVE_SVR4_LOCKFILES
+ {
+ struct stat s;
+
+ if (stat (qsysdep->zdevice, &s) != 0)
+ {
+ ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ zalc = zbufalc (sizeof "LK.123.123.123");
+ sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
+ major (s.st_rdev), minor (s.st_rdev));
+ z = zalc;
+ }
+#else /* ! HAVE_SVR4_LOCKFILES */
+ z = strrchr (qsysdep->zdevice, '/') + 1;
+#endif /* ! HAVE_SVR4_LOCKFILES */
+#endif /* ! HAVE_SVR4_LOCKFILES */
+ }
+
+ if (flok)
+ fret = fsdo_lock (z, FALSE, (boolean *) NULL);
+ else
+ fret = fsdo_unlock (z, FALSE);
+
+#if HAVE_COHERENT_LOCKFILES
+ if (fret)
+ {
+ if (flok)
+ {
+ if (lockttyexist (z))
+ {
+ ulog (LOG_NORMAL, "%s: port already locked");
+ fret = FALSE;
+ }
+ else
+ fret = fscoherent_disable_tty (z, &qsysdep->zenable);
+ }
+ else
+ {
+ fret = TRUE;
+ if (qsysdep->zenable != NULL)
+ {
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = "/etc/enable";
+ azargs[1] = qsysdep->zenable;
+ azargs[2] = NULL;
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE,
+ (const char *) NULL, TRUE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s",
+ qsysdep->zenable, strerror (errno));
+ fret = FALSE;
+ }
+ else
+ {
+ if (ixswait ((unsigned long) ipid, (const char *) NULL)
+ == 0)
+ fret = TRUE;
+ else
+ fret = FALSE;
+ }
+ ubuffree (qsysdep->zenable);
+ qsysdep->zenable = NULL;
+ }
+ }
+ }
+#endif /* HAVE_COHERENT_LOCKFILES */
+
+ ubuffree (zalc);
+ return fret;
+}
+
+/* If we can mark a modem line in use, then when we lock a port we
+ must open it and mark it in use. We can't wait until the actual
+ open because we can't fail out if it is locked then. */
+
+static boolean
+fsserial_lock (qconn, fin)
+ struct sconnection *qconn;
+ boolean fin;
+{
+ if (! fsserial_lockfile (TRUE, qconn))
+ return FALSE;
+
+#if HAVE_TIOCSINUSE || HAVE_TIOCEXCL
+ /* Open the line and try to mark it in use. */
+ {
+ struct ssysdep_conn *qsysdep;
+ int iflag;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (fin)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag);
+ if (qsysdep->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ qsysdep->o = open (qsysdep->zdevice,
+ O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (qsysdep->o < 0)
+ {
+ if (errno != EBUSY)
+ ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice,
+ strerror (errno));
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+ }
+
+#if HAVE_TIOCSINUSE
+ /* If we can't mark it in use, return FALSE to indicate that the
+ lock failed. */
+ if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0)
+ {
+ if (errno != EALREADY)
+ ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+#endif
+
+ if (fcntl (qsysdep->o, F_SETFD,
+ fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ (void) close (qsysdep->o);
+ qsysdep->o = -1;
+ (void) fsserial_lockfile (FALSE, qconn);
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (qsysdep->o, TIOCSCTTY, 0);
+#endif
+ }
+#endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
+
+ return TRUE;
+}
+
+/* Unlock a modem or direct port. */
+
+static boolean
+fsserial_unlock (qconn)
+ struct sconnection *qconn;
+{
+ boolean fret;
+ struct ssysdep_conn *qsysdep;
+
+ fret = TRUE;
+
+ /* The file may have been opened by fsserial_lock, so close it here
+ if necessary. */
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ if (qsysdep->o >= 0)
+ {
+#ifdef TIOCNOTTY
+ (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
+#endif
+ if (close (qsysdep->o) < 0)
+ {
+ ulog (LOG_ERROR, "close: %s", strerror (errno));
+ fret = FALSE;
+ }
+ qsysdep->o = -1;
+ }
+
+ if (! fsserial_lockfile (FALSE, qconn))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Open a serial line. This sets the terminal settings. We begin in
+ seven bit mode and let the protocol change if necessary. */
+
+#if HAVE_POSIX_TERMIOS
+typedef speed_t baud_code;
+#else
+typedef int baud_code;
+#endif
+
+static struct sbaud_table
+{
+ baud_code icode;
+ long ibaud;
+} asSbaud_table[] =
+{
+ { B50, 50 },
+ { B75, 75 },
+ { B110, 110 },
+ { B134, 134 },
+ { B150, 150 },
+ { B200, 200 },
+ { B300, 300 },
+ { B600, 600 },
+ { B1200, 1200 },
+ { B1800, 1800 },
+ { B2400, 2400 },
+ { B4800, 4800 },
+ { B9600, 9600 },
+#ifdef B19200
+ { B19200, 19200 },
+#else /* ! defined (B19200) */
+#ifdef EXTA
+ { EXTA, 19200 },
+#endif /* EXTA */
+#endif /* ! defined (B19200) */
+#ifdef B38400
+ { B38400, 38400 },
+#else /* ! defined (B38400) */
+#ifdef EXTB
+ { EXTB, 38400 },
+#endif /* EXTB */
+#endif /* ! defined (B38400) */
+#ifdef B57600
+ { B57600, 57600 },
+#endif
+#ifdef B76800
+ { B76800, 76800 },
+#endif
+#ifdef B115200
+ { B115200, 115200 },
+#endif
+ { B0, 0 }
+};
+
+#define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+/* Hold the MIN value for the terminal to avoid setting it
+ unnecessarily. */
+static int cSmin;
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+static boolean
+fsserial_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+ baud_code ib;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (q->zdevice != NULL)
+ ulog_device (strrchr (q->zdevice, '/') + 1);
+ else
+ {
+ const char *zport;
+ boolean fdummy;
+
+#if DEBUG > 0
+ if (qconn->qport != NULL &&
+ qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
+ ulog (LOG_FATAL, "fsserial_open: Can't happen");
+#endif
+ zport = zsysdep_port_name (&fdummy);
+ if (zport != NULL)
+ ulog_device (zport);
+ }
+
+ ib = B0;
+ if (ibaud != 0)
+ {
+ int i;
+
+ for (i = 0; i < CBAUD_TABLE; i++)
+ if (asSbaud_table[i].ibaud == ibaud)
+ break;
+ if (i >= CBAUD_TABLE)
+ {
+ ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
+ return FALSE;
+ }
+ ib = asSbaud_table[i].icode;
+ }
+
+ /* The port may have already been opened by the locking routine. */
+ if (q->o < 0)
+ {
+ int iflag;
+
+ if (fwait)
+ iflag = 0;
+ else
+ iflag = iSunblock;
+
+ q->o = open (q->zdevice, O_RDWR | iflag);
+ if (q->o < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ q->o = open (q->zdevice, O_RDWR | O_NONBLOCK);
+ }
+#endif
+ if (q->o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice,
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ return FALSE;
+ }
+
+#ifdef TIOCSCTTY
+ /* On BSD 4.4, make it our controlling terminal. */
+ (void) ioctl (q->o, TIOCSCTTY, 0);
+#endif
+ }
+
+ /* Get the port flags, and make sure the ports are blocking. */
+
+ q->iflags = fcntl (q->o, F_GETFL, 0);
+ if (q->iflags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ q->istdout_flags = -1;
+
+ if (! fgetterminfo (q->o, &q->sorig))
+ {
+ q->fterminal = FALSE;
+ return TRUE;
+ }
+
+ q->fterminal = TRUE;
+
+ q->snew = q->sorig;
+
+#if HAVE_BSD_TTY
+
+ q->snew.stty.sg_flags = RAW | ANYP;
+ if (ibaud == 0)
+ ib = q->snew.stty.sg_ospeed;
+ else
+ {
+ q->snew.stty.sg_ispeed = ib;
+ q->snew.stty.sg_ospeed = ib;
+ }
+
+ /* We don't want to receive any interrupt characters. */
+ q->snew.stchars.t_intrc = -1;
+ q->snew.stchars.t_quitc = -1;
+ q->snew.stchars.t_eofc = -1;
+ q->snew.stchars.t_brkc = -1;
+ q->snew.sltchars.t_suspc = -1;
+ q->snew.sltchars.t_rprntc = -1;
+ q->snew.sltchars.t_dsuspc = -1;
+ q->snew.sltchars.t_flushc = -1;
+ q->snew.sltchars.t_werasc = -1;
+ q->snew.sltchars.t_lnextc = -1;
+
+#ifdef NTTYDISC
+ /* We want to use the ``new'' terminal driver so that we can use the
+ local mode bits to control XON/XOFF. */
+ {
+ int iparam;
+
+ if (ioctl (q->o, TIOCGETD, &iparam) >= 0
+ && iparam != NTTYDISC)
+ {
+ iparam = NTTYDISC;
+ (void) ioctl (q->o, TIOCSETD, &iparam);
+ }
+ }
+#endif
+
+#ifdef TIOCHPCL
+ /* When the file is closed, hang up the line. This is a safety
+ measure in case the program crashes. */
+ (void) ioctl (q->o, TIOCHPCL, 0);
+#endif
+
+#ifdef TIOCFLUSH
+ {
+ int iparam;
+
+ /* Flush pending input. */
+#ifdef FREAD
+ iparam = FREAD;
+#else
+ iparam = 0;
+#endif
+ (void) ioctl (q->o, TIOCFLUSH, &iparam);
+ }
+#endif /* TIOCFLUSH */
+
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO
+
+ if (ibaud == 0)
+ ib = q->snew.c_cflag & CBAUD;
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ q->snew.c_cflag |= (ib | ISET_CFLAG);
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+#ifdef TCFLSH
+ /* Flush pending input. */
+ (void) ioctl (q->o, TCFLSH, 0);
+#endif
+
+#endif /* HAVE_SYSV_TERMIO */
+
+#if HAVE_POSIX_TERMIOS
+
+ if (ibaud == 0)
+ ib = cfgetospeed (&q->snew);
+
+ q->snew.c_iflag &=~ ICLEAR_IFLAG;
+ q->snew.c_oflag &=~ ICLEAR_OFLAG;
+ q->snew.c_cflag &=~ ICLEAR_CFLAG;
+ q->snew.c_cflag |= ISET_CFLAG;
+ q->snew.c_lflag &=~ ICLEAR_LFLAG;
+ cSmin = 1;
+ q->snew.c_cc[VMIN] = cSmin;
+ q->snew.c_cc[VTIME] = 0;
+
+ (void) cfsetospeed (&q->snew, ib);
+ (void) cfsetispeed (&q->snew, ib);
+
+ /* Flush pending input. */
+ (void) tcflush (q->o, TCIFLUSH);
+
+#endif /* HAVE_POSIX_TERMIOS */
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (ibaud != 0)
+ q->ibaud = ibaud;
+ else
+ {
+ int i;
+
+ q->ibaud = (long) 1200;
+ for (i = 0; i < CBAUD_TABLE; i++)
+ {
+ if (asSbaud_table[i].icode == ib)
+ {
+ q->ibaud = asSbaud_table[i].ibaud;
+ break;
+ }
+ }
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsserial_open: Baud rate is %ld", q->ibaud);
+ }
+
+ return TRUE;
+}
+
+/* Open a standard input port. The code alternates q->o between 0 and
+ 1 as appropriate. It is always 0 before any call to fsblock. */
+
+static boolean
+fsstdin_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+ q->o = 0;
+ if (! fsserial_open (qconn, ibaud, fwait))
+ return FALSE;
+ q->istdout_flags = fcntl (1, F_GETFL, 0);
+ if (q->istdout_flags < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Open a modem port. */
+
+static boolean
+fsmodem_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Open a direct port. */
+
+static boolean
+fsdirect_open (qconn, ibaud, fwait)
+ struct sconnection *qconn;
+ long ibaud;
+ boolean fwait;
+{
+ if (ibaud == (long) 0)
+ ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud;
+ return fsserial_open (qconn, ibaud, fwait);
+}
+
+/* Change the blocking status of the port. We keep track of the
+ current blocking status to avoid calling fcntl unnecessarily; fcntl
+ turns out to be surprisingly expensive, at least on Ultrix. */
+
+static boolean
+fsblock (qs, fblock)
+ struct ssysdep_conn *qs;
+ boolean fblock;
+{
+ int iwant;
+ int isys;
+
+ if (fblock)
+ iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->iflags | iSunblock;
+
+ if (iwant == qs->iflags)
+ return TRUE;
+
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ if (isys < 0)
+ {
+#if O_NONBLOCK != 0
+ if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
+ {
+ iSunblock = O_NONBLOCK;
+ iwant = qs->iflags | O_NONBLOCK;
+ isys = fcntl (qs->o, F_SETFL, iwant);
+ }
+#endif
+ if (isys < 0)
+ {
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+ }
+
+ qs->iflags = iwant;
+
+ if (qs->istdout_flags >= 0)
+ {
+ if (fblock)
+ iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK);
+ else
+ iwant = qs->istdout_flags | iSunblock;
+
+ if (fcntl (1, F_SETFL, iwant) < 0)
+ {
+ /* We don't bother to fix up iSunblock here, since we
+ succeeded above. */
+ ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
+ return FALSE;
+ }
+
+ qs->istdout_flags = iwant;
+ }
+
+ return TRUE;
+}
+
+/* Close a serial port. */
+
+static boolean
+fsserial_close (q)
+ struct ssysdep_conn *q;
+{
+ if (q->o >= 0)
+ {
+ /* Use a 30 second timeout to avoid hanging while draining
+ output. */
+ if (q->fterminal)
+ {
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (q->o, &q->sorig);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we timed out, use the non draining call. Hopefully
+ this can't hang. */
+ if (fSalarm)
+ (void) fsetterminfo (q->o, &q->sorig);
+ }
+
+#ifdef TIOCNOTTY
+ /* We don't want this as our controlling terminal any more, so
+ get rid of it. This is necessary because we don't want to
+ open /dev/tty, since that can confuse the serial port locking
+ on some computers. */
+ (void) ioctl (q->o, TIOCNOTTY, (char *) NULL);
+#endif
+
+ (void) close (q->o);
+ q->o = -1;
+
+ /* Sleep to give the terminal a chance to settle, in case we are
+ about to call out again. */
+ sleep (2);
+ }
+
+ return TRUE;
+}
+
+/* Close a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ (void) close (1);
+ (void) close (2);
+ qsysdep->o = 0;
+ return fsserial_close (qsysdep);
+}
+
+/* Close a modem port. */
+
+static boolean
+fsmodem_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ struct ssysdep_conn *qsysdep;
+ boolean fret;
+ struct uuconf_dialer sdialer;
+ const struct uuconf_chat *qchat;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+ fret = TRUE;
+
+ /* Figure out the dialer so that we can run the complete or abort
+ chat scripts. */
+ if (qdialer == NULL)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
+ {
+ const char *zdialer;
+ int iuuconf;
+
+ zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
+ iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
+ if (iuuconf == UUCONF_SUCCESS)
+ qdialer = &sdialer;
+ else
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ fret = FALSE;
+ }
+ }
+ else
+ qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
+ }
+
+ /* Get the complete or abort chat script to use. */
+ qchat = NULL;
+ if (qdialer != NULL)
+ {
+ if (fsuccess)
+ qchat = &qdialer->uuconf_scomplete;
+ else
+ qchat = &qdialer->uuconf_sabort;
+ }
+
+ if (qchat != NULL
+ && (qchat->uuconf_pzprogram != NULL
+ || qchat->uuconf_pzchat != NULL))
+ {
+ boolean fsighup_ignored;
+ HELD_SIG_MASK smask;
+ int i;
+ sig_atomic_t afhold[INDEXSIG_COUNT];
+
+ /* We're no longer interested in carrier. */
+ (void) fsmodem_carrier (qconn, FALSE);
+
+ /* The port I/O routines check whether any signal has been
+ received, and abort if one has. While we are closing down
+ the modem, we don't care if we received a signal in the past,
+ but we do care if we receive a new signal (otherwise it would
+ be difficult to kill a uucico which was closing down a
+ modem). We never care if we get SIGHUP at this point. So we
+ turn off SIGHUP, remember what signals we've already seen,
+ and clear our notion of what signals we've seen. We have to
+ block the signals while we remember and clear the array,
+ since we might otherwise miss a signal which occurred between
+ the copy and the clear (old systems can't block signals; they
+ will just have to suffer the race). */
+ usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
+ smask = isblocksigs ();
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ {
+ afhold[i] = afSignal[i];
+ afSignal[i] = FALSE;
+ }
+ usunblocksigs (smask);
+
+ if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL,
+ (const struct uuconf_dialer *) NULL, (const char *) NULL,
+ FALSE, qconn->qport->uuconf_zname,
+ qsysdep->ibaud))
+ fret = FALSE;
+
+ /* Restore the old signal array and the SIGHUP handler. It is
+ not necessary to block signals here, since all we are doing
+ is exactly what the signal handler itself would do if the
+ signal occurred. */
+ for (i = 0; i < INDEXSIG_COUNT; i++)
+ if (afhold[i])
+ afSignal[i] = TRUE;
+ if (! fsighup_ignored)
+ usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
+ }
+
+ if (qdialer != NULL
+ && qdialer == &sdialer)
+ (void) uuconf_dialer_free (puuconf, &sdialer);
+
+#if ! HAVE_RESET_BUG
+ /* Reset the terminal to make sure we drop DTR. It should be
+ dropped when we close the descriptor, but that doesn't seem to
+ happen on some systems. Use a 30 second timeout to avoid hanging
+ while draining output. */
+ if (qsysdep->fterminal)
+ {
+#if HAVE_BSD_TTY
+ qsysdep->snew.stty.sg_ispeed = B0;
+ qsysdep->snew.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ (void) cfsetospeed (&qsysdep->snew, B0);
+#endif
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (30);
+
+ (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew);
+ }
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* Let the port settle. */
+ sleep (2);
+ }
+#endif /* ! HAVE_RESET_BUG */
+
+ if (! fsserial_close (qsysdep))
+ fret = FALSE;
+
+ return fret;
+}
+
+/* Close a direct port. */
+
+/*ARGSUSED*/
+static boolean
+fsdirect_close (qconn, puuconf, qdialer, fsuccess)
+ struct sconnection *qconn;
+ pointer puuconf;
+ struct uuconf_dialer *qdialer;
+ boolean fsuccess;
+{
+ return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
+}
+
+/* Reset a serial port by hanging up. */
+
+static boolean
+fsserial_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+ sterminal sbaud;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ sbaud = q->snew;
+
+#if HAVE_BSD_TTY
+ sbaud.stty.sg_ispeed = B0;
+ sbaud.stty.sg_ospeed = B0;
+#endif
+#if HAVE_SYSV_TERMIO
+ sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
+#endif
+#if HAVE_POSIX_TERMIOS
+ if (cfsetospeed (&sbaud, B0) < 0)
+ {
+ ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno));
+ return FALSE;
+ }
+#endif
+
+ if (! fsetterminfodrain (q->o, &sbaud))
+ {
+ ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ /* Give the terminal a chance to settle. */
+ sleep (2);
+
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Reset a standard input port. */
+
+static boolean
+fsstdin_reset (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_reset (qconn);
+}
+
+/* Begin dialing out on a modem port. This opens the dialer device if
+ there is one. */
+
+boolean
+fsysdep_modem_begin_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *qsysdep;
+ const char *z;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+
+#ifdef TIOCMODEM
+ /* If we can tell the modem to obey modem control, do so. */
+ {
+ int iperm;
+
+ iperm = 0;
+ (void) ioctl (qsysdep->o, TIOCMODEM, &iperm);
+ }
+#endif /* TIOCMODEM */
+
+ /* If we supposed to toggle DTR, do so. */
+
+ if (qdial->uuconf_fdtr_toggle)
+ {
+#ifdef TIOCCDTR
+ (void) ioctl (qsysdep->o, TIOCCDTR, 0);
+ sleep (2);
+ (void) ioctl (qsysdep->o, TIOCSDTR, 0);
+#else /* ! defined (TIOCCDTR) */
+ (void) fconn_reset (qconn);
+#endif /* ! defined (TIOCCDTR) */
+
+ if (qdial->uuconf_fdtr_toggle_wait)
+ sleep (2);
+ }
+
+ if (! fsmodem_carrier (qconn, FALSE))
+ return FALSE;
+
+ /* Open the dial device if there is one. */
+ z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device;
+ if (z != NULL)
+ {
+ char *zfree;
+ int o;
+
+ qsysdep->ohold = qsysdep->o;
+
+ zfree = NULL;
+ if (*z != '/')
+ {
+ zfree = zbufalc (sizeof "/dev/" + strlen (z));
+ sprintf (zfree, "/dev/%s", z);
+ z = zfree;
+ }
+
+ o = open ((char *) z, O_RDWR | O_NOCTTY);
+ if (o < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
+ ubuffree (zfree);
+ return FALSE;
+ }
+ ubuffree (zfree);
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return FALSE;
+ }
+
+ qsysdep->o = o;
+ }
+
+ return TRUE;
+}
+
+/* Tell the port to require or not require carrier. On BSD this uses
+ TIOCCAR and TIOCNCAR, which I assume are generally supported (it
+ can also use the LNOMDM bit supported by IS68K Unix). On System V
+ it resets or sets CLOCAL. We only require carrier if the port
+ supports it. This will only be called with fcarrier TRUE if the
+ dialer supports carrier. */
+
+static boolean
+fsmodem_carrier (qconn, fcarrier)
+ struct sconnection *qconn;
+ boolean fcarrier;
+{
+ register struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ if (fcarrier)
+ {
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier)
+ {
+#ifdef TIOCCAR
+ /* Tell the modem to pay attention to carrier. */
+ if (ioctl (q->o, TIOCCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into nonlocal mode. */
+ q->snew.c_cflag &=~ CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+ }
+ else
+ {
+#ifdef TIOCNCAR
+ /* Tell the modem to ignore carrier. */
+ if (ioctl (q->o, TIOCNCAR, 0) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
+ return FALSE;
+ }
+#endif /* TIOCNCAR */
+
+#if HAVE_BSD_TTY
+#ifdef LNOMDM
+ /* IS68K Unix uses a local LNOMDM bit. */
+ {
+ int iparam;
+
+ iparam = LNOMDM;
+ if (ioctl (q->o, TIOCLBIS, &iparam) < 0)
+ {
+ ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+#endif /* LNOMDM */
+#endif /* HAVE_BSD_TTY */
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* Put the modem into local mode (ignore carrier) to start the chat
+ script. */
+ q->snew.c_cflag |= CLOCAL;
+ if (! fsetterminfo (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
+ return FALSE;
+ }
+
+#if HAVE_CLOCAL_BUG
+ /* On SCO and AT&T UNIX PC you have to reopen the port. */
+ {
+ int onew;
+
+ onew = open (q->zdevice, O_RDWR);
+ if (onew < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno));
+ return FALSE;
+ }
+
+ if (fcntl (onew, F_SETFD,
+ fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (onew);
+ return FALSE;
+ }
+
+ (void) close (q->o);
+ q->o = onew;
+ }
+#endif /* HAVE_CLOCAL_BUG */
+
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+ }
+
+ return TRUE;
+}
+
+/* Finish dialing out on a modem by closing any dialer device and waiting
+ for carrier. */
+
+boolean
+fsysdep_modem_end_dial (qconn, qdial)
+ struct sconnection *qconn;
+ struct uuconf_dialer *qdial;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
+ {
+ (void) close (q->o);
+ q->o = q->ohold;
+ }
+
+ if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier
+ && qdial->uuconf_fcarrier)
+ {
+ /* Tell the port that we need carrier. */
+ if (! fsmodem_carrier (qconn, TRUE))
+ return FALSE;
+
+#ifdef TIOCWONLINE
+
+ /* We know how to wait for carrier, so do so. */
+
+ /* If we already got a signal, just quit now. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* This bit of code handles signals just like fsysdep_conn_read
+ does. See that function for a longer explanation. */
+
+ /* Use fsysdep_catch to handle a longjmp from the signal
+ handler. */
+
+ fSalarm = FALSE;
+
+ if (fsysdep_catch ())
+ {
+ /* Start catching SIGALRM; normally we ignore it. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ (void) alarm (qdial->uuconf_ccarrier_wait);
+
+ /* We really don't care if we get an error, since that will
+ probably just mean that TIOCWONLINE isn't supported in
+ which case there's nothing we can do anyhow. If we get
+ SIGINT we want to keep waiting for carrier, because
+ SIGINT just means don't start any new sessions. We don't
+ handle SIGINT correctly if we do a longjmp in the signal
+ handler; too bad. */
+ while (ioctl (q->o, TIOCWONLINE, 0) < 0
+ && errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ if (FGOT_QUIT_SIGNAL () || fSalarm)
+ break;
+ }
+ }
+
+ /* Turn off the pending SIGALRM and ignore SIGALARM again. */
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ (void) alarm (0);
+ usysdep_end_catch ();
+
+ /* If we got a random signal, just return FALSE. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+ /* If we timed out, give an error. */
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR, "Timed out waiting for carrier");
+ return FALSE;
+ }
+
+#endif /* TIOCWONLINE */
+ }
+
+ return TRUE;
+}
+
+/* Read data from a connection, with a timeout. This routine handles
+ all types of connections, including TLI.
+
+ This function should return when we have read cmin characters or
+ the timeout has occurred. We have to work a bit to get Unix to do
+ this efficiently on a terminal. The simple implementation
+ schedules a SIGALRM signal and then calls read; if there is a
+ single character available, the call to read will return
+ immediately, so there must be a loop which terminates when the
+ SIGALRM is delivered or the correct number of characters has been
+ read. This can be very inefficient with a fast CPU or a low baud
+ rate (or both!), since each call to read may return only one or two
+ characters.
+
+ Under POSIX or System V, we can specify a minimum number of
+ characters to read, so there is no serious trouble.
+
+ Under BSD, we figure out how many characters we have left to read,
+ how long it will take for them to arrive at the current baud rate,
+ and sleep that long.
+
+ Doing this with a timeout and avoiding all possible race conditions
+ get very hairy, though. Basically, we're going to schedule a
+ SIGALRM for when the timeout expires. I don't really want to do a
+ longjmp in the SIGALRM handler, though, because that may lose data.
+ Therefore, I have the signal handler set a variable. However, this
+ means that there will be a span of time between the time the code
+ checks the variable and the time it calls the read system call; if
+ the SIGALRM occurs during that time, the read might hang forever.
+ To avoid this, the SIGALRM handler not only sets a global variable,
+ it also schedules another SIGALRM for one second in the future
+ (POSIX specifies that a signal handler is permitted to safely call
+ alarm). To avoid getting a continual sequence of SIGALRM
+ interrupts, we change the signal handler to ignore SIGALRM when
+ we're about to exit the function. This means that every time we
+ execute fsysdep_conn_read we make at least five system calls. It's
+ the best I've been able to come up with, though.
+
+ When fsysdep_conn_read finishes, there will be no SIGALRM scheduled
+ and SIGALRM will be ignored. */
+
+boolean
+fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ CATCH_PROTECT size_t cwant;
+ boolean fret;
+ register struct ssysdep_conn * const q
+ = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwant = *pclen;
+ *pclen = 0;
+
+ /* Guard against a bad timeout. We return TRUE when a timeout
+ expires. It is possible to get a negative timeout here because
+ the calling code does not check user supplied timeouts for
+ plausibility. */
+ if (ctimeout <= 0)
+ return TRUE;
+
+ /* We want to do a blocking read. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ fSalarm = FALSE;
+
+ /* We're going to set up an alarm signal to last for the entire
+ read. If the read system call cannot be interrupted, the signal
+ handler will do a longjmp causing fsysdep_catch (a macro) to
+ return FALSE. We handle that here. If read can be interrupted,
+ fsysdep_catch will be defined to TRUE. */
+ if (fsysdep_catch ())
+ {
+ /* Prepare to catch SIGALRM and schedule the signal. */
+ usysdep_start_catch ();
+ usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
+ alarm (ctimeout);
+ }
+ else
+ {
+ /* We caught a signal. We don't actually have to do anything,
+ as all the appropriate checks are made at the start of the
+ following loop. */
+ }
+
+ fret = FALSE;
+
+ while (TRUE)
+ {
+ int cgot;
+
+#if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
+ /* If we can tell the terminal not to return until we have a
+ certain number of characters, do so. */
+ if (q->fterminal)
+ {
+ int csetmin;
+
+ /* I'm not that confident about setting MIN to values larger
+ than 127, although up to 255 would probably work. */
+ if (cmin < 127)
+ csetmin = cmin;
+ else
+ csetmin = 127;
+
+ if (csetmin != cSmin)
+ {
+ q->snew.c_cc[VMIN] = csetmin;
+ while (! fsetterminfo (q->o, &q->snew))
+ {
+ if (errno != EINTR
+ || FGOT_QUIT_SIGNAL ())
+ {
+ int ierr;
+
+ /* We turn off the signal before reporting the
+ error to minimize any problems with
+ interrupted system calls. */
+ ierr = errno;
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+ ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
+ strerror (ierr));
+ return FALSE;
+ }
+
+ if (fSalarm)
+ {
+ ulog (LOG_ERROR,
+ "Timed out when setting MIN to %d; retrying",
+ csetmin);
+ fSalarm = FALSE;
+ alarm (ctimeout);
+ }
+ }
+ cSmin = csetmin;
+ }
+ }
+#endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
+
+ /* If we've received a signal, get out now. */
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+
+ /* If we've already gotten a SIGALRM, get out with whatever
+ we've accumulated. */
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+
+ /* Right here is the race condition which we avoid by having the
+ SIGALRM handler schedule another SIGALRM. */
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zbuf, cwant, &iflags);
+ if (cgot < 0 && t_errno != TSYSERR)
+ {
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zbuf, cwant);
+
+ /* If the read returned an error, check for signals. */
+ if (cgot < 0)
+ {
+ if (errno == EINTR)
+ {
+ /* Log the signal. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+ if (fSalarm)
+ {
+ fret = TRUE;
+ break;
+ }
+ if (FGOT_QUIT_SIGNAL ())
+ break;
+ }
+
+ /* If read returned an error, get out. We just ignore EINTR
+ here, since it must be from some signal we don't care about.
+ If the read returned 0 then the line must have been hung up
+ (normally we would have received SIGHUP, but we can't count
+ on that). We turn off the signals before calling ulog to
+ reduce problems with interrupted system calls. */
+ if (cgot <= 0)
+ {
+ if (cgot < 0 && errno == EINTR)
+ cgot = 0;
+ else
+ {
+ int ierr;
+
+ ierr = errno;
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ if (freport)
+ {
+ if (cgot == 0)
+ ulog (LOG_ERROR, "Line disconnected");
+ else
+ ulog (LOG_ERROR, "read: %s", strerror (ierr));
+ }
+
+ return FALSE;
+ }
+ }
+
+ cwant -= cgot;
+ if (cgot >= cmin)
+ cmin = 0;
+ else
+ cmin -= cgot;
+ zbuf += cgot;
+ *pclen += cgot;
+
+ /* If we have enough data, get out now. */
+ if (cmin == 0)
+ {
+ fret = TRUE;
+ break;
+ }
+
+#if HAVE_BSD_TTY
+ /* We still want more data, so sleep long enough for the rest of
+ it to arrive. We don't this for System V or POSIX because
+ setting MIN is good enough (we can't sleep longer than it
+ takes to get MAX_INPUT characters anyhow).
+
+ The baud rate is approximately 10 times the number of
+ characters which will arrive in one second, so the number of
+ milliseconds to sleep ==
+ characters * (milliseconds / character) ==
+ characters * (1000 * (seconds / character)) ==
+ characters * (1000 * (1 / (baud / 10))) ==
+ characters * (10000 / baud)
+
+ We arbitrarily reduce the sleep amount by 10 milliseconds to
+ attempt to account for the amount of time it takes to set up
+ the sleep. This is how long it takes to get half a character
+ at 19200 baud. We then don't bother to sleep for less than
+ 10 milliseconds. We don't sleep if the read was interrupted.
+
+ We use select to sleep. It would be easy to use poll as
+ well, but it's unlikely that any system with BSD ttys would
+ have poll but not select. Using select avoids hassles with
+ the pending SIGALRM; if it hits the select will be
+ interrupted, and otherwise the select will not affect it. */
+
+#if ! HAVE_SELECT
+ #error This code requires select; feel free to extend it
+#endif
+
+ if (q->fterminal && cmin > 1 && cgot > 0)
+ {
+ int csleepchars;
+ int isleep;
+
+ /* We don't try to read all the way up to MAX_INPUT,
+ since that might drop a character. */
+ if (cmin <= MAX_INPUT - 10)
+ csleepchars = cmin;
+ else
+ csleepchars = MAX_INPUT - 10;
+
+ isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
+ isleep -= 10;
+
+ if (isleep > 10)
+ {
+ struct timeval s;
+
+ s.tv_sec = isleep / 1000;
+ s.tv_usec = (isleep % 1000) * 1000;
+
+ /* Some versions of select take a pointer to an int,
+ while some take a pointer to an fd_set. I just cast
+ the arguments to a generic pointer, and assume that
+ any machine which distinguishes int * from fd_set *
+ (I would be amazed if there are any such machines)
+ have an appropriate prototype somewhere or other. */
+ (void) select (0, (pointer) NULL, (pointer) NULL,
+ (pointer) NULL, &s);
+
+ /* Here either the select finished sleeping or we got a
+ SIGALRM. If the latter occurred, fSalarm was set to
+ TRUE; it will be checked at the top of the loop. */
+ }
+ }
+#endif /* HAVE_BSD_TTY */
+ }
+
+ /* Turn off the pending SIGALRM and return. */
+
+ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
+ alarm (0);
+ usysdep_end_catch ();
+
+ return fret;
+}
+
+/* Read from a stdin port. */
+
+static boolean
+fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
+ struct sconnection *qconn;
+ char *zbuf;
+ size_t *pclen;
+ size_t cmin;
+ int ctimeout;
+ boolean freport;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
+}
+
+/* Write data to a connection. This routine handles all types of
+ connections, including TLI. */
+
+boolean
+fsysdep_conn_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *q;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ /* We want blocking writes here. */
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ czero = 0;
+
+ while (cwrite > 0)
+ {
+ int cdid;
+
+ /* Loop until we don't get an interrupt. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cwrite, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cwrite);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We were interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is lost.
+ If we fail to write anything ten times in a row, we
+ assume that this has happened. This is hacked in like
+ this because there seems to be no reliable way to tell
+ exactly why the write returned 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ czero = 0;
+
+ cwrite -= cdid;
+ zwrite += cdid;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Write to a stdin port. */
+
+static boolean
+fsstdin_write (qconn, zwrite, cwrite)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t cwrite;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ if (! fsblock (qsysdep, TRUE))
+ return FALSE;
+ qsysdep->o = 1;
+ return fsysdep_conn_write (qconn, zwrite, cwrite);
+}
+
+/* The fsysdep_conn_io routine is supposed to both read and write data
+ until it has either filled its read buffer or written out all the
+ data it was given. This lets us write out large packets without
+ losing incoming data. It handles all types of connections,
+ including TLI. */
+
+boolean
+fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
+ struct sconnection *qconn;
+ const char *zwrite;
+ size_t *pcwrite;
+ char *zread;
+ size_t *pcread;
+{
+ struct ssysdep_conn *q;
+ size_t cwrite, cread;
+ int czero;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ cwrite = *pcwrite;
+ *pcwrite = 0;
+ cread = *pcread;
+ *pcread = 0;
+
+ czero = 0;
+
+ while (TRUE)
+ {
+ int cgot, cdid;
+ size_t cdo;
+
+ /* This used to always use nonblocking writes, but it turns out
+ that some systems don't support them on terminals.
+
+ The current algorithm is:
+ loop:
+ unblocked read
+ if read buffer full, return
+ if nothing to write, return
+ if HAVE_UNBLOCKED_WRITES
+ write all data
+ else
+ write up to SINGLE_WRITE bytes
+ if all data written, return
+ if no data written
+ blocked write of up to SINGLE_WRITE bytes
+
+ This algorithm should work whether the system supports
+ unblocked writes on terminals or not. If the system supports
+ unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
+ call write more often than it needs to. If the system does
+ not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
+ then the write may hang so long that incoming data is lost.
+ This is actually possible at high baud rates on any system
+ when a blocking write is done; there is no solution, except
+ hardware handshaking. */
+
+ /* If we are running on standard input, we switch the file
+ descriptors by hand. */
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ /* Do an unblocked read. */
+ if (! fsblock (q, FALSE))
+ return FALSE;
+
+ /* Loop until we get something (error or data) other than an
+ acceptable EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ int iflags;
+
+ cgot = t_rcv (q->o, zread, cread, &iflags);
+ if (cgot < 0)
+ {
+ if (t_errno == TNODATA)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_rcv: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cgot = read (q->o, zread, cread);
+
+ if (cgot >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cgot < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "read: %s", strerror (errno));
+ return FALSE;
+ }
+ cgot = 0;
+ }
+
+ cread -= cgot;
+ zread += cgot;
+ *pcread += cgot;
+
+ /* If we've filled the read buffer, or we have nothing left to
+ write, return out. */
+ if (cread == 0 || cwrite == 0)
+ return TRUE;
+
+ /* The port is currently unblocked. Do a write. */
+ cdo = cwrite;
+
+#if ! HAVE_UNBLOCKED_WRITES
+ if (q->fterminal && cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+#endif
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0)
+ {
+ if (t_errno == TFLOW)
+ errno = EAGAIN;
+ else if (t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+ cdid = 0;
+ }
+
+ if (cdid > 0)
+ {
+ /* We wrote some data. If we wrote everything, return out.
+ Otherwise loop around and do another read. */
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+
+ if (cwrite == 0)
+ return TRUE;
+
+ czero = 0;
+ }
+ else
+ {
+ /* We didn't write any data. Do a blocking write. */
+
+ if (q->istdout_flags >= 0)
+ q->o = 0;
+
+ if (! fsblock (q, TRUE))
+ return FALSE;
+
+ cdo = cwrite;
+ if (cdo > SINGLE_WRITE)
+ cdo = SINGLE_WRITE;
+
+ DEBUG_MESSAGE1 (DEBUG_PORT,
+ "fsysdep_conn_io: Blocking write of %lud",
+ (unsigned long) cdo);
+
+ if (q->istdout_flags >= 0)
+ q->o = 1;
+
+ /* Loop until we get something besides EINTR. */
+ while (TRUE)
+ {
+ /* If we've received a signal, don't continue. */
+ if (FGOT_QUIT_SIGNAL ())
+ return FALSE;
+
+#if HAVE_TLI
+ if (q->ftli)
+ {
+ cdid = t_snd (q->o, zwrite, cdo, 0);
+ if (cdid < 0 && t_errno != TSYSERR)
+ {
+ ulog (LOG_ERROR, "t_snd: %s",
+ (t_errno >= 0 && t_errno < t_nerr
+ ? t_errlist[t_errno]
+ : "unknown TLI error"));
+ return FALSE;
+ }
+ }
+ else
+#endif
+ cdid = write (q->o, zwrite, cdo);
+
+ if (cdid >= 0)
+ break;
+ if (errno != EINTR)
+ break;
+
+ /* We got interrupted by a signal. Log it. */
+ ulog (LOG_ERROR, (const char *) NULL);
+ }
+
+ if (cdid < 0)
+ {
+ ulog (LOG_ERROR, "write: %s", strerror (errno));
+ return FALSE;
+ }
+
+ if (cdid == 0)
+ {
+ /* On some systems write will return 0 if carrier is
+ lost. If we fail to write anything ten times in a
+ row, we assume that this has happened. This is
+ hacked in like this because there seems to be no
+ reliable way to tell exactly why the write returned
+ 0. */
+ ++czero;
+ if (czero >= 10)
+ {
+ ulog (LOG_ERROR, "Line disconnected");
+ return FALSE;
+ }
+ }
+ else
+ {
+ cwrite -= cdid;
+ zwrite += cdid;
+ *pcwrite += cdid;
+ czero = 0;
+ }
+ }
+ }
+}
+
+/* Send a break character to a serial port. */
+
+static boolean
+fsserial_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *q;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+#if HAVE_BSD_TTY
+ (void) ioctl (q->o, TIOCSBRK, 0);
+ sleep (2);
+ (void) ioctl (q->o, TIOCCBRK, 0);
+ return TRUE;
+#endif /* HAVE_BSD_TTY */
+#if HAVE_SYSV_TERMIO
+ (void) ioctl (q->o, TCSBRK, 0);
+ return TRUE;
+#endif /* HAVE_SYSV_TERMIO */
+#if HAVE_POSIX_TERMIOS
+ return tcsendbreak (q->o, 0) == 0;
+#endif /* HAVE_POSIX_TERMIOS */
+}
+
+/* Send a break character to a stdin port. */
+
+static boolean
+fsstdin_break (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 1;
+ return fsserial_break (qconn);
+}
+
+/* Change the setting of a serial port. */
+
+/*ARGSUSED*/
+static boolean
+fsserial_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ register struct ssysdep_conn *q;
+ boolean fchanged, fdo;
+ int iset = 0;
+ int iclear = 0;
+
+ q = (struct ssysdep_conn *) qconn->psysdep;
+
+ if (! q->fterminal)
+ return TRUE;
+
+ fchanged = FALSE;
+
+ /* Set the parity for output characters. */
+
+#if HAVE_BSD_TTY
+
+ /* This will also cause parity detection on input characters. */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+#if HAVE_PARITY_BUG
+ /* The Sony NEWS mishandles this for some reason. */
+ iset = 0;
+ iclear = ANYP;
+#else
+ iset = ANYP;
+ iclear = 0;
+#endif
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = EVENP;
+ iclear = ODDP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = ODDP;
+ iclear = EVENP;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tparity)
+ {
+ case PARITYSETTING_DEFAULT:
+ break;
+ case PARITYSETTING_NONE:
+ iset = CS8;
+ iclear = PARENB | PARODD | (CSIZE &~ CS8);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_EVEN:
+ iset = PARENB | CS7;
+ iclear = PARODD | (CSIZE &~ CS7);
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_ODD:
+ iset = PARENB | PARODD | CS7;
+ iclear = CSIZE &~ CS7;
+ fdo = TRUE;
+ break;
+ case PARITYSETTING_MARK:
+ case PARITYSETTING_SPACE:
+ /* Not supported. */
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_cflag & iset) != iset
+ || (q->snew.c_cflag & iclear) != 0)
+ {
+ q->snew.c_cflag |= iset;
+ q->snew.c_cflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set whether input characters are stripped to seven bits. */
+
+#if HAVE_BSD_TTY
+
+#ifdef LPASS8
+ {
+ int i;
+
+ i = LPASS8;
+ if (tstrip == STRIPSETTING_EIGHTBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+ }
+ else if (tstrip == STRIPSETTING_SEVENBITS)
+ {
+ i = LPASS8;
+ (void) ioctl (q->o, TIOCLBIC, &i);
+ }
+ }
+#endif
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (tstrip)
+ {
+ case STRIPSETTING_DEFAULT:
+ break;
+ case STRIPSETTING_EIGHTBITS:
+ iset = 0;
+ iclear = ISTRIP;
+ fdo = TRUE;
+ break;
+ case STRIPSETTING_SEVENBITS:
+ iset = ISTRIP;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ /* Set XON/XOFF handshaking. */
+
+#if HAVE_BSD_TTY
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = RAW;
+ iclear = TANDEM | CBREAK;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+ iset = CBREAK | TANDEM;
+ iclear = RAW;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.stty.sg_flags & iset) != iset
+ || (q->snew.stty.sg_flags & iclear) != 0)
+ {
+ q->snew.stty.sg_flags |= iset;
+ q->snew.stty.sg_flags &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#else /* ! HAVE_BSD_TTY */
+
+ fdo = FALSE;
+ switch (txonxoff)
+ {
+ case XONXOFF_DEFAULT:
+ break;
+ case XONXOFF_OFF:
+ iset = 0;
+ iclear = IXON | IXOFF;
+ fdo = TRUE;
+ break;
+ case XONXOFF_ON:
+#ifdef CRTSCTS
+#if HAVE_POSIX_TERMIOS
+ /* This is system dependent, but I haven't figured out a good
+ way around it yet. If we are doing hardware flow control, we
+ don't send XON/XOFF characters but we do recognize them. */
+ if ((q->snew.c_cflag & CRTSCTS) != 0)
+ {
+ iset = IXON;
+ iclear = IXOFF;
+ fdo = TRUE;
+ break;
+ }
+#endif /* HAVE_POSIX_TERMIOS */
+#endif /* defined (CRTSCTS) */
+ iset = IXON | IXOFF;
+ iclear = 0;
+ fdo = TRUE;
+ break;
+ }
+
+ if (fdo)
+ {
+ if ((q->snew.c_iflag & iset) != iset
+ || (q->snew.c_iflag & iclear) != 0)
+ {
+ q->snew.c_iflag |= iset;
+ q->snew.c_iflag &=~ iclear;
+ fchanged = TRUE;
+ }
+ }
+
+#endif /* ! HAVE_BSD_TTY */
+
+ if (fchanged)
+ {
+ if (! fsetterminfodrain (q->o, &q->snew))
+ {
+ ulog (LOG_ERROR, "Can't change terminal settings: %s",
+ strerror (errno));
+ return FALSE;
+ }
+ }
+
+#if HAVE_BSD_TTY
+ if (txonxoff == XONXOFF_ON
+ && (q->snew.stty.sg_flags & ANYP) == ANYP)
+ {
+ int i;
+
+ /* At least on Ultrix, we seem to have to set LLITOUT and
+ LPASS8. This shouldn't foul things up anywhere else. As far
+ as I can tell, this has to be done after setting the terminal
+ into cbreak mode, not before. */
+#ifndef LLITOUT
+#define LLITOUT 0
+#endif
+#ifndef LPASS8
+#define LPASS8 0
+#endif
+#ifndef LAUTOFLOW
+#define LAUTOFLOW 0
+#endif
+ i = LLITOUT | LPASS8 | LAUTOFLOW;
+ (void) ioctl (q->o, TIOCLBIS, &i);
+
+#if HAVE_STRIP_BUG
+ /* Ultrix 4.0 has a peculiar problem: setting CBREAK always
+ causes input characters to be stripped. I hope this does not
+ apply to other BSD systems. It is possible to work around
+ this by using the termio call. I wish this sort of stuff was
+ not necessary!!! */
+ {
+ struct termio s;
+
+ if (ioctl (q->o, TCGETA, &s) >= 0)
+ {
+ s.c_iflag &=~ ISTRIP;
+ (void) ioctl (q->o, TCSETA, &s);
+ }
+ }
+#endif /* HAVE_STRIP_BUG */
+ }
+#endif /* HAVE_BSD_TTY */
+
+ return TRUE;
+}
+
+/* Change settings of a stdin port. */
+
+static boolean
+fsstdin_set (qconn, tparity, tstrip, txonxoff)
+ struct sconnection *qconn;
+ enum tparitysetting tparity;
+ enum tstripsetting tstrip;
+ enum txonxoffsetting txonxoff;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ qsysdep->o = 0;
+ return fsserial_set (qconn, tparity, tstrip, txonxoff);
+}
+
+/* Run a chat program. */
+
+static boolean
+fsrun_chat (oread, owrite, pzprog)
+ int oread;
+ int owrite;
+ char **pzprog;
+{
+ int aidescs[3];
+ FILE *e;
+ pid_t ipid;
+ char *z;
+ size_t c;
+
+ aidescs[0] = oread;
+ aidescs[1] = owrite;
+ aidescs[2] = SPAWN_READ_PIPE;
+
+ /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the
+ responsibility of maintaing security on the chat program. */
+ ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE,
+ (const char *) NULL, FALSE, TRUE, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
+ return FALSE;
+ }
+
+ e = fdopen (aidescs[2], (char *) "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
+ (void) close (aidescs[2]);
+ (void) kill (ipid, SIGKILL);
+ (void) ixswait ((unsigned long) ipid, (const char *) NULL);
+ return FALSE;
+ }
+
+ /* The FILE e now is attached to stderr of the program. Forward
+ every line the program outputs to the log file. */
+ z = NULL;
+ c = 0;
+ while (getline (&z, &c, e) > 0)
+ {
+ size_t clen;
+
+ clen = strlen (z);
+ if (z[clen - 1] == '\n')
+ z[clen - 1] = '\0';
+ if (*z != '\0')
+ ulog (LOG_NORMAL, "chat: %s", z);
+ }
+
+ xfree ((pointer) z);
+ (void) fclose (e);
+
+ return ixswait ((unsigned long) ipid, "Chat program") == 0;
+}
+
+/* Run a chat program on a stdin port. */
+
+/*ARGSUSED*/
+static boolean
+fsstdin_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ return fsrun_chat (0, 1, pzprog);
+}
+
+/* Run a chat program on any general type of connection. */
+
+boolean
+fsysdep_conn_chat (qconn, pzprog)
+ struct sconnection *qconn;
+ char **pzprog;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
+}
+
+/* Return baud rate of a serial port. */
+
+static long
+isserial_baud (qconn)
+ struct sconnection *qconn;
+{
+ struct ssysdep_conn *qsysdep;
+
+ qsysdep = (struct ssysdep_conn *) qconn->psysdep;
+ return qsysdep->ibaud;
+}
diff --git a/gnu/libexec/uucp/libunix/signal.c b/gnu/libexec/uucp/libunix/signal.c
new file mode 100644
index 0000000..33e24a7
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/signal.c
@@ -0,0 +1,208 @@
+/* signal.c
+ Signal handling routines.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Signal handling routines. When we catch a signal, we want to set
+ the appropriate elements of afSignal and afLog_signal to TRUE. If
+ we are on a system which restarts system calls, we may also want to
+ longjmp out. On a system which does not restart system calls,
+ these signal handling routines are well-defined by ANSI C. */
+
+#if HAVE_RESTARTABLE_SYSCALLS
+volatile sig_atomic_t fSjmp;
+volatile jmp_buf sSjmp_buf;
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+
+/* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be
+ set in the sigaction structure to force system calls to be
+ interrupted. */
+#ifndef SA_INTERRUPT
+#define SA_INTERRUPT 0
+#endif
+
+/* The SVR3 sigset function can be called just like signal, unless
+ system calls are restarted which is extremely unlikely; we prevent
+ this case in sysh.unx. */
+#if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC
+#define signal sigset
+#endif
+
+/* The sigvec structure changed from 4.2BSD to 4.3BSD. These macros
+ make the 4.3 code backward compatible. */
+#ifndef SV_INTERRUPT
+#define SV_INTERRUPT 0
+#endif
+#if ! HAVE_SIGVEC_SV_FLAGS
+#define sv_flags sv_onstack
+#endif
+
+/* Catch a signal. Reinstall the signal handler if necessary, set the
+ appropriate variables, and do a longjmp if necessary. */
+
+RETSIGTYPE
+ussignal (isig)
+ int isig;
+{
+ int iindex;
+
+#if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
+ (void) signal (isig, ussignal);
+#endif
+
+ switch (isig)
+ {
+ default: iindex = INDEXSIG_SIGHUP; break;
+#ifdef SIGINT
+ case SIGINT: iindex = INDEXSIG_SIGINT; break;
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break;
+#endif
+#ifdef SIGTERM
+ case SIGTERM: iindex = INDEXSIG_SIGTERM; break;
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break;
+#endif
+ }
+
+ afSignal[iindex] = TRUE;
+ afLog_signal[iindex] = TRUE;
+
+#if HAVE_RESTARTABLE_SYSCALLS
+ if (fSjmp)
+ longjmp (sSjmp_buf, 1);
+#endif /* HAVE_RESTARTABLE_SYSCALLS */
+}
+
+/* Prepare to catch a signal. This is basically the ANSI C routine
+ signal, but it uses sigaction or sigvec instead if they are
+ available. If fforce is FALSE, we do not set the signal if it is
+ currently being ignored. If pfignored is not NULL and fforce is
+ FALSE, then *pfignored will be set to TRUE if the signal was
+ previously being ignored (if fforce is TRUE the value returned in
+ *pfignored is meaningless). If we can't change the signal handler
+ we give a fatal error. */
+
+void
+usset_signal (isig, pfn, fforce, pfignored)
+ int isig;
+ RETSIGTYPE (*pfn) P((int));
+ boolean fforce;
+ boolean *pfignored;
+{
+#if HAVE_SIGACTION
+
+ struct sigaction s;
+
+ if (! fforce)
+ {
+ (void) (sigemptyset (&s.sa_mask));
+ if (sigaction (isig, (struct sigaction *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+ if (s.sa_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sa_handler = pfn;
+ (void) (sigemptyset (&s.sa_mask));
+ s.sa_flags = SA_INTERRUPT;
+
+ if (sigaction (isig, &s, (struct sigaction *) NULL) != 0)
+ ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGACTION */
+#if HAVE_SIGVEC
+
+ struct sigvec s;
+
+ if (! fforce)
+ {
+ if (sigvec (isig, (struct sigvec *) NULL, &s) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+ if (s.sv_handler == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ s.sv_handler = pfn;
+ s.sv_mask = 0;
+ s.sv_flags = SV_INTERRUPT;
+
+ if (sigvec (isig, &s, (struct sigvec *) NULL) != 0)
+ ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno));
+
+#else /* ! HAVE_SIGVEC */
+
+ if (! fforce)
+ {
+ if (signal (isig, SIG_IGN) == SIG_IGN)
+ {
+ if (pfignored != NULL)
+ *pfignored = TRUE;
+ return;
+ }
+
+ if (pfignored != NULL)
+ *pfignored = FALSE;
+ }
+
+ (void) signal (isig, pfn);
+
+#endif /* ! HAVE_SIGVEC */
+#endif /* ! HAVE_SIGACTION */
+}
+
+/* The routine called by the system independent code, which always
+ uses the same signal handler. */
+
+void
+usysdep_signal (isig)
+ int isig;
+{
+ usset_signal (isig, ussignal, FALSE, (boolean *) NULL);
+}
diff --git a/gnu/libexec/uucp/libunix/sindir.c b/gnu/libexec/uucp/libunix/sindir.c
new file mode 100644
index 0000000..d987508
--- /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 0000000..8d021db
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/size.c
@@ -0,0 +1,27 @@
+/* size.c
+ Get the size in bytes of a file. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+long
+csysdep_size (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno == ENOENT)
+ return -1;
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return -2;
+ }
+
+ return s.st_size;
+}
diff --git a/gnu/libexec/uucp/libunix/sleep.c b/gnu/libexec/uucp/libunix/sleep.c
new file mode 100644
index 0000000..b232f96
--- /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 0000000..7ab080d
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/spawn.c
@@ -0,0 +1,398 @@
+/* spawn.c
+ Spawn a program securely.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef environ
+extern char **environ;
+#endif
+
+/* Spawn a child in a fairly secure fashion. This returns the process
+ ID of the child or -1 on error. It takes far too many arguments:
+
+ pazargs -- arguments (element 0 is command)
+ aidescs -- file descriptors for stdin, stdout and stderr
+ fkeepuid -- TRUE if euid should be left unchanged
+ fkeepenv -- TRUE if environment should be left unmodified
+ zchdir -- directory to chdir to
+ fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT
+ fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC
+ zpath -- value for environment variable PATH
+ zuu_machine -- value for environment variable UU_MACHINE
+ zuu_user -- value for environment variable UU_USER
+
+ The aidescs array is three elements long. 0 is stdin, 1 is stdout
+ and 2 is stderr. The array may contain either file descriptor
+ numbers to dup appropriately, or one of the following:
+
+ SPAWN_NULL -- set descriptor to /dev/null
+ SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read
+ SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write
+
+ If fkeepenv is FALSE, a standard environment is created. The
+ environment arguments (zpath, zuu_machine and zuu_user) are only
+ used if fkeepenv is FALSE; any of them may be NULL.
+
+ This routine expects that all file descriptors have been set to
+ close-on-exec, so it doesn't have to worry about closing them
+ explicitly. It sets the close-on-exec flag for the new pipe
+ descriptors it returns. */
+
+pid_t
+ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell,
+ zpath, zuu_machine, zuu_user)
+ const char **pazargs;
+ int aidescs[3];
+ boolean fkeepuid;
+ boolean fkeepenv;
+ const char *zchdir;
+ boolean fnosigs;
+ boolean fshell;
+ const char *zpath;
+ const char *zuu_machine;
+ const char *zuu_user;
+{
+ char *zshcmd;
+ int i;
+ char *azenv[9];
+ char **pazenv;
+ boolean ferr;
+ int ierr = 0;
+ int onull;
+ int aichild_descs[3];
+ int cpar_close;
+ int aipar_close[4];
+ int cchild_close;
+ int aichild_close[3];
+ pid_t iret = 0;
+ const char *zcmd;
+
+ /* If we might have to use the shell, allocate enough space for the
+ quoted command before forking. Otherwise the allocation would
+ modify the data segment and we could not safely use vfork. */
+ zshcmd = NULL;
+ if (fshell)
+ {
+ size_t clen;
+
+ clen = 0;
+ for (i = 0; pazargs[i] != NULL; i++)
+ clen += strlen (pazargs[i]);
+ zshcmd = zbufalc (2 * clen + i);
+ }
+
+ /* Set up a standard environment. This is again done before forking
+ because it will modify the data segment. */
+ if (fkeepenv)
+ pazenv = environ;
+ else
+ {
+ const char *zterm, *ztz;
+ char *zspace;
+ int ienv;
+
+ if (zpath == NULL)
+ zpath = CMDPATH;
+
+ azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath));
+ sprintf (azenv[0], "PATH=%s", zpath);
+ zspace = azenv[0] + sizeof "PATH=" - 1;
+ while ((zspace = strchr (zspace, ' ')) != NULL)
+ *zspace = ':';
+
+ azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir));
+ sprintf (azenv[1], "HOME=%s", zSspooldir);
+
+ zterm = getenv ("TERM");
+ if (zterm == NULL)
+ zterm = "unknown";
+ azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm));
+ sprintf (azenv[2], "TERM=%s", zterm);
+
+ azenv[3] = zbufcpy ("SHELL=/bin/sh");
+
+ azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER));
+ sprintf (azenv[4], "USER=%s", OWNER);
+
+ ienv = 5;
+
+ ztz = getenv ("TZ");
+ if (ztz != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz));
+ sprintf (azenv[ienv], "TZ=%s", ztz);
+ ++ienv;
+ }
+
+ if (zuu_machine != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_MACHINE="
+ + strlen (zuu_machine));
+ sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine);
+ ++ienv;
+ }
+
+ if (zuu_user != NULL)
+ {
+ azenv[ienv] = zbufalc (sizeof "UU_USER="
+ + strlen (zuu_user));
+ sprintf (azenv[ienv], "UU_USER=%s", zuu_user);
+ ++ienv;
+ }
+
+ azenv[ienv] = NULL;
+ pazenv = azenv;
+ }
+
+ /* Set up any needed pipes. */
+
+ ferr = FALSE;
+ onull = -1;
+ cpar_close = 0;
+ cchild_close = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aidescs[i] == SPAWN_NULL)
+ {
+ if (onull < 0)
+ {
+ onull = open ((char *) "/dev/null", O_RDWR);
+ if (onull < 0
+ || fcntl (onull, F_SETFD,
+ fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ (void) close (onull);
+ ferr = TRUE;
+ break;
+ }
+ aipar_close[cpar_close] = onull;
+ ++cpar_close;
+ }
+ aichild_descs[i] = onull;
+ }
+ else if (aidescs[i] != SPAWN_READ_PIPE
+ && aidescs[i] != SPAWN_WRITE_PIPE)
+ aichild_descs[i] = aidescs[i];
+ else
+ {
+ int aipipe[2];
+
+ if (pipe (aipipe) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+
+ if (aidescs[i] == SPAWN_READ_PIPE)
+ {
+ aidescs[i] = aipipe[0];
+ aichild_close[cchild_close] = aipipe[0];
+ aichild_descs[i] = aipipe[1];
+ aipar_close[cpar_close] = aipipe[1];
+ }
+ else
+ {
+ aidescs[i] = aipipe[1];
+ aichild_close[cchild_close] = aipipe[1];
+ aichild_descs[i] = aipipe[0];
+ aipar_close[cpar_close] = aipipe[0];
+ }
+
+ ++cpar_close;
+ ++cchild_close;
+
+ if (fcntl (aidescs[i], F_SETFD,
+ fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ierr = errno;
+ ferr = TRUE;
+ break;
+ }
+ }
+ }
+
+#if DEBUG > 1
+ if (! ferr && FDEBUGGING (DEBUG_EXECUTE))
+ {
+ ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]);
+ for (i = 1; pazargs[i] != NULL; i++)
+ ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]);
+ ulog (LOG_DEBUG_END, "%s", "");
+ }
+#endif
+
+ if (! ferr)
+ {
+ /* This should really be vfork if available. */
+ iret = ixsfork ();
+ if (iret < 0)
+ {
+ ferr = TRUE;
+ ierr = errno;
+ }
+ }
+
+ if (ferr)
+ {
+ for (i = 0; i < cchild_close; i++)
+ (void) close (aichild_close[i]);
+ iret = -1;
+ }
+
+ if (iret != 0)
+ {
+ /* The parent. Close the child's ends of the pipes and return
+ the process ID, or an error. */
+ for (i = 0; i < cpar_close; i++)
+ (void) close (aipar_close[i]);
+ ubuffree (zshcmd);
+ if (! fkeepenv)
+ {
+ char **pz;
+
+ for (pz = azenv; *pz != NULL; pz++)
+ ubuffree (*pz);
+ }
+ errno = ierr;
+ return iret;
+ }
+
+ /* The child. */
+
+#ifdef STDIN_FILENO
+#if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2
+ #error The following code makes invalid assumptions
+#endif
+#endif
+
+ for (i = 0; i < 3; i++)
+ {
+ if (aichild_descs[i] != i)
+ (void) dup2 (aichild_descs[i], i);
+ /* This should only be necessary if aichild_descs[i] == i, but
+ some systems copy the close-on-exec flag for a dupped
+ descriptor, which is wrong according to POSIX. */
+ (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC);
+ }
+
+ zcmd = pazargs[0];
+ pazargs[0] = strrchr (zcmd, '/');
+ if (pazargs[0] == NULL)
+ pazargs[0] = zcmd;
+ else
+ ++pazargs[0];
+
+ if (! fkeepuid)
+ {
+ (void) setuid (getuid ());
+ (void) setgid (getgid ());
+ }
+
+ if (zchdir != NULL)
+ (void) chdir (zchdir);
+
+ if (fnosigs)
+ {
+#ifdef SIGHUP
+ (void) signal (SIGHUP, SIG_IGN);
+#endif
+#ifdef SIGINT
+ (void) signal (SIGINT, SIG_IGN);
+#endif
+#ifdef SIGQUIT
+ (void) signal (SIGQUIT, SIG_IGN);
+#endif
+ }
+
+ (void) execve ((char *) zcmd, (char **) pazargs, pazenv);
+
+ /* The exec failed. If permitted, try using /bin/sh to execute a
+ shell script. */
+
+ if (errno == ENOEXEC && fshell)
+ {
+ char *zto;
+ const char *azshargs[4];
+
+ pazargs[0] = zcmd;
+ zto = zshcmd;
+ for (i = 0; pazargs[i] != NULL; i++)
+ {
+ const char *zfrom;
+
+ for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++)
+ {
+ /* Some versions of /bin/sh appear to have a bug such
+ that quoting a '/' sometimes causes an error. I
+ don't know exactly when this happens (I can recreate
+ it on Ultrix 4.0), but in any case it is harmless to
+ not quote a '/'. */
+ if (*zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom;
+ }
+ *zto++ = ' ';
+ }
+ *(zto - 1) = '\0';
+
+ azshargs[0] = "sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zshcmd;
+ azshargs[3] = NULL;
+
+ (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv);
+ }
+
+ _exit (EXIT_FAILURE);
+
+ /* Avoid compiler warning. */
+ return -1;
+}
diff --git a/gnu/libexec/uucp/libunix/splcmd.c b/gnu/libexec/uucp/libunix/splcmd.c
new file mode 100644
index 0000000..9f6616a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/splcmd.c
@@ -0,0 +1,115 @@
+/* splcmd.c
+ Spool a command.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+/* Given a set of commands to execute for a remote system, create a
+ command file holding them. This creates a single command file
+ holding all the commands passed in. It returns a jobid. */
+
+char *
+zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ int ccmds;
+ const struct scmd *pascmds;
+{
+ char *z;
+ FILE *e;
+ int i;
+ const struct scmd *q;
+ char *zjobid;
+
+#if DEBUG > 0
+ if (! UUCONF_GRADE_LEGAL (bgrade))
+ ulog (LOG_FATAL, "Bad grade %d", bgrade);
+#endif
+
+ z = zscmd_file (qsys, bgrade);
+ if (z == NULL)
+ return NULL;
+
+ e = esysdep_fopen (z, FALSE, FALSE, TRUE);
+ if (e == NULL)
+ {
+ ubuffree (z);
+ return NULL;
+ }
+
+ for (i = 0, q = pascmds; i < ccmds; i++, q++)
+ {
+ switch (q->bcmd)
+ {
+ case 'S':
+ fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify == NULL ? (const char *) "" : q->znotify);
+ break;
+ case 'R':
+ fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'X':
+ fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser,
+ q->zoptions);
+ break;
+ case 'E':
+ fprintf (e, "E %s %s %s -%s %s 0%o %s 0 %s\n", q->zfrom, q->zto,
+ q->zuser, q->zoptions, q->ztemp, q->imode,
+ q->znotify, q->zcmd);
+ break;
+ default:
+ ulog (LOG_ERROR,
+ "zsysdep_spool_commands: Unrecognized type %d",
+ q->bcmd);
+ (void) fclose (e);
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+ }
+
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ (void) remove (z);
+ ubuffree (z);
+ return NULL;
+ }
+
+ zjobid = zsfile_to_jobid (qsys, z, bgrade);
+ if (zjobid == NULL)
+ (void) remove (z);
+ ubuffree (z);
+ return zjobid;
+}
diff --git a/gnu/libexec/uucp/libunix/splnam.c b/gnu/libexec/uucp/libunix/splnam.c
new file mode 100644
index 0000000..06ce360
--- /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 0000000..f28229f
--- /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 0000000..28487ef
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/srmdir.c
@@ -0,0 +1,112 @@
+/* srmdir.c
+ Remove a directory and all its contents.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int isremove_dir P((const char *, const struct stat *, int));
+
+/* Keep a list of directories to be removed. */
+
+struct sdirlist
+{
+ struct sdirlist *qnext;
+ char *zdir;
+};
+
+static struct sdirlist *qSdirlist;
+
+/* Remove a directory and all files in it. */
+
+boolean
+fsysdep_rmdir (zdir)
+ const char *zdir;
+{
+ boolean fret;
+ struct sdirlist *q;
+
+ qSdirlist = NULL;
+
+ fret = TRUE;
+ if (ftw ((char *) zdir, isremove_dir, 5) != 0)
+ {
+ ulog (LOG_ERROR, "ftw: %s", strerror (errno));
+ fret = FALSE;
+ }
+
+ q = qSdirlist;
+ while (q != NULL)
+ {
+ struct sdirlist *qnext;
+
+ if (rmdir (q->zdir) != 0)
+ {
+ ulog (LOG_ERROR, "rmdir (%s): %s", q->zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (q->zdir);
+ qnext = q->qnext;
+ xfree ((pointer) q);
+ q = qnext;
+ }
+
+ return fret;
+}
+
+/* Remove a file in a directory. */
+
+/*ARGSUSED*/
+static int
+isremove_dir (zfile, qstat, iflag)
+ const char *zfile;
+ const struct stat *qstat;
+ int iflag;
+{
+ if (iflag == FTW_D || iflag == FTW_DNR)
+ {
+ struct sdirlist *q;
+
+ q = (struct sdirlist *) xmalloc (sizeof (struct sdirlist));
+ q->qnext = qSdirlist;
+ q->zdir = zbufcpy (zfile);
+ qSdirlist = q;
+ }
+ else
+ {
+ if (remove (zfile) != 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno));
+ }
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/statsb.c b/gnu/libexec/uucp/libunix/statsb.c
new file mode 100644
index 0000000..79a14c0
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/statsb.c
@@ -0,0 +1,572 @@
+/* statsb.c
+ System dependent routines for uustat.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char statsb_rcsid[] = "$Id: statsb.c,v 1.1 1993/08/04 19:33:06 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#if HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+/* Local functions. */
+
+static int ussettime P((const char *z, time_t inow));
+static boolean fskill_or_rejuv P((pointer puuconf, const char *zid,
+ boolean fkill));
+
+/* See whether the user is permitted to kill arbitrary jobs. This is
+ true only for root and uucp. We check for uucp by seeing if the
+ real user ID and the effective user ID are the same; this works
+ because we should be suid to uucp, so our effective user ID will
+ always be uucp while our real user ID will be whoever ran the
+ program. */
+
+boolean
+fsysdep_privileged ()
+{
+ uid_t iuid;
+
+ iuid = getuid ();
+ return iuid == 0 || iuid == geteuid ();
+}
+
+/* Set file access time to the present. On many systems this could be
+ done by passing NULL to utime, but on some that doesn't work. This
+ routine is not time critical, so we never rely on NULL. */
+
+static int
+ussettime(z, inow)
+ const char *z;
+ time_t inow;
+{
+#if HAVE_UTIME_H
+ struct utimbuf s;
+
+ s.actime = inow;
+ s.modtime = inow;
+ return utime ((char *) z, &s);
+#else
+ time_t ai[2];
+
+ ai[0] = inow;
+ ai[1] = inow;
+ return utime ((char *) z, ai);
+#endif
+}
+
+/* Kill a job, given the jobid. */
+
+boolean
+fsysdep_kill_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, TRUE);
+}
+
+/* Rejuvenate a job, given the jobid. */
+
+boolean
+fsysdep_rejuvenate_job (puuconf, zid)
+ pointer puuconf;
+ const char *zid;
+{
+ return fskill_or_rejuv (puuconf, zid, FALSE);
+}
+
+/* Kill or rejuvenate a job, given the jobid. */
+
+static boolean
+fskill_or_rejuv (puuconf, zid, fkill)
+ pointer puuconf;
+ const char *zid;
+ boolean fkill;
+{
+ char *zfile;
+ char *zsys;
+ char bgrade;
+ time_t inow = 0;
+ int iuuconf;
+ struct uuconf_system ssys;
+ FILE *e;
+ boolean fret;
+ char *zline;
+ size_t cline;
+ int isys;
+
+ zfile = zsjobid_to_file (zid, &zsys, &bgrade);
+ if (zfile == NULL)
+ return FALSE;
+
+ if (! fkill)
+ inow = time ((time_t *) NULL);
+
+ iuuconf = uuconf_system_info (puuconf, zsys, &ssys);
+ if (iuuconf == UUCONF_NOT_FOUND)
+ {
+ if (! funknown_system (puuconf, zsys, &ssys))
+ {
+ ulog (LOG_ERROR, "%s: Bad job id", zid);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+ }
+ else if (iuuconf != UUCONF_SUCCESS)
+ {
+ ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ e = fopen (zfile, "r");
+ if (e == NULL)
+ {
+ if (errno == ENOENT)
+ ulog (LOG_ERROR, "%s: Job not found", zid);
+ else
+ ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ /* Now we have to read through the file to identify any temporary
+ files. */
+ fret = TRUE;
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ struct scmd s;
+
+ if (! fparse_cmd (zline, &s))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s", zfile);
+ fret = FALSE;
+ continue;
+ }
+
+ /* You are only permitted to delete a job if you submitted it or
+ if you are root or uucp. */
+ if (strcmp (s.zuser, zsysdep_login_name ()) != 0
+ && ! fsysdep_privileged ())
+ {
+ ulog (LOG_ERROR, "%s: Not submitted by you", zid);
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zfile);
+ ubuffree (zsys);
+ return FALSE;
+ }
+
+ if (s.bcmd == 'S' || s.bcmd == 'E')
+ {
+ char *ztemp;
+
+ ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade);
+ if (ztemp == NULL)
+ fret = FALSE;
+ else
+ {
+ if (fkill)
+ isys = remove (ztemp);
+ else
+ isys = ussettime (ztemp, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s",
+ fkill ? "remove" : "utime", ztemp,
+ strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (ztemp);
+ }
+ }
+ }
+
+ xfree ((pointer) zline);
+ (void) fclose (e);
+ (void) uuconf_system_free (puuconf, &ssys);
+ ubuffree (zsys);
+
+ if (fkill)
+ isys = remove (zfile);
+ else
+ isys = ussettime (zfile, inow);
+
+ if (isys != 0 && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime",
+ zfile, strerror (errno));
+ fret = FALSE;
+ }
+
+ ubuffree (zfile);
+
+ return fret;
+}
+
+/* Get the time a work job was queued. */
+
+long
+ixsysdep_work_time (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ char *zjobid, *zfile;
+ long iret;
+
+ zjobid = zsysdep_jobid (qsys, pseq);
+ zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL);
+ if (zfile == NULL)
+ return 0;
+ ubuffree (zjobid);
+ iret = ixsysdep_file_time (zfile);
+ ubuffree (zfile);
+ return iret;
+}
+
+/* Get the time a file was created (actually, the time it was last
+ modified). */
+
+long
+ixsysdep_file_time (zfile)
+ const char *zfile;
+{
+ struct stat s;
+
+ if (stat ((char *) zfile, &s) < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno));
+ return ixsysdep_time ((long *) NULL);
+ }
+
+ return (long) s.st_mtime;
+}
+
+/* Start getting the status files. */
+
+boolean
+fsysdep_all_status_init (phold)
+ pointer *phold;
+{
+ DIR *qdir;
+
+ qdir = opendir ((char *) ".Status");
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno));
+ return FALSE;
+ }
+
+ *phold = (pointer) qdir;
+ return TRUE;
+}
+
+/* Get the next status file. */
+
+char *
+zsysdep_all_status (phold, pferr, qstat)
+ pointer phold;
+ boolean *pferr;
+ struct sstatus *qstat;
+{
+ DIR *qdir = (DIR *) phold;
+ struct dirent *qentry;
+
+ while (TRUE)
+ {
+ errno = 0;
+ qentry = readdir (qdir);
+ if (qentry == NULL)
+ {
+ if (errno == 0)
+ *pferr = FALSE;
+ else
+ {
+ ulog (LOG_ERROR, "readdir: %s", strerror (errno));
+ *pferr = TRUE;
+ }
+ return NULL;
+ }
+
+ if (qentry->d_name[0] != '.')
+ {
+ struct uuconf_system ssys;
+
+ /* Hack seriously; fsysdep_get_status only looks at the
+ zname element of the qsys argument, so if we fake that we
+ can read the status file. This should really be done
+ differently. */
+ ssys.uuconf_zname = qentry->d_name;
+ if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL))
+ return zbufcpy (qentry->d_name);
+
+ /* If fsysdep_get_status fails, it will output an error
+ message. We just continue with the next entry, so that
+ most of the status files will be displayed. */
+ }
+ }
+}
+
+/* Finish getting the status file. */
+
+void
+usysdep_all_status_free (phold)
+ pointer phold;
+{
+ DIR *qdir = (DIR *) phold;
+
+ (void) closedir (qdir);
+}
+
+/* Get the status of all processes holding lock files. We do this by
+ invoking ps after we've figured out the process entries to use. */
+
+boolean
+fsysdep_lock_status ()
+{
+ DIR *qdir;
+ struct dirent *qentry;
+ int calc;
+ int *pai;
+ int cgot;
+ int aidescs[3];
+ char *zcopy, *ztok;
+ int cargs, iarg;
+ char **pazargs;
+
+ qdir = opendir ((char *) zSlockdir);
+ if (qdir == NULL)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno));
+ return FALSE;
+ }
+
+ /* We look for entries that start with "LCK.." and ignore everything
+ else. This won't find all possible lock files, but it should
+ find all the locks on terminals and systems. */
+
+ calc = 0;
+ pai = NULL;
+ cgot = 0;
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *zname;
+ int o;
+#if HAVE_V2_LOCKFILES
+ int i;
+#else
+ char ab[12];
+#endif
+ int cread;
+ int ierr;
+ int ipid;
+
+ if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0)
+ continue;
+
+ zname = zsysdep_in_dir (zSlockdir, qentry->d_name);
+ o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0);
+ if (o < 0)
+ {
+ if (errno != ENOENT)
+ ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ continue;
+ }
+
+#if HAVE_V2_LOCKFILES
+ cread = read (o, &i, sizeof i);
+#else
+ cread = read (o, ab, sizeof ab - 1);
+#endif
+
+ ierr = errno;
+ (void) close (o);
+
+ if (cread < 0)
+ {
+ ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr));
+ ubuffree (zname);
+ continue;
+ }
+
+ ubuffree (zname);
+
+#if HAVE_V2_LOCKFILES
+ ipid = i;
+#else
+ ab[cread] = '\0';
+ ipid = strtol (ab, (char **) NULL, 10);
+#endif
+
+ printf ("%s: %d\n", qentry->d_name, ipid);
+
+ if (cgot >= calc)
+ {
+ calc += 10;
+ pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int));
+ }
+
+ pai[cgot] = ipid;
+ ++cgot;
+ }
+
+ if (cgot == 0)
+ return TRUE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = 1;
+ aidescs[2] = 2;
+
+ /* Parse PS_PROGRAM into an array of arguments. */
+ zcopy = zbufcpy (PS_PROGRAM);
+
+ cargs = 0;
+ for (ztok = strtok (zcopy, " \t");
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"))
+ ++cargs;
+
+ pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *));
+
+ memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM);
+ for (ztok = strtok (zcopy, " \t"), iarg = 0;
+ ztok != NULL;
+ ztok = strtok ((char *) NULL, " \t"), ++iarg)
+ pazargs[iarg] = ztok;
+ pazargs[iarg] = NULL;
+
+#if ! HAVE_PS_MULTIPLE
+ /* We have to invoke ps multiple times. */
+ {
+ int i;
+ char *zlast, *zset;
+
+ zlast = pazargs[cargs - 1];
+ zset = zbufalc (strlen (zlast) + 20);
+ for (i = 0; i < cgot; i++)
+ {
+ pid_t ipid;
+
+ sprintf (zset, "%s%d", zlast, pai[i]);
+ pazargs[cargs - 1] = zset;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ }
+ ubuffree (zset);
+ }
+#else
+ {
+ char *zlast;
+ int i;
+ pid_t ipid;
+
+ zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1);
+ strcpy (zlast, pazargs[cargs - 1]);
+ for (i = 0; i < cgot; i++)
+ {
+ char ab[20];
+
+ sprintf (ab, "%d", pai[i]);
+ strcat (zlast, ab);
+ if (i + 1 < cgot)
+ strcat (zlast, ",");
+ }
+ pazargs[cargs - 1] = zlast;
+
+ ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE,
+ (const char *) NULL, FALSE, TRUE,
+ (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ else
+ (void) ixswait ((unsigned long) ipid, PS_PROGRAM);
+ ubuffree (zlast);
+ }
+#endif
+
+ ubuffree (zcopy);
+ xfree ((pointer) pazargs);
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/status.c b/gnu/libexec/uucp/libunix/status.c
new file mode 100644
index 0000000..f403068
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/status.c
@@ -0,0 +1,212 @@
+/* status.c
+ Routines to get and set the status for a system.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+
+/* If we are using HDB spool layout, store status using HDB status
+ values. SVR4 is a variant of HDB. */
+
+#define MAP_STATUS 1
+
+static const int aiMapstatus[] =
+{
+ 0, 13, 7, 6, 4, 20, 3, 2
+};
+#define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0]))
+
+#else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+#define MAP_STATUS 0
+
+#endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */
+
+/* Get the status of a system. This assumes that we are in the spool
+ directory. */
+
+boolean
+fsysdep_get_status (qsys, qret, pfnone)
+ const struct uuconf_system *qsys;
+ struct sstatus *qret;
+ boolean *pfnone;
+{
+ char *zname;
+ FILE *e;
+ char *zline;
+ char *zend, *znext;
+ boolean fbad;
+ int istat;
+
+ if (pfnone != NULL)
+ *pfnone = FALSE;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ if (errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno));
+ ubuffree (zname);
+ return FALSE;
+ }
+ zline = NULL;
+ }
+ else
+ {
+ size_t cline;
+
+ zline = NULL;
+ cline = 0;
+ if (getline (&zline, &cline, e) <= 0)
+ {
+ xfree ((pointer) zline);
+ zline = NULL;
+ }
+ (void) fclose (e);
+ }
+
+ if (zline == NULL)
+ {
+ /* There is either no status file for this system, or it's been
+ truncated, so fake a good status. */
+ qret->ttype = STATUS_COMPLETE;
+ qret->cretries = 0;
+ qret->ilast = 0;
+ qret->cwait = 0;
+ if (pfnone != NULL)
+ *pfnone = TRUE;
+ ubuffree (zname);
+ return TRUE;
+ }
+
+ /* It turns out that scanf is not used much in this program, so for
+ the benefit of small computers we avoid linking it in. This is
+ basically
+
+ sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries,
+ &qret->ilast, &qret->cwait);
+
+ except that it's done with strtol. */
+
+ fbad = FALSE;
+ istat = (int) strtol (zline, &zend, 10);
+ if (zend == zline)
+ fbad = TRUE;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map system dependent status
+ values on to our status values. */
+ {
+ int i;
+
+ for (i = 0; i < CMAPENTRIES; ++i)
+ {
+ if (aiMapstatus[i] == istat)
+ {
+ istat = i;
+ break;
+ }
+ }
+ }
+#endif /* MAP_STATUS */
+
+ if (istat < 0 || istat >= (int) STATUS_VALUES)
+ istat = (int) STATUS_COMPLETE;
+ qret->ttype = (enum tstatus_type) istat;
+ znext = zend;
+ qret->cretries = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->ilast = strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+ znext = zend;
+ qret->cwait = (int) strtol (znext, &zend, 10);
+ if (zend == znext)
+ fbad = TRUE;
+
+ xfree ((pointer) zline);
+
+ if (fbad)
+ {
+ ulog (LOG_ERROR, "%s: Bad status file format", zname);
+ ubuffree (zname);
+ return FALSE;
+ }
+
+ ubuffree (zname);
+
+ return TRUE;
+}
+
+/* Set the status of a remote system. This assumes the system is
+ locked when this is called, and that the program is in the spool
+ directory. */
+
+boolean
+fsysdep_set_status (qsys, qset)
+ const struct uuconf_system *qsys;
+ const struct sstatus *qset;
+{
+ char *zname;
+ FILE *e;
+ int istat;
+
+ zname = zsysdep_in_dir (".Status", qsys->uuconf_zname);
+
+ e = esysdep_fopen (zname, TRUE, FALSE, TRUE);
+ ubuffree (zname);
+ if (e == NULL)
+ return FALSE;
+ istat = (int) qset->ttype;
+
+#if MAP_STATUS
+ /* On some systems it may be appropriate to map istat onto a system
+ dependent number. */
+ if (istat >= 0 && istat < CMAPENTRIES)
+ istat = aiMapstatus[istat];
+#endif /* MAP_STATUS */
+
+ fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries,
+ qset->ilast, qset->cwait, azStatus[(int) qset->ttype],
+ qsys->uuconf_zname);
+ if (fclose (e) != 0)
+ {
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libunix/strerr.c b/gnu/libexec/uucp/libunix/strerr.c
new file mode 100644
index 0000000..d2a6c21
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/strerr.c
@@ -0,0 +1,22 @@
+/* strerr.c
+ Return a string for a Unix errno value. */
+
+#include "uucp.h"
+
+#include <errno.h>
+
+#ifndef sys_nerr
+extern int sys_nerr;
+#endif
+#ifndef sys_errlist
+extern char *sys_errlist[];
+#endif
+
+char *
+strerror (ierr)
+ int ierr;
+{
+ if (ierr >= 0 && ierr < sys_nerr)
+ return sys_errlist[ierr];
+ return (char *) "unknown error";
+}
diff --git a/gnu/libexec/uucp/libunix/time.c b/gnu/libexec/uucp/libunix/time.c
new file mode 100644
index 0000000..d046243
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/time.c
@@ -0,0 +1,32 @@
+/* time.c
+ Get the current time. */
+
+#include "uucp.h"
+
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "system.h"
+
+#ifndef time
+extern time_t time ();
+#endif
+
+/* Get the time in seconds since the epoch, with optional
+ microseconds. We use ixsysdep_process_time to get the microseconds
+ if it will work (it won't if it uses times, since that returns a
+ time based only on the process). */
+
+long
+ixsysdep_time (pimicros)
+ long *pimicros;
+{
+#if HAVE_GETTIMEOFDAY || HAVE_FTIME
+ return ixsysdep_process_time (pimicros);
+#else
+ if (pimicros != NULL)
+ *pimicros = 0;
+ return (long) time ((time_t *) NULL);
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/tmpfil.c b/gnu/libexec/uucp/libunix/tmpfil.c
new file mode 100644
index 0000000..2dac002
--- /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 0000000..c93e82e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/trunc.c
@@ -0,0 +1,157 @@
+/* trunc.c
+ Truncate a file to zero length. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+/* External functions. */
+#ifndef lseek
+extern off_t lseek ();
+#endif
+
+/* Truncate a file to zero length. If this fails, it closes and
+ removes the file. We support a number of different means of
+ truncation, which is probably a waste of time since this function
+ is currently only called when the 'f' protocol resends a file. */
+
+#if HAVE_FTRUNCATE
+#undef HAVE_LTRUNC
+#define HAVE_LTRUNC 0
+#endif
+
+#if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC
+#ifdef F_CHSIZE
+#define HAVE_F_CHSIZE 1
+#else /* ! defined (F_CHSIZE) */
+#ifdef F_FREESP
+#define HAVE_F_FREESP 1
+#endif /* defined (F_FREESP) */
+#endif /* ! defined (F_CHSIZE) */
+#endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */
+
+openfile_t
+esysdep_truncate (e, zname)
+ openfile_t e;
+ const char *zname;
+{
+ int o;
+
+#if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP
+ int itrunc;
+
+ if (! ffilerewind (e))
+ {
+ ulog (LOG_ERROR, "rewind: %s", strerror (errno));
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ o = fileno (e);
+#else
+ o = e;
+#endif
+
+#if HAVE_FTRUNCATE
+ itrunc = ftruncate (o, 0);
+#endif
+#if HAVE_LTRUNC
+ itrunc = ltrunc (o, (long) 0, SEEK_SET);
+#endif
+#if HAVE_F_CHSIZE
+ itrunc = fcntl (o, F_CHSIZE, (off_t) 0);
+#endif
+#if HAVE_F_FREESP
+ /* This selection is based on an implementation of ftruncate by
+ kucharsk@Solbourne.com (William Kucharski). */
+ {
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = 0;
+ fl.l_type = F_WRLCK;
+
+ itrunc = fcntl (o, F_FREESP, &fl);
+ }
+#endif
+
+ if (itrunc != 0)
+ {
+#if HAVE_FTRUNCATE
+ ulog (LOG_ERROR, "ftruncate: %s", strerror (errno));
+#endif
+#ifdef HAVE_LTRUNC
+ ulog (LOG_ERROR, "ltrunc: %s", strerror (errno));
+#endif
+#ifdef HAVE_F_CHSIZE
+ ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno));
+#endif
+#ifdef HAVE_F_FREESP
+ ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno));
+#endif
+
+ (void) ffileclose (e);
+ (void) remove (zname);
+ return EFILECLOSED;
+ }
+
+ return e;
+#else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+ (void) ffileclose (e);
+ (void) remove (zname);
+
+ o = creat ((char *) zname, IPRIVATE_FILE_MODE);
+
+ if (o == -1)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zname, strerror (errno));
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) close (o);
+ return EFILECLOSED;
+ }
+
+#if USE_STDIO
+ e = fdopen (o, (char *) BINWRITE);
+
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno));
+ (void) close (o);
+ (void) remove (zname);
+ return NULL;
+ }
+#else /* ! USE_STDIO */
+ e = o;
+#endif /* ! USE_STDIO */
+
+ return e;
+#endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
+}
diff --git a/gnu/libexec/uucp/libunix/uacces.c b/gnu/libexec/uucp/libunix/uacces.c
new file mode 100644
index 0000000..c92c78e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/uacces.c
@@ -0,0 +1,205 @@
+/* uacces.c
+ Check access to a file by user name.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+
+#include <pwd.h>
+#include <errno.h>
+
+#if HAVE_GETGRENT
+#include <grp.h>
+#if GETGRENT_DECLARATION_OK
+#ifndef getgrent
+extern struct group *getgrent ();
+#endif
+#endif
+#endif /* HAVE_GETGRENT */
+
+#if GETPWNAM_DECLARATION_OK
+#ifndef getpwnam
+extern struct passwd *getpwnam ();
+#endif
+#endif
+
+/* Do access(2) on a stat structure, except that the user name is
+ provided. If the user name in zuser is NULL, require the file to
+ be accessible to the world. Return TRUE if access is permitted,
+ FALSE otherwise. This does not log an error message. */
+
+boolean
+fsuser_access (q, imode, zuser)
+ const struct stat *q;
+ int imode;
+ const char *zuser;
+{
+ static char *zuser_hold;
+ static uid_t iuid_hold;
+ static gid_t igid_hold;
+ static int cgroups_hold;
+ static gid_t *paigroups_hold;
+ int ir, iw, ix, iand;
+
+ if (imode == F_OK)
+ return TRUE;
+
+ if (zuser != NULL)
+ {
+ /* We keep static variables around for the last user we did, to
+ avoid looking up a user multiple times. */
+ if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0)
+ {
+ struct passwd *qpwd;
+
+ if (zuser_hold != NULL)
+ {
+ ubuffree (zuser_hold);
+ zuser_hold = NULL;
+ cgroups_hold = 0;
+ xfree ((pointer) paigroups_hold);
+ paigroups_hold = NULL;
+ }
+
+ qpwd = getpwnam ((char *) zuser);
+ if (qpwd == NULL)
+ {
+ /* Check this as a remote request. */
+ zuser = NULL;
+ }
+ else
+ {
+#if HAVE_GETGRENT
+ struct group *qg;
+#endif
+
+ zuser_hold = zbufcpy (zuser);
+
+ iuid_hold = qpwd->pw_uid;
+ igid_hold = qpwd->pw_gid;
+
+#if HAVE_GETGRENT
+ /* Get the list of groups for this user. This is
+ definitely more appropriate for BSD than for System
+ V. It may just be a waste of time, and perhaps it
+ should be configurable. */
+ setgrent ();
+ while ((qg = getgrent ()) != NULL)
+ {
+ const char **pz;
+
+ if (qg->gr_gid == igid_hold)
+ continue;
+ for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++)
+ {
+ if ((*pz)[0] == *zuser
+ && strcmp (*pz, zuser) == 0)
+ {
+ paigroups_hold = ((gid_t *)
+ (xrealloc
+ ((pointer) paigroups_hold,
+ ((cgroups_hold + 1)
+ * sizeof (gid_t)))));
+ paigroups_hold[cgroups_hold] = qg->gr_gid;
+ ++cgroups_hold;
+ break;
+ }
+ }
+ }
+ endgrent ();
+#endif
+ }
+ }
+ }
+
+
+ /* Now do the actual access check. */
+
+ if (zuser != NULL)
+ {
+ /* The superuser can do anything. */
+ if (iuid_hold == 0)
+ return TRUE;
+
+ /* If this is the uid we're running under, there's no point to
+ checking access further, because when we actually try the
+ operation the system will do the checking for us. */
+ if (iuid_hold == geteuid ())
+ return TRUE;
+ }
+
+ ir = S_IROTH;
+ iw = S_IWOTH;
+ ix = S_IXOTH;
+
+ if (zuser != NULL)
+ {
+ if (iuid_hold == q->st_uid)
+ {
+ ir = S_IRUSR;
+ iw = S_IWUSR;
+ ix = S_IXUSR;
+ }
+ else
+ {
+ boolean fgroup;
+
+ fgroup = FALSE;
+ if (igid_hold == q->st_gid)
+ fgroup = TRUE;
+ else
+ {
+ int i;
+
+ for (i = 0; i < cgroups_hold; i++)
+ {
+ if (paigroups_hold[i] == q->st_gid)
+ {
+ fgroup = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fgroup)
+ {
+ ir = S_IRGRP;
+ iw = S_IWGRP;
+ ix = S_IXGRP;
+ }
+ }
+ }
+
+ iand = 0;
+ if ((imode & R_OK) != 0)
+ iand |= ir;
+ if ((imode & W_OK) != 0)
+ iand |= iw;
+ if ((imode & X_OK) != 0)
+ iand |= ix;
+
+ return (q->st_mode & iand) == iand;
+}
diff --git a/gnu/libexec/uucp/libunix/ufopen.c b/gnu/libexec/uucp/libunix/ufopen.c
new file mode 100644
index 0000000..5a7b6f2
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/ufopen.c
@@ -0,0 +1,218 @@
+/* ufopen.c
+ Open a file with the permissions of the invoking user.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+/* Local functions. */
+
+static boolean fsuser_perms P((uid_t *pieuid));
+static boolean fsuucp_perms P((long ieuid));
+
+/* Switch to permissions of the invoking user. */
+
+static boolean
+fsuser_perms (pieuid)
+ uid_t *pieuid;
+{
+ uid_t ieuid, iuid;
+
+ ieuid = geteuid ();
+ iuid = getuid ();
+ if (pieuid != NULL)
+ *pieuid = ieuid;
+
+#if HAVE_SETREUID
+ /* Swap the effective user id and the real user id. We can then
+ swap them back again when we want to return to the uucp user's
+ permissions. */
+ if (setreuid (ieuid, iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setreuid (%ld, %ld): %s",
+ (long) ieuid, (long) iuid, strerror (errno));
+ return FALSE;
+ }
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set the effective user id to the real user id. Since the
+ effective user id is saved (it's the saved setuid) we will able
+ to set back to it later. If the real user id is root we will not
+ be able to switch back and forth, so don't even try. */
+ if (iuid != 0)
+ {
+ if (setuid (iuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno));
+ return FALSE;
+ }
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* There's no way to switch between real permissions and effective
+ permissions. Just try to open the file with the uucp
+ permissions. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Restore the uucp permissions. */
+
+/*ARGSUSED*/
+static boolean
+fsuucp_perms (ieuid)
+ long ieuid;
+{
+#if HAVE_SETREUID
+ /* Swap effective and real user id's back to what they were. */
+ if (! fsuser_perms ((uid_t *) NULL))
+ return FALSE;
+#else /* ! HAVE_SETREUID */
+#if HAVE_SAVED_SETUID
+ /* Set ourselves back to our original effective user id. */
+ if (setuid ((uid_t) ieuid) < 0)
+ {
+ ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno));
+ /* Is this error message helpful or confusing? */
+ if (errno == EPERM)
+ ulog (LOG_ERROR,
+ "Probably HAVE_SAVED_SETUID in policy.h should be set to 0");
+ return FALSE;
+ }
+#else /* ! HAVE_SAVED_SETUID */
+ /* We didn't switch, no need to switch back. */
+#endif /* ! HAVE_SAVED_SETUID */
+#endif /* ! HAVE_SETREUID */
+
+ return TRUE;
+}
+
+/* Open a file with the permissions of the invoking user. Ignore the
+ fbinary argument since Unix has no distinction between text and
+ binary files. */
+
+/*ARGSUSED*/
+openfile_t
+esysdep_user_fopen (zfile, frd, fbinary)
+ const char *zfile;
+ boolean frd;
+ boolean fbinary;
+{
+ uid_t ieuid;
+ openfile_t e;
+ const char *zerr;
+ int o = 0;
+
+ if (! fsuser_perms (&ieuid))
+ return EFILECLOSED;
+
+ zerr = NULL;
+
+#if USE_STDIO
+ e = fopen (zfile, frd ? "r" : "w");
+ if (e == NULL)
+ zerr = "fopen";
+ else
+ o = fileno (e);
+#else
+ if (frd)
+ {
+ e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
+ zerr = "open";
+ }
+ else
+ {
+ e = creat ((char *) zfile, IPUBLIC_FILE_MODE);
+ zerr = "creat";
+ }
+ if (e >= 0)
+ {
+ o = e;
+ zerr = NULL;
+ }
+#endif
+
+ if (! fsuucp_perms ((long) ieuid))
+ {
+ if (ffileisopen (e))
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ if (zerr != NULL)
+ {
+ ulog (LOG_ERROR, "%s (%s): %s", zerr, zfile, strerror (errno));
+#if ! HAVE_SETREUID
+ /* Are these error messages helpful or confusing? */
+#if HAVE_SAVED_SETUID
+ if (errno == EACCES && getuid () == 0)
+ ulog (LOG_ERROR,
+ "The superuser may only transfer files that are readable by %s",
+ OWNER);
+#else
+ if (errno == EACCES)
+ ulog (LOG_ERROR,
+ "You may only transfer files that are readable by %s", OWNER);
+#endif
+#endif /* ! HAVE_SETREUID */
+ return EFILECLOSED;
+ }
+
+ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ (void) ffileclose (e);
+ return EFILECLOSED;
+ }
+
+ return e;
+}
diff --git a/gnu/libexec/uucp/libunix/ultspl.c b/gnu/libexec/uucp/libunix/ultspl.c
new file mode 100644
index 0000000..34921d2
--- /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 0000000..76f5345
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/unknwn.c
@@ -0,0 +1,43 @@
+/* unknwn.c
+ Check remote.unknown shell script. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+/* Run the remote.unknown shell script. If it succeeds, we return
+ FALSE because that means that the system is not permitted to log
+ in. If the execution fails, we return TRUE. */
+
+boolean
+fsysdep_unknown_caller (zscript, zsystem)
+ const char *zscript;
+ const char *zsystem;
+{
+ const char *azargs[3];
+ int aidescs[3];
+ pid_t ipid;
+
+ azargs[0] = zscript;
+ azargs[1] = zsystem;
+ azargs[2] = NULL;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ipid = ixsspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL, FALSE,
+ TRUE, (const char *) NULL, (const char *) NULL,
+ (const char *) NULL);
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return ixswait ((unsigned long) ipid, (const char *) NULL) != 0;
+}
diff --git a/gnu/libexec/uucp/libunix/uuto.c b/gnu/libexec/uucp/libunix/uuto.c
new file mode 100644
index 0000000..debba9d
--- /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 0000000..ab96123
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/walk.c
@@ -0,0 +1,59 @@
+/* walk.c
+ Walk a directory tree. */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#if HAVE_FTW_H
+#include <ftw.h>
+#endif
+
+static int iswalk_dir P((const char *zname, const struct stat *qstat,
+ int iflag));
+
+/* Walk a directory tree. */
+
+static size_t cSlen;
+static void (*puSfn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+static pointer pSinfo;
+
+boolean
+usysdep_walk_tree (zdir, pufn, pinfo)
+ const char *zdir;
+ void (*pufn) P((const char *zfull, const char *zrelative,
+ pointer pinfo));
+ pointer pinfo;
+{
+ cSlen = strlen (zdir) + 1;
+ puSfn = pufn;
+ pSinfo = pinfo;
+ return ftw ((char *) zdir, iswalk_dir, 5) == 0;
+}
+
+/* Pass a file found in the directory tree to the system independent
+ function. */
+
+/*ARGSUSED*/
+static int
+iswalk_dir (zname, qstat, iflag)
+ const char *zname;
+ const struct stat *qstat;
+ int iflag;
+{
+ char *zcopy;
+
+ if (iflag != FTW_F)
+ return 0;
+
+ zcopy = zbufcpy (zname + cSlen);
+
+ (*puSfn) (zname, zcopy, pSinfo);
+
+ ubuffree (zcopy);
+
+ return 0;
+}
diff --git a/gnu/libexec/uucp/libunix/wldcrd.c b/gnu/libexec/uucp/libunix/wldcrd.c
new file mode 100644
index 0000000..cfbd15e
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/wldcrd.c
@@ -0,0 +1,212 @@
+/* wldcrd.c
+ Expand wildcards.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_GLOB && ! HAVE_GLOB_H
+#undef HAVE_GLOB
+#define HAVE_GLOB 0
+#endif
+
+#if HAVE_GLOB
+#include <glob.h>
+#endif
+
+/* Local variables to hold the wildcard in progress. */
+
+#if HAVE_GLOB
+static glob_t sSglob;
+static int iSglob;
+#else
+static char *zSwildcard_alloc;
+static char *zSwildcard;
+#endif
+
+/* Start getting a wildcarded file spec. Use the glob function if it
+ is available, and otherwise use the shell. */
+
+boolean
+fsysdep_wildcard_start (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ if (glob (zfile, 0, (int (*) ()) NULL, &sSglob) != 0)
+ sSglob.gl_pathc = 0;
+ iSglob = 0;
+ return TRUE;
+
+#else /* ! HAVE_GLOB */
+
+ char *zcmd, *zto;
+ const char *zfrom;
+ size_t c;
+ const char *azargs[4];
+ FILE *e;
+ pid_t ipid;
+
+#if DEBUG > 0
+ if (*zfile != '/')
+ ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile);
+#endif
+
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+
+ zcmd = zbufalc (sizeof ECHO_PROGRAM + sizeof " " + 2 * strlen (zfile));
+ memcpy (zcmd, ECHO_PROGRAM, sizeof ECHO_PROGRAM - 1);
+ zto = zcmd + sizeof ECHO_PROGRAM - 1;
+ *zto++ = ' ';
+ zfrom = zfile;
+ while (*zfrom != '\0')
+ {
+ /* To avoid shell trickery, we quote all characters except
+ letters, digits, and wildcard specifiers. We don't quote '/'
+ to avoid an Ultrix sh bug. */
+ if (! isalnum (*zfrom)
+ && *zfrom != '*'
+ && *zfrom != '?'
+ && *zfrom != '['
+ && *zfrom != ']'
+ && *zfrom != '/')
+ *zto++ = '\\';
+ *zto++ = *zfrom++;
+ }
+ *zto = '\0';
+
+ azargs[0] = "/bin/sh";
+ azargs[1] = "-c";
+ azargs[2] = zcmd;
+ azargs[3] = NULL;
+
+ ubuffree (zcmd);
+
+ e = espopen (azargs, TRUE, &ipid);
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "espopen: %s", strerror (errno));
+ return FALSE;
+ }
+
+ zSwildcard_alloc = NULL;
+ c = 0;
+ if (getline (&zSwildcard_alloc, &c, e) <= 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ }
+
+ if (ixswait ((unsigned long) ipid, ECHO_PROGRAM) != 0)
+ {
+ xfree ((pointer) zSwildcard_alloc);
+ return FALSE;
+ }
+
+ if (zSwildcard_alloc == NULL)
+ return FALSE;
+
+ DEBUG_MESSAGE1 (DEBUG_EXECUTE,
+ "fsysdep_wildcard_start: got \"%s\"",
+ zSwildcard_alloc);
+
+ zSwildcard = zSwildcard_alloc;
+
+ return TRUE;
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Get the next wildcard spec. */
+
+/*ARGSUSED*/
+char *
+zsysdep_wildcard (zfile)
+ const char *zfile;
+{
+#if HAVE_GLOB
+
+ char *zret;
+
+ if (iSglob >= sSglob.gl_pathc)
+ return NULL;
+ zret = zbufcpy (sSglob.gl_pathv[iSglob]);
+ ++iSglob;
+ return zret;
+
+#else /* ! HAVE_GLOB */
+
+ char *zret;
+
+ if (zSwildcard_alloc == NULL || zSwildcard == NULL)
+ return NULL;
+
+ zret = zSwildcard;
+
+ while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+
+ if (*zSwildcard != '\0')
+ {
+ *zSwildcard = '\0';
+ ++zSwildcard;
+ while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard)))
+ ++zSwildcard;
+ }
+
+ if (*zSwildcard == '\0')
+ zSwildcard = NULL;
+
+ return zbufcpy (zret);
+
+#endif /* ! HAVE_GLOB */
+}
+
+/* Finish up getting wildcard specs. */
+
+boolean
+fsysdep_wildcard_end ()
+{
+#if HAVE_GLOB
+ globfree (&sSglob);
+ return TRUE;
+#else /* ! HAVE_GLOB */
+ xfree ((pointer) zSwildcard_alloc);
+ zSwildcard_alloc = NULL;
+ zSwildcard = NULL;
+ return TRUE;
+#endif /* ! HAVE_GLOB */
+}
diff --git a/gnu/libexec/uucp/libunix/work.c b/gnu/libexec/uucp/libunix/work.c
new file mode 100644
index 0000000..3d055c2
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/work.c
@@ -0,0 +1,765 @@
+/* work.c
+ Routines to read command files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char work_rcsid[] = "$Id: work.c,v 1.1 1993/08/04 19:33:20 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Local functions. */
+
+static char *zswork_directory P((const char *zsystem));
+static boolean fswork_file P((const char *zsystem, const char *zfile,
+ char *pbgrade));
+static int iswork_cmp P((constpointer pkey, constpointer pdatum));
+
+/* These functions can support multiple actions going on at once.
+ This allows the UUCP package to send and receive multiple files at
+ the same time. This is a very flexible feature, but I'm not sure
+ it will actually be used all that much.
+
+ The ssfile structure holds a command file name and all the lines
+ read in from that command file. The union within the ssline
+ structure initially holds a line from the file and then holds a
+ pointer back to the ssfile structure; a pointer to this union is
+ used as a sequence pointer. The ztemp entry of the ssline
+ structure holds the name of a temporary file to delete, if any. */
+
+#define CFILELINES (10)
+
+struct ssline
+{
+ char *zline;
+ struct ssfile *qfile;
+ char *ztemp;
+};
+
+struct ssfile
+{
+ char *zfile;
+ int clines;
+ int cdid;
+ struct ssline aslines[CFILELINES];
+};
+
+/* Static variables for the work scan. */
+
+static char **azSwork_files;
+static size_t cSwork_files;
+static size_t iSwork_file;
+static struct ssfile *qSwork_file;
+
+/* Given a system name, return a directory to search for work. */
+
+static char *
+zswork_directory (zsystem)
+ const char *zsystem;
+{
+#if SPOOLDIR_V2
+ return zbufcpy (".");
+#endif /* SPOOLDIR_V2 */
+#if SPOOLDIR_BSD42 || SPOOLDIR_BSD43
+ return zbufcpy ("C.");
+#endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ return zbufcpy (zsystem);
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_ULTRIX
+ return zsappend3 ("sys",
+ (fsultrix_has_spool (zsystem)
+ ? zsystem
+ : "DEFAULT"),
+ "C.");
+#endif /* SPOOLDIR_ULTRIX */
+#if SPOOLDIR_TAYLOR
+ return zsysdep_in_dir (zsystem, "C.");
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* See whether a file name from the directory returned by
+ zswork_directory is really a command for a particular system.
+ Return the command grade. */
+
+/*ARGSUSED*/
+static boolean
+fswork_file (zsystem, zfile, pbgrade)
+ const char *zsystem;
+ const char *zfile;
+ char *pbgrade;
+{
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
+ int cfilesys, csys;
+
+ /* The file name should be C.ssssssgqqqq, where g is exactly one
+ letter and qqqq is exactly four numbers. The system name may be
+ truncated to six or seven characters. The system name of the
+ file must match the system name we're looking for, since there
+ could be work files for several systems in one directory. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ csys = strlen (zsystem);
+ cfilesys = strlen (zfile) - 7;
+ if (csys != cfilesys
+ && (csys < 6 || (cfilesys != 6 && cfilesys != 7)))
+ return FALSE;
+ *pbgrade = zfile[cfilesys + 2];
+ return strncmp (zfile + 2, zsystem, cfilesys) == 0;
+#endif /* V2 || BSD42 || BSD43 || ULTRIX */
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ int clen;
+
+ /* The HDB file name should be C.ssssssgqqqq where g is exactly one
+ letter and qqqq is exactly four numbers or letters. We don't
+ check the system name, because it is guaranteed by the directory
+ we are looking in and some versions of uucp set it to the local
+ system rather than the remote one. I'm not sure of the exact
+ format of the SVR4 file name, but it does not include the grade
+ at all. */
+ if (zfile[0] != 'C' || zfile[1] != '.')
+ return FALSE;
+ clen = strlen (zfile);
+ if (clen < 7)
+ return FALSE;
+#if ! SPOOLDIR_SVR4
+ *pbgrade = zfile[clen - 5];
+#endif
+ return TRUE;
+#endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */
+#if SPOOLDIR_TAYLOR
+ /* We don't keep the system name in the file name, since that
+ forces truncation. Our file names are always C.gqqqq. */
+ *pbgrade = zfile[2];
+ return (zfile[0] == 'C'
+ && zfile[1] == '.'
+ && strlen (zfile) == 7);
+#endif /* SPOOLDIR_TAYLOR */
+}
+
+/* A comparison function to look through the list of file names. */
+
+static int
+iswork_cmp (pkey, pdatum)
+ constpointer pkey;
+ constpointer pdatum;
+{
+ const char * const *pzkey = (const char * const *) pkey;
+ const char * const *pzdatum = (const char * const *) pdatum;
+
+ return strcmp (*pzkey, *pzdatum);
+}
+
+/* See whether there is any work to do for a particular system. */
+
+boolean
+fsysdep_has_work (qsys)
+ const struct uuconf_system *qsys;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ qdir = opendir ((char *) zdir);
+ if (qdir == NULL)
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0')
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ ubuffree (zsub);
+ if (qdir == NULL)
+ continue;
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bgrade;
+
+ if (fswork_file (qsys->uuconf_zname, qentry->d_name, &bgrade))
+ {
+ closedir (qdir);
+#if SPOOLDIR_SVR4
+ closedir (qgdir);
+#endif
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+ return FALSE;
+}
+
+/* Initialize the work scan. We have to read all the files in the
+ work directory, so that we can sort them by work grade. The bgrade
+ argument is the minimum grade to consider. We don't want to return
+ files that we have already considered; usysdep_get_work_free will
+ clear the data out when we are done with the system. This returns
+ FALSE on error. */
+
+#define CWORKFILES (10)
+
+boolean
+fsysdep_get_work_init (qsys, bgrade)
+ const struct uuconf_system *qsys;
+ int bgrade;
+{
+ char *zdir;
+ DIR *qdir;
+ struct dirent *qentry;
+ size_t chad;
+ size_t callocated;
+#if SPOOLDIR_SVR4
+ DIR *qgdir;
+ struct dirent *qgentry;
+#endif
+
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+
+ qdir = opendir (zdir);
+ if (qdir == NULL)
+ {
+ boolean fret;
+
+ if (errno == ENOENT)
+ fret = TRUE;
+ else
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno));
+ fret = FALSE;
+ }
+ ubuffree (zdir);
+ return fret;
+ }
+
+ chad = cSwork_files;
+ callocated = cSwork_files;
+
+ /* Sort the files we already know about so that we can check the new
+ ones with bsearch. It would be faster to use a hash table, and
+ the code should be probably be changed. The sort done at the end
+ of this function does not suffice because it only includes the
+ files added last time, and does not sort the entire array. Some
+ (bad) qsort implementations are very slow when given a sorted
+ array, which causes particularly bad effects here. */
+ if (chad > 0)
+ qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp);
+
+#if SPOOLDIR_SVR4
+ qgdir = qdir;
+ while ((qgentry = readdir (qgdir)) != NULL)
+ {
+ char *zsub;
+
+ if (qgentry->d_name[0] == '.'
+ || qgentry->d_name[1] != '\0'
+ || UUCONF_GRADE_CMP (bgrade, qgentry->d_name[0]) < 0)
+ continue;
+ zsub = zsysdep_in_dir (zdir, qgentry->d_name);
+ qdir = opendir (zsub);
+ if (qdir == NULL)
+ {
+ if (errno != ENOTDIR && errno != ENOENT)
+ {
+ ulog (LOG_ERROR, "opendir (%s): %s", zsub,
+ strerror (errno));
+ ubuffree (zsub);
+ return FALSE;
+ }
+ ubuffree (zsub);
+ continue;
+ }
+ ubuffree (zsub);
+#endif
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char bfilegrade;
+ char *zname;
+
+#if ! SPOOLDIR_SVR4
+ zname = zbufcpy (qentry->d_name);
+#else
+ zname = zsysdep_in_dir (qgentry->d_name, qentry->d_name);
+ bfilegrade = qgentry->d_name[0];
+#endif
+
+ if (! fswork_file (qsys->uuconf_zname, qentry->d_name,
+ &bfilegrade)
+ || UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0
+ || (azSwork_files != NULL
+ && bsearch ((pointer) &zname,
+ (pointer) azSwork_files,
+ chad, sizeof (char *),
+ iswork_cmp) != NULL))
+ ubuffree (zname);
+ else
+ {
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "fsysdep_get_work_init: Found %s",
+ zname);
+
+ if (cSwork_files >= callocated)
+ {
+ callocated += CWORKFILES;
+ azSwork_files =
+ (char **) xrealloc ((pointer) azSwork_files,
+ callocated * sizeof (char *));
+ }
+
+ azSwork_files[cSwork_files] = zname;
+ ++cSwork_files;
+ }
+ }
+
+#if SPOOLDIR_SVR4
+ closedir (qdir);
+ }
+ qdir = qgdir;
+#endif
+
+ closedir (qdir);
+ ubuffree (zdir);
+
+ /* Sorting the files alphabetically will get the grades in the
+ right order, since all the file prefixes are the same. */
+
+ if (cSwork_files > chad)
+ qsort ((pointer) (azSwork_files + chad), cSwork_files - chad,
+ sizeof (char *), iswork_cmp);
+
+ return TRUE;
+}
+
+/* Get the next work entry for a system. This must parse the next
+ line in the next work file. The type of command is set into
+ qcmd->bcmd; if there are no more commands we call
+ fsysdep_get_work_init to rescan, in case any came in since the last
+ call. If there are still no commands, qcmd->bcmd is set to 'H'.
+ Each field in the structure is set to point to a spot in an
+ malloced string. The only time we use the grade here is when
+ calling fsysdep_get_work_init to rescan. */
+
+boolean
+fsysdep_get_work (qsys, bgrade, qcmd)
+ const struct uuconf_system *qsys;
+ int bgrade;
+ struct scmd *qcmd;
+{
+ char *zdir;
+
+ if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines)
+ qSwork_file = NULL;
+
+ if (azSwork_files == NULL)
+ {
+ qcmd->bcmd = 'H';
+ return TRUE;
+ }
+
+ zdir = NULL;
+
+ /* This loop continues until a line is returned. */
+ while (TRUE)
+ {
+ /* This loop continues until a file is opened and read in. */
+ while (qSwork_file == NULL)
+ {
+ FILE *e;
+ struct ssfile *qfile;
+ int iline, callocated;
+ char *zline;
+ size_t cline;
+ char *zname;
+
+ /* Read all the lines of a command file into memory. */
+ do
+ {
+ if (iSwork_file >= cSwork_files)
+ {
+ /* Rescan the work directory. */
+ if (! fsysdep_get_work_init (qsys, bgrade))
+ {
+ ubuffree (zdir);
+ return FALSE;
+ }
+ if (iSwork_file >= cSwork_files)
+ {
+ qcmd->bcmd = 'H';
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+
+ if (zdir == NULL)
+ {
+ zdir = zswork_directory (qsys->uuconf_zname);
+ if (zdir == NULL)
+ return FALSE;
+ }
+
+ zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]);
+
+ ++iSwork_file;
+
+ e = fopen (zname, "r");
+ if (e == NULL)
+ {
+ ulog (LOG_ERROR, "fopen (%s): %s", zname,
+ strerror (errno));
+ ubuffree (zname);
+ }
+ }
+ while (e == NULL);
+
+ qfile = (struct ssfile *) xmalloc (sizeof (struct ssfile));
+ callocated = CFILELINES;
+ iline = 0;
+
+ zline = NULL;
+ cline = 0;
+ while (getline (&zline, &cline, e) > 0)
+ {
+ if (iline >= callocated)
+ {
+ /* The sizeof (struct ssfile) includes CFILELINES
+ entries already, so using callocated * sizeof
+ (struct ssline) will give us callocated *
+ CFILELINES entries. */
+ qfile =
+ ((struct ssfile *)
+ xrealloc ((pointer) qfile,
+ (sizeof (struct ssfile) +
+ (callocated * sizeof (struct ssline)))));
+ callocated += CFILELINES;
+ }
+ qfile->aslines[iline].zline = zbufcpy (zline);
+ qfile->aslines[iline].qfile = NULL;
+ qfile->aslines[iline].ztemp = NULL;
+ iline++;
+ }
+
+ xfree ((pointer) zline);
+
+ if (fclose (e) != 0)
+ ulog (LOG_ERROR, "fclose: %s", strerror (errno));
+
+ if (iline == 0)
+ {
+ /* There were no lines in the file; this is a poll file,
+ for which we return a 'P' command. */
+ qfile->aslines[0].zline = zbufcpy ("P");
+ qfile->aslines[0].qfile = NULL;
+ qfile->aslines[0].ztemp = NULL;
+ iline = 1;
+ }
+
+ qfile->zfile = zname;
+ qfile->clines = iline;
+ qfile->cdid = 0;
+ qSwork_file = qfile;
+ }
+
+ /* This loop continues until all the lines from the current file
+ are used up, or a line is returned. */
+ while (TRUE)
+ {
+ int iline;
+
+ if (qSwork_file->cdid >= qSwork_file->clines)
+ {
+ /* We don't want to free qSwork_file here, since it must
+ remain until all the lines have been completed. It
+ is freed in fsysdep_did_work. */
+ qSwork_file = NULL;
+ /* Go back to the main loop which finds another file. */
+ break;
+ }
+
+ iline = qSwork_file->cdid;
+ ++qSwork_file->cdid;
+
+ /* Now parse the line into a command. */
+ if (! fparse_cmd (qSwork_file->aslines[iline].zline, qcmd))
+ {
+ ulog (LOG_ERROR, "Bad line in command file %s",
+ qSwork_file->zfile);
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ continue;
+ }
+
+ qSwork_file->aslines[iline].qfile = qSwork_file;
+ qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]);
+
+ if (qcmd->bcmd == 'S' || qcmd->bcmd == 'E')
+ {
+ char *zreal;
+
+ zreal = zsysdep_spool_file_name (qsys, qcmd->ztemp,
+ qcmd->pseq);
+ if (zreal == NULL)
+ {
+ ubuffree (qSwork_file->aslines[iline].zline);
+ qSwork_file->aslines[iline].zline = NULL;
+ ubuffree (zdir);
+ return FALSE;
+ }
+ qSwork_file->aslines[iline].ztemp = zreal;
+ }
+
+ ubuffree (zdir);
+ return TRUE;
+ }
+ }
+}
+
+/* When a command has been complete, fsysdep_did_work is called. The
+ sequence entry was set above to be the address of an aslines
+ structure whose pfile entry points to the ssfile corresponding to
+ this file. We can then check whether all the lines have been
+ completed (they will have been if the pfile entry is NULL) and
+ remove the file if they have been. This means that we only remove
+ a command file if we manage to complete every transfer it specifies
+ in a single UUCP session. I don't know if this is how regular UUCP
+ works. */
+
+boolean
+fsysdep_did_work (pseq)
+ pointer pseq;
+{
+ struct ssfile *qfile;
+ struct ssline *qline;
+ int i;
+
+ qline = (struct ssline *) pseq;
+
+ ubuffree (qline->zline);
+ qline->zline = NULL;
+
+ qfile = qline->qfile;
+ qline->qfile = NULL;
+
+ /* Remove the temporary file, if there is one. It really doesn't
+ matter if this fails, and not checking the return value lets us
+ attempt to remove D.0 or whatever an unused temporary file is
+ called without complaining. */
+ if (qline->ztemp != NULL)
+ {
+ (void) remove (qline->ztemp);
+ ubuffree (qline->ztemp);
+ qline->ztemp = NULL;
+ }
+
+ /* If not all the lines have been returned from fsysdep_get_work,
+ we can't remove the file yet. */
+ if (qfile->cdid < qfile->clines)
+ return TRUE;
+
+ /* See whether all the commands have been completed. */
+ for (i = 0; i < qfile->clines; i++)
+ if (qfile->aslines[i].qfile != NULL)
+ return TRUE;
+
+ /* All commands have finished. */
+ if (remove (qfile->zfile) != 0)
+ {
+ ulog (LOG_ERROR, "remove (%s): %s", qfile->zfile,
+ strerror (errno));
+ return FALSE;
+ }
+
+ ubuffree (qfile->zfile);
+ xfree ((pointer) qfile);
+
+ if (qfile == qSwork_file)
+ qSwork_file = NULL;
+
+ return TRUE;
+}
+
+/* Free up the results of a work scan, when we're done with this
+ system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_work_free (qsys)
+ const struct uuconf_system *qsys;
+{
+ if (azSwork_files != NULL)
+ {
+ size_t i;
+
+ for (i = 0; i < cSwork_files; i++)
+ ubuffree ((pointer) azSwork_files[i]);
+ xfree ((pointer) azSwork_files);
+ azSwork_files = NULL;
+ cSwork_files = 0;
+ iSwork_file = 0;
+ }
+ if (qSwork_file != NULL)
+ {
+ int i;
+
+ ubuffree (qSwork_file->zfile);
+ for (i = 0; i < qSwork_file->cdid; i++)
+ {
+ ubuffree (qSwork_file->aslines[i].zline);
+ ubuffree (qSwork_file->aslines[i].ztemp);
+ }
+ for (i = qSwork_file->cdid; i < qSwork_file->clines; i++)
+ ubuffree (qSwork_file->aslines[i].zline);
+ xfree ((pointer) qSwork_file);
+ qSwork_file = NULL;
+ }
+}
+
+/* Save the temporary file used by a send command, and return an
+ informative message to mail to the requestor. This is called when
+ a file transfer failed, to make sure that the potentially valuable
+ file is not completely lost. */
+
+const char *
+zsysdep_save_temp_file (pseq)
+ pointer pseq;
+{
+ struct ssline *qline = (struct ssline *) pseq;
+ char *zto, *zslash;
+ size_t cwant;
+ static char *zbuf;
+ static int cbuf;
+
+ if (! fsysdep_file_exists (qline->ztemp))
+ return NULL;
+
+ zslash = strrchr (qline->ztemp, '/');
+ if (zslash == NULL)
+ zslash = qline->ztemp;
+ else
+ ++zslash;
+
+ zto = zbufalc (sizeof PRESERVEDIR + sizeof "/" + strlen (zslash));
+ sprintf (zto, "%s/%s", PRESERVEDIR, zslash);
+
+ if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE,
+ (const char *) NULL))
+ {
+ ubuffree (zto);
+ return "Could not move file to preservation directory";
+ }
+
+ cwant = sizeof "File saved as\n\t/" + strlen (zSspooldir) + strlen (zto);
+ if (cwant > cbuf)
+ {
+ ubuffree (zbuf);
+ zbuf = zbufalc (cwant);
+ cbuf = cwant;
+ }
+
+ sprintf (zbuf, "File saved as\n\t%s/%s", zSspooldir, zto);
+ ubuffree (zto);
+ return zbuf;
+}
+
+/* Get the jobid of a work file. This is needed by uustat. */
+
+char *
+zsysdep_jobid (qsys, pseq)
+ const struct uuconf_system *qsys;
+ pointer pseq;
+{
+ return zsfile_to_jobid (qsys, ((struct ssline *) pseq)->qfile->zfile,
+ bsgrade (pseq));
+}
+
+/* Get the grade of a work file. The pseq argument can be NULL when
+ this is called from zsysdep_spool_file_name, and simply means that
+ this is a remote file; returning -1 will cause zsfind_file to do
+ the right thing. */
+
+char
+bsgrade (pseq)
+ pointer pseq;
+{
+ const char *zfile;
+ char bgrade;
+
+ if (pseq == NULL)
+ return -1;
+
+ zfile = ((struct ssline *) pseq)->qfile->zfile;
+
+#if ! SPOOLDIR_SVR4
+ bgrade = zfile[strlen (zfile) - CSEQLEN - 1];
+#else
+ bgrade = *(strchr (zfile, '/') + 1);
+#endif
+
+ return bgrade;
+}
diff --git a/gnu/libexec/uucp/libunix/xqtfil.c b/gnu/libexec/uucp/libunix/xqtfil.c
new file mode 100644
index 0000000..2cdcc18
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtfil.c
@@ -0,0 +1,265 @@
+/* xqtfil.c
+ Routines to read execute files.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtfil_rcsid[] = "$Id: xqtfil.c,v 1.1 1993/08/04 19:33:21 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "sysdep.h"
+#include "system.h"
+
+#include <errno.h>
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Under the V2 or BSD42 spool directory scheme, all execute files are
+ in the main spool directory. Under the BSD43 scheme, they are all
+ in the directory X.. Under the HDB or SVR4 scheme, they are in
+ directories named after systems. Under the ULTRIX scheme, they are
+ in X. subdirectories of subdirectories of sys. Under the TAYLOR
+ scheme, they are all in the subdirectory X. of a directory named
+ after the system.
+
+ This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search
+ directories of directories. */
+
+#if SPOOLDIR_V2 || SPOOLDIR_BSD42
+#define ZDIR "."
+#define SUBDIRS 0
+#endif
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+#define ZDIR "."
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_ULTRIX
+#define ZDIR "sys"
+#define SUBDIRS 1
+#endif
+#if SPOOLDIR_BSD43
+#define ZDIR "X."
+#define SUBDIRS 0
+#endif
+
+/* Static variables for the execute file scan. */
+
+static DIR *qSxqt_topdir;
+#if ! SUBDIRS
+static const char *zSdir;
+#else /* SUBDIRS */
+static char *zSdir;
+static DIR *qSxqt_dir;
+static char *zSsystem;
+#endif /* SUBDIRS */
+
+/* Initialize the scan for execute files. The function
+ usysdep_get_xqt_free will clear the data out when we are done with
+ the system. This returns FALSE on error. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_get_xqt_init ()
+{
+ usysdep_get_xqt_free ();
+
+ qSxqt_topdir = opendir ((char *) ZDIR);
+ if (qSxqt_topdir == NULL)
+ {
+ if (errno == ENOENT)
+ return TRUE;
+ ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Return the name of the next execute file to read and process. If
+ this returns NULL, *pferr must be checked. If will be TRUE on
+ error, FALSE if there are no more files. On a successful return
+ *pzsystem will be set to the system for which the execute file was
+ created. */
+
+char *
+zsysdep_get_xqt (pzsystem, pferr)
+ char **pzsystem;
+ boolean *pferr;
+{
+ *pferr = FALSE;
+
+ if (qSxqt_topdir == NULL)
+ return NULL;
+
+ /* This loop continues until we find a file. */
+ while (TRUE)
+ {
+ DIR *qdir;
+ struct dirent *q;
+
+#if ! SUBDIRS
+ zSdir = ZDIR;
+ qdir = qSxqt_topdir;
+#else /* SUBDIRS */
+ /* This loop continues until we find a subdirectory to read. */
+ while (qSxqt_dir == NULL)
+ {
+ struct dirent *qtop;
+
+ qtop = readdir (qSxqt_topdir);
+ if (qtop == NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ return NULL;
+ }
+
+ /* No system name may start with a dot (this is enforced by
+ tisystem in sysinf.c). This allows us to quickly skip
+ impossible directories. */
+ if (qtop->d_name[0] == '.')
+ continue;
+
+ DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in top directory",
+ qtop->d_name);
+
+ ubuffree (zSdir);
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4
+ zSdir = zbufcpy (qtop->d_name);
+#endif
+#if SPOOLDIR_ULTRIX
+ zSdir = zsappend3 ("sys", qtop->d_name, "X.");
+#endif
+#if SPOOLDIR_TAYLOR
+ zSdir = zsysdep_in_dir (qtop->d_name, "X.");
+#endif
+
+ ubuffree (zSsystem);
+ zSsystem = zbufcpy (qtop->d_name);
+
+ qSxqt_dir = opendir (zSdir);
+
+ if (qSxqt_dir == NULL
+ && errno != ENOTDIR
+ && errno != ENOENT)
+ ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno));
+ }
+
+ qdir = qSxqt_dir;
+#endif /* SUBDIRS */
+
+ q = readdir (qdir);
+
+#if DEBUG > 1
+ if (q != NULL)
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Found %s in subdirectory %s",
+ q->d_name, zSdir);
+#endif
+
+ /* If we've found an execute file, return it. We have to get
+ the system name, which is easy for HDB or TAYLOR. For other
+ spool directory schemes, we have to pull it out of the X.
+ file name; this would be insecure, except that zsfind_file
+ clobbers the file name to include the real system name. */
+ if (q != NULL
+ && q->d_name[0] == 'X'
+ && q->d_name[1] == '.')
+ {
+ char *zret;
+
+#if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR
+ *pzsystem = zbufcpy (zSsystem);
+#else
+ {
+ size_t clen;
+
+ clen = strlen (q->d_name) - 7;
+ *pzsystem = zbufalc (clen + 1);
+ memcpy (*pzsystem, q->d_name + 2, clen);
+ (*pzsystem)[clen] = '\0';
+ }
+#endif
+
+ zret = zsysdep_in_dir (zSdir, q->d_name);
+#if DEBUG > 1
+ DEBUG_MESSAGE2 (DEBUG_SPOOLDIR,
+ "zsysdep_get_xqt: Returning %s (system %s)",
+ zret, *pzsystem);
+#endif
+ return zret;
+ }
+
+ /* If we've reached the end of the directory, then if we are
+ using subdirectories loop around to read the next one,
+ otherwise we are finished. */
+ if (q == NULL)
+ {
+ (void) closedir (qdir);
+#if SUBDIRS
+ qSxqt_dir = NULL;
+ continue;
+#else
+ qSxqt_topdir = NULL;
+ return NULL;
+#endif
+ }
+ }
+}
+
+/* Free up the results of an execute file scan, when we're done with
+ this system. */
+
+/*ARGSUSED*/
+void
+usysdep_get_xqt_free ()
+{
+ if (qSxqt_topdir != NULL)
+ {
+ (void) closedir (qSxqt_topdir);
+ qSxqt_topdir = NULL;
+ }
+#if SUBDIRS
+ if (qSxqt_dir != NULL)
+ {
+ (void) closedir (qSxqt_dir);
+ qSxqt_dir = NULL;
+ }
+ ubuffree (zSdir);
+ zSdir = NULL;
+ ubuffree (zSsystem);
+ zSsystem = NULL;
+#endif
+}
diff --git a/gnu/libexec/uucp/libunix/xqtsub.c b/gnu/libexec/uucp/libunix/xqtsub.c
new file mode 100644
index 0000000..53e290a
--- /dev/null
+++ b/gnu/libexec/uucp/libunix/xqtsub.c
@@ -0,0 +1,698 @@
+/* xqtsub.c
+ System dependent functions used only by uuxqt.
+
+ Copyright (C) 1991, 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP package.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucp.h"
+
+#if USE_RCS_ID
+const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 1993/08/04 19:33:22 jtc Exp $";
+#endif
+
+#include "uudefs.h"
+#include "uuconf.h"
+#include "system.h"
+#include "sysdep.h"
+
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef FD_CLOEXEC
+#define FD_CLOEXEC 1
+#endif
+
+#if HAVE_OPENDIR
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#else /* ! HAVE_DIRENT_H */
+#include <sys/dir.h>
+#define dirent direct
+#endif /* ! HAVE_DIRENT_H */
+#endif /* HAVE_OPENDIR */
+
+/* Get a value for EX_TEMPFAIL. */
+
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#endif
+
+#ifndef EX_TEMPFAIL
+#define EX_TEMPFAIL 75
+#endif
+
+/* Get the full pathname of the command to execute, given the list of
+ permitted commands and the allowed path. */
+
+char *
+zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
+ const char *zcmd;
+ char **pzcmds;
+ char **pzpath;
+ boolean *pferr;
+{
+ char **pz;
+
+ *pferr = FALSE;
+
+ for (pz = pzcmds; *pz != NULL; pz++)
+ {
+ char *zslash;
+
+ if (strcmp (*pz, "ALL") == 0)
+ break;
+
+ zslash = strrchr (*pz, '/');
+ if (zslash != NULL)
+ ++zslash;
+ else
+ zslash = *pz;
+ if (strcmp (zslash, zcmd) == 0
+ || strcmp (*pz, zcmd) == 0)
+ {
+ /* If we already have an absolute path, we can get out
+ immediately. */
+ if (**pz == '/')
+ return zbufcpy (*pz);
+ break;
+ }
+ }
+
+ /* If we didn't find this command, get out. */
+ if (*pz == NULL)
+ return NULL;
+
+ /* We didn't find an absolute pathname, so we must look through
+ the path. */
+ for (pz = pzpath; *pz != NULL; pz++)
+ {
+ char *zname;
+ struct stat s;
+
+ zname = zsysdep_in_dir (*pz, zcmd);
+ if (stat (zname, &s) == 0)
+ return zname;
+ }
+
+ *pferr = FALSE;
+ return NULL;
+}
+
+/* Expand a local filename for uuxqt. This is special because uuxqt
+ only wants to expand filenames that start with ~ (it does not want
+ to prepend the current directory to other names) and if the ~ is
+ double, it is turned into a single ~. This returns NULL to
+ indicate that no change was required; it has no way to return
+ error. */
+
+char *
+zsysdep_xqt_local_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ if (*zfile != '~')
+ return NULL;
+ if (zfile[1] == '~')
+ {
+ size_t clen;
+ char *zret;
+
+ clen = strlen (zfile);
+ zret = zbufalc (clen);
+ memcpy (zret, zfile + 1, clen);
+ return zret;
+ }
+ return zsysdep_local_file (zfile, qsys->uuconf_zpubdir);
+}
+
+#if ! ALLOW_FILENAME_ARGUMENTS
+
+/* Check to see whether an argument specifies a file name; if it does,
+ make sure that the file may legally be sent and/or received. For
+ Unix, we do not permit any occurrence of "/../" in the name, nor
+ may it start with "../". Otherwise, if it starts with "/" we check
+ against the list of permitted files. */
+
+boolean
+fsysdep_xqt_check_file (qsys, zfile)
+ const struct uuconf_system *qsys;
+ const char *zfile;
+{
+ size_t clen;
+
+ clen = strlen (zfile);
+ if ((clen == sizeof "../" - 1
+ && strcmp (zfile, "../") == 0)
+ || (clen >= sizeof "/.." - 1
+ && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
+ || strstr (zfile, "/../") != NULL
+ || (*zfile == '/'
+ && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL)
+ || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
+ qsys->uuconf_zpubdir, TRUE, FALSE,
+ (const char *) NULL))))
+ {
+ ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif /* ! ALLOW_FILENAME_ARGUMENTS */
+
+/* Invoke the command specified by an execute file. */
+
+/*ARGSUSED*/
+boolean
+fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
+ fshell, iseq, pzerror, pftemp)
+ const struct uuconf_system *qsys;
+ const char *zuser;
+ const char **pazargs;
+ const char *zfullcmd;
+ const char *zinput;
+ const char *zoutput;
+ boolean fshell;
+ int iseq;
+ char **pzerror;
+ boolean *pftemp;
+{
+ int aidescs[3];
+ boolean ferr;
+ pid_t ipid;
+ int ierr;
+ char abxqtdir[sizeof XQTDIR + 4];
+ const char *zxqtdir;
+ int istat;
+ char *zpath;
+#if ALLOW_SH_EXECUTION
+ const char *azshargs[4];
+#endif
+
+ *pzerror = NULL;
+ *pftemp = FALSE;
+
+ aidescs[0] = SPAWN_NULL;
+ aidescs[1] = SPAWN_NULL;
+ aidescs[2] = SPAWN_NULL;
+
+ ferr = FALSE;
+
+ if (zinput != NULL)
+ {
+ aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
+ if (aidescs[0] < 0)
+ {
+ ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[0], F_SETFD,
+ fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr && zoutput != NULL)
+ {
+ aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
+ if (aidescs[1] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else if (fcntl (aidescs[1], F_SETFD,
+ fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (! ferr)
+ {
+ *pzerror = zstemp_file (qsys);
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ if (aidescs[2] < 0)
+ {
+ if (errno == ENOENT)
+ {
+ if (! fsysdep_make_dirs (*pzerror, FALSE))
+ {
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ else
+ aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
+ }
+ if (! ferr && aidescs[2] < 0)
+ {
+ ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
+ *pftemp = TRUE;
+ ferr = TRUE;
+ }
+ }
+ if (! ferr
+ && fcntl (aidescs[2], F_SETFD,
+ fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
+ {
+ ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
+ ferr = TRUE;
+ }
+ }
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (ferr)
+ {
+ if (aidescs[0] != SPAWN_NULL)
+ (void) close (aidescs[0]);
+ if (aidescs[1] != SPAWN_NULL)
+ (void) close (aidescs[1]);
+ if (aidescs[2] != SPAWN_NULL)
+ (void) close (aidescs[2]);
+ ubuffree (*pzerror);
+ return FALSE;
+ }
+
+#if ALLOW_SH_EXECUTION
+ if (fshell)
+ {
+ azshargs[0] = "/bin/sh";
+ azshargs[1] = "-c";
+ azshargs[2] = zfullcmd;
+ azshargs[3] = NULL;
+ pazargs = azshargs;
+ }
+#else
+ fshell = FALSE;
+#endif
+
+ if (qsys->uuconf_pzpath == NULL)
+ zpath = NULL;
+ else
+ {
+ size_t c;
+ char **pz;
+
+ c = 0;
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ c += strlen (*pz) + 1;
+ zpath = zbufalc (c);
+ *zpath = '\0';
+ for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
+ {
+ strcat (zpath, *pz);
+ if (pz[1] != NULL)
+ strcat (zpath, ":");
+ }
+ }
+
+ /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
+ aren't already using the shell. */
+ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE,
+ ! fshell, zpath, qsys->uuconf_zname, zuser);
+
+ ierr = errno;
+
+ ubuffree (zpath);
+
+ if (aidescs[0] != SPAWN_NULL)
+ (void) close (aidescs[0]);
+ if (aidescs[1] != SPAWN_NULL)
+ (void) close (aidescs[1]);
+ if (aidescs[2] != SPAWN_NULL)
+ (void) close (aidescs[2]);
+
+ if (ipid < 0)
+ {
+ ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
+ *pftemp = TRUE;
+ return FALSE;
+ }
+
+ istat = ixswait ((unsigned long) ipid, "Execution");
+
+ if (istat == EX_TEMPFAIL)
+ *pftemp = TRUE;
+
+ return istat == 0;
+}
+
+/* Lock a uuxqt process. */
+
+int
+ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ int i;
+
+ if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
+ cmaxuuxqts = 9999;
+ for (i = 0; i < cmaxuuxqts; i++)
+ {
+ sprintf (ab, "LCK.XQT.%d", i);
+ if (fsdo_lock (ab, TRUE, (boolean *) NULL))
+ break;
+ }
+ if (i >= cmaxuuxqts)
+ return -1;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
+ {
+ (void) fsdo_unlock (ab, TRUE);
+ return -1;
+ }
+ }
+
+ return i;
+}
+
+/* Unlock a uuxqt process. */
+
+boolean
+fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
+ int iseq;
+ const char *zcmd;
+ int cmaxuuxqts;
+{
+ char ab[sizeof "LCK.XQT.9999"];
+ boolean fret;
+
+ fret = TRUE;
+
+ sprintf (ab, "LCK.XQT.%d", iseq);
+ if (! fsdo_unlock (ab, TRUE))
+ fret = FALSE;
+
+ if (zcmd != NULL)
+ {
+ char abcmd[sizeof "LXQ.123456789"];
+
+ sprintf (abcmd, "LXQ.%.9s", zcmd);
+ abcmd[strcspn (abcmd, " \t/")] = '\0';
+ if (! fsdo_unlock (abcmd, TRUE))
+ fret = FALSE;
+ }
+
+ return fret;
+}
+
+/* See whether a particular uuxqt command is locked (this depends on
+ the implementation of fsdo_lock). */
+
+boolean
+fsysdep_uuxqt_locked (zcmd)
+ const char *zcmd;
+{
+ char ab[sizeof "LXQ.123456789"];
+ struct stat s;
+
+ sprintf (ab, "LXQ.%.9s", zcmd);
+ return stat (ab, &s) == 0;
+}
+
+/* Lock a particular execute file. */
+
+boolean
+fsysdep_lock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Unlock a particular execute file. */
+
+boolean
+fsysdep_unlock_uuxqt_file (zfile)
+ const char *zfile;
+{
+ char *zcopy, *z;
+ boolean fret;
+
+ zcopy = zbufcpy (zfile);
+
+ z = strrchr (zcopy, '/');
+ if (z == NULL)
+ *zcopy = 'L';
+ else
+ *(z + 1) = 'L';
+
+ fret = fsdo_unlock (zcopy, TRUE);
+ ubuffree (zcopy);
+ return fret;
+}
+
+/* Lock the execute directory. Since we use a different directory
+ depending on which LCK.XQT.dddd file we got, there is actually no
+ need to create a lock file. We do make sure that the directory
+ exists, though. */
+
+boolean
+fsysdep_lock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ if (mkdir (zxqtdir, S_IRWXU) < 0
+ && errno != EEXIST)
+ {
+ ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Unlock the execute directory and clear it out. The lock is
+ actually the LCK.XQT.dddd file, so we don't unlock it, but we do
+ remove all the files. */
+
+boolean
+fsysdep_unlock_uuxqt_dir (iseq)
+ int iseq;
+{
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ DIR *qdir;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ qdir = opendir ((char *) zxqtdir);
+ if (qdir != NULL)
+ {
+ struct dirent *qentry;
+
+ while ((qentry = readdir (qdir)) != NULL)
+ {
+ char *z;
+
+ if (strcmp (qentry->d_name, ".") == 0
+ || strcmp (qentry->d_name, "..") == 0)
+ continue;
+ z = zsysdep_in_dir (zxqtdir, qentry->d_name);
+ if (remove (z) < 0)
+ {
+ int ierr;
+
+ ierr = errno;
+ if (! fsysdep_directory (z))
+ ulog (LOG_ERROR, "remove (%s): %s", z,
+ strerror (ierr));
+ else
+ (void) fsysdep_rmdir (z);
+ }
+ ubuffree (z);
+ }
+
+ closedir (qdir);
+ }
+
+ return TRUE;
+}
+
+/* Move files into the execution directory. */
+
+boolean
+fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
+ int cfiles;
+ const char *const *pzfrom;
+ const char *const *pzto;
+ boolean fto;
+ int iseq;
+ char **pzinput;
+{
+ char *zinput;
+ const char *zxqtdir;
+ char abxqtdir[sizeof XQTDIR + 4];
+ int i;
+
+ if (pzinput == NULL)
+ zinput = NULL;
+ else
+ zinput = *pzinput;
+
+ if (iseq == 0)
+ zxqtdir = XQTDIR;
+ else
+ {
+ sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
+ zxqtdir = abxqtdir;
+ }
+
+ for (i = 0; i < cfiles; i++)
+ {
+ const char *zfrom, *zto;
+ char *zfree;
+
+ if (pzto[i] == NULL)
+ continue;
+
+ zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
+
+ zfrom = pzfrom[i];
+ zto = zfree;
+
+ if (zinput != NULL && strcmp (zinput, zfrom) == 0)
+ {
+ *pzinput = zbufcpy (zto);
+ zinput = NULL;
+ }
+
+ if (! fto)
+ {
+ const char *ztemp;
+
+ ztemp = zfrom;
+ zfrom = zto;
+ zto = ztemp;
+ (void) chmod (zfrom, IPRIVATE_FILE_MODE);
+ }
+
+ if (rename (zfrom, zto) < 0)
+ {
+#if HAVE_RENAME
+ /* On some systems the system call rename seems to fail for
+ arbitrary reasons. To get around this, we always try to
+ copy the file by hand if the rename failed. */
+ errno = EXDEV;
+#endif
+
+ if (errno != EXDEV)
+ {
+ ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
+ strerror (errno));
+ ubuffree (zfree);
+ break;
+ }
+
+ if (! fcopy_file (zfrom, zto, FALSE, FALSE))
+ {
+ ubuffree (zfree);
+ break;
+ }
+ if (remove (zfrom) < 0)
+ ulog (LOG_ERROR, "remove (%s): %s", zfrom,
+ strerror (errno));
+ }
+
+ if (fto)
+ (void) chmod (zto, IPUBLIC_FILE_MODE);
+
+ ubuffree (zfree);
+ }
+
+ if (i < cfiles)
+ {
+ if (fto)
+ (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
+ (char **) NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gnu/libexec/uucp/libuuconf/COPYING.LIB b/gnu/libexec/uucp/libuuconf/COPYING.LIB
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gnu/libexec/uucp/libuuconf/MANIFEST b/gnu/libexec/uucp/libuuconf/MANIFEST
new file mode 100644
index 0000000..8d1eb36
--- /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 0000000..066e928a
--- /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 <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libuuconf/README b/gnu/libexec/uucp/libuuconf/README
new file mode 100644
index 0000000..64a5eec
--- /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 0000000..6244dad
--- /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 0000000..8498d50
--- /dev/null
+++ b/gnu/libexec/uucp/libuuconf/addstr.c
@@ -0,0 +1,139 @@
+/* addstr.c
+ Add a string to a list of strings.
+
+ Copyright (C) 1992 Ian Lance Taylor
+
+ This file is part of the Taylor UUCP uuconf library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author of the program may be contacted at ian@airs.com or
+ c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
+ */
+
+#include "uucnfi.h"
+
+#if USE_RCS_ID
+const char _uuconf_addstr_rcsid[] = "$Id: addstr.c,v 1.1 1993/08/04 19:33:32 jtc Exp $";
+#endif
+
+#include <errno.h>
+
+/* When setting system information, we need to be able to distinguish
+ between a value that is not set and a value that has been set to
+ NULL. We do this by initializing the value to point to the
+ variable _uuconf_unset, and then correcting it in the function
+ _uuconf_isystem_basic_default. This variable is declared in this
+ file because some linkers will apparently not pull in an object
+ file which merely declarates a variable. This functions happens to
+ be pulled in by almost everything. */
+
+char *_uuconf_unset;
+
+/* Add a string to a list of strings. The list is maintained as an
+ array of elements ending in NULL. The total number of available
+ slots is always a multiple of CSLOTS, so by counting the current
+ number of elements we can tell whether a new slot is needed. If
+ the fcopy argument is TRUE, the new string is duplicated into
+ memory. If the fcheck argument is TRUE, this does not add a string
+ that is already in the list. The pblock argument may be used to do
+ the allocations within a memory block. This returns a standard
+ uuconf error code. */
+
+#define CSLOTS (8)
+
+int
+_uuconf_iadd_string (qglobal, zadd, fcopy, fcheck, ppzstrings, pblock)
+ struct sglobal *qglobal;
+ char *zadd;
+ boolean fcopy;
+ boolean fcheck;
+ char ***ppzstrings;
+ pointer pblock;
+{
+ char **pz;
+ size_t c;
+
+ if (fcheck && *ppzstrings != NULL)
+ {
+ for (pz = *ppzstrings; *pz != NULL; pz++)
+ if (strcmp (zadd, *pz) == 0)
+ return UUCONF_SUCCESS;
+ }
+
+ if (fcopy)
+ {
+ size_t clen;
+ char *znew;
+
+ clen = strlen (zadd) + 1;
+ znew = (char *) uuconf_malloc (pblock, clen);
+ if (znew == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ memcpy ((pointer) znew, (pointer) zadd, clen);
+ zadd = znew;
+ }
+
+ pz = *ppzstrings;
+ if (pz == NULL || pz == (char **) &_uuconf_unset)
+ {
+ pz = (char **) uuconf_malloc (pblock, CSLOTS * sizeof (char *));
+ if (pz == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ *ppzstrings = pz;
+ }
+ else
+ {
+ c = 0;
+ while (*pz != NULL)
+ {
+ ++pz;
+ ++c;
+ }
+
+ if ((c + 1) % CSLOTS == 0)
+ {
+ char **pznew;
+
+ pznew = (char **) uuconf_malloc (pblock,
+ ((c + 1 + CSLOTS)
+ * sizeof (char *)));
+ if (pznew == NULL)
+ {
+ if (qglobal != NULL)
+ qglobal->ierrno = errno;
+ return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO;
+ }
+ memcpy ((pointer) pznew, (pointer) *ppzstrings,
+ c * sizeof (char *));
+ uuconf_free (pblock, *ppzstrings);
+ *ppzstrings = pznew;
+ pz = pznew + c;
+ }
+ }
+
+ pz[0] = zadd;
+ pz[1] = NULL;
+
+ return UUCONF_SUCCESS;
+}
diff --git a/gnu/libexec/uucp/libuuconf/allblk.c b/gnu/libexec/uucp/libuuconf/allblk.c
new file mode 100644
index 0000000..b3dd7e0
--- /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 0000000..2808c62
--- /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 0000000..c5c9cad
--- /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 0000000..c40f660
--- /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 0000000..c1bbde1
--- /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 0000000..4df26dd
--- /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 <errno.h>
+
+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 0000000..957833e
--- /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 <errno.h>
+
+/* 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 0000000..f29481b
--- /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 <ctype.h>
+#include <errno.h>
+
+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 0000000..2020ea9
--- /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 <ctype.h>
+
+#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 0000000..333a4bf
--- /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 <errno.h>
+
+/* 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 0000000..63e9564
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..3be5381
--- /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 0000000..40cf763
--- /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 0000000..823239d
--- /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 <errno.h>
+
+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 0000000..efdef53
--- /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 0000000..7979d0e
--- /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 0000000..6a10ada
--- /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 0000000..d1def82
--- /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 <errno.h>
+
+/* 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 0000000..2bed403
--- /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 0000000..ab1b76a
--- /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 0000000..cb27d11
--- /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 0000000..60b00b7
--- /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 0000000..91916f1
--- /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 0000000..2906b9d
--- /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 0000000..a73f4c1
--- /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 0000000..8b02ff9
--- /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 <ctype.h>
+
+/* 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 0000000..666cc7f
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..0806059
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..2b1c1cc
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..9af4d7e
--- /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 <errno.h>
+
+/* 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 0000000..690de91
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..e7516f7
--- /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 <errno.h>
+
+/* 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 0000000..83129a3
--- /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 <errno.h>
+#include <ctype.h>
+
+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 0000000..de003a3
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..676c20f
--- /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 0000000..8e997d0
--- /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 <errno.h>
+
+/* 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 0000000..2422656
--- /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 <errno.h>
+
+/* 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 0000000..ef252a7
--- /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 0000000..b0047ee
--- /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 0000000..52d1a9f
--- /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 0000000..77839f6
--- /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 0000000..272d623
--- /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 <errno.h>
+
+/* 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 0000000..33adda4
--- /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 <errno.h>
+
+/* 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 0000000..1bc165b
--- /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 0000000..6d76764
--- /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 0000000..8b5e9e7
--- /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 0000000..4b2ea1c
--- /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 0000000..bcc9a0b
--- /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 <errno.h>
+
+/* 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 0000000..586c226
--- /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 0000000..682f38e
--- /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 0000000..0c4714d
--- /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 0000000..ba8365fd
--- /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 <errno.h>
+
+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 0000000..dd481c1
--- /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 <errno.h>
+#include <ctype.h>
+
+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 0000000..13517d4
--- /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 0000000..85297b0
--- /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 0000000..f73851f
--- /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 0000000..d239b10
--- /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 0000000..76cc5e8
--- /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 <ctype.h>
+
+/* 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 0000000..e9c13f0
--- /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 0000000..bcea0bf
--- /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 0000000..8ff18a6
--- /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 <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#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 0000000..f9b52c1
--- /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 <errno.h>
+
+/* 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 0000000..8eb627e
--- /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 <errno.h>
+
+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 0000000..f13c929
--- /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 <errno.h>
+
+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 0000000..e70090f
--- /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 0000000..d9e4b0d
--- /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 <errno.h>
+
+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 0000000..9bc8de2
--- /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 0000000..92f100b
--- /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 <errno.h>
+
+/* 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 0000000..6f31682
--- /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 <ctype.h>
+#include <errno.h>
+
+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 0000000..829fd12
--- /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 <errno.h>
+
+/* 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 0000000..bf09446
--- /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 <errno.h>
+
+/* 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 0000000..0a94a81
--- /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 <errno.h>
+
+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 0000000..7b796ea
--- /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 <errno.h>
+
+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 0000000..5e31ca2
--- /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 <errno.h>
+#include <ctype.h>
+
+#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 0000000..c0f96e5
--- /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 0000000..6a1f662
--- /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 0000000..be87696
--- /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 0000000..88ca350
--- /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 0000000..565dd27
--- /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 <errno.h>
+
+/* 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 0000000..9ce6a62
--- /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 0000000..a4eb30f
--- /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 0000000..20ff5bc
--- /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 <errno.h>
+
+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 0000000..b9382a3
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..c528ce3
--- /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 <errno.h>
+#include <ctype.h>
+
+/* 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 0000000..0bf04b58
--- /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 <errno.h>
+
+/* 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 0000000..c0280cc
--- /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 0000000..0939248
--- /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 0000000..6870a60
--- /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 <bsd.lib.mk>
diff --git a/gnu/libexec/uucp/libuucp/bsrch.c b/gnu/libexec/uucp/libuucp/bsrch.c
new file mode 100644
index 0000000..3b1a61c
--- /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 0000000..c44fa45
--- /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 0000000..098e551
--- /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 0000000..fc9687b
--- /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 0000000..86f7841
--- /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 <ctype.h>
+
+#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 0000000..646b787
--- /dev/null
+++ b/gnu/libexec/uucp/libuucp/escape.c
@@ -0,0 +1,98 @@
+/* escape.c
+ Translate escape sequences. */
+
+#include "uucp.h"
+
+#include <ctype.h>
+
+#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 0000000..1c204e7
--- /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 0000000..c3ebc08b
--- /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 <stdio.h>
+
+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 0000000..f97c64e
--- /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 0000000..e1f399a
--- /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 0000000..b61578a
--- /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 0000000..2258123
--- /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 0000000..6b928a4
--- /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 0000000..52223fb
--- /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 <ctype.h>
+
+#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 0000000..bee5f83
--- /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 0000000..4bb2251
--- /dev/null
+++ b/gnu/libexec/uucp/libuucp/strcas.c
@@ -0,0 +1,33 @@
+/* strcas.c
+ Compare two strings case insensitively. */
+
+#include "uucp.h"
+#include <ctype.h>
+
+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 0000000..ca8d8e9
--- /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 0000000..231e35b
--- /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 0000000..6959d62
--- /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 <ctype.h>
+
+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 0000000..a88e4b4
--- /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 0000000..111460b
--- /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 0000000..f663994
--- /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 <ctype.h>
+#include <errno.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#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 0000000..239b015
--- /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 0000000..4aac237
--- /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 0000000..36ae313
--- /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 0000000..de4190c
--- /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 0000000..e7d683b
--- /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 0000000..f0d4bdd
--- /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 0000000..710a07b
--- /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 0000000..2b04e13
--- /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 0000000..8e48186
--- /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 0000000..fa9e770
--- /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 0000000..856529a
--- /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 0000000..d305499
--- /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 <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>
+#endif
+
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#if HAVE_SELECT
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#endif
+
+#if HAVE_POLL
+#if HAVE_STROPTS_H
+#include <stropts.h>
+#endif
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#endif
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#endif
+
+#if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT)
+#include <time.h>
+#endif
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#if HAVE_UNION_WAIT
+typedef union wait wait_status;
+#else
+typedef int wait_status;
+#endif
+
+#if HAVE_STREAMS_PTYS
+#include <termio.h>
+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 0000000..0aaa00f
--- /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 <bsd.prog.mk>
diff --git a/gnu/libexec/uucp/uuchk/uuchk.c b/gnu/libexec/uucp/uuchk/uuchk.c
new file mode 100644
index 0000000..41021de
--- /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 0000000..e4c58aa
--- /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 <bsd.prog.mk>
+.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 0000000..2d2e77e
--- /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 0000000..3cdacef
--- /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 <ctype.h>
+#include <errno.h>
+
+#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 0000000..e9eaeb0
--- /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 <ctype.h>
+#include <errno.h>
+
+#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:
+
+ <DLE><k><c0><c1><C><x>
+
+ <DLE> is the ASCII DLE character (^P or '\020').
+ if 1 <= <k> <= 8, the packet is followed by 2 ** (k + 4) bytes of data;
+ if <k> == 9, these six bytes are a complete control packet;
+ other value of <k> are illegal.
+ <c0> is the low byte of a checksum.
+ <c1> is the high byte of a checksum.
+ <C> is a control byte (see below).
+ <x> is <k> ^ <c0> ^ <c1> ^ <C>.
+
+ The control byte <C> 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)))
+
+/* <k> 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 <k> are always transferred). Let <u> be the number
+ of bytes in the data segment not to be used. If <u> <= 0x7f, the first
+ byte of the data segment is <u> and the data follows. If <u> > 0x7f,
+ the first byte of the data segment is 0x80 | (<u> & 0x7f), the second
+ byte of the data segment is <u> >> 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 <k> 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 <k>
+ field in the header; the amount of data in a packet is
+ 2 ** (<k> + 4). <k> 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 0000000..606b2bd
--- /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 <ctype.h>
+#include <errno.h>
+
+#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 0000000..bdf2b85
--- /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 <ctype.h>
+#include <errno.h>
+
+#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 0000000..477ccf4
--- /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 0000000..e593e07
--- /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 <errno.h>
+
+#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: <cZrx_buf_len> 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 <wpZtxpos, wpZrxbytes> 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 <cZblklen> */
+static unsigned cZtxwcnt; /* counter used to space ack requests */
+static unsigned cZrxwcnt; /* counter used to watch receiver's buf size */
+static winpos_t wpZtxstart; /* <wpZtxpos> 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 <cZtx_window> 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 <cZblklen> 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 /* <cZblklen_override> 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 <fexit>?
+ * 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 <Attn> 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;
+
+ /*
+ * <wpZlastsync> 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 ...
+ * <frameend> 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 <lastsent>.
+ */
+
+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 ...
+ *
+ * <timeout> 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 <fdoread> 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 <hdrval_t> 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 <hdrval_t> 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 <wpZrxpos> 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 <rx_pktpos> 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 0000000..160aab7
--- /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 <errno.h>
+
+#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 0000000..9337de3
--- /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 <errno.h>
+
+#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 0000000..c082662
--- /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 <ctype.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#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 0000000..065caa4
--- /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 <errno.h>
+
+#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 0000000..fba8bb5
--- /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 0000000..ecd6c23
--- /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 <ctype.h>
+
+#if HAVE_LIMITS_H
+#include <limits.h>
+#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 0000000..494fe12
--- /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 <errno.h>
+
+#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 0000000..f06c3e2
--- /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 <bsd.prog.mk>
diff --git a/gnu/libexec/uucp/uuconv/uuconv.c b/gnu/libexec/uucp/uuconv/uuconv.c
new file mode 100644
index 0000000..82f4e35
--- /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 0000000..5e45460
--- /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 <bsd.prog.mk>
+.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 0000000..0fa81fe
--- /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 0000000..93e9ff4
--- /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 <ctype.h>
+#include <errno.h>
+
+#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 0000000..321656f
--- /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 <bsd.prog.mk>
+.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 0000000..9a58fff
--- /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 <ctype.h>
+#include <errno.h>
+
+#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 0000000..5e7b314
--- /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 <bsd.prog.mk>
+.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 0000000..54a87df
--- /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 0000000..c9a4312
--- /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 <bsd.prog.mk>
+.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 0000000..4e1f1b3
--- /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 <errno.h>
+
+#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 ("<return>: 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 0000000..ca0aa32
--- /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 <bsd.prog.mk>
diff --git a/gnu/libexec/uucp/uusched/uusched.in b/gnu/libexec/uucp/uusched/uusched.in
new file mode 100644
index 0000000..e539b90
--- /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 0000000..7451292
--- /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 <bsd.prog.mk>
+.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 0000000..b818521
--- /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 0000000..3c13526
--- /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 <ctype.h>
+#include <errno.h>
+
+#if HAVE_TIME_H
+#include <time.h>
+#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 0000000..7caef8f
--- /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 <bsd.prog.mk>
diff --git a/gnu/libexec/uucp/uuto/uuto.in b/gnu/libexec/uucp/uuto/uuto.in
new file mode 100644
index 0000000..2d7d96a
--- /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 0000000..8f1cb4e
--- /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 <bsd.prog.mk>
+.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 0000000..69c85ab
--- /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 0000000..5dc9866
--- /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 <ctype.h>
+#include <errno.h>
+
+/* 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 0000000..ded44bf
--- /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 <bsd.prog.mk>
+.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 0000000..faee1cf
--- /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 0000000..919ea7e
--- /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 <errno.h>
+#include <ctype.h>
+
+#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;
+}
OpenPOWER on IntegriCloud