uucp-1.04/0407750004150000170000000000005337265114010332 5 0ianusers 1 0 uucp-1.04/COPYING1004440004150000170000004307005337263476010432 037777777777 1 0 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. 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 exeuucp-1.04/ChangeLog1004440004150000170000035144405337263500011144 037777777777 1 0 Sat Feb 13 15:57:30 1993 Ian Lance Taylor (ian@comton.airs.com) * Released version 1.04. * unix/detach.c: Andrew A. Chernov: Don't check return of setsid. Sun Jan 31 01:45:56 1993 Ian Lance Taylor (ian@comton.airs.com) * cu.c (main): Pass "cu" to uuconf_init. * protz.c (fzprocess): Restore ZPAD char before calling getinsync. Sat Jan 30 22:19:26 1993 Ian Lance Taylor (ian@comton.airs.com) * Makefile.in (doc-dist): New target. Wed Jan 27 22:55:26 1993 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgstart): Set iGremote_segsize when using remote-packet-size. Tue Jan 26 01:01:34 1993 Ian Lance Taylor (ian@comton.airs.com) * proti.c (fiprocess_data): always send an ACK after receiving half a window, rather than sometimes resending a packet. Half a window of short packets can arrive very quickly. * tstuu.c (main, cread, fsend): rewrote communication routines to avoid deadlock. Sun Jan 24 01:02:47 1993 Ian Lance Taylor (ian@comton.airs.com) * trans.c (ufailed): don't report statistics if no bytes transferred. * Makefile.in (install): simplified somewhat. (dist): distribute the sample directory. Sat Jan 23 19:47:12 1993 Ian Lance Taylor (ian@comton.airs.com) * configure.in, conf.h.in, tli.c: Karl Swarz: check for and use . Fri Jan 22 00:09:37 1993 Ian Lance Taylor (ian@comton.airs.com) * send.c (flocal_send_request): Alan Judge: don't send C in option string when faking an E command as an S command. Thu Jan 21 00:09:31 1993 Ian Lance Taylor (ian@comton.airs.com) * uux.c (main): don't use E command if forwarding. Wed Jan 20 00:22:38 1993 Ian Lance Taylor (ian@comton.airs.com) * send.c (fsend_exec_file_init), rec.c (frec_file_end), uux.c (main): Chip Salzenberg: always put the C line last in an execution file, to support Fredmail. Tue Jan 19 00:09:43 1993 Ian Lance Taylor (ian@comton.airs.com) * trans.h, trans.c (ftcharge, floop, fgot_data): rewrote timing code. * trans.h, trans.c, send.c, rec.c, xcmd.c, protf.c, protz.c (fqueue_local, fqueue_remote, fqueue_send, fqueue_receive): added boolean return value and qdaemon argument. Mon Jan 18 00:01:46 1993 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (fdo_call, faccept_call): Ted Lindgreen, Chip Salzenberg: wait for remote hangup string before hanging up. * proti.c (fiprocess_data, fiprocess_packet): stop scanning input buffer after a CLOSE packet. Sat Jan 16 22:44:28 1993 Ian Lance Taylor (ian@comton.airs.com) * system.h, uucico.c (main), uuxqt.c (main), unix/init.c: Ted Lindgreen: eliminated INIT_DAEMON. * log.c (ulog): don't log SIGINT if fLog_sighup is FALSE. * unix/move.c (fsysdep_move_file), unix/xqtsub.c (fsysdep_move_uuxqt_files): the system call rename seems to fail on some systems for arbitrary reasons, so always try to copy the file by hand, not just if we get EXDEV. * policy.h, unix/pause.c: Gregory Gulik: added HAVE_HUNDREDTHS_NAP configuration parameter. Wed Jan 6 21:06:45 1993 Ian Lance Taylor (ian@comton.airs.com) * unix/serial.c (fsserial_lockfile): create HDB lock files when using HAVE_COHERENT_LOCKING. unix/cohtty.c (fscoherent_disable_tty): consistently return FALSE on error. * unix/cusub.c (fsysdep_terminal_raw): Andrew A. Chernov: if POSIX_TERMIOS, turn of IEXTEN flag. Sat Jan 2 23:19:27 1993 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgprocess_data): treat a duplicate RR as an RJ. Fri Jan 1 11:17:30 1993 Ian Lance Taylor (ian@comton.airs.com) * policy.h, unix/proctm.c: Steven S. Dick: use sysconf (_SC_CLK_TCK) for TIMES_TICK if possible. * uuconf/diacod.c: Gregory Gulik: accept an empty dialcode string. * system.h, uucico.c (main), uucp.c (main), uux.c (main), unix/run.c: Karsten Thygesen: removed ffork argument from fsysdep_run. Wed Dec 30 00:21:55 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/link.c: Andrey G Blochintsev: don't fail just because destination directories do not exist. * send.c (flocal_send_open_file): Scott Ballantyne: record file name when logging send of execution command. * protz.c: Chip Salzenberg: reformatted to 80 columns. Tue Dec 29 23:50:52 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconv.c (uvwrite_time): scott@geom.umn.edu: handle midnight more correctly. Fri Dec 18 00:49:16 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, uucp.c (uccopy), uux.c (main), cu.c (icuput, icutake), unix/ufopen.c (esysdep_user_fopen): Doug Evans: open files used for %put and %take using esysdep_user_fopen, rather than with privileges of uucp. Added frd and fbinary arguments to esysdep_user_fopen. Thu Dec 17 00:04:53 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/picksb.c (zsysdep_uupick): Peter Wemm: allocation error. * uupick.c (main): Peter Wemm: pass INIT_GETCWD to usysdep_initialize; really quit if 'q' is typed. * uulog.c (main): Peter Wemm: always canonicalize system name, not just if using HDB_LOGGING. * uudefs.h, log.c (ustats), trans.c (ufailed), send.c (fsend_await_confirm), rec.c (frec_file_end): Peter Wemm: added fmaster argument to ustats, used only in HDB_LOGGING. Wed Dec 16 23:35:51 1992 Ian Lance Taylor (ian@comton.airs.com) * uustat.c (main): Marc Unangst: forgot to call strtol for -y. * policy.h, sysh.unx: Brian J. Murrell: yet another configuration parameter: HAVE_BROKEN_SETREUID. Tue Dec 15 00:13:04 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconv.c (uvwrite_taylor_system): mnichols@pacesetter.com: use command-path rather than path. * trans.c (floop): Marc Unangst: don't clear frequested_hangup if we didn't manage to hang up. * uucp.h, rec.c (fremote_send_file_init): Oleg Girko: patches to make code compile if USE_STDIO is 0. * unix/proctm.c: Tim Peiffer: reverse sense of TIMES_TICK check in hopes of avoiding ISC preprocessor bug. * unix/fsusg.h, unix/fsusg.c, unix/bytfre.c, system.h, conf.h.in, configure.in, unix/Makefile.in, unix/MANIFEST: use new disk space checking routines from GNU fileutils 3.4. * unix/opensr.c (zsysdep_receive_temp): don't check free space here any more. * policy.h, trans.h, trans.c, rec.c, uucico.c, uudefs.h: Chip Salzenberg: check amount of remaining space on disk every FREE_SPACE_DELTA bytes, and abort the file transfer if disk space gets too low. Wed Dec 2 00:24:12 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, unix/serial.c (fsserial_set): Frank Conrad: added HAVE_PARITY_BUG parameter for the Sony NEWS. Mon Nov 30 00:06:59 1992 Ian Lance Taylor (ian@comton.airs.com) * lib/spool.c (fspool_file): Andrew Chernov: accept any alphanumeric character in the name, because it could be a grade from another system. Sun Nov 29 22:36:47 1992 Ian Lance Taylor (ian@comton.airs.com) * lib/buffer.c (ubuffree): scott@geom.umn.edu, Richard Gumpertz: use a temporary variable to hold the offsetof result. * configure.in: scott@geom.umn.edu: define HAVE_SYS_SELECT_H correctly. * protg.c (fgsend_control): Niels Baggesen: report all non-RR packets if DEBUG_ABNORMAL. * unix/cusub.c (uscu_child): Ed Carp: apparently the read and write calls can get EAGAIN on some systems. * unix/status.c (fsysdep_get_status, fsysdep_set_status): Chip Salzenberg: map status values when using SPOOLDIR_HDB. * rec.c (fremote_send_reply): do file restart correctly for E commands. Sun Nov 22 15:09:43 1992 Ian Lance Taylor (ian@comton.airs.com) * protz.c: Chip Salzenberg: always do bitwise operations on unsigned values. * getopt.h: Chip Salzenberg: don't rely on __STDC__. Thu Nov 19 00:13:46 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/freblk.c: Niels Baggesen: loop over the right list. * uulog.c (main): Peter Wemm: added -D, -F and -S options, made -f take an argument and default to showing 10 current lines. (ulusage): added new options and missing old ones. Wed Nov 18 22:26:36 1992 Ian Lance Taylor (ian@comton.airs.com) * rec.c (frec_file_end): Andrey G Blochintsev: call fsysdep_remember_reception as soon as the file has been moved to the final destination; write fake execution file via a temporary file to prevent uuxqt from getting at it early. * trans.c (usent_receive_ack): don't call fsysdep_remember_reception here. * unix/tmpfil.c (ZDIGS): don't use '.', since we use it to separate parts of the file name. Sun Nov 15 15:31:49 1992 Ian Lance Taylor (ian@comton.airs.com) * uustat.c (fsquery_show, csunits_show): Marc Unangst, Chip Salzenberg: line up uustat -q output. * sysh.unx, ftw.c (ftw_dir, ftw), srmdir.c (isremove_dir), walk.c (iswalk_dir): Marc Unangst: stat argument to function argument to ftw is const. * unix/serial.c (fsserial_set): Mike Bernson: set CSIZE correctly when changing parity. * uux.c (main): Andrew A. Chernov: check for executions which name the local system, to handle dumb mailers. * uucp.h: Doug Evans: #undef strerror if HAVE_STRERROR is 0, to avoid macro definition on Xenix. * unix/serial.c (fsserial_set): Peter Wemm: only check CRTSCTS if HAVE_POSIX_TERMIOS. * cu.c (main): Peter Wemm: use alternates for systems if a call fails. * tstuu.c (uprepare_test): Gerben Wierda: set execute bits for Chat1 and Chat2. * trans.c (floop): Marc Unangst: don't hang up when requested unless the send queue is empty. * uuxqt.c (iqrequestor): Marc Boucher: new function to accept R command with two arguments, as generated by UUPC. * uucico.c (faccept_call): Christian Seyb: don't free the system info until after writing the status. * configure.in: Marc Boucher: check -lsocket and -lnsl together. * unix/portnm.c: Stephen J. Walick: it's types.tcp.h, not tcp.types.h. * configure.in: Brian Campbell: check for /usr/bin/mailx. Sat Nov 14 11:11:04 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/hlocnm.c (uuconf_hdb_login_localname): Christian Seyb: check for _uuconf_unset as well as NULL. * conn.c (fconn_dial): initialize *ptdialerfound. * many files: rearranged header files to include "sysdep.h" before system header files. Also eliminated various pedantic warnings, and made _uuconf_unset char * to avoid possible alignment problems. Tue Nov 10 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com) * trans.h, uucico.c (fcall, faccept_call), trans.c (uclear_queue, floop): Stephen J. Walick: move clean up from end of floop into uclear_queue, and call it instead of just doing usysdep_get_work_free. * unix/serial.c (fsserial_lockfile): Marc Unangst: bad #endif location for HAVE_SVR4_LOCKFILES. (fsserial_init): Doug Evans: null terminate the device name. Sun Nov 8 10:58:59 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (fcall, faccept_call): Stephen J. Walick: call usysdep_get_work_free here. trans.c (floop): don't call usysdep_get_work free here. Sun Nov 1 17:05:07 1992 Ian Lance Taylor (ian@comton.airs.com) * Released gamma version 1.04. * configure.in: check that sys/select.h and sys/time.h work together, since that's how they are currently used. * cu.c, uustat.c, uuconf/diacod.c: add casts to eliminate warnings. * configure.in: don't add strlwr to LIBOBJS. * policy.h, unix/cohtty.c: Bob Hemedinger: finish Coherent style locking. Wed Oct 28 00:20:15 1992 Ian Lance Taylor (ian@comton.airs.com) * tstuu.c: Ralf Stephan: check HAVE_POLL_H and HAVE_STROPTS_H. * Nickolay Saukh: accept SVR4 style R request file position. uudefs.h: added ipos field to struct scmd. lib/parse.c: accept SVR4 style R request with file position to start from. send.c (fremote_rec_file_init): start transferring file from requested position. uucp.c, uux.c, uuxqt.c, xcmd.c: initialize ipos field. Sun Oct 25 10:39:23 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/serial.c (fsysdep_conn_write, fsysdep_conn_io): T. William Wells: take special care to ensure we don't write after SIGHUP. * policy.h, sysh.unx, unix/MANIFEST, unix/Makefile.in, unix/serial.c (fsserial_lockfile), unix/cohtty.c (new file): Bob Hemedinger: added HAVE_COHERENT_LOCKFILES. * unix/cusub.c (uscu_child): Igor V. Semenyuk: accept a 0 return from read until we have read some data at some point. Thu Oct 22 10:38:32 1992 Ian Lance Taylor (ian@comton.airs.com) * proti.c: various tweaks for bad connections. * uucp.h: T. William Wells: rename strcasecmp and strncasecmp, if the system doesn't provide them, to avoid the ANSI C name space. * lib/buffer.c: Bob Hemedinger: put ab in union so that offsetof will not take the address of an array. * uuxqt.c (uqdo_xqt_file): Bob Hemedinger: don't take address of array. Wed Oct 21 00:05:31 1992 Ian Lance Taylor (ian@comton.airs.com) * uustat.c (fsnotify): Gert Doering: if the file appears to be binary, don't include it in any mail message. * unix/mkdir.c: Michael Yu.Yaroslavtsev: check whether directory already exists before spawning /bin/mkdir. * proti.c: Michael Yu.Yaroslavtsev: iIsendpos and iIrecpos should be long. * send.c (flocal_send_await_reply): Gert Doering: improved error messages. * tli.c, unix/detach.c: include "sysdep.h" before . * configure.in, conf.h.in: added some system specific checks provided by autoconf. * tstuu.c, unix/serial.c: Merlyn LeRoy: check for ENODATA as well as EAGAIN and EWOULDBLOCK. * uucico.c (faccept_call): Zacharias J. Beckman: if calling back, clear status first. * uucico.c (fdo_call, faccept_call): Hans-Dieter Doll: avoid overflow when turning ulimit value into bytes. Tue Oct 20 23:12:26 1992 Ian Lance Taylor (ian@comton.airs.com) * serial.c (fsmodem_carrier): Hans-Dieter Doll: use IS68K LNOMDM bit if available. * chat.c (fcsend): Hans-Dieter Doll: advance z after EOT. * cu.c: T. William Wells: beep on connected and disconnected messages (only if ANSI_C, to use \a). * unix/run.c: Peter Wemm: pass fsetuid as TRUE to ixsspawn. Sun Oct 18 13:58:17 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, unix/serial.c (fsmodem_close): Stephen J. Walick: added HAVE_RESET_BUG for SCO Xenix. * configure.in: Igor V. Semenyuk: avoid looking in -linet for getline, since ISC has a different function there by that name. * unix/ufopen.c: Igor V. Semenyuk: handle unsigned uid_t. Sat Oct 17 11:00:30 1992 Ian Lance Taylor (ian@comton.airs.com) * conf.h.in, configure.in, uucp.h, unix/serial.c (fsserial_lockfile), lib/MANIFEST: eliminated strlwr. Fri Oct 16 01:10:56 1992 Ian Lance Taylor (ian@comton.airs.com) * Igor V. Semenyuk: uuchk.c (ukshow): print max-remote-debug correctly. lib/debug.c (idebug_parse): accept DEBUG_NONE. Thu Oct 15 00:49:58 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/cusub.c (fsysdep_terminal_puts): don't modify zalc before freeing it up. * protg.c (fgcheck_errors, fggot_ack, fgprocess_data): Mark E. Mallett: better handling of error decay. Wed Oct 14 22:09:20 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/lock.c: Tomi Vainio: make sure SEEK_SET is defined. * tcp.c (ftcp_dial): print a better error message if gethostbyname doesn't set errno. * Stephen J. Walick: configure.in, conf.h.in: check for . tcp.c, unix/opensr.c: include if available. lib/debug.c, unix/portnm.c, uuconf/int.c, uuconf/llocnm.c, uuconf/time.c: cast more arguments to eliminate more warnings. Tue Oct 13 00:25:03 1992 Ian Lance Taylor (ian@comton.airs.com) * prot.h, proti.c (fistart, fijstart), protj.c, uucico.c, tstuu.c (uprepare_test), Makefile.in, MANIFEST: added 'j' protocol. Sun Oct 11 23:45:20 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, unix/serial.c (fsserial_set): added HAVE_STRIP_BUG to policy.h to get around stupid Ultrix bug. * sysh.unx, unix/cusub.c, unix/serial.c (fsserial_open): for HAVE_BSD_TTY, keep tchars and ltchars in the sterminal structure, and in fsserial_open disable all interrupt characters. Sat Oct 10 01:18:31 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/tinit.c (itunknown): Gert Doering: don't save "unknown" with the other arguments. Fri Oct 9 00:56:43 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/lock.c: check for running process before doing kill. Thu Oct 8 00:20:12 1992 Ian Lance Taylor (ian@comton.airs.com) * chat.c, protf.c, send.c, rec.c, unix/locfil.c: Stephen J. Walick: cast arguments to strtol and strcspn to avoid warnings. * uustat.c (fsnotify): Marc Boucher: don't free string from uuconf_localname, and only prepend remote system name to execution requests, not to local UUCP commands. * unix/lock.c (fsdo_lock): Marc Boucher: set fret to TRUE before going around the loop again. * uucico.c: Marc Boucher: use 'a' protocol before 'g'. * unix/spool.c (zsfind_file): Matthias Zepf: fixed typos for SPOOLDIR_BSD*. Wed Oct 7 00:03:08 1992 Ian Lance Taylor (ian@comton.airs.com) * uuname.c (main): Marc Boucher: reverse sense of -a, and do not display aliases by default. * uucico.c (fdo_call): Marc Boucher: some systems only provide 14 characters in the Shere line. * tstuu.c (main): Marc Boucher: add support for STREAMS ptys. Tue Oct 6 23:16:15 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h: Marc Boucher: improve comments to describe SVR4. * chat.c (fcsend, fcecho_send, fcecho_send_strip, fcecho_send_nostrip): Marc Boucher: don't send CR after BREAK or EOT, and let chat-seven-bit apply to echo checking. * uuname.c (main): Andreas Vogel: usysdep_exit (TRUE) rather than usysdep_exit (EXIT_SUCCESS). Mon Oct 5 22:59:51 1992 Ian Lance Taylor (ian@comton.airs.com) * sysh.unx, unix/serial.c (fsserial_init): Marc Boucher: avoid freeing unallocated string. * unix/serial.c (fsmodem_carrier): Peter Wemm: eliminated useless undeclared variable which only appeared if HAVE_CLOCAL_BUG. * cu.c (main): don't require carrier when opening a direct line. (fcudo_cmd, fcudo_subcmd, uculist_fns, icuunrecogfn): T. William Wells: give reasonable error messages. Sun Oct 4 00:03:10 1992 Ian Lance Taylor (ian@comton.airs.com) * */Makefile.in: T. William Wells: use ar qc rather than ar rc. * many: T. William Wells: renamed isysdep_* functions to ixsysdep_*, and renamed isfork, isspawn, and isswait similarly, to avoid ANSI C namespace restrictions. * uucp.h: T. William Wells: default size_t to unsigned, not int. * configure.in: T. William Wells: new definition for AC_RETSIGTYPE. * configure.in: T. William Wells: test for sh builtin echo. conf.h.in: default ECHO_PROGRAM to undefined. * proti.c (fiprocess_data, fiprocess_packet): fix confusion between iIremote_winsize and iIrequest_winsize. * proti.c (fiwindow_wait, fisenddata): wait for a window opening before sending SPOS. * proti.c (fiprocess_data): don't send a NAK for a duplicate of the most recent packet. * configure.in: Stephen J. Walick: don't use AC_PREFIX, check for /usr/bin/mail. * system.h, sysh.unx, send.c (flocal_send_file_init, fsend_exec_file_init), rec.c (flocal_rec_file_init, fremote_send_file_init, frec_file_end), xcmd.c (fremote_xcmd_init), uuxqt.c (uqdo_xqt_file, uqcleanup), uux.c (main, uxadd_send_file), uucp.c (main, uccopy), uustat.c (fsworkfile_show, fsexecutions, fsnotify), unix/filnam.c (zsfile_name, zsysdep_data_file_name, zsysdep_xqt_file_name), unix/jobid.c (zsfile_to_jobid, zsjobid_to_file), unix/splcmd.c (zsysdep_spool_commands), unix/splnam.c (zsysdep_spool_file_name), spool.c (zsfind_file), statsb.c (fskill_or_rejuv, isysdep_work_time), work.c (fswork_file, fsysdep_get_work, zsysdep_jobid, bsgrade): Marc Unangst, Brian Murrell: Corrected support for SPOOLDIR_SVR4, since SVR4 doesn't use grades in file names. Changed flocal argument to pseq argument in zsysdep_spool_file_name, and changed flocal argument to bgrade argument in zfind_file. Added fxqt argument to zsysdep_data_file_name. Added bsgrade function. Added bgrade argument to zsfile_to_jobid, and pbgrade argument to zsjobid_to_file. Sat Oct 3 11:03:13 1992 Ian Lance Taylor (ian@comton.airs.com) * MANIFEST, Makefile.in, lib/MANIFEST, lib/Makefile.in, lib/parse.c: moved parse.c from main directory to lib. * system.h, unix/size.c, unix/Makefile.in, unix/MANIFEST: moved csysdep_size into its own file, made it return -1 if the file does not exist or -2 on other errors. uustat.c (fsworkfile_show): handle errors from csysdep_size. send.c (flocal_send_file_init): handle errors from csysdep_size, removed unneeded calls to fsysdep_file_exists. * trans.c (flocal_poll_file), tcp.c (ftcp_dial): Bob Cunningham: declare functions consistently static. * Makefile.in: Marc Unangst: don't run config.status unnecessarily. * configure.in: Marc Unangst: check for socket and t_open in -lsocket, -lnsl and -lxti. * uuconf/cmdarg.c: check first character to avoid calls to strcmp or strcasecmp. Thu Oct 1 23:44:24 1992 Ian Lance Taylor (ian@comton.airs.com) * trans.h, uucico.c (fdo_call, faccept_call), parse.c (fparse_cmd), send.c (flocal_send_request): Gert Doering: SVR4 UUCP uses a dummy string between the notify field and the size, for some reason. * tstuu.c (main, uprepare_test): added -n switch to not destroy existing configuration files. Fri Sep 25 00:16:35 1992 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgsenddata): T. William Wells: clear bytes correctly so that resending a packet doesn't get a completely incorrect size. * send.c (usadd_exec_line): Stephen J. Walick: don't send trailing spaces on the created execute file, because it confuses Waffle. Thu Sep 24 00:25:18 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/jobid.c (zsjobid_to_file): Franc,ois Pinard: if the job ID is too short, return NULL rather than dumping core. unix/statsb.c (fskill_or_rejuv, isysdep_work_time): handle a NULL return from zsjobid_to_file. Mon Sep 21 09:01:02 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/init.c, uuconf/syssub.c: Lele Gaifax: moved declaration of _uuconf_unset from syssub.c to addstr.c because NeXT linker does not pull in object files solely because of variable declarations. * sysh.unx: Lele Gaifax: typo in ftw declaration. * lib/Makefile.in, unix/Makefile.in: Lele Gaifax: bug in clean target. Thu Sep 17 01:01:13 1992 Ian Lance Taylor (ian@comton.airs.com) * Released beta version 1.04. Wed Sep 16 01:02:55 1992 Ian Lance Taylor (ian@comton.airs.com) * uux.c (main): null terminate the options list for an 'E' command. * ustat.c (fsexecutions): allow privileged users to kill remote execution files, and handle local executions correctly. * uuconf/hinit.c: added parens to avoid warning. * unix/splcmd.c: cast to avoid warning. * unix/serial.c (fsmodem_close): fixed HAVE_SYSV_TERMIO typo. * trans.c (uqueue_receive, floop, fgot_data): improved timing code to make fewer system calls. * send.c (fsend_exec_file_init, fsend_exec_file): handle separate E file correctly, and make a good statistics file entry for it. * Makefile.in, unix/Makefile.in, uuconf/Makefile.in, lib/Makefile.in: use -I flags to permit compilation in a separate directory. Set up clean targets per GNU standards. Tue Sep 15 00:07:09 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (zget_uucp_cmd): can't set size_t variable to -1. * Makefile.in (install): don't install info files. Added new targets info and install-info. Mon Sep 14 13:19:42 1992 Ian Lance Taylor (ian@comton.airs.com) * uuxqt.c (main): Gregory Bond: canonicalize the system name given by the -s argument. * system.h, uuconf.h, uucico.c (faccept_call), unix/unknwn.c, unix/Makefile.in, unix/MANIFEST, uuconf/syshdr.unx, uuconf/remunk.c, uuconf/hrmunk.c, uuconf/Makefile.in, uuconf/MANIFEST: support HDB remote.unknown shell script. * protg.c (igchecksum, igchecksum2): Inspired by Mark Pizzolato, put in new, improved checksum routines. * uuxqt.c (uqdo_xqt_file): make sure the execution file still exists after locking it. * unix/lock.c (fsdo_lock): don't fail if the lock file is removed between the link and the open. * unix/xqtsub.c (fsysdep_execute, fsysdep_lock_uuxqt_dir, fsysdep_unlock_uuxqt_dir, fsysdep_move_uuxqt_files): use .Xqtdir for first uuxqt execution, not .Xqtdir0000. Sun Sep 13 11:51:22 1992 Ian Lance Taylor (ian@comton.airs.com) * trans.h, uucico.c (fdo_call, faccept_call), send.c (flocal_send_request), rec.c (flocal_rec_send_request) parse.c (fparse_cmd): send file size in hex for SVR4 compatibility. Required new FEATURE_V103 for 1.03 backward compatibility, since 1.03 requires decimal size. * various: eliminated remaining calls to alloca. * tcp.c (ftcp_open), tli.c (ftli_open): set FD_CLOEXEC for sockets and TLI descriptors. * tcp.c (ftcp_open): switch to real user ID before binding the socket when running as a server. This will permit uucico invoked by root to open privileged TCP ports. Don't switch to real ID if effective ID is already root, to permit an suid root program to be invoked by anybody. * uuxqt.c (uqdo_xqt_file): removed special case for system which does not permit any commands: unnecessary and unusual. * uucico.c (fconn_call): Ed Carp: clear the SIGHUP signal indication before opening the modem. * trans.h, trans.c (fqueue, fcheck_queue, floop, fgot_data), send.c (fsend_await_confirm), rec.c (frec_file_send_confirm), uucico.c (fcall, faccept_call): recheck the work queue every 10 minutes. Honor CYM from the remote system. Send CYM if we have something to do. Sat Sep 12 15:47:52 1992 Ian Lance Taylor (ian@comton.airs.com) * Makefile.in: use $(MAKE) instead of make for recursive calls. * system.h, uucp.c (main), uux.c (main), unix/ufopen.c, unix/MANIFEST, unix/Makefile.in: added esysdep_user_open to open a file with user permissions. Fri Sep 11 00:27:32 1992 Ian Lance Taylor (ian@comton.airs.com) * uudefs.h, copy.c: added fcopy_open_file. * policy.h: added HAVE_SAVED_SETUID. * configure.in, conf.h.in: check for setreuid. Tue Sep 8 00:11:10 1992 Ian Lance Taylor (ian@comton.airs.com) * protf.c (ffsendcmd), prott.c (ftsendcmd): eliminate calls to alloca. * uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), uustat.c (main), uuchk.c (main), uuconv.c (main), uuname.c (main), uulog.c (main), uupick.c (main), cu.c (main), lib/getop1.c, lib/Makefile.in, lib/MANIFEST: added getopt_long, and changed all calls to getopt to call getopt_long instead. Mon Sep 7 22:26:51 1992 Ian Lance Taylor (ian@comton.airs.com) * getopt.h, lib/getopt.c, lib/Makefile.in: bring getopt up to glibc 1.04; call malloc instead of alloca in exchange. * system.h, uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), uustat.c (main), cu.c (main), uuname.c (main), unix/init.c (usysdep_initialize): added INIT_SUID, for old systems which don't do setuid correctly for root. * cu.c, unix/cusub.c: various minor improvements. Sun Sep 6 20:25:20 1992 Ian Lance Taylor (ian@comton.airs.com) * uux.c (uxcopy_stdin): use getchar rather than fread to avoid SVR4 bug. * uucico.c (fsend_uucp_cmd): Niels Baggesen: report message when DEBUG_HANDSHAKE. * protg.c (fgsend_control): Niels Baggesen: report sending an RJ when DEBUG_ABNORMAL. Tue Aug 25 00:07:20 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/time.c: Zacharias Beckman: let user defined time tables override the defaults. Mon Aug 24 00:25:23 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, uuxqt.c (uqdo_xqt_file), unix/xqtsub.c (zsysdep_xqt_local_file): Jarmo Raiha: expand ~name in uuxqt.c. * send.c (fremote_rec_reply): SVR4 sends the size of the file with the RY string, so we do too. We don't look for it, though. * uustat.c, uustat.1: Don Phillips: removed all printing of years and seconds. Hope nobody complains. * uucico.c (fdo_call): don't set the status to TALKING until we see the Shere string. * configure.in, conf.h.in, unix/wldcrd.c: if the system has glob, use it for wildcards. If it doesn't, quote special characters in the wildcard string. * uucico.c (fdo_call): Zacharias Beckman: don't report ``Login successful'' until we see the Shere string. * prot.c (fsend_data): Don Lewis: bug in crec calculation. * uustat.c (fsworkfile_show, usworkfile_header, fsnotify): Don Lewis: show poll files. * unix/init.c: check LOGNAME and USER environment variables before invoking getlogin. * unix/serial.c: Brian Campbell: check for B57600, B76800 and B115200 in baud rate table. Sun Aug 23 13:05:28 1992 Ian Lance Taylor (ian@comton.airs.com) * chat.c (fcsend), tstuu.c (uchild): Chip Salzenberg: call sleep (2) instead of sleep (1). Hopefully this won't break any chat scripts. * system.h, parse.c, trans.c (fqueue, flocal_poll_file), uustat.c (fsworkfiles_system, fsquery_system), unix/work.c (fsysdep_get_work, fsysdep_get_work_init): don't delete poll files immediately, but instead return a 'P' command and delete them when the command is passed to fsysdep_did_work. * tstuu.c (uprepare_test): change ``call-request'' to ``request''. * uuconf/iniglb.c (_uuconf_itimetable): return CMDTABRET_KEEP so we don't lose the timetable name and definition. * uuconf.h, send.c (fremote_rec_file_init), rec.c (fremote_send_file_init), uuchk.c (ukshow), uuconv.c (uvwrite_taylor_system, uvwrite_hdb_system), uuconf/tsinfo.c (iirequest), uuconf/hsinfo.c, uuconf/hunk.c, uuconf/syssub.c: added ``send-request'' and ``receive-request'' commands, eliminated ``call-request'' and ``called-request'' commands. * uux.c (main): make sure we are permitted to transfer files before queuing requests. * uuconf.h, uucico.c (fcall), uuconf/tsinfo.c, uuconf/syssub.c: David Nugent: added ``success-wait'' command for systems, to set a minimum time between successful calls. * send.c (fremote_rec_file_init): Don Phillips: let a request only specify the file base name in the TO argument. * uucico.c (main): Don Lewis: don't exit with success just because we were able to start uuxqt. * unix/serial.c (fsmodem_close, fsserial_read): always drop DTR when closing a modem connection. Also, retry if we time out when setting MIN. Sat Aug 22 22:31:34 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/time.c: Stephen Walick: don't require a comma between time strings, since HDB doesn't seem to. * protg.c (fgcheck_errors): added "error-decay" protocol parameter to decay errors as packets are successfully received. * uustat.c (fsmachines), uustat.1: Chris Lewis: don't display the year or seconds for uustat -m. Probably uustat -q should be changed as well. * tstuu.c: Larry Fahnoe: don't report EWOULDBLOCK errors when writing to a pty. Also removed functions which are now in lib. * MANIFEST, Makefile.in, uusched.in: added a simple uusched shell script. * parse.c: Heiko Rupp: don't die if there is trailing garbage in an 'R' command. * policy.h, system.h, sysh.unx, send.c, rec.c, uuxqt.c, uux.c, unix/filnam.c, unix/init.c, unix/jobid.c, unix/splnam.c, unix/spool.c, unix/statsb.c, unix/tmpfil.c, unix/work.c, unix/xqtfil.c: Brian J. Murrell and Don Phillips: added SPOOLDIR_SVR4. Thu Aug 20 00:06:32 1992 Ian Lance Taylor (ian@comton.airs.com) * sysh.unx: Chiaki Ishikawa: some systems define some but not all of the S_ file mode bits. * uuchk.c (ikshow_port): Chiaki Ishikawa: display lockname. Wed Aug 19 22:41:39 1992 Ian Lance Taylor (ian@comton.airs.com) * log.c (ustats): Scott Blachowicz: avoid overflow when reporting bytes per second. * unix/lock.c (fsdo_lock): Chip Salzenberg: sometimes other programs create lock files that uucp can't write. * trans.h, system.h, trans.c (floop, fgot_data, usent_receive_ack, uwindow_acked), send.c (flocal_send_await_reply, flocal_send_fail), rec.c (fremote_send_fail_send, frec_file_send_confirm), prote.c, protf.c, protg.c, proti.c, prott.c, protz.c (calls to fgot_data), unix/recep.c, unix/MANIFEST, unix/Makefile.in: keep trace of whether we have already received a file, in case the other side never sees our ack. Added new SN8 rejection, meaning that the file has already been received. Sat Aug 15 11:50:32 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf/time.c (itadd_span): Don Lewis: fixed bug if later span overlapped two or more earlier spans. Thu Aug 13 00:19:50 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, rec.c (fremote_send_file_init, fremote_send_reply), uucico.c (fdo_call, faccept_call), uucp.c (main), uux.c (main), unix/opensr.c (zsysdep_receive_temp, esysdep_open_receive): implemented file restart. Wed Aug 12 23:32:05 1992 Ian Lance Taylor (ian@comton.airs.com) * proti.c (fiprocess_data): ensure that the first argument to fgot_data is always > 0 if the second argument is > 0. Mon Aug 10 22:43:40 1992 Ian Lance Taylor (ian@comton.airs.com) * trans.c (floop, ustats_failed): handle half-duplex connections and failed calls correctly. Sun Aug 9 17:56:32 1992 Ian Lance Taylor (ian@comton.airs.com) * proti.c (firesend, fisenddata, ficheck_errors): made several changes to improve performance on a lossy line: can now shrink packet size using SYNC packets, avoids multiple bad header errors in a sequence of INTRO characters, avoids letting one side lock up if a NAK is lost. * configure.in: set HAVE_LONG_FILE_NAMES to 0 if cross-configuring. * tstuu.c: changed -p option to be mod 1000, not mod 100. * MANIFEST, Makefile.in, prot.h, uucico.c, protz.c, trans.c: Doug Evans: added Doug Evans's zmodem implementation as protocol 'a'. Wed Aug 5 22:28:14 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, uuconf.h, uucico.c (fcall), uuconf/tsinfo.c, uuconf/hsinfo.c, uuconf/syssub.c: added "max-retries" command for systems, eliminated CMAXRETRIES configuration parameter, set max_retries to 0 for HDB if retry time given, (from Chris Lewis) call once a day even if max_retries has been exceeded. * prot.h, uucico.c (fdo_call, faccept_call), prott.c, prote.c, proti.c, protg.c, protf.c: added pzlog argument to pfstart protocol entry point, changed handshake successful message to display it. Tue Aug 4 00:04:31 1992 Ian Lance Taylor (ian@comton.airs.com) * prot.h, uucico.c, protg.c (fbiggstart, cGshort_packets): Chip Salzenberg: added support for 'G' protocol. Added "short-packets" protocol parameter for 'g' and 'G' protocols. * uuconf.h, rec.c (flocal_rec_file_init), uucp.c, uux.c, uuxqt.c, uuchk.c, uuconv.c, uuconf/local.c, uuconf/tsinfo.c, uuconf/syssub.c: support UUCP forwarding. Added "forward-from", "forward-to", and "forward" commands for systems. * unix/spawn.c: don't close the file descriptor after dupping it. Sun Aug 2 23:04:18 1992 Ian Lance Taylor (ian@comton.airs.com) * trans.c (fremote_hangup_reply): don't hangup if a file transfer is in progress. * send.c (flocal_send_cancelled): don't pass a NULL buffer to pfsenddata. Sun Jul 26 13:28:27 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/work.c (fsysdep_get_work_init): return TRUE if there is no work directory. * configure.in, sysh.unx: don't run any programs in configure if we are cross-configuring; this applies to HAVE_FTIME and HAVE_RESTARTABLE_SYSCALLS. The code can cope with the buggy ftime. If we are cross-configuring, HAVE_RESTARTABLE_SYSCALLS is set to -1, and sysh.unx guesses that if the system has sigvec but not sigaction or SV_INTERRUPT it is on 4.2BSD and system calls are automatically restarted. * configure.in, conf.h.in, tstuu.c, unix/serial.c: removed COMBINED_UNBLOCK configuration parameter, and changed the code which sets O_NONBLOCK and O_NDELAY to drop back to using just O_NONBLOCK if it gets an EINVAL error. * configure.in, conf.h.in, uucp.h, protg.c (fgsenddata), cu.c (icutake), chat.c (icexpect), lib/MANIFEST: removed all calls to memmove, avoiding the SCO bug and making the 'g' protocol slightly more efficient. Sat Jul 25 14:20:30 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h, uudefs.h, many other files: broke part of uucp.h out into uudefs.h, stopped including uuconf.h in uucp.h, fixed up .c files to include uudefs.h and uuconf.h as necessary. * uuconf/syshdr.unx, uuconf/callin.c, uuconf/diacod.c uuconf/hdial.c, uuconf/hdnams.c, uuconf/hport.c, uuconf/hsinfo.c, uuconf/hsnams.c uuconf/rdlocs.c, uuconf/tcalou.c, uuconf/tdial.c, uuconf/tdnams.c, uuconf/tport.c, uuconf/vport.c, uuconf/vsinfo.c, uuconf/vsnams.c: changed uuconf library to not return an error if a configuration file does not exist; it now acts as though whatever it is is not found. * tstuu.c (main): use perror if execl fails. * configure.in, conf.h.in, uucp.h, uuconf.h, sysh.unx, conn.h, MANIFEST, Makefile.in, tli.c, chat.c (ccescape), conn.c (fconn_init), tcp.c, uucico.c (faccept_call), uuconv.c, uuchk.c, lib/MANIFEST, lib/Makefile.in, lib/escape.c, unix/cusub.c, unix/serial.c, uuconf/hport.c, uuconf/tportc.c: added support for TLI connections. Moved ccescape from chat.c to cescape in lib/escape.c. Made all connections on Unix use the same system dependent structure. Tue Jul 21 22:08:10 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h, trans.h, uucico.c (fdo_call, faccept_call), uuxqt.c (uqdo_xqt_file), uucp.c (main), uux.c (main), uustat.c (fsworkfile_show), parse.c (fparse_cmd), trans.c (fqueue, fgot_data, ftadd_cmd), send.c, rec.c, xcmd.c, protf.c (ffprocess_data), proti.c (fiprocess_data), tstuu.c (uprepare_tests), unix/splcmd.c (zsysdep_spool_commands), unix/statsb.c (fskill_or_rejuv), unix/work.c (fsysdep_get_work): added E request to send file executions which only require reading from standard input. Sat Jul 18 20:22:50 1992 Ian Lance Taylor (ian@comton.airs.com) * proti.c, Makefile.in, MANIFEST, prot.h, system.h, trans.h, uucico.c, prote.c, protf.c, protg.c, prott.c, trans.c, send.c, rec.c, xcmd.c, unix/opensr.c: added 'i' protocol. Added local and remote channel arguments to protocol sendcmd and senddata entry points. Cleaned up send and receive state machines. Removed pfgone argument from esysdep_open_send. Fri Jul 17 09:41:05 1992 Ian Lance Taylor (ian@comton.airs.com) * uuxqt.c (uqdo_xqt_file): only report base name of execution file, not full name. Thu Jul 16 00:45:06 1992 Ian Lance Taylor (ian@comton.airs.com) * lib/crc.c: unroll the loop a bit. * configure.in, conf.h.in, unix/init.c: updated to autoconf 0.120. Wed Jul 15 14:45:32 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconv.c, uuconf/uucnfi.h, uuconf/reliab.c, uuconf/tportc.c, uuconf/tdialc.c, uuconf/diasub.c, uuconf/hport.c, uuconf/prtsub.c, uuconf/vsinfo.c: added UUCONF_RELIABLE_FULLDUPLEX and "half-duplex" command for ports and dialers. Mon Jul 13 16:53:04 1992 Ian Lance Taylor (ian@comton.airs.com) * prot.h, lib/crc.c, lib/Makefile.in, lib/MANIFEST: added icrc function to compute 32 bit CRC (from Gary S. Brown, via Doug Evans). Sun Jul 12 21:40:15 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconv.c (uvwrite_time): Chris Lewis: don't output two commas in a row. * uuconv.c (uvwrite_taylor_system, uvwrite_taylor_port): Chris Lewis: generate command "protocol", not "protocols". Sat Jul 11 17:09:09 1992 Ian Lance Taylor (ian@comton.airs.com) * xcmd.c (fremote_xcmd_init): Chris Lewis: use qdaemon->puuconf, since puuconf is not defined. * uuconf/syshdr.unx, uuconf/hinit.c (uuconf_hdb_init): Chris Lewis: added HDB_SEPARATOR to insert between oldconfiglib and strings in HDB Sysfiles. * uuconf/syshdr.unx: Chris Lewis: define strerror as a macro. * uuconf/freblk.c, uuconf/free.c: Chris Lewis: don't define as void when ! UUCONF_ANSI_C. Thu Jul 9 09:17:55 1992 Ian Lance Taylor (ian@comton.airs.com) * prot.h, uucico.c (fdo_call, faccept_call), prote.c (festart), protf.c (ffstart), protg.c (fgstart), prott.c (ftstart): no need to pass fmaster as a separate argument to protocol start routine. * protf.c (ffawait_ack, ffawait_cksum): don't try to resend if we don't have a file. Wed Jul 8 14:28:23 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/srmdir.c (fsysdep_rmdir), unix/walk.c (usysdep_walk_tree): cast to char * to avoid warning. * cu.c (main): don't compare boolean to NULL. * unix/serial.c (isblocksigs), unix/signal.c (usset_signal): use extra parens to avoid bug in SCO 3.2.2 sys/signal.h header file. * sysh.unx: always define struct ssysdep_tcp, for the benefit of systems for which HAVE_TCP is 0. * MANIFEST, Makefile.in, unix/Makefile.in, uuconf/Makefile.in, lib/Makefile.in: updated automatic distribution code for multiple directories. * unix/cusub.c, unix/serial.c: don't clobber CR when using TERMIO or TERMIOS, and default MIN to 1 to the convenience of cu. * Makefile.in, uucp.h, system.h, prot.h, trans.h, uucico.c, trans.c, send.c, rec.c, xcmd.c, prot.c, protg.c, protf.c, prote.c, prott.c, log.c, file.c, unix/opensr.c, unix/work.c: rewrote file transfer internals to support bidirectional transfers. Keep queue of jobs to do, and support connections. Added new files trans.h, trans.c, send.c, rec.c, xcmd.c, and removed old file file.c. Mon Jun 29 15:14:15 1992 Ian Lance Taylor (ian@comton.airs.com) * Makefile.in: Stephen J. Walick: copy uustat.1 to uustat.$(manext), not uucp.($manext). Also try to create $(infodir). * chat.c (fcsend, fcprogram): check for NULL return from uuconf_callout. Thu Jun 18 22:37:28 1992 Ian Lance Taylor (ian@comton.airs.com) * configure.in, Makefile.in: updated to autoconf 0.118. Wed Jun 17 14:22:11 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/serial.c (fsserial_init): add /dev if necessary to device as well as to port name. * cu.c (main): set zdevice to NULL when faking line. * cu.c (main), uucp.c (main), uux.c (main), uuxqt.c (main): don't call zsysdep_localname until we've called usysdep_initialize. Tue Jun 16 17:42:50 1992 Ian Lance Taylor (ian@comton.airs.com) * unix/signal.c (usset_signal): set SA_INTERRUPT to force system calls to be interrupted on SunOS. Mon Jun 15 15:10:24 1992 Ian Lance Taylor (ian@comton.airs.com) * everything: integrated uuconf library. Split out lib and unix libraries. Made many changes, including defaults for port and dialer files, better handling of changed local name, better handling of HDB Permissions, new zbufalc routines to manage strings on the heap. Incorporated uuconv. Wed Jun 10 23:51:03 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/Makefile.in, uuconf/locnm.c, uuconf/llocnm.c, uuconf/hlocnm.c, uuconf/tlocnm.c: renamed uuconf_localname to uuconf_login_localname and added new uuconf_localname which doesn't need to read system information. Tue Jun 9 14:19:20 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/Makefile.in, uuconf/local.c: wrote uuconf_system_local. Mon Jun 8 14:14:30 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h: changed description of LOCKDIR, which now need not always be defined. * uuconf.h, uuconf/uucnfi.h, uuconf/lckdir.c, uuconf/iniglb.c, uuconf/tinit.c, uuconf/Makefile.in: added uuconf_lockdir, and ``lockdir'' command to config. Sat Jun 6 22:07:58 1992 Ian Lance Taylor (ian@comton.airs.com) * configure.in: updated to autoconf 0.115, added code to set LIBOBJS. * uuconf/Makefile.in, uuconf/uucnfi.h: removed references to routines now in lib/, changed to include regular UUCP header files. Fri Jun 5 15:31:29 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/uucnfi.h, uuconf/syssub.c, uuconf/uuconv.c: always set zpubdir for every system, changed uuconf_zpubdir to const char *. Wed Jun 3 15:15:32 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/Makefile.in, uuconf/deblev.c, uuconf/maxuxq.c, uuconf/pubdir.c, uuconf/spool.c: wrote uuconf_debuglevel, uuconf_maxuuxqts, uuconf_pubdir, uuconf_spooldir. * configure.in: updated to autoconf 0.114. * uuconf/tportc.c: default TCP ports to being fully reliable. Mon Jun 1 17:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/prtsub.c: removed uuconf_psysdep from uuconf_port. Sun May 31 00:07:40 1992 Ian Lance Taylor (ian@comton.airs.com) * uuconf.h, uuconf/Makefile.in, uuconf/diacod.c: wrote uuconf_dialcode. * uuconf.h, uuconf/Makefile.in, uuconf/logfil.c, uuconf/debfil.c, uuconf/stafil.c: wrote uuconf_logfile, uuconf_debugfile, uuconf_statsfile. * uuconf.h, uuconf/Makefile.in, uuconf/callin.c: wrote uuconf_callin. * uuconf/chatc.c, uuconf/time.c: Jean Mehat: only call tolower if isupper is true. * uuconf.h, uuconf/Makefile.in, uuconf/val.c, uuconf/tval.c: wrote uuconf_validate, uuconf_taylor_validate. Sat May 30 12:37:02 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, sys1.unx: changed zsysdep_local_name to zsysdep_localname, and made it fatal out rather than return NULL. * uuconf.h, uuconf/Makefile.in, uuconf/uucnfi.h, uuconf/iniglb.c, uuconf/rdlocs.c, uuconf/locnm.c, uuconf/tlocnm.c, uuconf/hlocnm.c: wrote uuconf_localname, uuconf_taylor_localname, uuconf_hdb_localname. * uuconf.h, uuconf/Makefile.in, uuconf/uucnfi.h, uuconf/iniglb.c, uuconf/tinit.c, uuconf/tsinfo.c, uuconf/hunk.c, uuconf/unk.c: wrote uuconf_system_unknown, uuconf_hdb_system_unknown, uuconf_taylor_system_unknown. * log.c, time.c: always include in uucp.h. * configure.in, conf.h.in: check for size_t, renamed checks for time_t. * configure.in, conf.h.in: check for . Fri May 29 00:03:05 1992 Ian Lance Taylor (ian@comton.airs.com) * sysinf.c (ztranslate_system): Jac Kersing: must xstrdup the argument, since it points to a buffer that will be reused. Thu May 28 12:42:20 1992 Ian Lance Taylor (ian@comton.airs.com) * sys3.unx (zsysdep_real_file_name): Ted Lindgreen: check return value of zstilde_expand. * copy.c, sys1.unx (usysdep_detach), sys2.unx (fsserial_close), sys3.unx, sys5.unx, sys7.unx: opening /dev/tty in usysdep_detach confuses the NeXT, so instead we just call TIOCNOTTY on 0. In fsserial_close we call TIOCNOTTY on the port before closing it, to make sure that we have ditched it under BSD. Also added O_NOCTTY to every open call other than opening a port, although there are still several fopen calls which should probably have it somehow. * system.h, uucico.c (fcall), uustat.c (fsquery_system, fsquery_show), sys3.unx (fsysdep_get_status), sys7.unx (zsysdep_all_status): Bob Izenberg: changed output of uustat -q to count number of commands rather than number of files being transferred, and to not report a non-existent status. Added pfnone argument to fsysdep_get_status, and changed all calls. * uucico.c, sys1.unx, sys2.unx, sys3.unx, sys5.unx, sys6.unx, sys7.unx: Rolf Nerstheimer: cast a bunch of arguments to open, creat, stat and chmod to avoid compiler warnings. * uucp.h, log.c (ulog), port.c (fport_close), prot.c (fgetcmd): Chip Salzenberg: don't log a SIGHUP signal while we're closing down the connection, since the other side might hang up faster than we do (we still react to it correctly, we just don't put it in the log file). * sys1.unx (usysdep_detach), tcp.c (ftcp_open): Petri Helenius: update the process ID we log after a fork. * Makefile.in, sys1.unx: Chip Salzenberg: changed LIBDIR to SBINDIR. * uucp.c (main, uccopy): Andreas Vogel: check local-receive of the correct system, rather than always using sLocalsys. * configure.in, conf.h.in, sys2.unx, tstuu.c: Rob Janssen: look for , and include it if it exists and we are using select. * protg.c: Rob Janssen: rearrange macros to avoid bug in XENIX compiler. * configure.in: Scott Blachowicz: check WIFEXITED before assuming HAVE_UNION_WAIT, to avoid problems on HP/UX. * configure.in, conf.h.in, sysh.unx, sys1.unx: John Theus: use sv_onstack instead of sv_flags in the sigvec structure on 4.2BSD. Wed May 27 23:23:39 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, sys2.unx (fsysdep_modem_no_carrier): Scott Reynolds: added HAVE_CLOCAL_BUG compilation parameter to work around problems on some serial ports. Tue May 26 15:50:17 1992 Ian Lance Taylor (ian@comton.airs.com) * uustat.c, uustat.1: added a bunch of options to support uuclean: -e, -i, -K, -M, -N, -W, -Q. * system.h, sys7.unx (fsysdep_privileged, fskill_or_rejuv): added fsysdep_privileged function. Thu May 21 13:30:21 1992 Ian Lance Taylor (ian@comton.airs.com) * uuxqt.c (uqdo_xqt_file): processing of execution file has to be case significant; this will change handling of "n" flag, which was not correctly handled before. Wed May 20 14:22:12 1992 Ian Lance Taylor (ian@comton.airs.com) * sys1.unx (usysdep_detach): close the statistics file when detaching. * policy.h, sys3.unx (fsdo_lock, fsdo_unlock), sys7.unx (fsysdep_lock_status): force LOCKDIR to always be defined. * uucp.h: put in an extern for alloca. * sysh.unx, sys1.unx, sys5.unx, sys6.unx: defined all the ?_OK macros in sysh.unx, which means that must be included before "sysdep.h" when they are both included. * sys2.unx (fsserial_set): corrected case in termio switch expression. * chat.c (fcsend): simplified expression for old compilers. * sys1.unx (rmdir): wrote rmdir replacement which invokes /bin/rmdir for old systems. * configure.in, conf.h.in, Makefile.in: updated for autoconf 0.112, added checks for ftw, ftw.h, and rmdir. * sys1.unx: added extern for ctime, removed externs for functions returning int, protected externs with ifndefs. * uucp.h, prot.h, system.h, uucico.c (fuucp), uuxqt.c (uqdo_xqt_file), prot.c (freceive_file), file.c (freceived_file), sys3.unx (fsysdep_move_file, fsysdep_change_mode), sys4.unx (zsysdep_save_temp_file): changed fsysdep_move_file to not set the file mode, and added fsysdep_change_mode to do it instead. * system.h, uucp.c (main, ucdirfile, uccopy), sys6.unx (usysdep_walk_tree, isdir, ftw, do_ftw): added -R option to uucp to recursively copy directories. Tue May 19 18:29:32 1992 Ian Lance Taylor (ian@comton.airs.com) * sys3.unx: changed zsysdep_in_dir to always append the filename to the directory, even if the directory did not already exist. * sysh.unx, sys1.unx, sys3.unx, sys4.unx, sys5.unx: renamed fsdirectory_exists to fsysdep_directory. Mon May 18 14:49:35 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, uucp.c (main), sys6.unx (zsysdep_uuto): added -t option to uucp to emulate uuto, wrote zsysdep_uuto to do Unix dependent destination translation for uuto, added -p option to uucp as synonym for -C for uuto compatibility. Sun May 17 22:04:09 1992 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgexchange_init): permit a second INITB to override the segment size given in the first INITB. Tue May 5 16:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (main, fdo_call), uucico.8: Chip Salzenberg: added -c option to uucico to not warn if invoked when the system may not be called. Tue Apr 28 15:05:01 1992 Ian Lance Taylor (ian@comton.airs.com) * sysh.unx, sys2.unx (fsserial_open, fsblock): preserve file status flags. * protg.c (fgwait_for_packet): Heiko Rupp: only send RJ packet if there are no unacknowledged packets. Mon Apr 27 18:56:42 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h: added several routines for cu. * cu.c, cu.h, sys8.unx: checked into RCS. * uux.c (main): Jose Manas: dumb bug when checking against calloc_args. Fri Apr 24 20:32:06 1992 Ian Lance Taylor (ian@comton.airs.com) * sys1.unx: changed HAVE_LONG_NAMES to HAVE_LONG_FILENAMES for new version of autoconf. * sys7.unx: check UTIME_NULL_MISSING with #if rather than #ifdef. * sys3.unx: check FS_* macros with #if rather than #ifdef. * uucp.h, sysh.unx: changed standard type definitions for new version of autoconf. * sysh.unx, sys1.unx, sys2.unx, tstuu.c: changed SIGtype to RETSIGTYPE for new version of autoconf. * sys1.unx, tstuu.c: make include of optional. * sys2.unx: get the right versions of major and minor. Wed Apr 22 11:19:11 1992 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgsenddata, fggot_ack): Michael Haberler: the slow start after error code was essentially shrinking the window size. * sysh.unx, system.h, sys1.unx (usysdep_initialize), uuchk.c, uucico.c, uucp.c, uulog.c, uuname.c, uustat.c, uux.c, uuxqt.c: changed usysdep_initialize to take a single argument with bit flags, added INIT_NOCHDIR as one of the flags. * uucp.h, log.c (ulog): added pfLstart and pfLend functions for ulog, so that cu can use them to restore the terminal settings. * bnu.c (ubnu_read_systems, fbnu_read_dialer_info), v2.c (uv2_read_systems): Michael Richardson: don't core dump if no chat script. Tue Apr 21 00:19:47 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (faccept_call): Chris Lewis: a successful call in should clear the number of retries. * sys2.unx (fsserial_set): set LLITOUT if going to CBREAK mode. * port.h, prote.c (festart), protf.c (ffstart), protg.c (fgstart), prott.c (ftstart), port.c (fport_set), sys2.unx (fsysdep_stdin_set, fsysdep_modem_set, fsysdep_direct_set, fsserial_set): gave fport_set independent control over output parity generation, input parity checking, and XON/XOFF handshaking, all to support cu. Mon Apr 20 11:47:23 1992 Ian Lance Taylor (ian@comton.airs.com) * port.h, uucico.c (fdo_call), port.c (fport_dial, fmodem_dial), tcp.c (ftcp_dial): added separate zphone argument to fport_dial to support cu. Thu Apr 16 01:15:42 1992 Ian Lance Taylor (ian@comton.airs.com) * bnu.c (ubadd_perm, ubadd_perm_alternate): Chris Lewis: handle a combination of Permissions entries which specify just LOGNAME with entries that specify both MACHINE and LOGNAME. Wed Apr 15 16:11:48 1992 Ian Lance Taylor (ian@comton.airs.com) * sys1.unx (usysdep_initialize, zsysdep_login_name): John Theus: don't die if can't get login name, unless it's really needed. Tue Apr 14 12:39:18 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (main, fcall): Petri Helenius: must relock system after detaching from terminal when trying different alternates. * system.h, uucico.c (fuucp), uustat.c (fsworkfiles_system, fsquery_system), sys4.unx (fsysdep_get_work_init, fsysdep_get_work): Marty Shannon: uustat would remove empty command files. * bnu.c (ubadd_perm_alternate): John Harkin: permit ALIAS in Permissions. * Makefile.in: John Harkin: add sys?.c dependencies to sys?.o to work around old makes which don't handle transitive .SUFFIXES. * sys2.unx: cast some function calls to void. * time.c (qttime_parse): cast to void warning. * sys1.unx (iswait): cast waitpid argument to avoid warning. * configure.in, policy.h, uucp.h, sys7.unx, tstuu.c: Zacharias Beckman: minor touchups for NeXT. * sys1.unx (usysdep_initialize), sys6.unx (zsysdep_add_cwd), uux.c (main): Jarmo Raiha: heuristic for whether to get the current directory can fail. * sys1.unx: pass argument to uudir, cast sigemptyset calls to void. * uucp.texi: Harlan Stenn: correct case of references. Tue Apr 7 01:02:17 1992 Ian Lance Taylor (ian@comton.airs.com) * Released version 1.03. Mon Apr 6 15:49:08 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (faccept_call): Marc Boucher: set *pqsys to NULL. * bnu.c (ubnu_read_systems, fbnu_find_port): Erik Forsberg: support multiple character modem classes. Fri Apr 3 00:37:25 1992 Ian Lance Taylor (ian@comton.airs.com) * sys2.unx: Petri Helenius: only clear known bits in termio or termios structure; didn't change HAVE_BSD_TTY handling--maybe next version. * configure.in: test TIMES_DECLARATION_OK correctly. * Makefile.in: update version to 1.03, remove distclean, add mostlyclean per GNU standards. * sys1.unx, chat.c: minor cleanups for gcc 2.1. Thu Apr 2 17:51:36 1992 Ian Lance Taylor (ian@comton.airs.com) * tstuu.c: conditionally declare times. * uucp.h, prot.c, sysinf.c, prtinf.c: added gcc 2.0 format checking to ulog, and fixed a few problems it discovered. Wed Apr 1 16:21:08 1992 Ian Lance Taylor (ian@comton.airs.com) * sys3.unx (esysdep_open_receive): David J. MacKenzie: some USG_STATFS systems use 512 as the block size of f_bfree, despite the existence of f_bsize. * port.c (fport_open): initialize stdin port. * policy.h, log.c: added CLOSE_LOGFILES configuration parameter. * sys2.unx: T. William Wells: handle a system without or . * configure.in: Franc,ois Pinard: warn if none of napms, nap, usleep, poll or select are available, since \p will sleep for a full second. * Makefile.in: Gerben Wierda: fixed uninstall to set file owner and mode correctly. Also changed install to handle uucp.info-4 and uustat.1. * MANIFEST: added uucp.info-4 and uustat.1. * uustat.1: Wrote. * uucico.8, uuxqt.8, uucp.1, uux.1: updated -x switch, cleaned up a bit. Tue Mar 31 14:40:06 1992 Ian Lance Taylor (ian@comton.airs.com) * sys1.unx (usysdep_initialize): use $PWD to get the current working directory if it's defined and correct. * sys1.unx (usysdep_initialize): Brian Antoine: use name from getpwname rather than getlogin. * uucp.texi: David J. MacKenzie: put in a number of corrections. Also split sys file and config file nodes, and rearranged several nodes. * protg.c (fgsenddata): Niels Baggesen: packet to retransmit did not get reset correctly. Mon Mar 30 10:03:28 1992 Ian Lance Taylor (ian@comton.airs.com) * tcp.c (ftcp_reset): Petri Helenius: TCP server never started uuxqt, because it exited in ftcp_reset. * policy.h, sysh.unx, sys2.unx (fsserial_lockfile): added HAVE_SVR4_LOCKFILES configuration parameter. * sys3.unx (esysdep_open_receive): Niels Baggesen: USG statfs has an f_bsize field. Sun Mar 29 23:04:20 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h, sysinf.c, prot.c, prote.c, protf.c, protg.c, prott.c: Niels Baggesen: added new debugging types abnormal and uucp-proto. * uucico.c (fuucp), prot.c (freceive_file), file.c (fstore_recfile): Dirk Musstopf: if a file receive fails before it starts, perhaps because the file was too large, remember to remove the temporary file. * sys2.unx (fsserial_lock, fsserial_open, fsserial_write, fsserial_io): always block and unblock the read and write descriptors together. Sat Mar 28 14:40:50 1992 Ian Lance Taylor (ian@comton.airs.com) * uustat.c: allow multiple systems and users to be specified at once; likewise for kills and rejuvenates. Allow old and young to be combined with systems and users. As suggested by Niels Baggesen, make machine status output more columnar. * uucp.h, uucico.c, config.c, sys3.unx: Michael I Bushnell: renamed enum tstatus to tstatus_type to avoid conflict with on some systems. * config.c, sysinf.c, prtinf.c, chat.c: David J. MacKenzie: allow backslash newline quoting in all TAYLOR_CONFIG configuration files. * chat.c (fchat): David J. MacKenzie: handle empty subexpect strings correctly. * uucico.c (main, fcall): Petri Helenius: must dump controlling terminal before going to next alternate. Also fixed David J. MacKenzie bug in which a signal did not prevent the next alternates from being tried. Also made sure qtime was always freed up. * uucp.h, uucico.c (fdo_call), sysinf.c (tialternate), uuchk.c (ukshow): Franc,ois Pinard: allow a name to be given to an alternate, and display the name when placing a call. * chat.c (fcprogram), port.c (fport_open, fport_close): David J. MacKenzie: send port device rather than port name to a chat program using \Y; make sure port device is reset if port open fails and when port is closed. * uucico.c (fuucp), log.c (ulog, ustats, ustats_close): close log and statistics file every time master and slave switch roles. Fri Mar 27 00:31:23 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (fdo_call): Mark Mallett: minor cleanup. * uuname.c (main): Franc,ois Pinard: output aliases, added -a switch. * uucico.8, uuxqt.8, uux.1, uucp.1: David J. MacKenzie: changed .TP5 to .TP 5; also updated to 1.03. * tstuu.c: Roberto Biancardi: if SIGCHLD is not defined, define it as SIGCLD. * config.c: David J. MacKenzie: cMaxuuxqts is independent of HAVE_TAYLOR_CONFIG. * uucp.h: Gerben Wierda: don't always declare bzero. * sys7.unx (ussettime, fsysdep_lock_status): Niels Baggesen, Gerben Wierda: minor patches. * sys2.unx: Gerben Wierda: minor cleanups. * uucp.h: Niels Baggesen: simplified debugging message macros to avoid broken compilers. * sys2.unx: don't use TIOCEXCL locking. * sys2.unx: rework HAVE_UNBLOCKED_WRITES == 0 to work even if writes are unblocked. Correct initialization of fwrite_blocking. * Makefile.in, configure.in: David J. MacKenzie: various cleanups. Changed default newconfigdir definition. Supported compilation in a different directory. Used symbolic links if available. Changed default infordir definition per Franc,ois Pinard. * policy.h: David J. MacKenzie: various cleanups. Thu Mar 26 12:17:41 1992 Ian Lance Taylor (ian@comton.airs.com) * sys3.unx: reduced race condition in fsdo_lock. * sys1.unx: Gerben Wierda: various cleanups. Also don't set sa_flags to SV_INTERRUPT per Chip Salzenberg. Wed Mar 25 22:20:24 1992 Ian Lance Taylor (ian@comton.airs.com) * configure.in: Overhauled for readability and functionality as suggested by T. William Wells and others. Added bug checks, including for SCO memmove and ftime. Tue Mar 24 12:18:56 1992 Ian Lance Taylor (ian@comton.airs.com) * sysinf.c (uiread_systems): fixed handling of alternates in file-wide defaults. Wed Mar 18 01:01:25 1992 Ian Lance Taylor (ian@comton.airs.com) * config.c (tprocess_one_cmd): handle CMDTABTYPE_FULLSTRING correctly if there are no arguments. * Released beta version 1.03 * sys1.unx (usysdep_detach): open the controlling terminal in non delay mode since it might be a modem. Tue Mar 17 00:01:53 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (fdo_call, faccept_call): T. William Wells: set current time in status file when call completes. * sys1.unx (iswait), sys2.unx (fsserial_read, fsserial_write, fsserial_io): log signals when they occur, even if we continue some sort of loop, rather than waiting for the next ulog call. * sys2.unx (fsserial_lock, fsserial_open): don't block when opening the write descriptor. Mon Mar 16 00:14:43 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, uuxqt.c (uqdo_xqt_file), sys5.unx (fsysdep_execute): pass command to fsysdep_execute as first element of argument array. * tcp.c: declare _exit. * uucp.h: move definition of const before use for non ANSI C. * uucp.h, sys1.unx: undefine remove in uucp.h if the system does not have it to avoid conflict with macro definitions. * uucico.c, uuxqt.c, protf.c, prott.c, prote.c, config.c, chat.c, port.c, sys2.unx: miscellaneous cleanups. * tcp.c (ftcp_open): cast argument to bzero. * time.c (qtimegrade_parse): cast argument to qttime_parse to long. * file.c: changed iRecmode to unsigned int. * configure.in, uucp.h: on SCO 3.2.2 sig_atomic_t is defined in but not . * sys1.unx: undefined remove before the function definition to avoid trouble on systems for which it is a macro. * Makefile.in: removed dependencies of getopt.o. * sys1.unx, sys7.unx, tstuu.c: adjusted external declarations. * getopt.h, getopt.c: get new versions from glibc 1.01. * sys1.unx: don't declare sigemptyset. * version.c: updated to beta 1.03. * chat.c (fcsend): Scott Ballantyne: go ahead and send a character for an illegal escape sequence rather than failing out. * uuxqt.c (uqdo_xqt_file), sys5.unx (zsysdep_find_command): cast result of alloca. * protg.c (fgprocess_data): Niels Baggesen: improved debugging information. Also tweaked fgprocess_data code to use memchr to find the next DLE rather than searching for it by hand. * uucico.c (faccept_call, fuucp): accept SVR4 -U flag giving maximum file transfer size; accept and ignore SVR4 -R flag meaning that the system supports file restart. Sun Mar 15 00:21:56 1992 Ian Lance Taylor (ian@comton.airs.com) * sysinf.c (titime, titimegrade): permit a retry time to be specified as an optional additional argument. * uucico.c (zget_uucp_cmd, zget_typed_line): turn off DEBUG_PORT when doing DEBUG_HANDSHAKE. * policy.h, sysh.unx, sys1.unx, sys2.unx (fsblock_writes, fsserial_write, fsserial_io): added configuration parameters HAVE_UNBLOCKED_WRITES and SINGLE_WRITE. Also blocked signals while clearing afSignal in fsysdep_modem_close. * chat.c (icexpect, fcsend): turn off DEBUG_PORT while doing chat script debugging. * sysh.unx, sys2.unx (fsserial_lock, fsserial_open, fsserial_write, fsserial_io, fsysdep_tcp_read, fsysdep_tcp_write, fsysdep_tcp_io): T. William Wells: some systems don't support unblocked writes, so don't use them. * port.c (fport_read, fport_write): show calls to fport_read and fport_write under DEBUG_PORT. * bnu.c (fbnu_find_port): Scott Ballantyne: accept "Any" as a Device speed. Sat Mar 14 20:52:11 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h, system.h, sysh.unx, uucico.c (main, zget_typed_line), uuxqt.c (main), uucp.c (main), uux.c (main, uxcopy_stdin), tcp.c (ftcp_open), log.c (ulog, ulog_close), sys1.unx (ussignal), sys2.unx (fsserial_close, fsysdep_modem_end_dial, fsserial_read, fsserial_write, fsserial_io, fsysdep_tcp_read, fsysdep_tcp_write, fsysdep_tcp_io): T. William Wells and Chip Salzenberg: keep an array of signals so that a new signal doesn't obliterate our knowledge of an old signal. Johan Vromans: if we get SIGINT continue the current session but don't start any new ones. * sysh.unx, sys1.unx (isspawn, espopen, iswait, fsysdep_mail, fsysdep_run, getcwd, mkdir), sys2.unx (fsrun_chat), sys3.unx (fsysdep_wildcard_start), sys5.unx (fsysdep_execute), sys7.unx (fsysdep_lock_status), uuxqt.c (uqdo_xqt_file), tcp.c (ftcp_open), tstuu.c (uchild): added function isspawn, espopen and iswait and channeled all execs of new processes and waits through them. Fri Mar 13 18:00:04 1992 Ian Lance Taylor (ian@comton.airs.com) * sysinf.c (uset_system_defaults): Chip Salzenberg: changed default login script timeout to 10 seconds. * prot.h, prot.c (freceive_data, breceive_char), protg.c, protf.c, prott.c, prote.c: changed breceive_char to go through freceive_data rather than calling fport_read directly. Added an freport argument to freceive_data, and change all old calls to pass it in as FALSE. Thu Mar 12 14:49:59 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h: added a padding byte to scmd structure, since at least one compiler needs it. * uucp.c (main): use fake local name (from ``myname'' command) when generating an execution request intended for the local system. * sysh.unx: corrected readdir prototype. * sys2.unx: moved local header files ahead of sleep routine determination. * General overhaul to change debugging system. Debugging is now done by type rather than by number. iDebug is now interpreted as a bit sequence. DEBUG may only be 0 (no checks or debugging), 1 (checks, no debugging) or 2 (checks and debugging). The debugging names are parsed by idebug_parse and tidebug_parse in config.c. The debugging types are additive. Many source files changed. Inspired by Michael Richardson, Johan Vromans and Peter da Silva. Wed Mar 11 12:01:03 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, uuxqt.c (uqdo_xqt_file): Chip Salzenberg: support Internet mail addresses in uuxqt replies (added configuration parameter HAVE_INTERNET_MAIL to control this). * sys7.unx (fskill_or_rejuv): permit uucp user to delete any job. * uucp.h, system.h, sysh.unx, config.c, uuxqt.c (main, uqabort), sys5.unx (isysdep_lock_uuxqt, fsysdep_unlock_uuxqt), bnu.c (ubnu_read_sysfiles): Marty Shannon: added max-uuxqts command, along with support for BNU Maxuuxqts, to limit number of concurrent uuxqt processes. * chat.c (icexpect, fcsend), uucico.c (zget_uucp_cmd, zget_typed_line): improved debugging by avoiding incredibly long lines. * system.h, sys5.unx (fsysdep_execute), uuxqt.c (uqdo_xqt_file): Jon Zeef: if a temporary failure occurs, retry the execution later. Tue Mar 10 12:40:30 1992 Ian Lance Taylor (ian@comton.airs.com) * sysh.unx, sys1.unx (isfork), sys2.unx, sys5.unx, tcp.c: Franc,ois Pinard: retry fork several times before giving up. * uucp.h, prot.c (fploop, fgot_data), file.c (usendfile_error, urecfile_error, frecfile_rewind): Niels Baggesen: if we can't read or write a file, treat it as a temporary error rather than a permanent error; if we get an error on write, drop the connection rather they try to continue. * uucp.h, system.h, sysh.unx, uucico.c (fuucp), prot.c (fsend_file, freceive_file), file.c (fsent_file, usendfile_error, freceived_file, urecfile_error, fmail_transfer), sys1.unx (usmake_spool_dir), sys4.unx (zsysdep_save_temp_file): if a file send fails, save the file away rather than lose it forever. * uucico.c (main): don't run uuxqt if we got a SIGTERM. * tcp.c (ftcp_open): Petri Helenius: have server fork twice to avoid zombies. * port.h, prtinf.c, v2.c, bnu.c (fbnu_find_port), uucico.c (fdo_call, faccept_call), uuchk.c (fkshow_port): added protocol command for ports, mostly to support BNU. Also modified uuchk to make the absence of any matching port or dialer more obvious. * sys3.unx (esysdep_open_receive): check size of destination file system as well as temporary file system; handle f_bsize field under FS_MNTENT. * configure.in, sysh.unx: test for including and in the same file, setting new configuration parameter HAVE_TERMIOS_AND_SYS_IOCTL_H accordingly; handle it in sysh.unx. Mon Mar 9 00:06:12 1992 Ian Lance Taylor (ian@comton.airs.com) * sys2.unx (fsserial_close): Franc,ois Pinard: sleep for a second after closing the serial port to give it a chance to settle. * sysh.unx (fsetterminfodrain), sys2.unx (fsserial_close, fsserial_reset, fsserial_set): wait for terminal output to drain before closing it, resetting it, or changing its parameters. * uucico.c (zget_uucp_cmd): Ted Lindgreen: strip parity bit from initial handshake strings. * system.h, sys3.unx (esysdep_open_send), uucico.c (fuucp): Ted Lindgreen: don't send a mail message if a file to send has been removed, since it might have been sent in a previous session. * uuchk.c (ukshow): Zacharias Beckman: put list of permitted programs and execution path on separate lines. * uucico.c (fdo_call, faccept_call): only look for hangup string in debugging mode, since there's nothing to be done with it anyhow. * uucico.c (faccept_call): Ted Lindgreen: report the minimum transfer grade requested during an incoming call in the log file. * uucp.h, uutime.h, config.c, uucico.c (fcall), time.c (ftimespan_match, btimegrade, cmax_size_now): added a new status type for ``wrong time to call''. If a system can never be called, this status type is not used (if an attempt is made to call the system, the status is left unchanged). Sun Mar 8 11:41:45 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (main, flogin_prompt, faccept_call): Ted Lindgreen: if we were asked to call a single system, or if a single system called in, then start uuxqt with -s for just that system. * uucico.c (main): Ted Lindgreen: ignore the -u option. * tstuu.c: Ted Lindgreen: don't include if it's not there. Also removed the ``ignore this error'' message from the chat scripts since it's no longer marked as an error. * sys2.unx (fsserial_set): Ted Lindgreen: if CRTSCTS is defined and turned on, then don't turn on IXOFF. * uucp.h, log.c, uucico.c (fdo_call, faccept_call): Ted Lindgreen: report the port name and (for incoming calls) the login name in the log file. Sat Mar 7 10:00:47 1992 Ian Lance Taylor (ian@comton.airs.com) * port.h, prtinf.c, sys2.unx (fsserial_lockfile, fsserial_lock): Peter da Silva: added ``lockname'' command to ports to permit specification of the file name to use when locking. * sys1.unx (usysdep_detach): let setpgrp fail silently. * sys2.unx: always include if it's present on the system. * time.c (btimegrade, cmax_size_now): removed extraneous semicolons. * sys2.unx (fsserial_lock, fsserial_open, fsserial_close): support TIOCEXCL locking. * sys2.unx (fsserial_open): preserve unknown bits in c_cflag when using HAVE_SYSV_TERMIO or HAVE_POSIX_TERMIOS. * prot.h: never included more than once. Fri Mar 6 21:53:28 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h: Eric Ziegast: some systems don't define EXIT_SUCCESS or EXIT_FAILURE in stdlib.h. * uucp.h, uutime.h, uucico.c (fuucp), sysinf.c (uinittimetables, uaddtimetable), uuchk.c (main, ukshow_size, ukshow_time, qcompress_span), time.c (all new): rewrote time routines completely for consistency and simplicity. Fixed bug causing incorrect maximum possible transfer size. Added new file uutime.h. Wed Mar 4 10:06:13 1992 Ian Lance Taylor (ian@comton.airs.com) * sys2.unx (fsserial_lockfile, fsserial_lock, fsysdep_modem_open, fsysdep_direct_open, fsysdep_modem_close, fsysdep_direct_close): Petri Helenius: if the open failed on a serial port, the lock files were not removed. * config.c (igradecmp): the local variables in igradecmp have to be integers; signed characters might not work correctly (although they would in all normal cases). * sys4.unx (fsysdep_has_work): Johan Vromans: set *pbgrade correctly if we still have work left over that we haven't looked at yet. * tstuu.c (main, uchoose, fwriteable): Roberto Biancardi: use poll if we haven't got select. * uucico.c (zget_uucp_cmd): Michael Haberler: some systems send \n after Shere, rather than a null byte. Tue Mar 3 01:03:22 1992 Ian Lance Taylor (ian@comton.airs.com) * uuxqt.c (main, uqdo_xqt_file): permit local executions, don't get grade out of system dependent file name. * sys4.unx (fsysdep_get_work): Bob Denny: warn if we can't open a command file. * v2.c (uv2_read_systems): Jeff Putsch: infinite loop when reading time string. * uucp.h, sys1.unx, sys2.unx, sys3.unx, tstuu.c, configure.in: Thomas Fischer: some NeXT compatibility stuff: removed externs of sleep and alarm, included in uucp.h. * uucp.h, port.h, uucico.c (zget_uucp_cmd, zget_typed_line), port.c (cdebug_char, udebug_buffer), chat.c (icexpect, fcsend, fcphone), log.c (ulog): Michael Richardson: added LOG_DEBUG_START, LOG_DEBUG_CONTINUE and LOG_DEBUG_END to allow a debugging line in the log file to be built character by character. Used this new feature in chat script debugging, rather than having each character appear on a separate line. Added fPort_debug variable to control port debugging. * uustat.c (fsquery, fsquery_system, fsquery_show): handle execution files queued up for the local system correctly when using -q option (they still don't show up on any other option). * uucp.texi, protg.c (fgstart, fgshutdown): Aleksey P. Rudnev: added remote-window and remote-packet-size 'g' protocol parameters. Reset the parameters to their default values in fgshutdown. * sysh.unx, sys2.unx (fsserial_read, usalarm), sys1.unx (usset_signal, usysdep_detach), uucico.c (main): overhauled fsserial_read yet again. The timeout passed in is now an absolute bound. A special SIGALRM handler does some wierd stuff to avoid any possible race. * config.c (uread_config), sysinf.c (uiread_systems, fcallout_login, fcheck_login), prtinf.c (ffind_port, fread_dialer_info), chat.c (fctranslate), uucico.c (faccept_call): T. William Wells: when using HAVE_TAYLOR_CONFIG in combination with V2 or BNU configuration files, don't complain if the HAVE_TAYLOR_CONFIG files are missing. Mon Mar 2 10:21:36 1992 Ian Lance Taylor (ian@comton.airs.com) * sys2.unx (fsserial_read): T. William Wells: don't arbitrarily extend read timeout. * uux.c (main): check iSignal before entering fread, since the user may have hit ^C earlier in the program. Sun Mar 1 23:39:33 1992 Ian Lance Taylor (ian@comton.airs.com) * policy.h, uucp.h, sysh.unx, sys2.unx (fsserial_lock, fsysdep_modem_close, fsysdep_direct_close), util.c (strlwr), configure.in: Marc Unangst: added HAVE_SCO_LOCKFILES configuration parameter to force lock file names to lower case. Fri Feb 28 00:07:12 1992 Ian Lance Taylor (ian@comton.airs.com) * system.h, uucico.c (faccept_call, fdo_xcmd), uuxqt.c (uqdo_xqt_file), uux.c (main), uucp.c (main, ucspool_cmds), sys3.unx (zsysdep_spool_cmds), uux.1, uucp.1: added -j switch to uucp and uux to display the jobid of the spooled job. * uucp.h, system.h, sysh.unx, uucico.c (fuucp, fdo_xcmd, fok_to_send, fok_to_receive), uuxqt.c (uqdo_xqt_files), uux.c (main, uxcopy_stdin), uucp.c (main), file.c (freceived_file), config.c (fin_directory_list), sys1.unx (fsysdep_file_exists, fsuser_access, fsysdep_in_directory), sys3.unx (esysdep_open_send, fsysdep_move_file), sys5.unx (fsysdep_xqt_check_file): Chip Salzenberg: recheck file access permissions before sending, to try to avoid symbolic link games. Check that the user has search access on all directories down to the file, and read or write access to the file or directory itself. Check in uucp and uux as well as uucico, to provide early messages. Check the standard input file in uuxqt. Be more careful about creating files in the spool directory. This eliminates all security problems I know of, except for a very short race in fsysdep_move_file. * sys3.unx (esysdep_open_send): give an error message if we try to send a directory (used to just fail silently). * system.h, sysh.unx, sys1.unx (usysdep_detach, ussignal, fsysdep_catch, usysdep_start_catch), sys2.unx (fsysdep_modem_end_dial, fsserial_read), uux.c (main): T. William Wells: fsysdep_catch obviously must be a macro, since it calls setjmp. Also TIOCNOTTY sets the process group to 0, so we don't have to fork before calling it. Thu Feb 27 00:08:09 1992 Ian Lance Taylor (ian@comton.airs.com) * sys1.unx, sys6.unx, sys7.unx: added some extern definitions. * configure.in, uucp.h, system.h, sysh.unx, uucico.c (main, ucatch, uabort, zget_typed_line, zget_uucp_cmd), uuxqt.c (main, uqcatch, uqabort), uux.c (main, uxcatch, uxrecord_file, uxabort), uucp.c (main, uccatch, ucrecord_file, ucabort), uustat.c (main, uscatch), uulog.c (main, ulcatch), uuname.c (main, uncatch), uucheck.c (main, ukcatch), log.c (ulog_fatal_fn, ulog, ulog_close), tstuu.c (main, uchild, uprepare_test), sys1.unx (usysdep_initialize, usysdep_detach, usysdep_signal, fsysdep_catch, usysdep_end_catch, ussignal, fsset_signal, fsysdep_run, raise), sys2.unx (usalarm, usysdep_pause, fsserial_lock, fsserial_open, fsysdep_stdin_close, fsysdep_modem_close, fsysdep_modem_end_dial, fsserial_read, fsserial_write, fsserial_io), sys5.unx (fsysdep_execute): T. William Wells: overhaul to support detaching from the terminal and completely reliable signals. uucico now calls usysdep_detach at various points; new option -D prevents detaching. The signal handling code all goes through usysdep_signal, fsysdep_catch and usysdep_end_catch. A signal now just sets iSignal, which is checked at various points, notably in the port routines and in the main loops in uucico and uuxqt. Tue Feb 25 10:59:23 1992 Ian Lance Taylor (ian@comton.airs.com) * protg.c (fgwait_for_packet): Bob Denny: reset the count of timeouts only when data is recognized, so that we aren't fooled by a sequence of imperfect echoes. * sys5.unx (zsysdep_get_xqt): Bob Denny: don't warn if opendir gets ENOENT. I think POSIX requires ENOTDIR, but what can you do? Mon Feb 24 14:37:10 1992 Ian Lance Taylor (ian@comton.airs.com) * uucico.c (main, uusage): don't treat an extra argument as a port name. * sys3.unx (esysdep_truncate): Roberto Biancardi: support F_CHSIZE and F_FREESP in esysdep_truncate. * configure.in, sys2.unx (fsserial_read, usysdep_pause): Roberto Biancardi: use poll to sleep less than a second if we haven't got anything else. * v2.c (uv2_read_systems, fv2_find_port), bnu.c (ubnu_read_systems, fbnu_find_port, fbnu_read_dialer_info), uustat.c (fsworkfile_show): Roberto Biancardi: skip spaces and tabs after doing a strtok ((char *) NULL, ""). * copy.c (fcopy_file), sys1.unx (esysdep_fopen), sys2.unx, sys3.unx (esysdep_open_receive, esysdep_truncate, fsdo_lock, fscmd_seq), sys5.unx (fsysdep_execute), sys7.unx, tstuu.c: John Theus: some systems use instead of . Also changed the code to call creat instead of open when appropriate. Should now work on V7, with the exception of O_NONBLOCK and O_NDELAY in sys2.unx and tstuu.c. * uucp.h: John Theus: if we don't have vprintf, ulog is defined without an ellipsis, so don't declare it with one. Sun Feb 23 14:45:53 1992 Ian Lance Taylor (ian@comton.airs.com) * uucp.h, system.h, bnu.c (ubnu_read_systems), config.c (fin_directory_list), sys1.unx (fsysdep_in_directory), sys5.unx (fsysdep_xqt_check_file), uucp.c (main), uuxqt.c (uqdo_xqt_file), uucico.c (fdo_xcmd, fok_to_send, fok_to_receive), tstuu.c (uprepare_test): only permit files to be received into directories that are world writeable. Check for this in fsysdep_in_directory, with a new argument. Changed calls appropriately. In tstuu create /usr/tmp/tstuu as world writeable. * bnu.c (ubadd_perm_alternate): Doug Evans: after all that, I got it wrong: WRITE only applies to remote requests. * uucp.h, uucico.c (fuucp, fdo_xcmd, fok_to_send, fok_to_receive), uuxqt.c (uqdo_xqt_file), uuchk.c (ukshow), sysinf.c (uset_system_defaults, tialternate), sys5.unx (fsysdep_xqt_check_file), bnu.c (ubadd_perm_alternate): fixed READ and WRITE handling to match BNU semantics. Added zcalled_local_send, zcalled_local_receive, zcalled_remote_send and zcalled_remote_receive fields to ssysteminfo structure for this, and handled them in all the appropriate places. Sat Feb 22 22:30:59 1992 Ian Lance Taylor (ian@comton.airs.com) * Complete overhaul of configuration to use automatic shell script. Eliminated conf.h, now generated by configure. Renamed Makefile to Makefile.in. Added policy.h for administrative decisions and other choices which can not be made automatically. Many changes to many source files, none having to do with code. Thu Feb 20 17:57:55 1992 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (fdo_call): Chip Salzenberg: some systems truncate the Shere= machine name to 7 characters. Wed Feb 19 14:36:31 1992 Ian Lance Taylor (ian at comton.airs.com) * sys7.unx (fskill_or_rejuv): make sure that only the submitter or the superuser is permitted to cancel (or rejuvenate) a request. * system.h, sysh.unx, sys3.unx (zsfile_to_jobid, zsjobid_to_file), sys4.unx (zsysdep_jobid), sys7.unx, uustat.c, Makefile, MANIFEST: wrote uustat. Changed CSEQLEN in sys3.unx from 5 to 4. Added several new system dependent functions, mostly in sys7.unx. * system.h, sys1.unx, log.c, file.c, chat.c, protg.c, uucico.c: rearranged the time functions for the convenience of uustat. Made isysdep_time take an optional pimicros arguments. Renamed usysdep_full_time to isysdep_process_time, and made clear that it need only work within a single process. Changed usysdep_localtime to take a time returned by isysdep_time rather than always use the current time. Changed the calls as appropriate. Tue Feb 18 14:03:19 1992 Ian Lance Taylor (ian at comton.airs.com) * uuxqt.c (main): pass fdaemon argument correctly to usysdep_initialize. Mon Feb 17 17:09:16 1992 Ian Lance Taylor (ian at comton.airs.com) * uuxqt.c (uqdo_xqt_file): T. William Wells: make sure sh uses absolute path of command, rather than relying on PATH. * sys5.unx (zsysdep_find_command): Michael Nolan: allow full command name to be specified by remote system, not just basename, if command is not in path. * log.c (ulog): don't use headers when outputting to terminal. * sys2.unx (fsrun_chat): Bob Denny: log chat program messages as LOG_NORMAL, not LOG_ERROR. Fri Feb 14 00:17:57 1992 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (ucatch), uuxqt.c (uqcatch): Neils Baggesen: under HAVE_BNU_LOGGING, don't lose the system name when dieing. * uulog.c, Makefile, MANIFEST: wrote uulog. * uuname.c, Makefile, MANIFEST: wrote uuname. * bnu.c (ubadd_perm_alternate): T. William Wells: must xstrdup the system name before calling uadd_validate. * log.c (ulog_close): Micheal Nolan: don't refer to eLdebug if the DEBUG configuration parameter is 0. * uucp.c (main): Niels Baggesen: abtname must be copied into memory, or it will be overwritten by the next file to be copied. Sun Feb 9 00:12:58 1992 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (fuucp), prot.c (fsend_file, freceive_file): Bob Denny: call fmail_transfer before calling fsysdep_did_work, because the latter frees up strings used by the former. * sysh.unx, sys1.unx (mkdir), uudir.c (new file), Makefile: added HAVE_MKDIR configuration parameter for systems without the mkdir system call. The emulation function in sys1.unx invokes the new suid program uudir which sets its uid to uucp and invokes /bin/mkdir. Added rules to create uudir to Makefile. Sat Feb 8 14:25:50 1992 Ian Lance Taylor (ian at comton.airs.com) * sysh.unx, sys1.unx (opendir, readdir, closedir), sys4.unx, sys5.unx: added HAVE_OLD_DIRECTORIES configuration parameter to support systems without opendir/readdir/closedir which use original Unix directory format. * sysh.unx, sys1.unx (dup2): added HAVE_DUP2 configuration parameter and dup2 emulation function. * sys1.unx (zsysdep_local_name): put utsname structure on stack rather than making it static. * sysh.unx, sys1.unx (usysdep_initialize, getcwd): if we have neither getcwd nor getwd, fork /bin/pwd to get the current working directory. * system.h, uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), uuchk.c (main), sys1.unx (usysdep_initialize), sys6.unx (fsysdep_needs_cwd, zsysdep_add_cwd): because getting the current working directory can be expensive on Unix, since some implementation of getcwd fork a shell to execute pwd, only try to get the cwd if it is going to be needed by uux or uucp. * uucico.c (main), uuxqt.c (main), uux.c (main), uucp.c (main), uuchk.c (main), log.c (ulog): handle all possible signals raised by abort, namely SIGABRT, SIGILL and SIGIOT. In ulog always call abort rather than raise (SIGABRT). * sys4.unx (usysdep_get_work_free): the qSwork_file information was freed up incorrectly if a file transfer failed. * sysh.unx, sys2.unx: Archaic Zilog System III computers use setret and longret rather than setjmp and longjmp, so I added a HAVE_SETRET configuration option. * prott.c (ftstart, ftsenddata): shifts of integers by more than 15 are not portable. * prot.c (fsend_file, freceive_file, fploop, fgot_data): I ran into an old compiler which couldn't handle the calls to pffile, so I simplified them to use a variable. * port.c (fmodem_dial): cast result of alloca. * getopt.h, getopt.c: Jay Vassos-Libove: renamed getopt and related variables by macro defining them to gnu_*. This avoids conflicts with system header files and system libraries. Fri Feb 7 12:08:42 1992 Ian Lance Taylor (ian at comton.airs.com) * everything: added HAVE_STRING_H and HAVE_STRINGS_H. Removed include of in every source file and put it in uucp.h. Since I had to change everything anyhow, added 1992 to the copyright date. * uucico.c (fcall): Bob Denny: retry time not reached is not really an error, so just make a normal log entry for it. Sun Feb 2 01:38:47 1992 Ian Lance Taylor (ian at comton.airs.com) * uucp.c (main): Get the file name for the destination of a local copy using zsysdep_real_file_name rather than zsysdep_in_dir, since the latter doesn't get the basename of the argument. * sys3.unx (fsysdep_get_status): Niels Baggesen: cast enum to int before comparison. * system.h, uucp.c (main), uux.c (main), sys6.unx (fsysdep_access, fsysdep_daemon_access): Niels Baggesen: check user access to file since programs are running setuid. Previously uucp and uux permitted a file readable only by uucp to be transferred to another system by user request! * chat.c (fchat): Michael Nolan: portions of a chat string might be separated by more than just a single space if they are read from a V2 or BNU configuration file. Fri Jan 31 19:51:57 1992 Ian Lance Taylor (ian at comton.airs.com) * protg.c: Chip Salzenberg: change default window size to 7. * sys3.unx (fsdo_unlock): Michael Nolan: cast result of alloca to (char *), not that it really matters. * log.c (ulog): Michael Nolan: if SIGABRT is not defined, just call abort. Thu Jan 30 18:19:33 1992 Ian Lance Taylor (ian at comton.airs.com) * bnu.c (ubadd_perm): Michael Nolan: debugging check was done wrong for entry with LOGNAME but no MACHINE. Wed Jan 29 13:28:59 1992 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (zget_uucp_cmd): Patrick Smith: only wait a short time for the hangup string. * sys4.unx (iswork_cmp): Patrick Smith: fixed casts to not cast away const. Tue Jan 28 11:06:34 1992 Ian Lance Taylor (ian at comton.airs.com) * sys1.unx, sys3.unx, tstuu.c: Jay Vassos-Libove: removed some declarations of system functions that conflict with system header files on BSD/386 alpha. * Makefile: Jeff Ross: make sure the uninstall target restores the original file owner and mode. * protg.c (fgsendcmd): the previous patch wasn't really correct. Mon Jan 27 22:30:47 1992 Ian Lance Taylor (ian at comton.airs.com) * log.c (ustats): Marty Shannon: don't report a failed transfer under USE_BNU_LOGGING. * sys3.unx (zsysdep_real_file_name): Marty Shannon: a trailing '/' on the name means that it is a directory, even if the directory does not already exist. * uucico.c (fuucp): Marty Shannon: the -f flag indicating that directories should not be created was not being handled correctly. * uucico.c (fcall): Chip Salzenberg: set .Status correctly if wrong time to call. * protg.c (fgsendcmd): John Antypas: didn't handle null byte at end of command which was exactly a power of two in length correctly. Tue Jan 21 14:37:10 1992 Ian Lance Taylor (ian at comton.airs.com) * Released version 1.02. * system.h, uucico.c (main), uux.c (main), uucp.c (main, zcone_system), sys1.unx (fsysdep_run): Chip Salzenberg: have uucp and uux start up uucico -s system rather than uucico -r1. Mon Jan 20 11:45:38 1992 Ian Lance Taylor (ian at comton.airs.com) * sys1.unx (fsysdep_make_dirs): don't try to create a directory with no name. * version.c: change version number to 1.02. * uucico.8, uuxqt.8, uucp.1, uux.1: change version number to 1.02. * MANIFEST: removed texinfo.tex; it's twice the size of any other file, so I think it's just to large to distribute. * uucico.c (fcall, fdo_call): Marty Shannon: update the time in the .Status file if it's the wrong time to call, and upon receiving a call. Sun Jan 19 13:29:23 1992 Ian Lance Taylor (ian at comton.airs.com) * protg.c (fgsendcmd, fgsenddata): Dave Platt: if the remote UUCP accepts packets larger than 64 bytes, assume it can handle differing packet sizes, so if we have a small amount of data to send, use a small packet. Besides the two routines mentioned, also made minor changes to other routines to get the packet length out of the packet data rather than always assuming the same packet size. * conf.h, uucp.h: Matthew Lyle: some systems don't declare errno in , so I added HAVE_ERRNO_DECLARATION. * conf.h, uucp.h, util.c (bsearch): added HAVE_BSEARCH configuration parameter. Sat Jan 18 17:45:28 1992 Ian Lance Taylor (ian at comton.airs.com) * tstuu.c (utransfer): Mike Park: don't sleep when the input buffer is full; it's too slow. * Makefile: when making a distribution,change the mode of separate copies of the configuration files Makefile, conf.h and sysh.unx. * uucico.c (faccept_call): Marty Shannon: update .Status file on incoming calls. * uucp.h, prot.h, uucico.c (fuucp), prot.c (fsend_file, fpsendfile_confirm, freceive_file, fprecfile_confirm, fxcmd, ustats_failed), file.c (fsent_file, usendfile_error, freceived_file, urecfile_error, frecfile_rewind, fmail_transfer): reworked calls to fsydep_did_work and sending of mail messages to be more sensible. Now sends mail to requestor if request fails permanently and does not remove file if request fails only temporarily. Thu Jan 16 11:33:08 1992 Ian Lance Taylor (ian at comton.airs.com) * protg.c (fgsendcmd, fgsenddata): zero out unused bytes in short packets. * prot.c (zgetcmd), protf.c (ffsendcmd), prott.c (ftsendcmd), prote.c (fesendcmd): Niels Baggesen: added some debugging messages. * protg.c (fgsendcmd): corrected misspelling in debugging message. * log.c (ustats): Niels Baggesen: add FAILED to end of xferstats line if appropriate. * uuxqt.c (uqdo_xqt_file): Niels Baggesen: was checking strcmp return value incorrectly, so messages to other systems were not being sent. * sys2.unx, tstuu.c: Mike Park: ioctl is sometimes declared varadic, so we can't declare it. Wed Jan 15 02:03:43 1992 Ian Lance Taylor (ian at comton.airs.com) * sys1.unx: put \n at end of fsysdep_run error message. * sysh.unx, sys1.unx, sys2.unx, tstuu.c: Mike Park: on some systems includes but can only be included once; added HAVE_SYS_TIME_AND_TIME_H to sysh.unx. * tstuu.c: Mike Park: removed prototype for times since some systems don't have clock_t. * conf.h, sys2.unx, util.c: Mike Park: some systems don't have . Every macro used from it already had a check to make sure it was defined anyhow. * tstuu.c (uprepare_test): Mike Park: sh on NeXT interprets a leading ~, so we have to quote the argument to system(3). Incredible. * conf.h, uucp.h: Mike Park: if HAVE_ALLOCA is 0 when compiling with gcc, don't define alloca as a macro. This will let the NeXT define it in some header file. * sysh.unx, sys2.unx, sys5.unx, tstuu.c: Mike Park: handle HAVE_UNION_WAIT completely. Assume that system(3) returns an int which should be put into the w_status field. Define macros for union wait if they are not already defined. Move all this stuff into sysh.unx rather than duplicating it in three different files. * conf.h, uucp.h, sysh.unx, config.c, bnu.c, v2.c, uucico.c, uuxqt.c, uux.c, uucp.c, uuchk.c, Makefile: set directory to look for configuration files in in Makefile rather than in sysh.unx. This forced a number of changes, as now all new style configuration files are looked up using NEWCONFIGLIB. Old style configuration files are looked up using OLDCONFIGLIB. Mon Jan 13 00:35:43 1992 Ian Lance Taylor (ian at comton.airs.com) * sys3.unx: David Nugent: don't declare chmod, since it may be prototyped to take an argument that is smaller than an int. * uucico.c (faccept_call): Chip Salzenberg: only declare sportinfo if it will be used (if HAVE_TAYLOR_CONFIG is true). * sys3.unx (isysdep_get_sequence): Chip Salzenberg: avoid use before set warning from gcc. * protf.c (ffprocess_data): Chip Salzenberg: avoid use before set warning from gcc. * sysh.unx, sys2.unx (fsserial_read, usysdep_pause): Chip Salzenberg: added HAVE_USLEEP configuration parameter for the AIX usleep routine. * uuchk.c, prtinf.c, config.c: Chip Salzenberg: strcmp is a macro on AIX, so avoid declaring it and undef it in config.c where we want to declare it because we want to take its address. * uucp.h, sys3.unx (fsysdep_get_status, fsysdep_set_status): Chip Salzenberg: handle out of range status codes in status files. * Makefile, sysh.unx: defined LIBDIR in the Makefile, rather than forcing the user to define it in two different places. * sys.unx, tstuu.c: Chip Salzenberg: can't declare execl, since it is varadic. * sys1.unx, sys2.unx, sys3.unx, sys5.unx, tstuu.c: David Nugent: can't declare open or fcntl, since they may use ... in header file prototype; added declaration for popen; added casts of first mkdir argument to char *. * sysh.unx, tstuu.c (uchild): Mike Park: added HAVE_WAITPID and HAVE_WAIT4 configuration parameters to allow the use of wait4 as found on the NeXT. * tstuu.c (uprepare_test): Mike Park: use IPUBLIC_DIRECTORY_MODE rather than S_IRWXU | S_IRWXG | S_IRWXO. * sysinf.c (tisystem): Mike Park: ulog was being passed the wrong number of arguments. Sun Jan 12 14:32:47 1992 Ian Lance Taylor (ian at comton.airs.com) * Eliminated CONFIG, INSTALL and THANKS. They are now included in uucp.texi. Changed README and MANIFEST accordingly. Added uucp.info* and texinfo.tex to MANIFEST. * Makefile, uucp.texi: renamed taylor.texi to uucp.texi. * uucico.c (fcall, fdo_call): John Antypas: pass in sportinfo structure for fdo_call to use for an unknown port. * log.c (ulog): allocate enough bytes to name file if HAVE_BNU_LOGGING is in use but zLogfile has no %s. Sat Jan 11 12:11:56 1992 Ian Lance Taylor (ian at comton.airs.com) * Makefile: changed to correspond to GNU standards, according to standards.text of 24 Nov 91. * Makefile: Franc,ois Pinard: use $(INSTALL_PROGRAM) and $(INSTALL) rather than cp to install the programs. * time.c (ftime_now), sys1.unx (usysdep_localtime): John Antypas: use memcpy to get the result of localtime rather than relying on structure assignment. * sysh.unx, prtinf.c: Hannu Strang: changed definition of SYSDEP_STDIN_CMDS to pass structure instead of address of structure to avoid bug in AIX compiler which causes it to fail to recognize an address constant containing the -> operator. Tue Jan 7 10:22:43 1992 Ian Lance Taylor (ian at comton.airs.com) * Released beta 1.02. * protg.c (fgcheck_errors): discount out of order packets in the total error count, and allow a negative error count to mean that any number of errors are accepted. * sysinf.c (tadd_proto_param): Niels Baggesen: allocate number of protocol parameters based on *pc, not sIhold.cproto_params. Sat Jan 4 16:42:21 1992 Ian Lance Taylor (ian at comton.airs.com) * log.c (ulog): tweaked HAVE_V2_LOGGING slightly. * v2.c (uv2_read_systems): set chat script correctly. * uucp.h, sys3.unx: avoid redefining SEEK_SET if it appears in but not . * chat.c (fcsend): made fcsend into a static function. * uucp.h, uucico.c, uuxqt.c, uux.c, uucp.c, uuchk.c, version.c: changed abProgram and abVersion from const char [] to char [] because the Microsoft compiler on SCO can't handle const char [] arrays correctly. * uux.c (main): allocate enough space for log message. * sys1.unx (usysdep_localtime): to get the current time, we can't call usysdep_full_time if the latter uses times. * sys1.unx, sys3.unx: added a couple more extern definitions for SCO 3.2.2. * uucico.c (main): start uuxqt even if a call fails. * sysh.unx, system.h, uuxqt.c (uqdo_xqt_file), sys5.unx (fsysdep_xqt_check_file): Chip Salzenberg: added configuration option ALLOW_FILENAME_ARGUMENTS to permit arguments that look like filenames, to allow undoing the patch I just made. Fri Jan 3 00:44:59 1992 Ian Lance Taylor (ian at comton.airs.com) * system.h, uuxqt.c (uqdo_xqt_file), sys5.unx (fsysdep_xqt_check_file): David J. Fiander: make sure that if an argument looks like a filename we are permitted to access it. * sys3.unx (fsdo_lock): remove temporary file if link fails in fsdo_lock. Thu Jan 2 00:01:53 1992 Ian Lance Taylor (ian at comton.airs.com) * protg.c (fgstart, fgshutdown, fgprocess_data): count remote rejections separately from resent packets when counting errors. Tue Dec 31 14:31:38 1991 Ian Lance Taylor (ian at comton.airs.com) * protg.c (fgstart): Franc,ois Pinard: forgot to initialize cGdelayed_packets. * prot.h, uucico.c, prote.c: added the 'e' protocol, creating the new file prote.c * prot.c (freceive_data), protf.c (fffile), prott.c (ftfile): changed pffile protocol entry point to pass number of bytes being sent; fixed bug in freceive_data which caused to ask for the wrong number of bytes when the buffer was empty. Mon Dec 30 23:16:48 1991 Ian Lance Taylor (ian at comton.airs.com) * sys2.unx (fsserial_open): Chip Salzenberg: don't turn on IXON and IXOFF initially; after all, the initialization packets might contain an XOFF character. Sun Dec 29 00:00:42 1991 Ian Lance Taylor (ian at comton.airs.com) * uucp.h, prot.c (fploop): John Theus: check for EOF before reading from file to work around bug in Tektronix library. * protg.c (fprocess_data): don't send RR packets when an error occurs; the other side will probably ignore them, and it may confuse some Telebit modems. * sys1.unx (usysdep_localtime): don't take the address of a cast value. * log.c (zldate_and_time): wasn't allocating enough buffer space. Sat Dec 28 01:09:58 1991 Ian Lance Taylor (ian at comton.airs.com) * uuxqt.c (uqdo_xqt_file): forgot to initialize zmail. * uucp.h, time.c, copy.c, sys1.unx, sys2.unx, sys3.unx, sys4.unx, sys5.unx, config.c, log.c, uuxqt.c, uux.c, tstuu.c: added a bunch of externs to decrease the number of implicit function definitions. * system.h, sys1.unx (usysdep_localtime), log.c (zldate_and_time): Lele Gaifax: put the full year in the log file, using the format YYYY-MM-DD HH:MM:SS.HH (ending in hundredths of seconds). * config.c (uprocesscmds): Terry Gardner: allow a # to be quoted in a configuration file. Also made uprocesscmds reentrant. * sysh.unx, sys2.unx (fsrun_chat), sys5.unx (fsysdep_execute), tstuu.c (uchild): Monty Solomon: added HAVE_UNION_WAIT configuration option to pass a variable of type union wait to the wait and waitpid system calls. * sysh.unx, sys1.unx (usysdep_initialize): John Theus: added HAVE_GETWD to use getwd instead of getcwd. * sysh.unx, sys1.unx (usysdep_full_time): added HAVE_FTIME configuration option. * tstuu.c (uchild): use TIMES_TICK from sysh.unx rather than CLK_TCK. * conf.h, uucp.h, util.c, getopt.c, tstuu.c: added HAVE_STRCHR and HAVE_INDEX to conf.h. Fri Dec 27 01:00:41 1991 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (fuucp): set fmasterdone correctly when running as a slave. * port.c (cpshow, upshow, fport_read, fport_write, fport_io): cleaned up debugging code by isolating out upshow and by making cpshow handle backslash. * tstuu.c (uprepare_test): create spool directories by hand, to make sure test 6 can be done and to test creating needed directories. * conf.h, uucp.h, bnu.c, v2.c, chat.c, protg.c, prott.c, sysinf.c, tcp.c, getopt.c, tstuu.c, util.c: added HAVE_MEMFNS and HAVE_BFNS to conf.h. Changed memset calls to use bzero. * protg.c (fgcheck_errors, fgprocess_data): added protocol parameter ``errors'' to set maximum number of errors permitted. Also made fgprocess_data only reply once per batch of data. Thu Dec 26 17:54:54 1991 Ian Lance Taylor (ian at comton.airs.com) * tcp.c (ftcp_dial, itcp_port_number): Monty Solomon: cast arguments to avoid prototype errors on NeXT. Mon Dec 23 00:16:19 1991 Ian Lance Taylor (ian at comton.airs.com) * uucp.h, sysinf.c, uucico.c (main, flogin_prompt, faccept_call), uuchk.c (main): David Nugent: allow debugging level to be set for a specific system. Sun Dec 22 15:51:10 1991 Ian Lance Taylor (ian at comton.airs.com) * conf.h, uucp.c, sysh.unx, tcp.c, sys1.unx, sys2.unx, sys3.unx, sys5.unx, sys6.unx, tstuu.c: Monty Solomon: added HAVE_UNISTD_H to conf.h for systems which don't have . Also added externs for all functions from , which required adding definitions for pid_t, uid_t and off_t to sysh.unx. * config.c, prtinf.c, time.c, uuchk.c: added externs for strcasecmp or strncasecmp, to avoid implicit function definitions now that I took the prototypes out of uucp.h. * sys3.unx (fsysdep_get_status): Franc,ois Pinard: the code added to avoid scanf had a stupid bug. * uucp.h: Monty Solomon: removed prototypes for strcasecmp and strncasecmp from uucp.h, since they may be in string.h. Sat Dec 21 16:04:58 1991 Ian Lance Taylor (ian at comton.airs.com) * uucp.h, uucico.c (ucatch), prot.c (fpsendfile_confirm, fprecfile_confirm, ustats_failed), file.c (fsent_file, freceived_file), log.c (ustats): Terry Gardner: record failed file transfers in the statistics file. * uucico.c: change protocol ordering to 't', 'g', 'f'. * uucico.c (faccept_call), tstuu.c (uprepare_test): John Theus: don't warn if the port file doesn't exist when the slave mode uucico looks up the port. * sys1.unx, sys5.unx: moved fsysdep_file_exists from sys5.unx to sys1.unx so that uucico can call it. * uux.c: Fran,cois Pinard: remove parentheses from ZSHELLSEPS so that they may be used to quote arguments as documented. This means that may not be used to start subshell, but that is no great loss. * uux.c (main): use ulog to report illegal grade error message. * sys1.unx (fsysdep_run): use the real program name from abProgram in the error messages in fsysdep_run. Thu Dec 19 19:02:28 1991 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (fdo_call, faccept_call): Terry Gardner: put the length of the conversation in the ``Call complete'' log file message. * uux.c: added space and tab to ZSHELLSEPS, because otherwise the command was parsed to include whitespace. * protg.c, protf.c: Oleg Tabarovsky: added statistical logging messages to the 'g' and 'f' protocols. These go to the main log file right now, but I'm not sure if that's appropriate. * sys2.unx (fsserial_set): don't change terminal settings if we don't have to. * port.c (fport_io): add complete diagnostics for fport_io so we can see every byte that goes in or out. * uucico.c (fuucp): don't give user name in errors produced by getting the next command. * uuxqt.c (main): don't process execute files for unknown systems. This is not unreasonable, I hope, and it avoids errors caused by an uninitialized sUnknown structure. * sys4.unx (fsysdep_get_work_init): sort the previously found files all together so we can correctly check new files using bsearch. * protf.c (pfprocess, pfprocess_data, pfwait): Franc,ois Pinard: don't kill 'f' protocol because of an illegal byte. Also slightly optimized the protocol to wait for up to seven characters at a time rather than just one. Wed Dec 18 00:12:42 1991 Ian Lance Taylor (ian at comton.airs.com) * sysh.unx, sys2.unx, tstuu.c: Terry Gardner: added USE_FOR_UNBLOCKED configuration parameter to support systems that don't permit O_NONBLOCK and O_NDELAY to both be set. * tstuu.c (uchild): give the uucico processes a chance to die on their own rather than killing them immediately. * uuxqt.c (main, uqdo_xqt_file): David Nugent: keep rescanning the list of execute files until nothing can be done. Also, don't remove the execute file if we get some sort of internal error. * sys4.unx (fsysdep_get_work, usysdep_get_work_free): David Nugent: after we've processed all the work files we found initially, rescan the work directory to pick up any that may have come in in the meantime. Also, reset iSwork_file to 0 in usysdep_get_work_free so that we can handle more than one system. * tstuu.c, uucico.c (main, fwait_for_calls, flogin_prompt): added -l option to uucico to prompt for the login name and password once and then exit. Tue Dec 17 00:24:41 1991 Ian Lance Taylor (ian at comton.airs.com) * uucp.h, uucico.c, uuxqt.c, uux.c, uucp.c, config.c (uread_config), log.c (ulog): eliminated ulog_program and added abProgram and ulog_to_file. Made log messages output to stderr more Unix like. * log.c (ulog): use a fixed number of fields in a log file message by replacing a missing system or user with '-'. * port.h, chat.c (renamed fchat_send to fcsend), bnu.c (fbnu_read_dialer_info), prtinf.c (tpcomplete), sys2.unx (fsysdep_modem_close), uuchk.c (ukshow_dialer): T. William Wells: change the modem complete and abort strings into chat scripts. * sys2.unx (fsserial_open): on BSD start in RAW mode to avoid dropping characters when we switch over. I originally thought being able to use XON/XOFF was worth the risk; I no longer think so. * tstuu.c (uprepare_test): have shell script sleep before printing the login name to make sure the second system has finished flushing its input buffer. * protg.c (fginit_sendbuffers), prott.c (ftsendcmd): David Nugent: avoid sending confidential information by zeroing out memory buffers before using them. * sysinf.c (tirequest, titransfer), prtinf.c (tpseven_bit, tpreliable, tpdtr_toggle): Marc Unangst: several functions did not accept true and false as boolean strings, contradicting the documentation. * uucp.h, system.h, sysh.unx, sys1.unx (usysdep_full_time), file.c (fstore_sendfile, fsent_file, fstore_recfile, freceived_file), log.c (ustats): generate statistics in microseconds instead of seconds for more accurate time keeping. * sys2.unx (fsserial_open): David Nugent: flush pending input when a serial port is opened. This will clear out a NO\sCARRIER string left by a previous dropped connection. Mon Dec 16 11:26:17 1991 Ian Lance Taylor (ian at comton.airs.com) * uucico.c (main), uuxqt.c (main), tstuu.c (main, uchild): David Nugent: ignore SIGHUP in uucico and uuxqt, so that they are unaffected by the parent shell closing down and by the remote terminal dropping the connection. * bnu.c (ubnu_read_sysfiles, ubnu_read_systems, fbnu_find_port, fbnu_read_dialer_info): Mike Bernson: ignore lines that begin with whitespace, fix compilation error. Sat Dec 14 20:59:10 1991 Ian Lance Taylor (ian at comton.airs.com) * sys2.unx (fsserial_open): don't turn on ISTRIP initially. * uucp.h, sysinf.c, chat.c (icexpect), uuchk.c (ukshow_chat): added chat-seven-bit command to allow control over whether parity bits are stripped out of chat scripts. * uucp.h, port.h, chat.c (fchat, fcprogram), config.c (tprocess_one_cmd), prtinf.c, sysinf.c (tichat, tprocess_chat_cmd), bnu.c (fbnu_read_dialer_info), port.c (fpdo_dial), uucico.c (fdo_call, faccept_call) uuchk.c (ukshow_chat): changed processing of chat commands to go through tprocess_chat_cmd, avoiding repetition. All chat script information is now held in an schat_info structure. Eliminated the fchat_program function, renaming it fcprogram and making it static to chat.c (it is now called via fchat). Added CMDTABTYPE_PREFIX. Added INIT_CHAT macro to initialize chat script information. Added TTYPE_CMDTABTYPE and CARGS_CMDTABTYPE to eliminate hex constants in tprocess_one_cmd. * sys5.unx (zsysdep_get_xqt): Oleg Tabarovsky: don't stop processing files just because opendir failed on one; it could just be because we don't have read permission. Fri Dec 13 17:43:52 1991 Ian Lance Taylor (ian at comton.airs.com) * config.c (uprocesscmds): don't continually allocate and free the array of arguments. Thu Dec 12 12:46:01 1991 Ian Lance Taylor (ian at comton.airs.com) * prot.c (fgetcmd): Franc,ois Pinard: don't bother to give an error if the final HY doesn't come in; apparently the MtXinu UUCP doesn't send it. * chat.c (icexpect, fchat_send): Franc,ois Pinard: add some chat script debugging messages. * log.c (ulog): David Nugent: move ERROR: from the start of the line to after the date and time; this makes it easier to use awk on log files. * sys3.unx (fsdo_lock), sys1.unx (usysdep_initialize): do locking using link rather than O_CREAT | O_EXCL to avoid race conditions and to safely run as the superuser. * sys3.unx (fsysdep_move_file): fcopyfile now creates the destination file with IPRIVATE_MODE, so we don't need to chmod to it. * sys1.unx (usysdep_initialize, fsysdep_other_config): set the GID as well as the UID, in case anybody wants to run this as a setgid package. Wed Dec 11 10:03:22 1991 Ian Lance Taylor (ian at comton.airs.com) * conf.h, uucp.h, util.c (strtol): Mark Powell: added my own version of strtol to util.c, for systems which lack it. * protg.c (fgstart, fgexchange_init): if we start resending packets during initialization, don't forget which packets we have already seen; otherwise the other side may assume we've already seen them while we're looking for them. Tue Dec 10 15:42:41 1991 Ian Lance Taylor (ian at comton.airs.com) * conf.h, sysh.unx, log.c (ulog, ustats), tstuu.c (uprepare_test): Arne Ludwig: merged in Arne Ludwig's patches to support V2 and BNU style logging, with some minor additions and changes. * sys1.unx, sys3.unx, sys5.unx, uux.c, uucp.c, uucico.c, copy.c, uucp.h, system.h: create directories when necessary rather than assuming that they exist. Added fmkdirs argument to esysdep_fopen and fcopy_file, changing all calls. Added fpublic argument to fsysdep_make_dirs, changing all calls. Moved fsysdep_make_dirs and fsdirectory_exists from sys3.unx to sys1.unx. Added checks for ENOENT in several places in sys3.unx and sys5.unx. * log.c, port.c (fport_open), sys2.unx (fsserial_open): added ulog_device routine to record device name. This is currently only used for the BNU statistics file, but more uses might arise later. * file.c, log.c, uucp.h: moved statistics file routines from file.c to log.c in preparation for supporting BNU log file routines. Mon Dec 9 12:00:52 1991 Ian Lance Taylor (ian at comton.airs.com) * bnu.c (ubnu_read_systems): Arne Ludwig: the device entry for a system can be followed by a comma and a list of protocols. * sysh.unx, sys3.unx (fsdo_lock): Richard Todd: add HAVE_V2_LOCKFILES, in which the process ID is written out in binary. * uuxqt.c (uqdo_xqt_file): Richard Todd: the requestor address is relative to the requesting system. * config.c (uprocesscmds, umulti_pushback): Richard Todd: each line pushed back because of "#" is local to a particular smulti_file structure. * prtinf.c (asPdialer_cmds): Richard Todd: exit the current dialer if the special command "#" is seen. A similar thing should be put in for ports, but it's marginally more complex. * config.c (uprocesscmds): Richard Todd: don't warn if the special "#" command is unrecognized. Sat Dec 7 13:05:40 1991 Ian Lance Taylor (ian at comton.airs.com) * config.c (uprocesscmds): Franc,ois Pinard: don't limit the number of arguments to a command! * chat.c (fchat): handle a chat script which consists only of a single string. Fri Dec 6 16:11:29 1991 Ian Lance Taylor (ian at comton.airs.com) * sys5.unx (fsysdep_execute): David J. Fiander: if execve fails with ENOEXEC, try using /bin/sh with a quoted argument. * uux.c (main): split arguments the way /bin/sh does. If any shell metacharacters appears, request uuxqt to execute the command using /bin/sh. * tstuu.c (uprepare_test): allow the uux to test to send a failure message. * uuxqt.c (uqdo_xqt_file): don't send mail on successful execution unless specifically requested; pay attention to the 'n' line which requests mail on success; ignore the 'Z' line because it now specifies the default action. * sys1.unx (usysdep_initialize), sys6.unx (zsysdep_add_cwd): Franc,ois Pinard: getcwd may legitimately fail, so only give an error if we really need the result. * chat.c (ccescape): Franc,ois Pinard: ccescape should never return a negative number, since the callers don't know how to deal with that. Mon Dec 2 16:26:16 1991 Ian Lance Taylor (ian at comton.airs.com) * bnu.c (ubnu_read_systems): Dave Buck: time strings with grades were parsed in an endless loop! * sys3.unx (fsdo_lock, fsdo_unlock): the alloca when using LOCKDIR was one byte too small. * config.c (tprocess_one_cmd): pass 10 to strtol rather than 0 to avoid surprises if a leading zero is used. * prtinf.c (tpproto_param, tpdialer_proto_param): Niels Baggesen: the ``protocol-parameter'' command didn't work for ports or dialers. Sun Dec 1 09:46:12 1991 Ian Lance Taylor (ian at comton.airs.com) * tstuu.c: don't use the fd_set typedef at all. * tstuu.c (uprepare_test): don't read V2 or BNU configuration files while testing. * bnu.c, v2.c, config.c (uread_config): David Nugent: even if the code was compiled with HAVE_TAYLOR_CONFIG, read the V2 and BNU configuration files if the code was compiled to support them. * uuchk.c (fkshow_port): Bob Izenberg: report dialer/token pairs correctly. Sat Nov 30 17:40:00 1991 Ian Lance Taylor (ian at comton.airs.com) * tstuu.c: Bob Izenberg: copied over conditional definitions of EAGAIN and EWOULDBLOCK from sys2.unx. * bnu.c (fbnu_read_dialer_info): Niels Baggesen: accept dialers with no substitutions. * bnu.c (ubnu_read_systems, ubadd_perm): Niels Baggesen: don't free up zline in ubadd_perm; in fact, changed the calling sequence to not even pass zline in at all. * bnu.c (ubadd_perm): Niels Baggesen: didn't handle multiple MACHINE= and multiple LOGNAME= values in a single Permissions line, because it was clobbering the machine name while processing the first logname. * bnu.c: Made zread and zwrite elements of sperm structure const char * to avoid warning. * copy.c, sys1.unx, sys2.unx, sys3.unx, sys5.unx, tstuu.c: Niels Baggesen: don't multiply include . Eventually there should be a macro controlling whether it gets included at all, for non-POSIX systems. * sys3.unx (fsysdep_get_status, isysdep_get_sequence): Marty Shannon: accept a truncated status file. I also eliminated scanf calls in sys3.unx, since that was the only place it was called; this was to make the executables smaller for systems which cared. * bnu.c (ubnu_read_sysfiles): Marty Shannon: accept comment characters in Sysfiles. * sysh.unx, sys3.unx: Marty Shannon: added HAVE_RENAME, put a fake rename system call in sys3.unx. * prtinf.c (ffind_port): Marty Shannon: failed to handle multiple ports in the port file since I forgot to reset my pointer variable. * bnu.c (ubnu_read_systems): Marty Shannon: don't initialize the auto array abpubdir, since old cc didn't permit initialization of auto aggregates. Mon Nov 25 20:56:39 1991 Ian Lance Taylor (ian at comton.airs.com) * tstuu.c: Bob Denny: add definitions for FD_SET, FD_ZERO and FD_ISSET. * config.c: Bob Denny: add explicit externs for strcmp and strcasecmp. * sys2.unx: the fread_blocking and fwrite_blocking fields were not getting initialized correctly in the TCP support routines. * sysh.unx, sys2.unx, sys5.unx, tstuu.c: Marty Shannon: added configuration option HAVE_SYSWAIT_H. * bnu.c (fbnu_find_port, fbnu_read_dialer_info), v2.c (fv2_find_port): Marty Shannon: the ireliable field of ports and dialers was not getting initialized. Sun Nov 24 15:06:37 1991 Ian Lance Taylor (ian at comton.airs.com) * tcp.c (itcp_port_number): Michael Haberler: wasn't calling htons if passed a numeric string. Sat Nov 23 13:43:52 1991 Ian Lance Taylor (ian at comton.airs.com) * Released version 1.01 to alt.sources and uunet ysh.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. * suucp-1.04/MANIFEST1004440004150000170000000075405337263500010516 037777777777 1 0 COPYING ChangeLog MANIFEST Makefile.in README TODO chat.c conf.h.in configure configure.in conn.c conn.h copy.c cu.1 cu.c cu.h getopt.h log.c policy.h prot.c prot.h prote.c protf.c protg.c proti.c protj.c prott.c protz.c rec.c send.c sysh.unx system.h tcp.c time.c tli.c trans.c trans.h tstuu.c util.c uuchk.c uucico.8 uucico.c uuconf.h uuconv.c uucp.1 uucp.c uucp.h uucp.texi uudefs.h uudir.c uulog.c uuname.c uupick.c uusched.in uustat.1 uustat.c uuto.in uux.1 uux.c uuxqt.8 uuxqt.c xcmd.c cess_one_cmd), prtinuucp-1.04/policy.h1006440004150000170000005501105337265075010233 0 0 1 0 /* 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 0 /* 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 0 /* When the code does do a blocking write, it wants to write the largest amount of data which the kernel will accept as a single unit. On BSD this is typically the value of OBUFSIZ in , usually 100. On System V before SVR4 this is typically the size of a clist, CLSIZE in , which is usually 64. On SVR4, which uses STREAMS-based ttys, 2048 is reasonable. Define SINGLE_WRITE to the correct value for your system. If SINGLE_WRITE is too large, data loss may occur. If SINGLE_WRITE is too small, file transfer will use more CPU time than necessary. If you have no idea, 64 should work on most modern systems. */ #define SINGLE_WRITE 64 /* Some tty drivers, such as those from SCO and AT&T's Unix PC, have a bug in the implementation of ioctl() that causes CLOCAL to be ineffective until the port is opened a second time. If HAVE_CLOCAL_BUG is set to 1, code will be added to do this second open on the port. Set this if you are getting messages that say "Line disconnected" while in the dial chat script after only writing the first few characters to the port. This bug causes the resetting of CLOCAL to have no effect, so the "\m" (require carrier) escape sequence won't function properly in dialer chat scripts. */ #define HAVE_CLOCAL_BUG 0 /* On some systems, such as SCO Xenix, resetting DTR on a port apparently prevents getty from working on the port, and thus prevents anybody from dialing in. If HAVE_RESET_BUG is set to 1, DTR will not be reset when a serial port is closed. */ #define HAVE_RESET_BUG 0 /* The Sony NEWS reportedly handles no parity by clearing both the odd and even parity bits in the sgtty structure, unlike most BSD based systems in which no parity is indicated by setting both the odd and even parity bits. Setting HAVE_PARITY_BUG to 1 will handle this correctly. */ #define HAVE_PARITY_BUG 0 #if HAVE_BSD_TTY #ifdef sony #undef HAVE_PARITY_BUG #define HAVE_PARITY_BUG 1 #endif #endif /* On Ultrix 4.0, at least, setting CBREAK causes input characters to be stripped, regardless of the setting of LPASS8 and LLITOUT. This can be worked around by using the termio call to reset ISTRIP. This probably does not apply to any other operating system. Setting HAVE_STRIP_BUG to 1 will use this workaround. */ #define HAVE_STRIP_BUG 0 #if HAVE_BSD_TTY #ifdef ultrix #undef HAVE_STRIP_BUG #define HAVE_STRIP_BUG 1 #endif #endif /* TIMES_TICK is the fraction of a second which times(2) returns (for example, if times returns 100ths of a second TIMES_TICK should be set to 100). On a true POSIX system (one which has the sysconf function and also has _SC_CLK_TCK defined in ) TIMES_TICK may simply be left as 0. On some systems the environment variable HZ is what you want for TIMES_TICK, but on some other systems HZ has the wrong value; check the man page. If you leave this set to 0, the code will try to guess; it will doubtless be wrong on some non-POSIX systems. If TIMES_TICK is wrong the code may report incorrect file transfer times in the statistics file, but on many systems times(2) will actually not be used and this value will not matter at all. */ #define TIMES_TICK 0 /* If your system does not support saved set user ID, set HAVE_SAVED_SETUID to 0. However, this is ignored if your system has the setreuid function. Most modern Unixes have one or the other. If your system has the setreuid function, don't worry about this define, or about the following discussion. If you set HAVE_SAVED_SETUID to 0, you will not be able to use uucp to transfer files that the uucp user can not read. Basically, you will only be able to use uucp on world-readable files. If you set HAVE_SAVED_SETUID to 1, but your system does not have saved set user ID, uucp will fail with an error message whenever anybody other than the uucp user uses it. */ #define HAVE_SAVED_SETUID 1 /* On some systems, such as the DG Aviion and, possibly, the RS/6000, the setreuid function is broken. It should be possible to use setreuid to swap the real and effective user ID's, but on some systems it will not change the real user ID (I believe this is due to a misreading of the POSIX standard). On such a system you must set HAVE_BROKEN_SETREUID to 1; if you do not, you will get error messages from setreuid. Systems on which setreuid exists but is broken pretty much always have saved setuid. */ #define HAVE_BROKEN_SETREUID 0 /* On the 3B2, and possibly other systems, nap takes an argument in hundredths of a second rather than milliseconds. I don't know of any way to test for this. Set HAVE_HUNDREDTHS_NAP to 1 if this is true on your system. This does not matter if your system does not have the nap function. */ #define HAVE_HUNDREDTHS_NAP 0 /* Set PS_PROGRAM to the program to run to get a process status, including the arguments to pass it. This is used by ``uustat -p''. Set HAVE_PS_MULTIPLE to 1 if a comma separated list of process numbers may be appended (e.g. ``ps -flp1,10,100''). Otherwise ps will be invoked several times, with a single process number append each time. The default definitions should work on most systems, although some (such as the NeXT) will complain about the 'p' option; for those, use the second set of definitions. The third set of definitions are appropriate for System V. To use the second or third set of definitions, change the ``#if 1'' to ``#if 0'' and change the appropriate ``#if 0'' to ``#if 1''. */ #if 1 #define PS_PROGRAM "/bin/ps -lp" #define HAVE_PS_MULTIPLE 0 #endif #if 0 #define PS_PROGRAM "/bin/ps -l" #define HAVE_PS_MULTIPLE 0 #endif #if 0 #define PS_PROGRAM "/bin/ps -flp" #define HAVE_PS_MULTIPLE 1 #endif /* If you use other programs that also lock devices, such as cu or uugetty, the other programs and UUCP must agree on whether a device is locked. This is typically done by creating a lock file in a specific directory; the lock files are generally named LCK..something or LK.something. If the LOCKDIR macro is defined, these lock files will be placed in the named directory; otherwise they will be placed in the default spool directory. On some HDB systems the lock files are placed in /etc/locks. On some they are placed in /usr/spool/locks. On the NeXT they are placed in /usr/spool/uucp/LCK. */ /* #define LOCKDIR "/usr/spool/uucp" */ /* #define LOCKDIR "/etc/locks" */ /* #define LOCKDIR "/usr/spool/locks" */ /* #define LOCKDIR "/usr/spool/uucp/LCK" */ /* You must also specify the format of the lock files by setting exactly one of the following macros to 1. Check an existing lock file to decide which of these choices is more appropriate. The HDB style is to write the locking process ID in ASCII, passed to ten characters, followed by a newline. The V2 style is to write the locking process ID as four binary bytes in the host byte order. Many BSD derived systems use this type of lock file, including the NeXT. SCO lock files are similar to HDB lock files, but always lock the lowercase version of the tty (i.e., LCK..tty2a is created if you are locking tty2A). They are appropriate if you are using Taylor UUCP on an SCO Unix, SCO Xenix, or SCO Open Desktop system. SVR4 lock files are also similar to HDB lock files, but they use a different naming convention. The filenames are LK.xxx.yyy.zzz, where xxx is the major device number of the device holding the special device file, yyy is the major device number of the port device itself, and zzz is the minor device number of the port device. Coherent use a completely different method of terminal locking. See unix/cohtty for details. For locks other than for terminals, HDB type lock files are used. */ #define HAVE_V2_LOCKFILES 0 #define HAVE_HDB_LOCKFILES 1 #define HAVE_SCO_LOCKFILES 0 #define HAVE_SVR4_LOCKFILES 0 #define HAVE_COHERENT_LOCKFILES 0 /* If your system supports Internet mail addresses (which look like user@host.domain rather than system!user), HAVE_INTERNET_MAIL should be set to 1. This is checked by uuxqt when sending error (or success, if requested) notifications to the person who submitted the job. */ #define HAVE_INTERNET_MAIL 1 /* Adminstrative decisions. */ /* Set USE_RCS_ID to 1 if you want the RCS ID strings compiled into the executable. Leaving them out will decrease the executable size. Leaving them in will make it easier to determine which version you are running. */ #define USE_RCS_ID 1 /* DEBUG controls how much debugging information is compiled into the code. If DEBUG is defined as 0, no sanity checks will be done and no debugging messages will be compiled in. If DEBUG is defined as 1 sanity checks will be done but there will still be no debugging messages. If DEBUG is 2 than debugging messages will be compiled in. When initially testing, DEBUG should be 2, and you should probably leave it at 2 unless a small reduction in the executable file size will be very helpful. */ #define DEBUG 2 /* Set the default grade to use for a uucp command if the -g option is not used. The grades, from highest to lowest, are 0 to 9, A to Z, a to z. */ #define BDEFAULT_UUCP_GRADE ('N') /* Set the default grade to use for a uux command if the -g option is not used. */ #define BDEFAULT_UUX_GRADE ('N') /* To compile in use of the new style of configuration files described in the documentation, set HAVE_TAYLOR_CONFIG to 1. */ #define HAVE_TAYLOR_CONFIG 1 /* To compile in use of V2 style configuration files (L.sys, L-devices and so on), set HAVE_V2_CONFIG to 1. To compile in use of HDB style configuration files (Systems, Devices and so on) set HAVE_HDB_CONFIG to 1. The files will be looked up in the oldconfigdir directory as defined in the Makefile. You may set any or all of HAVE_TAYLOR_CONFIG, HAVE_V2_CONFIG and HAVE_HDB_CONFIG to 1 (you must set at least one of the macros). When looking something up (a system, a port, etc.) the new style configuration files will be read first, followed by the V2 configuration files, followed by the HDB configuration files. */ #define HAVE_V2_CONFIG 0 #define HAVE_HDB_CONFIG 0 /* Exactly one of the following macros must be set to 1. The exact format of the spool directories is explained in unix/spool.c. SPOOLDIR_V2 -- Use a Version 2 (original UUCP) style spool directory SPOOLDIR_BSD42 -- Use a BSD 4.2 style spool directory SPOOLDIR_BSD43 -- Use a BSD 4.3 style spool directory SPOOLDIR_HDB -- Use a HDB (BNU) style spool directory SPOOLDIR_ULTRIX -- Use an Ultrix style spool directory SPOOLDIR_SVR4 -- Use a System V Release 4 spool directory SPOOLDIR_TAYLOR -- Use a new style spool directory If you are not worried about compatibility with a currently running UUCP, use SPOOLDIR_TAYLOR. */ #define SPOOLDIR_V2 0 #define SPOOLDIR_BSD42 0 #define SPOOLDIR_BSD43 0 #define SPOOLDIR_HDB 0 #define SPOOLDIR_ULTRIX 0 #define SPOOLDIR_SVR4 0 #define SPOOLDIR_TAYLOR 1 /* You must select which type of logging you want by setting exactly one of the following to 1. These control output to the log file and to the statistics file. If you define HAVE_TAYLOR_LOGGING, each line in the log file will look something like this: uucico uunet uucp (1991-12-10 09:04:34.45 16390) Receiving uunet/D./D.uunetSwJ72 and each line in the statistics file will look something like this: uucp uunet (1991-12-10 09:04:40.20) received 2371 bytes in 5 seconds (474 bytes/sec) If you define HAVE_V2_LOGGING, each line in the log file will look something like this: uucico uunet uucp (12/10-09:04 16390) Receiving uunet/D./D.uunetSwJ72 and each line in the statistics file will look something like this: uucp uunet (12/10-09:04 16390) (692373862) received data 2371 bytes 5 seconds If you define HAVE_HDB_LOGGING, each program will by default use a separate log file. For uucico talking to uunet, for example, it will be /usr/spool/uucp/.Log/uucico/uunet. Each line will look something like this: uucp uunet (12/10-09:04:22,16390,1) Receiving uunet/D./D.uunetSwJ72 and each line in the statistics file will look something like this: uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, 474 bytes/sec The main reason to prefer one format over another is that you may have shell scripts which expect the files to have a particular format. If you have none, choose whichever format you find more appealing. */ #define HAVE_TAYLOR_LOGGING 1 #define HAVE_V2_LOGGING 0 #define HAVE_HDB_LOGGING 0 /* If you would like the log, debugging and statistics files to be closed after each message, set CLOSE_LOGFILES to 1. This will permit the log files to be easily moved. If a log file does not exist when a new message is written out, it will be created. Setting CLOSE_LOGFILES to 1 will obviously require slightly more processing time. */ #define CLOSE_LOGFILES 0 /* The name of the default spool directory. If HAVE_TAYLOR_CONFIG is set to 1, this may be overridden by the ``spool'' command in the configuration file. */ #define SPOOLDIR "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/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 "/usr/spool/uucp/.Admin/audit.local" #endif /* HAVE_HDB_LOGGING */ (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 auucp-1.04/README1004440004150000170000002171405337263501010245 037777777777 1 0 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. pool/uucp/.Admin/audit.local" #endif /* HAVE_HDB_LOuucp-1.04/TODO1004440004150000170000004317605337263501010063 037777777777 1 0 This is a list of things to do for the Taylor UUCP package. Please feel free to work on any of them. You may want to check with me first to make sure that nobody else is working on them as well. Some of these are my thoughts, but most are suggestions from other people; I have tried to give credit. They are in the order I received them; the missing numbers have already been implemented. Just because something is on the list doesn't mean that I necessarily think it is a good idea. It does mean that I think it's worth thinking about. 2. John Cowan says: >I think you should accept a broader range of time specifications. >Consider using getdate() (from your handy Usenet news source code) >with its high-powered yacc parser. Of course, getdate() accepts a single date, but we want a range. A better syntax would be certainly be nice. 9. Gordon Burditt warns about modifications to the TZ environment variable, to fool uucico into dialing out at an inappropriate time. 10. Gordon Burditt says: >(4) Less important, because few people will have this problem, is a >port-specific dialcodes file. Why? Well, one system I had was connected >to 2 inside lines "dial 9 for outside line", and one outside line (which >doesn't want the 9). A number of the systems called were "inside", so >you didn't add the 9 on those lines dialing from inside, but you did add >"390" to the 4-digit number if you dialed it via "outside". Also not >unheard of are systems with 2 outside lines that are local to different >area codes, or one local outside line and one WATS line (which MUST >have an area code). >Example: > inside-line Dialcodes outside-line Dialcodes > pbx "" pbx "390" > local "9" local "" > nyc "9-1212" nyc "1212" 12. Ralf E. Stranzenbach says: >It would be nice to also have the option of running a shell script each time >uucico connects/disconnects a systen. I do not mean shell scripts for dial/in. >I would like to do some accounting and batching when the connection >establishes. 13. les@chinet.chi.il.us (Leslie Mikesell) writes: >>local-send /usr/spool/uucppublic !/usr/spool/uucpublic/private >> >>The directories are searched from left to right, and the last one to >>match determines whether the file may be sent or not. This is >>slightly more general than NOWRITE, since it permits a public >>directory within a private directory within a public directory, >>although probably nobody will ever want that. > >Interesting... The obvious enhancement is to generalize to shell-like >wild cards for the READ/WRITE/COMMANDS entries. 14. Should there be a way for chat scripts to specify the parity to generate? I don't think there's much point to specifying what parity to accept. 17. The -b and -s switches to uux are not implemented by uuxqt. 18. If we are supposed to call a system back, we should do it immediately rather than merely queuing up an empty command file. 22. Add an ftp port type which uses anonymous ftp rather than any of the UUCP protocols to do file transfers. This would allow ftp work to be done late at night, and allow neighbors of cooperative Internet sites to use UUCP forwarding for anonymous FTP. 31. David Nugent: add a -C option to uucico to only call the system if there is work to do. 32. It would be nice if uucico could sleep until a line was available. This is complicated by the possibility of wanting to wait for any of several different lines, and one would really want some sort of semaphore function to do it right. If the available lines could be sorted, then each could be assigned to a byte in a line lock file. Looking for a line could be done by sleeping on a read lock on all possible lines. Once it came through, write locks would be attempted. If they all failed, somebody else snuck in, so you would sleep on a read lock again. This isn't great because a process could be starved, but it might be better than nothing. This could be tied in to uucp and uux, such that they wouldn't actually fire up uucico unless a line was known to be available; an additional switch would be used to fire up uucico anyhow (or one could switch the default behaviour and the switch). So how do you sort the lines? You could just use the index in the port (or Devices) file, but what if multiple ports used the same physical device? Hmmm. 43. David Nugent: it would be nice to be able to set debugging, log, and statistics files on a site by site basis. Brian Murrell: heck, set those files on a port by port basis as well. 74. Yanek Martinson: allow each system to independently choose whether to permit shell execution. 81. Marty Shannon: log reason for dial failure (chat-fail string) in .Status file. 83. Switch between 'M' and 'S' correctly in the BNU log file output. 86. Les Mikesell: allow a separate program to be specified to handle the communications with a particular system. 105. T. William Wells: close and open the Debug file after each file transfer. Alternatively, cycle through a series of Debug file names every 1000 lines or so. 106. Marty Shannon: add a time command for ports, to specify when they may be used. 115. T. William Wells: new options for uustat: -i display job ids only Also, there should perhaps be a configuration option to request uustat to only display jobs submitted by the user running uustat, except for root and uucp. 117. Marc Unangst: provide some way to change the debugging level of a running uucico. T. William Wells suggests having it read a file to change arbitrary configuration information, although obviously one has to be careful of what gets changed while a connection is active. 120. Jarmo Raiha: new chat-fail commands: one to not update the status file and require a retry wait, and one to permit the string to occur a few times before reporting an error. 124. Peter da Silva: perhaps there should be a ``chat-end-program'' command to let a program be run after the initial handshake has been completed and the protocol has been selected and turned on. This would let people run stty to change their terminal parameters. 128. Richard Stallman: have an interactive program to set up a chat script. It would let you type directly to the port, recording what you type as send strings and recording what comes back from the other side as expect strings. 129. Use POSIX fcntl locks when possible instead of creating a lock file. 130. Chip Salzenberg: BSD lets you override the timeout for a particular expect string by using a trailing ~. 138. T. William Wells: BNU apparently uses a file named A.whatever to hold the line number reached in current C. file processing. This is a hack, and won't work right with size control anyhow, but fsysdep_did_work could, for example, clobber the first byte in the line to a # or something to mark that it had been finished. Still a hack, but a better one. 139. Patrick Smith: incorporate patches to generate full debugging traces with less debugging file overhead. The debugging file repeats too much information at great length right now--not good. 141. Franc,ois Pinard: batch up pauses and delays in chat scripts and do them all at once in a single system call. This is particularly useful for pauses on systems which don't support subsecond sleeps. For everything else it's a fairly minor optimization. 142. Franc,ois Pinard: give uustat an option to requeue jobs to another system. This only makes a lot of sense for rmail executions, but it's fairly easy to do for any type of command. I think uucico does all the file checking needed to ensure that this doesn't break security, but that should be double-checked. 144. T. William Wells: add a -g option to uucico to permit specifying the maximum grade to be transferred at that time. This could restrict the timegrade command further, but should not be permitted to override it. 145. T. William Wells: if uucico or uuxqt get started with bad arguments, put an indication in the log file since stderr may be /dev/null. 146. Richard Todd: it would be nice to sometimes be able to request the other side to turn on debugging. 147. Bart Schaefer: some more possible options for uucico: -R reverse roles (hangup immediately). Not too exciting. some method to restrict calling to particular systems. 148. Jarmo Raiha: some method to control the work queue at the remote end. This could get awfully general, though. 149. The interaction of the time command and defaults can be confusing, since any time command in the actual system entry, even a fairly specific one, will wipe out the default entry. Not sure what can be done about this. 150. Jarmo Raiha: should there be some way to specify modem initialization strings when uucico is hanging on a port with -l or -e? This would presumably require a new type of chat script associated with a dialer. 151. Petri Helenius: log complete CONNECT string reported by modem, so that the baud rate is recorded in the log file. 152. Marc Evans: let the protocol selection be based on the CONNECT string, so that different protocols could be selected based on what type of connection was made. 153. Chris Lewis: provide a signal to get a core dump even on systems which won't do core dumps if the uid is not the euid. One could catch a signal, call setuid (getuid ()), and then raise the signal again. Unfortunately the core dump has to wind up in a directory which is world writable, so that the process is able to create the core file, but is not world readable, since that would permit anybody to read the core dump file and extract private information from it. 154. Les Mikesell: write a new version of dial.o, with provisions for running a chat script. 155. Scott Blachowicz: perhaps there should be some way to telling uucico to not log certain errors. This could get fairly complex, though. 156. Franc,ois Pinard: have uustat -m report the time of the last successful conversation when reporting a failure. 158. Thomas Fischer: should there be a way to completely disable an entry in the sys, port or dial file? Such as a ``disable'' command? 159. Petri Helenius: when uuxqt -s is invoked, lock uuxqt for the system so that only one uuxqt is invoked per system. If the -c option is used, don't lock on a per system basis, and ignore any per system locks (regardless of -s). If neither option is used, respect existing system and command locks, and do any other type of file. 161. Scott Blachowicz: provide some sort of include mechanism for the configuration files. 162. Chris Lewis: add uuxqtpolicy command, probably in config, supporting the following values which determine when uuxqt should be run: - never (let cron or something else worry about it) - perinvocation (when uucico exits for good - current behaviour) - persite (when uucico terminates a conversation - HDBish) - periodic (per 5 or 10 incoming X. files - BSDish) - perturnaround? 163. Sort jobs in the send queue by size. Pretty easy. 164. Ed Carp: preserve files if uuxqt execution fails. 165. Marc Sheldon: use exit codes from in uux and uucp. 166. Chip Salzenberg: allow chat failure strings to specify a retry time. 167. Gregory Bond: allow a dialer sequence for a TCP port, so you can make a TCP connection to a modem and then dial out. 168. Jose A. Manas: allow a maximum connect time, after which we try to hang up the connection. This requires a protocol extension, since there's no way to force the other side to hang up. The best we can do without an extension is refuse to send any new jobs ourselves. Of course, we could just drop the connection. 169. Franc,ois Pinard: when given uustat -k00FC, check each possible job ID and use it if there is an unambiguous one. 170. T. William Wells: if ! HAVE_SETREUID && ! HAVE_SAVED_SETUID, fork a subprocesses to revoke setuid and read the file over a pipe. 171. Provide some option to have the internal uuconf functions not start with an underscore. 172. T. William Wells: have some way to configure the parity for cu. 173. Gert Doering: uuchk should display unknown system information. 175. T. William Wells: Cu will not let itself be interrupted before the connection is established. If the chat script doesn't write something, cu does something odd, I've forgotten exactly what. Cu takes an inordinate amount of time after the line drops to exit. Somebody, cu, I think, but maybe uucico, drops dtr twice sometimes. Again, somebody will attempt to write after a hangup signal has been received. Once a hangup has been received, I/O should not be attempted. Among other things this will save the bacon of those who have brain damaged serial drivers (FAS, sigh, is among them) that don't handle output properly on a dropped line. Me: Note that sometimes you do want to write to a line after receiving a hangup signal. For example, you might want to use ATZ to reset a modem. 176. Hans-Dieter Doll: provide some way (another escape sequence) to pass the protocol to a chat-program. Or, allow the protocol as an argument to the chat script command, which is more general, but maybe a bit too fancy. 177. Nickolay Saukh: use a default port for cu, you can just do ``cu number''. 178. Don Phillips: should there be some way to restrict of grade of transfers even when the other system places the call? 179. Nickolay Saukh: add something to chat scripts to specify the timeout for an expect string, e.g. AT\c OK\W3 to wait for 3 seconds. Except that perhaps the unit should not be seconds. Berkeley apparently uses ~number, not \W number, but I don't see any reason to prevent use of the ~ character in an expect string. 180. Nickolay Saukh: if we have received a partial file, request the remote system to start sending from that point. We currently accept SVR4 style remote file positioning requests, but we do not generate them. 181. Mark Powell: provide some way to restrict file transfer by size as well as grade? One way would be to let uux select the grade based on the file size. 182. Mark Powell: permit using multiple timetables in a single time statement. 183. Optionally check for interrupts in fcopy_file, since it can take a long time to copy a file named in a uucp request. 184. Ian Moran: if an attempt is made to a copy a file to a directory which denies write permission, perhaps the file should be saved somewhere. It must be saved in a private location, though. 185. A syntax error in a command received from the remote system should not hold up the queue. Unfortunately, I don't know what can be done except deny the command and report it. Reporting a garbled command error should report the command correctly, rather than just the first character. 186. Franc,ois Pinard: have an option to control nostop vs. stop on the cu command line. 187. Fix the notion of %nostop to be SVID compatible. 188. Frank Conrad: provide a means to set the strip mode for a port, to make it easy to use it from cu. 189. Marc Unangst: there should be a way to specify that a system should only be called if there are jobs of a certain grade, but if the system is called then jobs of any grade should be transferred. This basically means splitting the ``timegrade'' command into two commands: ``place-call-timegrade'' and ``transfer-timegrade''. Or maybe another optional argument to ``timegrade'': timegrade grade time-string [retry] [transfer-any] not to mention time time-string [retry] [transfer-any] Or maybe a separate command for a system or port like transfer-any BOOL 190. Chip Salzenberg: it would be really nice if uucico could automatically figure out when it could use an E command, so that uux didn't have to generate it and so that uucico could use with other versions of uux. Unfortunately, it would require uucico to read the execution file to see if it were suitable; this would be complex, but it would probably be worth it since normally the execution file would wind up not being sent. Of course, the current method works too; it's just harder to combine with other versions of UUCP. 191. Brian J. Murrell: should there be a way to cu a specific alternate? 192. Andrew A. Chernov: Perhaps cu -pport system should be able to try different alternates for the system, because there might be different phone numbers to try. 193. Brian J. Murrell: it would be nice to be able to ^C a cu chat script if you know it's going to fail. Right now you have to use ^\. 194. Steven S. Dick: have some way to force uucico off the phone at a certain time. If that is done, it might be cool to have some way to predict how long a file transfer will take, and not do it if it will take too long. But, if doing file restart, you can just quit and then pick it up later. 195. Franc,ois Pinard: if the disk fills up, or some other error occurs, while receiving a file, perhaps it would make sense to turn the connection around immediately and see if the other side had anything to do, and then try again later. This would require a protocol extension. I don't know if it's worth it. The code should be checked to see how well it handles a disk full situation. 196. For real adjustability, provide some mechanism for picking the lead characters to use for the shell scripts, between : and #!. 197. Try alternate IP addresses if there are any. 198. Lele Gaifax: mention the device in Stats, and provide some way to associate the entry in Log with the entry in Stats. 199. Michael Richardson: provide some way to turn on parity for the login chat, since some systems apparently require it. Provide some way for cu to control parity after connecting. 200. Chip Salzenberg: add max-remote-debug to config. 201. Gert Doering: change the timeout message in chat scripts to reflect which chat script timed out (dialer or login). 202. Bill Foote: have uuchk check whether a system is defined more than once. 203. o 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 requestuucp-1.04/chat.c1004440004150000170000007652205337263502010460 037777777777 1 0 /* 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.38 1992/10/21 03:44:46 ian Rel $"; #endif #include #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "prot.h" #include "system.h" /* Local functions. */ static int icexpect P((struct sconnection *qconn, int cstrings, char **azstrings, size_t *aclens, int ctimeout, boolean fstrip)); static boolean fcsend P((struct sconnection *qconn, pointer puuconf, const char *zsend, const struct uuconf_system *qsys, const struct uuconf_dialer *qdial, const char *zphone, boolean ftranslate, boolean fstrip)); static boolean fcecho_send_strip P((struct sconnection *qconn, const char *z, size_t clen)); static boolean fcecho_send_nostrip P((struct sconnection *qconn, const char *z, size_t clen)); static boolean fcecho_send P((struct sconnection *qconn, const char *z, size_t clen, boolean fstrip)); static boolean fcphone P((struct sconnection *qconn, pointer puuconf, const struct uuconf_dialer *qdial, const char *zphone, boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite, size_t cwrite)), boolean ftranslate, boolean *pfquote)); static boolean fctranslate P((pointer puuconf, const char *zphone, const char **pzprefix, const char **pzsuffix)); static boolean fcprogram P((struct sconnection *qconn, pointer puuconf, char **pzprogram, const struct uuconf_system *qsys, const struct uuconf_dialer *qdial, const char *zphone, const char *zport, long ibaud)); /* Run a chat script with the other system. The chat script is a series of expect send pairs. We wait for the expect string to show up, and then we send the send string. The chat string for a system holds the expect and send strings separated by a single space. */ boolean fchat (qconn, puuconf, qchat, qsys, qdial, zphone, ftranslate, zport, ibaud) struct sconnection *qconn; pointer puuconf; const struct uuconf_chat *qchat; const struct uuconf_system *qsys; const struct uuconf_dialer *qdial; const char *zphone; boolean ftranslate; const char *zport; long ibaud; { int cstrings; char **azstrings; size_t *aclens; char **pzchat; char *zbuf; size_t cbuflen; boolean fret; int i; /* First run the program, if any. */ if (qchat->uuconf_pzprogram != NULL) { if (! fcprogram (qconn, puuconf, qchat->uuconf_pzprogram, qsys, qdial, zphone, zport, ibaud)) return FALSE; } /* If there's no chat script, we're done. */ if (qchat->uuconf_pzchat == NULL) return TRUE; if (qchat->uuconf_pzfail == NULL) { cstrings = 1; azstrings = (char **) xmalloc (sizeof (char *)); aclens = (size_t *) xmalloc (sizeof (size_t)); } else { char **pz; /* We leave string number 0 for the chat script. */ cstrings = 1; for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++) ++cstrings; azstrings = (char **) xmalloc (cstrings * sizeof (char *)); aclens = (size_t *) xmalloc (cstrings * sizeof (size_t)); /* Get the strings into the array, and handle all the escape characters. */ for (cstrings = 1, pz = qchat->uuconf_pzfail; *pz != NULL; cstrings++, pz++) { azstrings[cstrings] = zbufcpy (*pz); aclens[cstrings] = cescape (azstrings[cstrings]); } } cbuflen = 0; zbuf = NULL; fret = TRUE; pzchat = qchat->uuconf_pzchat; while (*pzchat != NULL) { size_t clen; /* Loop over subexpects and subsends. */ while (TRUE) { /* Copy the expect string into the buffer so that we can modify it in cescape. */ clen = strlen (*pzchat); if (clen >= cbuflen) { ubuffree (zbuf); zbuf = zbufalc (clen + 1); cbuflen = clen; } memcpy (zbuf, *pzchat, clen + 1); azstrings[0] = zbuf; if (azstrings[0][0] == '-') ++azstrings[0]; aclens[0] = cescape (azstrings[0]); if (aclens[0] == 0 || (aclens[0] == 2 && strcmp (azstrings[0], "\"\"") == 0)) { /* There is no subexpect sequence. If there is a subsend sequence we move on to it. Otherwise we let this expect succeed. This is somewhat inconsistent, but it seems to be the traditional approach. */ if (pzchat[1] == NULL || pzchat[1][0] != '-') break; } else { int istr; istr = icexpect (qconn, cstrings, azstrings, aclens, qchat->uuconf_ctimeout, qchat->uuconf_fstrip); /* If we found the string, break out of the subexpect/subsend loop. */ if (istr == 0) break; /* If we got an error, return FALSE. */ if (istr < -1) { fret = FALSE; break; } /* If we found a failure string, log it and get out. */ if (istr > 0) { ulog (LOG_ERROR, "Chat script failed: Got \"%s\"", qchat->uuconf_pzfail[istr - 1]); fret = FALSE; break; } /* We timed out; look for a send subsequence. If none, the chat script has failed. */ if (pzchat[1] == NULL || pzchat[1][0] != '-') { ulog (LOG_ERROR, "Timed out in chat script"); fret = FALSE; break; } } /* Send the send subsequence without the leading '-'. A \"\" will send nothing. An empty string will send a carriage return. */ ++pzchat; if (! fcsend (qconn, puuconf, *pzchat + 1, qsys, qdial, zphone, ftranslate, qchat->uuconf_fstrip)) { fret = FALSE; break; } /* If there is no expect subsequence, we are done. */ if (pzchat[1] == NULL || pzchat[1][0] != '-') break; /* Move on to next expect subsequence. */ ++pzchat; } if (! fret) break; /* Move on to the send string. If there is none, we have succeeded. */ do { ++pzchat; } while (*pzchat != NULL && (*pzchat)[0] == '-'); if (*pzchat == NULL) break; if (**pzchat != '\0') { if (! fcsend (qconn, puuconf, *pzchat, qsys, qdial, zphone, ftranslate, qchat->uuconf_fstrip)) { fret = FALSE; break; } } ++pzchat; } ubuffree (zbuf); for (i = 1; i < cstrings; i++) ubuffree (azstrings[i]); xfree ((pointer) azstrings); xfree ((pointer) aclens); return fret; } /* Read characters and wait for one of a set of memory strings to come in. This returns the index into the array of the string that arrives, or -1 on timeout, or -2 on error. */ static int icexpect (qconn, cstrings, azstrings, aclens, ctimeout, fstrip) struct sconnection *qconn; int cstrings; char **azstrings; size_t *aclens; int ctimeout; boolean fstrip; { int i; size_t cmax; char *zhave; size_t chave; long iendtime; #if DEBUG > 1 int cchars; int iolddebug; #endif cmax = aclens[0]; for (i = 1; i < cstrings; i++) if (cmax < aclens[i]) cmax = aclens[i]; zhave = zbufalc (cmax); chave = 0; iendtime = ixsysdep_time ((long *) NULL) + ctimeout; #if DEBUG > 1 cchars = 0; iolddebug = iDebug; if (FDEBUGGING (DEBUG_CHAT)) { udebug_buffer ("icexpect: Looking for", azstrings[0], aclens[0]); ulog (LOG_DEBUG_START, "icexpect: Got \""); iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); } #endif while (TRUE) { int bchar; /* If we have no more time, get out. */ if (ctimeout <= 0) { #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { ulog (LOG_DEBUG_END, "\" (timed out)"); iDebug = iolddebug; } #endif ubuffree (zhave); return -1; } /* Read one character at a time. We could use a more complex algorithm to read in larger batches, but it's probably not worth it. If the buffer is full, shift it left; we already know that no string matches, and the buffer holds the largest string, so this can't lose a match. */ if (chave >= cmax) { size_t imove; for (imove = 0; imove < cmax - 1; imove++) zhave[imove] = zhave[imove + 1]; --chave; } /* The timeout/error return values from breceive_char are the same as for this function. */ bchar = breceive_char (qconn, ctimeout, TRUE); if (bchar < 0) { #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { /* If there was an error, it will probably be logged in the middle of our string, but this is only debugging so it's not a big deal. */ ulog (LOG_DEBUG_END, "\" (%s)", bchar == -1 ? "timed out" : "error"); iDebug = iolddebug; } #endif ubuffree (zhave); return bchar; } /* Strip the parity bit if desired. */ if (fstrip) bchar &= 0x7f; zhave[chave] = (char) bchar; ++chave; #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { char ab[5]; ++cchars; if (cchars > 60) { ulog (LOG_DEBUG_END, "\""); ulog (LOG_DEBUG_START, "icexpect: Got \""); cchars = 0; } (void) cdebug_char (ab, bchar); ulog (LOG_DEBUG_CONTINUE, "%s", ab); } #endif /* See if any of the strings can be found in the buffer. Since we read one character at a time, the string can only be found at the end of the buffer. */ for (i = 0; i < cstrings; i++) { if (aclens[i] <= chave && memcmp (zhave + chave - aclens[i], azstrings[i], aclens[i]) == 0) { #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { if (i == 0) ulog (LOG_DEBUG_END, "\" (found it)"); else { ulog (LOG_DEBUG_END, "\""); udebug_buffer ("icexpect: Found", azstrings[i], aclens[i]); } iDebug = iolddebug; } #endif ubuffree (zhave); return i; } } ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL)); } } #if DEBUG > 1 /* Debugging function for fcsend. This takes the fquote variable, the length of the string (0 if this an informational string which can be printed directly) and the string itself. It returns the new value for fquote. The fquote variable is TRUE if the debugging output is in the middle of a quoted string. */ static size_t cCsend_chars; static int iColddebug; static boolean fcsend_debug P((boolean, size_t, const char *)); static boolean fcsend_debug (fquote, clen, zbuf) boolean fquote; size_t clen; const char *zbuf; { size_t cwas; if (! FDEBUGGING (DEBUG_CHAT)) return TRUE; cwas = cCsend_chars; if (clen > 0) cCsend_chars += clen; else cCsend_chars += strlen (zbuf); if (cCsend_chars > 60 && cwas > 10) { ulog (LOG_DEBUG_END, "%s", fquote ? "\"" : ""); fquote = FALSE; ulog (LOG_DEBUG_START, "fcsend: Writing"); cCsend_chars = 0; } if (clen == 0) { ulog (LOG_DEBUG_CONTINUE, "%s %s", fquote ? "\"" : "", zbuf); return FALSE; } else { int i; if (! fquote) ulog (LOG_DEBUG_CONTINUE, " \""); for (i = 0; i < clen; i++) { char ab[5]; (void) cdebug_char (ab, zbuf[i]); ulog (LOG_DEBUG_CONTINUE, "%s", ab); } return TRUE; } } /* Finish up the debugging information for fcsend. */ static void ucsend_debug_end P((boolean, boolean)); static void ucsend_debug_end (fquote, ferr) boolean fquote; boolean ferr; { if (! FDEBUGGING (DEBUG_CHAT)) return; if (fquote) ulog (LOG_DEBUG_CONTINUE, "\""); if (ferr) ulog (LOG_DEBUG_CONTINUE, " (error)"); ulog (LOG_DEBUG_END, "%s", ""); iDebug = iColddebug; } #else /* DEBUG <= 1 */ /* Use macro definitions to make fcsend look neater. */ #define fcsend_debug(fquote, clen, zbuf) TRUE #define ucsend_debug_end(fquote, ferror) #endif /* DEBUG <= 1 */ /* Send a string out. This has to parse escape sequences as it goes. Note that it handles the dialer escape sequences (\e, \E, \D, \T) although they make no sense for chatting with a system. */ static boolean fcsend (qconn, puuconf, z, qsys, qdial, zphone, ftranslate, fstrip) struct sconnection *qconn; pointer puuconf; const char *z; const struct uuconf_system *qsys; const struct uuconf_dialer *qdial; const char *zphone; boolean ftranslate; boolean fstrip; { boolean fnocr; boolean (*pfwrite) P((struct sconnection *, const char *, size_t)); char *zcallout_login; char *zcallout_pass; boolean fquote; if (strcmp (z, "\"\"") == 0) return TRUE; fnocr = FALSE; pfwrite = fconn_write; zcallout_login = NULL; zcallout_pass = NULL; #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { ulog (LOG_DEBUG_START, "fcsend: Writing"); fquote = FALSE; cCsend_chars = 0; iColddebug = iDebug; iDebug &=~ (DEBUG_OUTGOING | DEBUG_PORT); } #endif while (*z != '\0') { const char *zlook; boolean fsend; char bsend; zlook = z + strcspn ((char *) z, "\\BE"); if (zlook > z) { size_t c; c = zlook - z; fquote = fcsend_debug (fquote, c, z); if (! (*pfwrite) (qconn, z, c)) { ucsend_debug_end (fquote, TRUE); return FALSE; } } if (*zlook == '\0') break; z = zlook; fsend = FALSE; switch (*z) { case 'B': if (strncmp (z, "BREAK", 5) == 0) { fquote = fcsend_debug (fquote, (size_t) 0, "break"); if (! fconn_break (qconn)) { ucsend_debug_end (fquote, TRUE); return FALSE; } fnocr = TRUE; z += 5; } else { fsend = TRUE; bsend = 'B'; ++z; } break; case 'E': if (strncmp (z, "EOT", 3) == 0) { fsend = TRUE; bsend = '\004'; fnocr = TRUE; z += 3; } else { fsend = TRUE; bsend = 'E'; ++z; } break; case '\\': ++z; switch (*z) { case '-': fsend = TRUE; bsend = '-'; break; case 'b': fsend = TRUE; bsend = '\b'; break; case 'c': fnocr = TRUE; break; case 'd': fquote = fcsend_debug (fquote, (size_t) 0, "sleep"); usysdep_sleep (2); break; case 'e': fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-off"); pfwrite = fconn_write; break; case 'E': fquote = fcsend_debug (fquote, (size_t) 0, "echo-check-on"); if (fstrip) pfwrite = fcecho_send_strip; else pfwrite = fcecho_send_nostrip; break; case 'K': fquote = fcsend_debug (fquote, (size_t) 0, "break"); if (! fconn_break (qconn)) { ucsend_debug_end (fquote, TRUE); return FALSE; } break; case 'n': fsend = TRUE; bsend = '\n'; break; case 'N': fsend = TRUE; bsend = '\0'; break; case 'p': fquote = fcsend_debug (fquote, (size_t) 0, "pause"); usysdep_pause (); break; case 'r': fsend = TRUE; bsend = '\r'; break; case 's': fsend = TRUE; bsend = ' '; break; case 't': fsend = TRUE; bsend = '\t'; break; case '\0': --z; /* Fall through. */ case '\\': fsend = TRUE; bsend = '\\'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': fsend = TRUE; bsend = *z - '0'; if (z[1] >= '0' && z[1] <= '7') bsend = (char) (8 * bsend + *++z - '0'); if (z[1] >= '0' && z[1] <= '7') bsend = (char) (8 * bsend + *++z - '0'); break; case 'x': fsend = TRUE; bsend = 0; while (isxdigit (BUCHAR (z[1]))) { if (isdigit (BUCHAR (z[1]))) bsend = (char) (16 * bsend + *++z - '0'); else if (isupper (BUCHAR (z[1]))) bsend = (char) (16 * bsend + *++z - 'A'); else bsend = (char) (16 * bsend + *++z - 'a'); } break; case 'L': { const char *zlog; if (qsys == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\L"); return FALSE; } zlog = qsys->uuconf_zcall_login; if (zlog == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "No login defined"); return FALSE; } if (zlog[0] == '*' && zlog[1] == '\0') { if (zcallout_login == NULL) { int iuuconf; iuuconf = uuconf_callout (puuconf, qsys, &zcallout_login, &zcallout_pass); if (iuuconf == UUCONF_NOT_FOUND || zcallout_login == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "No login defined"); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ucsend_debug_end (fquote, TRUE); ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } } zlog = zcallout_login; } fquote = fcsend_debug (fquote, (size_t) 0, "login"); fquote = fcsend_debug (fquote, strlen (zlog), zlog); if (! (*pfwrite) (qconn, zlog, strlen (zlog))) { ucsend_debug_end (fquote, TRUE); return FALSE; } } break; case 'P': { const char *zpass; if (qsys == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\P"); return FALSE; } zpass = qsys->uuconf_zcall_password; if (zpass == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "No password defined"); return FALSE; } if (zpass[0] == '*' && zpass[1] == '\0') { if (zcallout_pass == NULL) { int iuuconf; iuuconf = uuconf_callout (puuconf, qsys, &zcallout_login, &zcallout_pass); if (iuuconf == UUCONF_NOT_FOUND || zcallout_pass == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "No password defined"); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ucsend_debug_end (fquote, TRUE); ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } } zpass = zcallout_pass; } fquote = fcsend_debug (fquote, (size_t) 0, "password"); fquote = fcsend_debug (fquote, strlen (zpass), zpass); if (! (*pfwrite) (qconn, zpass, strlen (zpass))) { ucsend_debug_end (fquote, TRUE); return FALSE; } } break; case 'D': if (qdial == NULL || zphone == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\D"); return FALSE; } fquote = fcsend_debug (fquote, (size_t) 0, "\\D"); if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, &fquote)) { ucsend_debug_end (fquote, TRUE); return FALSE; } break; case 'T': if (qdial == NULL || zphone == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\T"); return FALSE; } fquote = fcsend_debug (fquote, (size_t) 0, "\\T"); if (! fcphone (qconn, puuconf, qdial, zphone, pfwrite, TRUE, &fquote)) { ucsend_debug_end (fquote, TRUE); return FALSE; } break; case 'M': if (qdial == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\M"); return FALSE; } fquote = fcsend_debug (fquote, (size_t) 0, "ignore-carrier"); if (! fconn_carrier (qconn, FALSE)) { ucsend_debug_end (fquote, TRUE); return FALSE; } break; case 'm': if (qdial == NULL) { ucsend_debug_end (fquote, TRUE); ulog (LOG_ERROR, "Illegal use of \\m"); return FALSE; } if (qdial->uuconf_fcarrier) { fquote = fcsend_debug (fquote, (size_t) 0, "need-carrier"); if (! fconn_carrier (qconn, TRUE)) { ucsend_debug_end (fquote, TRUE); return FALSE; } } break; default: /* This error message will screw up any debugging information, but it's easily avoidable. */ ulog (LOG_ERROR, "Unrecognized escape sequence \\%c in send string", *z); fsend = TRUE; bsend = *z; break; } ++z; break; #if DEBUG > 0 default: ulog (LOG_FATAL, "fcsend: Can't happen"); break; #endif } if (fsend) { fquote = fcsend_debug (fquote, (size_t) 1, &bsend); if (! (*pfwrite) (qconn, &bsend, (size_t) 1)) { ucsend_debug_end (fquote, TRUE); return FALSE; } } } xfree ((pointer) zcallout_login); xfree ((pointer) zcallout_pass); /* Output a final carriage return, unless there was a \c. Don't bother to check for an echo. */ if (! fnocr) { char b; b = '\r'; fquote = fcsend_debug (fquote, (size_t) 1, &b); if (! fconn_write (qconn, &b, (size_t) 1)) { ucsend_debug_end (fquote, TRUE); return FALSE; } } ucsend_debug_end (fquote, FALSE); return TRUE; } /* Write out a phone number with optional dialcode translation. The pfquote argument is only used for debugging. */ static boolean fcphone (qconn, puuconf, qdial, zphone, pfwrite, ftranslate, pfquote) struct sconnection *qconn; pointer puuconf; const struct uuconf_dialer *qdial; const char *zphone; boolean (*pfwrite) P((struct sconnection *qc, const char *zwrite, size_t cwrite)); boolean ftranslate; boolean *pfquote; { const char *zprefix, *zsuffix; if (ftranslate) { if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix)) return FALSE; } else { zprefix = zphone; zsuffix = NULL; } while (zprefix != NULL) { while (TRUE) { const char *z; const char *zstr; z = zprefix + strcspn ((char *) zprefix, "=-"); if (z > zprefix) { size_t clen; clen = z - zprefix; *pfquote = fcsend_debug (*pfquote, clen, zprefix); if (! (*pfwrite) (qconn, zprefix, clen)) return FALSE; } if (*z == '=') zstr = qdial->uuconf_zdialtone; else if (*z == '-') zstr = qdial->uuconf_zpause; else /* *z == '\0' */ break; if (zstr != NULL) { *pfquote = fcsend_debug (*pfquote, strlen (zstr), zstr); if (! (*pfwrite) (qconn, zstr, strlen (zstr))) return FALSE; } zprefix = z + 1; } zprefix = zsuffix; zsuffix = NULL; } return TRUE; } /* Given a phone number, run it through dial code translation returning two strings. */ static boolean fctranslate (puuconf, zphone, pzprefix, pzsuffix) pointer puuconf; const char *zphone; const char **pzprefix; const char **pzsuffix; { int iuuconf; char *zdialcode, *zto; const char *zfrom; char *ztrans; *pzprefix = zphone; *pzsuffix = NULL; zdialcode = zbufalc (strlen (zphone) + 1); zfrom = zphone; zto = zdialcode; while (*zfrom != '\0' && isalpha (BUCHAR (*zfrom))) *zto++ = *zfrom++; *zto = '\0'; if (*zdialcode == '\0') { ubuffree (zdialcode); return TRUE; } iuuconf = uuconf_dialcode (puuconf, zdialcode, &ztrans); ubuffree (zdialcode); if (iuuconf == UUCONF_NOT_FOUND) return TRUE; else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } else { /* We really should figure out a way to free up ztrans here. */ *pzprefix = ztrans; *pzsuffix = zfrom; return TRUE; } } /* Write out a string making sure the each character is echoed back. There are two versions of this function, one which strips the parity bit from the characters and one which does not. This is so that I can use a single function pointer in fcsend, and to avoid using any static variables so that I can put chat scripts in a library some day. */ static boolean fcecho_send_strip (qconn, zwrite, cwrite) struct sconnection *qconn; const char *zwrite; size_t cwrite; { return fcecho_send (qconn, zwrite, cwrite, TRUE); } static boolean fcecho_send_nostrip (qconn, zwrite, cwrite) struct sconnection *qconn; const char *zwrite; size_t cwrite; { return fcecho_send (qconn, zwrite, cwrite, FALSE); } static boolean fcecho_send (qconn, zwrite, cwrite, fstrip) struct sconnection *qconn; const char *zwrite; size_t cwrite; boolean fstrip; { const char *zend; zend = zwrite + cwrite; for (; zwrite < zend; zwrite++) { int b; char bwrite; bwrite = *zwrite; if (! fconn_write (qconn, &bwrite, (size_t) 1)) return FALSE; if (fstrip) bwrite &= 0x7f; do { /* We arbitrarily wait five seconds for the echo. */ b = breceive_char (qconn, 5, TRUE); /* Now b == -1 on timeout, -2 on error. */ if (b < 0) { if (b == -1) ulog (LOG_ERROR, "Character not echoed"); return FALSE; } if (fstrip) b &= 0x7f; } while (b != BUCHAR (bwrite)); } return TRUE; } /* Run a chat program. Expand any escape sequences and call a system dependent program to run it. */ static boolean fcprogram (qconn, puuconf, pzprogram, qsys, qdial, zphone, zport, ibaud) struct sconnection *qconn; pointer puuconf; char **pzprogram; const struct uuconf_system *qsys; const struct uuconf_dialer *qdial; const char *zphone; const char *zport; long ibaud; { size_t cargs; char **pzpass, **pzarg; char **pz; char *zcallout_login; char *zcallout_pass; boolean fret; cargs = 1; for (pz = pzprogram; *pz != NULL; pz++) ++cargs; pzpass = (char **) xmalloc (cargs * sizeof (char *)); zcallout_login = NULL; zcallout_pass = NULL; fret = TRUE; /* Copy the string into memory expanding escape sequences. */ for (pz = pzprogram, pzarg = pzpass; *pz != NULL; pz++, pzarg++) { const char *zfrom; size_t calc, clen; char *zto; if (strchr (*pz, '\\') == NULL) { *pzarg = zbufcpy (*pz); continue; } *pzarg = NULL; zto = NULL; calc = 0; clen = 0; for (zfrom = *pz; *zfrom != '\0'; zfrom++) { const char *zadd = NULL; size_t cadd; char abadd[15]; if (*zfrom != '\\') { if (clen + 2 > calc) { char *znew; calc = clen + 50; znew = zbufalc (calc); memcpy (znew, *pzarg, clen); ubuffree (*pzarg); *pzarg = znew; zto = znew + clen; } *zto++ = *zfrom; ++clen; continue; } ++zfrom; switch (*zfrom) { case '\0': --zfrom; /* Fall through. */ case '\\': zadd = "\\"; break; case 'L': { const char *zlog; if (qsys == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\L"); fret = FALSE; break; } zlog = qsys->uuconf_zcall_login; if (zlog == NULL) { ulog (LOG_ERROR, "chat-program: No login defined"); fret = FALSE; break; } if (zlog[0] == '*' && zlog[1] == '\0') { if (zcallout_login == NULL) { int iuuconf; iuuconf = uuconf_callout (puuconf, qsys, &zcallout_login, &zcallout_pass); if (iuuconf == UUCONF_NOT_FOUND || zcallout_login == NULL) { ulog (LOG_ERROR, "chat-program: No login defined"); fret = FALSE; break; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } } zlog = zcallout_login; } zadd = zlog; } break; case 'P': { const char *zpass; if (qsys == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\P"); fret = FALSE; break; } zpass = qsys->uuconf_zcall_password; if (zpass == NULL) { ulog (LOG_ERROR, "chat-program: No password defined"); fret = FALSE; break; } if (zpass[0] == '*' && zpass[1] == '\0') { if (zcallout_pass == NULL) { int iuuconf; iuuconf = uuconf_callout (puuconf, qsys, &zcallout_login, &zcallout_pass); if (iuuconf == UUCONF_NOT_FOUND || zcallout_pass == NULL) { ulog (LOG_ERROR, "chat-program: No password defined"); fret = FALSE; break; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } } zpass = zcallout_pass; } zadd = zpass; } break; case 'D': if (qdial == NULL || zphone == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\D"); fret = FALSE; break; } zadd = zphone; break; case 'T': { const char *zprefix, *zsuffix; if (qdial == NULL || zphone == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\T"); fret = FALSE; break; } if (! fctranslate (puuconf, zphone, &zprefix, &zsuffix)) { fret = FALSE; break; } if (zsuffix == NULL) zadd = zprefix; else { size_t cprefix; cprefix = strlen (zprefix); if (clen + cprefix + 1 > calc) { char *znew; calc = clen + cprefix + 20; znew = zbufalc (calc); memcpy (znew, *pzarg, clen); ubuffree (*pzarg); *pzarg = znew; zto = znew + clen; } memcpy (zto, zprefix, cprefix); zto += cprefix; clen += cprefix; zadd = zsuffix; } } break; case 'Y': if (zLdevice == NULL && zport == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\Y"); fret = FALSE; break; } /* zLdevice will generally make more sense than zport, but it might not be set yet. */ zadd = zLdevice; if (zadd == NULL) zadd = zport; break; case 'Z': if (qsys == NULL) { ulog (LOG_ERROR, "chat-program: Illegal use of \\Z"); fret = FALSE; break; } zadd = qsys->uuconf_zname; break; case 'S': { if (ibaud == 0) { ulog (LOG_ERROR, "chat-program: Illegal use of \\S"); fret = FALSE; break; } sprintf (abadd, "%ld", ibaud); zadd = abadd; } break; default: { ulog (LOG_ERROR, "chat-program: Unrecognized escape sequence \\%c", *zfrom); abadd[0] = *zfrom; abadd[1] = '\0'; zadd = abadd; } break; } if (! fret) break; cadd = strlen (zadd); if (clen + cadd + 1 > calc) { char *znew; calc = clen + cadd + 20; znew = zbufalc (calc); memcpy (znew, *pzarg, clen); ubuffree (*pzarg); *pzarg = znew; zto = znew + clen; } memcpy (zto, zadd, cadd + 1); zto += cadd; clen += cadd; } if (! fret) break; *zto++ = '\0'; ++clen; } *pzarg = NULL; if (fret) fret = fconn_run_chat (qconn, pzpass); for (pz = pzpass; *pz != NULL; pz++) ubuffree (*pz); xfree ((pointer) pzpass); xfree ((pointer) zcallout_login); xfree ((pointer) zcallout_pass); return fret; } return FALSE; } } ucsend_debug_end (fquote, FALSE); return TRUE; } /* Write out a phone number with optional dialcode translation. The pfquote argument isuucp-1.04/conf.h.in1004440004150000170000004345405337263502011076 037777777777 1 0 /* 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 undefined /* Set ECHO_PROGRAM to a program which echoes its arguments; if echo is a shell builtin you can just use "echo". */ #define ECHO_PROGRAM undefined /* 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 0 /* */ #define HAVE_STRING_H 0 /* */ #define HAVE_STRINGS_H 0 /* */ #define HAVE_UNISTD_H 0 /* */ #define HAVE_STDLIB_H 0 /* */ #define HAVE_LIMITS_H 0 /* */ #define HAVE_TIME_H 0 /* */ #define HAVE_SYS_WAIT_H 0 /* */ #define HAVE_SYS_IOCTL_H 0 /* */ #define HAVE_DIRENT_H 0 /* */ #define HAVE_MEMORY_H 0 /* */ #define HAVE_SYS_PARAM_H 0 /* */ #define HAVE_UTIME_H 0 /* */ #define HAVE_FCNTL_H 0 /* */ #define HAVE_SYS_FILE_H 0 /* */ #define HAVE_SYS_TIMES_H 0 /* */ #define HAVE_LIBC_H 0 /* */ #define HAVE_SYSEXITS_H 0 /* */ #define HAVE_POLL_H 0 /* */ #define HAVE_TIUSER_H 0 /* */ #define HAVE_XTI_H 0 /* */ #define HAVE_SYS_TLI_H 0 /* */ #define HAVE_STROPTS_H 0 /* */ #define HAVE_FTW_H 0 /* */ #define HAVE_GLOB_H 0 /* */ #define HAVE_SYS_SELECT_H 0 /* */ #define HAVE_SYS_TYPES_TCP_H 0 /* */ /* If major and minor are not defined in , but are in , set MAJOR_IN_MKDEV to 1. If they are in , set MAJOR_IN_SYSMACROS to 1. */ #define MAJOR_IN_MKDEV 0 #define MAJOR_IN_SYSMACROS 0 /* If the macro offsetof is not defined in , you may give it a definition here. If you do not, the code will use a definition (in uucp.h) that should be fairly portable. */ /* #define offsetof */ /* Set RETSIGTYPE to the return type of a signal handler. On newer systems this will be void; some older systems use int. */ #define RETSIGTYPE void /* Set HAVE_SYS_TIME_AND_TIME_H to 1 if and can both be included in a single source file; if you don't have either or both of them, it doesn't matter what you set this to. */ #define HAVE_SYS_TIME_AND_TIME_H 0 /* Set HAVE_TERMIOS_AND_SYS_IOCTL_H to 1 if and can both be included in a single source file; if you don't have either or both of them, it doesn't matter what you set this to. */ #define HAVE_TERMIOS_AND_SYS_IOCTL_H 0 /* 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 0 /* The package needs several standard types. If you are using the configure script, it will look in standard places for these types, and give default definitions for them here if it doesn't find them. The default definitions should work on most systems, but you may want to check them. If you are configuring by hand, you will have to figure out whether the types are defined on your system, and what they should be defined to. Any type that is not defined on your system should get a macro definition. The definition should be of the name of the type in all capital letters. For example, #define PID_T int. If the type is defined in a standard header file, the macro name should not be defined. */ /* The type pid_t is used to hold a process ID number. It is normally defined in . This is the type returned by the functions fork or getpid. Usually int will work fine. */ #undef PID_T /* The type uid_t is used to hold a user ID number. It is normally defined in . This is the type returned by the getuid function. Usually int will work fine. */ #undef UID_T /* The type gid_t is used to hold a group ID number. It is sometimes defined in . This is the type returned by the getgid function. Usually int will work fine. */ #undef GID_T /* The type off_t is used to hold an offset in a file. It is sometimes defined in . This is the type of the second argument to the lseek function. Usually long will work fine. */ #undef OFF_T /* Set HAVE_SIG_ATOMIC_T_IN_SIGNAL_H if the type sig_atomic_t is defined in as required by ANSI C. */ #define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 0 /* Set HAVE_SIG_ATOMIC_T_IN_TYPES_H if the type sig_atomic_t is defined in . This is ignored if HAVE_SIG_ATOMIC_T_IN_SIGNAL_H is set to 1. */ #define HAVE_SIG_ATOMIC_T_IN_TYPES_H 0 /* The type sig_atomic_t is used to hold a value which may be referenced in a single atomic operation. If it is not defined in either or , you may want to give it a definition here. If you don't, the code will use char. If your compiler does not support sig_atomic_t, there is no type which is really correct; fortunately, for this package it does not really matter very much. */ #undef SIG_ATOMIC_T /* Set HAVE_SIZE_T_IN_STDDEF_H to 1 if the type size_t is defined in as required by ANSI C. */ #define HAVE_SIZE_T_IN_STDDEF_H 0 /* Set HAVE_SIZE_T_IN_TYPES_H to 1 if the type size_t is defined in . This is ignored if HAVE_SIZE_T_IN_STDDEF_H is set to 1. */ #define HAVE_SIZE_T_IN_TYPES_H 0 /* The type size_t is used to hold the size of an object. In particular, an argument of this type is passed as the size argument to the malloc and realloc functions. If size_t is not defined in either or , you may want to give it a definition here. If you don't, the code will use unsigned. */ #undef SIZE_T /* Set HAVE_TIME_T_IN_TIME_H to 1 if the type time_t is defined in , as required by the ANSI C standard. */ #define HAVE_TIME_T_IN_TIME_H 0 /* Set HAVE_TIME_T_IN_TYPES_H to 1 if the type time_t is defined in . This is ignored if HAVE_TIME_T_IN_TIME_H is set to 1. */ #define HAVE_TIME_T_IN_TYPES_H 0 /* 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 0 #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 0 /* Set HAVE_UNSIGNED_CHAR to 1 if the compiler supports the type unsigned char. */ #define HAVE_UNSIGNED_CHAR 0 /* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in . */ #define HAVE_ERRNO_DECLARATION 0 /* 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 0 #define HAVE_FTRUNCATE 0 #define HAVE_LTRUNC 0 #define HAVE_WAITPID 0 #define HAVE_WAIT4 0 #define HAVE_GLOB 0 #define HAVE_SETREUID 0 /* 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 0 /* bsrch.o */ #define HAVE_GETLINE 0 /* getlin.o */ #define HAVE_MEMCHR 0 /* memchr.o */ #define HAVE_STRDUP 0 /* strdup.o */ #define HAVE_STRSTR 0 /* strstr.o */ #define HAVE_STRTOL 0 /* strtol.o */ /* If neither of these functions exists, you should add bzero.o to lib/Makefile. */ #define HAVE_BZERO 0 #define HAVE_MEMSET 0 /* If neither of these functions exists, you should add memcmp.o to lib/Makefile. */ #define HAVE_MEMCMP 0 #define HAVE_BCMP 0 /* If neither of these functions exists, you should add memcpy.o to lib/Makefile. */ #define HAVE_MEMCPY 0 #define HAVE_BCOPY 0 /* If neither of these functions exists, you should add strcas.o to lib/Makefile. */ #define HAVE_STRCASECMP 0 #define HAVE_STRICMP 0 /* If neither of these functions exists, you should add strncs.o to lib/Makefile. */ #define HAVE_STRNCASECMP 0 #define HAVE_STRNICMP 0 /* If neither of these functions exists, you should add strchr.o to lib/Makefile. */ #define HAVE_STRCHR 0 #define HAVE_INDEX 0 /* If neither of these functions exists, you should add strrch.o to lib/Makefile. */ #define HAVE_STRRCHR 0 #define HAVE_RINDEX 0 /* 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 0 /* dirent.o */ #define HAVE_DUP2 0 /* dup2.o */ #define HAVE_FTW 0 /* ftw.o */ #define HAVE_REMOVE 0 /* remove.o */ #define HAVE_RENAME 0 /* rename.o */ #define HAVE_STRERROR 0 /* 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 0 #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 0 #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 0 #define HAVE_GETWD 0 #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 0 #define HAVE_SIGVEC 0 #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 0 /* 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 0 #define HAVE_SIGBLOCK 0 #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 0 #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 0 #define HAVE_SETSID 0 /* 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 0 #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 0 #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 0 /* 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 0 #define HAVE_POLL 0 #define HAVE_SELECT 0 /* 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 0 /* If the socket function is available, TCP support code will be compiled in. */ #define HAVE_SOCKET 0 /* 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 0 /* extern struct passwd *getpwuid (); */ #define GETPWUID_DECLARATION_OK 0 /* extern struct group *getgrent (); */ #define GETGRENT_DECLARATION_OK 0 /* Set HAVE_BSD_PGRP to 1 if your getpgrp call takes 1 argument and your setpgrp calls takes 2 arguments (on System V they generally take no arguments). You can safely set this to 1 on System V, provided the call will compile without any errors. */ #define HAVE_BSD_PGRP 0 /* Set HAVE_UNION_WAIT to 1 if union wait is defined in the header file . */ #define HAVE_UNION_WAIT 0 /* Set HAVE_LONG_FILE_NAMES to 1 if the system supports file names longer than 14 characters. */ #define HAVE_LONG_FILE_NAMES 0 /* If slow system calls are restarted after interrupts, set HAVE_RESTARTABLE_SYSCALLS to 1. This is ignored if HAVE_SIGACTION is 1 or if HAVE_SIGVEC is 1 and HAVE_SIGVEC_SV_FLAGS is 1 and SV_INTERRUPT is defined in . In both of these cases system calls can be prevented from restarting. */ #define HAVE_RESTARTABLE_SYSCALLS 0 /* 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 ports the type unsigned char. */ #define HAVE_UNSIGNED_CHAR 0 /* Set HAVE_ERRNO_DECLARATION to 1 if errno is declared in . */ #define HAVE_ERRNO_DECLARATION 0 /* There are now a number of functionuucp-1.04/configure1007750004150000170000015301705337263764011315 037777777777 1 0 #!/bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf. # Copyright (C) 1991, 1992, 1993 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. # Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] # [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET] # Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and # --with-PACKAGE unless this script has special code to handle it. for arg do # Handle --exec-prefix with a space before the argument. if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= # Handle --host with a space before the argument. elif test x$next_host = xyes; then next_host= # Handle --prefix with a space before the argument. elif test x$next_prefix = xyes; then prefix=$arg; next_prefix= # Handle --srcdir with a space before the argument. elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= else case $arg in # For backward compatibility, also recognize exact --exec_prefix. -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*) exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e) next_exec_prefix=yes ;; -gas | --gas | --ga | --g) ;; -host=* | --host=* | --hos=* | --ho=* | --h=*) ;; -host | --host | --hos | --ho | --h) next_host=yes ;; -nfp | --nfp | --nf) ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no) no_create=1 ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) next_prefix=yes ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*) srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) next_srcdir=yes ;; -with-* | --with-*) package=`echo $arg|sed 's/-*with-//'` # Delete all the valid chars; see if any are left. if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then echo "configure: $package: invalid package name" >&2; exit 1 fi eval "with_`echo $package|sed s/-/_/g`=1" ;; *) ;; esac fi done trap 'rm -f conftest* core; exit 1' 1 3 15 rm -f conftest* compile='${CC-cc} $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. unique_file=policy.h # Find the source files, if location was not specified. if test -z "$srcdir"; then srcdirdefaulted=yes # Try the directory containing this script, then `..'. prog=$0 confdir=`echo $prog|sed 's%/[^/][^/]*$%%'` test "X$confdir" = "X$prog" && confdir=. srcdir=$confdir if test ! -r $srcdir/$unique_file; then srcdir=.. fi fi if test ! -r $srcdir/$unique_file; then if test x$srcdirdefaulted = xyes; then echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2 else echo "configure: Can not find sources in \`${srcdir}'." 1>&2 fi exit 1 fi # Preserve a srcdir of `.' to avoid automounter screwups with pwd. # But we can't avoid them for `..', to make subdirectories work. case $srcdir in .|/*|~*) ;; *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute. esac compile='rm -f conftest.t; mv conftest.c conftest.t; echo "$DEFS" > conftest.c; cat conftest.t >> conftest.c; rm -f conftest.t; ${CC-cc} conftest.c -o conftest $LIBS >/dev/null 2>&1' if test -z "$CC"; then echo checking for gcc saveifs="$IFS"; IFS="${IFS}:" for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/gcc; then CC="gcc" break fi done IFS="$saveifs" fi test -z "$CC" && CC="cc" # Find out if we are using GNU C, under whatever name. cat > conftest.c < conftest.out 2>&1 if egrep yes conftest.out >/dev/null 2>&1; then GCC=1 # For later tests. fi rm -f conftest* echo checking how to run the C preprocessor if test -z "$CPP"; then CPP='${CC-cc} -E' cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then : else CPP=/lib/cpp fi rm -f conftest* fi if test -n "$GCC"; then echo checking whether -traditional is needed pattern="Autoconf.*'x'" prog='#include Autoconf TIOCGETP' cat > conftest.c < conftest.out 2>&1" if egrep "$pattern" conftest.out >/dev/null 2>&1; then need_trad=1 fi rm -f conftest* if test -z "$need_trad"; then prog='#include Autoconf TCGETA' cat > conftest.c < conftest.out 2>&1" if egrep "$pattern" conftest.out >/dev/null 2>&1; then need_trad=1 fi rm -f conftest* fi test -n "$need_trad" && CC="$CC -traditional" fi # Make sure to not get the incompatible SysV /etc/install and # /usr/sbin/install, which might be in PATH before a BSD-like install, # or the SunOS /usr/etc/install directory, or the AIX /bin/install, # or the AFS install, which mishandles nonexistent args. (Sigh.) if test -z "$INSTALL"; then echo checking for install saveifs="$IFS"; IFS="${IFS}:" for dir in $PATH; do test -z "$dir" && dir=. case $dir in /etc|/usr/sbin|/usr/etc|/usr/afsws/bin) ;; *) if test -f $dir/install; then if grep dspmsg $dir/install >/dev/null 2>&1; then : # AIX else INSTALL="$dir/install -c" INSTALL_PROGRAM='$(INSTALL)' INSTALL_DATA='$(INSTALL) -m 644' break fi fi ;; esac done IFS="$saveifs" fi INSTALL=${INSTALL-cp} INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'} INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'} if test -z "$RANLIB"; then echo checking for ranlib saveifs="$IFS"; IFS="${IFS}:" for dir in $PATH; do test -z "$dir" && dir=. if test -f $dir/ranlib; then RANLIB="ranlib" break fi done IFS="$saveifs" fi test -z "$RANLIB" && RANLIB="@:" echo checking for POSIXized ISC if test -d /etc/conf/kconfig.d && grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 then ISC=1 # If later tests want to check for ISC. DEFS="${DEFS}#define _POSIX_SOURCE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_SOURCE\${SEDdB}_POSIX_SOURCE\${SEDdC}1\${SEDdD} \${SEDuA}_POSIX_SOURCE\${SEDuB}_POSIX_SOURCE\${SEDuC}1\${SEDuD} \${SEDeA}_POSIX_SOURCE\${SEDeB}_POSIX_SOURCE\${SEDeC}1\${SEDeD} " if test -n "$GCC"; then CC="$CC -posix" else CC="$CC -Xp" fi fi echo checking for minix/config.h cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then MINIX=1 fi rm -f conftest* # The Minix shell can't assign to the same variable on the same line! if test -n "$MINIX"; then DEFS="${DEFS}#define _POSIX_SOURCE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_SOURCE\${SEDdB}_POSIX_SOURCE\${SEDdC}1\${SEDdD} \${SEDuA}_POSIX_SOURCE\${SEDuB}_POSIX_SOURCE\${SEDuC}1\${SEDuD} \${SEDeA}_POSIX_SOURCE\${SEDeB}_POSIX_SOURCE\${SEDeC}1\${SEDeD} " DEFS="${DEFS}#define _POSIX_1_SOURCE 2 " SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_1_SOURCE\${SEDdB}_POSIX_1_SOURCE\${SEDdC}2\${SEDdD} \${SEDuA}_POSIX_1_SOURCE\${SEDuB}_POSIX_1_SOURCE\${SEDuC}2\${SEDuD} \${SEDeA}_POSIX_1_SOURCE\${SEDeB}_POSIX_1_SOURCE\${SEDeC}2\${SEDeD} " DEFS="${DEFS}#define _MINIX 1 " SEDDEFS="${SEDDEFS}\${SEDdA}_MINIX\${SEDdB}_MINIX\${SEDdC}1\${SEDdD} \${SEDuA}_MINIX\${SEDuB}_MINIX\${SEDuC}1\${SEDuD} \${SEDeA}_MINIX\${SEDeB}_MINIX\${SEDeC}1\${SEDeD} " fi echo checking for AIX cat > conftest.c < conftest.out 2>&1" if egrep "yes" conftest.out >/dev/null 2>&1; then DEFS="${DEFS}#define _ALL_SOURCE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}_ALL_SOURCE\${SEDdB}_ALL_SOURCE\${SEDdC}1\${SEDdD} \${SEDuA}_ALL_SOURCE\${SEDuB}_ALL_SOURCE\${SEDuC}1\${SEDuD} \${SEDeA}_ALL_SOURCE\${SEDeB}_ALL_SOURCE\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for DYNIX/ptx libseq cat > conftest.c < conftest.out 2>&1" if egrep "yes" conftest.out >/dev/null 2>&1; then SEQUENT=1 fi rm -f conftest* test -n "$SEQUENT" && test -f /usr/lib/libseq.a && LIBS="$LIBS -lseq" echo checking for IRIX libsun if test -f /usr/lib/libsun.a; then LIBS="$LIBS -lsun" fi echo checking whether cross-compiling # If we cannot run a trivial program, we must be cross compiling. cat > conftest.c </dev/null; then : else cross_compiling=1 fi rm -f conftest* CFLAGS=${CFLAGS--g} echo checking for mail program if test -s /usr/ucb/mail; then DEFS="${DEFS}#define MAIL_PROGRAM `echo '"/usr/ucb/mail"'` " SEDDEFS="${SEDDEFS}\${SEDdA}MAIL_PROGRAM\${SEDdB}MAIL_PROGRAM\${SEDdC}`echo '"/usr/ucb/mail"'`\${SEDdD} \${SEDuA}MAIL_PROGRAM\${SEDuB}MAIL_PROGRAM\${SEDuC}`echo '"/usr/ucb/mail"'`\${SEDuD} \${SEDeA}MAIL_PROGRAM\${SEDeB}MAIL_PROGRAM\${SEDeC}`echo '"/usr/ucb/mail"'`\${SEDeD} " elif test -s /bin/mail; then DEFS="${DEFS}#define MAIL_PROGRAM `echo '"/bin/mail"'` " SEDDEFS="${SEDDEFS}\${SEDdA}MAIL_PROGRAM\${SEDdB}MAIL_PROGRAM\${SEDdC}`echo '"/bin/mail"'`\${SEDdD} \${SEDuA}MAIL_PROGRAM\${SEDuB}MAIL_PROGRAM\${SEDuC}`echo '"/bin/mail"'`\${SEDuD} \${SEDeA}MAIL_PROGRAM\${SEDeB}MAIL_PROGRAM\${SEDeC}`echo '"/bin/mail"'`\${SEDeD} " elif test -s /usr/bin/mail; then DEFS="${DEFS}#define MAIL_PROGRAM `echo '"/usr/bin/mail"'` " SEDDEFS="${SEDDEFS}\${SEDdA}MAIL_PROGRAM\${SEDdB}MAIL_PROGRAM\${SEDdC}`echo '"/usr/bin/mail"'`\${SEDdD} \${SEDuA}MAIL_PROGRAM\${SEDuB}MAIL_PROGRAM\${SEDuC}`echo '"/usr/bin/mail"'`\${SEDuD} \${SEDeA}MAIL_PROGRAM\${SEDeB}MAIL_PROGRAM\${SEDeC}`echo '"/usr/bin/mail"'`\${SEDeD} " elif test -s /usr/bin/mailx; then DEFS="${DEFS}#define MAIL_PROGRAM `echo '"/usr/bin/mailx"'` " SEDDEFS="${SEDDEFS}\${SEDdA}MAIL_PROGRAM\${SEDdB}MAIL_PROGRAM\${SEDdC}`echo '"/usr/bin/mailx"'`\${SEDdD} \${SEDuA}MAIL_PROGRAM\${SEDuB}MAIL_PROGRAM\${SEDuC}`echo '"/usr/bin/mailx"'`\${SEDuD} \${SEDeA}MAIL_PROGRAM\${SEDeB}MAIL_PROGRAM\${SEDeC}`echo '"/usr/bin/mailx"'`\${SEDeD} " fi echo checking for echo program if (PATH= echo test) 2>/dev/null | grep test >/dev/null 2>&1; then DEFS="${DEFS}#define ECHO_PROGRAM `echo '"echo"'` " SEDDEFS="${SEDDEFS}\${SEDdA}ECHO_PROGRAM\${SEDdB}ECHO_PROGRAM\${SEDdC}`echo '"echo"'`\${SEDdD} \${SEDuA}ECHO_PROGRAM\${SEDuB}ECHO_PROGRAM\${SEDuC}`echo '"echo"'`\${SEDuD} \${SEDeA}ECHO_PROGRAM\${SEDeB}ECHO_PROGRAM\${SEDeC}`echo '"echo"'`\${SEDeD} " elif test -s /bin/echo; then DEFS="${DEFS}#define ECHO_PROGRAM `echo '"/bin/echo"'` " SEDDEFS="${SEDDEFS}\${SEDdA}ECHO_PROGRAM\${SEDdB}ECHO_PROGRAM\${SEDdC}`echo '"/bin/echo"'`\${SEDdD} \${SEDuA}ECHO_PROGRAM\${SEDuB}ECHO_PROGRAM\${SEDuC}`echo '"/bin/echo"'`\${SEDuD} \${SEDeA}ECHO_PROGRAM\${SEDeB}ECHO_PROGRAM\${SEDeC}`echo '"/bin/echo"'`\${SEDeD} " fi echo checking for ln -s rm -f conftestdata if ln -s X conftestdata 2>/dev/null then rm -f conftestdata LN_S="ln -s" else LN_S=ln fi for hdr in stddef.h string.h strings.h unistd.h stdlib.h limits.h do trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` echo checking for ${hdr} cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define ${trhdr} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} \${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} \${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} " fi rm -f conftest* done for hdr in time.h sys/wait.h sys/ioctl.h dirent.h memory.h sys/param.h do trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` echo checking for ${hdr} cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define ${trhdr} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} \${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} \${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} " fi rm -f conftest* done for hdr in utime.h fcntl.h sys/file.h sys/times.h libc.h sysexits.h do trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` echo checking for ${hdr} cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define ${trhdr} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} \${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} \${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} " fi rm -f conftest* done for hdr in poll.h tiuser.h xti.h sys/tli.h stropts.h ftw.h glob.h do trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` echo checking for ${hdr} cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define ${trhdr} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} \${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} \${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} " fi rm -f conftest* done for hdr in sys/types.tcp.h do trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` echo checking for ${hdr} cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define ${trhdr} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} \${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} \${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} " fi rm -f conftest* done echo checking for sys/select.h cat > conftest.c < #include main() { exit(0); } t() { int i; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SYS_SELECT_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SYS_SELECT_H\${SEDdB}HAVE_SYS_SELECT_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SYS_SELECT_H\${SEDuB}HAVE_SYS_SELECT_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SYS_SELECT_H\${SEDeB}HAVE_SYS_SELECT_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for major, minor and makedev header cat > conftest.c < main() { exit(0); } t() { return makedev(0, 0); } EOF if eval $compile; then makedev=1 fi rm -f conftest* if test -z "$makedev"; then echo checking for sys/mkdev.h cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define MAJOR_IN_MKDEV 1 " SEDDEFS="${SEDDEFS}\${SEDdA}MAJOR_IN_MKDEV\${SEDdB}MAJOR_IN_MKDEV\${SEDdC}1\${SEDdD} \${SEDuA}MAJOR_IN_MKDEV\${SEDuB}MAJOR_IN_MKDEV\${SEDuC}1\${SEDuD} \${SEDeA}MAJOR_IN_MKDEV\${SEDeB}MAJOR_IN_MKDEV\${SEDeC}1\${SEDeD} " makedev=1 fi rm -f conftest* fi if test -z "$makedev"; then echo checking for sys/sysmacros.h cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define MAJOR_IN_SYSMACROS 1 " SEDDEFS="${SEDDEFS}\${SEDdA}MAJOR_IN_SYSMACROS\${SEDdB}MAJOR_IN_SYSMACROS\${SEDdC}1\${SEDdD} \${SEDuA}MAJOR_IN_SYSMACROS\${SEDuB}MAJOR_IN_SYSMACROS\${SEDuC}1\${SEDuD} \${SEDeA}MAJOR_IN_SYSMACROS\${SEDeB}MAJOR_IN_SYSMACROS\${SEDeC}1\${SEDeD} " fi rm -f conftest* fi echo checking for return type of signal handlers cat > conftest.c < #include #ifdef signal #undef signal #endif extern void (*signal ()) (); main() { exit(0); } t() { int i; } EOF if eval $compile; then DEFS="${DEFS}#define RETSIGTYPE void " SEDDEFS="${SEDDEFS}\${SEDdA}RETSIGTYPE\${SEDdB}RETSIGTYPE\${SEDdC}void\${SEDdD} \${SEDuA}RETSIGTYPE\${SEDuB}RETSIGTYPE\${SEDuC}void\${SEDuD} \${SEDeA}RETSIGTYPE\${SEDeB}RETSIGTYPE\${SEDeC}void\${SEDeD} " else DEFS="${DEFS}#define RETSIGTYPE int " SEDDEFS="${SEDDEFS}\${SEDdA}RETSIGTYPE\${SEDdB}RETSIGTYPE\${SEDdC}int\${SEDdD} \${SEDuA}RETSIGTYPE\${SEDuB}RETSIGTYPE\${SEDuC}int\${SEDuD} \${SEDeA}RETSIGTYPE\${SEDeB}RETSIGTYPE\${SEDeC}int\${SEDeD} " fi rm -f conftest* echo checking for time.h and sys/time.h being included together cat > conftest.c < #include main() { exit(0); } t() { int i; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SYS_TIME_AND_TIME_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SYS_TIME_AND_TIME_H\${SEDdB}HAVE_SYS_TIME_AND_TIME_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SYS_TIME_AND_TIME_H\${SEDuB}HAVE_SYS_TIME_AND_TIME_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SYS_TIME_AND_TIME_H\${SEDeB}HAVE_SYS_TIME_AND_TIME_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for termios.h and sys/ioctl.h being included together cat > conftest.c < #include main() { exit(0); } t() { int i; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_TERMIOS_AND_SYS_IOCTL_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDdB}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDuB}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDeB}HAVE_TERMIOS_AND_SYS_IOCTL_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for CBREAK cat > conftest.c < main() { exit(0); } t() { int i = CBREAK; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_CBREAK 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_CBREAK\${SEDdB}HAVE_CBREAK\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_CBREAK\${SEDuB}HAVE_CBREAK\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_CBREAK\${SEDeB}HAVE_CBREAK\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for pid_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { pid_t x; } EOF if eval $compile; then : else DEFS="${DEFS}#define PID_T int " SEDDEFS="${SEDDEFS}\${SEDdA}PID_T\${SEDdB}PID_T\${SEDdC}int\${SEDdD} \${SEDuA}PID_T\${SEDuB}PID_T\${SEDuC}int\${SEDuD} \${SEDeA}PID_T\${SEDeB}PID_T\${SEDeC}int\${SEDeD} " fi rm -f conftest* echo checking for uid_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { uid_t x; } EOF if eval $compile; then : else DEFS="${DEFS}#define UID_T int " SEDDEFS="${SEDDEFS}\${SEDdA}UID_T\${SEDdB}UID_T\${SEDdC}int\${SEDdD} \${SEDuA}UID_T\${SEDuB}UID_T\${SEDuC}int\${SEDuD} \${SEDeA}UID_T\${SEDeB}UID_T\${SEDeC}int\${SEDeD} " fi rm -f conftest* echo checking for gid_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { gid_t x; } EOF if eval $compile; then : else DEFS="${DEFS}#define GID_T int " SEDDEFS="${SEDDEFS}\${SEDdA}GID_T\${SEDdB}GID_T\${SEDdC}int\${SEDdD} \${SEDuA}GID_T\${SEDuB}GID_T\${SEDuC}int\${SEDuD} \${SEDeA}GID_T\${SEDeB}GID_T\${SEDeC}int\${SEDeD} " fi rm -f conftest* echo checking for off_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { off_t x; } EOF if eval $compile; then : else DEFS="${DEFS}#define OFF_T long " SEDDEFS="${SEDDEFS}\${SEDdA}OFF_T\${SEDdB}OFF_T\${SEDdC}long\${SEDdD} \${SEDuA}OFF_T\${SEDuB}OFF_T\${SEDuC}long\${SEDuD} \${SEDeA}OFF_T\${SEDeB}OFF_T\${SEDeC}long\${SEDeD} " fi rm -f conftest* echo checking for sig_atomic_t in signal.h cat > conftest.c < main() { exit(0); } t() { sig_atomic_t x; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SIG_ATOMIC_T_IN_SIGNAL_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDdB}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDuB}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDeB}HAVE_SIG_ATOMIC_T_IN_SIGNAL_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for sig_atomic_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { sig_atomic_t x; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SIG_ATOMIC_T_IN_TYPES_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDdB}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDuB}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDeB}HAVE_SIG_ATOMIC_T_IN_TYPES_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* case $DEFS in *HAVE_STDDEF_H*) echo checking for size_t in stddef.h cat > conftest.c < main() { exit(0); } t() { size_t x; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SIZE_T_IN_STDDEF_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SIZE_T_IN_STDDEF_H\${SEDdB}HAVE_SIZE_T_IN_STDDEF_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SIZE_T_IN_STDDEF_H\${SEDuB}HAVE_SIZE_T_IN_STDDEF_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SIZE_T_IN_STDDEF_H\${SEDeB}HAVE_SIZE_T_IN_STDDEF_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* ;; esac echo checking for size_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { size_t x; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SIZE_T_IN_TYPES_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SIZE_T_IN_TYPES_H\${SEDdB}HAVE_SIZE_T_IN_TYPES_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SIZE_T_IN_TYPES_H\${SEDuB}HAVE_SIZE_T_IN_TYPES_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SIZE_T_IN_TYPES_H\${SEDeB}HAVE_SIZE_T_IN_TYPES_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for time_t in time.h cat > conftest.c < main() { exit(0); } t() { time_t i; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_TIME_T_IN_TIME_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_TIME_T_IN_TIME_H\${SEDdB}HAVE_TIME_T_IN_TIME_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_TIME_T_IN_TIME_H\${SEDuB}HAVE_TIME_T_IN_TIME_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_TIME_T_IN_TIME_H\${SEDeB}HAVE_TIME_T_IN_TIME_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for time_t in sys/types.h cat > conftest.c < main() { exit(0); } t() { time_t i; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_TIME_T_IN_TYPES_H 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_TIME_T_IN_TYPES_H\${SEDdB}HAVE_TIME_T_IN_TYPES_H\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_TIME_T_IN_TYPES_H\${SEDuB}HAVE_TIME_T_IN_TYPES_H\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_TIME_T_IN_TYPES_H\${SEDeB}HAVE_TIME_T_IN_TYPES_H\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking how to get filesystem space usage # SVR4 cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define STAT_STATVFS 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATVFS\${SEDdB}STAT_STATVFS\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATVFS\${SEDuB}STAT_STATVFS\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATVFS\${SEDeB}STAT_STATVFS\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* if test -z "$space"; then # AIX echo "${DEFS}#include " > conftest.c eval "$CPP conftest.c > conftest.out 2>&1" if egrep "f_nlsdirtype" conftest.out >/dev/null 2>&1; then DEFS="${DEFS}#define STAT_STATFS2_BSIZE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATFS2_BSIZE\${SEDdB}STAT_STATFS2_BSIZE\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATFS2_BSIZE\${SEDuB}STAT_STATFS2_BSIZE\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATFS2_BSIZE\${SEDeB}STAT_STATFS2_BSIZE\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* fi if test -z "$space"; then # SVR3 cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define STAT_STATFS4 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATFS4\${SEDdB}STAT_STATFS4\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATFS4\${SEDuB}STAT_STATFS4\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATFS4\${SEDeB}STAT_STATFS4\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* fi if test -z "$space"; then # 4.3BSD cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define STAT_STATFS2_BSIZE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATFS2_BSIZE\${SEDdB}STAT_STATFS2_BSIZE\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATFS2_BSIZE\${SEDuB}STAT_STATFS2_BSIZE\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATFS2_BSIZE\${SEDeB}STAT_STATFS2_BSIZE\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* fi if test -z "$space"; then # 4.4BSD echo "${DEFS}#include " > conftest.c eval "$CPP conftest.c > conftest.out 2>&1" if egrep "MOUNT_UFS" conftest.out >/dev/null 2>&1; then DEFS="${DEFS}#define STAT_STATFS2_FSIZE 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATFS2_FSIZE\${SEDdB}STAT_STATFS2_FSIZE\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATFS2_FSIZE\${SEDuB}STAT_STATFS2_FSIZE\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATFS2_FSIZE\${SEDeB}STAT_STATFS2_FSIZE\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* fi if test -z "$space"; then # Ultrix cat > conftest.c < EOF err=`eval "$CPP conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="${DEFS}#define STAT_STATFS2_FS_DATA 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_STATFS2_FS_DATA\${SEDdB}STAT_STATFS2_FS_DATA\${SEDdC}1\${SEDdD} \${SEDuA}STAT_STATFS2_FS_DATA\${SEDuB}STAT_STATFS2_FS_DATA\${SEDuC}1\${SEDuD} \${SEDeA}STAT_STATFS2_FS_DATA\${SEDeB}STAT_STATFS2_FS_DATA\${SEDeC}1\${SEDeD} " space=1 fi rm -f conftest* fi if test -z "$space"; then echo checking for ustat cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_ustat choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ustat(); ustat(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define STAT_USTAT 1 " SEDDEFS="${SEDDEFS}\${SEDdA}STAT_USTAT\${SEDdB}STAT_USTAT\${SEDdC}1\${SEDdD} \${SEDuA}STAT_USTAT\${SEDuB}STAT_USTAT\${SEDuC}1\${SEDuD} \${SEDeA}STAT_USTAT\${SEDeB}STAT_USTAT\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif fi echo checking for void cat > conftest.c < conftest.c < conftest.c < main() { exit(0); } t() { int i = errno; errno = 1; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_ERRNO_DECLARATION 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_ERRNO_DECLARATION\${SEDdB}HAVE_ERRNO_DECLARATION\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_ERRNO_DECLARATION\${SEDuB}HAVE_ERRNO_DECLARATION\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_ERRNO_DECLARATION\${SEDeB}HAVE_ERRNO_DECLARATION\${SEDeC}1\${SEDeD} " fi rm -f conftest* for func in memset memcmp memchr memcpy bcopy bcmp bzero do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in strchr strrchr index rindex strerror strtol strstr do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in strdup strcasecmp strncasecmp stricmp strnicmp do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in bsearch vfprintf do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in remove ftruncate ltrunc rename opendir dup2 waitpid wait4 do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in sigsetjmp setret sigaction sigvec sigset do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in sigprocmask sigblock sighold getdtablesize sysconf do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in setpgrp setsid setreuid gethostname uname do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in gettimeofday ftw glob do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done SAVELIBS="$LIBS" LIBS=`echo $LIBS | sed 's/-linet//'` for func in getline do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done LIBS="$SAVELIBS" echo checking for ftime cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_ftime choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ftime(); ftime(); #endif } EOF if eval $compile; then if test -n "$cross_compiling" then DEFS="${DEFS}#define HAVE_FTIME 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_FTIME\${SEDdB}HAVE_FTIME\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_FTIME\${SEDuB}HAVE_FTIME\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_FTIME\${SEDeB}HAVE_FTIME\${SEDeC}1\${SEDeD} " else cat > conftest.c < #include main () { struct timeb s, slast; int c = 0; ftime (&slast); while (c < 10) { ftime (&s); if (s.time < slast.time || (s.time == slast.time && s.millitm < slast.millitm)) exit (1); if (s.time != slast.time) ++c; slast.time = s.time; slast.millitm = s.millitm; } exit (0); } EOF eval $compile if test -s conftest && (./conftest; exit) 2>/dev/null; then DEFS="${DEFS}#define HAVE_FTIME 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_FTIME\${SEDdB}HAVE_FTIME\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_FTIME\${SEDuB}HAVE_FTIME\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_FTIME\${SEDeB}HAVE_FTIME\${SEDeC}1\${SEDeD} " else echo 1>&2 "Your ftime seems to be buggy" fi fi rm -f conftest* fi rm -f conftest* #endif for func in times do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done for func in napms nap usleep poll select do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done case $DEFS in *HAVE_NAPMS*) ;; *HAVE_NAP*) ;; *HAVE_USLEEP*) ;; *HAVE_POLL*) ;; *HAVE_SELECT*) ;; *) echo 1>&2 'WARNING: No way to sleep for less than one second' echo 1>&2 ' \p in chat scripts will sleep for a full second' ;; esac for func in getgrent do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done trfrom='[a-z]' trto='[A-Z]' for i in socket t_open; do def=HAVE_`echo $i|tr "$trfrom" "$trto"` echo checking for $i cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_$i choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char $i(); $i(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define $def 1 " SEDDEFS="${SEDDEFS}\${SEDdA}$def\${SEDdB}$def\${SEDdC}1\${SEDdD} \${SEDuA}$def\${SEDuB}$def\${SEDuC}1\${SEDuD} \${SEDeA}$def\${SEDeB}$def\${SEDeC}1\${SEDeD} " else missing=1 fi rm -f conftest* #endif for lib in "-lsocket" "-lsocket -lnsl" "-lnsl" "-lxti"; do if test -n "$missing"; then case $LIBS in *${lib}*) ;; *) SAVELIBS="$LIBS" LIBS="$LIBS $lib" missing= echo checking for $i with $lib cat > conftest.c < conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done case $DEFS in *HAVE_GETCWD*) ;; *HAVE_GETCD*) ;; *) UNIXOBJS="$UNIXOBJS getcwd.o" if test -s /bin/pwd; then DEFS="${DEFS}#define PWD_PROGRAM `echo '"/bin/pwd"'` " SEDDEFS="${SEDDEFS}\${SEDdA}PWD_PROGRAM\${SEDdB}PWD_PROGRAM\${SEDdC}`echo '"/bin/pwd"'`\${SEDdD} \${SEDuA}PWD_PROGRAM\${SEDuB}PWD_PROGRAM\${SEDuC}`echo '"/bin/pwd"'`\${SEDuD} \${SEDeA}PWD_PROGRAM\${SEDeB}PWD_PROGRAM\${SEDeC}`echo '"/bin/pwd"'`\${SEDeD} " fi ;; esac for func in mkdir do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done case $DEFS in *HAVE_MKDIR*) UUDIR='# ' ;; *) UUDIR= UNIXOBJS="$UNIXOBJS mkdir.o" if test -s /bin/mkdir; then DEFS="${DEFS}#define MKDIR_PROGRAM `echo '"/bin/mkdir"'` " SEDDEFS="${SEDDEFS}\${SEDdA}MKDIR_PROGRAM\${SEDdB}MKDIR_PROGRAM\${SEDdC}`echo '"/bin/mkdir"'`\${SEDdD} \${SEDuA}MKDIR_PROGRAM\${SEDuB}MKDIR_PROGRAM\${SEDuC}`echo '"/bin/mkdir"'`\${SEDuD} \${SEDeA}MKDIR_PROGRAM\${SEDeB}MKDIR_PROGRAM\${SEDeC}`echo '"/bin/mkdir"'`\${SEDeD} " fi ;; esac for func in rmdir do trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} cat > conftest.c < main() { exit(0); } t() { #ifdef __stub_${func} choke me #else /* Override any gcc2 internal prototype to avoid an error. */ extern char ${func}(); ${func}(); #endif } EOF if eval $compile; then DEFS="${DEFS}#define ${trfunc} 1 " SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} \${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} \${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} " fi rm -f conftest* #endif done case $DEFS in *HAVE_RMDIR*) ;; *) UNIXOBJS="$UNIXOBJS rmdir.o" if test -s /bin/rmdir; then DEFS="${DEFS}#define RMDIR_PROGRAM `echo '"/bin/rmdir"'` " SEDDEFS="${SEDDEFS}\${SEDdA}RMDIR_PROGRAM\${SEDdB}RMDIR_PROGRAM\${SEDdC}`echo '"/bin/rmdir"'`\${SEDdD} \${SEDuA}RMDIR_PROGRAM\${SEDuB}RMDIR_PROGRAM\${SEDuC}`echo '"/bin/rmdir"'`\${SEDuD} \${SEDeA}RMDIR_PROGRAM\${SEDeB}RMDIR_PROGRAM\${SEDeC}`echo '"/bin/rmdir"'`\${SEDeD} " fi ;; esac case $DEFS in *HAVE_BSEARCH*) ;; *) LIBOBJS="$LIBOBJS bsrch.o" ;; esac case $DEFS in *HAVE_BZERO*) ;; *HAVE_MEMSET*) ;; *) LIBOBJS="$LIBOBJS bzero.o" ;; esac case $DEFS in *HAVE_GETLINE*) ;; *) LIBOBJS="$LIBOBJS getlin.o" ;; esac case $DEFS in *HAVE_MEMCHR*) ;; *) LIBOBJS="$LIBOBJS memchr.o" ;; esac case $DEFS in *HAVE_MEMCMP*) ;; *HAVE_BCMP*) ;; *) LIBOBJS="$LIBOBJS memcmp.o" ;; esac case $DEFS in *HAVE_MEMCPY*) ;; *HAVE_BCOPY*) ;; *) LIBOBJS="$LIBOBJS memcpy.o" ;; esac case $DEFS in *HAVE_STRCASECMP*) ;; *HAVE_STRICMP*) ;; *) LIBOBJS="$LIBOBJS strcas.o" ;; esac case $DEFS in *HAVE_STRCHR*) ;; *HAVE_INDEX*) ;; *) LIBOBJS="$LIBOBJS strchr.o" ;; esac case $DEFS in *HAVE_STRDUP*) ;; *) LIBOBJS="$LIBOBJS strdup.o" ;; esac case $DEFS in *HAVE_STRNCASECMP*) ;; *HAVE_STRNICMP*) ;; *) LIBOBJS="$LIBOBJS strncs.o" ;; esac case $DEFS in *HAVE_STRRCHR*) ;; *HAVE_RINDEX*) ;; *) LIBOBJS="$LIBOBJS strrch.o" ;; esac case $DEFS in *HAVE_STRSTR*) ;; *) LIBOBJS="$LIBOBJS strstr.o" ;; esac case $DEFS in *HAVE_STRTOL*) ;; *) LIBOBJS="$LIBOBJS strtol.o" ;; esac case $DEFS in *HAVE_OPENDIR*) ;; *) UNIXOBJS="$UNIXOBJS dirent.o" ;; esac case $DEFS in *HAVE_DUP2*) ;; *) UNIXOBJS="$UNIXOBJS dup2.o" ;; esac case $DEFS in *HAVE_FTW*) ;; *) UNIXOBJS="$UNIXOBJS ftw.o" ;; esac case $DEFS in *HAVE_REMOVE*) ;; *) UNIXOBJS="$UNIXOBJS remove.o" ;; esac case $DEFS in *HAVE_RENAME*) ;; *) UNIXOBJS="$UNIXOBJS rename.o" ;; esac case $DEFS in *HAVE_STRERROR*) ;; *) UNIXOBJS="$UNIXOBJS strerr.o" ;; esac case $DEFS in *HAVE_SIGVEC*) echo checking for sv_flags cat > conftest.c < main() { exit(0); } t() { struct sigvec s; s.sv_flags = 0; } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_SIGVEC_SV_FLAGS 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_SIGVEC_SV_FLAGS\${SEDdB}HAVE_SIGVEC_SV_FLAGS\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_SIGVEC_SV_FLAGS\${SEDuB}HAVE_SIGVEC_SV_FLAGS\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_SIGVEC_SV_FLAGS\${SEDeB}HAVE_SIGVEC_SV_FLAGS\${SEDeC}1\${SEDeD} " fi rm -f conftest* ;; esac trfrom='[a-z]' trto='[A-Z]' echo checking for times declared as "long" cat > conftest.c < #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern long times (); main() { exit(0); } t() { } EOF if eval $compile; then DEFS="${DEFS}#define `echo times | tr "$trfrom" "$trto"`_DECLARATION_OK 1 " SEDDEFS="${SEDDEFS}\${SEDdA}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdB}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdC}1\${SEDdD} \${SEDuA}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuB}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuC}1\${SEDuD} \${SEDeA}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeB}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeC}1\${SEDeD} " fi rm -f conftest* trfrom='[a-z]' trto='[A-Z]' echo checking for getpwnam declared as "struct passwd *" cat > conftest.c < #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern struct passwd * getpwnam (); main() { exit(0); } t() { } EOF if eval $compile; then DEFS="${DEFS}#define `echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK 1 " SEDDEFS="${SEDDEFS}\${SEDdA}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdB}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdC}1\${SEDdD} \${SEDuA}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuB}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuC}1\${SEDuD} \${SEDeA}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeB}`echo getpwnam | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeC}1\${SEDeD} " fi rm -f conftest* trfrom='[a-z]' trto='[A-Z]' echo checking for getpwuid declared as "struct passwd *" cat > conftest.c < #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern struct passwd * getpwuid (); main() { exit(0); } t() { } EOF if eval $compile; then DEFS="${DEFS}#define `echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK 1 " SEDDEFS="${SEDDEFS}\${SEDdA}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdB}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdC}1\${SEDdD} \${SEDuA}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuB}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuC}1\${SEDuD} \${SEDeA}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeB}`echo getpwuid | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeC}1\${SEDeD} " fi rm -f conftest* trfrom='[a-z]' trto='[A-Z]' echo checking for getgrent declared as "struct group *" cat > conftest.c < #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern struct group * getgrent (); main() { exit(0); } t() { } EOF if eval $compile; then DEFS="${DEFS}#define `echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK 1 " SEDDEFS="${SEDDEFS}\${SEDdA}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdB}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDdC}1\${SEDdD} \${SEDuA}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuB}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuC}1\${SEDuD} \${SEDeA}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeB}`echo getgrent | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for BSD setpgrp cat > conftest.c < #endif main() { exit(0); } t() { getpgrp (0); setpgrp (0, 0); } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_BSD_PGRP 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_BSD_PGRP\${SEDdB}HAVE_BSD_PGRP\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_BSD_PGRP\${SEDuB}HAVE_BSD_PGRP\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_BSD_PGRP\${SEDeB}HAVE_BSD_PGRP\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for union wait cat > conftest.c < #ifndef WIFEXITED #define WIFEXITED(u) ((u).w_termsig == 0) #endif main() { exit(0); } t() { union wait u; if (WIFEXITED (u)) wait (&u); } EOF if eval $compile; then DEFS="${DEFS}#define HAVE_UNION_WAIT 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_UNION_WAIT\${SEDdB}HAVE_UNION_WAIT\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_UNION_WAIT\${SEDuB}HAVE_UNION_WAIT\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_UNION_WAIT\${SEDeB}HAVE_UNION_WAIT\${SEDeC}1\${SEDeD} " fi rm -f conftest* if test -n "$cross_compiling"; then DEFS="${DEFS}#define HAVE_LONG_FILE_NAMES 0 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_LONG_FILE_NAMES\${SEDdB}HAVE_LONG_FILE_NAMES\${SEDdC}0\${SEDdD} \${SEDuA}HAVE_LONG_FILE_NAMES\${SEDuB}HAVE_LONG_FILE_NAMES\${SEDuC}0\${SEDuD} \${SEDeA}HAVE_LONG_FILE_NAMES\${SEDeB}HAVE_LONG_FILE_NAMES\${SEDeC}0\${SEDeD} " DEFS="${DEFS}#define HAVE_RESTARTABLE_SYSCALLS -1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_RESTARTABLE_SYSCALLS\${SEDdB}HAVE_RESTARTABLE_SYSCALLS\${SEDdC}-1\${SEDdD} \${SEDuA}HAVE_RESTARTABLE_SYSCALLS\${SEDuB}HAVE_RESTARTABLE_SYSCALLS\${SEDuC}-1\${SEDuD} \${SEDeA}HAVE_RESTARTABLE_SYSCALLS\${SEDeB}HAVE_RESTARTABLE_SYSCALLS\${SEDeC}-1\${SEDeD} " else echo checking for restartable system calls cat > conftest.c < #include ucatch (isig) { } main () { int i = fork (), status; if (i == 0) { sleep (3); kill (getppid (), SIGINT); sleep (3); exit (0); } signal (SIGINT, ucatch); status = wait(&i); if (status == -1) wait(&i); exit (status == -1); } EOF eval $compile if test -s conftest && (./conftest; exit) 2>/dev/null; then DEFS="${DEFS}#define HAVE_RESTARTABLE_SYSCALLS 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_RESTARTABLE_SYSCALLS\${SEDdB}HAVE_RESTARTABLE_SYSCALLS\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_RESTARTABLE_SYSCALLS\${SEDuB}HAVE_RESTARTABLE_SYSCALLS\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_RESTARTABLE_SYSCALLS\${SEDeB}HAVE_RESTARTABLE_SYSCALLS\${SEDeC}1\${SEDeD} " fi rm -f conftest* echo checking for long file names (echo 1 > conftest9012345) 2>/dev/null (echo 2 > conftest9012346) 2>/dev/null val=`cat conftest9012345 2>/dev/null` test -f conftest9012345 && test "$val" = 1 && DEFS="${DEFS}#define HAVE_LONG_FILE_NAMES 1 " SEDDEFS="${SEDDEFS}\${SEDdA}HAVE_LONG_FILE_NAMES\${SEDdB}HAVE_LONG_FILE_NAMES\${SEDdC}1\${SEDdD} \${SEDuA}HAVE_LONG_FILE_NAMES\${SEDuB}HAVE_LONG_FILE_NAMES\${SEDuC}1\${SEDuD} \${SEDeA}HAVE_LONG_FILE_NAMES\${SEDeB}HAVE_LONG_FILE_NAMES\${SEDeC}1\${SEDeD} " rm -f conftest9012345 conftest9012346 fi if test -n "$prefix"; then test -z "$exec_prefix" && exec_prefix='${prefix}' prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%" fi if test -n "$exec_prefix"; then prsub="$prsub s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%\ exec_prefix\\1=\\2$exec_prefix%" fi trap 'rm -f config.status; exit 1' 1 3 15 echo creating config.status rm -f config.status cat > config.status </dev/null`: # # $0 $* for arg do case "\$arg" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) exec /bin/sh $0 $* ;; *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;; esac done trap 'rm -f Makefile uuconf/Makefile lib/Makefile unix/Makefile conf.h conftest*; exit 1' 1 3 15 CC='$CC' CPP='$CPP' INSTALL='$INSTALL' INSTALL_PROGRAM='$INSTALL_PROGRAM' INSTALL_DATA='$INSTALL_DATA' RANLIB='$RANLIB' CFLAGS='$CFLAGS' LDFLAGS='$LDFLAGS' LN_S='$LN_S' UUDIR='$UUDIR' LIBOBJS='$LIBOBJS' UNIXOBJS='$UNIXOBJS' LIBS='$LIBS' srcdir='$srcdir' prefix='$prefix' exec_prefix='$exec_prefix' prsub='$prsub' EOF cat >> config.status <<\EOF top_srcdir=$srcdir for file in .. Makefile uuconf/Makefile lib/Makefile unix/Makefile; do if [ "x$file" != "x.." ]; then srcdir=$top_srcdir # Remove last slash and all that follows it. Not all systems have dirname. dir=`echo $file|sed 's%/[^/][^/]*$%%'` if test "$dir" != "$file"; then test "$top_srcdir" != . && srcdir=$top_srcdir/$dir test ! -d $dir && mkdir $dir fi echo creating $file rm -f $file echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file sed -e " $prsub s%@CC@%$CC%g s%@CPP@%$CPP%g s%@INSTALL@%$INSTALL%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@RANLIB@%$RANLIB%g s%@CFLAGS@%$CFLAGS%g s%@LDFLAGS@%$LDFLAGS%g s%@LN_S@%$LN_S%g s%@UUDIR@%$UUDIR%g s%@LIBOBJS@%$LIBOBJS%g s%@UNIXOBJS@%$UNIXOBJS%g s%@LIBS@%$LIBS%g s%@srcdir@%$srcdir%g s%@DEFS@%-DHAVE_CONFIG_H%" $top_srcdir/${file}.in >> $file fi; done echo creating conf.h # These sed commands are put into SEDDEFS when defining a macro. # They are broken into pieces to make the sed script easier to manage. # They are passed to sed as "A NAME B NAME C VALUE D", where NAME # is the cpp macro being defined and VALUE is the value it is being given. # Each defining turns into a single global substitution command. # # SEDd sets the value in "#define NAME VALUE" lines. SEDdA='s@^\([ ]*\)#\([ ]*define[ ][ ]*\)' SEDdB='\([ ][ ]*\)[^ ]*@\1#\2' SEDdC='\3' SEDdD='@g' # SEDu turns "#undef NAME" with trailing blanks into "#define NAME VALUE". SEDuA='s@^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' SEDuB='\([ ]\)@\1#\2define\3' SEDuC=' ' SEDuD='\4@g' # SEDe turns "#undef NAME" without trailing blanks into "#define NAME VALUE". SEDeA='s@^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' SEDeB='$@\1#\2define\3' SEDeC=' ' SEDeD='@g' rm -f conftest.sed cat > conftest.sed <> config.status <> config.status <<\EOF CONFEOF rm -f conftest.h # Break up the sed commands because old seds have small limits. cp $top_srcdir/conf.h.in conftest.h1 while : do lines=`grep -c . conftest.sed` if test -z "$lines" || test "$lines" -eq 0; then break; fi rm -f conftest.s1 conftest.s2 conftest.h2 sed 40q conftest.sed > conftest.s1 # Like head -40. sed 1,40d conftest.sed > conftest.s2 # Like tail +41. sed -f conftest.s1 < conftest.h1 > conftest.h2 rm -f conftest.s1 conftest.h1 conftest.sed mv conftest.h2 conftest.h1 mv conftest.s2 conftest.sed done rm -f conftest.sed conftest.h echo "/* conf.h. Generated automatically by configure. */" > conftest.h cat conftest.h1 >> conftest.h rm -f conftest.h1 if cmp -s conf.h conftest.h 2>/dev/null; then # The file exists and we would not be changing it. rm -f conftest.h else rm -f conf.h mv conftest.h conf.h fi EOF chmod +x config.status test -n "$no_create" || ./config.status | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDuC}1\${SEDuD} \${SEDeA}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeB}`echo times | tr "$trfrom" "$trto"`_DECLARATION_OK\${SEDeC}1\${SEDeD} " fi rm -f conftest* trfrom='[a-z]' trto='[A-Z]' echo checking for getpwnam declared as "struct passwd *" cat > conftest.c < #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern struct puucp-1.04/configure.in1004440004150000170000002420205337263503011673 037777777777 1 0 dnl Taylor UUCP configuration file dnl This should be processed with autoconf to produce a configure script. dnl Copyright (c) 1992 Ian Lance Taylor dnl AC_INIT(policy.h) AC_CONFIG_HEADER(conf.h) AC_PROG_CC AC_PROG_CPP AC_GCC_TRADITIONAL AC_PROG_INSTALL AC_PROG_RANLIB AC_ISC_POSIX AC_MINIX AC_AIX AC_DYNIX_SEQ AC_IRIX_SUN AC_CROSS_CHECK dnl CFLAGS=${CFLAGS--g} AC_SUBST(CFLAGS)dnl AC_SUBST(LDFLAGS)dnl dnl echo checking for mail program if test -s /usr/ucb/mail; then AC_DEFINE([MAIL_PROGRAM], `echo '"/usr/ucb/mail"'`) elif test -s /bin/mail; then AC_DEFINE([MAIL_PROGRAM], `echo '"/bin/mail"'`) elif test -s /usr/bin/mail; then AC_DEFINE([MAIL_PROGRAM], `echo '"/usr/bin/mail"'`) elif test -s /usr/bin/mailx; then AC_DEFINE([MAIL_PROGRAM], `echo '"/usr/bin/mailx"'`) fi echo checking for echo program if (PATH= echo test) 2>/dev/null | grep test >/dev/null 2>&1; then AC_DEFINE([ECHO_PROGRAM], `echo '"echo"'`) elif test -s /bin/echo; then AC_DEFINE([ECHO_PROGRAM], `echo '"/bin/echo"'`) fi AC_LN_S dnl AC_HAVE_HEADERS(stddef.h string.h strings.h unistd.h stdlib.h limits.h) AC_HAVE_HEADERS(time.h sys/wait.h sys/ioctl.h dirent.h memory.h sys/param.h) AC_HAVE_HEADERS(utime.h fcntl.h sys/file.h sys/times.h libc.h sysexits.h) AC_HAVE_HEADERS(poll.h tiuser.h xti.h sys/tli.h stropts.h ftw.h glob.h) AC_HAVE_HEADERS(sys/types.tcp.h) dnl AC_COMPILE_CHECK([sys/select.h], [#include #include ], [int i;], [AC_DEFINE(HAVE_SYS_SELECT_H)]) dnl AC_MAJOR_HEADER dnl AC_RETSIGTYPE dnl AC_COMPILE_CHECK([time.h and sys/time.h being included together], [#include #include ], [int i;], AC_DEFINE([HAVE_SYS_TIME_AND_TIME_H])) dnl AC_COMPILE_CHECK([termios.h and sys/ioctl.h being included together], [#include #include ], [int i;], AC_DEFINE([HAVE_TERMIOS_AND_SYS_IOCTL_H])) dnl AC_COMPILE_CHECK([CBREAK], [#include ], [int i = CBREAK;], AC_DEFINE([HAVE_CBREAK])) dnl AC_COMPILE_CHECK([pid_t in sys/types.h], [#include ], [pid_t x;], , AC_DEFINE(PID_T, int)) dnl AC_COMPILE_CHECK([uid_t in sys/types.h], [#include ], [uid_t x;], , AC_DEFINE(UID_T, int)) dnl AC_COMPILE_CHECK([gid_t in sys/types.h], [#include ], [gid_t x;], , AC_DEFINE(GID_T, int)) dnl AC_COMPILE_CHECK([off_t in sys/types.h], [#include ], [off_t x;], , AC_DEFINE(OFF_T, long)) dnl dnl On SCO 3.2.2 sig_atomic_t is in but not . AC_COMPILE_CHECK([sig_atomic_t in signal.h], [#include ], [sig_atomic_t x;], AC_DEFINE([HAVE_SIG_ATOMIC_T_IN_SIGNAL_H])) dnl AC_COMPILE_CHECK([sig_atomic_t in sys/types.h], [#include ], [sig_atomic_t x;], AC_DEFINE([HAVE_SIG_ATOMIC_T_IN_TYPES_H])) dnl case $DEFS in *HAVE_STDDEF_H*) AC_COMPILE_CHECK([size_t in stddef.h], [#include ], [size_t x;], AC_DEFINE([HAVE_SIZE_T_IN_STDDEF_H])) ;; esac dnl AC_COMPILE_CHECK([size_t in sys/types.h], [#include ], [size_t x;], AC_DEFINE([HAVE_SIZE_T_IN_TYPES_H])) dnl AC_COMPILE_CHECK([time_t in time.h], [#include ], [time_t i;], AC_DEFINE([HAVE_TIME_T_IN_TIME_H])) dnl AC_COMPILE_CHECK([time_t in sys/types.h], [#include ], [time_t i;], AC_DEFINE([HAVE_TIME_T_IN_TYPES_H])) dnl dnl The filesystem info code is from David MacKenzie's fileutils 3.4 dnl package. echo checking how to get filesystem space usage # SVR4 AC_TEST_CPP([#include ], AC_DEFINE(STAT_STATVFS) space=1) if test -z "$space"; then # AIX AC_HEADER_EGREP(f_nlsdirtype, sys/statfs.h, AC_DEFINE(STAT_STATFS2_BSIZE) space=1) fi if test -z "$space"; then # SVR3 AC_TEST_CPP([#include ], AC_DEFINE(STAT_STATFS4) space=1) fi if test -z "$space"; then # 4.3BSD AC_TEST_CPP([#include ], AC_DEFINE(STAT_STATFS2_BSIZE) space=1) fi if test -z "$space"; then # 4.4BSD AC_HEADER_EGREP(MOUNT_UFS, sys/mount.h, AC_DEFINE(STAT_STATFS2_FSIZE) space=1) fi if test -z "$space"; then # Ultrix AC_TEST_CPP([#include ], AC_DEFINE(STAT_STATFS2_FS_DATA) space=1) fi if test -z "$space"; then AC_FUNC_CHECK(ustat, AC_DEFINE(STAT_USTAT)) fi dnl AC_COMPILE_CHECK([void], [], [extern void foo (); (void) exit (0);], AC_DEFINE([HAVE_VOID])) dnl AC_COMPILE_CHECK([unsigned char], [], [unsigned char i = (unsigned char) -1;], AC_DEFINE([HAVE_UNSIGNED_CHAR])) dnl AC_COMPILE_CHECK([errno], [#include ], [int i = errno; errno = 1;], AC_DEFINE([HAVE_ERRNO_DECLARATION])) dnl undefine([index]) AC_HAVE_FUNCS(memset memcmp memchr memcpy bcopy bcmp bzero) AC_HAVE_FUNCS(strchr strrchr index rindex strerror strtol strstr) AC_HAVE_FUNCS(strdup strcasecmp strncasecmp stricmp strnicmp) AC_HAVE_FUNCS(bsearch vfprintf) AC_HAVE_FUNCS(remove ftruncate ltrunc rename opendir dup2 waitpid wait4) AC_HAVE_FUNCS(sigsetjmp setret sigaction sigvec sigset) AC_HAVE_FUNCS(sigprocmask sigblock sighold getdtablesize sysconf) AC_HAVE_FUNCS(setpgrp setsid setreuid gethostname uname) AC_HAVE_FUNCS(gettimeofday ftw glob) dnl Check for getline, but not in -linet, since ISC has an dnl incompatible version there. SAVELIBS="$LIBS" LIBS=`echo $LIBS | sed 's/-linet//'` AC_HAVE_FUNCS(getline) LIBS="$SAVELIBS" dnl Check for the SCO buggy ftime; the code can cope with the bug, dnl though it would prefer not to, so if we're cross-configuring we dnl accept that ftime exists. AC_FUNC_CHECK(ftime, [AC_TEST_PROGRAM([ #include #include main () { struct timeb s, slast; int c = 0; ftime (&slast); while (c < 10) { ftime (&s); if (s.time < slast.time || (s.time == slast.time && s.millitm < slast.millitm)) exit (1); if (s.time != slast.time) ++c; slast.time = s.time; slast.millitm = s.millitm; } exit (0); } ], AC_DEFINE(HAVE_FTIME), echo 1>&2 "Your ftime seems to be buggy", AC_DEFINE(HAVE_FTIME))]) dnl AC_HAVE_FUNCS(times) AC_HAVE_FUNCS(napms nap usleep poll select) case $DEFS in *HAVE_NAPMS*) ;; *HAVE_NAP*) ;; *HAVE_USLEEP*) ;; *HAVE_POLL*) ;; *HAVE_SELECT*) ;; *) echo 1>&2 'WARNING: No way to sleep for less than one second' echo 1>&2 ' \p in chat scripts will sleep for a full second' ;; esac dnl AC_HAVE_FUNCS(getgrent) dnl changequote(,)dnl trfrom='[a-z]' trto='[A-Z]' changequote([,])dnl for i in socket t_open; do def=HAVE_`echo $i|tr "$trfrom" "$trto"` AC_FUNC_CHECK([$i],[AC_DEFINE($def)],[missing=1])dnl for lib in "-lsocket" "-lsocket -lnsl" "-lnsl" "-lxti"; do if test -n "$missing"; then case $LIBS in *${lib}*) ;; *) SAVELIBS="$LIBS" LIBS="$LIBS $lib" missing= AC_COMPILE_CHECK([$i with $lib], , [extern char $i(); $i();], [AC_DEFINE($def)], [missing=1; LIBS="$SAVELIBS"])dnl ;; esac fi done done dnl AC_HAVE_FUNCS(getcwd getwd) case $DEFS in *HAVE_GETCWD*) ;; *HAVE_GETCD*) ;; *) UNIXOBJS="$UNIXOBJS getcwd.o" if test -s /bin/pwd; then AC_DEFINE([PWD_PROGRAM], `echo '"/bin/pwd"'`) fi ;; esac dnl AC_HAVE_FUNCS(mkdir) case $DEFS in *HAVE_MKDIR*) UUDIR='# ' ;; *) UUDIR= UNIXOBJS="$UNIXOBJS mkdir.o" if test -s /bin/mkdir; then AC_DEFINE([MKDIR_PROGRAM], `echo '"/bin/mkdir"'`) fi ;; esac AC_SUBST(UUDIR)dnl dnl AC_HAVE_FUNCS(rmdir) case $DEFS in *HAVE_RMDIR*) ;; *) UNIXOBJS="$UNIXOBJS rmdir.o" if test -s /bin/rmdir; then AC_DEFINE([RMDIR_PROGRAM], `echo '"/bin/rmdir"'`) fi ;; esac dnl dnl Figure out which functions we need from lib subdirectory case $DEFS in *HAVE_BSEARCH*) ;; *) LIBOBJS="$LIBOBJS bsrch.o" ;; esac case $DEFS in *HAVE_BZERO*) ;; *HAVE_MEMSET*) ;; *) LIBOBJS="$LIBOBJS bzero.o" ;; esac case $DEFS in *HAVE_GETLINE*) ;; *) LIBOBJS="$LIBOBJS getlin.o" ;; esac case $DEFS in *HAVE_MEMCHR*) ;; *) LIBOBJS="$LIBOBJS memchr.o" ;; esac case $DEFS in *HAVE_MEMCMP*) ;; *HAVE_BCMP*) ;; *) LIBOBJS="$LIBOBJS memcmp.o" ;; esac case $DEFS in *HAVE_MEMCPY*) ;; *HAVE_BCOPY*) ;; *) LIBOBJS="$LIBOBJS memcpy.o" ;; esac case $DEFS in *HAVE_STRCASECMP*) ;; *HAVE_STRICMP*) ;; *) LIBOBJS="$LIBOBJS strcas.o" ;; esac case $DEFS in *HAVE_STRCHR*) ;; *HAVE_INDEX*) ;; *) LIBOBJS="$LIBOBJS strchr.o" ;; esac case $DEFS in *HAVE_STRDUP*) ;; *) LIBOBJS="$LIBOBJS strdup.o" ;; esac case $DEFS in *HAVE_STRNCASECMP*) ;; *HAVE_STRNICMP*) ;; *) LIBOBJS="$LIBOBJS strncs.o" ;; esac case $DEFS in *HAVE_STRRCHR*) ;; *HAVE_RINDEX*) ;; *) LIBOBJS="$LIBOBJS strrch.o" ;; esac case $DEFS in *HAVE_STRSTR*) ;; *) LIBOBJS="$LIBOBJS strstr.o" ;; esac case $DEFS in *HAVE_STRTOL*) ;; *) LIBOBJS="$LIBOBJS strtol.o" ;; esac AC_SUBST(LIBOBJS)dnl dnl Figure out which functions we need from unix subdirectory case $DEFS in *HAVE_OPENDIR*) ;; *) UNIXOBJS="$UNIXOBJS dirent.o" ;; esac case $DEFS in *HAVE_DUP2*) ;; *) UNIXOBJS="$UNIXOBJS dup2.o" ;; esac case $DEFS in *HAVE_FTW*) ;; *) UNIXOBJS="$UNIXOBJS ftw.o" ;; esac case $DEFS in *HAVE_REMOVE*) ;; *) UNIXOBJS="$UNIXOBJS remove.o" ;; esac case $DEFS in *HAVE_RENAME*) ;; *) UNIXOBJS="$UNIXOBJS rename.o" ;; esac case $DEFS in *HAVE_STRERROR*) ;; *) UNIXOBJS="$UNIXOBJS strerr.o" ;; esac AC_SUBST(UNIXOBJS) dnl case $DEFS in *HAVE_SIGVEC*) AC_COMPILE_CHECK([sv_flags], [#include ], [struct sigvec s; s.sv_flags = 0;], AC_DEFINE([HAVE_SIGVEC_SV_FLAGS])) ;; esac dnl dnl See whether we can make an extern declaration define(ILT_CHECK_DECLARATION, [changequote(,)dnl trfrom='[a-z]' trto='[A-Z]' changequote([,])dnl AC_COMPILE_CHECK([$1 declared as "$2"], [#include #include #include #ifdef HAVE_LIBC_H #include #endif #ifdef HAVE_SYS_TIMES_H #include #endif extern $2 $1 ();], , AC_DEFINE(`echo $1 | tr "$trfrom" "$trto"`_DECLARATION_OK))]) dnl ILT_CHECK_DECLARATION(times, long) ILT_CHECK_DECLARATION(getpwnam, struct passwd *) ILT_CHECK_DECLARATION(getpwuid, struct passwd *) ILT_CHECK_DECLARATION(getgrent, struct group *) dnl AC_COMPILE_CHECK([BSD setpgrp], [#ifdef HAVE_UNISTD_H #include #endif], [getpgrp (0); setpgrp (0, 0);], AC_DEFINE([HAVE_BSD_PGRP])) dnl AC_COMPILE_CHECK([union wait], [#include #ifndef WIFEXITED #define WIFEXITED(u) ((u).w_termsig == 0) #endif], [union wait u; if (WIFEXITED (u)) wait (&u);], AC_DEFINE([HAVE_UNION_WAIT])) dnl if test -n "$cross_compiling"; then AC_DEFINE([HAVE_LONG_FILE_NAMES], [0]) AC_DEFINE([HAVE_RESTARTABLE_SYSCALLS], [-1]) else AC_RESTARTABLE_SYSCALLS AC_LONG_FILE_NAMES fi dnl AC_OUTPUT(Makefile uuconf/Makefile lib/Makefile unix/Makefile) 2 Ian Lance Taylor dnl AC_INIT(policy.h) AC_CONFIG_HEADER(conf.h) AC_PROG_CC AC_PROG_CPP AC_GCC_TRADITIONAL AC_PROG_INSTALL AC_PROG_RANLIB AC_ISC_POSIX AC_MINIX AC_AIX AC_DYNIX_SEQ AC_IRIX_SUN AC_CROSS_CHECK dnl CFLAGS=${CFLAGS--g} AC_SUBST(CFLAGS)dnl AC_SUBST(LDFLAGS)dnl dnl echo checking for mail program if test -s /usr/ucb/mail; then AC_DEFINE([MAIL_PROGRAM], `echo '"/usr/ucbuucp-1.04/conn.c1004440004150000170000003232305337263503010466 037777777777 1 0 /* 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.5 1992/11/14 17:13:49 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" static boolean fcdo_dial P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, const char *zphone, boolean ftranslate)); /* Create a new connection. This relies on system dependent functions to set the qcmds and psysdep fields. If qport is NULL, it opens a standard input port. */ boolean fconn_init (qport, qconn) struct uuconf_port *qport; struct sconnection *qconn; { qconn->qport = qport; switch (qport == NULL ? UUCONF_PORTTYPE_STDIN : qport->uuconf_ttype) { case UUCONF_PORTTYPE_STDIN: return fsysdep_stdin_init (qconn); case UUCONF_PORTTYPE_MODEM: return fsysdep_modem_init (qconn); case UUCONF_PORTTYPE_DIRECT: return fsysdep_direct_init (qconn); #if HAVE_TCP case UUCONF_PORTTYPE_TCP: return fsysdep_tcp_init (qconn); #endif #if HAVE_TLI case UUCONF_PORTTYPE_TLI: return fsysdep_tli_init (qconn); #endif default: ulog (LOG_ERROR, "Unknown port type"); return FALSE; } } /* Connection dispatch routines. */ /* Free a connection. */ void uconn_free (qconn) struct sconnection *qconn; { (*qconn->qcmds->pufree) (qconn); } /* Lock a connection. */ boolean fconn_lock (qconn, fin) struct sconnection *qconn; boolean fin; { boolean (*pflock) P((struct sconnection *, boolean)); pflock = qconn->qcmds->pflock; if (pflock == NULL) return TRUE; return (*pflock) (qconn, fin); } /* Unlock a connection. */ boolean fconn_unlock (qconn) struct sconnection *qconn; { boolean (*pfunlock) P((struct sconnection *)); pfunlock = qconn->qcmds->pfunlock; if (pfunlock == NULL) return TRUE; return (*pfunlock) (qconn); } /* Open a connection. */ boolean fconn_open (qconn, ibaud, ihighbaud, fwait) struct sconnection *qconn; long ibaud; long ihighbaud; boolean fwait; { boolean fret; #if DEBUG > 1 if (FDEBUGGING (DEBUG_PORT)) { char abspeed[20]; if (ibaud == (long) 0) strcpy (abspeed, "default speed"); else sprintf (abspeed, "speed %ld", ibaud); if (qconn->qport == NULL) ulog (LOG_DEBUG, "fconn_open: Opening stdin port (%s)", abspeed); else if (qconn->qport->uuconf_zname == NULL) ulog (LOG_DEBUG, "fconn_open: Opening unnamed port (%s)", abspeed); else ulog (LOG_DEBUG, "fconn_open: Opening port %s (%s)", qconn->qport->uuconf_zname, abspeed); } #endif /* If the system provides a range of baud rates, we select the highest baud rate supported by the port. */ if (ihighbaud != 0 && qconn->qport != NULL) { struct uuconf_port *qport; qport = qconn->qport; ibaud = ihighbaud; if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) { if (qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud != 0) { if (qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud < ibaud) ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud; } else if (qport->uuconf_u.uuconf_smodem.uuconf_ibaud != 0) ibaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud; } else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) { if (qport->uuconf_u.uuconf_sdirect.uuconf_ibaud != 0) ibaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; } } /* This will normally be overridden by the port specific open routine. */ if (qconn->qport == NULL) ulog_device ("stdin"); else ulog_device (qconn->qport->uuconf_zname); fret = (*qconn->qcmds->pfopen) (qconn, ibaud, fwait); if (! fret) ulog_device ((const char *) NULL); return fret; } /* Close a connection. */ boolean fconn_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { boolean fret; DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_close: Closing connection"); /* Don't report hangup signals while we're closing. */ fLog_sighup = FALSE; fret = (*qconn->qcmds->pfclose) (qconn, puuconf, qdialer, fsuccess); /* Make sure any signal reporting has been done before we set fLog_sighup back to TRUE. */ ulog (LOG_ERROR, (const char *) NULL); fLog_sighup = TRUE; ulog_device ((const char *) NULL); return fret; } /* Reset the connection. */ boolean fconn_reset (qconn) struct sconnection *qconn; { DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_reset: Resetting connection"); return (*qconn->qcmds->pfreset) (qconn); } /* Dial out on the connection. */ boolean fconn_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) struct sconnection *qconn; pointer puuconf; const struct uuconf_system *qsys; const char *zphone; struct uuconf_dialer *qdialer; enum tdialerfound *ptdialerfound; { struct uuconf_dialer sdialer; enum tdialerfound tfound; boolean (*pfdial) P((struct sconnection *, pointer, const struct uuconf_system *, const char *, struct uuconf_dialer *, enum tdialerfound *)); if (qdialer == NULL) qdialer = &sdialer; if (ptdialerfound == NULL) ptdialerfound = &tfound; qdialer->uuconf_zname = NULL; *ptdialerfound = DIALERFOUND_FALSE; pfdial = qconn->qcmds->pfdial; if (pfdial == NULL) return TRUE; return (*pfdial) (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound); } /* Read data from the connection. */ boolean fconn_read (qconn, zbuf, pclen, cmin, ctimeout, freport) struct sconnection *qconn; char *zbuf; size_t *pclen; size_t cmin; int ctimeout; boolean freport; { boolean fret; fret = (*qconn->qcmds->pfread) (qconn, zbuf, pclen, cmin, ctimeout, freport); #if DEBUG > 1 if (FDEBUGGING (DEBUG_INCOMING)) udebug_buffer ("fconn_read: Read", zbuf, *pclen); else if (FDEBUGGING (DEBUG_PORT)) ulog (LOG_DEBUG, "fconn_read: Read %lu", (unsigned long) *pclen); #endif return fret; } /* Write data to the connection. */ boolean fconn_write (qconn, zbuf, clen) struct sconnection *qconn; const char *zbuf; size_t clen; { #if DEBUG > 1 if (FDEBUGGING (DEBUG_OUTGOING)) udebug_buffer ("fconn_write: Writing", zbuf, clen); else if (FDEBUGGING (DEBUG_PORT)) ulog (LOG_DEBUG, "fconn_write: Writing %lu", (unsigned long) clen); #endif return (*qconn->qcmds->pfwrite) (qconn, zbuf, clen); } /* Read and write data. */ boolean fconn_io (qconn, zwrite, pcwrite, zread, pcread) struct sconnection *qconn; const char *zwrite; size_t *pcwrite; char *zread; size_t *pcread; { boolean fret; #if DEBUG > 1 size_t cwrite = *pcwrite; size_t cread = *pcread; if (cread == 0 || cwrite == 0) ulog (LOG_FATAL, "fconn_io: cread %lu; cwrite %lu", (unsigned long) cread, (unsigned long) cwrite); #endif #if DEBUG > 1 if (FDEBUGGING (DEBUG_OUTGOING)) udebug_buffer ("fconn_io: Writing", zwrite, cwrite); #endif fret = (*qconn->qcmds->pfio) (qconn, zwrite, pcwrite, zread, pcread); DEBUG_MESSAGE4 (DEBUG_PORT, "fconn_io: Wrote %lu of %lu, read %lu of %lu", (unsigned long) *pcwrite, (unsigned long) cwrite, (unsigned long) *pcread, (unsigned long) cread); #if DEBUG > 1 if (*pcread > 0 && FDEBUGGING (DEBUG_INCOMING)) udebug_buffer ("fconn_io: Read", zread, *pcread); #endif return fret; } /* Send a break character to a connection. Some port types may not support break characters, in which case we just return TRUE. */ boolean fconn_break (qconn) struct sconnection *qconn; { boolean (*pfbreak) P((struct sconnection *)); pfbreak = *qconn->qcmds->pfbreak; if (pfbreak == NULL) return TRUE; DEBUG_MESSAGE0 (DEBUG_PORT, "fconn_break: Sending break character"); return (*pfbreak) (qconn); } /* Change the setting of a connection. Some port types may not support this, in which case we just return TRUE. */ boolean fconn_set (qconn, tparity, tstrip, txonxoff) struct sconnection *qconn; enum tparitysetting tparity; enum tstripsetting tstrip; enum txonxoffsetting txonxoff; { boolean (*pfset) P((struct sconnection *, enum tparitysetting, enum tstripsetting, enum txonxoffsetting)); pfset = qconn->qcmds->pfset; if (pfset == NULL) return TRUE; DEBUG_MESSAGE3 (DEBUG_PORT, "fconn_set: Changing setting to %d, %d, %d", (int) tparity, (int) tstrip, (int) txonxoff); return (*pfset) (qconn, tparity, tstrip, txonxoff); } /* Require or ignore carrier on a connection. */ boolean fconn_carrier (qconn, fcarrier) struct sconnection *qconn; boolean fcarrier; { boolean (*pfcarrier) P((struct sconnection *, boolean)); pfcarrier = qconn->qcmds->pfcarrier; if (pfcarrier == NULL) return TRUE; return (*pfcarrier) (qconn, fcarrier); } /* Run a chat program on a connection. */ boolean fconn_run_chat (qconn, pzprog) struct sconnection *qconn; char **pzprog; { return (*qconn->qcmds->pfchat) (qconn, pzprog); } /* Get the baud rate of a connection. */ long iconn_baud (qconn) struct sconnection *qconn; { long (*pibaud) P((struct sconnection *)); pibaud = qconn->qcmds->pibaud; if (pibaud == NULL) return 0; return (*pibaud) (qconn); } /* Modem dialing routines. */ /*ARGSUSED*/ boolean fmodem_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) struct sconnection *qconn; pointer puuconf; const struct uuconf_system *qsys; const char *zphone; struct uuconf_dialer *qdialer; enum tdialerfound *ptdialerfound; { *ptdialerfound = DIALERFOUND_FALSE; if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) { char **pz; boolean ffirst; /* The pzdialer field is a sequence of dialer/token pairs. The dialer portion names a dialer to use. The token portion is what \D and \T in the chat script expand to. If there is no token for the last dialer, the phone number for the system is used. */ ffirst = TRUE; pz = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer; while (*pz != NULL) { int iuuconf; struct uuconf_dialer *q; struct uuconf_dialer s; const char *ztoken; boolean ftranslate; if (! ffirst) q = &s; else q = qdialer; iuuconf = uuconf_dialer_info (puuconf, *pz, q); if (iuuconf == UUCONF_NOT_FOUND) { ulog (LOG_ERROR, "%s: Dialer not found", *pz); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } ++pz; ztoken = *pz; ftranslate = FALSE; if (ztoken == NULL || strcmp (ztoken, "\\D") == 0) ztoken = zphone; else if (strcmp (ztoken, "\\T") == 0) { ztoken = zphone; ftranslate = TRUE; } if (! fcdo_dial (qconn, puuconf, q, ztoken, ftranslate)) { (void) uuconf_dialer_free (puuconf, q); if (! ffirst) (void) uuconf_dialer_free (puuconf, qdialer); return FALSE; } if (ffirst) { *ptdialerfound = DIALERFOUND_FREE; ffirst = FALSE; } else (void) uuconf_dialer_free (puuconf, q); if (*pz != NULL) ++pz; } return TRUE; } else if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer != NULL) { struct uuconf_dialer *q; q = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer; *qdialer = *q; *ptdialerfound = DIALERFOUND_TRUE; return fcdo_dial (qconn, puuconf, q, zphone, FALSE); } else { ulog (LOG_ERROR, "No dialer information"); return FALSE; } } /* Actually use a dialer. We set up the modem (which may include opening the dialer device), run the chat script, and finish dealing with the modem. */ static boolean fcdo_dial (qconn, puuconf, qdial, zphone, ftranslate) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdial; const char *zphone; boolean ftranslate; { const char *zname; if (! fsysdep_modem_begin_dial (qconn, qdial)) return FALSE; if (qconn->qport == NULL) zname = NULL; else zname = qconn->qport->uuconf_zname; if (! fchat (qconn, puuconf, &qdial->uuconf_schat, (const struct uuconf_system *) NULL, qdial, zphone, ftranslate, zname, iconn_baud (qconn))) return FALSE; return fsysdep_modem_end_dial (qconn, qdial); } 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)", uucp-1.04/conn.h1004440004150000170000002752505337263503010503 037777777777 1 0 /* 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) */ ge output parity generation. */ PARITYSETTING_DEFAULT, /* No parity (all eight output bits used). */ PARITYSETTING_NONE, /* Even parity. */ PARITYSETTING_EVENuucp-1.04/copy.c1004440004150000170000001034105337263504010500 037777777777 1 0 /* 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.12 1992/11/14 16:10:27 ian Rel $"; #endif #include "uudefs.h" #include "system.h" #include "sysdep.h" #include #include /* Copy one file to another. */ #if USE_STDIO boolean fcopy_file (zfrom, zto, fpublic, fmkdirs) const char *zfrom; const char *zto; boolean fpublic; boolean fmkdirs; { FILE *efrom; boolean fret; efrom = fopen (zfrom, BINREAD); if (efrom == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zfrom, strerror (errno)); return FALSE; } fret = fcopy_open_file (efrom, zto, fpublic, fmkdirs); (void) fclose (efrom); return fret; } boolean fcopy_open_file (efrom, zto, fpublic, fmkdirs) FILE *efrom; const char *zto; boolean fpublic; boolean fmkdirs; { FILE *eto; char ab[8192]; int c; eto = esysdep_fopen (zto, fpublic, FALSE, fmkdirs); if (eto == NULL) return FALSE; while ((c = fread (ab, sizeof (char), sizeof ab, efrom)) != 0) { if (fwrite (ab, sizeof (char), (size_t) c, eto) != c) { ulog (LOG_ERROR, "fwrite: %s", strerror (errno)); (void) fclose (eto); (void) remove (zto); return FALSE; } } if (fclose (eto) != 0) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); (void) remove (zto); return FALSE; } return TRUE; } #else /* ! USE_STDIO */ #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif boolean fcopy_file (zfrom, zto, fpublic, fmkdirs) const char *zfrom; const char *zto; boolean fpublic; boolean fmkdirs; { int ofrom; boolean fret; ofrom = open (zfrom, O_RDONLY | O_NOCTTY, 0); if (ofrom < 0) { ulog (LOG_ERROR, "open (%s): %s", zfrom, strerror (errno)); return FALSE; } fret = fcopy_open_file (ofrom, zto, fpublic, fmkdirs); (void) close (ofrom); return fret; } boolean fcopy_open_file (ofrom, zto, fpublic, fmkdirs) int ofrom; const char *zto; boolean fpublic; boolean fmkdirs; { int oto; char ab[8192]; int c; /* These file mode arguments are from the UNIX version of sysdep.h; each system dependent header file will need their own definitions. */ oto = creat (zto, fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE); if (oto < 0) { if (errno == ENOENT && fmkdirs) { if (! fsysdep_make_dirs (zto, fpublic)) return FALSE; oto = creat (zto, fpublic ? IPUBLIC_FILE_MODE : IPRIVATE_FILE_MODE); } if (oto < 0) { ulog (LOG_ERROR, "open (%s): %s", zto, strerror (errno)); return FALSE; } } while ((c = read (ofrom, ab, sizeof ab)) > 0) { if (write (oto, ab, (size_t) c) != c) { ulog (LOG_ERROR, "write: %s", strerror (errno)); (void) close (oto); (void) remove (zto); return FALSE; } } if (close (oto) < 0) { ulog (LOG_ERROR, "close: %s", strerror (errno)); (void) remove (zto); return FALSE; } if (c < 0) { ulog (LOG_ERROR, "read: %s", strerror (errno)); (void) remove (zto); return FALSE; } return TRUE; } #endif /* ! USE_STDIO */ / 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 sconnecuucp-1.04/cu.11004440004150000170000001602705337263504010062 037777777777 1 0 ''' $Id: cu.1,v 1.2 1993/01/24 02:13:45 ian Rel $ .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. , (size_t) c, eto) != c) { ulog (LOG_ERROR, "fwrite: %s", strerror (errno)); (void) fclose (eto); (void) remove (zto); return FALSE; } } if (fclose (eto) != 0) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); (void) remove (zto); return FALSE; } return TRUE; } #else /* ! USE_STDIO */ #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONuucp-1.04/cu.c1004440004150000170000013762105337263505010151 037777777777 1 0 /* 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.19 1993/01/31 23:35:59 ian Rel $"; #endif #include "cu.h" #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "prot.h" #include "system.h" #include "sysdep.h" #include "getopt.h" #include #include #include /* Here are the user settable variables. The user is permitted to change these while running the program, using ~s. */ /* The escape character used to introduce a special command. The escape character is the first character of this string. */ const char *zCuvar_escape = "~"; /* Whether to delay for a second before printing the host name after seeing an escape character. */ boolean fCuvar_delay = TRUE; /* The input characters which finish a line. The escape character is only recognized following one of these characters. The default is carriage return, ^U, ^C, ^O, ^D, ^S, ^Q, ^R, which I got from the Ultrix /etc/remote file. */ const char *zCuvar_eol = "\r\025\003\017\004\023\021\022"; /* Whether to transfer binary data (nonprintable characters other than newline and tab) when sending a file. If this is FALSE, then newline is changed to carriage return. */ boolean fCuvar_binary = FALSE; /* A prefix string to use before sending a binary character from a file; this is only used if fCuvar_binary is TRUE. The default is ^Z. */ const char *zCuvar_binary_prefix = "\026"; /* Whether to check for echoes of characters sent when sending a file. This is ignored if fCuvar_binary is TRUE. */ boolean fCuvar_echocheck = FALSE; /* A character to look for after each newline is sent when sending a file. The character is the first character in this string, except that a '\0' means that no echo check is done. */ const char *zCuvar_echonl = "\r"; /* The timeout to use when looking for an character. */ int cCuvar_timeout = 30; /* The character to use to kill a line if an echo check fails. The first character in this string is sent. The default is ^U. */ const char *zCuvar_kill = "\025"; /* The number of times to try resending a line if the echo check keeps failing. */ int cCuvar_resend = 10; /* The string to send at the end of a file sent with ~>. The default is ^D. */ const char *zCuvar_eofwrite = "\004"; /* The string to look for to finish a file received with ~<. For tip this is a collection of single characters, but I don't want to do that because it means that there are characters which cannot be received. The default is a guess at a typical shell prompt. */ const char *zCuvar_eofread = "$"; /* Whether to provide verbose information when sending or receiving a file. */ boolean fCuvar_verbose = TRUE; /* The table used to give a value to a variable, and to print all the variable values. */ static const struct uuconf_cmdtab asCuvars[] = { { "escape", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_escape, NULL }, { "delay", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_delay, NULL }, { "eol", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eol, NULL }, { "binary", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_binary, NULL }, { "binary-prefix", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_binary_prefix, NULL }, { "echocheck", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_echocheck, NULL }, { "echonl", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_echonl, NULL }, { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_timeout, NULL }, { "kill", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_kill, NULL }, { "resend", UUCONF_CMDTABTYPE_INT, (pointer) &cCuvar_resend, NULL }, { "eofwrite", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofwrite, NULL }, { "eofread", UUCONF_CMDTABTYPE_STRING, (pointer) &zCuvar_eofread, NULL }, { "verbose", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fCuvar_verbose, NULL }, { NULL, 0, NULL, NULL} }; /* The program name. */ char abProgram[] = "cu"; /* The string printed at the initial connect. */ #if ANSI_C #define ZCONNMSG "\aConnected." #else #define ZCONNMSG "Connected." #endif /* The string printed when disconnecting. */ #if ANSI_C #define ZDISMSG "\aDisconnected." #else #define ZDISMSG "Disconnected." #endif /* Local variables. */ /* The string we print when the user is once again connected to the port after transferring a file or taking some other action. */ static const char abCuconnected[] #if ANSI_C = "\a[connected]"; #else = "[connected]"; #endif /* Global uuconf pointer. */ static pointer pCuuuconf; /* Connection. */ static struct sconnection *qCuconn; /* Whether to close the connection. */ static boolean fCuclose_conn; /* Dialer used to dial out. */ static struct uuconf_dialer *qCudialer; /* Whether we need to restore the terminal. */ static boolean fCurestore_terminal; /* Whether we are doing local echoing. */ static boolean fCulocalecho; /* Whether we need to call fsysdep_cu_finish. */ static boolean fCustarted; /* A structure used to pass information to icuport_lock. */ struct sconninfo { boolean fmatched; boolean flocked; struct sconnection *qconn; const char *zline; }; /* Local functions. */ static void ucuusage P((void)); static void ucuabort P((void)); static void uculog_start P((void)); static void uculog_end P((void)); static int icuport_lock P((struct uuconf_port *qport, pointer pinfo)); static boolean fcudo_cmd P((pointer puuconf, struct sconnection *qconn, int bcmd)); static boolean fcuset_var P((pointer puuconf, char *zline)); static int icuunrecogvar P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icuunrecogfn P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static void uculist_vars P((void)); static void uculist_fns P((const char *zescape)); static boolean fcudo_subcmd P((pointer puuconf, struct sconnection *qconn, char *zline)); static boolean fcusend_buf P((struct sconnection *qconn, const char *zbuf, size_t cbuf)); #define ucuputs(zline) \ do { if (! fsysdep_terminal_puts (zline)) ucuabort (); } while (0) /* Long getopt options. */ static const struct option asCulongopts[] = { { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* -c: phone number. */ char *zphone = NULL; /* -e: even parity. */ boolean feven = FALSE; /* -l: line. */ char *zline = NULL; /* -n: prompt for phone number. */ boolean fprompt = FALSE; /* -o: odd parity. */ boolean fodd = FALSE; /* -p: port name. */ const char *zport = NULL; /* -s: speed. */ long ibaud = 0L; /* -t: map cr to crlf. */ boolean fmapcr = FALSE; /* -z: system. */ const char *zsystem = NULL; /* -I: configuration file name. */ const char *zconfig = NULL; int iopt; pointer puuconf; int iuuconf; const char *zlocalname; int i; struct uuconf_system ssys; const struct uuconf_system *qsys = NULL; boolean flooped; struct uuconf_port sport; struct sconnection sconn; struct sconninfo sinfo; long ihighbaud; struct uuconf_dialer sdialer; struct uuconf_dialer *qdialer; char bcmd; /* We want to accept -# as a speed. It's easiest to look through the arguments, replace -# with -s#, and let getopt handle it. */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && isdigit (BUCHAR (argv[i][1]))) { size_t clen; char *z; clen = strlen (argv[i]); z = zbufalc (clen + 2); z[0] = '-'; z[1] = 's'; memcpy (z + 2, argv[i] + 1, clen); argv[i] = z; } } while ((iopt = getopt_long (argc, argv, "a:c:dehnI:l:op:s:tx:z:", asCulongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'c': /* Phone number. */ zphone = optarg; break; case 'd': /* Set debugging level to maximum. */ #if DEBUG > 1 iDebug = DEBUG_MAX; #endif break; case 'e': /* Even parity. */ feven = TRUE; break; case 'h': /* Local echo. */ fCulocalecho = TRUE; break; case 'n': /* Prompt for phone number. */ fprompt = TRUE; break; case 'l': /* Line name. */ zline = optarg; break; case 'o': /* Odd parity. */ fodd = TRUE; break; case 'p': case 'a': /* Port name (-a is for compatibility). */ zport = optarg; break; case 's': /* Speed. */ ibaud = strtol (optarg, (char **) NULL, 10); break; case 't': /* Map cr to crlf. */ fmapcr = TRUE; break; case 'z': /* System name. */ zsystem = optarg; break; case 'I': /* Configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 0: /* Long option found and flag set. */ break; default: ucuusage (); break; } } /* There can be one more argument, which is either a system name, a phone number, or "dir". We decide which it is based on the first character. To call a UUCP system whose name begins with a digit, or one which is named "dir", you must use -z. */ if (optind != argc) { if (optind != argc - 1 || zsystem != NULL || zphone != NULL) ucuusage (); if (strcmp (argv[optind], "dir") != 0) { if (isdigit (BUCHAR (argv[optind][0]))) zphone = argv[optind]; else zsystem = argv[optind]; } } /* If the user doesn't give a system, port, line or speed, then there's no basis on which to select a port. */ if (zsystem == NULL && zport == NULL && zline == NULL && ibaud == 0L) ucuusage (); if (fprompt) { size_t cphone; printf ("Phone number: "); (void) fflush (stdout); zphone = NULL; cphone = 0; if (getline (&zphone, &cphone, stdin) <= 0 || *zphone == '\0') { fprintf (stderr, "%s: No phone number entered\n", abProgram); exit (EXIT_FAILURE); } } iuuconf = uuconf_init (&puuconf, "cu", zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); pCuuuconf = puuconf; #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif usysdep_initialize (puuconf, INIT_NOCHDIR | INIT_SUID); iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) exit (EXIT_FAILURE); } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); ulog_fatal_fn (ucuabort); pfLstart = uculog_start; pfLend = uculog_end; #ifdef SIGINT usysdep_signal (SIGINT); #endif #ifdef SIGHUP usysdep_signal (SIGHUP); #endif #ifdef SIGQUIT usysdep_signal (SIGQUIT); #endif #ifdef SIGTERM usysdep_signal (SIGTERM); #endif #ifdef SIGPIPE usysdep_signal (SIGPIPE); #endif if (zsystem != NULL) { iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); ulog (LOG_FATAL, "%s: System not found", zsystem); } qsys = &ssys; } /* This loop is used if a system is specified. It loops over the various alternates until it finds one for which the dial succeeds. This is an ugly spaghetti construction, and it should be broken up into different functions someday. */ flooped = FALSE; while (TRUE) { enum tparitysetting tparity; enum tstripsetting tstrip; /* The uuconf_find_port function only selects directly on a port name and a speed. To select based on the line name, we use a function. If we can't find any defined port, and the user specified a line name but did not specify a port name or a system or a phone number, then we fake a direct port with that line name (we don't fake a port if a system or phone number were given because if we fake a port we have no way to place a call; perhaps we should automatically look up a particular dialer). This permits users to say cu -lttyd0 without having to put ttyd0 in the ports file, provided they have read and write access to the port. */ sinfo.fmatched = FALSE; sinfo.flocked = FALSE; sinfo.qconn = &sconn; sinfo.zline = zline; if (zport != NULL || zline != NULL || ibaud != 0L) { iuuconf = uuconf_find_port (puuconf, zport, ibaud, 0L, icuport_lock, (pointer) &sinfo, &sport); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { if (sinfo.flocked) { (void) fconn_unlock (&sconn); uconn_free (&sconn); } ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } if (zline == NULL || zport != NULL || zphone != NULL || qsys != NULL) { if (sinfo.fmatched) ulog (LOG_FATAL, "All matching ports in use"); else ulog (LOG_FATAL, "No matching ports"); } sport.uuconf_zname = zline; sport.uuconf_ttype = UUCONF_PORTTYPE_DIRECT; sport.uuconf_zprotocols = NULL; sport.uuconf_qproto_params = NULL; sport.uuconf_ireliable = 0; sport.uuconf_zlockname = NULL; sport.uuconf_palloc = NULL; sport.uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL; sport.uuconf_u.uuconf_sdirect.uuconf_ibaud = ibaud; if (! fsysdep_port_access (&sport)) ulog (LOG_FATAL, "%s: Permission denied", zline); if (! fconn_init (&sport, &sconn)) ucuabort (); if (! fconn_lock (&sconn, FALSE)) ulog (LOG_FATAL, "%s: Line in use", zline); qCuconn = &sconn; } ihighbaud = 0L; } else { for (; qsys != NULL; qsys = qsys->uuconf_qalternate) { if (! qsys->uuconf_fcall) continue; if (qsys->uuconf_qport != NULL) { if (fconn_init (qsys->uuconf_qport, &sconn)) { if (fconn_lock (&sconn, FALSE)) { qCuconn = &sconn; break; } uconn_free (&sconn); } } else { sinfo.fmatched = FALSE; sinfo.flocked = FALSE; sinfo.qconn = &sconn; iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport, qsys->uuconf_ibaud, qsys->uuconf_ihighbaud, icuport_lock, (pointer) &sinfo, &sport); if (iuuconf == UUCONF_SUCCESS) break; if (iuuconf != UUCONF_NOT_FOUND) { if (sinfo.flocked) { (void) fconn_unlock (&sconn); uconn_free (&sconn); } ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } } } if (qsys == NULL) { const char *zrem; if (flooped) zrem = "remaining "; else zrem = ""; if (sinfo.fmatched) ulog (LOG_FATAL, "%s: All %smatching ports in use", zsystem, zrem); else ulog (LOG_FATAL, "%s: No %smatching ports", zsystem, zrem); } ibaud = qsys->uuconf_ibaud; ihighbaud = qsys->uuconf_ihighbaud; } /* Here we have locked a connection to use. */ if (! fconn_open (&sconn, ibaud, ihighbaud, FALSE)) ucuabort (); fCuclose_conn = TRUE; if (FGOT_SIGNAL ()) ucuabort (); /* Set up the connection. */ if (fodd && feven) { tparity = PARITYSETTING_NONE; tstrip = STRIPSETTING_SEVENBITS; } else if (fodd) { tparity = PARITYSETTING_ODD; tstrip = STRIPSETTING_SEVENBITS; } else if (feven) { tparity = PARITYSETTING_EVEN; tstrip = STRIPSETTING_SEVENBITS; } else { tparity = PARITYSETTING_DEFAULT; tstrip = STRIPSETTING_DEFAULT; } if (! fconn_set (&sconn, tparity, tstrip, XONXOFF_ON)) ucuabort (); if (qsys != NULL) zphone = qsys->uuconf_zphone; if (qsys != NULL || zphone != NULL) { enum tdialerfound tdialer; if (! fconn_dial (&sconn, puuconf, qsys, zphone, &sdialer, &tdialer)) { if (zport != NULL || zline != NULL || ibaud != 0L || qsys == NULL) ucuabort (); if (qsys->uuconf_qalternate == NULL) ulog (LOG_FATAL, "%s: No remaining alternates", zsystem); fCuclose_conn = FALSE; (void) fconn_close (&sconn, pCuuuconf, qCudialer, FALSE); qCuconn = NULL; (void) fconn_unlock (&sconn); uconn_free (&sconn); /* Loop around and try another alternate. */ flooped = TRUE; continue; } if (tdialer == DIALERFOUND_FALSE) qdialer = NULL; else qdialer = &sdialer; } else { /* If no system or phone number was specified, we connect directly to the modem. We only permit this if the user has access to the port, since it permits various shenanigans such as reprogramming the automatic callbacks. */ if (! fsysdep_port_access (sconn.qport)) ulog (LOG_FATAL, "Access to port denied"); qdialer = NULL; if (! fconn_carrier (&sconn, FALSE)) ulog (LOG_FATAL, "Can't turn off carrier"); } break; } qCudialer = qdialer; if (FGOT_SIGNAL ()) ucuabort (); /* Here we have connected, and can start the main cu protocol. The program spends most of its time in system dependent code, and only comes out when a special command is received from the terminal. */ printf ("%s\n", ZCONNMSG); if (! fsysdep_terminal_raw (fCulocalecho)) ucuabort (); fCurestore_terminal = TRUE; if (! fsysdep_cu_init (&sconn)) ucuabort (); fCustarted = TRUE; while (fsysdep_cu (&sconn, &bcmd, zlocalname)) if (! fcudo_cmd (puuconf, &sconn, bcmd)) break; fCustarted = FALSE; if (! fsysdep_cu_finish ()) ucuabort (); fCurestore_terminal = FALSE; (void) fsysdep_terminal_restore (); (void) fconn_close (&sconn, puuconf, qdialer, TRUE); (void) fconn_unlock (&sconn); uconn_free (&sconn); printf ("\n%s\n", ZDISMSG); ulog_close (); usysdep_exit (TRUE); /* Avoid errors about not returning a value. */ return 0; } /* Print a usage message and die. */ static void ucuusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: cu [options] [system or phone-number]\n"); fprintf (stderr, " -a port, -p port: Use named port\n"); fprintf (stderr, " -l line: Use named device (e.g. tty0)\n"); fprintf (stderr, " -s speed, -#: Use given speed\n"); fprintf (stderr, " -c phone: Phone number to call\n"); fprintf (stderr, " -z system: System to call\n"); fprintf (stderr, " -e: Set even parity\n"); fprintf (stderr, " -o: Set odd parity\n"); fprintf (stderr, " -h: Echo locally\n"); fprintf (stderr, " -t: Map carriage return to carriage return/linefeed\n"); fprintf (stderr, " -n: Prompt for phone number\n"); fprintf (stderr, " -d: Set maximum debugging level\n"); fprintf (stderr, " -x debug: Set debugging type\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* This function is called when a fatal error occurs. */ static void ucuabort () { if (fCustarted) { fCustarted = FALSE; (void) fsysdep_cu_finish (); } if (fCurestore_terminal) { fCurestore_terminal = FALSE; (void) fsysdep_terminal_restore (); } if (qCuconn != NULL) { struct sconnection *qconn; if (fCuclose_conn) { fCuclose_conn = FALSE; (void) fconn_close (qCuconn, pCuuuconf, qCudialer, FALSE); } qconn = qCuconn; qCuconn = NULL; (void) fconn_unlock (qconn); uconn_free (qconn); } ulog_close (); printf ("\n%s\n", ZDISMSG); usysdep_exit (FALSE); } /* This variable is just used to communicate between uculog_start and uculog_end. */ static boolean fCulog_restore; /* This function is called by ulog before it output anything. We use it to restore the terminal, if necessary. ulog is only called for errors or debugging in cu, so it's not too costly to do this. If we didn't do it, then at least on Unix each line would leave the cursor in the same column rather than wrapping back to the start, since CRMOD will not be on. */ static void uculog_start () { if (! fCurestore_terminal) fCulog_restore = FALSE; else { fCulog_restore = TRUE; fCurestore_terminal = FALSE; if (! fsysdep_terminal_restore ()) ucuabort (); } } /* This function is called by ulog after everything is output. It sets the terminal back, if necessary. */ static void uculog_end () { if (fCulog_restore) { if (! fsysdep_terminal_raw (fCulocalecho)) ucuabort (); fCurestore_terminal = TRUE; } } /* Check to see if this port has the desired line, to handle the -l option. If it does, or if no line was specified, set up a connection and lock it. */ static int icuport_lock (qport, pinfo) struct uuconf_port *qport; pointer pinfo; { struct sconninfo *q = (struct sconninfo *) pinfo; if (q->zline != NULL && ! fsysdep_port_is_line (qport, q->zline)) return UUCONF_NOT_FOUND; q->fmatched = TRUE; if (! fconn_init (qport, q->qconn)) return UUCONF_NOT_FOUND; else if (! fconn_lock (q->qconn, FALSE)) { uconn_free (q->qconn); return UUCONF_NOT_FOUND; } else { qCuconn = q->qconn; q->flocked = TRUE; return UUCONF_SUCCESS; } } /* Execute a cu escape command. Return TRUE if the connection should continue, or FALSE if the connection should be terminated. */ static boolean fcudo_cmd (puuconf, qconn, bcmd) pointer puuconf; struct sconnection *qconn; int bcmd; { char *zline; char *z; char abescape[5]; boolean fret; size_t clen; char abbuf[100]; /* Some commands take a string up to the next newline character. */ switch (bcmd) { default: zline = NULL; break; case '!': case '$': case '|': case '+': case '%': case 'c': case '>': case '<': case 'p': case 't': case 's': { zline = zsysdep_terminal_line ((const char *) NULL); if (zline == NULL) ucuabort (); zline[strcspn (zline, "\n")] = '\0'; } break; } switch (bcmd) { default: if (! isprint (*zCuvar_escape)) sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); else { abescape[0] = *zCuvar_escape; abescape[1] = '\0'; } sprintf (abbuf, "[Unrecognized. Use %s%s to send %s]", abescape, abescape, abescape); ucuputs (abbuf); return TRUE; case '.': /* Hangup. */ return FALSE; case '!': case '$': case '|': case '+': /* Shell out. */ if (! fsysdep_cu_copy (FALSE) || ! fsysdep_terminal_restore ()) ucuabort (); fCurestore_terminal = FALSE; { enum tshell_cmd t; switch (bcmd) { default: case '!': t = SHELL_NORMAL; break; case '$': t = SHELL_STDOUT_TO_PORT; break; case '|': t = SHELL_STDIN_FROM_PORT; break; case '+': t = SHELL_STDIO_ON_PORT; break; } (void) fsysdep_shell (qconn, zline, t); } if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_raw (fCulocalecho)) ucuabort (); fCurestore_terminal = TRUE; ubuffree (zline); return TRUE; case '%': fret = fcudo_subcmd (puuconf, qconn, zline); ubuffree (zline); return fret; case '#': if (! fconn_break (qconn)) ucuabort (); return TRUE; case 'c': (void) fsysdep_chdir (zline); ubuffree (zline); return TRUE; case '>': case '<': case 'p': case 't': clen = strlen (zline); z = zbufalc (clen + 3); z[0] = bcmd; z[1] = ' '; memcpy (z + 2, zline, clen + 1); ubuffree (zline); fret = fcudo_subcmd (puuconf, qconn, z); ubuffree (z); return fret; case 'z': if (! fsysdep_cu_copy (FALSE) || ! fsysdep_terminal_restore ()) ucuabort (); fCurestore_terminal = FALSE; if (! fsysdep_suspend ()) ucuabort (); if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_raw (fCulocalecho)) ucuabort (); fCurestore_terminal = TRUE; return TRUE; case 's': fret = fcuset_var (puuconf, zline); ubuffree (zline); return fret; case 'v': uculist_vars (); return TRUE; case '?': if (! isprint (*zCuvar_escape)) sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); else { abescape[0] = *zCuvar_escape; abescape[1] = '\0'; } ucuputs (""); ucuputs ("[Escape sequences]"); sprintf (abbuf, "[%s. hangup] [%s!CMD run shell]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%s$CMD stdout to remote] [%s|CMD stdin from remote]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%s+CMD stdin and stdout to remote]", abescape); ucuputs (abbuf); sprintf (abbuf, "[%s# send break] [%scDIR change directory]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%s> send file] [%s< receive file]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%spFROM TO send to Unix] [%stFROM TO receive from Unix]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%ssVAR VAL set variable] [%ssVAR set boolean]", abescape, abescape); ucuputs (abbuf); sprintf (abbuf, "[%ss!VAR unset boolean] [%sv list variables]", abescape, abescape); ucuputs (abbuf); #ifdef SIGTSTP sprintf (abbuf, "[%sz suspend]", abescape); ucuputs (abbuf); #endif uculist_fns (abescape); return TRUE; } } /* List ~% functions. */ static void uculist_fns (zescape) const char *zescape; { char abbuf[100]; sprintf (abbuf, "[%s%%break send break] [%s%%cd DIR change directory]", zescape, zescape); ucuputs (abbuf); sprintf (abbuf, "[%s%%put FROM TO send file] [%s%%take FROM TO receive file]", zescape, zescape); ucuputs (abbuf); sprintf (abbuf, "[%s%%nostop no XON/XOFF] [%s%%stop use XON/XOFF]", zescape, zescape); ucuputs (abbuf); } /* Set a variable. */ static boolean fcuset_var (puuconf, zline) pointer puuconf; char *zline; { char *zvar, *zval; char *azargs[2]; char azbool[2]; int iuuconf; zvar = strtok (zline, "= \t"); if (zvar == NULL) { ucuputs (abCuconnected); return TRUE; } zval = strtok ((char *) NULL, " \t"); if (zval == NULL) { azargs[0] = zvar; if (azargs[0][0] != '!') azbool[0] = 't'; else { ++azargs[0]; azbool[0] = 'f'; } azbool[1] = '\0'; azargs[1] = azbool; } else { azargs[0] = zvar; azargs[1] = zval; } iuuconf = uuconf_cmd_args (puuconf, 2, azargs, asCuvars, (pointer) NULL, icuunrecogvar, 0, (pointer) NULL); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return TRUE; } /* Warn about an unknown variable. */ /*ARGSUSED*/ static int icuunrecogvar (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { char abescape[5]; if (! isprint (*zCuvar_escape)) sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); else { abescape[0] = *zCuvar_escape; abescape[1] = '\0'; } ulog (LOG_ERROR, "%s: unknown variable (%sv lists variables)", argv[0], abescape); return UUCONF_CMDTABRET_CONTINUE; } /* List all the variables with their values. */ static void uculist_vars () { const struct uuconf_cmdtab *q; char abbuf[100]; ucuputs (""); for (q = asCuvars; q->uuconf_zcmd != NULL; q++) { switch (UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype)) { case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN): if (*(boolean *) q->uuconf_pvar) sprintf (abbuf, "%s true", q->uuconf_zcmd); else sprintf (abbuf, "%s false", q->uuconf_zcmd); break; case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT): sprintf (abbuf, "%s %d", q->uuconf_zcmd, *(int *) q->uuconf_pvar); break; case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG): sprintf (abbuf, "%s %ld", q->uuconf_zcmd, *(long *) q->uuconf_pvar); break; case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING): case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING): { const char *z; char abchar[5]; size_t clen; sprintf (abbuf, "%s ", q->uuconf_zcmd); clen = strlen (abbuf); for (z = *(const char **) q->uuconf_pvar; *z != '\0'; z++) { int cchar; if (! isprint (*z)) { sprintf (abchar, "\\%03o", (unsigned int) *z); cchar = 4; } else { abchar[0] = *z; abchar[1] = '\0'; cchar = 1; } if (clen + cchar < sizeof (abbuf)) strcat (abbuf, abchar); clen += cchar; } } break; default: sprintf (abbuf, "%s [unprintable type]", q->uuconf_zcmd); break; } ucuputs (abbuf); } } /* Subcommands. These are commands that begin with ~%. */ /* This variable is only used so that we can pass a non-NULL address in pvar. It is never assigned to or examined. */ static char bCutype; /* The command table for the subcommands. */ static int icubreak P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icudebug P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icuchdir P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icuput P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icutake P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int icunostop P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static const struct uuconf_cmdtab asCucmds[] = { { "break", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak }, { "b", UUCONF_CMDTABTYPE_FN | 1, NULL, icubreak }, { "cd", UUCONF_CMDTABTYPE_FN | 0, NULL, icuchdir }, { "d", UUCONF_CMDTABTYPE_FN | 1, NULL, icudebug }, { "put", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput }, { "take", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake }, { "nostop", UUCONF_CMDTABTYPE_FN | 1, NULL, icunostop }, { "stop", UUCONF_CMDTABTYPE_FN | 1, &bCutype, icunostop }, { ">", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icuput }, { "<", UUCONF_CMDTABTYPE_FN | 0, &bCutype, icutake }, { "p", UUCONF_CMDTABTYPE_FN | 0, NULL, icuput }, { "t", UUCONF_CMDTABTYPE_FN | 0, NULL, icutake }, { NULL, 0, NULL, NULL } }; /* Do a subcommand. This is called by commands beginning with ~%. */ static boolean fcudo_subcmd (puuconf, qconn, zline) pointer puuconf; struct sconnection *qconn; char *zline; { char *azargs[3]; int iarg; int iuuconf; for (iarg = 0; iarg < 3; iarg++) { azargs[iarg] = strtok (iarg == 0 ? zline : (char *) NULL, " \t\n"); if (azargs[iarg] == NULL) break; } if (iarg == 0) { ucuputs (abCuconnected); return TRUE; } iuuconf = uuconf_cmd_args (puuconf, iarg, azargs, asCucmds, (pointer) qconn, icuunrecogfn, 0, (pointer) NULL); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return TRUE; } /* Warn about an unknown function. */ /*ARGSUSED*/ static int icuunrecogfn (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { char abescape[5]; if (! isprint (*zCuvar_escape)) sprintf (abescape, "\\%03o", (unsigned int) *zCuvar_escape); else { abescape[0] = *zCuvar_escape; abescape[1] = '\0'; } if (argv[0][0] == '?') uculist_fns (abescape); else ulog (LOG_ERROR, "%s: unknown (%s%%? lists choices)", argv[0], abescape); return UUCONF_CMDTABRET_CONTINUE; } /* Send a break. */ /*ARGSUSED*/ static int icubreak (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { struct sconnection *qconn = (struct sconnection *) pinfo; if (! fconn_break (qconn)) ucuabort (); return UUCONF_CMDTABRET_CONTINUE; } /* Change directories. */ /*ARGSUSED*/ static int icuchdir (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { const char *zarg; if (argc <= 1) zarg = NULL; else zarg = argv[1]; (void) fsysdep_chdir (zarg); return UUCONF_CMDTABRET_CONTINUE; } /* Toggle debugging. */ /*ARGSUSED*/ static int icudebug (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { #if DEBUG > 1 if (iDebug != 0) iDebug = 0; else iDebug = DEBUG_MAX; #else ucuputs ("[compiled without debugging]"); #endif return UUCONF_CMDTABRET_CONTINUE; } /* Control whether the port does xon/xoff handshaking. If pvar is not NULL, this is "stop"; otherwise it is "nostop". */ /*ARGSUSED*/ static int icunostop (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { struct sconnection *qconn = (struct sconnection *) pinfo; if (! fconn_set (qconn, PARITYSETTING_DEFAULT, STRIPSETTING_DEFAULT, pvar == NULL ? XONXOFF_OFF : XONXOFF_ON)) ucuabort (); return UUCONF_CMDTABRET_CONTINUE; } /* Send a file to the remote system. The first argument is the file to send. If that argument is not present, it is prompted for. The second argument is to file name to use on the remote system. If that argument is not present, the basename of the local filename is used. If pvar is not NULL, then this is ~>, which is used to send a command to a non-Unix system. We treat is the same as ~%put, except that we assume the user has already entered the appropriate command (for ~%put, we force ``cat >to'' to the other side). */ /*ARGSUSED*/ static int icuput (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { struct sconnection *qconn = (struct sconnection *) pinfo; char *zfrom; char *zto = NULL; char *zalc; openfile_t e; int cline; char *zbuf; size_t cbuf; if (argc > 1) zfrom = zbufcpy (argv[1]); else { zfrom = zsysdep_terminal_line ("File to send: "); if (zfrom == NULL) ucuabort (); zfrom[strcspn (zfrom, " \t\n")] = '\0'; if (*zfrom == '\0') { ubuffree (zfrom); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } } if (pvar == NULL) { if (argc > 2) zto = zbufcpy (argv[2]); else { char *zbase; char *zprompt; zbase = zsysdep_base_name (zfrom); if (zbase == NULL) ucuabort (); zprompt = zbufalc (sizeof "Remote file name []: " + strlen (zbase)); sprintf (zprompt, "Remote file name [%s]: ", zbase); zto = zsysdep_terminal_line (zprompt); ubuffree (zprompt); if (zto == NULL) ucuabort (); zto[strcspn (zto, " \t\n")] = '\0'; if (*zto != '\0') ubuffree (zbase); else { ubuffree (zto); zto = zbase; } } } e = esysdep_user_fopen (zfrom, TRUE, fCuvar_binary); if (! ffileisopen (e)) { const char *zerrstr; if (pvar == NULL) ubuffree (zto); zerrstr = strerror (errno); zalc = zbufalc (strlen (zfrom) + sizeof ": " + strlen (zerrstr)); sprintf (zalc, "%s: %s", zfrom, zerrstr); ubuffree (zfrom); ucuputs (zalc); ubuffree (zalc); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } ubuffree (zfrom); /* Tell the system dependent layer to stop copying data from the port to the terminal. We want to read the echoes ourself. Also permit the local user to generate signals. */ if (! fsysdep_cu_copy (FALSE) || ! fsysdep_terminal_signals (TRUE)) ucuabort (); /* If pvar is NULL, then we are sending a file to a Unix system. We send over the command "cat > TO" to prepare it to receive. If pvar is not NULL, the user is assumed to have set up whatever action was needed to receive the file. */ if (pvar == NULL) { boolean fret; zalc = zbufalc (sizeof "cat > \n" + strlen (zto)); sprintf (zalc, "cat > %s\n", zto); ubuffree (zto); fret = fcusend_buf (qconn, zalc, strlen (zalc)); ubuffree (zalc); if (! fret) { (void) ffileclose (e); if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_signals (FALSE)) ucuabort (); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } } cline = 0; zbuf = NULL; cbuf = 0; while (TRUE) { char abbuf[512]; size_t c; #if USE_STDIO if (fCuvar_binary) #endif { if (ffileeof (e)) break; c = cfileread (e, abbuf, sizeof abbuf); if (ffilereaderror (e, c)) { ucuputs ("[file read error]"); break; } if (c == 0) break; zbuf = abbuf; } #if USE_STDIO else { if (getline (&zbuf, &cbuf, e) <= 0) { xfree ((pointer) zbuf); break; } c = strlen (zbuf); } #endif if (fCuvar_verbose) { ++cline; printf ("%d ", cline); (void) fflush (stdout); } if (! fcusend_buf (qconn, zbuf, c)) { if (! fCuvar_binary) xfree ((pointer) zbuf); (void) fclose (e); if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_signals (FALSE)) ucuabort (); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } } (void) ffileclose (e); if (pvar == NULL) { char beof; beof = '\004'; if (! fconn_write (qconn, &beof, 1)) ucuabort (); } else { if (*zCuvar_eofwrite != '\0') { if (! fconn_write (qconn, zCuvar_eofwrite, strlen (zCuvar_eofwrite))) ucuabort (); } } if (fCuvar_verbose) ucuputs (""); ucuputs ("[file transfer complete]"); if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_signals (FALSE)) ucuabort (); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } /* Get a file from the remote side. This is ~%take, or ~t, or ~<. The first two are assumed to be taking the file from a Unix system, so we force the command "cat FROM; echo */ /*ARGSUSED*/ static int icutake (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { struct sconnection *qconn = (struct sconnection *) pinfo; const char *zeof; char *zfrom, *zto, *zcmd; char *zalc; openfile_t e; char bcr; size_t ceoflen; char *zlook = NULL; size_t ceofhave; boolean ferr; if (argc > 1) zfrom = zbufcpy (argv[1]); else { zfrom = zsysdep_terminal_line ("Remote file to retreive: "); if (zfrom == NULL) ucuabort (); zfrom[strcspn (zfrom, " \t\n")] = '\0'; if (*zfrom == '\0') { ubuffree (zfrom); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } } if (argc > 2) zto = zbufcpy (argv[2]); else { char *zbase; char *zprompt; zbase = zsysdep_base_name (zfrom); if (zbase == NULL) ucuabort (); zprompt = zbufalc (sizeof "Local file name []: " + strlen (zbase)); sprintf (zprompt, "Local file name [%s]: ", zbase); zto = zsysdep_terminal_line (zprompt); ubuffree (zprompt); if (zto == NULL) ucuabort (); zto[strcspn (zto, " \t\n")] = '\0'; if (*zto != '\0') ubuffree (zbase); else { ubuffree (zto); zto = zbase; } } if (pvar != NULL) { zcmd = zsysdep_terminal_line ("Remote command to execute: "); if (zcmd == NULL) ucuabort (); zcmd[strcspn (zcmd, "\n")] = '\0'; zeof = zCuvar_eofread; } else { zcmd = zbufalc (sizeof "cat ; echo; echo ////cuend////" + strlen (zfrom)); sprintf (zcmd, "cat %s; echo; echo ////cuend////", zfrom); zeof = "\n////cuend////\n"; } ubuffree (zfrom); e = esysdep_user_fopen (zto, FALSE, fCuvar_binary); if (! ffileisopen (e)) { const char *zerrstr; ubuffree (zcmd); zerrstr = strerror (errno); zalc = zbufalc (strlen (zto) + sizeof ": " + strlen (zerrstr)); sprintf (zalc, "%s: %s\n", zto, zerrstr); ucuputs (zalc); ubuffree (zalc); ucuputs (abCuconnected); ubuffree (zto); return UUCONF_CMDTABRET_CONTINUE; } ubuffree (zto); if (! fsysdep_cu_copy (FALSE) || ! fsysdep_terminal_signals (TRUE)) ucuabort (); if (! fconn_write (qconn, zcmd, strlen (zcmd))) ucuabort (); bcr = '\r'; if (! fconn_write (qconn, &bcr, 1)) ucuabort (); ubuffree (zcmd); /* Eliminated any previously echoed data to avoid confusion. */ iPrecstart = 0; iPrecend = 0; /* If we're dealing with a Unix system, we can reliably discard the command. Otherwise, the command will probably wind up in the file; too bad. */ if (pvar == NULL) { int b; while ((b = breceive_char (qconn, cCuvar_timeout, TRUE)) != '\n') { if (b == -2) ucuabort (); if (b < 0) { ucuputs ("[timed out waiting for newline]"); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } } } ceoflen = strlen (zeof); zlook = zbufalc (ceoflen); ceofhave = 0; ferr = FALSE; while (TRUE) { int b; if (FGOT_SIGNAL ()) { /* Make sure the signal is logged. */ ulog (LOG_ERROR, (const char *) NULL); ucuputs ("[file receive aborted]"); /* Reset the SIGINT flag so that it does not confuse us in the future. */ afSignal[INDEXSIG_SIGINT] = FALSE; break; } b = breceive_char (qconn, cCuvar_timeout, TRUE); if (b == -2) ucuabort (); if (b < 0) { if (ceofhave > 0) (void) fwrite (zlook, sizeof (char), ceofhave, e); ucuputs ("[timed out]"); break; } if (ceoflen == 0) { if (cfilewrite (e, &b, 1) != 1) { ferr = TRUE; break; } } else { zlook[ceofhave] = b; ++ceofhave; if (ceofhave == ceoflen) { size_t cmove; char *zmove; if (memcmp (zeof, zlook, ceoflen) == 0) { ucuputs ("[file transfer complete]"); break; } if (cfilewrite (e, zlook, 1) != 1) { ferr = TRUE; break; } zmove = zlook; for (cmove = ceoflen - 1, zmove = zlook; cmove > 0; cmove--, zmove++) zmove[0] = zmove[1]; --ceofhave; } } } ubuffree (zlook); if (! ffileclose (e)) ferr = TRUE; if (ferr) ucuputs ("[file write error]"); if (! fsysdep_cu_copy (TRUE) || ! fsysdep_terminal_signals (FALSE)) ucuabort (); ucuputs (abCuconnected); return UUCONF_CMDTABRET_CONTINUE; } /* Send a buffer to the remote system. If fCuvar_binary is FALSE, each buffer passed in will be a single line; in this case we can check the echoed characters and kill the line if they do not match. This returns FALSE if an echo check fails. If a port error occurrs, it calls ucuabort. */ static boolean fcusend_buf (qconn, zbufarg, cbufarg) struct sconnection *qconn; const char *zbufarg; size_t cbufarg; { const char *zbuf; size_t cbuf; int ctries; size_t cbplen; char *zsendbuf; zbuf = zbufarg; cbuf = cbufarg; ctries = 0; if (fCuvar_binary) cbplen = strlen (zCuvar_binary_prefix); else cbplen = 1; zsendbuf = zbufalc (64 * (cbplen + 1)); /* Loop while we still have characters to send. The value of cbuf will be reset to cbufarg if an echo failure occurs while sending a line in non-binary mode. */ while (cbuf > 0) { int csend; char *zput; const char *zget; boolean fnl; int i; if (FGOT_SIGNAL ()) { /* Make sure the signal is logged. */ ubuffree (zsendbuf); ulog (LOG_ERROR, (const char *) NULL); ucuputs ("[file send aborted]"); /* Reset the SIGINT flag so that it does not confuse us in the future. */ afSignal[INDEXSIG_SIGINT] = FALSE; return FALSE; } /* Discard anything we've read from the port up to now, to avoid confusing the echo checking. */ iPrecstart = 0; iPrecend = 0; /* Send all characters up to a newline before actually sending the newline. This makes it easier to handle the special newline echo checking. Send up to 64 characters at a time before doing echo checking. */ if (*zbuf == '\n') csend = 1; else { const char *znl; znl = memchr (zbuf, '\n', cbuf); if (znl == NULL) csend = cbuf; else csend = znl - zbuf; if (csend > 64) csend = 64; } /* Translate this part of the buffer. If we are not in binary mode, we translate \n to \r, and ignore any nonprintable characters. */ zput = zsendbuf; fnl = FALSE; for (i = 0, zget = zbuf; i < csend; i++, zget++) { if (isprint (*zget) || *zget == '\t') *zput++ = *zget; else if (*zget == '\n') { if (fCuvar_binary) *zput++ = '\n'; else *zput++ = '\r'; fnl = TRUE; } else if (fCuvar_binary) { strcpy (zput, zCuvar_binary_prefix); zput += cbplen; *zput++ = *zget; } } zbuf += csend; cbuf -= csend; if (zput == zsendbuf) continue; /* Send the data over the port. */ if (! fsend_data (qconn, zsendbuf, (size_t) (zput - zsendbuf), TRUE)) ucuabort (); /* We do echo checking if requested, unless we are in binary mode. Echo checking of a newline is different from checking of normal characters; when we send a newline we look for *zCuvar_echonl. */ if ((fCuvar_echocheck && ! fCuvar_binary) || (fnl && *zCuvar_echonl != '\0')) { long iend; iend = ixsysdep_time ((long *) NULL) + (long) cCuvar_timeout; for (zget = zsendbuf; zget < zput; zget++) { int bread; int bwant; if (fCuvar_binary ? *zget == '\n' : *zget == '\r') { bwant = *zCuvar_echonl; if (bwant == '\0') continue; } else { if (! fCuvar_echocheck || ! isprint (*zget)) continue; bwant = *zget; } do { if (FGOT_SIGNAL ()) { /* Make sure the signal is logged. */ ubuffree (zsendbuf); ulog (LOG_ERROR, (const char *) NULL); ucuputs ("[file send aborted]"); /* Reset the SIGINT flag so that it does not confuse us in the future. */ afSignal[INDEXSIG_SIGINT] = FALSE; return FALSE; } bread = breceive_char (qconn, iend - ixsysdep_time ((long *) NULL), TRUE); if (bread < 0) { if (bread == -2) ucuabort (); /* If we timed out, and we're not in binary mode, we kill the line and try sending it again from the beginning. */ if (! fCuvar_binary && *zCuvar_kill != '\0') { ++ctries; if (ctries < cCuvar_resend) { if (fCuvar_verbose) { printf ("R "); (void) fflush (stdout); } if (! fsend_data (qconn, zCuvar_kill, 1, TRUE)) ucuabort (); zbuf = zbufarg; cbuf = cbufarg; break; } } ubuffree (zsendbuf); ucuputs ("[timed out looking for echo]"); return FALSE; } } while (bread != *zget); if (bread < 0) break; } } } ubuffree (zsendbuf); return TRUE; } } if (! fcusend_buf (qconn, zbuf, c)) { if (! fCuvar_binary) xfree ((pointer) zbuf); (void)uucp-1.04/cu.h1004440004150000170000000574705337263505010161 037777777777 1 0 /* 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; command will probably wiuucp-1.04/getopt.h1004440004150000170000001007305337263505011040 037777777777 1 0 /* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. This file was modified slightly by Ian Lance Taylor, November 1992, for Taylor UUCP. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* Ian Lance Taylor added the following defines for Taylor UUCP. This avoids reported conflicts with system getopt definitions. */ #define getopt gnu_getopt #define optarg gnu_optarg #define optind gnu_optind #define opterr gnu_opterr /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { const char *name; /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ enum _argtype { no_argument, required_argument, optional_argument }; extern int getopt P((int argc, char *const *argv, const char *shortopts)); extern int getopt_long P((int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind)); extern int getopt_long_only P((int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind)); /* Internal only. Users should not call this directly. */ extern int _getopt_internal P((int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only)); #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ 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 = *zCuucp-1.04/log.c1004440004150000170000004055605337263506010324 037777777777 1 0 /* 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.40 1993/01/17 04:18:19 ian Rel $"; #endif #include #if ANSI_C #include #endif #if HAVE_TIME_H #include #endif #include "uudefs.h" #include "uuconf.h" #include "system.h" /* Local functions. */ static const char *zldate_and_time P((void)); /* Log file name. */ static const char *zLogfile; /* The function to call when a LOG_FATAL error occurs. */ static void (*pfLfatal) P((void)); /* Whether to go to a file. */ static boolean fLfile; /* ID number. */ static int iLid; /* The current user name. */ static char *zLuser; /* The current system name. */ static char *zLsystem; /* The current device name. */ char *zLdevice; /* The open log file. */ static FILE *eLlog; /* Whether we have tried to open the log file. We need this because we don't want to keep trying to open the log file if we failed the first time. It can't be static because under HAVE_HDB_LOGGING we may have to write to various different log files. */ static boolean fLlog_tried; #if DEBUG > 1 /* Debugging file name. */ static const char *zLdebugfile; /* The open debugging file. */ static FILE *eLdebug; /* Whether we've tried to open the debugging file. */ static boolean fLdebug_tried; /* Whether we've written out any debugging information. */ static boolean fLdebugging; #endif /* Statistics file name. */ static const char *zLstatsfile; /* The open statistics file. */ static FILE *eLstats; /* Whether we've tried to open the statistics file. */ static boolean fLstats_tried; /* The array of signals. The elements are only set to TRUE by the default signal handler. They are only set to FALSE if we don't care whether we got the signal or not. */ volatile sig_atomic_t afSignal[INDEXSIG_COUNT]; /* The array of signals to log. The elements are only set to TRUE by the default signal handler. They are set to FALSE when the signal is logged in ulog. This means that if a signal comes in at just the right time we won't log it (or, rather, we'll log it once instead of twice), but that is not a catatrophe. */ volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT]; /* Flag that indicates SIGHUP is worth logging. */ boolean fLog_sighup = TRUE; /* Signal names to use when logging signals. */ static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES; /* If not NULL, ulog calls this function before outputting anything. This is used to support cu. */ void (*pfLstart) P((void)); /* If not NULL, ulog calls this function after outputting everything. This is used to support cu. */ void (*pfLend) P((void)); /* Set the function to call on a LOG_FATAL error. */ void ulog_fatal_fn (pfn) void (*pfn) P((void)); { pfLfatal = pfn; } /* Decide whether to send log message to the file or not. */ void ulog_to_file (puuconf, ffile) pointer puuconf; boolean ffile; { int iuuconf; iuuconf = uuconf_logfile (puuconf, &zLogfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 iuuconf = uuconf_debugfile (puuconf, &zLdebugfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #endif iuuconf = uuconf_statsfile (puuconf, &zLstatsfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); fLfile = ffile; } /* Set the ID number. This will be called by the usysdep_initialize if there is something sensible to set it to. */ void ulog_id (i) int i; { iLid = i; } /* Set the user we are making log entries for. The arguments will be copied into memory. */ void ulog_user (zuser) const char *zuser; { ubuffree (zLuser); zLuser = zbufcpy (zuser); } /* Set the system name we are making log entries for. The name is copied into memory. */ void ulog_system (zsystem) const char *zsystem; { if (zsystem == NULL || zLsystem == NULL || strcmp (zsystem, zLsystem) != 0) { ubuffree (zLsystem); zLsystem = zbufcpy (zsystem); #if HAVE_HDB_LOGGING /* Under HDB logging we now must write to a different log file. */ ulog_close (); #endif /* HAVE_HDB_LOGGING */ } } /* Set the device name. This is copied into memory. */ void ulog_device (zdevice) const char *zdevice; { ubuffree (zLdevice); zLdevice = zbufcpy (zdevice); } /* Make a log entry. We make a token concession to non ANSI_C systems, but it clearly won't always work. */ #if ! ANSI_C #undef HAVE_VFPRINTF #endif /*VARARGS2*/ #if HAVE_VFPRINTF void ulog (enum tlog ttype, const char *zmsg, ...) #else void ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j) enum tlog ttype; const char *zmsg; #endif { #if HAVE_VFPRINTF va_list parg; #endif FILE *e, *edebug; boolean fstart, fend; const char *zhdr, *zstr; /* Log any received signal. We do it this way to avoid calling ulog from the signal handler. A few routines call ulog to get this message out with zmsg == NULL. */ { static boolean fdoing_sigs; if (! fdoing_sigs) { int isig; fdoing_sigs = TRUE; for (isig = 0; isig < INDEXSIG_COUNT; isig++) { if (afLog_signal[isig]) { afLog_signal[isig] = FALSE; /* Apparently SunOS sends SIGINT rather than SIGHUP when hanging up, so we don't log either signal if fLog_sighup is FALSE. */ if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT) || fLog_sighup) ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]); } } fdoing_sigs = FALSE; } } if (zmsg == NULL) return; #if DEBUG > 1 /* If we've had a debugging file open in the past, then we want to write all log file entries to the debugging file even if it's currently closed. */ if (fLfile && eLdebug == NULL && ! fLdebug_tried && (fLdebugging || (int) ttype >= (int) LOG_DEBUG)) { fLdebug_tried = TRUE; eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE); fLdebugging = TRUE; } #endif /* DEBUG > 1 */ if (! fLfile) e = stderr; #if DEBUG > 1 else if ((int) ttype >= (int) LOG_DEBUG) { e = eLdebug; /* If we can't open the debugging file, don't output any debugging messages. */ if (e == NULL) return; } #endif /* DEBUG > 1 */ else { if (eLlog == NULL && ! fLlog_tried) { fLlog_tried = TRUE; #if ! HAVE_HDB_LOGGING eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE); #else /* HAVE_HDB_LOGGING */ { const char *zsys; char *zfile; /* We want to write to .Log/program/system, e.g. .Log/uucico/uunet. The system name may not be set. */ if (zLsystem == NULL) zsys = "ANY"; else zsys = zLsystem; zfile = zbufalc (strlen (zLogfile) + strlen (abProgram) + strlen (zsys) + 1); sprintf (zfile, zLogfile, abProgram, zsys); eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE); ubuffree (zfile); } #endif /* HAVE_HDB_LOGGING */ if (eLlog == NULL) { /* We can't open the log file. We don't even have a safe way to report this problem, since we may not be able to write to stderr (it may, for example, be attached to the incoming call). */ if (pfLfatal != NULL) (*pfLfatal) (); usysdep_exit (FALSE); } } e = eLlog; /* eLlog might be NULL here because we might try to open the log file recursively via esysdep_fopen. */ if (e == NULL) return; } if (pfLstart != NULL) (*pfLstart) (); edebug = NULL; #if DEBUG > 1 if ((int) ttype < (int) LOG_DEBUG) edebug = eLdebug; #endif fstart = TRUE; fend = TRUE; switch (ttype) { case LOG_NORMAL: zhdr = ""; break; case LOG_ERROR: zhdr = "ERROR: "; break; case LOG_FATAL: zhdr = "FATAL: "; break; #if DEBUG > 1 case LOG_DEBUG: zhdr = "DEBUG: "; break; case LOG_DEBUG_START: zhdr = "DEBUG: "; fend = FALSE; break; case LOG_DEBUG_CONTINUE: zhdr = NULL; fstart = FALSE; fend = FALSE; break; case LOG_DEBUG_END: zhdr = NULL; fstart = FALSE; break; #endif default: zhdr = "???: "; break; } if (fstart) { if (! fLfile) { fprintf (e, "%s: ", abProgram); if (edebug != NULL) fprintf (edebug, "%s: ", abProgram); } else { #if HAVE_TAYLOR_LOGGING fprintf (e, "%s ", abProgram); if (edebug != NULL) fprintf (edebug, "%s ", abProgram); #else /* ! HAVE_TAYLOR_LOGGING */ fprintf (e, "%s ", zLuser == NULL ? "uucp" : zLuser); if (edebug != NULL) fprintf (edebug, "%s ", zLuser == NULL ? "uucp" : zLuser); #endif /* HAVE_TAYLOR_LOGGING */ fprintf (e, "%s ", zLsystem == NULL ? "-" : zLsystem); if (edebug != NULL) fprintf (edebug, "%s ", zLsystem == NULL ? "-" : zLsystem); #if HAVE_TAYLOR_LOGGING fprintf (e, "%s ", zLuser == NULL ? "-" : zLuser); if (edebug != NULL) fprintf (edebug, "%s ", zLuser == NULL ? "-" : zLuser); #endif /* HAVE_TAYLOR_LOGGING */ zstr = zldate_and_time (); fprintf (e, "(%s", zstr); if (edebug != NULL) fprintf (edebug, "(%s", zstr); if (iLid != 0) { #if ! HAVE_HDB_LOGGING #if HAVE_TAYLOR_LOGGING fprintf (e, " %d", iLid); if (edebug != NULL) fprintf (edebug, " %d", iLid); #else /* ! HAVE_TAYLOR_LOGGING */ fprintf (e, "-%d", iLid); if (edebug != NULL) fprintf (edebug, "-%d", iLid); #endif /* ! HAVE_TAYLOR_LOGGING */ #else /* HAVE_HDB_LOGGING */ /* I assume that the second number here is meant to be some sort of file sequence number, and that it should correspond to the sequence number in the statistics file. I don't have any really convenient way to do this, so I won't unless somebody thinks it's very important. */ fprintf (e, ",%d,%d", iLid, 0); if (edebug != NULL) fprintf (edebug, ",%d,%d", iLid, 0); #endif /* HAVE_HDB_LOGGING */ } fprintf (e, ") "); if (edebug != NULL) fprintf (edebug, ") "); fprintf (e, "%s", zhdr); if (edebug != NULL) fprintf (edebug, "%s", zhdr); } } #if HAVE_VFPRINTF va_start (parg, zmsg); vfprintf (e, zmsg, parg); va_end (parg); if (edebug != NULL) { va_start (parg, zmsg); vfprintf (edebug, zmsg, parg); va_end (parg); } #else /* ! HAVE_VFPRINTF */ fprintf (e, zmsg, a, b, c, d, f, g, h, i, j); if (edebug != NULL) fprintf (edebug, zmsg, a, b, c, d, f, g, h, i, j); #endif /* ! HAVE_VFPRINTF */ if (fend) { fprintf (e, "\n"); if (edebug != NULL) fprintf (edebug, "\n"); } (void) fflush (e); if (edebug != NULL) (void) fflush (edebug); if (pfLend != NULL) (*pfLend) (); if (ttype == LOG_FATAL) { if (pfLfatal != NULL) (*pfLfatal) (); usysdep_exit (FALSE); } #if CLOSE_LOGFILES ulog_close (); #endif } /* Log a uuconf error. */ void ulog_uuconf (ttype, puuconf, iuuconf) enum tlog ttype; pointer puuconf; int iuuconf; { char ab[512]; (void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab); ulog (ttype, "%s", ab); } /* Close the log file. There's nothing useful we can do with errors, so we don't check for them. */ void ulog_close () { /* Make sure we logged any signal we received. */ ulog (LOG_ERROR, (const char *) NULL); if (eLlog != NULL) { (void) fclose (eLlog); eLlog = NULL; fLlog_tried = FALSE; } #if DEBUG > 1 if (eLdebug != NULL) { (void) fclose (eLdebug); eLdebug = NULL; fLdebug_tried = FALSE; } #endif } /* Add an entry to the statistics file. We may eventually want to put failed file transfers in here, but we currently do not. */ /*ARGSUSED*/ void ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fmaster) boolean fsucceeded; const char *zuser; const char *zsystem; boolean fsent; long cbytes; long csecs; long cmicros; boolean fmaster; { long cbps; /* The seconds and microseconds are now counted independently, so they may be out of synch. */ if (cmicros < 0) { csecs -= ((- cmicros) / 1000000L) + 1; cmicros = 1000000L - ((- cmicros) % 1000000L); } if (cmicros >= 1000000L) { csecs += cmicros / 10000000L; cmicros = cmicros % 1000000L; } /* On a system which can determine microseconds we might very well have both csecs == 0 and cmicros == 0. */ if (csecs == 0 && cmicros < 1000) cbps = 0; else { long cmillis; /* This computation will not overflow provided csecs < 2147483 and cbytes and cbps both fit in a long. */ cmillis = csecs * 1000 + cmicros / 1000; cbps = ((cbytes / cmillis) * 1000 + ((cbytes % cmillis) * 1000) / cmillis); } if (eLstats == NULL) { if (fLstats_tried) return; fLstats_tried = TRUE; eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE); if (eLstats == NULL) return; } #if HAVE_TAYLOR_LOGGING fprintf (eLstats, "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec)\n", zuser, zsystem, zldate_and_time (), fsucceeded ? "" : "failed after ", fsent ? "sent" : "received", cbytes, csecs, cmicros / 1000, cbps); #endif /* HAVE_TAYLOR_LOGGING */ #if HAVE_V2_LOGGING fprintf (eLstats, "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n", zuser, zsystem, zldate_and_time (), (long) time ((time_t *) NULL), fsent ? "sent" : "received", fsucceeded ? "data" : "failed after", cbytes, csecs + cmicros / 500000); #endif /* HAVE_V2_LOGGING */ #if HAVE_HDB_LOGGING { static int iseq; /* I don't know what the 'C' means. The sequence number should probably correspond to the sequence number in the log file, but that is currently always 0; using this fake sequence number will still at least reveal which transfers are from different calls. We don't report a failed data transfer with this format. */ if (! fsucceeded) return; ++iseq; fprintf (eLstats, "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld %s\n", zsystem, zuser, fmaster ? 'M' : 'S', zldate_and_time (), iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice, fsent ? "->" : "<-", cbytes, csecs, cmicros / 1000, cbps, "bytes/sec"); } #endif /* HAVE_HDB_LOGGING */ (void) fflush (eLstats); #if CLOSE_LOGFILES ustats_close (); #endif } /* Close the statistics file. */ void ustats_close () { if (eLstats != NULL) { if (fclose (eLstats) != 0) ulog (LOG_ERROR, "fclose: %s", strerror (errno)); eLstats = NULL; fLstats_tried = FALSE; } } /* Return the date and time in a form used for a log entry. */ static const char * zldate_and_time () { long isecs, imicros; struct tm s; #if HAVE_TAYLOR_LOGGING static char ab[sizeof "1991-12-31 12:00:00.00"]; #endif #if HAVE_V2_LOGGING static char ab[sizeof "12/31-12:00"]; #endif #if HAVE_HDB_LOGGING static char ab[sizeof "12/31-12:00:00"]; #endif isecs = ixsysdep_time (&imicros); usysdep_localtime (isecs, &s); #if HAVE_TAYLOR_LOGGING sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d", s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour, s.tm_min, s.tm_sec, (int) (imicros / 10000)); #endif #if HAVE_V2_LOGGING sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday, s.tm_hour, s.tm_min); #endif #if HAVE_HDB_LOGGING sprintf (ab, "%d/%d-%02d:%02d:%02d", s.tm_mon + 1, s.tm_mday, s.tm_hour, s.tm_min, s.tm_sec); #endif return ab; } OG_ERROR, "Got %s signal", azSignal_names[isig]); } } fdoing_sigs = FALSE; } } if (zmsg == NULL) return; #if DEBUG > 1 uucp-1.04/Makefile.in1006440004150000170000003173205337265075010634 0 0 1 0 # This is the Makefile for Taylor UUCP # # The file Makefile.in should be processed by configure to generate # Makefile. If you want to generate Makefile by hand, you must find # all variables surrounded by @ and replace them with the correct # value (e.g. @CC@ must be replaced by something like cc or gcc). # # Once you have done that, you should check the definitions at the top # of this file to make sure that they are reasonable for your system. # Prefix directory for installation directories. prefix = /usr/local # The user name that should own the resulting executables, several of # which are suid. owner = uucp # Where to install uucico, uuxqt, uuchk and uuconv. If you use this # definition, $(prefix)/lib must exist. sbindir = $(prefix)/lib/uucp # Where to install uucp, uux, uustat, uuname, uulog, uuto, uupick and # cu. bindir = $(prefix)/bin # Where to install man pages. Section 1 for user programs, 8 for daemons. man1dir = $(prefix)/man/man1 man1ext = .1 man8dir = $(prefix)/man/man8 man8ext = .8 # Where to install the info files. infodir = $(prefix)/info # The directory to look in for new style configuration files (when # using HAVE_TAYLOR_CONFIG). Note that by default this is different # from sbindir, unlike traditional UUCP packages. newconfigdir = $(prefix)/conf/uucp # The directory to look in for BNU (when using HAVE_BNU_CONFIG) or # V2 (when using HAVE_V2_CONFIG) style configuration files. oldconfigdir = /usr/lib/uucp # If you don't want to compile tstuu, which requires BSD style ptys # and the Taylor configuration files, comment out the following line # The tstuu program is only used to test the package; it is described # further in the documentation. TSTUU = tstuu # # The next few lines are set up by the configuration script. You may # want to look them over. # # If you do not have the mkdir system call, undefine the following three # lines. This will install uudir as an suid root program. This is # necessary because invoking /bin/mkdir from an suid program will # leave the directories owned by the wrong user. @UUDIR@UUDIR = uudir @UUDIR@uudirdir = $(sbindir)/util @UUDIR@UUDIRFLAGS = -DUUDIR_PROGRAM=\"$(uudirdir)/$(UUDIR)\" # Source directory and, if necessary, VPATH srcdir = @srcdir@ VPATH = @srcdir@ # Define programs and flags CC = @CC@ CFLAGS = @CFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ RANLIB = @RANLIB@ LN_S = @LN_S@ MAKEINFO = makeinfo TEXI2DVI = texi2dvi DVITPS = dvips # # Nothing else to configure # SHELL = /bin/sh VERSION = 1.04 MORECFLAGS = -I$(srcdir) -I. -DSBINDIR=\"$(sbindir)\" -DOWNER=\"$(owner)\" -DVERSION=\"$(VERSION)\" $(UUDIRFLAGS) MDEFINES = CC='$(CC)' CFLAGS='$(CFLAGS)' RANLIB='$(RANLIB)' LN_S='$(LN_S)' newconfigdir='$(newconfigdir)' oldconfigdir='$(oldconfigdir)' owner='$(owner)' sbindir='$(sbindir)' UUDIRFLAGS='$(UUDIRFLAGS)' VERSION='$(VERSION)' PROGRAMS = uucico uuxqt uux uucp uuchk uuconv uustat uuname uusched \ uulog uuto uupick cu UUOBJS = uucico.o trans.o send.o rec.o xcmd.o prot.o protg.o protf.o \ prott.o prote.o proti.o protj.o protz.o time.o log.o chat.o \ conn.o tcp.o tli.o util.o copy.o XQTOBJS = uuxqt.o util.o log.o copy.o UUXOBJS = uux.o util.o log.o copy.o UUCPOBJS = uucp.o util.o log.o copy.o UUSTATOBJS = uustat.o util.o log.o copy.o UUNAMEOBJS = uuname.o log.o UULOGOBJS = uulog.o log.o UUPICKOBJS = uupick.o log.o copy.o CUOBJS = cu.o prot.o log.o chat.o conn.o tcp.o tli.o copy.o UUCHKOBJS = uuchk.o UUCONVOBJS = uuconv.o TSTOBJS = tstuu.o ALLOBJS = uucico.o uuxqt.o uux.o uucp.o uuchk.o uuconv.o uustat.o \ uuname.o uulog.o uupick.o cu.o uudir.o tstuu.o trans.o send.o \ rec.o xcmd.o prot.o protg.o protf.o prott.o prote.o proti.o \ protj.o protz.o util.o time.o log.o chat.o conn.o tcp.o tli.o \ copy.o UULIBS = unix/libunix.a uuconf/libuuconf.a lib/libuucp.a all: $(PROGRAMS) $(TSTUU) $(UUDIR) install: $(PROGRAMS) $(UUDIR) if test -d $(sbindir); then true; else mkdir $(sbindir); fi if test -d $(bindir); then true; else mkdir $(bindir); fi -if test -f $(sbindir)/uucico.old; then rm -f $(sbindir)/uucico; else mv $(sbindir)/uucico $(sbindir)/uucico.old; fi -if test -f $(sbindir)/uuxqt.old; then rm -f $(sbindir)/uuxqt; else mv $(sbindir)/uuxqt $(sbindir)/uuxqt.old; fi -if test -f $(sbindir)/uusched.old; then rm -f $(sbindir)/uusched; else mv $(sbindir)/uusched $(sbindir)/uusched.old; fi $(INSTALL_PROGRAM) uucico $(sbindir)/uucico $(INSTALL_PROGRAM) uuxqt $(sbindir)/uuxqt $(INSTALL_PROGRAM) uuchk $(sbindir)/uuchk $(INSTALL_PROGRAM) uuconv $(sbindir)/uuconv $(INSTALL_PROGRAM) uusched $(sbindir)/uusched chown $(owner) $(sbindir)/uucico $(sbindir)/uuxqt chmod 4555 $(sbindir)/uucico $(sbindir)/uuxqt chown $(owner) $(sbindir)/uuchk $(sbindir)/uuconv if test "$(UUDIR)X" != "X"; then \ if test -d $(uudirdir); then \ true \ else \ mkdir $(uudirdir); \ fi; \ chown $(owner) $(uudirdir); \ chmod 100 $(uudirdir); \ $(INSTALL_PROGRAM) uudir $(uudirdir)/uudir; \ chown root $(uudirdir)/uudir; \ chmod 4555 $(uudirdir)/uudir; \ else \ true; \ fi -for i in uux uucp uustat uuname uulog uuto uupick cu; do \ if test -f $(bindir)/$$i.old; then \ rm -f $(bindir)/$$i; \ else \ mv $(bindir)/$$i $(bindir)/$$i.old; \ fi; \ $(INSTALL_PROGRAM) $$i $(bindir)/$$i; \ done chown $(owner) $(bindir)/uux $(bindir)/uucp $(bindir)/uustat chown $(owner) $(bindir)/uuname $(bindir)/cu chmod 4555 $(bindir)/uux $(bindir)/uucp $(bindir)/uustat chmod 4555 $(bindir)/uuname $(bindir)/cu $(INSTALL_DATA) $(srcdir)/uucico.8 $(man8dir)/uucico$(man8ext) $(INSTALL_DATA) $(srcdir)/uuxqt.8 $(man8dir)/uuxqt$(man8ext) $(INSTALL_DATA) $(srcdir)/uux.1 $(man1dir)/uux$(man1ext) $(INSTALL_DATA) $(srcdir)/uucp.1 $(man1dir)/uucp$(man1ext) $(INSTALL_DATA) $(srcdir)/uustat.1 $(man1dir)/uustat$(man1ext) $(INSTALL_DATA) $(srcdir)/cu.1 $(man1dir)/cu$(man1ext) @echo Use \"make install-info\" to install the info pages. uninstall: rm -f $(sbindir)/uucico $(sbindir)/uuxqt $(sbindir)/uusched -cp $(sbindir)/uucico.old $(sbindir)/uucico -cp $(sbindir)/uuxqt.old $(sbindir)/uuxqt -cp $(sbindir)/uusched.old $(sbindir)/uusched -chown $(owner) $(sbindir)/uucico $(sbindir)/uuxqt -chmod 4555 $(sbindir)/uucico $(sbindir)/uuxqt -chown $(owner) $(sbindir)/uuchk $(sbindir)/uuconv rm -f $(bindir)/uux $(bindir)/uucp $(bindir)/uustat rm -f $(bindir)/uuname $(bindir)/uulog $(bindir)/uuto rm -f $(bindir)/uupick $(bindir)/cu -cp $(bindir)/uux.old $(bindir)/uux -cp $(bindir)/uucp.old $(bindir)/uucp -cp $(bindir)/uustat.old $(bindir)/uustat -cp $(bindir)/uuname.old $(bindir)/uuname -cp $(bindir)/uulog.old $(bindir)/uulog -cp $(bindir)/uuto.old $(bindir)/uuto -cp $(bindir)/uupick.old $(bindir)/uupick -cp $(bindir)/cu.old $(bindir)/cu -chown $(owner) $(bindir)/uux $(bindir)/uucp $(bindir)/uustat -chown $(owner) $(bindir)/uuname $(bindir)/cu -chmod 4555 $(bindir)/uux $(bindir)/uucp $(bindir)/uustat -chmod 4555 $(bindir)/uuname $(bindir)/cu uucico: $(UUOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uucico $(UUOBJS) $(UULIBS) $(LIBS) uuxqt: $(XQTOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uuxqt $(XQTOBJS) $(UULIBS) $(LIBS) uux: $(UUXOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uux $(UUXOBJS) $(UULIBS) $(LIBS) uucp: $(UUCPOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uucp $(UUCPOBJS) $(UULIBS) $(LIBS) uustat: $(UUSTATOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uustat $(UUSTATOBJS) $(UULIBS) $(LIBS) uuname: $(UUNAMEOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uuname $(UUNAMEOBJS) $(UULIBS) $(LIBS) uulog: $(UULOGOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uulog $(UULOGOBJS) $(UULIBS) $(LIBS) uusched: uusched.in Makefile -rm -f uusched sed 's,@SBINDIR@,$(sbindir),' < $(srcdir)/uusched.in > uusched chmod 0555 uusched uuto: uuto.in Makefile -rm -f uuto sed 's,@BINDIR@,$(bindir),' < $(srcdir)/uuto.in > uuto chmod 0555 uuto uupick: $(UUPICKOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uupick $(UUPICKOBJS) $(UULIBS) $(LIBS) cu: $(CUOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o cu $(CUOBJS) $(UULIBS) $(LIBS) uuchk: $(UUCHKOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uuchk $(UUCHKOBJS) $(UULIBS) $(LIBS) uuconv: $(UUCONVOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o uuconv $(UUCONVOBJS) $(UULIBS) $(LIBS) tstuu: $(TSTOBJS) $(UULIBS) $(CC) $(LDFLAGS) -o tstuu $(TSTOBJS) $(UULIBS) $(LIBS) uudir: uudir.o $(UULIBS) $(CC) $(LDFLAGS) -o uudir uudir.o $(UULIBS) $(LIBS) .c.o: $(CC) -c $(CFLAGS) $(MORECFLAGS) $< uuconv.o: uuconv.c $(CC) -c $(CFLAGS) $(MORECFLAGS) -I$(srcdir)/uuconf -Iuuconf $(srcdir)/uuconv.c sysdep.h: sysh.unx rm -f sysdep.h $(LN_S) $(srcdir)/sysh.unx sysdep.h || cp $(srcdir)/sysh.unx sysdep.h uuconf/libuuconf.a: FORCE (cd uuconf; $(MAKE) $(MDEFINES) libuuconf.a) unix/libunix.a: FORCE sysdep.h (cd unix; $(MAKE) $(MDEFINES) libunix.a) lib/libuucp.a: FORCE (cd lib; $(MAKE) $(MDEFINES) libuucp.a) FORCE:; clean: (cd unix; $(MAKE) $(MDEFINES) clean) (cd uuconf; $(MAKE) $(MDEFINES) clean) (cd lib; $(MAKE) $(MDEFINES) clean) rm -f $(ALLOBJS) $(PROGRAMS) tstuu sysdep.h rm -f uucp-$(VERSION).tar.Z rm -rf uucp-$(VERSION) distclean: (cd unix; $(MAKE) $(MDEFINES) distclean) (cd uuconf; $(MAKE) $(MDEFINES) distclean) (cd lib; $(MAKE) $(MDEFINES) distclean) rm -f $(ALLOBJS) $(PROGRAMS) tstuu sysdep.h rm -f uucp-$(VERSION).tar.Z rm -rf uucp-$(VERSION) rm -f Makefile conf.h config.status mostlyclean: clean realclean: distclean # The distribution targets are mostly for my own use; they are not # expected to work on all other systems. dist: -rm -rf uucp-$(VERSION) -rm -f uucp-$(VERSION).tar uucp-$(VERSION).tar.Z mkdir uucp-$(VERSION) ln `cat MANIFEST` uucp-$(VERSION) rm -f uucp-$(VERSION)/policy.h uucp-$(VERSION)/Makefile.in cp policy.h Makefile.in uucp-$(VERSION) chmod 0644 uucp-$(VERSION)/policy.h uucp-$(VERSION)/Makefile.in chmod 0644 uucp-$(VERSION)/uucp.texi mkdir uucp-$(VERSION)/contrib ln contrib/* uucp-$(VERSION)/contrib mkdir uucp-$(VERSION)/sample ln sample/* uucp-$(VERSION)/sample (cd unix; $(MAKE) $(MDEFINES) dist) (cd uuconf; $(MAKE) $(MDEFINES) dist) (cd lib; $(MAKE) $(MDEFINES) dist) tar -cvf uucp-$(VERSION).tar uucp-$(VERSION) compress uucp-$(VERSION).tar doc-dist: uucp.texi uucp.info uucp.dvi uucp.ps -rm -rf uucp-doc-$(VERSION) uucp-doc-dist -rm -f uucp-doc-$(VERSION).tar uucp-doc-$(VERSION).tar.Z mkdir uucp-doc-$(VERSION) ln README-DOC uucp-doc-$(VERSION) ln $(srcdir)/uucp.texi uucp-doc-$(VERSION) for i in uucp.info*; do ln $$i uucp-doc-$(VERSION); done ln uucp.dvi uucp-doc-$(VERSION) ln uucp.cp uucp.fn uucp.aux uucp-doc-$(VERSION) ln texinfo.tex uucp-doc-$(VERSION) mkdir uucp-doc-dist mv uucp-doc-$(VERSION) uucp-doc-dist/uucp-$(VERSION) cd uucp-doc-dist; tar -cvf ../uucp-doc-$(VERSION).tar uucp-$(VERSION) compress uucp-doc-$(VERSION).tar -rm -rf uucp-doc-dist info: uucp.info uucp.info: uucp.texi $(MAKEINFO) $< install-info: uucp.info for i in uucp.info*; do \ $(INSTALL_DATA) $$i $(infodir)/$$i; \ done dvi: uucp.dvi uucp.dvi: uucp.texi $(TEXI2DVI) $< ps: uucp.ps uucp.ps: uucp.dvi $(DVITPS) -o uucp.ps $< # Having Makefile depend on conf.h.in insures that conf.h will get # rebuilt when conf.h.in changes. We don't want conf.h to change # unnecessarily, nor do we want to run config.status unnecessarily. # This won't work on versions of make that don't check dependencies # for Makefile, but I'm the only person likely to change conf.h.in # anyhow. Makefile: config.status Makefile.in conf.h.in sh config.status config.status: configure configure --no-create configure: configure.in autoconf TAGS: etags *.h *.c # Header file dependencies. These are maintained by hand. $(ALLOBJS): uucp.h conf.h policy.h uucico.o: uudefs.h uuconf.h system.h prot.h conn.h trans.h getopt.h uuxqt.o: uudefs.h uuconf.h system.h getopt.h uux.o: uudefs.h uuconf.h system.h getopt.h sysdep.h uucp.o: uudefs.h uuconf.h system.h getopt.h uustat.o: uudefs.h uuconf.h system.h getopt.h uuname.o: uudefs.h uuconf.h system.h getopt.h uulog.o: uudefs.h uuconf.h system.h getopt.h uupick.o: uudefs.h uuconf.h system.h getopt.h cu.o: cu.h uudefs.h uuconf.h sysdep.h conn.h prot.h system.h getopt.h uuchk.o: uuconf.h getopt.h uuconv.o: $(srcdir)/uuconf/uucnfi.h uuconf.h getopt.h uudir.o: sysdep.h tstuu.o: sysdep.h getopt.h system.h trans.o: uudefs.h uuconf.h system.h prot.h trans.h send.o: uudefs.h uuconf.h system.h prot.h trans.h rec.o: uudefs.h uuconf.h system.h prot.h trans.h xcmd.o: uudefs.h uuconf.h system.h prot.h trans.h prot.o: uudefs.h system.h prot.h conn.h protg.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h protf.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h prott.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h prote.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h proti.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h protj.o: uudefs.h prot.h conn.h system.h trans.h protz.o: uudefs.h uuconf.h prot.h conn.h system.h trans.h log.o: uudefs.h uuconf.h system.h chat.o: uudefs.h uuconf.h system.h prot.h conn.h conn.o: uudefs.h uuconf.h conn.h tcp.o: uudefs.h uuconf.h conn.h sysdep.h system.h tli.o: uudefs.h uuconf.h conn.h sysdep.h system.h time.o: uudefs.h uuconf.h util.o: uudefs.h uuconf.h system.h copy.o: uudefs.h system.h sysdep.h .NOEXPORT: cu UUOBJS = uucico.o trans.o send.o uucp-1.04/prot.c1004440004150000170000001453005337263506010520 037777777777 1 0 /* 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.27 1992/08/25 01:00:30 ian Rel $"; #endif #include #include "uudefs.h" #include "system.h" #include "conn.h" #include "prot.h" /* Variables visible to the protocol-specific routines. */ /* Buffer to hold received data. */ char abPrecbuf[CRECBUFLEN]; /* Index of start of data in abPrecbuf. */ int iPrecstart; /* Index of end of data (first byte not included in data) in abPrecbuf. */ int iPrecend; /* We want to output and input at the same time, if supported on this machine. If we have something to send, we send it all while accepting a large amount of data. Once we have sent everything we look at whatever we have received. If data comes in faster than we can send it, we may run out of buffer space. */ boolean fsend_data (qconn, zsend, csend, fdoread) struct sconnection *qconn; const char *zsend; size_t csend; boolean fdoread; { if (! fdoread) return fconn_write (qconn, zsend, csend); while (csend > 0) { size_t crec, csent; if (iPrecend < iPrecstart) crec = iPrecstart - iPrecend - 1; else { crec = CRECBUFLEN - iPrecend; if (iPrecstart == 0) --crec; } csent = csend; if (! fconn_io (qconn, zsend, &csent, abPrecbuf + iPrecend, &crec)) return FALSE; csend -= csent; zsend += csent; iPrecend = (iPrecend + crec) % CRECBUFLEN; } return TRUE; } /* Read data from the other system when we have nothing to send. The argument cneed is the amount of data the caller wants, and ctimeout is the timeout in seconds. The function sets *pcrec to the amount of data which was actually received, which may be less than cneed if there isn't enough room in the receive buffer. If no data is received before the timeout expires, *pcrec will be returned as 0. If an error occurs, the function returns FALSE. If the freport argument is FALSE, no error should be reported. */ boolean freceive_data (qconn, cneed, pcrec, ctimeout, freport) struct sconnection *qconn; size_t cneed; size_t *pcrec; int ctimeout; boolean freport; { /* Set *pcrec to the maximum amount of data we can read. fconn_read expects *pcrec to be the buffer size, and sets it to the amount actually received. */ if (iPrecend < iPrecstart) *pcrec = iPrecstart - iPrecend - 1; else { *pcrec = CRECBUFLEN - iPrecend; if (iPrecstart == 0) --(*pcrec); } #if DEBUG > 0 /* If we have no room in the buffer, we're in trouble. The protocols must be written to ensure that this can't happen. */ if (*pcrec == 0) ulog (LOG_FATAL, "freceive_data: No room in buffer"); #endif /* If we don't have room for all the data the caller wants, we simply have to expect less. We'll get the rest later. */ if (*pcrec < cneed) cneed = *pcrec; if (! fconn_read (qconn, abPrecbuf + iPrecend, pcrec, cneed, ctimeout, freport)) return FALSE; iPrecend = (iPrecend + *pcrec) % CRECBUFLEN; return TRUE; } /* Read a single character. Get it out of the receive buffer if it's there, otherwise ask freceive_data for at least one character. This is used because as a protocol is shutting down freceive_data may read ahead and eat characters that should be read outside the protocol routines. We call freceive_data rather than fconn_read with an argument of 1 so that we can get all the available data in a single system call. The ctimeout argument is the timeout in seconds; the freport argument is FALSE if no error should be reported. This returns a character, or -1 on timeout or -2 on error. */ int breceive_char (qconn, ctimeout, freport) struct sconnection *qconn; int ctimeout; boolean freport; { char b; if (iPrecstart == iPrecend) { size_t crec; if (! freceive_data (qconn, sizeof (char), &crec, ctimeout, freport)) return -2; if (crec == 0) return -1; } b = abPrecbuf[iPrecstart]; iPrecstart = (iPrecstart + 1) % CRECBUFLEN; return BUCHAR (b); } /* Send mail about a file transfer. We send to the given mailing address if there is one, otherwise to the user. */ boolean fmail_transfer (fsuccess, zuser, zmail, zwhy, zfromfile, zfromsys, ztofile, ztosys, zsaved) boolean fsuccess; const char *zuser; const char *zmail; const char *zwhy; const char *zfromfile; const char *zfromsys; const char *ztofile; const char *ztosys; const char *zsaved; { const char *zsendto; const char *az[20]; int i; if (zmail != NULL && *zmail != '\0') zsendto = zmail; else zsendto = zuser; i = 0; az[i++] = "The file\n\t"; if (zfromsys != NULL) { az[i++] = zfromsys; az[i++] = "!"; } az[i++] = zfromfile; if (fsuccess) az[i++] = "\nwas successfully transferred to\n\t"; else az[i++] = "\ncould not be transferred to\n\t"; if (ztosys != NULL) { az[i++] = ztosys; az[i++] = "!"; } az[i++] = ztofile; az[i++] = "\nas requested by\n\t"; az[i++] = zuser; if (! fsuccess) { az[i++] = "\nfor the following reason:\n\t"; az[i++] = zwhy; az[i++] = "\n"; } if (zsaved != NULL) { az[i++] = zsaved; az[i++] = "\n"; } return fsysdep_mail (zsendto, fsuccess ? "UUCP succeeded" : "UUCP failed", i, az); } E) $(MDEFINES) dist) (cd lib; $(MAKE) $(MDEFINES) dist) tar -cvf uucp-$(VERSION).tar uucp-$(VERSION) compress uucp-$(VERSION).tar doc-dist: uucp.texi uucp.info uucpuucp-1.04/prot.h1004440004150000170000002467605337263507010542 037777777777 1 0 /* 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)); eful, but WITHOUT ANY WARRANTY; without even the implied warranuucp-1.04/prote.c1004440004150000170000002137105337263507010667 037777777777 1 0 /* 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.15 1992/08/20 02:45:32 ian Rel $"; #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; } cause '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 *qdauucp-1.04/protf.c1004440004150000170000004771405337263510010673 037777777777 1 0 /* 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.28 1993/01/19 05:10:46 ian Rel $"; #endif #include #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "trans.h" #include "system.h" #include "prot.h" /* This implementation is based on code by Piet Beertema, CWI, Amsterdam, Sep 1984. This code implements the 'f' protocol, which requires a flow-controlled error-free seven-bit data path. It does check for errors, but only at the end of each file transmission, so a noisy line without error correcting modems will be unusable. The conversion to seven bit data is done as follows, where b represents the character to convert: 0 <= b <= 037: 0172, b + 0100 (0100 to 0137) 040 <= b <= 0171: b ( 040 to 0171) 0172 <= b <= 0177: 0173, b - 0100 ( 072 to 077) 0200 <= b <= 0237: 0174, b - 0100 (0100 to 0137) 0240 <= b <= 0371: 0175, b - 0200 ( 040 to 0171) 0372 <= b <= 0377: 0176, b - 0300 ( 072 to 077) This causes all output bytes to be in the range 040 to 0176; these are the printable ASCII characters. */ /* This structure is used to hold information when dealing with the end of file acknowledgement. */ struct sfinfo { /* The functions from the generic code. */ boolean (*psendfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon)); boolean (*precfn) P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); /* The info pointer from the generic code. */ pointer pinfo; /* The character to send after receiving the checksum. */ char bsend; }; /* Internal functions. */ static boolean ffprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, size_t *pcneed)); static boolean ffawait_ack P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean ffawait_cksum P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean ffsend_ack P((struct stransfer *qtrans, struct sdaemon *qdaemon)); /* The size of the buffer we allocate to store outgoing data in. */ #define CFBUFSIZE (256) /* The timeout to wait for data to arrive before giving up. */ static int cFtimeout = 120; /* The maximum number of retries. */ static int cFmaxretries = 2; /* The buffer we allocate for outgoing data. */ static char *zFbuf; /* TRUE if we are receiving a file rather than a command. */ static boolean fFfile; /* The checksum so far. */ static unsigned int iFcheck; /* The last special byte (0172 to 0176) or 0 if none. */ static char bFspecial; /* The number of times we have retried this file. */ static int cFretries; /* Whether this file has been acknowledged. */ static boolean fFacked; struct uuconf_cmdtab asFproto_params[] = { { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cFtimeout, NULL }, { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cFmaxretries, NULL }, { NULL, 0, NULL, NULL } }; /* Statistics. */ /* The number of data bytes sent in files. */ static long cFsent_data; /* The number of actual bytes sent in files. */ static long cFsent_bytes; /* The number of data bytes received in files. */ static long cFrec_data; /* The number of actual bytes received in files. */ static long cFrec_bytes; /* The number of file retries when sending. */ static long cFsend_retries; /* The number of file retries when receiving. */ static long cFrec_retries; /* Start the protocol. */ boolean ffstart (qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { *pzlog = NULL; cFsent_data = 0; cFsent_bytes = 0; cFrec_data = 0; cFrec_bytes = 0; cFsend_retries = 0; cFrec_retries = 0; /* Use XON/XOFF handshaking. */ if (! fconn_set (qdaemon->qconn, PARITYSETTING_DEFAULT, STRIPSETTING_SEVENBITS, XONXOFF_ON)) return FALSE; /* We sleep to allow the other side to reset the terminal; this is what Mr. Beertema's code does. */ usysdep_sleep (2); return TRUE; } /* Shutdown the protocol. */ /*ARGSIGNORED*/ boolean ffshutdown (qdaemon) struct sdaemon *qdaemon; { xfree ((pointer) zFbuf); zFbuf = NULL; ulog (LOG_NORMAL, "Protocol 'f': sent %ld bytes for %ld, received %ld bytes for %ld", cFsent_bytes, cFsent_data, cFrec_bytes, cFrec_data); if (cFsend_retries != 0 || cFrec_retries != 0) ulog (LOG_NORMAL, "Protocol 'f' file retries: %ld sending, %ld receiving", cFsend_retries, cFrec_retries); cFtimeout = 120; cFmaxretries = 2; return TRUE; } /* Send a command string. We just send the string followed by a carriage return. */ /*ARGSUSED*/ boolean ffsendcmd (qdaemon, z, ilocal, iremote) struct sdaemon *qdaemon; const char *z; int ilocal; int iremote; { size_t clen; char *zalc; boolean fret; DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ffsendcmd: Sending command \"%s\"", z); clen = strlen (z); zalc = zbufalc (clen + 2); memcpy (zalc, z, clen); zalc[clen] = '\r'; zalc[clen + 1] = '\0'; fret = fsend_data (qdaemon->qconn, zalc, clen + 1, TRUE); ubuffree (zalc); return fret; } /* Get space to be filled with data. We allocate the space from the heap. */ /*ARGSIGNORED*/ char * zfgetspace (qdaemon, pclen) struct sdaemon *qdaemon; size_t *pclen; { *pclen = CFBUFSIZE; if (zFbuf == NULL) zFbuf = (char *) xmalloc (CFBUFSIZE); return zFbuf; } /* Send out a data packet. We have to encode the data into seven bits and accumulate a checksum. */ /*ARGSIGNORED*/ boolean ffsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) struct sdaemon *qdaemon; char *zdata; size_t cdata; int ilocal; int iremote; long ipos; { char ab[CFBUFSIZE * 2]; char *ze; register unsigned int itmpchk; cFsent_data += cdata; ze = ab; itmpchk = iFcheck; while (cdata-- > 0) { register int b; /* Rotate the checksum left. */ if ((itmpchk & 0x8000) == 0) itmpchk <<= 1; else { itmpchk <<= 1; ++itmpchk; } /* Add the next byte into the checksum. */ b = *zdata++ & 0xff; itmpchk += b; /* Encode the byte. */ if (b <= 0177) { if (b <= 037) { *ze++ = '\172'; *ze++ = (char) (b + 0100); } else if (b <= 0171) *ze++ = (char) b; else { *ze++ = '\173'; *ze++ = (char) (b - 0100); } } else { if (b <= 0237) { *ze++ = '\174'; *ze++ = (char) (b - 0100); } else if (b <= 0371) { *ze++ = '\175'; *ze++ = (char) (b - 0200); } else { *ze++ = '\176'; *ze++ = (char) (b - 0300); } } } iFcheck = itmpchk; cFsent_bytes += ze - ab; /* Passing FALSE tells fsend_data not to bother looking for incoming information, since we really don't expect any. */ return fsend_data (qdaemon->qconn, ab, (size_t) (ze - ab), FALSE); } /* Process data and return the amount of data we are looking for in *pcneed. The 'f' protocol doesn't really reveal this, but when transferring file we know that we need at least seven characters for the checksum. */ static boolean ffprocess_data (qdaemon, pfexit, pcneed) struct sdaemon *qdaemon; boolean *pfexit; size_t *pcneed; { int i; register unsigned int itmpchk; *pfexit = FALSE; if (pcneed != NULL) *pcneed = 1; if (! fFfile) { /* A command continues until a '\r' character, which we turn into '\0' before calling fgot_data. */ while (iPrecstart != iPrecend) { for (i = iPrecstart; i < CRECBUFLEN && i != iPrecend; i++) { if (abPrecbuf[i] == '\r') { int istart; DEBUG_MESSAGE1 (DEBUG_PROTO, "ffprocess_data: Got %d command bytes", i - iPrecstart + 1); abPrecbuf[i] = '\0'; istart = iPrecstart; iPrecstart = (i + 1) % CRECBUFLEN; if (pcneed != NULL) *pcneed = 0; return fgot_data (qdaemon, abPrecbuf + istart, (size_t) (i - istart + 1), (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, pfexit); } } DEBUG_MESSAGE1 (DEBUG_PROTO, "ffprocess_data: Got %d command bytes", i - iPrecstart); if (! fgot_data (qdaemon, abPrecbuf + iPrecstart, (size_t) (i - iPrecstart), (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, pfexit)) return FALSE; iPrecstart = i % CRECBUFLEN; } return TRUE; } /* Here the data is destined for a file, and we must decode it. */ itmpchk = iFcheck; while (iPrecstart != iPrecend) { char *zstart, *zto, *zfrom; int c; zto = zfrom = zstart = abPrecbuf + iPrecstart; c = iPrecend - iPrecstart; if (c < 0) c = CRECBUFLEN - iPrecstart; while (c-- != 0) { int b; b = *zfrom++ & 0xff; if (b < 040 || b > 0176) { ulog (LOG_ERROR, "Illegal byte %d", b); continue; } /* Characters >= 0172 are always special characters. The only legal pair of consecutive special characters are 0176 0176 which immediately precede the four digit checksum. */ if (b >= 0172) { if (bFspecial != 0) { if (bFspecial != 0176 || b != 0176) { ulog (LOG_ERROR, "Illegal bytes %d %d", bFspecial, b); bFspecial = 0; continue; } /* Pass any initial data. */ if (zto != zstart) { /* Don't count the checksum in the received bytes. */ cFrec_bytes += zfrom - zstart - 2; cFrec_data += zto - zstart; if (! fgot_data (qdaemon, zstart, (size_t) (zto - zstart), (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, pfexit)) return FALSE; } /* The next characters we want to read are the checksum, so skip the second 0176. */ iPrecstart = (iPrecstart + zfrom - zstart) % CRECBUFLEN; iFcheck = itmpchk; /* Tell fgot_data that we've read the entire file by passing 0 length data. This will wind up calling fffile to verify the checksum. We set *pcneed to 0 because we don't want to read any more data from the port, since we may have already read the checksum. */ if (pcneed != NULL) *pcneed = 0; return fgot_data (qdaemon, (const char *) NULL, (size_t) 0, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, pfexit); } /* Here we have encountered a special character that does not follow another special character. */ bFspecial = (char) b; } else { int bnext; /* Here we have encountered a nonspecial character. */ switch (bFspecial) { default: bnext = b; break; case 0172: bnext = b - 0100; break; case 0173: case 0174: bnext = b + 0100; break; case 0175: bnext = b + 0200; break; case 0176: bnext = b + 0300; break; } *zto++ = (char) bnext; bFspecial = 0; /* Rotate the checksum left. */ if ((itmpchk & 0x8000) == 0) itmpchk <<= 1; else { itmpchk <<= 1; ++itmpchk; } /* Add the next byte into the checksum. */ itmpchk += bnext; } } if (zto != zstart) { DEBUG_MESSAGE1 (DEBUG_PROTO, "ffprocess_data: Got %d bytes", zto - zstart); cFrec_data += zto - zstart; if (! fgot_data (qdaemon, zstart, (size_t) (zto - zstart), (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, pfexit)) return FALSE; } cFrec_bytes += zfrom - zstart; iPrecstart = (iPrecstart + zfrom - zstart) % CRECBUFLEN; } iFcheck = itmpchk; if (pcneed != NULL) { /* At this point we may have seen the first 0176 in the checksum but not the second. The checksum is at least seven characters long (0176 0176 a b c d \r). This won't help much, but reading seven characters is a lot better than reading two, which is what I saw in a 2400 baud log file. */ if (bFspecial == 0176) *pcneed = 6; else *pcneed = 7; } return TRUE; } /* Wait for data to come in and process it until we've finished a command or a file. */ boolean ffwait (qdaemon) struct sdaemon *qdaemon; { while (TRUE) { boolean fexit; size_t cneed, crec; if (! ffprocess_data (qdaemon, &fexit, &cneed)) return FALSE; if (fexit) return TRUE; if (cneed > 0) { /* We really want to do something like get all available characters, then sleep for half a second and get all available characters again, and keep this up until we don't get anything after sleeping. */ if (! freceive_data (qdaemon->qconn, cneed, &crec, cFtimeout, TRUE)) return FALSE; if (crec == 0) { ulog (LOG_ERROR, "Timed out waiting for data"); return FALSE; } } } } /* File level operations. Reset the checksums when starting to send or receive a file, and output the checksum when we've finished sending a file. */ /*ARGSUSED*/ boolean fffile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) struct sdaemon *qdaemon; struct stransfer *qtrans; boolean fstart; boolean fsend; long cbytes; boolean *pfhandled; { DEBUG_MESSAGE3 (DEBUG_PROTO, "fffile: fstart %s; fsend %s; fFacked %s", fstart ? "true" : "false", fsend ? "true" : "false", fFacked ? "true" : "false"); *pfhandled = FALSE; if (fstart) { iFcheck = 0xffff; cFretries = 0; fFacked = FALSE; if (! fsend) { bFspecial = 0; fFfile = TRUE; } return TRUE; } else { struct sfinfo *qinfo; /* We need to handle the checksum and the acknowledgement. If we get a successful ACK, we set fFacked to TRUE and call the send or receive function by hand. This will wind up calling here again, so if fFacked is TRUE we just return out and let the send or receive function do whatever it does. This is a bit of a hack. */ if (fFacked) { fFacked = FALSE; return TRUE; } if (fsend) { char ab[sizeof "\176\176ABCD\r"]; /* Send the final checksum. */ sprintf (ab, "\176\176%04x\r", iFcheck & 0xffff); if (! fsend_data (qdaemon->qconn, ab, (size_t) 7, TRUE)) return FALSE; /* Now wait for the acknowledgement. */ fFfile = FALSE; qinfo = (struct sfinfo *) xmalloc (sizeof (struct sfinfo)); qinfo->psendfn = qtrans->psendfn; qinfo->precfn = qtrans->precfn; qinfo->pinfo = qtrans->pinfo; qtrans->psendfn = NULL; qtrans->precfn = ffawait_ack; qtrans->pinfo = (pointer) qinfo; qtrans->fcmd = TRUE; *pfhandled = TRUE; return fqueue_receive (qdaemon, qtrans); } else { /* Wait for the checksum. */ fFfile = FALSE; qinfo = (struct sfinfo *) xmalloc (sizeof (struct sfinfo)); qinfo->psendfn = qtrans->psendfn; qinfo->precfn = qtrans->precfn; qinfo->pinfo = qtrans->pinfo; qtrans->psendfn = NULL; qtrans->precfn = ffawait_cksum; qtrans->pinfo = (pointer) qinfo; qtrans->fcmd = TRUE; *pfhandled = TRUE; return fqueue_receive (qdaemon, qtrans); } } } /* Wait for the ack after sending a file and the checksum. */ static boolean ffawait_ack (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; qtrans->precfn = NULL; /* An R means to retry sending the file. */ if (*zdata == 'R') { if (! ffileisopen (qtrans->e)) { ulog (LOG_ERROR, "Request to resent non-file"); return FALSE; } ++cFretries; if (cFretries > cFmaxretries) { ulog (LOG_ERROR, "Too many retries"); return FALSE; } ulog (LOG_NORMAL, "Resending file"); if (! ffilerewind (qtrans->e)) { ulog (LOG_ERROR, "rewind: %s", strerror (errno)); return FALSE; } qtrans->ipos = (long) 0; iFcheck = 0xffff; ++cFsend_retries; qtrans->psendfn = qinfo->psendfn; qtrans->precfn = qinfo->precfn; qtrans->pinfo = qinfo->pinfo; xfree ((pointer) qinfo); qtrans->fsendfile = TRUE; return fqueue_send (qdaemon, qtrans); } if (*zdata != 'G') { DEBUG_MESSAGE1 (DEBUG_PROTO, "fffile: Got \"%s\"", zdata); ulog (LOG_ERROR, "File send failed"); return FALSE; } qtrans->psendfn = qinfo->psendfn; qtrans->precfn = qinfo->precfn; qtrans->pinfo = qinfo->pinfo; xfree ((pointer) qinfo); /* Now call the send function by hand after setting fFacked to TRUE. Since fFacked is true fffile will simply return out, and the send function can do whatever it what was going to do. */ fFacked = TRUE; return (*qtrans->psendfn) (qtrans, qdaemon); } /* This function is called when the checksum arrives. */ /*ARGSUSED*/ static boolean ffawait_cksum (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; unsigned int icheck; qtrans->precfn = NULL; if (! isxdigit (zdata[0]) || ! isxdigit (zdata[1]) || ! isxdigit (zdata[2]) || ! isxdigit (zdata[3]) || zdata[4] != '\0') { ulog (LOG_ERROR, "Bad checksum format"); xfree (qtrans->pinfo); return FALSE; } icheck = (unsigned int) strtol ((char *) zdata, (char **) NULL, 16); if (icheck != (iFcheck & 0xffff)) { DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "Checksum failed; calculated 0x%x, got 0x%x", iFcheck & 0xffff, icheck); if (! ffileisopen (qtrans->e)) { ulog (LOG_ERROR, "Failed to get non-file"); return FALSE; } ++cFretries; if (cFretries > cFmaxretries) { ulog (LOG_ERROR, "Too many retries"); qinfo->bsend = 'Q'; } else { ulog (LOG_NORMAL, "File being resent"); /* This bit of code relies on the receive code setting qtrans->s.ztemp to the full name of the temporary file being used. */ qtrans->e = esysdep_truncate (qtrans->e, qtrans->s.ztemp); if (! ffileisopen (qtrans->e)) return FALSE; qtrans->ipos = (long) 0; iFcheck = 0xffff; bFspecial = 0; fFfile = TRUE; ++cFrec_retries; /* Send an R to tell the other side to resend the file. */ qinfo->bsend = 'R'; } } else { /* Send a G to tell the other side the file was received correctly. */ qinfo->bsend = 'G'; } qtrans->psendfn = ffsend_ack; return fqueue_send (qdaemon, qtrans); } /* Send the acknowledgement, and then possible wait for the resent file. */ static boolean ffsend_ack (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct sfinfo *qinfo = (struct sfinfo *) qtrans->pinfo; char ab[2]; ab[0] = qinfo->bsend; ab[1] = '\0'; if (! ffsendcmd (qdaemon, ab, 0, 0)) return FALSE; qtrans->psendfn = qinfo->psendfn; qtrans->precfn = qinfo->precfn; qtrans->pinfo = qinfo->pinfo; xfree ((pointer) qinfo); if (ab[0] == 'Q') return FALSE; if (ab[0] == 'R') { qtrans->frecfile = TRUE; return fqueue_receive (qdaemon, qtrans); } fFacked = TRUE; return (*qtrans->precfn) (qtrans, qdaemon, (const char *) NULL, (size_t) 0); } >= 0172) { if (bFspecial != 0) { uucp-1.04/protg.c1004440004150000170000015647505337263510010701 037777777777 1 0 /* 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.54 1993/01/28 03:57:06 ian Rel $"; #endif #include #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "trans.h" #include "system.h" #include "prot.h" /* Each 'g' protocol packet begins with six bytes. They are: is the ASCII DLE character (^P or '\020'). if 1 <= <= 8, the packet is followed by 2 ** (k + 4) bytes of data; if == 9, these six bytes are a complete control packet; other value of are illegal. is the low byte of a checksum. is the high byte of a checksum. is a control byte (see below). is ^ ^ ^ . The control byte is divided into three bitfields: t t x x x y y y The two bit field tt is the packet type. The three bit field xxx is the control type for a control packet, or the sequence number for a data packet. The three bit field yyy is a value for a control packet, or the sequence number of the last packet received for a data packet. For all successfully recieved packets, the control byte is stored into iGpacket_control. */ /* Names for the bytes in the frame header. */ #define IFRAME_DLE (0) #define IFRAME_K (1) #define IFRAME_CHECKLOW (2) #define IFRAME_CHECKHIGH (3) #define IFRAME_CONTROL (4) #define IFRAME_XOR (5) /* Length of the frame header. */ #define CFRAMELEN (6) /* Macros to break apart the control bytes. */ #define CONTROL_TT(b) ((int)(((b) >> 6) & 03)) #define CONTROL_XXX(b) ((int)(((b) >> 3) & 07)) #define CONTROL_YYY(b) ((int)((b) & 07)) /* DLE value. */ #define DLE ('\020') /* Get the length of a packet given a pointer to the header. */ #define CPACKLEN(z) ((size_t) (1 << ((z)[IFRAME_K] + 4))) /* field value for a control message. */ #define KCONTROL (9) /* Get the next sequence number given a sequence number. */ #define INEXTSEQ(i) ((i + 1) & 07) /* Compute i1 - i2 modulo 8. */ #define CSEQDIFF(i1, i2) (((i1) + 8 - (i2)) & 07) /* Packet types. These are from the tt field. CONTROL -- control packet ALTCHAN -- alternate channel; not used by UUCP DATA -- full data segment SHORTDATA -- less than full data segment (all the bytes specified by the packet length are always transferred). Let be the number of bytes in the data segment not to be used. If <= 0x7f, the first byte of the data segment is and the data follows. If > 0x7f, the first byte of the data segment is 0x80 | ( & 0x7f), the second byte of the data segment is >> 7, and the data follows. The maximum possible data segment size is 2**12, so this handles all possible cases. */ #define CONTROL (0) #define ALTCHAN (1) #define DATA (2) #define SHORTDATA (3) /* Control types. These are from the xxx field if the type (tt field) is CONTROL. CLOSE -- close the connection RJ -- reject; packet yyy last to be received correctly SRJ -- selective reject; reject only packet yyy (not used by UUCP) RR -- receiver ready; packet yyy received correctly INITC -- third step of initialization; yyy holds window size INITB -- second step of initialization; yyy holds maximum value - 1 INITA -- first step of initialization; yyy holds window size. The yyy value for RR is the same as the yyy value for an ordinary data packet. */ #define CLOSE (1) #define RJ (2) #define SRJ (3) #define RR (4) #define INITC (5) #define INITB (6) #define INITA (7) /* Maximum amount of data in a single packet. This is set by the field in the header; the amount of data in a packet is 2 ** ( + 4). ranges from 1 to 8. */ #define CMAXDATAINDEX (8) #define CMAXDATA (1 << (CMAXDATAINDEX + 4)) /* Maximum window size. */ #define CMAXWINDOW (7) /* Defaults for the protocol parameters. These may all be changed by using the ``protocol-parameter g'' command, so there is no particular reason to change the values given here. */ /* The desired window size. This is what we tell the other system to use. It must be between 1 and 7, and there's no reason to use less than 7. Protocol parameter ``window''. */ #define IWINDOW (7) /* The desired packet size. Many implementations only support 64 byte packets. Protocol parameter ``packet-size''. */ #define IPACKSIZE (64) /* The number of times to retry the exchange of INIT packets when starting the protocol. Protocol parameter ``startup-retries''. */ #define CSTARTUP_RETRIES (8) /* The timeout to use when waiting for an INIT packet when starting up the protocol. Protocol parameter ``init-timeout''. */ #define CEXCHANGE_INIT_TIMEOUT (10) /* The number of times to retry sending and waiting for a single INIT packet when starting the protocol. This controls a single INIT packet, while CSTARTUP_RETRIES controls how many times to try the entire INIT sequence. Protocol parameter ``init-retries''. */ #define CEXCHANGE_INIT_RETRIES (4) /* The timeout to use when waiting for a packet. Protocol parameter ``timeout''. */ #define CTIMEOUT (10) /* The number of times to retry waiting for a packet. Each time the timeout fails we send a copy of our last data packet or a reject message for the packet we expect from the other side, depending on whether we are waiting for an acknowledgement or a data packet. This is the number of times we try doing that and then waiting again. Protocol parameter ``retries''. */ #define CRETRIES (6) /* If we see more than this much unrecognized data, we drop the connection. This must be larger than a single packet size, which means it must be larger than 4096 (the largest possible packet size). Protocol parameter ``garbage''. */ #define CGARBAGE (10000) /* If we see more than this many protocol errors, we drop the connection. Protocol parameter ``errors''. */ #define CERRORS (100) /* Default decay rate. Each time we send or receive this many packets succesfully, we decrement the error level by one (protocol parameter ``error-decay''). */ #define CERROR_DECAY (10) /* If this value is non-zero, it will be used as the remote window size regardless of what the other side requested. This can be useful for dealing with some particularly flawed packages. This default value should always be 0, and protocol parameter ``remote-window'' should be used for the affected systems. */ #define IREMOTE_WINDOW (0) /* If this value is non-zero, it will be used as the packet size to send to the remote system regardless of what it requested. It's difficult to imagine any circumstances where you would want to set this. Protocol parameter ``remote-packet-size''. */ #define IREMOTE_PACKSIZE (0) /* Local variables. */ /* Next sequence number to send. */ static int iGsendseq; /* Last sequence number that has been acked. */ static int iGremote_ack; /* Last sequence number to be retransmitted. */ static int iGretransmit_seq; /* Last sequence number we have received. */ static int iGrecseq; /* Last sequence number we have acked. */ static int iGlocal_ack; /* Window size to request (protocol parameter ``window''). */ static int iGrequest_winsize = IWINDOW; /* Packet size to request (protocol parameter ``packet-size''). */ static int iGrequest_packsize = IPACKSIZE; /* Remote window size (set during handshake). */ static int iGremote_winsize; /* Forced remote window size (protocol parameter ``remote-window''). */ static int iGforced_remote_winsize = IREMOTE_WINDOW; /* Remote segment size (set during handshake). This is one less than the value in a packet header. */ static int iGremote_segsize; /* Remote packet size (set based on iGremote_segsize). */ static size_t iGremote_packsize; /* Forced remote packet size (protocol parameter ``remote-packet-size''). */ static int iGforced_remote_packsize = IREMOTE_PACKSIZE; /* Recieved control byte. */ static int iGpacket_control; /* Number of times to retry the initial handshake. Protocol parameter ``startup-retries''. */ static int cGstartup_retries = CSTARTUP_RETRIES; /* Number of times to retry sending an initial control packet. Protocol parameter ``init-retries''. */ static int cGexchange_init_retries = CEXCHANGE_INIT_RETRIES; /* Timeout (seconds) for receiving an initial control packet. Protocol parameter ``init-timeout''. */ static int cGexchange_init_timeout = CEXCHANGE_INIT_TIMEOUT; /* Timeout (seconds) for receiving a data packet. Protocol parameter ``timeout''. */ static int cGtimeout = CTIMEOUT; /* Maximum number of timeouts when receiving a data packet or acknowledgement. Protocol parameter ``retries''. */ static int cGretries = CRETRIES; /* Amount of garbage data we are prepared to see before giving up. Protocol parameter ``garbage''. */ static int cGgarbage_data = CGARBAGE; /* Maximum number of errors we are prepared to see before giving up. Protocol parameter ``errors''. */ static int cGmax_errors = CERRORS; /* Each time we receive this many packets succesfully, we decrement the error level by one (protocol parameter ``error-decay''). */ static int cGerror_decay = CERROR_DECAY; /* Whether to use shorter packets when possible. Protocol parameter ``short-packets''. */ static boolean fGshort_packets = TRUE; /* Protocol parameter commands. */ struct uuconf_cmdtab asGproto_params[] = { { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iGrequest_winsize, NULL }, { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iGrequest_packsize, NULL }, { "startup-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGstartup_retries, NULL }, { "init-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cGexchange_init_timeout, NULL }, { "init-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGexchange_init_retries, NULL }, { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cGtimeout, NULL }, { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cGretries, NULL }, { "garbage", UUCONF_CMDTABTYPE_INT, (pointer) &cGgarbage_data, NULL }, { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cGmax_errors, NULL }, { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cGerror_decay, NULL }, { "remote-window", UUCONF_CMDTABTYPE_INT, (pointer) &iGforced_remote_winsize, NULL }, { "remote-packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iGforced_remote_packsize, NULL }, { "short-packets", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) &fGshort_packets, NULL }, { NULL, 0, NULL, NULL } }; /* Statistics. */ /* Number of packets we have sent. */ static long cGsent_packets; /* Number of packets we have resent (these are not included in cGsent_packets). */ static long cGresent_packets; /* Number of packets we have delayed sending (these should not be counted in cGresent_packets). */ static long cGdelayed_packets; /* Number of packets we have received. */ static long cGrec_packets; /* Number of packets rejected because the header was bad. */ static long cGbad_hdr; /* Number of packets rejected because the checksum was bad. */ static long cGbad_checksum; /* Number of packets received out of order. */ static long cGbad_order; /* Number of packets rejected by receiver (number of RJ packets received). */ static long cGremote_rejects; /* The error level. This is the total number of errors as adjusted by cGerror_decay. */ static long cGerror_level; /* Each time we send an RJ, we can expect several out of order of packets, because the other side will probably have sent a full window by the time it sees the RJ. This variable keeps track of the number of out of order packets we expect to see. We don't count expected out of order packets against the error level. This is reset to 0 when an in order packet is received. */ static int cGexpect_bad_order; #if DEBUG > 1 /* Control packet names used for debugging. */ static const char * const azGcontrol[] = {"?0?", "CLOSE", "RJ", "SRJ", "RR", "INITC", "INITB", "INITA"}; #endif /* Local functions. */ static boolean fgexchange_init P((struct sdaemon *qdaemon, int ictl, int ival, int *piset)); static boolean fgsend_control P((struct sdaemon *qdaemon, int ictl, int ival)); static char *zgadjust_ack P((int iseq)); static boolean fgwait_for_packet P((struct sdaemon *qdaemon, boolean freturncontrol, int ctimeout, int cretries)); static boolean fgsend_acks P((struct sdaemon *qdaemon)); static boolean fggot_ack P((struct sdaemon *qdaemon, int iack)); static boolean fgprocess_data P((struct sdaemon *qdaemon, boolean fdoacks, boolean freturncontrol, boolean *pfexit, size_t *pcneed, boolean *pffound)); static boolean fginit_sendbuffers P((boolean fallocate)); static boolean fgcheck_errors P((struct sdaemon *qdaemon)); static int igchecksum P((const char *zdata, size_t clen)); static int igchecksum2 P((const char *zfirst, size_t cfirst, const char *zsecond, size_t csecond)); /* Start the protocol. This requires a three way handshake. Both sides must send and receive an INITA packet, an INITB packet, and an INITC packet. The INITA and INITC packets contain the window size, and the INITB packet contains the packet size. */ boolean fgstart (qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { int iseg; int i; boolean fgota, fgotb; *pzlog = NULL; /* The 'g' protocol requires a full eight bit interface. */ if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) return FALSE; iGsendseq = 1; iGremote_ack = 0; iGretransmit_seq = -1; iGrecseq = 0; iGlocal_ack = 0; cGsent_packets = 0; cGresent_packets = 0; cGdelayed_packets = 0; cGrec_packets = 0; cGbad_hdr = 0; cGbad_checksum = 0; cGbad_order = 0; cGremote_rejects = 0; cGerror_level = 0; cGexpect_bad_order = 0; /* We must determine the segment size based on the packet size which may have been modified by a protocol parameter command. A segment size of 2^n is passed as n - 5. */ i = iGrequest_packsize; iseg = -1; while (i > 0) { ++iseg; i >>= 1; } iseg -= 5; if (iseg < 0 || iseg > 7) { ulog (LOG_ERROR, "Illegal packet size %d for '%c' protocol", iGrequest_packsize, qdaemon->qproto->bname); iseg = 1; } fgota = FALSE; fgotb = FALSE; for (i = 0; i < cGstartup_retries; i++) { if (fgota) { if (! fgsend_control (qdaemon, INITA, iGrequest_winsize)) return FALSE; } else { if (! fgexchange_init (qdaemon, INITA, iGrequest_winsize, &iGremote_winsize)) continue; } fgota = TRUE; if (fgotb) { if (! fgsend_control (qdaemon, INITB, iseg)) return FALSE; } else { if (! fgexchange_init (qdaemon, INITB, iseg, &iGremote_segsize)) continue; } fgotb = TRUE; if (! fgexchange_init (qdaemon, INITC, iGrequest_winsize, &iGremote_winsize)) continue; /* We have succesfully connected. Determine the remote packet size. */ iGremote_packsize = 1 << (iGremote_segsize + 5); /* If the user requested us to force specific remote window and packet sizes, do so now. */ if (iGforced_remote_winsize > 0 && iGforced_remote_winsize <= CMAXWINDOW) iGremote_winsize = iGforced_remote_winsize; if (iGforced_remote_packsize >= 32 && iGforced_remote_packsize <= 4096) { /* Force the value to a power of two. */ i = iGforced_remote_packsize; iseg = -1; while (i > 0) { ++iseg; i >>= 1; } iGremote_packsize = 1 << iseg; iGremote_segsize = iseg - 5; } /* Set up packet buffers to use. We don't do this until we know the maximum packet size we are going to send. */ if (! fginit_sendbuffers (TRUE)) return FALSE; *pzlog = zbufalc (sizeof "protocol '' packet size window " + 50); sprintf (*pzlog, "protocol '%c' packet size %d window %d", qdaemon->qproto->bname, (int) iGremote_packsize, (int) iGremote_winsize); return TRUE; } DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgstart: Protocol startup failed"); return FALSE; } /* The 'G' protocol is identical to the 'g' protocol, except that short packets are never supported. */ boolean fbiggstart (qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { fGshort_packets = FALSE; return fgstart (qdaemon, pzlog); } /* Exchange initialization messages with the other system. A problem: We send INITA; it gets received We receive INITA We send INITB; it gets garbled We receive INITB We have seen and sent INITB, so we start to send INITC. The other side as sent INITB but not seen it, so it times out and resends INITB. We will continue sending INITC and the other side will continue sending INITB until both sides give up and start again with INITA. It might seem as though if we are sending INITC and receive INITB, we should resend our INITB, but this could cause infinite echoing of INITB on a long-latency line. Rather than risk that, I have implemented a fast drop-back procedure. If we are sending INITB and receive INITC, the other side has gotten ahead of us. We immediately fail and begin again with INITA. For the other side, if we are sending INITC and see INITA, we also immediately fail back to INITA. Unfortunately, this doesn't work for the other case, in which we are sending INITB but the other side has not yet seen INITA. As far as I can see, if this happens we just have to wait until we time out and resend INITA. */ static boolean fgexchange_init (qdaemon, ictl, ival, piset) struct sdaemon *qdaemon; int ictl; int ival; int *piset; { int i; /* The three-way handshake should be independent of who initializes it, but it seems that some versions of uucico assume that the caller sends first and the callee responds. This only matters if we are the callee and the first packet is garbled. If we send a packet, the other side will assume that we must have seen the packet they sent and will never time out and send it again. Therefore, if we are the callee we don't send a packet the first time through the loop. This can still fail, but should usually work, and, after all, if the initialization packets are received correctly there will be no problem no matter what we do. */ for (i = 0; i < cGexchange_init_retries; i++) { long itime; int ctimeout; if (qdaemon->fcaller || i > 0) { if (! fgsend_control (qdaemon, ictl, ival)) return FALSE; } itime = ixsysdep_time ((long *) NULL); ctimeout = cGexchange_init_timeout; do { long inewtime; /* We pass 0 as the retry count to fgwait_for_packet because we want to handle retries here and because if it retried it would send a packet, which would be bad. */ if (! fgwait_for_packet (qdaemon, TRUE, ctimeout, 0)) break; if (CONTROL_TT (iGpacket_control) == CONTROL) { if (CONTROL_XXX (iGpacket_control) == ictl) { *piset = CONTROL_YYY (iGpacket_control); /* If we didn't already send our initialization packet, send it now. */ if (! qdaemon->fcaller && i == 0) { if (! fgsend_control (qdaemon, ictl, ival)) return FALSE; } return TRUE; } /* If the other side is farther along than we are, we have lost a packet. Fail immediately back to INITA (but don't fail if we are already doing INITA, since that would count against cStart_retries more than it should). */ if (CONTROL_XXX (iGpacket_control) < ictl && ictl != INITA) return FALSE; /* If we are sending INITC and we receive an INITA, the other side has failed back (we know this because we have seen an INITB from them). Fail back ourselves to start the whole handshake over again. */ if (CONTROL_XXX (iGpacket_control) == INITA && ictl == INITC) return FALSE; /* As a special hack, if we are sending INITC and we receive INITB, we update the segment size from the packet. This permits a second INITB to override the first one. It would be nice to do this in a cleaner way. */ if (CONTROL_XXX (iGpacket_control) == INITB && ictl == INITC) iGremote_segsize = CONTROL_YYY (iGpacket_control); } inewtime = ixsysdep_time ((long *) NULL); ctimeout -= inewtime - itime; } while (ctimeout > 0); } return FALSE; } /* Shut down the protocol. */ boolean fgshutdown (qdaemon) struct sdaemon *qdaemon; { (void) fgsend_control (qdaemon, CLOSE, 0); (void) fgsend_control (qdaemon, CLOSE, 0); (void) fginit_sendbuffers (FALSE); /* The count of sent packets may not be accurate, because some of them may have not been sent yet if the connection failed in the middle (the ones that counted for cGdelayed_packets). I don't think it's worth being precise. */ ulog (LOG_NORMAL, "Protocol '%c' packets: sent %ld, resent %ld, received %ld", qdaemon->qproto->bname, cGsent_packets, cGresent_packets - cGdelayed_packets, cGrec_packets); if (cGbad_hdr != 0 || cGbad_checksum != 0 || cGbad_order != 0 || cGremote_rejects != 0) ulog (LOG_NORMAL, "Errors: header %ld, checksum %ld, order %ld, remote rejects %ld", cGbad_hdr, cGbad_checksum, cGbad_order, cGremote_rejects); /* Reset all the parameters to their default values, so that the protocol parameters used for this connection do not affect the next one. */ iGrequest_winsize = IWINDOW; iGrequest_packsize = IPACKSIZE; cGstartup_retries = CSTARTUP_RETRIES; cGexchange_init_timeout = CEXCHANGE_INIT_TIMEOUT; cGexchange_init_retries = CEXCHANGE_INIT_RETRIES; cGtimeout = CTIMEOUT; cGretries = CRETRIES; cGgarbage_data = CGARBAGE; cGmax_errors = CERRORS; cGerror_decay = CERROR_DECAY; iGforced_remote_winsize = IREMOTE_WINDOW; iGforced_remote_packsize = IREMOTE_PACKSIZE; fGshort_packets = TRUE; return TRUE; } /* Send a command string. We send packets containing the string until the entire string has been sent. Each packet is full. */ /*ARGSUSED*/ boolean fgsendcmd (qdaemon, z, ilocal, iremote) struct sdaemon *qdaemon; const char *z; int ilocal; int iremote; { size_t clen; boolean fagain; DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fgsendcmd: Sending command \"%s\"", z); clen = strlen (z); do { char *zpacket; size_t cdummy; zpacket = zggetspace (qdaemon, &cdummy); if (clen < iGremote_packsize) { size_t csize; /* If the remote packet size is larger than 64 (the default, which may indicate an older UUCP package), try to fit this command into a smaller packet. We still always send a complete packet, though. */ if (iGremote_packsize <= 64 || ! fGshort_packets) csize = iGremote_packsize; else { csize = 32; while (csize <= clen) csize <<= 1; } memcpy (zpacket, z, clen); bzero (zpacket + clen, csize - clen); fagain = FALSE; if (! fgsenddata (qdaemon, zpacket, csize, 0, 0, (long) 0)) return FALSE; } else { memcpy (zpacket, z, iGremote_packsize); z += iGremote_packsize; clen -= iGremote_packsize; fagain = TRUE; if (! fgsenddata (qdaemon, zpacket, iGremote_packsize, 0, 0, (long) 0)) return FALSE; } } while (fagain); return TRUE; } /* We keep an array of buffers to retransmit as necessary. Rather than waste static space on large buffer sizes, we allocate the buffers once we know how large the other system expects them to be. The sequence numbers used in the 'g' protocol are only three bits long, so we allocate eight buffers and maintain a correspondence between buffer index and sequence number. This always wastes some buffer space, but it's easy to implement. We leave room at the front of the buffer for the frame header and two additional bytes. The two extra bytes are used for short packets, which essentially use a longer header and shorter data. We do this to avoid moving the data. We zero out any unused bytes before the frame, so we can locate the real header given a buffer by finding the first non-zero byte (which will be one of the first three bytes in the buffer). */ #define CSENDBUFFERS (CMAXWINDOW + 1) static char *azGsendbuffers[CSENDBUFFERS]; static boolean fginit_sendbuffers (fallocate) boolean fallocate; { int i; /* Free up any remaining old buffers. */ for (i = 0; i < CSENDBUFFERS; i++) { xfree ((pointer) azGsendbuffers[i]); if (fallocate) { azGsendbuffers[i] = (char *) malloc (CFRAMELEN + 2 + iGremote_packsize); if (azGsendbuffers[i] == NULL) return FALSE; /* This bzero might not seem necessary, since before we send out each packet we zero out any non-data bytes. However, if we receive an SRJ at the start of the conversation, we will send out the packet before it has been set to anything, thus sending the contents of our heap. We avoid this by using bzero. */ bzero (azGsendbuffers[i], CFRAMELEN + 2 + iGremote_packsize); } else azGsendbuffers[i] = NULL; } return TRUE; } /* Allocate a packet to send out. The return value of this function must be filled in and passed to fgsenddata, or discarded. This will ensure that the buffers and iGsendseq stay in synch. Set *pclen to the amount of data to place in the buffer. */ /*ARGSUSED*/ char * zggetspace (qdaemon, pclen) struct sdaemon *qdaemon; size_t *pclen; { *pclen = iGremote_packsize; return azGsendbuffers[iGsendseq] + CFRAMELEN + 2; } /* Send out a data packet. This computes the checksum, sets up the header, and sends the packet out. The argument zdata should point to the return value of zggetspace. */ /*ARGSIGNORED*/ boolean fgsenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) struct sdaemon *qdaemon; char *zdata; size_t cdata; int ilocal; int iremote; long ipos; { char *z; int itt, iseg; size_t csize; int iclr1, iclr2; unsigned short icheck; /* Set the initial length bytes. See the description at the definition of SHORTDATA, above. */ itt = DATA; csize = iGremote_packsize; iseg = iGremote_segsize + 1; #if DEBUG > 0 if (cdata > csize) ulog (LOG_FATAL, "fgsend_packet: Packet size too large"); #endif iclr1 = -1; iclr2 = -2; if (cdata < csize) { /* If the remote packet size is larger than 64, the default, we can assume they can handle a smaller packet as well, which will be more efficient to send. */ if (iGremote_packsize > 64 && fGshort_packets) { /* The packet size is 1 << (iseg + 4). */ iseg = 1; csize = 32; while (csize < cdata) { csize <<= 1; ++iseg; } } if (csize != cdata) { size_t cshort; /* We have to add bytes which indicate how short the packet is. We do this by pushing the header backward, which we can do because we allocated two extra bytes for this purpose. */ iclr2 = 0; itt = SHORTDATA; cshort = csize - cdata; if (cshort <= 127) { --zdata; zdata[0] = (char) cshort; zdata[-1] = '\0'; bzero (zdata + cdata + 1, cshort - 1); } else { zdata -= 2; zdata[0] = (char) (0x80 | (cshort & 0x7f)); zdata[1] = (char) (cshort >> 7); bzero (zdata + cdata + 2, cshort - 2); iclr1 = 0; } } } z = zdata - CFRAMELEN; /* Zero out the preceding bytes, in case the last time this buffer was used those bytes were used. We need to zero out the initial bytes so that we can find the true start of the packet in zgadjust_ack. */ z[iclr1] = '\0'; z[iclr2] = '\0'; z[IFRAME_DLE] = DLE; z[IFRAME_K] = (char) iseg; icheck = (unsigned short) igchecksum (zdata, csize); /* We're just about ready to go. Wait until there is room in the receiver's window for us to send the packet. We do this now so that we send the correct value for the last packet received. Note that if iGsendseq == iGremote_ack, this means that the sequence numbers are actually 8 apart, since the packet could not have been acknowledged before it was sent; this can happen when the window size is 7. */ while (iGsendseq == iGremote_ack || CSEQDIFF (iGsendseq, iGremote_ack) > iGremote_winsize) { if (! fgwait_for_packet (qdaemon, TRUE, cGtimeout, cGretries)) return FALSE; } /* Ack all packets up to the next one, since the UUCP protocol requires that all packets be acked in order. */ while (CSEQDIFF (iGrecseq, iGlocal_ack) > 1) { iGlocal_ack = INEXTSEQ (iGlocal_ack); if (! fgsend_control (qdaemon, RR, iGlocal_ack)) return FALSE; } iGlocal_ack = iGrecseq; z[IFRAME_CONTROL] = (char) ((itt << 6) | (iGsendseq << 3) | iGrecseq); iGsendseq = INEXTSEQ (iGsendseq); icheck = ((unsigned short) ((0xaaaa - (icheck ^ (z[IFRAME_CONTROL] & 0xff))) & 0xffff)); z[IFRAME_CHECKLOW] = (char) (icheck & 0xff); z[IFRAME_CHECKHIGH] = (char) (icheck >> 8); z[IFRAME_XOR] = (char) (z[IFRAME_K] ^ z[IFRAME_CHECKLOW] ^ z[IFRAME_CHECKHIGH] ^ z[IFRAME_CONTROL]); /* If we're waiting for acks of retransmitted packets, then don't send this packet yet. The other side may not be ready for it yet. Instead, code in fggot_ack will send the outstanding packets when an ack is received. */ ++cGsent_packets; if (iGretransmit_seq != -1) { ++cGdelayed_packets; return TRUE; } DEBUG_MESSAGE2 (DEBUG_PROTO, "fgsenddata: Sending packet %d (%d bytes)", CONTROL_XXX (z[IFRAME_CONTROL]), cdata); return fsend_data (qdaemon->qconn, z, CFRAMELEN + csize, TRUE); } /* Recompute the control byte and checksum of a packet so that it includes the correct packet acknowledgement. This is called when a packet is retransmitted to make sure the retransmission does not confuse the other side. It returns a pointer to the start of the packet, skipping the bytes that may be unused at the start of azGsendbuffers[iseq]. */ static char * zgadjust_ack (iseq) int iseq; { register char *z; unsigned short icheck; z = azGsendbuffers[iseq]; if (*z == '\0') ++z; if (*z == '\0') ++z; /* If the received packet number is the same, there is nothing to do. */ if (CONTROL_YYY (z[IFRAME_CONTROL]) == iGrecseq) return z; /* Get the old checksum. */ icheck = (unsigned short) (((z[IFRAME_CHECKHIGH] & 0xff) << 8) | (z[IFRAME_CHECKLOW] & 0xff)); icheck = ((unsigned short) (((0xaaaa - icheck) ^ (z[IFRAME_CONTROL] & 0xff)) & 0xffff)); /* Update the control byte. */ z[IFRAME_CONTROL] = (char) ((z[IFRAME_CONTROL] &~ 07) | iGrecseq); /* Create the new checksum. */ icheck = ((unsigned short) ((0xaaaa - (icheck ^ (z[IFRAME_CONTROL] & 0xff))) & 0xffff)); z[IFRAME_CHECKLOW] = (char) (icheck & 0xff); z[IFRAME_CHECKHIGH] = (char) (icheck >> 8); /* Update the XOR byte. */ z[IFRAME_XOR] = (char) (z[IFRAME_K] ^ z[IFRAME_CHECKLOW] ^ z[IFRAME_CHECKHIGH] ^ z[IFRAME_CONTROL]); return z; } /* Send a control packet. These are fairly simple to construct. It seems reasonable to me that we should be able to send a control packet at any time, even if the receive window is closed. In particular, we don't want to delay when sending a CLOSE control message. If I'm wrong, it can be changed easily enough. */ static boolean fgsend_control (qdaemon, ixxx, iyyy) struct sdaemon *qdaemon; int ixxx; int iyyy; { char ab[CFRAMELEN]; int ictl; unsigned short icheck; #if DEBUG > 1 if (FDEBUGGING (DEBUG_PROTO) || (FDEBUGGING (DEBUG_ABNORMAL) && ixxx != RR)) ulog (LOG_DEBUG, "fgsend_control: Sending control %s %d", azGcontrol[ixxx], iyyy); #endif ab[IFRAME_DLE] = DLE; ab[IFRAME_K] = KCONTROL; ictl = (CONTROL << 6) | (ixxx << 3) | iyyy; icheck = (unsigned short) (0xaaaa - ictl); ab[IFRAME_CHECKLOW] = (char) (icheck & 0xff); ab[IFRAME_CHECKHIGH] = (char) (icheck >> 8); ab[IFRAME_CONTROL] = (char) ictl; ab[IFRAME_XOR] = (char) (ab[IFRAME_K] ^ ab[IFRAME_CHECKLOW] ^ ab[IFRAME_CHECKHIGH] ^ ab[IFRAME_CONTROL]); return fsend_data (qdaemon->qconn, ab, (size_t) CFRAMELEN, TRUE); } /* Wait for data to come in. This continues processing until a complete file or command has been received. */ boolean fgwait (qdaemon) struct sdaemon *qdaemon; { return fgwait_for_packet (qdaemon, FALSE, cGtimeout, cGretries); } /* Get a packet. This is called when we have nothing to send, but want to wait for a packet to come in. If freturncontrol is TRUE, this will return after getting any control packet. Otherwise, it will continue to receive packets until a complete file or a complete command has been received. The timeout and the number of retries are specified as arguments. The function returns FALSE if an error occurs or if cretries timeouts of ctimeout seconds were exceeded. */ static boolean fgwait_for_packet (qdaemon, freturncontrol, ctimeout, cretries) struct sdaemon *qdaemon; boolean freturncontrol; int ctimeout; int cretries; { int ctimeouts; int cgarbage; int cshort; ctimeouts = 0; cgarbage = 0; cshort = 0; while (TRUE) { boolean fexit; size_t cneed; boolean ffound; size_t crec; if (! fgprocess_data (qdaemon, TRUE, freturncontrol, &fexit, &cneed, &ffound)) return FALSE; if (fexit) return TRUE; DEBUG_MESSAGE1 (DEBUG_PROTO, "fgwait_for_packet: Need %lu bytes", (unsigned long) cneed); if (ffound) { ctimeouts = 0; cgarbage = 0; } else { if (cgarbage > cGgarbage_data) { ulog (LOG_ERROR, "Too much unrecognized data"); return FALSE; } } if (! freceive_data (qdaemon->qconn, cneed, &crec, ctimeout, TRUE)) return FALSE; cgarbage += crec; if (crec != 0) { /* If we don't get enough data twice in a row, we may have dropped some data and still be looking for the end of a large packet. Incrementing iPrecstart will force fgprocess_data to skip that packet and look through the rest of the data. In some situations, this will be a mistake. */ if (crec >= cneed) cshort = 0; else { ++cshort; if (cshort > 1) { iPrecstart = (iPrecstart + 1) % CRECBUFLEN; cshort = 0; } } } else { /* The read timed out. If we have an unacknowledged packet, send it again. Otherwise, send an RJ with the last packet we received correctly. */ ++ctimeouts; if (ctimeouts > cretries) { if (cretries > 0) ulog (LOG_ERROR, "Timed out waiting for packet"); return FALSE; } if (INEXTSEQ (iGremote_ack) != iGsendseq) { int inext; char *zsend; inext = INEXTSEQ (iGremote_ack); DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgwait_for_packet: Resending packet %d", inext); ++cGresent_packets; zsend = zgadjust_ack (inext); if (! fsend_data (qdaemon->qconn, zsend, CFRAMELEN + CPACKLEN (zsend), TRUE)) return FALSE; iGretransmit_seq = inext; } else { /* Send all pending acks first, to avoid confusing the other side. */ if (iGlocal_ack != iGrecseq) { if (! fgsend_acks (qdaemon)) return FALSE; } if (! fgsend_control (qdaemon, RJ, iGrecseq)) return FALSE; } } } } /* Send acks for all packets we haven't acked yet. */ static boolean fgsend_acks (qdaemon) struct sdaemon *qdaemon; { while (iGlocal_ack != iGrecseq) { iGlocal_ack = INEXTSEQ (iGlocal_ack); if (! fgsend_control (qdaemon, RR, iGlocal_ack)) return FALSE; } return TRUE; } /* Handle an ack of a packet. According to Hanrahan's paper, this acknowledges all previous packets. If this is an ack for a retransmitted packet, continue by resending up to two more packets following the retransmitted one. This should recover quickly from a line glitch, while avoiding the problem of continual retransmission. */ static boolean fggot_ack (qdaemon, iack) struct sdaemon *qdaemon; int iack; { int inext; char *zsend; /* We only decrement the error level if we are not retransmitting packets. We want to catch a sudden downgrade in line quality as fast as possible. */ if (cGerror_level > 0 && iGretransmit_seq == -1 && cGsent_packets % cGerror_decay == 0) --cGerror_level; cGexpect_bad_order = 0; /* Each time packet 0 is acknowledged, we call uwindow_acked since a new window has been acked. */ if (iack < iGremote_ack) uwindow_acked (qdaemon, FALSE); iGremote_ack = iack; if (iGretransmit_seq == -1) return TRUE; inext = INEXTSEQ (iGretransmit_seq); if (inext == iGsendseq) iGretransmit_seq = -1; else { DEBUG_MESSAGE1 (DEBUG_PROTO, "fggot_ack: Sending packet %d", inext); ++cGresent_packets; zsend = zgadjust_ack (inext); if (! fsend_data (qdaemon->qconn, zsend, CFRAMELEN + CPACKLEN (zsend), TRUE)) return FALSE; inext = INEXTSEQ (inext); if (inext == iGsendseq) iGretransmit_seq = -1; else { DEBUG_MESSAGE1 (DEBUG_PROTO, "fggot_ack: Sending packet %d", inext); ++cGresent_packets; zsend = zgadjust_ack (inext); if (! fsend_data (qdaemon->qconn, zsend, CFRAMELEN + CPACKLEN (zsend), TRUE)) return FALSE; iGretransmit_seq = inext; } } return TRUE; } /* See if we've received more than the permitted number of errors. If we receive a bad packet, we can expect a window full (less one) of out of order packets to follow, so we discount cGbad_order accordingly. */ static boolean fgcheck_errors (qdaemon) struct sdaemon *qdaemon; { if (cGerror_level > cGmax_errors && cGmax_errors >= 0) { ulog (LOG_ERROR, "Too many '%c' protocol errors", qdaemon->qproto->bname); return FALSE; } return TRUE; } /* Process the receive buffer into a data packet, if possible. All control packets are handled here. When a data packet is received, fgprocess_data calls fgot_data with the data; if that sets its pfexit argument to TRUE fgprocess_data will set *pfexit to TRUE and return TRUE. Also, if the freturncontrol argument is TRUE fgprocess_data will set *pfexit to TRUE and return TRUE. Otherwise fgprocess_data will continue trying to process data. If some error occurs, fgprocess_data will return FALSE. If there is not enough data to form a complete packet, then *pfexit will be set to FALSE, *pcneed will be set to the number of bytes needed to form a complete packet (unless pcneed is NULL) and fgprocess_data will return TRUE. If this function found a data packet, and pffound is not NULL, it will set *pffound to TRUE; this can be used to tell valid data from an endless stream of garbage and control packets. If fdoacks is TRUE, received packets will be acknowledged; otherwise they must be acknowledged later. */ static boolean fgprocess_data (qdaemon, fdoacks, freturncontrol, pfexit, pcneed, pffound) struct sdaemon *qdaemon; boolean fdoacks; boolean freturncontrol; boolean *pfexit; size_t *pcneed; boolean *pffound; { *pfexit = FALSE; if (pffound != NULL) *pffound = FALSE; while (iPrecstart != iPrecend) { char ab[CFRAMELEN]; int i, iget, cwant; unsigned short ihdrcheck, idatcheck; const char *zfirst, *zsecond; int cfirst, csecond; boolean fduprr; /* Look for the DLE which must start a packet. */ if (abPrecbuf[iPrecstart] != DLE) { char *zdle; cfirst = iPrecend - iPrecstart; if (cfirst < 0) cfirst = CRECBUFLEN - iPrecstart; zdle = memchr (abPrecbuf + iPrecstart, DLE, (size_t) cfirst); if (zdle == NULL) { iPrecstart = (iPrecstart + cfirst) % CRECBUFLEN; continue; } /* We don't need % CRECBUFLEN here because zdle - (abPrecbuf + iPrecstart) < cfirst <= CRECBUFLEN - iPrecstart. */ iPrecstart += zdle - (abPrecbuf + iPrecstart); } /* Get the first six bytes into ab. */ for (i = 0, iget = iPrecstart; i < CFRAMELEN && iget != iPrecend; i++, iget = (iget + 1) % CRECBUFLEN) ab[i] = abPrecbuf[iget]; /* If there aren't six bytes, there is no packet. */ if (i < CFRAMELEN) { if (pcneed != NULL) *pcneed = CFRAMELEN - i; return TRUE; } /* Make sure these six bytes start a packet. The check on IFRAME_DLE is basically a debugging check, since the above code should have ensured that it will never fail. If this is not the start of a packet, bump iPrecstart and loop around to look for another DLE. */ if (ab[IFRAME_DLE] != DLE || ab[IFRAME_K] < 1 || ab[IFRAME_K] > 9 || ab[IFRAME_XOR] != (ab[IFRAME_K] ^ ab[IFRAME_CHECKLOW] ^ ab[IFRAME_CHECKHIGH] ^ ab[IFRAME_CONTROL]) || CONTROL_TT (ab[IFRAME_CONTROL]) == ALTCHAN) { ++cGbad_hdr; ++cGerror_level; DEBUG_MESSAGE4 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Bad header: K %d TT %d XOR byte %d calc %d", ab[IFRAME_K] & 0xff, CONTROL_TT (ab[IFRAME_CONTROL]), ab[IFRAME_XOR] & 0xff, (ab[IFRAME_K] ^ ab[IFRAME_CHECKLOW] ^ ab[IFRAME_CHECKHIGH] ^ ab[IFRAME_CONTROL]) & 0xff); if (! fgcheck_errors (qdaemon)) return FALSE; iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } /* The zfirst and cfirst pair point to the first set of data for this packet; the zsecond and csecond point to the second set, in case the packet wraps around the end of the buffer. */ zfirst = abPrecbuf + iPrecstart + CFRAMELEN; cfirst = 0; zsecond = NULL; csecond = 0; if (ab[IFRAME_K] == KCONTROL) { /* This is a control packet. It should not have any data. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) { ++cGbad_hdr; ++cGerror_level; DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Bad header: control packet with data"); if (! fgcheck_errors (qdaemon)) return FALSE; iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } idatcheck = (unsigned short) (0xaaaa - ab[IFRAME_CONTROL]); cwant = 0; } else { int cinbuf; unsigned short icheck; /* This is a data packet. It should not be type CONTROL. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL) { ++cGbad_hdr; ++cGerror_level; DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Bad header: data packet is type CONTROL"); if (! fgcheck_errors (qdaemon)) return FALSE; iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } cinbuf = iPrecend - iPrecstart; if (cinbuf < 0) cinbuf += CRECBUFLEN; cinbuf -= CFRAMELEN; /* Make sure we have enough data. If we don't, wait for more. */ cwant = (int) CPACKLEN (ab); if (cinbuf < cwant) { if (pcneed != NULL) *pcneed = cwant - cinbuf; return TRUE; } /* Set up the data pointers and compute the checksum. */ if (iPrecend >= iPrecstart) cfirst = cwant; else { cfirst = CRECBUFLEN - (iPrecstart + CFRAMELEN); if (cfirst >= cwant) cfirst = cwant; else if (cfirst > 0) { zsecond = abPrecbuf; csecond = cwant - cfirst; } else { /* Here cfirst is non-positive, so subtracting from abPrecbuf will actually skip the appropriate number of bytes at the start of abPrecbuf. */ zfirst = abPrecbuf - cfirst; cfirst = cwant; } } if (csecond == 0) icheck = (unsigned short) igchecksum (zfirst, (size_t) cfirst); else icheck = (unsigned short) igchecksum2 (zfirst, (size_t) cfirst, zsecond, (size_t) csecond); idatcheck = ((unsigned short) (((0xaaaa - (icheck ^ (ab[IFRAME_CONTROL] & 0xff))) & 0xffff))); } ihdrcheck = (unsigned short) (((ab[IFRAME_CHECKHIGH] & 0xff) << 8) | (ab[IFRAME_CHECKLOW] & 0xff)); if (ihdrcheck != idatcheck) { DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Bad checksum: header 0x%x, data 0x%x", ihdrcheck, idatcheck); ++cGbad_checksum; ++cGerror_level; if (! fgcheck_errors (qdaemon)) return FALSE; /* If the checksum failed for a data packet, then if it was the one we were expecting send an RJ, otherwise ignore it. Previously if this code got the wrong packet number it would send an RR, but that may confuse some Telebit modems and it doesn't help in any case since the receiver will probably just ignore the RR as a duplicate (that's basically what this code does). If we totally missed the packet we will time out and send an RJ in the function fgwait_for_packet above. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) { /* Make sure we've acked everything up to this point. */ if (iGrecseq != iGlocal_ack) { if (! fgsend_acks (qdaemon)) return FALSE; } /* If this is the packet we wanted, tell the sender that it failed. */ if (CONTROL_XXX (ab[IFRAME_CONTROL]) == INEXTSEQ (iGrecseq)) { if (! fgsend_control (qdaemon, RJ, iGrecseq)) return FALSE; cGexpect_bad_order += iGrequest_winsize - 1; } } /* We can't skip the packet data after this, because if we have lost incoming bytes the next DLE will be somewhere in what we thought was the packet data. */ iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } /* We have a packet; remove the processed bytes from the receive buffer. */ iPrecstart = (iPrecstart + cwant + CFRAMELEN) % CRECBUFLEN; /* Store the control byte for the handshake routines. */ iGpacket_control = ab[IFRAME_CONTROL] & 0xff; /* Annoyingly, some UUCP packages appear to send an RR packet rather than an RJ packet when they want a packet to be resent. If we get a duplicate RR, we treat it as an RJ. */ fduprr = FALSE; if (CONTROL_TT (ab[IFRAME_CONTROL]) == CONTROL && CONTROL_XXX (ab[IFRAME_CONTROL]) == RR && iGremote_ack == CONTROL_YYY (ab[IFRAME_CONTROL]) && INEXTSEQ (iGremote_ack) != iGsendseq) { DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Treating duplicate RR as RJ"); fduprr = TRUE; } /* Update the received sequence number from the yyy field of a data packet or an RR control packet. If we've been delaying sending packets until we received an ack, this may send out some packets. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL || CONTROL_XXX (ab[IFRAME_CONTROL]) == RR) { if (! fggot_ack (qdaemon, CONTROL_YYY (ab[IFRAME_CONTROL]))) return FALSE; } /* If this isn't a control message, make sure we have received the expected packet sequence number, acknowledge the packet if it's the right one, and process the data. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) != CONTROL) { if (CONTROL_XXX (ab[IFRAME_CONTROL]) != INEXTSEQ (iGrecseq)) { /* We got the wrong packet number. */ DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Got packet %d; expected %d", CONTROL_XXX (ab[IFRAME_CONTROL]), INEXTSEQ (iGrecseq)); if (cGexpect_bad_order > 0) --cGexpect_bad_order; else { ++cGbad_order; ++cGerror_level; if (! fgcheck_errors (qdaemon)) return FALSE; } /* This code used to send an RR to encourage the other side to get back in synch, but that may confuse some Telebit modems and does little good in any case, since the other side will probably just ignore it anyhow (that's what this code does). */ continue; } /* We got the packet we expected. */ ++cGrec_packets; if (cGerror_level > 0 && cGrec_packets % cGerror_decay == 0) --cGerror_level; cGexpect_bad_order = 0; iGrecseq = INEXTSEQ (iGrecseq); DEBUG_MESSAGE1 (DEBUG_PROTO, "fgprocess_data: Got packet %d", iGrecseq); /* Tell the caller that we found something. */ if (pffound != NULL) *pffound = TRUE; /* If we are supposed to do acknowledgements here, send back an RR packet. */ if (fdoacks) { if (! fgsend_acks (qdaemon)) return FALSE; } /* If this is a short data packet, adjust the data pointers and lengths. */ if (CONTROL_TT (ab[IFRAME_CONTROL]) == SHORTDATA) { int cshort, cmove; if ((zfirst[0] & 0x80) == 0) { cshort = zfirst[0] & 0xff; cmove = 1; } else { int cbyte2; if (cfirst > 1) cbyte2 = zfirst[1] & 0xff; else cbyte2 = zsecond[0] & 0xff; cshort = (zfirst[0] & 0x7f) + (cbyte2 << 7); cmove = 2; } DEBUG_MESSAGE1 (DEBUG_PROTO, "fgprocess_data: Packet short by %d", cshort); /* Adjust the start of the buffer for the bytes used by the count. */ if (cfirst > cmove) { zfirst += cmove; cfirst -= cmove; } else { zfirst = zsecond + (cmove - cfirst); cfirst = csecond - (cmove - cfirst); csecond = 0; } /* Adjust the length of the buffer for the bytes we are not supposed to consider. */ cshort -= cmove; if (csecond >= cshort) csecond -= cshort; else { cfirst -= cshort - csecond; csecond = 0; } #if DEBUG > 0 /* This should not happen, but just in case. */ if (cfirst < 0) cfirst = 0; #endif } if (! fgot_data (qdaemon, zfirst, (size_t) cfirst, zsecond, (size_t) csecond, -1, -1, (long) -1, INEXTSEQ (iGremote_ack) == iGsendseq, pfexit)) return FALSE; /* If fgot_data told us that we were finished, get out. */ if (*pfexit) return TRUE; /* If we've been asked to return control packets, get out now. */ if (freturncontrol) { *pfexit = TRUE; return TRUE; } continue; } /* Handle control messages here. */ #if DEBUG > 1 if (FDEBUGGING (DEBUG_PROTO) || (FDEBUGGING (DEBUG_ABNORMAL) && CONTROL_XXX (ab[IFRAME_CONTROL]) != RR)) ulog (LOG_DEBUG, "fgprocess_data: Got control %s %d", azGcontrol[CONTROL_XXX (ab[IFRAME_CONTROL])], CONTROL_YYY (ab[IFRAME_CONTROL])); #endif switch (CONTROL_XXX (ab[IFRAME_CONTROL])) { case CLOSE: /* The other side has closed the connection. */ if (fLog_sighup) { ulog (LOG_ERROR, "Received unexpected CLOSE packet"); (void) fgsend_control (qdaemon, CLOSE, 0); } return FALSE; case RR: /* Acknowledge receipt of a packet. This was already handled above, unless we are treating it as RJ. */ if (! fduprr) break; /* Fall through. */ case RJ: /* The other side dropped a packet. Begin retransmission with the packet following the one acknowledged. We don't retransmit the packets immediately, but instead wait for the first one to be acked. This prevents us from sending an entire window several times if we get several RJ packets. */ iGremote_ack = CONTROL_YYY (ab[IFRAME_CONTROL]); iGretransmit_seq = INEXTSEQ (iGremote_ack); if (iGretransmit_seq == iGsendseq) iGretransmit_seq = -1; else { char *zpack; DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Remote reject: next %d resending %d", iGsendseq, iGretransmit_seq); ++cGresent_packets; ++cGremote_rejects; ++cGerror_level; if (! fgcheck_errors (qdaemon)) return FALSE; zpack = zgadjust_ack (iGretransmit_seq); if (! fsend_data (qdaemon->qconn, zpack, CFRAMELEN + CPACKLEN (zpack), TRUE)) return FALSE; } break; case SRJ: /* Selectively reject a particular packet. This is not used by UUCP, but it's easy to support. */ DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fgprocess_data: Selective reject of %d", CONTROL_YYY (ab[IFRAME_CONTROL])); { char *zpack; ++cGresent_packets; ++cGremote_rejects; ++cGerror_level; zpack = zgadjust_ack (CONTROL_YYY (ab[IFRAME_CONTROL])); if (! fsend_data (qdaemon->qconn, zpack, CFRAMELEN + CPACKLEN (zpack), TRUE)) return FALSE; } break; case INITC: case INITB: case INITA: /* Ignore attempts to reinitialize. */ break; } /* If we've been asked to return control packets, get out. */ if (freturncontrol) { *pfexit = TRUE; return TRUE; } /* Loop around to look for the next packet, if any. */ } /* There is no data left in the receive buffer. */ if (pcneed != NULL) *pcneed = CFRAMELEN; return TRUE; } /* Compute the 'g' protocol checksum. This is unfortunately rather awkward. This is the most time consuming code in the entire program. It's also not a great checksum, since it can be fooled by some single bit errors. */ /* Sorry about this knavery, but it speeds up the VAX code significantly. It would be better to rewrite the whole routine in assembler. */ #ifdef __GNUC__ #ifdef __vax__ #define VAX_ASM 1 #endif #endif #if VAX_ASM #define ROTATE(i) \ asm ("cvtwl %1,%0\n\trotl $1,%0,%0" : "=g" (i) : "g" (i)) #else #define ROTATE(i) i += i + ((i & 0x8000) >> 15) #endif #define ITERATION \ /* Rotate ichk1 left. */ \ ROTATE (ichk1); \ \ /* The guts of the checksum. */ \ b = BUCHAR (*z++); \ if (b != 0) \ { \ ichk1 &= 0xffff; \ ichk1 += b; \ ichk2 += ichk1 ^ c; \ if ((ichk1 >> 16) != 0) \ ichk1 ^= ichk2; \ } \ else \ { \ ichk2 += ichk1 ^ c; \ ichk1 ^= ichk2; \ } \ \ --c static int igchecksum (z, c) register const char *z; register size_t c; { register unsigned long ichk1, ichk2; ichk1 = 0xffff; ichk2 = 0; do { register unsigned int b; ITERATION; ITERATION; ITERATION; ITERATION; } while (c > 0); return ichk1 & 0xffff; } /* We use a separate function compute the checksum if the block is split around the end of the receive buffer since it occurs much less frequently and the checksum is already high up in the profiles. These functions are almost identical, and this one actually only has a few more instructions in the inner loop. */ static int igchecksum2 (zfirst, cfirst, zsecond, csecond) const char *zfirst; size_t cfirst; const char *zsecond; size_t csecond; { register unsigned long ichk1, ichk2; register const char *z; register size_t c; z = zfirst; c = cfirst + csecond; ichk1 = 0xffff; ichk2 = 0; do { register unsigned int b; ITERATION; /* If the first buffer has been finished, switch to the second. */ --cfirst; if (cfirst == 0) z = zsecond; } while (c > 0); return ichk1 & 0xffff; } ed 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 evuucp-1.04/proti.c1004440004150000170000012460205337263511010667 037777777777 1 0 /* 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.17 1993/01/26 06:03:42 ian Rel $"; #endif #include #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "trans.h" #include "system.h" #include "prot.h" /* The 'i' protocol is a simple sliding window protocol, created by me. It is in many ways similar to the 'g' protocol. Several ideas are also taken from the paper ``A High-Throughput Message Transport System'' by P. Lauder. I don't know where the paper was published, but the author's e-mail address is piers@cs.su.oz.au. However, I haven't adopted his main idea, which is to dispense with windows entirely. This is because some links still do require flow control and, more importantly, because I want to have a limit to the amount of data I must be able to resend upon request. To reduce the costs of window acknowledgements, I use a large window and only require an ack at the halfway point. Each packet starts with a header containing the following information: Intro byte 8 bits byte 1 Packet number 5 bits byte 2 Local channel 3 bits Packet ack 5 bits byte 3 Remote channel 3 bits Packet type 3 bits bytes 4-5 Direction 1 bit Data length 12 bits Header check 8 bits byte 6 If the data length is not 0, this is followed by the data and a 32 bit CRC checksum. The following packet types are defined: SYNC Initialize the connection DATA Data packet ACK Simple acknowledgement with no data NAK Negative acknowledgement; requests resend of single packet SPOS Set file position CLOSE Close the connection */ /* The offsets of the bytes in the packet header. */ #define IHDR_INTRO (0) #define IHDR_LOCAL (1) #define IHDR_REMOTE (2) #define IHDR_CONTENTS1 (3) #define IHDR_CONTENTS2 (4) #define IHDR_CHECK (5) /* Macros to set and extract values of IHDR_LOCAL and IHDR_REMOTE. */ #define IHDRWIN_SET(iseq, ichan) (((iseq) << 3) | (ichan)) #define IHDRWIN_GETSEQ(ival) (((ival) >> 3) & 0x1f) #define IHDRWIN_GETCHAN(ival) ((ival) & 0x07) /* Macros to set and extract values of IHDR_CONTENTS fields. */ #define IHDRCON_SET1(ttype, fcaller, cbytes) \ (((ttype) << 5) | ((fcaller) ? (1 << 4) : 0) | (((cbytes) >> 8) & 0x0f)) #define IHDRCON_SET2(ttype, fcaller, cbytes) ((cbytes) & 0xff) #define THDRCON_GETTYPE(i1, i2) (((i1) >> 5) & 0x07) #define FHDRCON_GETCALLER(i1, i2) (((i1) & (1 << 4)) != 0) #define CHDRCON_GETBYTES(i1, i2) ((((i1) & 0x0f) << 8) | ((i2) & 0xff)) /* Macros for the IHDR_CHECK field. */ #define IHDRCHECK_VAL(zhdr) \ ((zhdr[IHDR_LOCAL] \ ^ zhdr[IHDR_REMOTE] \ ^ zhdr[IHDR_CONTENTS1] \ ^ zhdr[IHDR_CONTENTS2]) \ & 0xff) /* Length of the packet header. */ #define CHDRLEN (6) /* Amount of space to skip between start of packet and actual data. This is used to make the actual data longword aligned, to encourage good performance when copying data into the buffer. */ #define CHDRSKIPLEN (CHDRLEN + (sizeof (long) - CHDRLEN % sizeof (long))) /* Amount of space to skip between memory buffer and header. */ #define CHDROFFSET (CHDRSKIPLEN - CHDRLEN) /* Length of the trailing checksum. */ #define CCKSUMLEN (4) /* Macros to set and get the checksum. These multiply evaluate their arguments. */ #define ICKSUM_GET(z) \ ((((((((unsigned long) ((z)[0] & 0xff)) << 8) \ | (unsigned long) ((z)[1] & 0xff)) << 8) \ | (unsigned long) ((z)[2] & 0xff)) << 8) \ | (unsigned long) ((z)[3] & 0xff)) #define UCKSUM_SET(z, i) \ (void) ((z)[0] = (((i) >> 24) & 0xff), \ (z)[1] = (((i) >> 16) & 0xff), \ (z)[2] = (((i) >> 8) & 0xff), \ (z)[3] = ((i) & 0xff)) /* The header introduction character. */ #define IINTRO ('\007') /* The packet types. */ #define DATA (0) #define SYNC (1) #define ACK (2) #define NAK (3) #define SPOS (4) #define CLOSE (5) /* Largest possible packet size (plus 1). */ #define IMAXPACKSIZE (1 << 12) /* Largest possible sequence number (plus 1). */ #define IMAXSEQ 32 /* Get the next sequence number given a sequence number. */ #define INEXTSEQ(i) ((i + 1) & (IMAXSEQ - 1)) /* Compute i1 - i2 in sequence space (i.e., the number of packets from i2 to i1). */ #define CSEQDIFF(i1, i2) (((i1) + IMAXSEQ - (i2)) & (IMAXSEQ - 1)) /* Largest possible channel number (plus 1). */ #define IMAXICHAN (8) /* Default packet size to request (protocol parameter ``packet-size''). */ #define IREQUEST_PACKSIZE (1024) /* Default window size to request (protocol parameter ``window''). */ #define IREQUEST_WINSIZE (16) /* Default timeout to use when sending the SYNC packet (protocol parameter ``sync-timeout''). */ #define CSYNC_TIMEOUT (10) /* Default number of times to retry sending the SYNC packet (protocol parameter ``sync-retries''). */ #define CSYNC_RETRIES (6) /* Default timeout to use when waiting for a packet (protocol parameter ``timeout''). */ #define CTIMEOUT (10) /* Default number of times to retry sending a packet before giving up (protocol parameter ``retries''). */ #define CRETRIES (6) /* Default maximum level of errors to accept before giving up (protocol parameter ``errors''). */ #define CERRORS (100) /* Default decay rate. Each time we receive this many packets succesfully, we decrement the error level by one (protocol parameter ``error-decay''). */ #define CERROR_DECAY (10) /* The default list of characters to avoid: XON and XOFF. This string is processed as an escape sequence. This is 'j' protocol parameter ``avoid''; it is defined in this file because the 'i' and 'j' protocols share protocol parameters. */ #define ZAVOID "\\021\\023" /* Local variables. */ /* Packet size to request (protocol parameter ``packet-size''). */ static int iIrequest_packsize = IREQUEST_PACKSIZE; /* Window size to request (protocol parameter ``window''). */ static int iIrequest_winsize = IREQUEST_WINSIZE; /* Remote packet size (set from SYNC packet or from iIforced_remote_packsize). */ static int iIremote_packsize; /* Size which buffers were allocated for. */ static int iIalc_packsize; /* Forced remote packet size, used if non-zero (protocol parameter ``remote-packet-size''). */ static int iIforced_remote_packsize = 0; /* Remote window size (set from SYNC packet or from iIforced_remote_winsize). */ static int iIremote_winsize; /* Forced remote window size, used if non-zero (protocol parameter ``remote-window''). */ static int iIforced_remote_winsize = 0; /* Timeout to use when sending the SYNC packet (protocol parameter ``sync-timeout''). */ int cIsync_timeout = CSYNC_TIMEOUT; /* Number of times to retry sending the SYNC packet (protocol parameter ``sync-retries''). */ static int cIsync_retries = CSYNC_RETRIES; /* Timeout to use when waiting for a packet (protocol parameter ``timeout''). */ static int cItimeout = CTIMEOUT; /* Number of times to retry sending a packet before giving up (protocol parameter ``retries''). */ static int cIretries = CRETRIES; /* Maximum level of errors to accept before giving up (protocol parameter ``errors''). */ static int cIerrors = CERRORS; /* Each time we receive this many packets succesfully, we decrement the error level by one (protocol parameter ``error-decay''). */ static int cIerror_decay = CERROR_DECAY; /* The set of characters to avoid (protocol parameter ``avoid''). This is actually part of the 'j' protocol; it is defined in this file because the 'i' and 'j' protocols use the same protocol parameters. */ const char *zJavoid_parameter = ZAVOID; /* Routine to use when sending data. This is a hook for the 'j' protocol. */ static boolean (*pfIsend) P((struct sconnection *qconn, const char *zsend, size_t csend, boolean fdoread)); /* Routine to use to use when reading data. This is a hook for the 'j' protocol. */ static boolean (*pfIreceive) P((struct sconnection *qconn, size_t cneed, size_t *pcrec, int ctimeout, boolean freport)); /* Next sequence number to send. */ static int iIsendseq; /* Last sequence number received. */ static int iIrecseq; /* Last sequence number we have acknowledged. */ static int iIlocal_ack; /* Last sequence number remote system has acknowledged. */ static int iIremote_ack; /* File position we are sending from. */ static long iIsendpos; /* File position we are receiving to. */ static long iIrecpos; /* TRUE if closing the connection. */ static boolean fIclosing; /* Array of sent packets indexed by packet number. */ static char *azIsendbuffers[IMAXSEQ]; /* Array of received packets that we aren't ready to process yet, indexed by packet number. */ static char *azIrecbuffers[IMAXSEQ]; /* For each packet sequence number, record whether we sent a NAK for the packet. */ static boolean afInaked[IMAXSEQ]; /* Number of SYNC packets received (used only to detect whether one was received). */ static int cIsyncs; /* Number of packets sent. */ static long cIsent_packets; /* Number of packets received. */ static long cIreceived_packets; /* Number of packets resent. */ static long cIresent_packets; /* Number of bad packet headers received. */ static long cIbad_hdr; /* Number of out of order packets received. */ static long cIbad_order; /* Number of bad checksums received. */ static long cIbad_cksum; /* Number of packets rejected by remote system. */ static long cIremote_rejects; /* Protocol parameter commands. */ struct uuconf_cmdtab asIproto_params[] = { { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_packsize, NULL }, { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_winsize, NULL }, { "remote-packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iIforced_remote_packsize, NULL }, { "remote-window", UUCONF_CMDTABTYPE_INT, (pointer) &iIforced_remote_winsize, NULL }, { "sync-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_timeout, NULL }, { "sync-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_retries, NULL }, { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cItimeout, NULL }, { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIretries, NULL }, { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cIerrors, NULL }, { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cIerror_decay, NULL }, /* The ``avoid'' protocol parameter is part of the 'j' protocol, but it is convenient for the 'i' and 'j' protocols to share the same protocol parameter table. */ { "avoid", UUCONF_CMDTABTYPE_STRING, (pointer) &zJavoid_parameter, NULL }, { NULL, 0, NULL, NULL } }; /* Local functions. */ static boolean finak P((struct sdaemon *qdaemon, int iseq)); static boolean firesend P((struct sdaemon *qdaemon)); static boolean fiwindow_wait P((struct sdaemon *qdaemon)); static boolean fiwait_for_packet P((struct sdaemon *qdaemon, int ctimeout, int cretries, boolean fone, boolean *ftimedout)); static boolean ficheck_errors P((struct sdaemon *qdaemon)); static boolean fiprocess_data P((struct sdaemon *qdaemon, boolean *pfexit, boolean *pffound, size_t *pcneed)); static boolean fiprocess_packet P((struct sdaemon *qdaemon, const char *zhdr, const char *zfirst, int cfirst, const char *zsecond, int csecond, boolean *pfexit)); /* The 'i' protocol start routine. The work is done in a routine which is also called by the 'j' protocol start routine. */ boolean fistart (qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fsend_data, freceive_data); } /* Start the protocol. This routine is called by both the 'i' and 'j' protocol start routines. We keep transmitting a SYNC packet containing the window and packet size we would like to receive until we receive a SYNC packet from the remote system. The first two bytes of the data contents of a SYNC packet are the maximum packet size we want to receive (high byte, low byte), and the next byte is the maximum window size we want to use. */ boolean fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) struct sdaemon *qdaemon; char **pzlog; int imaxpacksize; boolean (*pfsend) P((struct sconnection *qconn, const char *zsend, size_t csend, boolean fdoread)); boolean (*pfreceive) P((struct sconnection *qconn, size_t cneed, size_t *pcrec, int ctimeout, boolean freport)); { char ab[CHDRLEN + 3 + CCKSUMLEN]; unsigned long icksum; int ctries; int csyncs; *pzlog = NULL; pfIsend = pfsend; pfIreceive = pfreceive; if (iIforced_remote_packsize <= 0 || iIforced_remote_packsize >= imaxpacksize) iIforced_remote_packsize = 0; else iIremote_packsize = iIforced_remote_packsize; iIalc_packsize = 0; if (iIforced_remote_winsize <= 0 || iIforced_remote_winsize >= IMAXSEQ) iIforced_remote_winsize = 0; else iIremote_winsize = iIforced_remote_winsize; iIsendseq = 1; iIrecseq = 0; iIlocal_ack = 0; iIremote_ack = 0; iIsendpos = 0; iIrecpos = 0; fIclosing = FALSE; cIsent_packets = 0; cIreceived_packets = 0; cIresent_packets = 0; cIbad_hdr = 0; cIbad_order = 0; cIbad_cksum = 0; cIremote_rejects = 0; ab[IHDR_INTRO] = IINTRO; ab[IHDR_LOCAL] = ab[IHDR_REMOTE] = IHDRWIN_SET (0, 0); ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3); ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3); ab[IHDR_CHECK] = IHDRCHECK_VAL (ab); ab[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff; ab[CHDRLEN + 1] = iIrequest_packsize & 0xff; ab[CHDRLEN + 2] = iIrequest_winsize; icksum = icrc (ab + CHDRLEN, 3, ICRCINIT); UCKSUM_SET (ab + CHDRLEN + 3, icksum); /* The static cIsyncs is incremented each time a SYNC packet is received. */ csyncs = cIsyncs; ctries = 0; while (TRUE) { boolean ftimedout; DEBUG_MESSAGE2 (DEBUG_PROTO, "fistart: Sending SYNC packsize %d winsize %d", iIrequest_packsize, iIrequest_winsize); if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 3 + CCKSUMLEN, TRUE)) return FALSE; if (fiwait_for_packet (qdaemon, cIsync_timeout, 0, FALSE, &ftimedout)) { if (csyncs != cIsyncs) break; } else { if (! ftimedout) return FALSE; ++ctries; if (ctries > cIsync_retries) { ulog (LOG_ERROR, "Protocol startup failed"); return FALSE; } } } /* We got a SYNC packet; set up packet buffers to use. */ if (iIremote_packsize > imaxpacksize) iIremote_packsize = imaxpacksize; do { int iseq; for (iseq = 0; iseq < IMAXSEQ; iseq++) { azIrecbuffers[iseq] = NULL; afInaked[iseq] = FALSE; azIsendbuffers[iseq] = (char *) malloc (iIremote_packsize + CHDRSKIPLEN + CCKSUMLEN); if (azIsendbuffers[iseq] == NULL) { int ifree; for (ifree = 0; ifree < iseq; ifree++) free ((pointer) azIsendbuffers[ifree]); break; } } if (iseq >= IMAXSEQ) { *pzlog = zbufalc (sizeof "protocol 'i' packet size %d window %d" + 50); sprintf (*pzlog, "protocol '%c' packet size %d window %d", qdaemon->qproto->bname, iIremote_packsize, iIremote_winsize); iIalc_packsize = iIremote_packsize; return TRUE; } iIremote_packsize >>= 1; } while (iIremote_packsize > 200); ulog (LOG_ERROR, "'%c' protocol startup failed; insufficient memory for packets", qdaemon->qproto->bname); return FALSE; } /* Shut down the protocol. We can be fairly informal about this, since we know that the upper level protocol has already exchanged hangup messages. If we didn't know that, we would have to make sure that all packets before the CLOSE had been received. */ boolean fishutdown (qdaemon) struct sdaemon *qdaemon; { char *z; size_t clen; fIclosing = TRUE; z = zigetspace (qdaemon, &clen) - CHDRLEN; z[IHDR_INTRO] = IINTRO; z[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0); z[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); iIlocal_ack = iIrecseq; z[IHDR_CONTENTS1] = IHDRCON_SET1 (CLOSE, qdaemon->fcaller, 0); z[IHDR_CONTENTS2] = IHDRCON_SET2 (CLOSE, qdaemon->fcaller, 0); z[IHDR_CHECK] = IHDRCHECK_VAL (z); DEBUG_MESSAGE0 (DEBUG_PROTO, "fishutdown: Sending CLOSE"); if (! (*pfIsend) (qdaemon->qconn, z, CHDRLEN, FALSE)) return FALSE; ulog (LOG_NORMAL, "Protocol '%c' packets: sent %ld, resent %ld, received %ld", qdaemon->qproto->bname, cIsent_packets, cIresent_packets, cIreceived_packets); if (cIbad_hdr != 0 || cIbad_cksum != 0 || cIbad_order != 0 || cIremote_rejects != 0) ulog (LOG_NORMAL, "Errors: header %ld, checksum %ld, order %ld, remote rejects %ld", cIbad_hdr, cIbad_cksum, cIbad_order, cIremote_rejects); /* Reset the protocol parameters to their default values. */ iIrequest_packsize = IREQUEST_PACKSIZE; iIrequest_winsize = IREQUEST_WINSIZE; iIforced_remote_packsize = 0; iIforced_remote_winsize = 0; cIsync_timeout = CSYNC_TIMEOUT; cIsync_retries = CSYNC_RETRIES; cItimeout = CTIMEOUT; cIretries = CRETRIES; cIerrors = CERRORS; cIerror_decay = CERROR_DECAY; zJavoid_parameter = ZAVOID; return TRUE; } /* Send a command string. These are just sent as normal packets, ending in a packet containing a null byte. */ boolean fisendcmd (qdaemon, z, ilocal, iremote) struct sdaemon *qdaemon; const char *z; int ilocal; int iremote; { size_t clen; DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fisendcmd: Sending command \"%s\"", z); clen = strlen (z); while (TRUE) { char *zpacket; size_t csize; zpacket = zigetspace (qdaemon, &csize); if (clen < csize) { memcpy (zpacket, z, clen + 1); return fisenddata (qdaemon, zpacket, clen + 1, ilocal, iremote, (long) -1); } memcpy (zpacket, z, csize); z += csize; clen -= csize; if (! fisenddata (qdaemon, zpacket, csize, ilocal, iremote, (long) -1)) return FALSE; } /*NOTREACHED*/ } /* Send a NAK. */ static boolean finak (qdaemon, iseq) struct sdaemon *qdaemon; int iseq; { char abnak[CHDRLEN]; abnak[IHDR_INTRO] = IINTRO; abnak[IHDR_LOCAL] = IHDRWIN_SET (iseq, 0); abnak[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); iIlocal_ack = iIrecseq; abnak[IHDR_CONTENTS1] = IHDRCON_SET1 (NAK, qdaemon->fcaller, 0); abnak[IHDR_CONTENTS2] = IHDRCON_SET2 (NAK, qdaemon->fcaller, 0); abnak[IHDR_CHECK] = IHDRCHECK_VAL (abnak); afInaked[iseq] = TRUE; DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "finak: Sending NAK %d", iseq); return (*pfIsend) (qdaemon->qconn, abnak, CHDRLEN, TRUE); } /* Resend the latest packet the remote has not acknowledged. */ static boolean firesend (qdaemon) struct sdaemon *qdaemon; { int iseq; char *zhdr; size_t clen; iseq = INEXTSEQ (iIremote_ack); if (iseq == iIsendseq) { /* Everything has been ACKed and there is nothing to resend. */ return TRUE; } DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "firesend: Resending packet %d", iseq); /* Update the received sequence number. */ zhdr = azIsendbuffers[iseq] + CHDROFFSET; if (IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE]) != iIrecseq) { int iremote; iremote = IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]); zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr); iIlocal_ack = iIrecseq; } ++cIresent_packets; clen = CHDRCON_GETBYTES (zhdr[IHDR_CONTENTS1], zhdr[IHDR_CONTENTS2]); return (*pfIsend) (qdaemon->qconn, zhdr, CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), TRUE); } /* Wait until there is an opening in the receive window of the remote system. */ static boolean fiwindow_wait (qdaemon) struct sdaemon *qdaemon; { /* iIsendseq is the sequence number we are sending, and iIremote_ack is the last sequence number acknowledged by the remote. */ while (CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) { /* If a NAK is lost, it is possible for the other side to be sending a stream of packets while we are waiting for an ACK. This should be caught in fiprocess_data; if it is about to send an ACK, but it has an unacknowledged packet to send, it sends the entire packet. Hopefully that will trigger an ACK or a NAK and get us going again. */ DEBUG_MESSAGE0 (DEBUG_PROTO, "fiwindow_wait: Waiting for ACK"); if (! fiwait_for_packet (qdaemon, cItimeout, cIretries, TRUE, (boolean *) NULL)) return FALSE; } return TRUE; } /* Get buffer space to use for packet data. We return a pointer to the space to be used for the actual data, leaving room for the header. */ /*ARGSUSED*/ char * zigetspace (qdaemon, pclen) struct sdaemon *qdaemon; size_t *pclen; { *pclen = iIremote_packsize; return azIsendbuffers[iIsendseq] + CHDRSKIPLEN; } /* Send a data packet. The zdata argument will always point to value returned by zigetspace, so we know that we have room before it for the header information. */ boolean fisenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) struct sdaemon *qdaemon; char *zdata; size_t cdata; int ilocal; int iremote; long ipos; { char *zhdr; unsigned long icksum; boolean fret; #if DEBUG > 0 if (ilocal < 0 || ilocal >= IMAXICHAN || iremote < 0 || iremote >= IMAXICHAN) ulog (LOG_FATAL, "fisenddata: ilocal %d iremote %d", ilocal, iremote); #endif /* If we are changing the file position, we must send an SPOS packet. */ if (ipos != iIsendpos && ipos != (long) -1) { int inext; char *zspos; /* We need to get a buffer to hold the SPOS packet, and it needs to be next sequence number. However, the data we have been given is currently in the next sequence number buffer. So we shuffle the buffers around. */ inext = INEXTSEQ (iIsendseq); zspos = azIsendbuffers[inext]; azIsendbuffers[inext] = zdata - CHDRSKIPLEN; azIsendbuffers[iIsendseq] = zspos; zspos += CHDROFFSET; zspos[IHDR_INTRO] = IINTRO; zspos[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0); zspos[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); iIlocal_ack = iIrecseq; zspos[IHDR_CONTENTS1] = IHDRCON_SET1 (SPOS, qdaemon->fcaller, CCKSUMLEN); zspos[IHDR_CONTENTS2] = IHDRCON_SET2 (SPOS, qdaemon->fcaller, CCKSUMLEN); zspos[IHDR_CHECK] = IHDRCHECK_VAL (zspos); UCKSUM_SET (zspos + CHDRLEN, (unsigned long) ipos); icksum = icrc (zspos + CHDRLEN, CCKSUMLEN, ICRCINIT); UCKSUM_SET (zspos + CHDRLEN + CCKSUMLEN, icksum); /* Wait for an opening in the window. */ if (iIremote_winsize > 0 && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) { if (! fiwindow_wait (qdaemon)) return FALSE; } DEBUG_MESSAGE1 (DEBUG_PROTO, "fisenddata: Sending SPOS %ld", ipos); if (! (*pfIsend) (qdaemon->qconn, zspos, CHDRLEN + CCKSUMLEN + CCKSUMLEN, TRUE)) return FALSE; iIsendseq = INEXTSEQ (iIsendseq); iIsendpos = ipos; } zhdr = zdata - CHDRLEN; zhdr[IHDR_INTRO] = IINTRO; zhdr[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, ilocal); zhdr[IHDR_CONTENTS1] = IHDRCON_SET1 (DATA, qdaemon->fcaller, cdata); zhdr[IHDR_CONTENTS2] = IHDRCON_SET2 (DATA, qdaemon->fcaller, cdata); /* Compute and set the checksum. */ if (cdata > 0) { icksum = icrc (zdata, cdata, ICRCINIT); UCKSUM_SET (zdata + cdata, icksum); } /* Wait until there is an opening in the window (we hope to not have to wait here at all, actually; ideally the window should be large enough to avoid a wait). */ if (iIremote_winsize > 0 && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize) { if (! fiwindow_wait (qdaemon)) return FALSE; } /* We only fill in IHDR_REMOTE now, since only now do know the correct value of iIrecseq. */ zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); iIlocal_ack = iIrecseq; zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr); DEBUG_MESSAGE2 (DEBUG_PROTO, "fisenddata: Sending packet %d (%d bytes)", iIsendseq, (int) cdata); iIsendseq = INEXTSEQ (iIsendseq); ++cIsent_packets; fret = (*pfIsend) (qdaemon->qconn, zhdr, cdata + CHDRLEN + (cdata > 0 ? CCKSUMLEN : 0), TRUE); iIsendpos += cdata; if (fret && iPrecstart != iPrecend) { boolean fexit; fret = fiprocess_data (qdaemon, &fexit, (boolean *) NULL, (size_t *) NULL); } return fret; } /* Wait for data to come in. */ boolean fiwait (qdaemon) struct sdaemon *qdaemon; { return fiwait_for_packet (qdaemon, cItimeout, cIretries, FALSE, (boolean *) NULL); } /* Wait for a packet. Either there is no data to send, or the remote window is full. */ static boolean fiwait_for_packet (qdaemon, ctimeout, cretries, fone, pftimedout) struct sdaemon *qdaemon; int ctimeout; int cretries; boolean fone; boolean *pftimedout; { int cshort; int ctimeouts; if (pftimedout != NULL) *pftimedout = FALSE; cshort = 0; ctimeouts = 0; while (TRUE) { boolean fexit, ffound; size_t cneed; size_t crec; if (! fiprocess_data (qdaemon, &fexit, &ffound, &cneed)) return FALSE; if (fexit || (fone && ffound)) return TRUE; if (cneed == 0) continue; DEBUG_MESSAGE1 (DEBUG_PROTO, "fiwait_for_packet: Need %d bytes", (int) cneed); if (! (*pfIreceive) (qdaemon->qconn, cneed, &crec, ctimeout, TRUE)) return FALSE; if (crec != 0) { /* If we didn't get enough data twice in a row, we may have dropped some data and be waiting for the end of a large packet. Incrementing iPrecstart will force fiprocess_data to skip the current packet and try to find the next one. */ if (crec >= cneed) cshort = 0; else { ++cshort; if (cshort > 1) { iPrecstart = (iPrecstart + 1) % CRECBUFLEN; cshort = 0; } } } else { int i; /* We timed out on the read. */ ++ctimeouts; if (ctimeouts > cretries) { if (cretries > 0) ulog (LOG_ERROR, "Timed out waiting for packet"); if (pftimedout != NULL) *pftimedout = TRUE; return FALSE; } /* Clear out the list of packets we have sent NAKs for. We should have seen some sort of response by now. */ for (i = 0; i < IMAXSEQ; i++) afInaked[i] = FALSE; /* Send a NAK for the packet we want, and, if we have an unacknowledged packet, send it again. */ if (! finak (qdaemon, INEXTSEQ (iIrecseq)) || ! firesend (qdaemon)) return FALSE; } } /*NOTREACHED*/ } /* Make sure we haven't overflowed the permissible error level. */ static boolean ficheck_errors (qdaemon) struct sdaemon *qdaemon; { if (cIerrors < 0) return TRUE; if (((cIbad_order + cIbad_hdr + cIbad_cksum + cIremote_rejects) - (cIreceived_packets / cIerror_decay)) > cIerrors) { /* Try shrinking the packet size. */ if (iIrequest_packsize > 400) { char absync[CHDRLEN + 3 + CCKSUMLEN]; unsigned long icksum; iIrequest_packsize /= 2; absync[IHDR_INTRO] = IINTRO; absync[IHDR_LOCAL] = IHDRWIN_SET (0, 0); absync[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); iIlocal_ack = iIrecseq; absync[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3); absync[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3); absync[IHDR_CHECK] = IHDRCHECK_VAL (absync); absync[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff; absync[CHDRLEN + 1] = iIrequest_packsize & 0xff; absync[CHDRLEN + 2] = iIrequest_winsize; icksum = icrc (absync + CHDRLEN, 3, ICRCINIT); UCKSUM_SET (absync + CHDRLEN + 3, icksum); cIerrors *= 2; DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "ficheck_errors: Sending SYNC packsize %d winsize %d", iIrequest_packsize, iIrequest_winsize); return (*pfIsend) (qdaemon->qconn, absync, CHDRLEN + 3 + CCKSUMLEN, TRUE); } ulog (LOG_ERROR, "Too many '%c' protocol errors", qdaemon->qproto->bname); return FALSE; } return TRUE; } /* Process data waiting in the receive buffer, passing to the fgot_data function. */ static boolean fiprocess_data (qdaemon, pfexit, pffound, pcneed) struct sdaemon *qdaemon; boolean *pfexit; boolean *pffound; size_t *pcneed; { boolean fbadhdr; if (pfexit != NULL) *pfexit = FALSE; if (pffound != NULL) *pffound = FALSE; fbadhdr = FALSE; while (iPrecstart != iPrecend) { char ab[CHDRLEN]; int cfirst, csecond; char *zfirst, *zsecond; int i; int iget; int ttype; int iseq; int csize; int iack; /* If we're closing the connection, ignore any data remaining in the input buffer. */ if (fIclosing) { if (pfexit != NULL) *pfexit = TRUE; if (pcneed != NULL) *pcneed = 0; return TRUE; } /* Look for the IINTRO character. */ if (abPrecbuf[iPrecstart] != IINTRO) { char *zintro; int cintro; cintro = iPrecend - iPrecstart; if (cintro < 0) cintro = CRECBUFLEN - iPrecstart; zintro = memchr (abPrecbuf + iPrecstart, IINTRO, (size_t) cintro); if (zintro == NULL) { iPrecstart = (iPrecstart + cintro) % CRECBUFLEN; continue; } /* We don't need % CRECBUFLEN here because zintro - (abPrecbuf + iPrecstart) < cintro <= CRECBUFLEN - iPrecstart. */ iPrecstart += zintro - (abPrecbuf + iPrecstart); } /* Get the header into ab. */ for (i = 0, iget = iPrecstart; i < CHDRLEN && iget != iPrecend; i++, iget = (iget + 1) % CRECBUFLEN) ab[i] = abPrecbuf[iget]; if (i < CHDRLEN) { if (pcneed != NULL) *pcneed = CHDRLEN - i; return TRUE; } if ((ab[IHDR_CHECK] & 0xff) != IHDRCHECK_VAL (ab) || (FHDRCON_GETCALLER (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]) ? qdaemon->fcaller : ! qdaemon->fcaller)) { /* We only report a single bad header message per call, to avoid generating many errors if we get many INTRO bytes in a row. */ if (! fbadhdr) { DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_data: Bad header"); ++cIbad_hdr; if (! ficheck_errors (qdaemon)) return FALSE; fbadhdr = TRUE; } iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } zfirst = zsecond = NULL; cfirst = csecond = 0; ttype = THDRCON_GETTYPE (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]); if (ttype == DATA || ttype == SPOS || ttype == CLOSE) iseq = IHDRWIN_GETSEQ (ab[IHDR_LOCAL]); else iseq = -1; csize = CHDRCON_GETBYTES (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]); if (iseq != -1) { /* Make sure this packet is in our receive window. The last packet we have acked is iIlocal_ack. */ if (iIrequest_winsize > 0 && CSEQDIFF (iseq, iIlocal_ack) > iIrequest_winsize) { DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_data: Out of order packet %d", iseq); ++cIbad_order; if (! ficheck_errors (qdaemon)) return FALSE; iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } } if (csize > 0) { int cinbuf; char abcksum[CCKSUMLEN]; unsigned long ickdata; cinbuf = iPrecend - iPrecstart; if (cinbuf < 0) cinbuf += CRECBUFLEN; if (cinbuf < CHDRLEN + csize + CCKSUMLEN) { if (pcneed != NULL) *pcneed = CHDRLEN + csize + CCKSUMLEN - cinbuf; return TRUE; } if (iPrecend > iPrecstart) { cfirst = csize; zfirst = abPrecbuf + iPrecstart + CHDRLEN; } else { cfirst = CRECBUFLEN - (iPrecstart + CHDRLEN); if (cfirst <= 0) { /* Here cfirst is non-positive, so subtracting from abPrecbuf will actually skip the appropriate number of bytes at the start of abPrecbuf. */ zfirst = abPrecbuf - cfirst; cfirst = csize; } else { if (cfirst >= csize) cfirst = csize; else { zsecond = abPrecbuf; csecond = csize - cfirst; } zfirst = abPrecbuf + iPrecstart + CHDRLEN; } } /* Get the checksum into abcksum. */ for (i = 0, iget = (iPrecstart + CHDRLEN + csize) % CRECBUFLEN; i < CCKSUMLEN; i++, iget = (iget + 1) % CRECBUFLEN) abcksum[i] = abPrecbuf[iget]; ickdata = icrc (zfirst, (size_t) cfirst, ICRCINIT); if (csecond > 0) ickdata = icrc (zsecond, (size_t) csecond, ickdata); if (ICKSUM_GET (abcksum) != ickdata) { DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_data: Bad checksum; data %lu, frame %lu", ickdata, ICKSUM_GET (abcksum)); ++cIbad_cksum; if (! ficheck_errors (qdaemon)) return FALSE; /* If this sequence number is in our receive window, send a NAK. iIrecseq is the last sequence number we have succesfully received. */ if (iseq != -1 && iseq != iIrecseq && (iIrequest_winsize <= 0 || CSEQDIFF (iseq, iIrecseq) <= iIrequest_winsize) && azIrecbuffers[iseq] == NULL) { if (! finak (qdaemon, iseq)) return FALSE; } iPrecstart = (iPrecstart + 1) % CRECBUFLEN; continue; } } /* Here we know that this is a valid packet, so we can adjust iPrecstart accordingly. */ if (csize == 0) iPrecstart = (iPrecstart + CHDRLEN) % CRECBUFLEN; else { iPrecstart = ((iPrecstart + CHDRLEN + csize + CCKSUMLEN) % CRECBUFLEN); ++cIreceived_packets; } /* Get the ack from the packet, if appropriate. iIsendseq is the next sequence number we are going to send, and iIremote_ack is the last sequence number acknowledged by the remote system. */ iack = IHDRWIN_GETSEQ (ab[IHDR_REMOTE]); if (iIremote_winsize > 0 && iack != iIsendseq && CSEQDIFF (iack, iIremote_ack) <= iIremote_winsize && CSEQDIFF (iIsendseq, iack) <= iIremote_winsize) { /* Call uwindow_acked each time packet 0 is acked. */ if (iack < iIremote_ack) uwindow_acked (qdaemon, FALSE); iIremote_ack = iack; } if (iseq != -1) { afInaked[iseq] = FALSE; /* If we haven't handled all previous packets, we must save off this packet and deal with it later. */ if (iseq != INEXTSEQ (iIrecseq)) { if (iseq == iIrecseq || (iIrequest_winsize > 0 && CSEQDIFF (iseq, iIrecseq) > iIrequest_winsize)) { DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_data: Ignoring out of order packet %d", iseq); continue; } else { DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_data: Saving unexpected packet %d", iseq); if (azIrecbuffers[iseq] == NULL) { azIrecbuffers[iseq] = zbufalc ((size_t) (CHDRLEN + csize)); memcpy (azIrecbuffers[iseq], ab, CHDRLEN); if (csize > 0) { memcpy (azIrecbuffers[iseq] + CHDRLEN, zfirst, (size_t) cfirst); if (csecond > 0) memcpy (azIrecbuffers[iseq] + CHDRLEN + cfirst, zsecond, (size_t) csecond); } } } /* Send NAK's for each packet between the last one we received and this one, avoiding any packets for which we've already sent NAK's or which we've already received. */ for (i = INEXTSEQ (iIrecseq); i != iseq; i = INEXTSEQ (i)) { if (! afInaked[i] && azIrecbuffers[i] == NULL) { if (! finak (qdaemon, i)) return FALSE; } } continue; } iIrecseq = iseq; } if (pffound != NULL) *pffound = TRUE; if (! fiprocess_packet (qdaemon, ab, zfirst, cfirst, zsecond, csecond, pfexit)) return FALSE; if (iseq != -1) { int inext; /* If we've already received the next packet(s), process them. */ inext = INEXTSEQ (iIrecseq); while (azIrecbuffers[inext] != NULL) { char *z; int c; z = azIrecbuffers[inext]; c = CHDRCON_GETBYTES (z[IHDR_CONTENTS1], z[IHDR_CONTENTS2]); iIrecseq = inext; if (! fiprocess_packet (qdaemon, z, z + CHDRLEN, c, (char *) NULL, 0, pfexit)) return FALSE; ubuffree (azIrecbuffers[inext]); azIrecbuffers[inext] = NULL; inext = INEXTSEQ (inext); } } /* If we have received half of our window size or more since the last ACK, send one now. Sending an ACK for half the window at a time should significantly cut the acknowledgement traffic when only one side is sending. We should normally not have to send an ACK if we have data to send, since each packet sent will ACK the most recently received packet. However, it can happen if we receive a burst of short packets, such as a set of command acknowledgements. */ if (iIrequest_winsize > 0 && CSEQDIFF (iIrecseq, iIlocal_ack) >= iIrequest_winsize / 2) { char aback[CHDRLEN]; aback[IHDR_INTRO] = IINTRO; aback[IHDR_LOCAL] = IHDRWIN_SET (0, 0); aback[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); iIlocal_ack = iIrecseq; aback[IHDR_CONTENTS1] = IHDRCON_SET1 (ACK, qdaemon->fcaller, 0); aback[IHDR_CONTENTS2] = IHDRCON_SET2 (ACK, qdaemon->fcaller, 0); aback[IHDR_CHECK] = IHDRCHECK_VAL (aback); DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_data: Sending ACK %d", iIrecseq); if (! (*pfIsend) (qdaemon->qconn, aback, CHDRLEN, TRUE)) return FALSE; } } if (pcneed != NULL) *pcneed = CHDRLEN; return TRUE; } /* Process a single packet. */ static boolean fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) struct sdaemon *qdaemon; const char *zhdr; const char *zfirst; int cfirst; const char *zsecond; int csecond; boolean *pfexit; { int ttype; ttype = THDRCON_GETTYPE (zhdr[IHDR_CONTENTS1], zhdr[IHDR_CONTENTS2]); switch (ttype) { case DATA: { int iseq; boolean fret; iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); DEBUG_MESSAGE2 (DEBUG_PROTO, "fiprocess_packet: Got DATA packet %d size %d", iseq, cfirst + csecond); fret = fgot_data (qdaemon, zfirst, (size_t) cfirst, zsecond, (size_t) csecond, IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]), IHDRWIN_GETCHAN (zhdr[IHDR_LOCAL]), iIrecpos, INEXTSEQ (iIremote_ack) == iIsendseq, pfexit); iIrecpos += cfirst + csecond; return fret; } case SYNC: { int ipack, iwin; /* We accept a SYNC packet to adjust the packet and window sizes at any time. */ if (cfirst + csecond < 3) { ulog (LOG_ERROR, "Bad SYNC packet"); return FALSE; } ipack = (zfirst[0] & 0xff) << 8; if (cfirst > 1) ipack |= zfirst[1] & 0xff; else ipack |= zsecond[0]; if (cfirst > 2) iwin = zfirst[2]; else iwin = zsecond[2 - cfirst]; DEBUG_MESSAGE2 (DEBUG_PROTO, "fiprocess_packet: Got SYNC packsize %d winsize %d", ipack, iwin); if (iIforced_remote_packsize == 0 && (iIalc_packsize == 0 || ipack <= iIalc_packsize)) iIremote_packsize = ipack; if (iIforced_remote_winsize == 0) iIremote_winsize = iwin; /* We increment a static variable to tell the initialization code that a SYNC was received, and we set *pfexit to TRUE to get out to the initialization code (this will do no harm if we are called from elsewhere). */ ++cIsyncs; *pfexit = TRUE; return TRUE; } case ACK: /* There is nothing to do here, since the ack was already handled in fiprocess_data. */ DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Got ACK %d", IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE])); return TRUE; case NAK: /* We must resend the requested packet. */ { int iseq; char *zsend; size_t clen; ++cIremote_rejects; if (! ficheck_errors (qdaemon)) return FALSE; iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); /* The timeout code will send a NAK for the packet the remote side wants. So we may see a NAK here for the packet we are about to send. */ if (iseq == iIsendseq || (iIremote_winsize > 0 && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize))) { DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_packet: Ignoring out of order NAK %d", iseq); return TRUE; } DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, "fiprocess_packet: Got NAK %d; resending packet", iseq); /* Update the received sequence number. */ zsend = azIsendbuffers[iseq] + CHDROFFSET; if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq) { int iremote; iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]); zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend); iIlocal_ack = iIrecseq; } ++cIresent_packets; clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1], zsend[IHDR_CONTENTS2]); return (*pfIsend) (qdaemon->qconn, zsend, CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), TRUE); } case SPOS: /* Set the file position. */ { char abpos[CCKSUMLEN]; const char *zpos; if (cfirst >= CCKSUMLEN) zpos = zfirst; else { memcpy (abpos, zfirst, (size_t) cfirst); memcpy (abpos + cfirst, zsecond, (size_t) (CCKSUMLEN - cfirst)); zpos = abpos; } iIrecpos = (long) ICKSUM_GET (zpos); DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Got SPOS %ld", iIrecpos); return TRUE; } case CLOSE: { boolean fexpected; fexpected = ! fLog_sighup || fIclosing; if (! fexpected) ulog (LOG_ERROR, "Received unexpected CLOSE packet"); else DEBUG_MESSAGE0 (DEBUG_PROTO, "fiprocess_packet: Got CLOSE packet"); fIclosing = TRUE; *pfexit = TRUE; return fexpected; } default: /* Just ignore unrecognized packet types, for future protocol enhancements. */ DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Got packet type %d", ttype); return TRUE; } /*NOTREACHED*/ } tive, so subtracting from abPrecbuf will actually skip the appropriate number of bytes at the start of abPrecbufuucp-1.04/protj.c1004440004150000170000004522005337263511010666 037777777777 1 0 /* 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.2 1992/10/22 02:59:38 ian Rel $"; #endif #include #include #include "uudefs.h" #include "conn.h" #include "trans.h" #include "system.h" #include "prot.h" /* The 'j' protocol. The 'j' protocol is a wrapper around the 'i' protocol, which avoids the use of certain characters, such as XON and XOFF. Each 'j' protocol packet begins with a '^' character, followed by a two byte encoded size giving the total number of bytes in the packet. The first byte is HIGH, the second byte is LOW, and the number of bytes is (HIGH - 32) * 64 + (LOW - 32), where 32 <= HIGH < 127 and 32 <= LOW < 96 (i.e., HIGH and LOW are printable ASCII characters). This is followed by a '=' character. The next two bytes are the number of data bytes in the packet, using the same encoding. This is followed by a '@' character, and then that number of data bytes. The remaining bytes in the packet are indices of bytes which must be transformed, followed by a trailing '~' character. The indices are encoded in the following overly complex format. Each byte index is two bytes long. The first byte in the index is INDEX-HIGH and the second is INDEX-LOW. If 32 <= INDEX-HIGH < 126, the byte index refers to the byte at position (INDEX-HIGH - 32) * 32 + INDEX-LOW % 32 in the actual data, where 32 <= INDEX-LOW < 127. If 32 <= INDEX-LOW < 64, then 128 must be added to the indexed byte. If 64 <= INDEX-LOW < 96, then the indexed byte must be exclusive or'red with 32. If 96 <= INDEX-LOW < 127, both operations must be performed. If INDEX-HIGH == 126, then the byte index refers to the byte at position (INDEX-LOW - 32) * 32 + 31, where 32 <= INDEX-LOW < 126. 128 must be added to the byte, and it must be exclusive or'red with 32. This unfortunately requires a special test (when encoding INDEX-LOW must be checked for 127; when decoding INDEX-HIGH must be checked for 126). It does, however, permit the byte indices field to consist exclusively of printable ASCII characters. The maximum value for a byte index is (125 - 32) * 32 + 31 == 3007, so the is the maximum number of data bytes permitted. Since it is convenient to have each 'j' protocol packet correspond to each 'i' protocol packet, we restrict the 'i' protocol accordingly. Note that this encoding method assumes that we can send all printable ASCII characters. */ /* The first byte of each packet. I just picked these values randomly, trying to get characters that were perhaps slightly less likely to appear in normal text. */ #define FIRST '\136' /* The fourth byte of each packet. */ #define FOURTH '\075' /* The seventh byte of each packet. */ #define SEVENTH '\100' /* The trailing byte of each packet. */ #define TRAILER '\176' /* The length of the header. */ #define CHDRLEN (7) /* Get a number of bytes encoded in a two byte length at the start of a packet. */ #define CGETLENGTH(b1, b2) (((b1) - 32) * 64 + ((b2) - 32)) /* Set the high and low bytes of a two byte length at the start of a packet. */ #define ISETLENGTH_FIRST(i) ((i) / 64 + 32) #define ISETLENGTH_SECOND(i) ((i) % 64 + 32) /* The maximum packet size we support, as determined by the byte indices. */ #define IMAXPACKSIZE ((125 - 32) * 32 + 31) /* Amount to offset the bytes in the byte index by. */ #define INDEX_OFFSET (32) /* Maximum value of INDEX-LOW, before offsetting. */ #define INDEX_MAX_LOW (32) /* Maximum value of INDEX-HIGH, before offsetting. */ #define INDEX_MAX_HIGH (94) /* The set of characters to avoid. */ static char *zJavoid; /* The number of characters to avoid. */ static size_t cJavoid; /* A buffer used when sending data. */ static char *zJbuf; /* The end of the undecoded data in abPrecbuf. */ static int iJrecend; /* Local functions. */ static boolean fjsend_data P((struct sconnection *qconn, const char *zsend, size_t csend, boolean fdoread)); static boolean fjreceive_data P((struct sconnection *qconn, size_t cneed, size_t *pcrec, int ctimeout, boolean freport)); static boolean fjprocess_data P((size_t *pcneed)); /* Start the protocol. We first send over the list of characters to avoid as an escape sequence, starting with FIRST and ending with TRAILER. There is no error checking done on this string. */ boolean fjstart (qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { size_t clen; char *zsend; int b; size_t cbuf, cgot; char *zbuf; int i; /* Send the characters we want to avoid to the other side. */ clen = strlen (zJavoid_parameter); zsend = zbufalc (clen + 3); zsend[0] = FIRST; memcpy (zsend + 1, zJavoid_parameter, clen); zsend[clen + 1] = TRAILER; zsend[clen + 2] = '\0'; if (! fsend_data (qdaemon->qconn, zsend, clen + 2, TRUE)) { ubuffree (zsend); return FALSE; } ubuffree (zsend); /* Read the characters the other side wants to avoid. */ while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE)) != FIRST) { if (b < 0) { if (b == -1) ulog (LOG_ERROR, "Timed out in 'j' protocol startup"); return FALSE; } } cbuf = 20; zbuf = zbufalc (cbuf); cgot = 0; while ((b = breceive_char (qdaemon->qconn, cIsync_timeout, TRUE)) != TRAILER) { if (b < 0) { ubuffree (zbuf); if (b == -1) ulog (LOG_ERROR, "Timed out in 'j' protocol startup"); return FALSE; } if (cgot + 1 >= cbuf) { char *znew; cbuf += 20; znew = zbufalc (cbuf); memcpy (znew, zbuf, cgot); ubuffree (zbuf); zbuf = znew; } zbuf[cgot] = b; ++cgot; } zbuf[cgot] = '\0'; /* Merge the local and remote avoid bytes into one list, translated into bytes. */ cgot = cescape (zbuf); clen = strlen (zJavoid_parameter); zJavoid = zbufalc (clen + cgot + 1); memcpy (zJavoid, zJavoid_parameter, clen + 1); cJavoid = cescape (zJavoid); for (i = 0; i < cgot; i++) { if (memchr (zJavoid, zbuf[i], cJavoid) == NULL) { zJavoid[cJavoid] = zbuf[i]; ++cJavoid; } } ubuffree (zbuf); /* We can't avoid ASCII printable characters, since the encoding method assumes that they can always be sent. If it ever turns out to be important, a different encoding method could be used, perhaps keyed by a different FIRST character. */ if (cJavoid == 0) { ulog (LOG_ERROR, "No characters to avoid in 'j' protocol"); return FALSE; } for (i = 0; i < cJavoid; i++) { if (zJavoid[i] >= 32 && zJavoid[i] <= 126) { ulog (LOG_ERROR, "'j' protocol can't avoid character '\\%03o'", zJavoid[i]); return FALSE; } } /* If we are avoiding XON and XOFF, use XON/XOFF handshaking. */ if (memchr (zJavoid, '\021', cJavoid) != NULL && memchr (zJavoid, '\023', cJavoid) != NULL) { if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, STRIPSETTING_EIGHTBITS, XONXOFF_ON)) return FALSE; } /* Let the port settle. */ usysdep_sleep (2); /* Allocate a buffer we use when sending data. We will probably never actually need one this big; if this code is ported to a computer with small amounts of memory, this should be changed to increase the buffer size as needed. */ zJbuf = zbufalc (CHDRLEN + IMAXPACKSIZE * 3 + 1); zJbuf[0] = FIRST; zJbuf[3] = FOURTH; zJbuf[6] = SEVENTH; /* iJrecend is the end of the undecoded data, and iPrecend is the end of the decoded data. At this point there is no decoded data, and we must initialize the variables accordingly. */ iJrecend = iPrecend; iPrecend = iPrecstart; /* Now do the 'i' protocol startup. */ return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fjsend_data, fjreceive_data); } /* Shut down the protocol. */ boolean fjshutdown (qdaemon) struct sdaemon *qdaemon; { boolean fret; fret = fishutdown (qdaemon); ubuffree (zJavoid); ubuffree (zJbuf); return fret; } /* Encode a packet of data and send it. This copies the data, which is a waste of time, but calling fsend_data three times (for the header, the body, and the trailer) would waste even more time. */ static boolean fjsend_data (qconn, zsend, csend, fdoread) struct sconnection *qconn; const char *zsend; size_t csend; boolean fdoread; { char *zput, *zindex; const char *zfrom, *zend; char bfirst, bsecond; int iprecendhold; boolean fret; zput = zJbuf + CHDRLEN; zindex = zput + csend; zfrom = zsend; zend = zsend + csend; /* Optimize for the common case of avoiding two characters. */ bfirst = zJavoid[0]; if (cJavoid <= 1) bsecond = bfirst; else bsecond = zJavoid[1]; while (zfrom < zend) { char b; boolean f128, f32; int i, ihigh, ilow; b = *zfrom++; if (b != bfirst && b != bsecond) { int ca; char *za; if (cJavoid <= 2) { *zput++ = b; continue; } ca = cJavoid - 2; za = zJavoid + 2; while (ca-- != 0) if (*za++ == b) break; if (ca < 0) { *zput++ = b; continue; } } if ((b & 0x80) == 0) f128 = FALSE; else { b &=~ 0x80; f128 = TRUE; } if (b >= 32 && b != 127) f32 = FALSE; else { b ^= 0x20; f32 = TRUE; } /* We must now put the byte index into the buffer. The byte index is encoded similarly to the length of the actual data, but the byte index also encodes the operations that must be performed on the byte. The first byte in the index is the most significant bits. If we only had to subtract 128 from the byte, we use the second byte directly. If we had to xor the byte with 32, we add 32 to the second byte index. If we had to perform both operations, we add 64 to the second byte index. However, if we had to perform both operations, and the second byte index was 31, then after adding 64 and offsetting by 32 we would come up with 127, which we are not permitted to use. Therefore, in this special case we set the first byte of the index to 126 and put the original first byte into the second byte position instead. This is why we could not permit the high byte of the length of the actual data to be 126. We can get away with the switch because both the value of the second byte index (31) and the operations to perform (both) are known. */ i = zput - (zJbuf + CHDRLEN); ihigh = i / INDEX_MAX_LOW; ilow = i % INDEX_MAX_LOW; if (f128 && ! f32) ; else if (f32 && ! f128) ilow += INDEX_MAX_LOW; else { /* Both operations had to be performed. */ if (ilow != INDEX_MAX_LOW - 1) ilow += 2 * INDEX_MAX_LOW; else { ilow = ihigh; ihigh = INDEX_MAX_HIGH; } } *zindex++ = ihigh + INDEX_OFFSET; *zindex++ = ilow + INDEX_OFFSET; *zput++ = b; } *zindex++ = TRAILER; /* Set the lengths into the buffer. zJbuf[0,3,6] were set when zJbuf was allocated, and are never changed thereafter. */ zJbuf[1] = ISETLENGTH_FIRST (zindex - zJbuf); zJbuf[2] = ISETLENGTH_SECOND (zindex - zJbuf); zJbuf[4] = ISETLENGTH_FIRST (csend); zJbuf[5] = ISETLENGTH_SECOND (csend); /* Send the data over the line. We must preserve iPrecend as discussed in fjreceive_data. */ iprecendhold = iPrecend; iPrecend = iJrecend; fret = fsend_data (qconn, zJbuf, (size_t) (zindex - zJbuf), fdoread); iJrecend = iPrecend; iPrecend = iprecendhold; /* Process any bytes that may have been placed in abPrecbuf. */ if (fret && iPrecend != iJrecend) { if (! fjprocess_data ((size_t *) NULL)) return FALSE; } return fret; } /* Receive and decode data. This is called by fiwait_for_packet. We need to be able to return decoded data between iPrecstart and iPrecend, while not losing any undecoded partial packets we may have read. We use iJrecend as a pointer to the end of the undecoded data, and set iPrecend for the decoded data. iPrecend points to the start of the undecoded data. */ static boolean fjreceive_data (qconn, cineed, pcrec, ctimeout, freport) struct sconnection *qconn; size_t cineed; size_t *pcrec; int ctimeout; boolean freport; { int iprecendstart; size_t cjneed; size_t crec; int cnew; iprecendstart = iPrecend; /* Figure out how many bytes we need to decode the next packet. */ if (! fjprocess_data (&cjneed)) return FALSE; /* As we long as we read some data but don't have enough to decode a packet, we try to read some more. We decrease the timeout each time so that we will not wait forever if the connection starts dribbling data. */ do { int iprecendhold; size_t cneed; if (cjneed > cineed) cneed = cjneed; else cneed = cineed; /* We are setting iPrecend to the end of the decoded data for the 'i' protocol. When we do the actual read, we have to set it to the end of the undecoded data so that any undecoded data we have received is not overwritten. */ iprecendhold = iPrecend; iPrecend = iJrecend; if (! freceive_data (qconn, cneed, &crec, ctimeout, freport)) return FALSE; iJrecend = iPrecend; iPrecend = iprecendhold; /* Process any data we have received. This will set iPrecend to the end of the new decoded data. */ if (! fjprocess_data (&cjneed)) return FALSE; cnew = iPrecend - iprecendstart; if (cnew < 0) cnew += CRECBUFLEN; if (cnew > cineed) cineed = 0; else cineed -= cnew; --ctimeout; } while (cnew == 0 && crec > 0 && ctimeout > 0); DEBUG_MESSAGE1 (DEBUG_PROTO, "fjreceive_data: Got %d decoded bytes", cnew); *pcrec = cnew; return TRUE; } /* Decode the data in the buffer, optionally returning the number of bytes needed to complete the next packet. */ static boolean fjprocess_data (pcneed) size_t *pcneed; { int istart; istart = iPrecend; while (istart != iJrecend) { int i, iget; char ab[CHDRLEN]; int cpacket, cdata, chave; int iindex, iendindex; /* Find the next occurrence of FIRST. If we have to skip some garbage bytes to get to it, zero them out (so they don't confuse the 'i' protocol) and advance iPrecend. This will save us from looking at them again. */ if (abPrecbuf[istart] != FIRST) { int cintro; char *zintro; size_t cskipped; cintro = iJrecend - istart; if (cintro < 0) cintro = CRECBUFLEN - istart; zintro = memchr (abPrecbuf + istart, FIRST, (size_t) cintro); if (zintro == NULL) { bzero (abPrecbuf + istart, (size_t) cintro); istart = (istart + cintro) % CRECBUFLEN; iPrecend = istart; continue; } cskipped = zintro - (abPrecbuf + istart); bzero (abPrecbuf + istart, cskipped); istart += cskipped; iPrecend = istart; } for (i = 0, iget = istart; i < CHDRLEN && iget != iJrecend; ++i, iget = (iget + 1) % CRECBUFLEN) ab[i] = abPrecbuf[iget]; if (i < CHDRLEN) { if (pcneed != NULL) *pcneed = CHDRLEN - i; return TRUE; } cpacket = CGETLENGTH (ab[1], ab[2]); cdata = CGETLENGTH (ab[4], ab[5]); /* Make sure the header has the right magic characters, that the data is not larger than the packet, and that we have an even number of byte index characters. */ if (ab[3] != FOURTH || ab[6] != SEVENTH || cdata > cpacket - CHDRLEN - 1 || (cpacket - cdata - CHDRLEN - 1) % 2 == 1) { istart = (istart + 1) % CRECBUFLEN; continue; } chave = iJrecend - istart; if (chave < 0) chave += CRECBUFLEN; if (chave < cpacket) { if (pcneed != NULL) *pcneed = cpacket - chave; return TRUE; } /* Figure out where the byte indices start and end. */ iindex = (istart + CHDRLEN + cdata) % CRECBUFLEN; iendindex = (istart + cpacket - 1) % CRECBUFLEN; /* Make sure the magic trailer character is there. */ if (abPrecbuf[iendindex] != TRAILER) { istart = (istart + 1) % CRECBUFLEN; continue; } /* We have a packet to decode. The decoding process is simpler than the encoding process, since all we have to do is examine the byte indices. We zero out the byte indices as we go, so that they will not confuse the 'i' protocol. */ while (iindex != iendindex) { int ihigh, ilow; boolean f32, f128; int iset; ihigh = abPrecbuf[iindex] - INDEX_OFFSET; abPrecbuf[iindex] = 0; iindex = (iindex + 1) % CRECBUFLEN; ilow = abPrecbuf[iindex] - INDEX_OFFSET; abPrecbuf[iindex] = 0; iindex = (iindex + 1) % CRECBUFLEN; /* Now we must undo the encoding, by adding 128 and xoring with 32 as appropriate. Which to do is encoded in the low byte, except that if the high byte is the special value 126, then the low byte is actually the high byte and both operations are performed. */ f128 = TRUE; f32 = TRUE; if (ihigh == INDEX_MAX_HIGH) iset = ilow * INDEX_MAX_LOW + INDEX_MAX_LOW - 1; else { iset = ihigh * INDEX_MAX_LOW + ilow % INDEX_MAX_LOW; if (ilow < INDEX_MAX_LOW) f32 = FALSE; else if (ilow < 2 * INDEX_MAX_LOW) f128 = FALSE; } /* Now iset is the index from the start of the data to the byte to modify; adjust it to an index in abPrecbuf. */ iset = (istart + CHDRLEN + iset) % CRECBUFLEN; if (f128) abPrecbuf[iset] |= 0x80; if (f32) abPrecbuf[iset] ^= 0x20; } /* Zero out the header and trailer to avoid confusing the 'i' protocol, and update iPrecend to the end of decoded data. */ for (i = 0, iget = istart; i < CHDRLEN && iget != iJrecend; ++i, iget = (iget + 1) % CRECBUFLEN) abPrecbuf[iget] = 0; abPrecbuf[iendindex] = 0; iPrecend = (iendindex + 1) % CRECBUFLEN; istart = iPrecend; } if (pcneed != NULL) *pcneed = CHDRLEN + 1; return TRUE; } /* 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 uucp-1.04/prott.c1004440004150000170000002005205337263512010675 037777777777 1 0 /* 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.25 1992/09/08 04:22:05 ian Rel $"; #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; } 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 uucp-1.04/protz.c1004440004150000170000020537305337263512010716 037777777777 1 0 /* 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.7 1993/01/31 06:57:35 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "trans.h" #include "system.h" #include "prot.h" #define ZPROTOCOL_VERSION 1 /* * Control message characters ... */ #define ZPAD '*' /* Padding character begins frames */ #define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ #define ZBIN 'A' /* Binary frame indicator */ #define ZHEX 'B' /* HEX frame indicator */ /* * Frame types (see array "frametypes" in zm.c) ... * * Note that the numbers here have been reorganized, as we don't support * all of them (nor do we need to). * * WARNING: The init sequence assumes ZINIT < ZDATA < ZACK < ZINITEND. */ #define ZINIT 0 /* Init (contains protocol version, flags) */ #define ZDATA 1 /* Data packet(s) follow */ #define ZRPOS 2 /* Resume data trans at this position */ #define ZACK 3 /* ACK to above */ #define ZNAK 4 /* Last packet was garbled */ #define Zreserved 5 /* reserved (for future concerns) */ #define ZINITEND 6 /* end of init sequence */ #define ZFIN 7 /* Finish session */ /* * ZDLE sequences ... * * Note addition of ZCRCF: "end of message". */ #define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ #define ZCRCG 'i' /* CRC next, frame continues nonstop */ #define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ #define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ #define ZCRCF 'l' /* CRC next, ZACK expected, end of message */ #define ZRUB0 'm' /* Translate to rubout 0177 */ #define ZRUB1 'n' /* Translate to rubout 0377 */ /* * zdlread return values (internal) ... * Other values are ZM_ERROR, ZM_TIMEOUT, ZM_RCDO. */ #define GOTOR 0400 #define GOTCRCE (ZCRCE | GOTOR) /* ZDLE-ZCRCE received */ #define GOTCRCG (ZCRCG | GOTOR) /* ZDLE-ZCRCG received */ #define GOTCRCQ (ZCRCQ | GOTOR) /* ZDLE-ZCRCQ received */ #define GOTCRCW (ZCRCW | GOTOR) /* ZDLE-ZCRCW received */ #define GOTCRCF (ZCRCF | GOTOR) /* ZDLE-ZCRCF received */ /* * Byte positions within header array ... */ #define ZF0 3 /* First flags byte */ #define ZF1 2 #define ZF2 1 #define ZF3 0 #define ZP0 0 /* Low order 8 bits of position */ #define ZP1 1 #define ZP2 2 #define ZP3 3 /* High order 8 bits of position */ /* * Bit Masks for ZRQINIT flags byte ZF0 ... */ #define TX_ESCCTL 1 /* Tx will escape control chars */ /* * Possible errors when running ZMODEM ... */ #define ZM_ERROR (-1) /* crc error, etc. */ #define ZM_TIMEOUT (-2) #define ZM_RCDO (-3) /* Carrier Lost */ /* * ASCII characters ... */ #define LF 012 #define CR 015 #define XON 021 #define XOFF 023 #define XON_WAIT 10 /* seconds */ /* * Packet sizes ... * * FIXME: CPACKETSIZE is hardcoded in a lot of places. * It's not clear to me whether changing it's value would be a * "good thing" or not. But of course that doesn't excuse the hardcoding. */ #define CPACKETSIZE 1024 /* max packet size (data only) */ #define CFRAMELEN 12 /* header size */ #define CSUFFIXLEN 10 /* suffix at end of data packets */ #define CEXCHANGE_INIT_RETRIES 4 /* The header CRC value. */ #if ANSI_C #define IHDRCRC 0xDEBB20E3UL #else #define IHDRCRC ((unsigned long) 0xDEBB20E3L) #endif /* packet buffer size */ #define CPACKBUFSIZE (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/) /* * Data types ... */ typedef unsigned char achdrval_t[4]; typedef unsigned long hdrval_t; typedef unsigned long winpos_t; /* * Configurable parms ... * * FIXME: isn't used yet. It may not be needed. */ #define CTIMEOUT 10 #define CRETRIES 10 #define CSTARTUP_RETRIES 4 #define CGARBAGE 2400 #define CSEND_WINDOW 16384 #define FESCAPE_CONTROL FALSE static int cZtimeout = CTIMEOUT; /* (seconds) */ static int cZretries = CRETRIES; static int cZstartup_retries = CSTARTUP_RETRIES; static int cZmax_garbage = CGARBAGE; /* max garbage before header */ static int cZtx_window = CSEND_WINDOW; /* our transmission window */ static int cZrx_buf_len = 0; /* our reception buffer size */ static boolean fZesc_ctl = FESCAPE_CONTROL; /* escape control chars */ struct uuconf_cmdtab asZproto_params[] = { {"timeout", UUCONF_CMDTABTYPE_INT, (pointer) & cZtimeout, NULL}, {"retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZretries, NULL}, {"startup-retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZstartup_retries, NULL}, {"garbage", UUCONF_CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL}, {"send-window", UUCONF_CMDTABTYPE_INT, (pointer) & cZtx_window, NULL}, {"escape-control", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl, NULL}, {NULL, 0, NULL, NULL} }; /* * Variables for statistic gathering ... * * We use to record the number of "packets" * sent/received. Packets is in double quotes because some of them aren't full. */ static unsigned long cZheaders_sent; static unsigned long cZheaders_received; static unsigned long cZbytes_resent; static unsigned long cZtimeouts; static unsigned long cZerrors; /* * Data buffers ... */ static char *zZtx_buf; /* transmit buffer */ static char *zZtx_packet_buf; /* raw outgoing packet data */ static char *zZrx_packet_buf; /* raw incoming packet data */ /* * Transmitter state variables ... */ static unsigned cZblklen; /* data length in sent/received packets */ static unsigned cZtxwspac; /* spacing between ZCRCQ requests */ /*static unsigned cZblklen_override;*//* override value for */ static unsigned cZtxwcnt; /* counter used to space ack requests */ static unsigned cZrxwcnt; /* counter used to watch receiver's buf size */ static winpos_t wpZtxstart; /* when message started */ static winpos_t wpZtxpos; /* transmitter position */ static winpos_t wpZlastsync; /* last offset to which we got a ZRPOS */ static winpos_t wpZlrxpos; /* receiver's last reported offset */ static winpos_t wpZrxpos; /* receiver file position */ static int iZlast_tx_data_packet; /* type of last ZDATA packet (ZCRCx) */ static int iZjunk_count; /* amount of garbage characters received */ static int iZtleft; /* for dynamic packet resizing */ static int iZbeenhereb4; /* times we've been ZRPOS'd to same place */ /* * Receiver state variables ... */ static winpos_t wpZrxbytes; /* receiver byte count */ static int iZlast_rx_data_packet; /* last successfully received ZCRCx packet */ /* * Misc. globals ... */ static char xon = XON; #ifdef DJE_TESTING int uucptest = -1; int uucptest2; int uucptestseed; #endif /* * Kludge!!! * See fzfinish_tx(). Basically the next two globals are used to record the * fact that we got a ZDATA, but aren't quite ready to process it. */ static int iZpkt_rcvd_kludge; /* -1 if not valid */ static hdrval_t hvZpkt_hdrval_kludge; /* * Packet types ... */ static const char *azZframe_types[] = { "Carrier Lost", /* -3 */ "Timeout", /* -2 */ "Error", /* -1 */ #define FTOFFSET 3 "ZINIT", "ZDATA", "ZRPOS", "ZACK", "ZNAK", "Zreserved", "ZINITEND", "ZFIN", "UNKNOWN!!!" }; #define FTNUMBER (sizeof(azZframe_types) / sizeof(char *)) #ifndef min #define min(a, b) ((a) < (b) ? (a) : (b)) #endif #define ZZHEADER_NAME(itype) \ azZframe_types[min((itype) + FTOFFSET, FTNUMBER - 1)] /* * Local functions ... */ static boolean fzsend_data P((struct sdaemon *qdaemon, char *zdata, size_t cdata, boolean fendofmessage)); static boolean fzprocess P((struct sdaemon *qdaemon)); static boolean fzstart_proto P((struct sdaemon *qdaemon)); static int izexchange_init P((struct sdaemon *qdaemon, int send_type, achdrval_t send_val, achdrval_t recv_val)); static boolean fzshutdown_proto P((struct sdaemon *qdaemon)); static boolean fzstart_tx P((void)); static boolean fzfinish_tx P((struct sdaemon *qdaemon, long *plredo)); static boolean fzstart_rx P((void)); static boolean fzfinish_rx P((struct sdaemon *qdaemon)); static boolean fzsend_hdr P((struct sdaemon *qdaemon, int ipkttype, int ihdrtype, hdrval_t hdrval, boolean fcheckreceive)); static boolean fzsend_data_packet P((struct sdaemon *qdaemon, char *zdata, size_t cdata, int frameend, boolean fcheckreceive)); static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype, hdrval_t hdrval)); static int czbuild_data_packet P((char *zresult, const char *zdata, size_t cdata, int frameend)); /* * The rest of the functions do not follow Ian's naming style. I have left * the names the same as the original zm source. Over time, they may change. */ static int izrecv_hdr P((struct sdaemon *qdaemon, achdrval_t hdr)); static int zrbhdr32 P((struct sdaemon *qdaemon, achdrval_t hdr)); static int zrhhdr P((struct sdaemon *qdaemon, achdrval_t hdr)); static int zrdat32 P((struct sdaemon *qdaemon, char *buf, int length, int *iprxcount)); static int getinsync P((struct sdaemon *qdaemon, boolean flag)); static char *zputhex P((char *p, int ch)); static char *zputchar P((char *p, int ch)); static int zgethex P((struct sdaemon *qdaemon)); static int zdlread P((struct sdaemon *qdaemon)); static int noxrd7 P((struct sdaemon *qdaemon)); static int realreadchar P((struct sdaemon *qdaemon, int timeout)); static boolean fzreceive_ready P((void)); static void stohdr P((hdrval_t pos, achdrval_t hdr)); static hdrval_t rclhdr P((achdrval_t hdr)); static hdrval_t hvzencode_data_hdr P((winpos_t cbytes)); static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes)); static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos, winpos_t lrxpos, winpos_t txpos)); /* * This macro replaces readchar() because it achieves a noticable speed up. The * readchar() function has been renamed realreadchar(). Thanks to Ian for * running this stuff through a profiler to find this out. Ian suggests further * speed ups may be obtained by doing a similar thing in zrdat32(). */ /* Assign the next character to b. */ #define READCHAR(qdaemon, b, i) \ (iPrecstart != iPrecend \ ? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \ iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \ : ((b) = realreadchar ((qdaemon), (i)))) /************************************************************************/ /* * Start the protocol ... */ boolean fzstart(qdaemon, pzlog) struct sdaemon *qdaemon; char **pzlog; { *pzlog = zbufalc (sizeof "protocol 'a' starting: , , , , , " + 100); sprintf (*pzlog, "protocol 'a' starting: %d, %d, %d, %d, %d, %d", cZtimeout, cZretries, cZstartup_retries, cZmax_garbage, cZtx_window, fZesc_ctl); if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) return FALSE; /* * For now, we place tight restrictions on the size of the transmit * window. This might be relaxed in the future. If it is relaxed, * some of these tests will stay, some will go. That is why it is * coded like it is. */ if (cZtx_window % 1024 != 0 || cZtx_window < 4096 || cZtx_window > 65536 || 65536 % cZtx_window != 0 ) { ulog (LOG_ERROR, "fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536"); return FALSE; } zZtx_buf = (char *) xmalloc (CPACKETSIZE); zZtx_packet_buf = (char *) xmalloc (CPACKBUFSIZE); zZrx_packet_buf = (char *) xmalloc (CPACKBUFSIZE); iZlast_tx_data_packet = -1; iZlast_rx_data_packet = -1; wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0; cZtxwspac = cZtx_window / 4; cZheaders_sent = cZheaders_received = cZbytes_resent = 0; cZtimeouts = cZerrors = 0; iZpkt_rcvd_kludge = -1; #if 0 /* * We ensure is at least 4k, so the following is * unnecessary. It can be put back in later if needed. */ if (cZblklen_override > cZtxwspac || (!cZblklen_override && cZtxwspac < 1024)) cZblklen_override = cZtxwspac; #endif #ifdef DJE_TESTING { extern int uucptest,uucptest2,uucptestseed; FILE *f; if (uucptest == -1) { f = fopen ("/usr/local/src/bin/uucp/uucptest", "r"); if (f != NULL) { fscanf (f, "%d %d %d", &uucptestseed, &uucptest, &uucptest2); fclose (f); } srand (uucptestseed); } } #endif /* * Fire up the protocol (exchange init messages) ... */ if (!fzstart_proto (qdaemon)) return FALSE; return TRUE; } /* * Stop the protocol ... */ boolean fzshutdown(qdaemon) struct sdaemon *qdaemon; { (void) fzshutdown_proto (qdaemon); xfree ((pointer) zZtx_buf); xfree ((pointer) zZtx_packet_buf); xfree ((pointer) zZrx_packet_buf); zZtx_buf = NULL; zZtx_packet_buf = NULL; zZrx_packet_buf = NULL; /* * Print some informative statistics ... * * I use the word "messages" here instead of "headers" because the * latter is jargonese. */ ulog (LOG_NORMAL, "Protocol 'a' messages: sent %lu, received %lu", cZheaders_sent, cZheaders_received); ulog (LOG_NORMAL, "Protocol 'a' packets: sent %lu, received %lu", wpZtxpos / 1024, wpZrxbytes / 1024); if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0) ulog (LOG_NORMAL, "Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu", cZbytes_resent, cZtimeouts, cZerrors); /* * Reset all the parameters to their default values, so that the * protocol parameters used for this connection do not affect the * next one. */ cZtimeout = CTIMEOUT; cZretries = CRETRIES; cZstartup_retries = CSTARTUP_RETRIES; cZmax_garbage = CGARBAGE; cZtx_window = CSEND_WINDOW; fZesc_ctl = FESCAPE_CONTROL; cZheaders_sent = cZheaders_received = cZbytes_resent = 0; cZtimeouts = cZerrors = 0; return TRUE; } /* * Send a command string ... * We send everything up to and including the null byte. * * We assume the command will fit in the outgoing data buffer. * FIXME: A valid assumption? */ /*ARGSUSED*/ boolean fzsendcmd(qdaemon, z, ilocal, iremote) struct sdaemon *qdaemon; const char *z; int ilocal; int iremote; { size_t n,clen; long lredo; char *zbuf; clen = strlen (z) + 1; DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsendcmd: sending command %s", z); if (!fzstart_tx ()) /* must be called before zzgetspace() */ return FALSE; if ((zbuf = zzgetspace (qdaemon, &n)) == NULL) return FALSE; #if DEBUG > 0 if (clen > n) ulog (LOG_FATAL, "fzsendcmd: clen > n"); #endif strcpy (zbuf, z); /* * Send it out ... */ do { if (!fzsend_data (qdaemon, zbuf, clen, TRUE)) return FALSE; if (!fzfinish_tx (qdaemon, &lredo)) return FALSE; } while (lredo >= 0); return fzprocess (qdaemon); } /* * Allocate a packet to send out ... * * Note that 'z' has dynamic packet resizing and that will range * from 32 to 1024, in multiples of 2. */ /*ARGSUSED*/ char * zzgetspace(qdaemon, pclen) struct sdaemon *qdaemon; size_t *pclen; { *pclen = cZblklen; return zZtx_buf; } /* * Send a block of data ... * * If (cdata == 0) then the end of the file has been reached. */ /*ARGSUSED*/ boolean fzsenddata(qdaemon, zdata, cdata, ilocal, iremote, ipos) struct sdaemon *qdaemon; char *zdata; size_t cdata; int ilocal; int iremote; long ipos; { DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsenddata: %d bytes", cdata); if (! fzsend_data (qdaemon, zdata, cdata, cdata == 0)) return FALSE; return fzprocess (qdaemon); } /* * Send a block of data (command or file) ... */ /* This should buffer the data internally. Until it does, it needs to be able to reset the file position when it is called. This is really ugly. */ extern struct stransfer *qTsend; static boolean fzsend_data(qdaemon, zdata, cdata, fendofmessage) struct sdaemon *qdaemon; char *zdata; size_t cdata; boolean fendofmessage; { size_t n; if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) { cZtxwcnt = cZrxwcnt = 0; iZjunk_count = 0; if (!fzsend_hdr (qdaemon, ZBIN, ZDATA, hvzencode_data_hdr (wpZtxpos), TRUE)) return FALSE; } n = cdata; if (fendofmessage) iZlast_tx_data_packet = ZCRCF; else if (iZjunk_count > 3) iZlast_tx_data_packet = ZCRCW; else if (wpZtxpos == wpZlastsync) iZlast_tx_data_packet = ZCRCW; else if (cZrx_buf_len && (cZrxwcnt += n) >= cZrx_buf_len) iZlast_tx_data_packet = ZCRCW; else if ((cZtxwcnt += n) >= cZtxwspac) { iZlast_tx_data_packet = ZCRCQ; cZtxwcnt = 0; } else iZlast_tx_data_packet = ZCRCG; if (++iZtleft > 3) { iZtleft = 0; if (cZblklen < 1024) cZblklen *= 2; #if 0 /* is currently unnecessary */ if (cZblklen_override && cZblklen > cZblklen_override) cZblklen = cZblklen_override; #endif if (cZblklen > 1024) cZblklen = 1024; if (cZrx_buf_len && cZblklen > cZrx_buf_len) cZblklen = cZrx_buf_len; } #if DEBUG > 1 if (FDEBUGGING(DEBUG_PROTO)) { const char *type; switch (iZlast_tx_data_packet) { case ZCRCW: type = "ZCRCW"; break; case ZCRCG: type = "ZCRCG"; break; case ZCRCQ: type = "ZCRCQ"; break; case ZCRCE: type = "ZCRCE"; break; case ZCRCF: type = "ZCRCF"; break; default : type = "UNKNOWN!!!"; break; } DEBUG_MESSAGE3 (DEBUG_PROTO, "fzsend_data: %s, pos 0x%lx, %d bytes", type, wpZtxpos, n); } #endif if (!fzsend_data_packet (qdaemon, zdata, n, iZlast_tx_data_packet, TRUE)) return FALSE; wpZtxpos += n; if (iZlast_tx_data_packet == ZCRCW) { /* * FIXME: Ideally this would be done in fzprocess. However, it * is only called if there is data pending which there * may not be yet. I could have patched fploop() a bit but * for now, I've done it like this. */ switch (getinsync (qdaemon, FALSE)) { case ZACK: break; case ZRPOS: if (qTsend == NULL || ! ffileisopen (qTsend->e)) { ulog (LOG_ERROR, "Can't reset non-file"); return FALSE; } iZlast_tx_data_packet = -1; /* trigger ZDATA */ DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsend_data: Seeking to %ld", (long) (wpZrxpos - wpZtxstart)); if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); return FALSE; } break; default: return FALSE; } return TRUE; } /* * If we've reached the maximum transmit window size, let the * receiver catch up ... * * I use (cZtx_window - 2048) to play it safe. */ while (wpZtxpos - wpZlrxpos >= cZtx_window - 2048) { if (iZlast_tx_data_packet != ZCRCQ) { if (!fzsend_data_packet (qdaemon, zdata, (size_t) 0, iZlast_tx_data_packet = ZCRCQ, TRUE)) return FALSE; } /* * FIXME: I'd rather not call ffileseek() in this file. When we * start buffering the outgoing data, the following * ffileseek() will disappear. */ switch (getinsync (qdaemon, TRUE)) { case ZACK: break; case ZRPOS: if (qTsend == NULL || ! ffileisopen (qTsend->e)) { ulog (LOG_ERROR, "Can't reset non-file"); return FALSE; } iZlast_tx_data_packet = -1; /* trigger ZDATA */ DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsend_data: Seeking to %ld", (long) (wpZrxpos - wpZtxstart)); if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); return FALSE; } break; default: return FALSE; } } return TRUE; } /* * Process existing data ... */ static boolean fzprocess(qdaemon) struct sdaemon *qdaemon; { int c,ch; while (fzreceive_ready ()) { READCHAR (qdaemon, ch, 1); switch (ch) { case ZPAD: /* see if we're detecting ZRPOS packets quickly */ DEBUG_MESSAGE0 (DEBUG_PROTO, "fzprocess: possible ZRPOS packet"); /* We just ate the ZPAD char that getinsync expects, so put it back. */ iPrecstart = ((iPrecstart + CRECBUFLEN - 1) % CRECBUFLEN); c = getinsync (qdaemon, TRUE); if (c == ZACK) break; /* FIXME: sz does a TCFLSH here */ #if 0 /* FIXME: Not sure if this is needed, or where to put it. */ /* ZCRCE - dinna wanna starta ping-pong game */ if (!fzsend_data_packet (qdaemon, zZtx_packet_buf, 0, ZCRCE, TRUE)) return FALSE; #endif if (c == ZRPOS) { if (qTsend == NULL || ! ffileisopen (qTsend->e)) { ulog (LOG_ERROR, "Attempt to back up non-file"); return FALSE; } if (! ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); return FALSE; } iZlast_tx_data_packet = -1; /* trigger ZDATA */ break; /* not returning is intentional */ } return FALSE; case XOFF: case XOFF | 0200: READCHAR (qdaemon, ch, XON_WAIT); break; case CR: break; default: iZjunk_count++; break; } } return TRUE; } /* * Wait for data to come in. * * This continues processing until a complete file or command has been * received. */ boolean fzwait(qdaemon) struct sdaemon *qdaemon; { int c,cerr,rxcount; boolean fexit; achdrval_t rx_hdr; if (!fzstart_rx ()) return FALSE; cerr = cZretries; goto nxthdr; for (;;) { if (!fzsend_hdr (qdaemon, ZHEX, ZRPOS, hvzencode_data_hdr (wpZrxbytes), FALSE)) return FALSE; nxthdr: c = izrecv_hdr (qdaemon, rx_hdr); switch (c) { case ZM_TIMEOUT: case ZNAK: if (--cerr < 0) { ulog (LOG_ERROR, "fzwait: retries exhausted"); return FALSE; } continue; case ZM_ERROR: if (--cerr < 0) { ulog (LOG_ERROR, "fzwait: retries exhausted"); return FALSE; } /*fport_break ();*/ continue; case ZM_RCDO: case ZFIN: return FALSE; case ZRPOS: case ZACK: goto nxthdr; /* ignore, partner is out of sync */ case ZDATA: { winpos_t rx_bytes; zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); DEBUG_MESSAGE2 (DEBUG_PROTO, "fzwait: bytes(us,them) 0x%lx,0x%lx", wpZrxbytes, rx_bytes); if (rx_bytes != wpZrxbytes) { if (--cerr < 0) { ulog (LOG_ERROR, "fzwait: retries exhausted"); return FALSE; } (void) zrdat32 (qdaemon, zZrx_packet_buf, 1024, &rxcount); /*fport_break ();*/ /* * FIXME: Seems to me we should ignore this one * and go for a timeout, the theory being * that the appropriate ZRPOS has already * been sent. We're obviously out of sync. * /dje 92Mar10 */ continue; /* goto nxthdr? */ } moredata: /* * Do not call fgot_data() with (rxcount == 0) if it's * not ZCRCF. fgot_data() will erroneously think this * is the end of the message. */ c = zrdat32 (qdaemon, zZrx_packet_buf, 1024, &rxcount); #if DEBUG > 1 if (FDEBUGGING(DEBUG_PROTO)) { const char *msg; if (c < 0) { msg = ZZHEADER_NAME(c); } else { switch (c) { case GOTCRCW: msg = "ZCRCW"; break; case GOTCRCG: msg = "ZCRCG"; break; case GOTCRCQ: msg = "ZCRCQ"; break; case GOTCRCE: msg = "ZCRCE"; break; case GOTCRCF: msg = "ZCRCF"; break; default : msg = NULL; break; } } if (msg != NULL) DEBUG_MESSAGE2 (DEBUG_PROTO, "fzwait: zrdat32: %s, %d bytes", msg, rxcount); else DEBUG_MESSAGE2 (DEBUG_PROTO, "fzwait: zrdat32: %d, %d bytes", c, rxcount); } #endif switch (c) { case ZM_ERROR: /* CRC error */ cZerrors++; if (--cerr < 0) { ulog (LOG_ERROR, "fzwait: retries exhausted"); return FALSE; } /*fport_break ();*/ continue; case ZM_TIMEOUT: cZtimeouts++; if (--cerr < 0) { ulog (LOG_ERROR, "fzwait: retries exhausted"); return FALSE; } continue; case ZM_RCDO: return FALSE; case GOTCRCW: iZlast_rx_data_packet = ZCRCW; cerr = cZretries; if (rxcount != 0 && !fgot_data (qdaemon, zZrx_packet_buf, (size_t) rxcount, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, &fexit)) return FALSE; wpZrxbytes += rxcount; if (!fzsend_hdr (qdaemon, ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE)) return FALSE; if (! fsend_data (qdaemon->qconn, &xon, (size_t) 1, FALSE)) return FALSE; goto nxthdr; case GOTCRCQ: iZlast_rx_data_packet = ZCRCQ; cerr = cZretries; if (rxcount != 0 && !fgot_data (qdaemon, zZrx_packet_buf, (size_t) rxcount, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, &fexit)) return FALSE; wpZrxbytes += rxcount; if (!fzsend_hdr (qdaemon, ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE)) return FALSE; goto moredata; case GOTCRCG: iZlast_rx_data_packet = ZCRCG; cerr = cZretries; if (rxcount != 0 && !fgot_data (qdaemon, zZrx_packet_buf, (size_t) rxcount, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, &fexit)) return FALSE; wpZrxbytes += rxcount; goto moredata; case GOTCRCE: iZlast_rx_data_packet = ZCRCE; cerr = cZretries; if (rxcount != 0 && !fgot_data (qdaemon, zZrx_packet_buf, (size_t) rxcount, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, &fexit)) return FALSE; wpZrxbytes += rxcount; goto nxthdr; case GOTCRCF: iZlast_rx_data_packet = ZCRCF; /* * fzfinish_rx() must be called before * fgot_data() because fgot_data() will send * out a UUCP-command but the sender won't be * ready for it until it receives our final * ZACK. */ cerr = cZretries; wpZrxbytes += rxcount; if (!fzfinish_rx (qdaemon)) return FALSE; if (!fgot_data (qdaemon, zZrx_packet_buf, (size_t) rxcount, (const char *) NULL, (size_t) 0, -1, -1, (long) -1, TRUE, &fexit)) return FALSE; /* * FIXME: Examine ? * Or maybe ensure it's TRUE? */ return TRUE; } return FALSE; } default: ulog (LOG_FATAL, "fzwait: received header %s", ZZHEADER_NAME(c)); return FALSE; } } return TRUE; } /* * File level routine. Called when initiating/terminating file transfers. * * When starting to send a file: (TRUE, TRUE, cbytes) * When starting to receive a file: (TRUE, FALSE, -1) * When send EOF, check resend: (FALSE, TRUE, -1) * When receive EOF, check re-receive: (FALSE, FALSE, -1) */ boolean fzfile(qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) struct sdaemon *qdaemon; struct stransfer *qtrans; boolean fstart; boolean fsend; long cbytes; boolean *pfhandled; { long iredo; *pfhandled = FALSE; DEBUG_MESSAGE2 (DEBUG_PROTO, "fzfile: fstart=%d, fsend=%d", fstart, fsend); if (fsend) { if (fstart) return fzstart_tx (); if (! fzfinish_tx (qdaemon, &iredo)) return FALSE; if (iredo >= 0) { if (! ffileisopen (qtrans->e)) { ulog (LOG_ERROR, "Attempt to back up non-file"); return FALSE; } if (! ffileseek (qtrans->e, iredo)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); return FALSE; } *pfhandled = TRUE; qtrans->fsendfile = TRUE; return fqueue_send (qdaemon, qtrans); } } return TRUE; } /****************************************************************************/ #if 0 /* not used, we only use 32 bit crc's */ /* * crctab calculated by Mark G. Mendel, Network Systems Corporation */ static unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; #endif /* crctab */ /* * Copyright (C) 1986 Gary S. Brown. You may use this program, or * code or tables extracted from it, as desired without restriction. */ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ static unsigned long crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; /* * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. * NOTE: First argument must be in range 0 to 255. * Second argument is referenced twice. * * Programmers may incorporate any or all code into their programs, * giving proper credit within the source. Publication of the * source routines is permitted so long as proper credit is given * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, * Omen Technology. */ #define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) #define UPDC32(b, crc) \ (crc_32_tab[((unsigned)(crc) ^ (unsigned)(b)) & 0xff] \ ^ (((crc) >> 8) & 0x00ffffffL)) /****************************************************************************/ /* * This section contains the guts of the Zmodem protocol. The intention * is to leave as much of it alone as possible at the start. Overtime it * will be cleaned up (EG: I'd like to clean up the naming of the globals). * Also, Zmodem has a different coding style. Over time this will be converted * to the Taylor UUCP coding style. */ /* * Start the protocol (exchange init packets) ... * * UUCP can transfer files in both directions in one session. Therefore the * init sequence is a little different. * * 1) ZINIT packets are exchanged * - contains protocol version and protocol flags * 2) ZDATA packets are exchanged * - is intended to contain various numeric and string information * 3) ZACK packets are exchanged * 4) ZINITEND packets are exchanged */ static boolean fzstart_proto(qdaemon) struct sdaemon *qdaemon; { int i; achdrval_t tx_hdr,rx_hdr; for (i = 0; i < cZstartup_retries; i++) { stohdr (0L, tx_hdr); tx_hdr[ZF0] = ZPROTOCOL_VERSION; if (fZesc_ctl) tx_hdr[ZF1] |= TX_ESCCTL; switch (izexchange_init (qdaemon, ZINIT, tx_hdr, rx_hdr)) { case -1: return FALSE; case 0: continue; case 1: break; } #if 0 /* can't work, but kept for documentation */ if (rx_hdr[ZF0] == 0) { ulog (LOG_ERROR, "Old protocol version, init failed"); return FALSE; } #endif fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0; stohdr (0L, tx_hdr); switch (izexchange_init (qdaemon, ZDATA, tx_hdr, rx_hdr)) { case -1: return FALSE; case 0: continue; case 1: break; } stohdr (0L, tx_hdr); switch (izexchange_init (qdaemon, ZACK, tx_hdr, rx_hdr)) { case -1: return FALSE; case 0: continue; case 1: break; } stohdr (0L, tx_hdr); switch (izexchange_init (qdaemon, ZINITEND, tx_hdr, rx_hdr)) { case -1: return FALSE; case 0: continue; case 1: break; } DEBUG_MESSAGE0 (DEBUG_PROTO, "fzstart_proto: Protocol started"); return TRUE; /* FIXME: see protg.c regarding sequencing here. */ } ulog (LOG_ERROR, "Protocol init failed"); return FALSE; } /* * Exchange init messages. This is based on 'g'. * See the comments concerning fgexchange_init() in protg.c. * * We return 1 for success, 0 for restart, -1 for comm failure (terminate). */ static int izexchange_init(qdaemon, send_type, send_val, recv_val) struct sdaemon *qdaemon; int send_type; achdrval_t send_val; achdrval_t recv_val; { int i,recv_type,count; for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) { if (!fzsend_hdr (qdaemon, send_type == ZDATA ? ZBIN : ZHEX, send_type, rclhdr (send_val), FALSE)) return -1; /* * The ZDATA packet is intended to contain the string * (eventually, if it's ever usable) and allow for anything * else that will need to be thrown in. */ if (send_type == ZDATA) { count = czbuild_data_packet (zZtx_packet_buf, "", (size_t) 1, ZCRCF); if (!fsend_data (qdaemon->qconn, zZtx_packet_buf, (size_t) count, FALSE)) return -1; } recv_type = izrecv_hdr (qdaemon, recv_val); switch (recv_type) { case ZM_TIMEOUT: case ZM_ERROR: continue; case ZM_RCDO: case ZFIN: return -1; case ZINIT: case ZACK: case ZINITEND: break; case ZDATA: if (zrdat32 (qdaemon, zZrx_packet_buf, 1024, &count) == GOTCRCF) break; continue; default: continue; } if (recv_type == send_type) return 1; /* * If the other side is farther along than we are, we have lost * a packet. Fall immediately back to ZINIT (but don't fail * if we are already doing ZINIT, since that would count * against cStart_retries more than it should). * * FIXME: The ">" test is "<" in protg.c. Check who's right. */ if (recv_type > send_type && send_type != ZINIT) return 0; /* * If we are sending ZINITEND and we receive an ZINIT, the * other side has falled back (we know this because we have * seen a ZINIT from them). Fall back ourselves to start * the whole handshake over again. */ if (recv_type == ZINIT && send_type == ZINITEND) return 0; } return 0; } /* * Shut down the protocol ... */ static boolean fzshutdown_proto(qdaemon) struct sdaemon *qdaemon; { (void) fzsend_hdr (qdaemon, ZHEX, ZFIN, 0L, FALSE); return TRUE; } /* * Reset the transmitter side for sending a new message ... */ static boolean fzstart_tx() { iZlast_tx_data_packet = -1; /* * is set to -1L to suppress ZCRCW request otherwise * triggered by (wpZlastsync == wpZtxpos). */ cZblklen = 1024; wpZlastsync = -1L; iZbeenhereb4 = 0; iZtleft = 0; iZjunk_count = 0; wpZtxpos = (wpZtxpos + 1024L) & ~1023L; /* next packet boundary */ wpZlrxpos = wpZrxpos = wpZtxpos; wpZtxstart = wpZtxpos; /* so we can compute the "file offset" */ return TRUE; } /* * Finish the sending of a message ... * * Basically, we wait for some indication that the receiver received our last * message. If the receiver tells us to restart from some point, we set * *plredo to that point. * * FIXME: This function is a major kludge at the moment. It is taken from * getinsync(). It is necessary because I don't yet buffer outgoing data. * It will go away when we do (buffer outgoing data). */ static boolean fzfinish_tx(qdaemon, plredo) struct sdaemon *qdaemon; long *plredo; { int c,cerr,ctimeouts; achdrval_t rx_hdr; winpos_t rx_bytes; *plredo = -1; cerr = cZretries; ctimeouts = 0; DEBUG_MESSAGE4 (DEBUG_PROTO, "fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx", wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes); for (;;) { c = izrecv_hdr (qdaemon, rx_hdr); switch (c) { case ZRPOS: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos); /* * If the receiver sends a ZRPOS for the 1k block after * the one we're currently at, we lost the final ZACK. * We cheat and ignore this ZRPOS. Remember: the theory * is that this entire function will go away when we * begin buffering the outgoing data. Of course, one * can reword the protocol definition and say this * isn't cheating at all. */ if (((wpZtxpos + 1024) & ~1023) == wpZrxpos) return TRUE; cZbytes_resent += wpZtxpos - wpZrxpos; wpZlrxpos = wpZtxpos = wpZrxpos; if (wpZlastsync == wpZrxpos) { if (++iZbeenhereb4 > 4) if (cZblklen > 32) cZblklen /= 2; /* FIXME: shouldn't we reset iZbeenhereb4? */ } wpZlastsync = wpZrxpos; iZlast_tx_data_packet = ZCRCW; /* force a timeout */ *plredo = wpZrxpos - wpZtxstart; return TRUE; case ZACK: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos); wpZlrxpos = wpZrxpos; if (wpZtxpos == wpZrxpos) /* the ACK we want? */ return TRUE; break; case ZDATA: /* * We cheat here and take advantage of UUCP's current * half duplex nature. If we get a ZDATA starting on * the next 1k boundary, we lost the ZACK. We cheat and * tuck it away so that izrecv_hdr() can later detect * it. Remember: see above. */ zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) { iZpkt_rcvd_kludge = ZDATA; hvZpkt_hdrval_kludge = rclhdr (rx_hdr); return TRUE; } break; /* ignore, out of sync (old) */ case ZNAK: /* * We cheat here and take advantage of UUCP's current * half duplex nature. If we get a ZNAK starting on * the next 1k boundary, we lost the ZACK. We cheat and * throw the ZNAK away. Remember: see above. * * On the other hand, if (rx_bytes == wpZrxbytes) then * the other side is also in fzfinish_tx(). He must * have lost our ZACK, so we send him another. */ zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) return TRUE; if (rx_bytes == wpZrxbytes) { if (!fzsend_hdr (qdaemon, ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), TRUE)) return FALSE; } break; /* ignore, out of sync (old) */ case ZFIN: case ZM_RCDO: return FALSE; case ZM_TIMEOUT: if (--cerr < 0) { ulog (LOG_ERROR, "fzfinish_tx: retries exhausted"); return FALSE; } /* * Normally the sender doesn't send NAK's for timeouts. * We have to here because of the following scenario: * * - We send ZDATA/ZCRCF * - They send ZACK (corrupted) * - They send ZDATA/ZCRCF (corrupted) * * At this point, both sides are in fzfinish_tx(). * We only send ZNAK every second timeout to increase * our timeout delay vs. our partner. This tries to * avoid ZRPOS and ZNAK "passing in transit". */ if (++ctimeouts % 2 == 0) if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE)) return FALSE; break; case ZM_ERROR: default: if (--cerr < 0) { ulog (LOG_ERROR, "fzfinish_tx: retries exhausted"); return FALSE; } if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE)) return FALSE; break; } } } /* * Initialize the receiver ... */ static boolean fzstart_rx() { wpZrxbytes = (wpZrxbytes + 1024L) & ~1023L; /* next packet boundary */ return TRUE; } /* * Terminate the receiver ... * * Acknowledge the last packet received. */ static boolean fzfinish_rx(qdaemon) struct sdaemon *qdaemon; { DEBUG_MESSAGE0 (DEBUG_PROTO, "fzfinish_rx: message/file received"); return fzsend_hdr (qdaemon, ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), FALSE); } /* * Send a Zmodem header to our partner ... */ static boolean fzsend_hdr(qdaemon, ipkttype, ihdrtype, hdrval, fcheckreceive) struct sdaemon *qdaemon; int ipkttype; int ihdrtype; hdrval_t hdrval; boolean fcheckreceive; { int cpacketlen; DEBUG_MESSAGE2 (DEBUG_PROTO, "fzsend_hdr: %s, data = 0x%lx", ZZHEADER_NAME(ihdrtype), hdrval); cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype, ihdrtype, hdrval); #ifdef DJE_TESTING #if 0 if (ihdrtype == ZACK && rand () % 100 < uucptest2) { cZheaders_sent++; return TRUE; } #else if (ihdrtype == ZACK || ihdrtype == ZDATA) { boolean fresult; int old; extern int uucptest,uucptest2; old = uucptest; uucptest = uucptest2; cZheaders_sent++; fresult = fsend_data (qdaemon->qconn, zZtx_packet_buf, (size_t) cpacketlen, fcheckreceive); uucptest = old; return fresult; } #endif #endif cZheaders_sent++; return fsend_data (qdaemon->qconn, zZtx_packet_buf, (size_t) cpacketlen, fcheckreceive); } /* * Send a data packet to our partner ... * is one of ZCRCx. */ static boolean fzsend_data_packet(qdaemon, zdata, cdata, frameend, fcheckreceive) struct sdaemon *qdaemon; char *zdata; size_t cdata; int frameend; boolean fcheckreceive; { int cpacketlen; cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata, frameend); return fsend_data (qdaemon->qconn, zZtx_packet_buf, (size_t) cpacketlen, fcheckreceive); } /* * Build Zmodem headers ... * * Note that we use 32 bit CRC's for ZHEX headers. * * This function is a combination of zm fns: zsbhdr(), zsbh32(), and zshhdr(). */ static int czbuild_header(zresult, ipkttype, ihdrtype, hdrval) char *zresult; int ipkttype; int ihdrtype; hdrval_t hdrval; { char *p; int i; unsigned long crc; achdrval_t achdrval; p = zresult; switch (ipkttype) { case ZBIN: *p++ = ZPAD; *p++ = ZDLE; *p++ = ZBIN; p = zputchar (p, ihdrtype); crc = ICRCINIT; crc = UPDC32 (ihdrtype, crc); stohdr (hdrval, achdrval); for (i = 0; i < 4; i++) { p = zputchar (p, achdrval[i]); crc = UPDC32 (achdrval[i], crc); } crc = ~crc; for (i = 0; i < 4; i++) { p = zputchar (p, (char) crc); crc >>= 8; } break; case ZHEX: /* build hex header */ *p++ = ZPAD; *p++ = ZPAD; *p++ = ZDLE; *p++ = ZHEX; p = zputhex (p, ihdrtype); crc = ICRCINIT; crc = UPDC32 (ihdrtype, crc); stohdr (hdrval, achdrval); for (i = 0; i < 4; i++) { p = zputhex (p, achdrval[i]); crc = UPDC32 (achdrval[i], crc); } crc = ~crc; for (i = 0; i < 4; i++) { p = zputhex (p, (char) crc); crc >>= 8; } *p++ = CR; /* * Uncork the remote in case a fake XOFF has stopped data flow. */ if (ihdrtype != ZFIN && ihdrtype != ZACK) /* FIXME: why? */ *p++ = XON; break; default: ulog (LOG_FATAL, "czbuild_header: ipkttype == %d", ipkttype); break; } return p - zresult; } /* * Build Zmodem data packets ... * * This function is zsdata() and zsda32() from the zm source. */ static int czbuild_data_packet(zresult, zdata, cdata, frameend) char *zresult; const char *zdata; size_t cdata; int frameend; { char *p; unsigned long crc; p = zresult; crc = ICRCINIT; for ( ; cdata-- != 0; zdata++) { char c; c = *zdata; if (c & 0140) *p++ = c; else p = zputchar (p, c); crc = UPDC32 ((unsigned char) c, crc); } *p++ = ZDLE; *p++ = frameend; crc = UPDC32 (frameend, crc); crc = ~crc; for (cdata = 0; cdata < 4; cdata++) { p = zputchar (p, (char) crc); crc >>= 8; } if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) { *p++ = CR; *p++ = XON; } return p - zresult; } /* * Read in a header ... * * This is function zgethdr() from the Zmodem source. */ static int izrecv_hdr(qdaemon, hdr) struct sdaemon *qdaemon; achdrval_t hdr; { int c,cerr; /* * Kludge alert! If another part of the program received a packet but * wasn't ready to handle it, it is tucked away for us to handle now. */ if (iZpkt_rcvd_kludge != -1) { c = iZpkt_rcvd_kludge; iZpkt_rcvd_kludge = -1; stohdr (hvZpkt_hdrval_kludge, hdr); DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: queued %s, data = 0x%lx", ZZHEADER_NAME(c), rclhdr (hdr)); cZheaders_received++; return c; } cerr = cZmax_garbage; /* Max bytes before start of frame */ again: switch (c = noxrd7 (qdaemon)) { case ZM_TIMEOUT: case ZM_ERROR: case ZM_RCDO: goto fifi; case ZPAD: /* This is what we want */ break; case CR: /* padding at end of previous header */ default: if (--cerr < 0) { c = ZM_ERROR; goto fifi; } goto again; } splat: switch (c = noxrd7 (qdaemon)) { case ZPAD: if (--cerr < 0) { c = ZM_ERROR; goto fifi; } goto splat; case ZM_TIMEOUT: case ZM_RCDO: goto fifi; case ZDLE: /* This is what we want */ break; default: if (--cerr < 0) { c = ZM_ERROR; goto fifi; } goto again; } switch (c = noxrd7 (qdaemon)) { case ZM_TIMEOUT: case ZM_RCDO: goto fifi; case ZBIN: c = zrbhdr32 (qdaemon, hdr); break; case ZHEX: c = zrhhdr (qdaemon, hdr); break; default: if (--cerr < 0) { c = ZM_ERROR; goto fifi; } goto again; } fifi: switch (c) { case ZM_TIMEOUT: cZtimeouts++; break; case ZM_ERROR: cZerrors++; break; case ZM_RCDO: break; default: cZheaders_received++; break; } DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%x", ZZHEADER_NAME(c), rclhdr (hdr)); return c; } /* * Receive a binary style header (type and position) with 32 bit FCS ... */ static int zrbhdr32(qdaemon, hdr) struct sdaemon *qdaemon; achdrval_t hdr; { int c,i,type; unsigned long crc; if ((c = zdlread (qdaemon)) & ~0377) return c; type = c; crc = ICRCINIT; crc = UPDC32 (c, crc); for (i = 0; i < 4; i++) { if ((c = zdlread (qdaemon)) & ~0377) return c; crc = UPDC32 (c, crc); hdr[i] = (char) c; } for (i = 0; i < 4; i++) { if ((c = zdlread (qdaemon)) & ~0377) return c; crc = UPDC32 (c, crc); } if (crc != IHDRCRC) return ZM_ERROR; return type; } /* * Receive a hex style header (type and position) ... */ static int zrhhdr(qdaemon, hdr) struct sdaemon *qdaemon; achdrval_t hdr; { int c,i,type; unsigned long crc; if ((c = zgethex (qdaemon)) < 0) return c; type = c; crc = ICRCINIT; crc = UPDC32 (c, crc); for (i = 0; i < 4; i++) { if ((c = zgethex (qdaemon)) < 0) return c; crc = UPDC32 (c, crc); hdr[i] = (char) c; } for (i = 0; i < 4; i++) { if ((c = zgethex (qdaemon)) < 0) return c; crc = UPDC32 (c, crc); } if (crc != IHDRCRC) return ZM_ERROR; return type; } /* * Receive a data packet ... */ static int zrdat32(qdaemon, buf, length, iprxcount) struct sdaemon *qdaemon; char *buf; int length; int *iprxcount; { int c,d; unsigned long crc; char *end; crc = ICRCINIT; *iprxcount = 0; end = buf + length; while (buf <= end) { if ((c = zdlread (qdaemon)) & ~0377) { crcfoo: switch (c) { case GOTCRCE: case GOTCRCG: case GOTCRCQ: case GOTCRCW: case GOTCRCF: d = c; c &= 0377; crc = UPDC32 (c, crc); if ((c = zdlread (qdaemon)) & ~0377) goto crcfoo; crc = UPDC32 (c, crc); if ((c = zdlread (qdaemon)) & ~0377) goto crcfoo; crc = UPDC32 (c, crc); if ((c = zdlread (qdaemon)) & ~0377) goto crcfoo; crc = UPDC32 (c, crc); if ((c = zdlread (qdaemon)) & ~0377) goto crcfoo; crc = UPDC32 (c, crc); if (crc != IHDRCRC) return ZM_ERROR; *iprxcount = length - (end - buf); return d; case ZM_TIMEOUT: case ZM_RCDO: return c; default: return ZM_ERROR; } } *buf++ = (char) c; crc = UPDC32 (c, crc); } return ZM_ERROR; /* bad packet, too long */ } /* * Respond to receiver's complaint, get back in sync with receiver ... */ static int getinsync(qdaemon, flag) struct sdaemon *qdaemon; boolean flag; { int c,cerr; achdrval_t rx_hdr; cerr = cZretries; for (;;) { c = izrecv_hdr (qdaemon, rx_hdr); switch (c) { case ZRPOS: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos); cZbytes_resent += wpZtxpos - wpZrxpos; wpZlrxpos = wpZtxpos = wpZrxpos; if (wpZlastsync == wpZrxpos) { if (++iZbeenhereb4 > 4) if (cZblklen > 32) cZblklen /= 2; /* FIXME: shouldn't we reset iZbeenhereb4? */ } wpZlastsync = wpZrxpos; return ZRPOS; case ZACK: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos, wpZlrxpos, wpZtxpos); wpZlrxpos = wpZrxpos; if (flag || wpZtxpos == wpZrxpos) return ZACK; break; case ZNAK: { winpos_t rx_bytes; /* * Our partner is in fzfinish_tx() and is waiting * for ZACK ... */ zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes); if (rx_bytes == wpZrxbytes) { if (!fzsend_hdr (qdaemon, ZHEX, ZACK, hvzencode_data_hdr (wpZrxbytes), TRUE)) return FALSE; } break; } case ZFIN: case ZM_RCDO: return c; case ZM_TIMEOUT: if (--cerr < 0) { ulog (LOG_ERROR, "getinsync: retries exhausted"); return ZM_ERROR; } break; /* sender doesn't send ZNAK for timeout */ case ZM_ERROR: default: if (--cerr < 0) { ulog (LOG_ERROR, "getinsync: retries exhausted"); return ZM_ERROR; } if (!fzsend_hdr (qdaemon, ZHEX, ZNAK, hvzencode_data_hdr (wpZtxpos), TRUE)) return ZM_ERROR; break; } } } /* * Send a byte as two hex digits ... */ static char * zputhex(p, ch) char *p; int ch; { static char digits[] = "0123456789abcdef"; *p++ = digits[(ch & 0xF0) >> 4]; *p++ = digits[ch & 0xF]; return p; } /* * Send character c with ZMODEM escape sequence encoding ... * * Escape XON, XOFF. * FIXME: Escape CR following @ (Telenet net escape) ... disabled for now * Will need to put back references to . */ static char * zputchar(p, ch) char *p; int ch; { char c = ch; /* Quick check for non control characters */ if (c & 0140) { *p++ = c; } else { switch (c & 0377) { case ZDLE: *p++ = ZDLE; *p++ = c ^ 0100; break; case CR: #if 0 if (!fZesc_ctl && (lastsent & 0177) != '@') goto sendit; #endif /* fall through */ case 020: /* ^P */ case XON: case XOFF: *p++ = ZDLE; c ^= 0100; /*sendit:*/ *p++ = c; break; default: if (fZesc_ctl && !(c & 0140)) { *p++ = ZDLE; c ^= 0100; } *p++ = c; break; } } return p; } /* * Decode two lower case hex digits into an 8 bit byte value ... */ static int zgethex(qdaemon) struct sdaemon *qdaemon; { int c,n; if ((c = noxrd7 (qdaemon)) < 0) return c; n = c - '0'; if (n > 9) n -= ('a' - ':'); if (n & ~0xF) return ZM_ERROR; if ((c = noxrd7 (qdaemon)) < 0) return c; c -= '0'; if (c > 9) c -= ('a' - ':'); if (c & ~0xF) return ZM_ERROR; c += (n << 4); return c; } /* * Read a byte, checking for ZMODEM escape encoding ... */ static int zdlread(qdaemon) struct sdaemon *qdaemon; { int c; again: READCHAR (qdaemon, c, cZtimeout); if (c < 0) return c; if (c & 0140) /* quick check for non control characters */ return c; switch (c) { case ZDLE: break; case XON: goto again; case XOFF: READCHAR (qdaemon, c, XON_WAIT); goto again; default: if (fZesc_ctl && !(c & 0140)) goto again; return c; } again2: READCHAR (qdaemon, c, cZtimeout); if (c < 0) return c; switch (c) { case ZCRCE: case ZCRCG: case ZCRCQ: case ZCRCW: case ZCRCF: return c | GOTOR; case ZRUB0: /* FIXME: This is never generated. */ return 0177; case ZRUB1: /* FIXME: This is never generated. */ return 0377; case XON: goto again2; case XOFF: READCHAR (qdaemon, c, XON_WAIT); goto again2; default: if (fZesc_ctl && !(c & 0140)) goto again2; /* FIXME: why again2? */ if ((c & 0140) == 0100) return c ^ 0100; break; } return ZM_ERROR; } /* * Read a character from the modem line with timeout ... * Eat parity bit, XON and XOFF characters. */ static int noxrd7(qdaemon) struct sdaemon *qdaemon; { int c; for (;;) { READCHAR (qdaemon, c, cZtimeout); if (c < 0) return c; switch (c &= 0177) { case XON: continue; case XOFF: READCHAR (qdaemon, c, XON_WAIT); continue; case CR: case ZDLE: return c; default: if (fZesc_ctl && !(c & 0140)) continue; return c; } } } /* * Read a character from the receive buffer, or from the line if empty ... * * is in seconds (maybe make it tenths of seconds like in Zmodem?) */ static int realreadchar(qdaemon, timeout) struct sdaemon *qdaemon; int timeout; { int c; if ((c = breceive_char (qdaemon->qconn, timeout, TRUE)) >= 0) return c; switch (c) { case -1: return ZM_TIMEOUT; case -2: return ZM_RCDO; } ulog (LOG_FATAL, "realreadchar: breceive_char() returned %d", c); return ZM_ERROR; } /* * Check if the receive channel has any characters in it. * * At present we can only test the receive buffer. No mechanism is available * to go to the hardware. This should not be a problem though, as long as all * appropriate calls to fsend_data() set to TRUE. */ static boolean fzreceive_ready() { return iPrecstart != iPrecend; } /* * Store integer value in an achdrval_t ... */ static void stohdr(val, hdr) hdrval_t val; achdrval_t hdr; { hdr[ZP0] = (char) val; hdr[ZP1] = (char) (val >> 8); hdr[ZP2] = (char) (val >> 16); hdr[ZP3] = (char) (val >> 24); } /* * Recover an integer from a header ... */ static hdrval_t rclhdr(hdr) achdrval_t hdr; { hdrval_t v; v = hdr[ZP3] & 0377; v = (v << 8) | (hdr[ZP2] & 0377); v = (v << 8) | (hdr[ZP1] & 0377); v = (v << 8) | (hdr[ZP0] & 0377); return v; } /* * Encode a from the byte count ... * * We use to store the byte count / 32 and a message sequence number which * made this function very useful. Don't remove it. * FIXME: Well, maybe remove it later. */ static hdrval_t hvzencode_data_hdr(cbytes) winpos_t cbytes; { return (hdrval_t) cbytes; } /* * Decode a into a byte count ... * * We use to store the byte count / 32 and a message sequence number which * made this function very useful. Don't remove it. * FIXME: Well, maybe remove it later. */ static void zdecode_data_hdr(hdrval, pcbytes) hdrval_t hdrval; winpos_t *pcbytes; { *pcbytes = hdrval; } /* * Update from the received data header value ... * * FIXME: Here is where we'd handle wrapping around at 4 gigabytes. */ static winpos_t lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos) achdrval_t rx_hdr; winpos_t rxpos,lrxpos,txpos; { winpos_t rx_pktpos; zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos); DEBUG_MESSAGE4 (DEBUG_PROTO, "lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx", rx_pktpos, rxpos, lrxpos, txpos); /* * Check if valid. It could be old. */ if (rx_pktpos < wpZlrxpos || rx_pktpos > ((wpZtxpos + 1024L) & ~1023L)) return rxpos; return rx_pktpos; } 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 ZMuucp-1.04/rec.c1004440004150000170000007664305337263513010320 037777777777 1 0 /* 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.21 1993/01/20 05:26:30 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "prot.h" #include "trans.h" /* If the other side does not tell us the size of a file it wants to send us, we assume it is this long. This is only used for free space checking. */ #define CASSUMED_FILE_SIZE (10240) /* We keep this information in the pinfo field of the stransfer structure. */ struct srecinfo { /* Local user to send mail to (may be NULL). */ char *zmail; /* Full file name. */ char *zfile; /* Temporary file name. */ char *ztemp; /* TRUE if this is a spool directory file. */ boolean fspool; /* TRUE if this was a local request. */ boolean flocal; /* TRUE if the file has been completely received. */ boolean freceived; /* TRUE if remote request has been replied to. */ boolean freplied; /* TRUE if we moved the file to the final destination. */ boolean fmoved; }; /* This structure is kept in the pinfo field if we are refusing a remote request. */ struct srecfailinfo { /* Reason for refusal. */ enum tfailure twhy; /* TRUE if we have sent the reason for refusal. */ boolean fsent; /* TRUE if we have seen the end of the file. */ boolean freceived; }; /* Local functions. */ static void urrec_free P((struct stransfer *qtrans)); static boolean flocal_rec_fail P((struct stransfer *qtrans, struct scmd *qcmd, const struct uuconf_system *qsys, const char *zwhy)); static boolean flocal_rec_send_request P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean flocal_rec_await_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean fremote_send_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fremote_send_fail P((struct sdaemon *qdaemon, struct scmd *qcmd, enum tfailure twhy, int iremote)); static boolean fremote_send_fail_send P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fremote_discard P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean frec_file_end P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean frec_file_send_confirm P((struct stransfer *qtrans, struct sdaemon *qdaemon)); /* Free up a receive stransfer structure. */ static void urrec_free (qtrans) struct stransfer *qtrans; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; if (qinfo != NULL) { ubuffree (qinfo->zmail); ubuffree (qinfo->zfile); ubuffree (qinfo->ztemp); xfree (qtrans->pinfo); } utransfree (qtrans); } /* Set up a request for a file from the remote system. This may be called before the remote system has been called. This is the order of function calls: flocal_rec_file_init --> fqueue_local flocal_rec_send_request (send R ...) --> fqueue_receive flocal_rec_await_reply (open file, call pffile) --> fqueue_receive receive file frec_file_end (close and move file, call pffile) --> fqueue_send frec_file_send_confirm (send CY) */ boolean flocal_rec_file_init (qdaemon, qcmd) struct sdaemon *qdaemon; struct scmd *qcmd; { const struct uuconf_system *qsys; boolean fspool; char *zfile; struct srecinfo *qinfo; struct stransfer *qtrans; qsys = qdaemon->qsys; /* Make sure we are permitted to transfer files. */ if (qdaemon->fcaller ? ! qsys->uuconf_fcall_transfer : ! qsys->uuconf_fcalled_transfer) { /* This case will have been checked by uucp or uux, but it could have changed. */ if (! qsys->uuconf_fcall_transfer && ! qsys->uuconf_fcalled_transfer) return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, "not permitted to request files"); return TRUE; } fspool = fspool_file (qcmd->zto); if (fspool) { pointer puuconf; int iuuconf; const char *zlocalname; struct uuconf_system slocalsys; /* Normal users are not allowed to request files to be received into the spool directory. To support uux forwarding, we use the special option '9'. This permits a file to be received into the spool directory for the local system only without the usual checking. This is only done for local requests, of course. */ if (qcmd->zto[0] != 'D' || strchr (qcmd->zoptions, '9') == NULL) return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, "not permitted to receive"); puuconf = qdaemon->puuconf; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys); if (iuuconf == UUCONF_NOT_FOUND) { iuuconf = uuconf_system_local (puuconf, &slocalsys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } zfile = zsysdep_spool_file_name (&slocalsys, qcmd->zto, qcmd->pseq); (void) uuconf_system_free (puuconf, &slocalsys); if (zfile == NULL) return FALSE; } else { zfile = zsysdep_add_base (qcmd->zto, qcmd->zfrom); if (zfile == NULL) return FALSE; /* Check permissions. */ if (! fin_directory_list (zfile, qsys->uuconf_pzlocal_receive, qsys->uuconf_zpubdir, TRUE, FALSE, qcmd->zuser)) { ubuffree (zfile); return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, "not permitted to receive"); } /* The 'f' option means that directories should not be created if they do not already exist. */ if (strchr (qcmd->zoptions, 'f') == NULL) { if (! fsysdep_make_dirs (zfile, TRUE)) { ubuffree (zfile); return flocal_rec_fail ((struct stransfer *) NULL, qcmd, qsys, "cannot create directories"); } } } qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo)); if (strchr (qcmd->zoptions, 'm') == NULL) qinfo->zmail = NULL; else qinfo->zmail = zbufcpy (qcmd->zuser); qinfo->zfile = zfile; qinfo->ztemp = NULL; qinfo->fspool = fspool; qinfo->flocal = TRUE; qinfo->freceived = FALSE; qinfo->freplied = TRUE; qtrans = qtransalc (qcmd); qtrans->psendfn = flocal_rec_send_request; qtrans->pinfo = (pointer) qinfo; return fqueue_local (qdaemon, qtrans); } /* Report an error for a local receive request. */ static boolean flocal_rec_fail (qtrans, qcmd, qsys, zwhy) struct stransfer *qtrans; struct scmd *qcmd; const struct uuconf_system *qsys; const char *zwhy; { if (zwhy != NULL) { ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy); (void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, zwhy, qcmd->zfrom, qsys->uuconf_zname, qcmd->zto, (const char *) NULL, (const char *) NULL); (void) fsysdep_did_work (qcmd->pseq); } if (qtrans != NULL) urrec_free (qtrans); return TRUE; } /* This is called when we are ready to send the actual request to the other system. */ static boolean flocal_rec_send_request (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; long cbytes, cbytes2; size_t clen; char *zsend; boolean fret; qinfo->ztemp = zsysdep_receive_temp (qdaemon->qsys, qinfo->zfile, (const char *) NULL); if (qinfo->ztemp == NULL) { urrec_free (qtrans); return FALSE; } /* Check the amount of free space available for both the temporary file and the real file. */ cbytes = csysdep_bytes_free (qinfo->ztemp); cbytes2 = csysdep_bytes_free (qinfo->zfile); if (cbytes < cbytes2) cbytes = cbytes2; if (cbytes != -1) { cbytes -= qdaemon->qsys->uuconf_cfree_space; if (cbytes < 0) cbytes = 0; } if (qdaemon->clocal_size != -1 && (cbytes == -1 || qdaemon->clocal_size < cbytes)) cbytes = qdaemon->clocal_size; /* We send the string R from to user options We put a dash in front of options. If we are talking to a counterpart, we also send the maximum size file we are prepared to accept, as returned by esysdep_open_receive. */ clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 30); zsend = zbufalc (clen); if ((qdaemon->ifeatures & FEATURE_SIZES) == 0) sprintf (zsend, "R %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions); else if ((qdaemon->ifeatures & FEATURE_V103) == 0) sprintf (zsend, "R %s %s %s -%s 0x%lx", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions, (unsigned long) cbytes); else sprintf (zsend, "R %s %s %s -%s %ld", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions, cbytes); fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, qtrans->iremote); ubuffree (zsend); if (! fret) { urrec_free (qtrans); return FALSE; } qtrans->fcmd = TRUE; qtrans->precfn = flocal_rec_await_reply; return fqueue_receive (qdaemon, qtrans); } /* This is called when a reply is received for the request. */ /*ARGSUSED*/ static boolean flocal_rec_await_reply (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; long crestart; const char *zlog; if (zdata[0] != 'R' || (zdata[1] != 'Y' && zdata[1] != 'N')) { ulog (LOG_ERROR, "%s: bad response to receive request: \"%s\"", qtrans->s.zfrom, zdata); urrec_free (qtrans); return FALSE; } if (zdata[1] == 'N') { boolean fnever; const char *zerr; fnever = TRUE; if (zdata[2] == '2') zerr = "no such file"; else if (zdata[2] == '6') { /* We sent over the maximum file size we were prepared to receive, and the remote system is telling us that the file is larger than that. Try again later. It would be better if we could know whether there will ever be enough room. */ zerr = "too large to receive now"; fnever = FALSE; } else zerr = "unknown reason"; if (fnever) return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, zerr); ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); urrec_free (qtrans); return TRUE; } /* The mode should have been sent as "RY 0%o". If it wasn't, we use 0666. */ qtrans->s.imode = (unsigned int) strtol ((char *) (zdata + 2), (char **) NULL, 8); if (qtrans->s.imode == 0) qtrans->s.imode = 0666; /* Open the file to receive into. We just ignore any restart count, since we have no way to tell it to the other side. SVR4 may have some way to do this, but I don't know what it is. */ qtrans->e = esysdep_open_receive (qdaemon->qsys, qinfo->zfile, (const char *) NULL, qinfo->ztemp, &crestart); if (! ffileisopen (qtrans->e)) return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, "cannot open file"); if (qinfo->fspool) zlog = qtrans->s.zto; else zlog = qinfo->zfile; qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); sprintf (qtrans->zlog, "Receiving %s", zlog); if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, (long) -1, &fhandled)) { (void) ffileclose (qtrans->e); return flocal_rec_fail (qtrans, &qtrans->s, qdaemon->qsys, (const char *) NULL); } if (fhandled) return TRUE; } qtrans->frecfile = TRUE; qtrans->psendfn = frec_file_send_confirm; qtrans->precfn = frec_file_end; return fqueue_receive (qdaemon, qtrans); } /* Make sure there is still enough disk space available to receive a file. */ boolean frec_check_free (qtrans, cfree_space) struct stransfer *qtrans; long cfree_space; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; long cfree1, cfree2; cfree1 = csysdep_bytes_free (qinfo->ztemp); cfree2 = csysdep_bytes_free (qinfo->zfile); if (cfree1 < cfree2) cfree1 = cfree2; if (cfree1 != -1 && cfree1 < cfree_space) { ulog (LOG_ERROR, "%s: too big to receive now", qinfo->zfile); return FALSE; } return TRUE; } /* A remote request to send a file to the local system, meaning that we are going to receive a file. If we are using a protocol which does not support multiple channels, the remote system will not start sending us the file until it has received our confirmation. In that case, the order of functions is as follows: fremote_send_file_init (open file) --> fqueue_remote fremote_send_reply (send SY, call pffile) --> fqueue_receive receive file frec_file_end (close and move file, call pffile) --> fqueue_send frec_file_send_confirm (send CY) If the protocol supports multiple channels, then the remote system will start sending the file immediately after the send request. That means that the data may come in before remote_send_reply is called, so frec_file_end may be called before fremote_send_reply. Note that this means the pffile entry points may be called in reverse order for such a protocol. If the send request is rejected, via fremote_send_fail, and the protocol supports multiple channels, we must accept and discard data until a zero byte buffer is received from the other side, indicating that it has received our rejection. This code also handles execution requests, which are very similar to send requests. */ boolean fremote_send_file_init (qdaemon, qcmd, iremote) struct sdaemon *qdaemon; struct scmd *qcmd; int iremote; { const struct uuconf_system *qsys; boolean fspool; char *zfile; openfile_t e; char *ztemp; long cbytes, cbytes2; long crestart; struct srecinfo *qinfo; struct stransfer *qtrans; const char *zlog; qsys = qdaemon->qsys; if (! qsys->uuconf_frec_request) { ulog (LOG_ERROR, "%s: not permitted to receive files from remote", qcmd->zfrom); return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); } fspool = fspool_file (qcmd->zto); /* We don't accept remote command files. An execution request may only send a simple data file. */ if ((fspool && qcmd->zto[0] == 'C') || (qcmd->bcmd == 'E' && (! fspool || qcmd->zto[0] != 'D'))) { ulog (LOG_ERROR, "%s: not permitted to receive", qcmd->zfrom); return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); } /* See if we have already received this file in a previous conversation. */ if (fsysdep_already_received (qsys, qcmd->zto, qcmd->ztemp)) return fremote_send_fail (qdaemon, qcmd, FAILURE_RECEIVED, iremote); if (fspool) { zfile = zsysdep_spool_file_name (qsys, qcmd->zto, (pointer) NULL); if (zfile == NULL) return FALSE; } else { zfile = zsysdep_local_file (qcmd->zto, qsys->uuconf_zpubdir); if (zfile != NULL) { char *zadd; zadd = zsysdep_add_base (zfile, qcmd->zfrom); ubuffree (zfile); zfile = zadd; } if (zfile == NULL) return FALSE; /* Check permissions. */ if (! fin_directory_list (zfile, qsys->uuconf_pzremote_receive, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL)) { ulog (LOG_ERROR, "%s: not permitted to receive", zfile); ubuffree (zfile); return fremote_send_fail (qdaemon, qcmd, FAILURE_PERM, iremote); } if (strchr (qcmd->zoptions, 'f') == NULL) { if (! fsysdep_make_dirs (zfile, TRUE)) { ubuffree (zfile); return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote); } } } ztemp = zsysdep_receive_temp (qsys, zfile, qcmd->ztemp); /* Adjust the number of bytes we are prepared to receive according to the amount of free space we are supposed to leave available and the maximum file size we are permitted to transfer. */ cbytes = csysdep_bytes_free (ztemp); cbytes2 = csysdep_bytes_free (zfile); if (cbytes < cbytes2) cbytes = cbytes2; if (cbytes != -1) { cbytes -= qsys->uuconf_cfree_space; if (cbytes < 0) cbytes = 0; } if (qdaemon->cremote_size != -1 && (cbytes == -1 || qdaemon->cremote_size < cbytes)) cbytes = qdaemon->cremote_size; /* If the number of bytes we are prepared to receive is less than the file size, we must fail. If the remote did not tell us the file size, arbitrarily assumed that it is 10240 bytes. */ if (cbytes != -1) { long csize; csize = qcmd->cbytes; if (csize == -1) csize = CASSUMED_FILE_SIZE; if (cbytes < csize) { ulog (LOG_ERROR, "%s: too big to receive", zfile); ubuffree (ztemp); ubuffree (zfile); return fremote_send_fail (qdaemon, qcmd, FAILURE_SIZE, iremote); } } /* Open the file to receive into. This may find an old copy of the file, which will be used for file restart if the other side supports it. */ e = esysdep_open_receive (qsys, zfile, qcmd->ztemp, ztemp, &crestart); if (! ffileisopen (e)) { ubuffree (ztemp); ubuffree (zfile); return fremote_send_fail (qdaemon, qcmd, FAILURE_OPEN, iremote); } if (crestart > 0) { if ((qdaemon->ifeatures & FEATURE_RESTART) == 0) crestart = -1; else { DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fremote_send_file_init: Restarting receive from %ld", crestart); if (! ffileseek (e, crestart)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); (void) ffileclose (e); ubuffree (ztemp); ubuffree (zfile); return FALSE; } } } qinfo = (struct srecinfo *) xmalloc (sizeof (struct srecinfo)); if (strchr (qcmd->zoptions, 'n') == NULL) qinfo->zmail = NULL; else qinfo->zmail = zbufcpy (qcmd->znotify); qinfo->zfile = zfile; qinfo->ztemp = ztemp; qinfo->fspool = fspool; qinfo->flocal = FALSE; qinfo->freceived = FALSE; qinfo->freplied = FALSE; qtrans = qtransalc (qcmd); qtrans->psendfn = fremote_send_reply; qtrans->precfn = frec_file_end; qtrans->iremote = iremote; qtrans->pinfo = (pointer) qinfo; qtrans->frecfile = TRUE; qtrans->e = e; if (crestart > 0) qtrans->ipos = crestart; if (qcmd->bcmd == 'E') zlog = qcmd->zcmd; else { if (qinfo->fspool) zlog = qcmd->zto; else zlog = qinfo->zfile; } qtrans->zlog = zbufalc (sizeof "Receiving " + strlen (zlog)); sprintf (qtrans->zlog, "Receiving %s", zlog); return fqueue_remote (qdaemon, qtrans); } /* Reply to a send request, and prepare to receive the file. */ static boolean fremote_send_reply (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; char ab[50]; ab[0] = qtrans->s.bcmd; ab[1] = 'Y'; if (qtrans->ipos <= 0) ab[2] = '\0'; else sprintf (ab + 2, " 0x%lx", (unsigned long) qtrans->ipos); if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, qtrans->iremote)) { (void) ffileclose (qtrans->e); (void) remove (qinfo->ztemp); urrec_free (qtrans); return FALSE; } qinfo->freplied = TRUE; if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, FALSE, (long) -1, &fhandled)) { (void) ffileclose (qtrans->e); (void) remove (qinfo->ztemp); urrec_free (qtrans); return FALSE; } if (fhandled) return TRUE; } /* If the file has been completely received, we just want to send the final confirmation. Otherwise, we must wait for the file first. */ qtrans->psendfn = frec_file_send_confirm; if (qinfo->freceived) return fqueue_send (qdaemon, qtrans); else return fqueue_receive (qdaemon, qtrans); } /* If we can't receive a file, queue up a response to the remote system. */ static boolean fremote_send_fail (qdaemon, qcmd, twhy, iremote) struct sdaemon *qdaemon; struct scmd *qcmd; enum tfailure twhy; int iremote; { struct srecfailinfo *qinfo; struct stransfer *qtrans; qinfo = (struct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo)); qinfo->twhy = twhy; qinfo->fsent = FALSE; /* If the protocol does not support multiple channels (cchans <= 1), then we have essentially already received the entire file. */ qinfo->freceived = qdaemon->qproto->cchans <= 1; qtrans = qtransalc (qcmd); qtrans->psendfn = fremote_send_fail_send; qtrans->precfn = fremote_discard; qtrans->iremote = iremote; qtrans->pinfo = (pointer) qinfo; return fqueue_remote (qdaemon, qtrans); } /* Send a failure string for a send command to the remote system; this is called when we are ready to reply to the command. */ static boolean fremote_send_fail_send (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; char ab[4]; boolean fret; ab[0] = qtrans->s.bcmd; ab[1] = 'N'; switch (qinfo->twhy) { case FAILURE_PERM: ab[2] = '2'; break; case FAILURE_OPEN: ab[2] = '4'; break; case FAILURE_SIZE: ab[2] = '6'; break; case FAILURE_RECEIVED: /* Remember this file as though we successfully received it; when the other side acknowledges our rejection, we know that we no longer have to remember that we received this file. */ usent_receive_ack (qdaemon, qtrans); ab[2] = '8'; break; default: ab[2] = '\0'; break; } ab[3] = '\0'; fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, ab, qtrans->ilocal, qtrans->iremote); qinfo->fsent = TRUE; /* Wait for the end of file marker if we haven't gotten it yet. */ if (! qinfo->freceived) { if (! fqueue_receive (qdaemon, qtrans)) fret = FALSE; } else { xfree (qtrans->pinfo); utransfree (qtrans); } return fret; } /* Discard data until we reach the end of the file. This is used for a protocol with multiple channels, since the remote system may start sending the file before the confirmation is sent. If we refuse the file, the remote system will get us back in synch by sending an empty buffer, which is what we look for here. */ /*ARGSUSED*/ static boolean fremote_discard (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct srecfailinfo *qinfo = (struct srecfailinfo *) qtrans->pinfo; DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fremote_discard: Discarding %lu bytes", (unsigned long) cdata); if (cdata != 0) return TRUE; qinfo->freceived = TRUE; /* If we have already sent the denial, we are done. */ if (qinfo->fsent) { xfree (qtrans->pinfo); utransfree (qtrans); } return TRUE; } /* This is called when a file has been completely received. It sends a response to the remote system. */ /*ARGSUSED*/ static boolean frec_file_end (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; const char *zerr; boolean fnever; DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, "frec_file_end: %s to %s (freplied %s)", qtrans->s.zfrom, qtrans->s.zto, qinfo->freplied ? "TRUE" : "FALSE"); if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, FALSE, (long) -1, &fhandled)) { (void) ffileclose (qtrans->e); (void) remove (qinfo->ztemp); urrec_free (qtrans); return FALSE; } if (fhandled) return TRUE; } qinfo->freceived = TRUE; fnever = FALSE; if (! ffileclose (qtrans->e)) { zerr = strerror (errno); ulog (LOG_ERROR, "%s: close: %s", qtrans->s.zto, zerr); } else if (! fsysdep_move_file (qinfo->ztemp, qinfo->zfile, qinfo->fspool, FALSE, ! qinfo->fspool, (qinfo->flocal ? qtrans->s.zuser : (const char *) NULL))) { zerr = "could not move to final location"; ulog (LOG_ERROR, "%s: %s", qinfo->zfile, zerr); fnever = TRUE; } else { if (! qinfo->fspool) { unsigned int imode; /* Unless we can change the ownership of the file, the only choice to make about these bits is whether to set the execute bit or not. */ if ((qtrans->s.imode & 0111) != 0) imode = 0777; else imode = 0666; (void) fsysdep_change_mode (qinfo->zfile, imode); } zerr = NULL; } if (zerr != NULL) (void) remove (qinfo->ztemp); ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname, FALSE, qtrans->cbytes, qtrans->isecs, qtrans->imicros, qdaemon->fmaster); if (zerr == NULL) { if (qinfo->zmail != NULL && *qinfo->zmail != '\0') (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail, (const char *) NULL, qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, qtrans->s.zto, (const char *) NULL, (const char *) NULL); if (qtrans->s.pseq != NULL) (void) fsysdep_did_work (qtrans->s.pseq); if (! qinfo->flocal) { /* Remember that we have received this file, so that if the connection drops at this point we won't receive it again. We could check the return value here, but if we return FALSE we couldn't do anything but drop the connection, which would hardly be reasonable. Instead we trust that the administrator will notice and handle any error messages, which are very unlikely to occur if everything is set up correctly. */ (void) fsysdep_remember_reception (qdaemon->qsys, qtrans->s.zto, qtrans->s.ztemp); } } else { /* If the transfer failed, we send mail if it was requested locally and if it can never succeed. */ if (qinfo->flocal && fnever) { (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail, zerr, qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, qtrans->s.zto, (const char *) NULL, (const char *) NULL); (void) fsysdep_did_work (qtrans->s.pseq); } } /* If this is an execution request, we must create the execution file itself. */ if (qtrans->s.bcmd == 'E' && zerr == NULL) { char *zxqt, *zxqtfile, *ztemp; FILE *e; boolean fbad; /* We get an execution file name by simply replacing the leading D in the received file name with an X. This pretty much always has to work since we can always receive a file name starting with X, so the system dependent code must be prepared to see one. */ zxqt = zbufcpy (qtrans->s.zto); zxqt[0] = 'X'; zxqtfile = zsysdep_spool_file_name (qdaemon->qsys, zxqt, (pointer) NULL); ubuffree (zxqt); if (zxqtfile == NULL) { urrec_free (qtrans); return FALSE; } /* We have to write via a temporary file, because otherwise uuxqt might pick up the file before we have finished writing it. */ e = NULL; ztemp = zsysdep_receive_temp (qdaemon->qsys, zxqtfile, "D.0"); if (ztemp != NULL) e = esysdep_fopen (ztemp, FALSE, FALSE, TRUE); if (e == NULL) { ubuffree (zxqtfile); ubuffree (ztemp); urrec_free (qtrans); return FALSE; } fprintf (e, "U %s %s\n", qtrans->s.zuser, qdaemon->qsys->uuconf_zname); fprintf (e, "F %s\n", qtrans->s.zto); fprintf (e, "I %s\n", qtrans->s.zto); if (strchr (qtrans->s.zoptions, 'N') != NULL) fprintf (e, "N\n"); if (strchr (qtrans->s.zoptions, 'Z') != NULL) fprintf (e, "Z\n"); if (strchr (qtrans->s.zoptions, 'R') != NULL) fprintf (e, "R %s\n", qtrans->s.znotify); if (strchr (qtrans->s.zoptions, 'e') != NULL) fprintf (e, "e\n"); fprintf (e, "C %s\n", qtrans->s.zcmd); fbad = FALSE; if (fclose (e) == EOF) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); (void) remove (ztemp); fbad = TRUE; } if (! fbad) { if (! fsysdep_move_file (ztemp, zxqtfile, TRUE, FALSE, FALSE, (const char *) NULL)) fbad = TRUE; } ubuffree (zxqtfile); ubuffree (ztemp); if (fbad) { urrec_free (qtrans); return FALSE; } } /* Prepare to send the completion string to the remote system. If we have not yet replied to the remote send request, we leave the transfer structure on the remote queue. Otherwise we add it to the send queue. The psendfn field will already be set. */ qinfo->fmoved = zerr == NULL; if (qinfo->freplied) return fqueue_send (qdaemon, qtrans); return TRUE; } /* Send the final confirmation string to the remote system. */ static boolean frec_file_send_confirm (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; const char *zsend; boolean fret; if (! qinfo->fmoved) zsend = "CN5"; else if (! qdaemon->frequest_hangup) zsend = "CY"; else { #if DEBUG > 0 if (qdaemon->fmaster) ulog (LOG_FATAL, "frec_file_send_confirm: Can't happen"); #endif DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "frec_send_file_confirm: Requesting remote to transfer control"); zsend = "CYM"; } fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, qtrans->iremote); /* Now, if that was a remote command, then when the confirmation message is acked we no longer have to remember that we received that file. */ if (! qinfo->flocal && qinfo->fmoved) usent_receive_ack (qdaemon, qtrans); urrec_free (qtrans); return fret; } /* Discard a temporary file if it is not useful. A temporary file is useful if it could be used to restart a receive. This is called if the connection is lost. It is only called if qtrans->frecfile is TRUE. */ boolean frec_discard_temp (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { struct srecinfo *qinfo = (struct srecinfo *) qtrans->pinfo; if ((qdaemon->ifeatures & FEATURE_RESTART) == 0 || qtrans->s.ztemp == NULL || qtrans->s.ztemp[0] != 'D' || strcmp (qtrans->s.ztemp, "D.0") == 0) (void) remove (qinfo->ztemp); return TRUE; } ruct srecfailinfo *) xmalloc (sizeof (struct srecfailinfo)); qinfo->twhy = twhy; qinfo->fuucp-1.04/send.c1004440004150000170000011013105337263514010456 037777777777 1 0 /* 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.26 1993/01/22 05:11:19 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "prot.h" #include "trans.h" /* We keep this information in the pinfo field of the stransfer structure. */ struct ssendinfo { /* Local user to send mail to (may be NULL). */ char *zmail; /* Full file name. */ char *zfile; /* Number of bytes in file. */ long cbytes; /* TRUE if this was a local request. */ boolean flocal; /* TRUE if this is a spool directory file. */ boolean fspool; /* TRUE if the file has been completely sent. */ boolean fsent; /* Execution file for sending an unsupported E request. */ char *zexec; }; /* Local functions. */ static void usfree_send P((struct stransfer *qtrans)); static boolean flocal_send_fail P((struct stransfer *qtrans, struct scmd *qcmd, const struct uuconf_system *qsys, const char *zwhy)); static boolean flocal_send_request P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean flocal_send_await_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean flocal_send_cancelled P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean flocal_send_open_file P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fremote_rec_fail P((struct sdaemon *qdaemon, enum tfailure twhy, int iremote)); static boolean fremote_rec_fail_send P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fremote_rec_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fsend_file_end P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean fsend_await_confirm P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean fsend_exec_file_init P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static void usadd_exec_line P((char **pz, size_t *pcalc, size_t *pclen, int bcmd, const char *z1, const char *z2)); static boolean fsend_exec_file P((struct stransfer *qtrans, struct sdaemon *qdaemon)); /* Free up a send stransfer structure. */ static void usfree_send (qtrans) struct stransfer *qtrans; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; if (qinfo != NULL) { ubuffree (qinfo->zmail); ubuffree (qinfo->zfile); ubuffree (qinfo->zexec); xfree (qtrans->pinfo); } utransfree (qtrans); } /* Set up a local request to send a file. This may be called before we have even tried to call the remote system. If we are using a traditional protocol, which doesn't support channel numbers and doesn't permit the file to be sent until an acknowledgement has been received, the sequence of function calls looks like this: flocal_send_file_init --> fqueue_local flocal_send_request (sends S request) --> fqueue_receive flocal_send_await_reply (waits for SY) --> fqueue_send flocal_send_open_file (opens file, calls pffile) --> fqueue_send send file fsend_file_end (calls pffile) --> fqueue_receive fsend_await_confirm (waits for CY) If flocal_send_await_reply gets an SN, it deletes the request. If the SY reply contains a file position at which to start sending, flocal_send_await_reply sets qinfo->ipos. This gets more complex if the protocol supports channels. In that case, we want to start sending the file data immediately, to avoid the round trip delay between flocal_send_request and flocal_send_await_reply. To do this, flocal_send_request calls fqueue_send rather than fqueue_receive. The main execution sequence looks like this: flocal_send_file_init --> fqueue_local flocal_send_request (sends S request) --> fqueue_send flocal_send_open_file (opens file, calls pffile) --> fqueue_send send file fsend_file_end (calls pffile) --> fqueue_receive sometime: flocal_send_await_reply (waits for SY) fsend_await_confirm (waits for CY) In this case flocal_send_await_reply must be run before fsend_await_confirm; it may be run anytime after flocal_send_request. If flocal_send_await_reply is called before the entire file has been sent: if it gets an SN, it calls flocal_send_cancelled to send an empty data block to inform the remote system that the file transfer has stopped. If it gets a file position request, it must adjust the file position accordingly. If flocal_send_await_reply is called after the entire file has been sent: if it gets an SN, it can simply delete the request. It can ignore any file position request. If the request is not deleted, flocal_send_await_reply must arrange for the next string to be passed to fsend_await_confirm. Presumably fsend_await_confirm will only be called after the entire file has been sent. Just to make things even more complex, these same routines support sending execution requests, since that is much like sending a file. For an execution request, the bcmd character will be E rather than S. If an execution request is being sent to a system which does not support them, it must be sent as two S requests instead. The second one will be the execution file, but no actual file is created; instead the zexec and znext fields in the ssendinfo structure are used. So if the bcmd character is E, then if the zexec field is NULL, the data file is being sent, otherwise the fake execution file is being sent. */ boolean flocal_send_file_init (qdaemon, qcmd) struct sdaemon *qdaemon; struct scmd *qcmd; { const struct uuconf_system *qsys; boolean fspool; char *zfile; long cbytes; struct ssendinfo *qinfo; struct stransfer *qtrans; qsys = qdaemon->qsys; if (qdaemon->fcaller ? ! qsys->uuconf_fcall_transfer : ! qsys->uuconf_fcalled_transfer) { /* uux or uucp should have already made sure that the transfer is possible, but it might have changed since then. */ if (! qsys->uuconf_fcall_transfer && ! qsys->uuconf_fcalled_transfer) return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, "not permitted to transfer files"); /* We can't do the request now, but it may get done later. */ return TRUE; } /* The 'C' option means that the file has been copied to the spool directory. */ if (strchr (qcmd->zoptions, 'C') == NULL && ! fspool_file (qcmd->zfrom)) { fspool = FALSE; if (! fin_directory_list (qcmd->zfrom, qsys->uuconf_pzlocal_send, qsys->uuconf_zpubdir, TRUE, TRUE, qcmd->zuser)) return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, "not permitted to send"); zfile = zbufcpy (qcmd->zfrom); } else { fspool = TRUE; zfile = zsysdep_spool_file_name (qsys, qcmd->ztemp, qcmd->pseq); if (zfile == NULL) return FALSE; } /* Make sure we meet any local size restrictions. The connection may not have been opened at this point, so we can't check remote size restrictions. */ cbytes = csysdep_size (zfile); if (cbytes < 0) { ubuffree (zfile); if (cbytes != -1) return FALSE; /* A cbytes value of -1 means that the file does not exist. This can happen legitimately if it has already been sent from the spool directory. */ if (! fspool) return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, "does not exist"); (void) fsysdep_did_work (qcmd->pseq); return TRUE; } if (qdaemon->clocal_size != -1 && qdaemon->clocal_size < cbytes) { ubuffree (zfile); if (qdaemon->cmax_ever == -2) { long c1, c2; c1 = cmax_size_ever (qsys->uuconf_qcall_local_size); c2 = cmax_size_ever (qsys->uuconf_qcalled_local_size); if (c1 > c2) qdaemon->cmax_ever = c1; else qdaemon->cmax_ever = c2; } if (qdaemon->cmax_ever != -1 && qdaemon->cmax_ever < qcmd->cbytes) return flocal_send_fail ((struct stransfer *) NULL, qcmd, qsys, "too large to send"); return TRUE; } /* We are now prepared to send the command to the remote system. We queue up a transfer request to send the command when we are ready. */ qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo)); if (strchr (qcmd->zoptions, 'm') == NULL) qinfo->zmail = NULL; else qinfo->zmail = zbufcpy (qcmd->zuser); qinfo->zfile = zfile; qinfo->cbytes = cbytes; qinfo->flocal = TRUE; qinfo->fspool = fspool; qinfo->fsent = FALSE; qinfo->zexec = NULL; qtrans = qtransalc (qcmd); qtrans->psendfn = flocal_send_request; qtrans->pinfo = (pointer) qinfo; return fqueue_local (qdaemon, qtrans); } /* Clean up after a failing local send request. If zwhy is not NULL, this reports an error to the log file and to the user. */ static boolean flocal_send_fail (qtrans, qcmd, qsys, zwhy) struct stransfer *qtrans; struct scmd *qcmd; const struct uuconf_system *qsys; const char *zwhy; { if (zwhy != NULL) { char *zfree; if (qcmd->bcmd != 'E') zfree = NULL; else { zfree = zbufalc (sizeof "Execution of \"\": " + strlen (qcmd->zcmd) + strlen (zwhy)); sprintf (zfree, "Execution of \"%s\": %s", qcmd->zcmd, zwhy); zwhy = zfree; } ulog (LOG_ERROR, "%s: %s", qcmd->zfrom, zwhy); (void) fmail_transfer (FALSE, qcmd->zuser, (const char *) NULL, zwhy, qcmd->zfrom, (const char *) NULL, qcmd->zto, qsys->uuconf_zname, zsysdep_save_temp_file (qcmd->pseq)); ubuffree (zfree); } (void) fsysdep_did_work (qcmd->pseq); if (qtrans != NULL) usfree_send (qtrans); return TRUE; } /* This is called when we are ready to send the request to the remote system. We form the request and send it over. If the protocol does not support multiple channels, we start waiting for the response; otherwise we can start sending the file immediately. */ static boolean flocal_send_request (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; char *zsend; const char *znotify; char absize[20]; boolean fret; /* Make sure the file meets any remote size restrictions. */ if (qdaemon->cmax_receive != -1 && qdaemon->cmax_receive < qinfo->cbytes) return flocal_send_fail (qtrans, &qtrans->s, qdaemon->qsys, "too large for receiver"); /* Construct the notify string to send. If we are going to send a size or an execution command, it must be non-empty. */ znotify = qtrans->s.znotify; if (znotify == NULL) znotify = ""; if ((qdaemon->ifeatures & FEATURE_SIZES) != 0 || (qtrans->s.bcmd == 'E' && (qdaemon->ifeatures & FEATURE_EXEC) != 0)) { if (*znotify == '\0') znotify = "\"\""; } else { /* We don't need a notify string. Some crufty UUCP code can't handle a pair of double quotes. */ if (strcmp (znotify, "\"\"") == 0) znotify = ""; } /* Construct the size string to send. */ if ((qdaemon->ifeatures & FEATURE_SIZES) == 0 && (qtrans->s.bcmd != 'E' || (qdaemon->ifeatures & FEATURE_EXEC) == 0)) absize[0] = '\0'; else if ((qdaemon->ifeatures & FEATURE_V103) == 0) sprintf (absize, "0x%lx", (unsigned long) qinfo->cbytes); else sprintf (absize, "%ld", qinfo->cbytes); zsend = zbufalc (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + strlen (qtrans->s.ztemp) + strlen (znotify) + strlen (absize) + (qtrans->s.zcmd != NULL ? strlen (qtrans->s.zcmd) : 0) + 50); /* If this an execution request and the other side supports execution requests, we send an E command. Otherwise we send an S command. The case of an execution request when we are sending the fake execution file is handled just like an S request at this point. */ if (qtrans->s.bcmd == 'E' && (qdaemon->ifeatures & FEATURE_EXEC) != 0) { /* Send the string E zfrom zto zuser zoptions ztemp imode znotify size zcmd to the remote system. We put a '-' in front of the (possibly empty) options and a '0' in front of the mode. */ sprintf (zsend, "E %s %s %s -%s %s 0%o %s %s %s", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions, qtrans->s.ztemp, qtrans->s.imode, znotify, absize, qtrans->s.zcmd); } else { const char *zoptions, *zdummy; /* Send the string S zfrom zto zuser zoptions ztemp imode znotify to the remote system. We put a '-' in front of the (possibly empty) options and a '0' in front of the mode. If size negotiation is supported, we also send the size; in this case if znotify is empty we must send it as "". If this is really an execution request, we have to simplify the options string to remove the various execution options which may confuse the remote system. SVR4 expects a string "dummy" between the notify string and the size; I don't know why. */ if (qtrans->s.bcmd != 'E') zoptions = qtrans->s.zoptions; else if (strchr (qtrans->s.zoptions, 'C') != NULL) { /* This should set zoptions to "C", but at least one UUCP program gets confused by it. That means that it will fail in certain cases, but I suppose we might as well kowtow to compatibility. This shouldn't matter to any other program, I hope. */ zoptions = ""; } else zoptions = "c"; if ((qdaemon->ifeatures & FEATURE_SVR4) != 0) zdummy = " dummy "; else zdummy = " "; sprintf (zsend, "S %s %s %s -%s %s 0%o %s%s%s", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, zoptions, qtrans->s.ztemp, qtrans->s.imode, znotify, zdummy, absize); } fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, qtrans->iremote); ubuffree (zsend); if (! fret) { usfree_send (qtrans); return FALSE; } /* If we are using a protocol which can make multiple channels, then we can open and send the file whenever we are ready. This is because we will be able to distinguish the response by the channel it is directed to. This assumes that every protocol which supports multiple channels also supports sending the file position in mid-stream, since otherwise we would not be able to restart files. */ qtrans->fcmd = TRUE; qtrans->psendfn = flocal_send_open_file; qtrans->precfn = flocal_send_await_reply; if (qdaemon->qproto->cchans > 1) return fqueue_send (qdaemon, qtrans); else return fqueue_receive (qdaemon, qtrans); } /* This is called when a reply is received for the send request. As described at length above, if the protocol supports multiple channels we may be in the middle of sending the file, or we may even finished sending the file. */ static boolean flocal_send_await_reply (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; char bcmd; if (qtrans->s.bcmd == 'E' && (qdaemon->ifeatures & FEATURE_EXEC) != 0) bcmd = 'E'; else bcmd = 'S'; if (zdata[0] != bcmd || (zdata[1] != 'Y' && zdata[1] != 'N')) { ulog (LOG_ERROR, "%s: Bad response to %c request: \"%s\"", qtrans->s.zfrom, bcmd, zdata); usfree_send (qtrans); return FALSE; } if (zdata[1] == 'N') { const char *zerr; boolean fnever; fnever = TRUE; if (zdata[2] == '2') zerr = "permission denied by remote"; else if (zdata[2] == '4') { zerr = "remote cannot create work files"; fnever = FALSE; } else if (zdata[2] == '6') { zerr = "too large for remote now"; fnever = FALSE; } else if (zdata[2] == '7') { /* The file is too large to ever send. */ zerr = "too large for remote"; } else if (zdata[2] == '8') { /* The file was already received by the remote system. This is not an error, it just means that the ack from the remote was lost in the previous conversation, and there is no need to resend the file. */ zerr = NULL; } else zerr = "unknown reason"; if (! fnever) { if (qtrans->s.bcmd == 'E') ulog (LOG_ERROR, "Execution of \"%s\": %s", qtrans->s.zcmd, zerr); else ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); } else { if (! flocal_send_fail ((struct stransfer *) NULL, &qtrans->s, qdaemon->qsys, zerr)) return FALSE; } /* If the protocol does not support multiple channels, we can simply remove the transaction. Otherwise we must make sure the remote side knows that we have finished sending the file data. If we have already sent the entire file, there will be no confusion. */ if (qdaemon->qproto->cchans == 1 || qinfo->fsent) { usfree_send (qtrans); return TRUE; } else { qtrans->psendfn = flocal_send_cancelled; qtrans->precfn = NULL; qtrans->fsendfile = FALSE; return fqueue_send (qdaemon, qtrans); } } /* A number following the SY or EY is the file position to start sending from. If we are already sending the file, we must set the position accordingly. */ if (zdata[2] != '\0') { long cskip; cskip = strtol ((char *) (zdata + 2), (char **) NULL, 0); if (cskip > 0 && qtrans->ipos < cskip) { if (qtrans->fsendfile && ! qinfo->fsent) { if (! ffileseek (qtrans->e, cskip)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); usfree_send (qtrans); return FALSE; } } qtrans->ipos = cskip; } } /* Now queue up to send the file or to wait for the confirmation. We already set psendfn at the end of flocal_send_request. If the protocol supports multiple channels, we have already called fqueue_send; calling it again would move the request in the queue, which would make the log file a bit confusing. */ qtrans->precfn = fsend_await_confirm; if (qinfo->fsent) return fqueue_receive (qdaemon, qtrans); else if (qdaemon->qproto->cchans <= 1) return fqueue_send (qdaemon, qtrans); else return TRUE; } /* Open the file, if any, and prepare to send it. */ static boolean flocal_send_open_file (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; const char *zuser; /* If this is not a fake execution file, open it. */ if (qinfo->zexec == NULL) { /* If there is an ! in the user name, this is a remote request queued up by fremote_xcmd_init. */ zuser = qtrans->s.zuser; if (strchr (zuser, '!') != NULL) zuser = NULL; qtrans->e = esysdep_open_send (qdaemon->qsys, qinfo->zfile, ! qinfo->fspool, zuser); if (! ffileisopen (qtrans->e)) { (void) fmail_transfer (FALSE, qtrans->s.zuser, (const char *) NULL, "cannot open file", qtrans->s.zfrom, (const char *) NULL, qtrans->s.zto, qdaemon->qsys->uuconf_zname, zsysdep_save_temp_file (qtrans->s.pseq)); (void) fsysdep_did_work (qtrans->s.pseq); usfree_send (qtrans); /* Unfortunately, there is no way to cancel a file send after we've already put it in progress. So we have to return FALSE to drop the connection. */ return FALSE; } } /* If flocal_send_await_reply has received a reply with a file position, it will have set qtrans->ipos to the position at which to start. */ if (qtrans->ipos > 0) { if (qinfo->zexec != NULL) { if (qtrans->ipos > qtrans->cbytes) qtrans->ipos = qtrans->cbytes; } else { if (! ffileseek (qtrans->e, qtrans->ipos)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); usfree_send (qtrans); return FALSE; } } } /* We don't bother to log sending the execution file. */ if (qinfo->zexec == NULL) { const char *zsend; char *zalc; if (qtrans->s.bcmd != 'E') { zsend = qtrans->s.zfrom; zalc = NULL; } else { zalc = zbufalc (strlen (qtrans->s.zcmd) + sizeof " ()" + strlen (qtrans->s.zfrom)); sprintf (zalc, "%s (%s)", qtrans->s.zcmd, qtrans->s.zfrom); zsend = zalc; } qtrans->zlog = zbufalc (sizeof "Sending " + strlen (zsend)); sprintf (qtrans->zlog, "Sending %s", zsend); ubuffree (zalc); } if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE, qinfo->cbytes, &fhandled)) { usfree_send (qtrans); return FALSE; } if (fhandled) return TRUE; } if (qinfo->zexec != NULL) qtrans->psendfn = fsend_exec_file; else { qtrans->fsendfile = TRUE; qtrans->psendfn = fsend_file_end; } return fqueue_send (qdaemon, qtrans); } /* Cancel a file send by sending an empty buffer. This is only called for a protocol which supports multiple channels. It is needed so that both systems agree as to when a channel is no longer needed. */ static boolean flocal_send_cancelled (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { char *zdata; size_t cdata; boolean fret; zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); if (zdata == NULL) { usfree_send (qtrans); return FALSE; } fret = (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, (size_t) 0, qtrans->ilocal, qtrans->iremote, qtrans->ipos); usfree_send (qtrans); return fret; } /* A remote request to receive a file (meaning that we have to send a file). The sequence of functions calls is as follows: fremote_rec_file_init (open file) --> fqueue_remote fremote_rec_reply (send RY, call pffile) --> fqueue_send send file fsend_file_end (calls pffile) --> fqueue_receive fsend_await_confirm (waits for CY) */ boolean fremote_rec_file_init (qdaemon, qcmd, iremote) struct sdaemon *qdaemon; struct scmd *qcmd; int iremote; { const struct uuconf_system *qsys; char *zfile; long cbytes; unsigned int imode; openfile_t e; struct ssendinfo *qinfo; struct stransfer *qtrans; qsys = qdaemon->qsys; if (! qsys->uuconf_fsend_request) { ulog (LOG_ERROR, "%s: not permitted to send files to remote", qcmd->zfrom); return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); } if (fspool_file (qcmd->zfrom)) { ulog (LOG_ERROR, "%s: not permitted to send", qcmd->zfrom); return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); } zfile = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir); if (zfile != NULL) { char *zbased; zbased = zsysdep_add_base (zfile, qcmd->zto); ubuffree (zfile); zfile = zbased; } if (zfile == NULL) return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); if (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, TRUE, (const char *) NULL)) { ulog (LOG_ERROR, "%s: not permitted to send", zfile); ubuffree (zfile); return fremote_rec_fail (qdaemon, FAILURE_PERM, iremote); } /* If the file is larger than the amount of space the other side reported, we can't send it. Should we adjust this check based on the restart position? */ cbytes = csysdep_size (zfile); if (cbytes != -1 && ((qcmd->cbytes != -1 && qcmd->cbytes < cbytes) || (qdaemon->cremote_size != -1 && qdaemon->cremote_size < cbytes) || (qdaemon->cmax_receive != -1 && qdaemon->cmax_receive < cbytes))) { ulog (LOG_ERROR, "%s: too large to send", zfile); ubuffree (zfile); return fremote_rec_fail (qdaemon, FAILURE_SIZE, iremote); } imode = ixsysdep_file_mode (zfile); e = esysdep_open_send (qsys, zfile, TRUE, (const char *) NULL); if (! ffileisopen (e)) { ubuffree (zfile); return fremote_rec_fail (qdaemon, FAILURE_OPEN, iremote); } /* If the remote requested that the file send start from a particular position, arrange to do so. */ if (qcmd->ipos > 0) { if (! ffileseek (e, qcmd->ipos)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); ubuffree (zfile); return FALSE; } } qinfo = (struct ssendinfo *) xmalloc (sizeof (struct ssendinfo)); qinfo->zmail = NULL; qinfo->zfile = zfile; qinfo->cbytes = cbytes; qinfo->flocal = FALSE; qinfo->fspool = FALSE; qinfo->fsent = FALSE; qinfo->zexec = NULL; qtrans = qtransalc (qcmd); qtrans->psendfn = fremote_rec_reply; qtrans->iremote = iremote; qtrans->pinfo = (pointer) qinfo; qtrans->e = e; qtrans->ipos = qcmd->ipos; qtrans->s.imode = imode; return fqueue_remote (qdaemon, qtrans); } /* Reply to a receive request from the remote system, and prepare to start sending the file. */ static boolean fremote_rec_reply (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; char absend[50]; sprintf (absend, "RY 0%o 0x%lx", qtrans->s.imode, (unsigned long) qinfo->cbytes); if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, absend, qtrans->ilocal, qtrans->iremote)) { (void) ffileclose (qtrans->e); usfree_send (qtrans); return FALSE; } qtrans->zlog = zbufalc (sizeof "Sending " + strlen (qtrans->s.zfrom)); sprintf (qtrans->zlog, "Sending %s", qtrans->s.zfrom); if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, TRUE, TRUE, qinfo->cbytes, &fhandled)) { usfree_send (qtrans); return FALSE; } if (fhandled) return TRUE; } qtrans->fsendfile = TRUE; qtrans->psendfn = fsend_file_end; qtrans->precfn = fsend_await_confirm; return fqueue_send (qdaemon, qtrans); } /* If we can't send a file as requested by the remote system, queue up a failure reply which will be sent when possible. */ static boolean fremote_rec_fail (qdaemon, twhy, iremote) struct sdaemon *qdaemon; enum tfailure twhy; int iremote; { enum tfailure *ptinfo; struct stransfer *qtrans; ptinfo = (enum tfailure *) xmalloc (sizeof (enum tfailure)); *ptinfo = twhy; qtrans = qtransalc ((struct scmd *) NULL); qtrans->psendfn = fremote_rec_fail_send; qtrans->iremote = iremote; qtrans->pinfo = (pointer) ptinfo; return fqueue_remote (qdaemon, qtrans); } /* Send a failure string for a receive command to the remote system; this is called when we are ready to reply to the command. */ static boolean fremote_rec_fail_send (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { enum tfailure *ptinfo = (enum tfailure *) qtrans->pinfo; const char *z; boolean fret; switch (*ptinfo) { case FAILURE_PERM: case FAILURE_OPEN: z = "RN2"; break; case FAILURE_SIZE: z = "RN6"; break; default: z = "RN"; break; } fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, z, qtrans->ilocal, qtrans->iremote); xfree (qtrans->pinfo); utransfree (qtrans); return fret; } /* This is called when the main loop has finished sending a file. It prepares to wait for a response from the remote system. Note that if this is a local request and the protocol supports multiple channels, we may not even have received a confirmation of the send request. */ static boolean fsend_file_end (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; if (qdaemon->qproto->pffile != NULL) { boolean fhandled; if (! (*qdaemon->qproto->pffile) (qdaemon, qtrans, FALSE, TRUE, (long) -1, &fhandled)) { usfree_send (qtrans); return FALSE; } if (fhandled) return TRUE; } qinfo->fsent = TRUE; /* qtrans->precfn should have been set by a previous function. */ qtrans->fcmd = TRUE; return fqueue_receive (qdaemon, qtrans); } /* Handle the confirmation string received after sending a file. */ /*ARGSUSED*/ static boolean fsend_await_confirm (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; boolean fnever; const char *zerr; if (qinfo->zexec == NULL) (void) ffileclose (qtrans->e); fnever = FALSE; if (zdata[0] != 'C' || (zdata[1] != 'Y' && zdata[1] != 'N')) { zerr = "bad confirmation from remote"; ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata); } else if (zdata[1] == 'N') { fnever = TRUE; if (zdata[2] == '5') { zerr = "file could not be stored in final location"; ulog (LOG_ERROR, "%s: %s", qtrans->s.zfrom, zerr); } else { zerr = "file send failed for unknown reason"; ulog (LOG_ERROR, "%s: %s \"%s\"", qtrans->s.zfrom, zerr, zdata); } } else { zerr = NULL; /* If we receive CYM, it means that the other side wants us to hang up so that they can send us something. The fhangup_requested field is checked in the main loop. */ if (zdata[2] == 'M' && qdaemon->fmaster) { DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fsend_await_confirm: Remote has requested transfer of control"); qdaemon->fhangup_requested = TRUE; } } ustats (zerr == NULL, qtrans->s.zuser, qdaemon->qsys->uuconf_zname, TRUE, qtrans->cbytes, qtrans->isecs, qtrans->imicros, qdaemon->fmaster); if (zerr == NULL) { /* If this is an execution request, and the remote system doesn't support execution requests, we have to set up the fake execution file and loop around again. */ if (qtrans->s.bcmd == 'E' && (qdaemon->ifeatures & FEATURE_EXEC) == 0 && qinfo->zexec == NULL) return fsend_exec_file_init (qtrans, qdaemon); /* Send mail about the transfer if requested. */ if (qinfo->zmail != NULL && *qinfo->zmail != '\0') (void) fmail_transfer (TRUE, qtrans->s.zuser, qinfo->zmail, (const char *) NULL, qtrans->s.zfrom, (const char *) NULL, qtrans->s.zto, qdaemon->qsys->uuconf_zname, (const char *) NULL); if (qtrans->s.pseq != NULL) (void) fsysdep_did_work (qtrans->s.pseq); } else { /* If the file send failed, we only try to save the file and send mail if it was requested locally and it will never succeed. We send mail to qinfo->zmail if set, otherwise to qtrans->s.zuser. I hope this is reasonable. */ if (fnever && qinfo->flocal) { (void) fmail_transfer (FALSE, qtrans->s.zuser, qinfo->zmail, zerr, qtrans->s.zfrom, (const char *) NULL, qtrans->s.zto, qdaemon->qsys->uuconf_zname, zsysdep_save_temp_file (qtrans->s.pseq)); (void) fsysdep_did_work (qtrans->s.pseq); } } usfree_send (qtrans); return TRUE; } /* Prepare to send an execution file to a system which does not support execution requests. We build the execution file in memory, and then call flocal_send_request as though we were sending a real file. Instead of sending a file, the code in flocal_send_open_file will arrange to call fsend_exec_file which will send data out of the buffer we have created. */ static boolean fsend_exec_file_init (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; char *zxqtfile; char abtname[CFILE_NAME_LEN]; char abxname[CFILE_NAME_LEN]; char *z; size_t calc, clen; z = NULL; calc = 0; clen = 0; usadd_exec_line (&z, &calc, &clen, 'U', qtrans->s.zuser, qdaemon->zlocalname); usadd_exec_line (&z, &calc, &clen, 'F', qtrans->s.zto, ""); usadd_exec_line (&z, &calc, &clen, 'I', qtrans->s.zto, ""); if (strchr (qtrans->s.zoptions, 'N') != NULL) usadd_exec_line (&z, &calc, &clen, 'N', "", ""); if (strchr (qtrans->s.zoptions, 'Z') != NULL) usadd_exec_line (&z, &calc, &clen, 'Z', "", ""); if (strchr (qtrans->s.zoptions, 'R') != NULL) usadd_exec_line (&z, &calc, &clen, 'R', qtrans->s.znotify, ""); if (strchr (qtrans->s.zoptions, 'e') != NULL) usadd_exec_line (&z, &calc, &clen, 'e', "", ""); usadd_exec_line (&z, &calc, &clen, 'C', qtrans->s.zcmd, ""); qinfo->zexec = z; qinfo->cbytes = clen; zxqtfile = zsysdep_data_file_name (qdaemon->qsys, qdaemon->zlocalname, BDEFAULT_UUX_GRADE, TRUE, abtname, (char *) NULL, abxname); if (zxqtfile == NULL) { usfree_send (qtrans); return FALSE; } ubuffree (zxqtfile); ubuffree ((char *) qtrans->s.zfrom); qtrans->s.zfrom = zbufcpy (abtname); ubuffree ((char *) qtrans->s.zto); qtrans->s.zto = zbufcpy (abxname); ubuffree ((char *) qtrans->s.zoptions); qtrans->s.zoptions = zbufcpy ("C"); ubuffree ((char *) qtrans->s.ztemp); qtrans->s.ztemp = zbufcpy (abtname); qtrans->psendfn = flocal_send_request; qtrans->precfn = NULL; qtrans->ipos = 0; qtrans->cbytes = 0; qtrans->isecs = 0; qtrans->imicros = 0; qinfo->fsent = FALSE; return fqueue_send (qdaemon, qtrans); } /* Add a line to the fake execution file. */ static void usadd_exec_line (pz, pcalc, pclen, bcmd, z1, z2) char **pz; size_t *pcalc; size_t *pclen; int bcmd; const char *z1; const char *z2; { size_t c1, c2; char *znew; c1 = strlen (z1); c2 = strlen (z2); if (*pclen + c1 + c2 + 4 >= *pcalc) { *pcalc += c1 + c2 + 100; znew = zbufalc (*pcalc); if (*pclen > 0) { memcpy (znew, *pz, *pclen); ubuffree (*pz); } *pz = znew; } znew = *pz + *pclen; *znew++ = bcmd; if (*z1 != '\0') { *znew++ = ' '; memcpy (znew, z1, c1); znew += c1; if (*z2 != '\0') { *znew++ = ' '; memcpy (znew, z2, c2); znew += c2; } } /* In some bizarre non-Unix case we might have to worry about the newline here. We don't know how a newline is normally written out to a file, but whatever is written to a file is what we will normally transfer. If that is not simply \n then this fake execution file will not look like other execution files. */ *znew++ = '\n'; *pclen = znew - *pz; } /* This routine is called to send the contents of the fake execution file. Normally file data is sent by the floop routine in trans.c, but since we don't have an actual file we must do it here. This routine sends the complete buffer, followed by a zero length packet, and then calls fsend_file_end. */ static boolean fsend_exec_file (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { struct ssendinfo *qinfo = (struct ssendinfo *) qtrans->pinfo; char *zdata; size_t cdata; size_t csend; zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); if (zdata == NULL) { usfree_send (qtrans); return FALSE; } csend = qinfo->cbytes - qtrans->ipos; if (csend > cdata) csend = cdata; memcpy (zdata, qinfo->zexec + qtrans->ipos, csend); if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, csend, qtrans->ilocal, qtrans->iremote, qtrans->ipos)) { usfree_send (qtrans); return FALSE; } qtrans->cbytes += csend; qtrans->ipos += csend; if (csend == 0) return fsend_file_end (qtrans, qdaemon); /* Leave the job on the send queue. */ return TRUE; } 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) uucp-1.04/sysh.unx1004440004150000170000003565005337263514011117 037777777777 1 0 /* sysh.unx -*- C -*- The header file for the UNIX system dependent routines. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #ifndef SYSH_UNX_H #define SYSH_UNX_H #if ANSI_C /* These structures are used in prototypes but are not defined in this header file. */ struct uuconf_system; struct sconnection; #endif /* Make sure the defines do not conflict. These are in this file because they are Unix dependent. */ #if HAVE_V2_LOCKFILES + HAVE_HDB_LOCKFILES + HAVE_SCO_LOCKFILES + HAVE_SVR4_LOCKFILES + HAVE_COHERENT_LOCKFILES != 1 #error LOCKFILES define not set or duplicated #endif /* SCO and SVR4 lockfiles are basically just like HDB lockfiles. */ #if HAVE_SCO_LOCKFILES || HAVE_SVR4_LOCKFILES #undef HAVE_HDB_LOCKFILES #define HAVE_HDB_LOCKFILES 1 #endif #if HAVE_BSD_TTY + HAVE_SYSV_TERMIO + HAVE_POSIX_TERMIOS != 1 #error Terminal driver define not set or duplicated #endif #if SPOOLDIR_V2 + SPOOLDIR_BSD42 + SPOOLDIR_BSD43 + SPOOLDIR_HDB + SPOOLDIR_ULTRIX + SPOOLDIR_SVR4 + SPOOLDIR_TAYLOR != 1 #error Spool directory define not set or duplicated #endif /* If setreuid is broken, don't use it. */ #if HAVE_BROKEN_SETREUID #undef HAVE_SETREUID #define HAVE_SETREUID 0 #endif /* Get some standard types from the configuration header file. */ #ifdef PID_T typedef PID_T pid_t; #endif #ifdef UID_T typedef UID_T uid_t; #endif #ifdef GID_T typedef GID_T gid_t; #endif #ifdef OFF_T typedef OFF_T off_t; #endif /* On Unix, binary files are the same as text files. */ #define BINREAD "r" #define BINWRITE "w" /* If we have sigaction, we can force system calls to not be restarted. */ #if HAVE_SIGACTION #undef HAVE_RESTARTABLE_SYSCALLS #define HAVE_RESTARTABLE_SYSCALLS 0 #endif /* If we have sigvec, and we have HAVE_SIGVEC_SV_FLAGS, and SV_INTERRUPT is defined, we can force system calls to not be restarted (signal.h is included by uucp.h before this point, so SV_INTERRUPT will be defined by now if it it ever is). */ #if HAVE_SIGVEC && HAVE_SIGVEC_SV_FLAGS #ifdef SV_INTERRUPT #undef HAVE_RESTARTABLE_SYSCALLS #define HAVE_RESTARTABLE_SYSCALLS 0 #endif #endif /* If we were cross-configured, we will have a value of -1 for HAVE_RESTARTABLE_SYSCALLS. In this case, we try to guess what the correct value should be. Yuck. If we have sigvec, but neither of the above cases applied (which we know because they would have changed HAVE_RESTARTABLE_SYSCALLS) then we are probably on 4.2BSD and system calls are automatically restarted. Otherwise, assume that they are not. */ #if HAVE_RESTARTABLE_SYSCALLS == -1 #undef HAVE_RESTARTABLE_SYSCALLS #if HAVE_SIGVEC #define HAVE_RESTARTABLE_SYSCALLS 1 #else #define HAVE_RESTARTABLE_SYSCALLS 0 #endif #endif /* HAVE_RESTARTABLE_SYSCALLS == -1 */ /* We don't handle sigset in combination with restartable system calls, so we check for it although this combination will never happen. */ #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && HAVE_SIGSET #if HAVE_RESTARTABLE_SYSCALLS #undef HAVE_SIGSET #define HAVE_SIGSET 0 #endif #endif /* If we don't have restartable system calls, we can ignore fsysdep_catch, usysdep_start_catch and usysdep_end_catch. Otherwise fsysdep_catch has to do a setjmp. */ #if ! HAVE_RESTARTABLE_SYSCALLS #define fsysdep_catch() (TRUE) #define usysdep_start_catch() #define usysdep_end_catch() #define CATCH_PROTECT #else /* HAVE_RESTARTABLE_SYSCALLS */ #if HAVE_SETRET && ! HAVE_SIGSETJMP #include #define setjmp setret #define longjmp longret #define jmp_buf ret_buf #else /* ! HAVE_SETRET || HAVE_SIGSETJMP */ #include #if HAVE_SIGSETJMP #undef setjmp #undef longjmp #undef jmp_buf #define setjmp(s) sigsetjmp ((s), TRUE) #define longjmp siglongjmp #define jmp_buf sigjmp_buf #endif /* HAVE_SIGSETJMP */ #endif /* ! HAVE_SETRET || HAVE_SIGSETJMP */ extern volatile sig_atomic_t fSjmp; extern volatile jmp_buf sSjmp_buf; #define fsysdep_catch() (setjmp (sSjmp_buf) == 0) #define usysdep_start_catch() (fSjmp = TRUE) #define usysdep_end_catch() (fSjmp = FALSE) #define CATCH_PROTECT volatile #endif /* HAVE_RESTARTABLE_SYSCALLS */ /* Get definitions for the terminal driver. */ #if HAVE_BSD_TTY #include struct sbsd_terminal { struct sgttyb stty; struct tchars stchars; struct ltchars sltchars; }; typedef struct sbsd_terminal sterminal; #define fgetterminfo(o, q) \ (ioctl ((o), TIOCGETP, &(q)->stty) == 0 \ && ioctl ((o), TIOCGETC, &(q)->stchars) == 0 \ && ioctl ((o), TIOCGLTC, &(q)->sltchars) == 0) #define fsetterminfo(o, q) \ (ioctl ((o), TIOCSETN, &(q)->stty) == 0 \ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0) #define fsetterminfodrain(o, q) \ (ioctl ((o), TIOCSETP, &(q)->stty) == 0 \ && ioctl ((o), TIOCSETC, &(q)->stchars) == 0 \ && ioctl ((o), TIOCSLTC, &(q)->sltchars) == 0) #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO #include typedef struct termio sterminal; #define fgetterminfo(o, q) (ioctl ((o), TCGETA, (q)) == 0) #define fsetterminfo(o, q) (ioctl ((o), TCSETA, (q)) == 0) #define fsetterminfodrain(o, q) (ioctl ((o), TCSETAW, (q)) == 0) #endif /* HAVE_SYSV_TERMIO */ #if HAVE_POSIX_TERMIOS #include typedef struct termios sterminal; #define fgetterminfo(o, q) (tcgetattr ((o), (q)) == 0) #define fsetterminfo(o, q) (tcsetattr ((o), TCSANOW, (q)) == 0) #define fsetterminfodrain(o, q) (tcsetattr ((o), TCSADRAIN, (q)) == 0) /* On some systems it is not possible to include both and in the same source files; I don't really know why. On such systems, we pretend that we don't have . */ #if ! HAVE_TERMIOS_AND_SYS_IOCTL_H #undef HAVE_SYS_IOCTL_H #define HAVE_SYS_IOCTL_H 0 #endif #endif /* HAVE_POSIX_TERMIOS */ /* The root directory (this is needed by the system independent stuff as the default for local-send). */ #define ZROOTDIR "/" /* The name of the execution directory within the spool directory (this is need by the system independent uuxqt.c). */ #define XQTDIR ".Xqtdir" /* The name of the directory in which we preserve file transfers that failed. */ #define PRESERVEDIR ".Preserve" /* The length of the sequence number used in a file name. */ #define CSEQLEN (4) /* Get some standard definitions. Avoid including the files more than once--some might have been included by uucp.h. */ #if USE_STDIO && HAVE_UNISTD_H #include #endif #if ! USE_TYPES_H #include #endif #include /* Get definitions for the file permission bits. */ #ifndef S_IRWXU #define S_IRWXU 0700 #endif #ifndef S_IRUSR #define S_IRUSR 0400 #endif #ifndef S_IWUSR #define S_IWUSR 0200 #endif #ifndef S_IXUSR #define S_IXUSR 0100 #endif #ifndef S_IRWXG #define S_IRWXG 0070 #endif #ifndef S_IRGRP #define S_IRGRP 0040 #endif #ifndef S_IWGRP #define S_IWGRP 0020 #endif #ifndef S_IXGRP #define S_IXGRP 0010 #endif #ifndef S_IRWXO #define S_IRWXO 0007 #endif #ifndef S_IROTH #define S_IROTH 0004 #endif #ifndef S_IWOTH #define S_IWOTH 0002 #endif #ifndef S_IXOTH #define S_IXOTH 0001 #endif #ifndef S_ISDIR #ifdef S_IFDIR #define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) #else /* ! defined (S_IFDIR) */ #define S_ISDIR(i) (((i) & 0170000) == 040000) #endif /* ! defined (S_IFDIR) */ #endif /* ! defined (S_ISDIR) */ /* We need the access macros. */ #ifndef R_OK #define R_OK 4 #define W_OK 2 #define X_OK 1 #define F_OK 0 #endif /* ! defined (R_OK) */ /* We create files with these modes (should this be configurable?). */ #define IPRIVATE_FILE_MODE (S_IRUSR | S_IWUSR) #define IPUBLIC_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* We create directories with this mode (should this be configurable?). */ #define IDIRECTORY_MODE (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) #define IPUBLIC_DIRECTORY_MODE (S_IRWXU | S_IRWXG | S_IRWXO) #if ! HAVE_OPENDIR /* Define some structures to use if we don't have opendir, etc. These will only work if we have the old Unix filesystem, with a 2 byte inode and a 14 byte filename. */ #include struct dirent { char d_name[DIRSIZ + 1]; }; typedef struct { int o; struct dirent s; } DIR; extern DIR *opendir P((const char *zdir)); extern struct dirent *readdir P((DIR *)); extern int closedir P((DIR *)); #endif /* ! HAVE_OPENDIR */ #if ! HAVE_FTW_H /* If there is no , define the ftw constants. */ #define FTW_F (0) #define FTW_D (1) #define FTW_DNR (2) #define FTW_NS (3) #endif /* ! HAVE_FTW_H */ /* This structure holds the system dependent information we keep for a connection. This is used by the TCP and TLI code. */ struct ssysdep_conn { /* File descriptor. */ int o; /* Device name. */ char *zdevice; /* File status flags. */ int iflags; /* File status flags for descriptor 1 (-1 if not standard input). */ int istdout_flags; /* Hold the real descriptor when using a dialer device. */ int ohold; /* TRUE if this is a terminal and the remaining fields are valid. */ boolean fterminal; /* TRUE if this is a TLI descriptor. */ boolean ftli; /* Baud rate. */ long ibaud; /* Original terminal settings. */ sterminal sorig; /* Current terminal settings. */ sterminal snew; #if HAVE_COHERENT_LOCKFILES /* On Coherent we need to hold on to the real port name which will be used to enable the port. Ick. */ char *zenable; #endif }; /* These functions do I/O and chat scripts to a port. They are called by the TCP and TLI routines. */ extern boolean fsysdep_conn_read P((struct sconnection *qconn, char *zbuf, size_t *pclen, size_t cmin, int ctimeout, boolean freport)); extern boolean fsysdep_conn_write P((struct sconnection *qconn, const char *zbuf, size_t clen)); extern boolean fsysdep_conn_io P((struct sconnection *qconn, const char *zwrite, size_t *pcwrite, char *zread, size_t *pcread)); extern boolean fsysdep_conn_chat P((struct sconnection *qconn, char **pzprog)); /* Set a signal handler. */ extern void usset_signal P((int isig, RETSIGTYPE (*pfn) P((int)), boolean fforce, boolean *pfignored)); /* Default signal handler. This sets the appropriate element of the afSignal array. If system calls are automatically restarted, it may do a longjmp to an fsysdep_catch. */ extern RETSIGTYPE ussignal P((int isig)); /* Try to fork, repeating several times. */ extern pid_t ixsfork P((void)); /* Spawn a job. Returns the process ID of the spawned job or -1 on error. The following macros may be passed in aidescs. */ /* Set descriptor to /dev/null. */ #define SPAWN_NULL (-1) /* Set element of aidescs to a pipe for caller to read from. */ #define SPAWN_READ_PIPE (-2) /* Set element of aidescs to a pipe for caller to write to. */ #define SPAWN_WRITE_PIPE (-3) extern pid_t ixsspawn P((const char **pazargs, int *aidescs, boolean fkeepuid, boolean fkeepenv, const char *zchdir, boolean fnosigs, boolean fshell, const char *zpath, const char *zuu_machine, const char *zuu_user)); /* Do a form of popen using ixsspawn. */ extern FILE *espopen P((const char **pazargs, boolean frd, pid_t *pipid)); /* Wait for a particular process to finish, returning the exit status. The process ID should be pid_t, but we can't put that in a prototype. */ extern int ixswait P((unsigned long ipid, const char *zreport)); /* Find a spool file in the spool directory. For a local file, the bgrade argument is the grade of the file. This is needed for SPOOLDIR_SVR4. */ extern char *zsfind_file P((const char *zsimple, const char *zsystem, int bgrade)); /* Return the grade given a sequence number. */ extern char bsgrade P((pointer pseq)); /* Lock a string. */ extern boolean fsdo_lock P((const char *, boolean fspooldir, boolean *pferr)); /* Unlock a string. */ extern boolean fsdo_unlock P((const char *, boolean fspooldir)); /* Check access for a particular user name, or NULL to check access for any user. */ extern boolean fsuser_access P((const struct stat *, int imode, const char *zuser)); /* Stick two directories and a file name together. */ extern char *zsappend3 P((const char *zdir1, const char *zdir2, const char *zfile)); /* Stick three directories and a file name together. */ extern char *zsappend4 P((const char *zdir1, const char *zdir2, const char *zdir3, const char *zfile)); /* Get a temporary file name. */ extern char *zstemp_file P((const struct uuconf_system *qsys)); /* Get a command file name. */ extern char *zscmd_file P((const struct uuconf_system *qsys, int bgrade)); /* Get a jobid from a system, a file name, and a grade. */ extern char *zsfile_to_jobid P((const struct uuconf_system *qsys, const char *zfile, int bgrade)); /* Get a file name from a jobid. This also returns the associated system in *pzsystem and the grade in *pbgrade. */ extern char *zsjobid_to_file P((const char *zid, char **pzsystem, char *pbgrade)); /* See whether there is a spool directory for a system when using SPOOLDIR_ULTRIX. */ extern boolean fsultrix_has_spool P((const char *zsystem)); #if HAVE_COHERENT_LOCKFILES /* Lock a coherent tty. */ extern boolean lockttyexist P((const char *z)); extern boolean fscoherent_disable_tty P((const char *zdevice, char **pzenable)); #endif /* Some replacements for standard Unix functions. */ #if ! HAVE_DUP2 extern int dup2 P((int oold, int onew)); #endif #if ! HAVE_FTW extern int ftw P((const char *zdir, int (*pfn) P((const char *zfile, const struct stat *qstat, int iflag)), int cdescriptors)); #endif #if ! HAVE_GETCWD && ! HAVE_GETWD extern char *getcwd P((char *zbuf, size_t cbuf)); #endif #if ! HAVE_MKDIR extern int mkdir P((const char *zdir, int imode)); #endif #if ! HAVE_RENAME extern int rename P((const char *zold, const char *znew)); #endif #if ! HAVE_RMDIR extern int rmdir P((const char *zdir)); #endif /* The working directory from which the program was run (this is set by usysdep_initialize if called with INIT_GETCWD). */ extern char *zScwd; /* The spool directory name. */ extern const char *zSspooldir; /* The lock directory name. */ extern const char *zSlockdir; /* The local UUCP name (needed for some spool directory stuff). */ extern const char *zSlocalname; #endif /* ! defined (SYSH_UNX_H) */ ver. */ #if HAVE_BSD_TTY #include struct sbsd_terminal { struct sgttyb sttuucp-1.04/system.h1004440004150000170000013216205337263515011067 037777777777 1 0 /* system.h Header file for system dependent stuff in the Taylor UUCP package. This file is not itself system dependent. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #ifndef SYSTEM_H #define SYSTEM_H #if ANSI_C /* These structures are used in prototypes but are not defined in this header file. */ struct tm; struct uuconf_system; struct uuconf_port; struct sconnection; struct sstatus; struct scmd; #endif /* Any function which returns an error should also report an error message, unless otherwise indicated. Any function that returns a char *, rather than a const char *, is returning a pointer to a buffer allocated by zbufalc which must be freed using ubuffree, unless otherwise indicated. */ /* The maximum length of a remote system name. */ extern size_t cSysdep_max_name_len; /* Initialize. If something goes wrong, this routine should just exit. The flag argument is 0, or a combination of any of the following flags. */ /* This program needs to know the current working directory. This is used because on Unix it can be expensive to determine the current working directory (some versions of getcwd fork a process), but in most cases we don't need to know it. However, we are going to chdir to the spool directory (unless INIT_CHDIR is set), so we have to get the cwd now if we are ever going to get it. Both uucp and uux use the function fsysdep_needs_cwd to determine whether they will need the current working directory, and pass the argument to usysdep_initialize appropriately. There's probably a cleaner way to handle this, but this will suffice for now. */ #define INIT_GETCWD (01) /* This program should not chdir to the spool directory. This may only make sense on Unix. It is set by cu. */ #define INIT_NOCHDIR (02) /* This program needs special access to the spool directories. That means, on Unix, this program is normally installed setuid. */ #define INIT_SUID (04) extern void usysdep_initialize P((pointer puuconf, int iflags)); /* Exit the program. The fsuccess argument indicates whether to return an indication of success or failure to the outer environment. This routine should not return. */ extern void usysdep_exit P((boolean fsuccess)); /* Called when a non-standard configuration file is being used, to avoid handing out privileged access. If it returns FALSE, default configuration file will be used. This is called before the usysdep_initialize function is called. */ extern boolean fsysdep_other_config P((const char *)); /* Detach from the controlling terminal. This probably only makes sense on Unix. It is called by uucico to try to get the modem port as a controlling terminal. It is also called by uucico before it starts up uuxqt, so that uuxqt will be a complete daemon. */ extern void usysdep_detach P((void)); /* Get the local node name if it is not specified in the configuration files. Returns NULL on error; otherwise the return value should point to a static buffer. */ extern const char *zsysdep_localname P((void)); /* Get the login name. This is used when uucico is started up with no arguments in slave mode, which causes it to assume that somebody has logged in. It also used by uucp and uux for recording the user name. This may not return NULL. The return value should point to a static buffer. */ extern const char *zsysdep_login_name P((void)); /* Set a signal handler for a signal. If the signal occurs, the appropriate element of afSignal should be set to the signal number (see the declaration of afSignal in uucp.h). This routine might be able to just use signal, but Unix requires more complex handling. This is called before usysdep_initialize. */ extern void usysdep_signal P((int isig)); /* Catch a signal. This is actually defined as a macro in the system dependent header file, and the prototype here just indicates how it should be called. It is called before a routine which must exit if a signal occurs, and is expected to set do a setjmp (which is why it must be a macro). It is actually only called in one place in the system independent code, before the call to read stdin in uux. This is needed to handle 4.2 BSD restartable system calls, which require a longjmp. On systems which don't need to do setjmp/longjmp around system calls, this can be redefined in sysdep.h to TRUE. It should return TRUE if the routine should proceed, or FALSE if a signal occurred. After having this return TRUE, usysdep_start_catch should be used to start catching the signal; this basically tells the signal handler that it's OK to do the longjmp, if fsysdep_catch did not already do so. */ #ifndef fsysdep_catch extern boolean fsysdep_catch P((void)); #endif /* Start catching a signal. This is called after fsysdep_catch to tell the signal handler to go ahead and do the longjmp. This may be implemented as a macro in sysdep.h. */ #ifndef usysdep_start_catch extern void usysdep_start_catch P((void)); #endif /* Stop catching a signal. This is called when it is no longer necessary for fsysdep_catch to handle signals. This may be implemented as a macro in sysdep.h. */ #ifndef usysdep_end_catch extern void usysdep_end_catch P((void)); #endif /* Link two files. On Unix this should attempt the link. If it succeeds it should return TRUE with *pfworked set to TRUE. If the link fails because it must go across a device, it should return TRUE with *pfworked set to FALSE. If the link fails for some other reason, it should log an error message and return FALSE. On a system which does not support links to files, this should just return TRUE with *pfworked set to FALSE. */ extern boolean fsysdep_link P((const char *zfrom, const char *zto, boolean *pfworked)); /* Get the port name. This is used when uucico is started up in slave mode to figure out which port was used to call in so that it can determine any appropriate protocol parameters. This may return NULL if the port cannot be determined, which will just mean that no protocol parameters are applied. The name returned should be the sort of name that would appear in the port file. This should set *pftcp_port to TRUE if it can determine that the port is a TCP connection rather than a normal serial port. The return value (if not NULL) should point to a static buffer. */ extern const char *zsysdep_port_name P((boolean *pftcp_port)); /* Expand a file name on the local system. On Unix, if the zfile argument begins with ~user/ it goes in that users home directory, and if it begins with ~/ it goes in the public directory (the public directory is passed to this routine, since each system may have its own public directory). Similar conventions may be desirable on other systems. This should always return an absolute path name, probably in the public directory. It should return NULL on error; otherwise the return value should be allocated using zbufcpy or zbufalc. */ extern char *zsysdep_local_file P((const char *zname, const char *zpubdir)); /* Return whether a file name is in a directory, and check for read or write access. This should check whether zfile is within zdir (or is zdir itself). If it is not, it should return FALSE. If zfile is in zdir, then fcheck indicates whether further checking should be done. If fcheck is FALSE, no further checking is done. Otherwise, if freadable is TRUE the user zuser should have search access to all directories from zdir down to zfile and should have read access on zfile itself (if zfile does not exist, or is not a regular file, this function may return FALSE but does not have to). If freadable is FALSE, the user zuser should have search access to all directories from zdir down to zfile and should have write access on zfile (which may be a directory, or may not actually exist, which is acceptable). The zuser argument may be NULL, in which case the check should be made for any user, not just zuser. There is no way for this function to return error. */ extern boolean fsysdep_in_directory P((const char *zfile, const char *zdir, boolean fcheck, boolean freadable, const char *zuser)); /* Return TRUE if a file exists, FALSE otherwise. There is no way to return error. */ extern boolean fsysdep_file_exists P((const char *zfile)); /* Start up a program. The code expects fsysdep_run to return after doing a fork, but at least for now everything will work fine if it does not (on a system which does not support forking). The three string arguments may be catenated together to form the program to execute; I did it this way to make it easy to call execl(2), and because I never needed more than two arguments. The program will always be "uucico" or "uuxqt". The return value will be passed directly to usysdep_exit, and should be TRUE on success, FALSE on error. */ extern boolean fsysdep_run P((const char *zprogram, const char *zarg1, const char *zarg2)); /* Send a mail message. This function will be passed an array of strings. All necessary newlines are already included; the strings should simply be concatenated together to form the mail message. It should return FALSE on error, although the return value is often ignored. */ extern boolean fsysdep_mail P((const char *zto, const char *zsubject, int cstrs, const char **paz)); /* Get the time in seconds since some epoch. The actual epoch is unimportant, so long as the time values are consistent across program executions and the value is never negative. If the pimicros argument is not NULL, it should be set to the number of microseconds (if this is not available, *pimicros should be set to zero). */ extern long ixsysdep_time P((long *pimicros)); /* Get the time in seconds and microseconds (millionths of a second) since some epoch. The actual epoch is not important, and it may change in between program invocations; this is provided because on Unix the times function may be used. If microseconds can not be determined, *pimicros can just be set to zero. */ extern long ixsysdep_process_time P((long *pimicros)); /* Parse the value returned by ixsysdep_time into a struct tm. I assume that this structure is defined in . This is basically just localtime, except that the ANSI function takes a time_t which may not be what is returned by ixsysdep_time. */ extern void usysdep_localtime P((long itime, struct tm *q)); /* Sleep for a number of seconds. */ extern void usysdep_sleep P((int cseconds)); /* Pause for half a second, or 1 second if subsecond sleeps are not possible. */ extern void usysdep_pause P((void)); /* Lock a remote system. This should return FALSE if the system is already locked (no error should be reported). */ extern boolean fsysdep_lock_system P((const struct uuconf_system *qsys)); /* Unlock a remote system. This should return FALSE on error (although the return value is generally ignored). */ extern boolean fsysdep_unlock_system P((const struct uuconf_system *qsys)); /* Get the conversation sequence number for a remote system, and increment it for next time. This should return -1 on error. */ extern long ixsysdep_get_sequence P((const struct uuconf_system *qsys)); /* Get the status of a remote system. This should return FALSE on error. Otherwise it should set *qret to the status. If no status information is available, this should set *qret to sensible values and return TRUE. If pfnone is not NULL, then it should be set to TRUE if no status information was available or FALSE otherwise. */ extern boolean fsysdep_get_status P((const struct uuconf_system *qsys, struct sstatus *qret, boolean *pfnone)); /* Set the status of a remote system. This should return FALSE on error. The system will be locked before this call is made. */ extern boolean fsysdep_set_status P((const struct uuconf_system *qsys, const struct sstatus *qset)); /* See whether a remote system is permitted to log in. This is just to support the remote.unknown shell script for HDB. The zscript argument is the script name, as return by uuconf_remote_unknown. The zsystem argument is the name given by the remote system. If the system is not permitted to log in, this function should log an error and return FALSE. */ extern boolean fsysdep_unknown_caller P((const char *zscript, const char *zsystem)); /* Check whether there is work for a remote system. It should return TRUE if there is work, FALSE otherwise; there is no way to indicate an error. */ extern boolean fsysdep_has_work P((const struct uuconf_system *qsys)); /* Initialize the work scan. This will be called before fsysdep_get_work. The bgrade argument is the minimum grade of execution files that should be considered (e.g. a bgrade of 'd' will allow all grades from 'A' to 'Z' and 'a' to 'd'). This function should return FALSE on error. */ extern boolean fsysdep_get_work_init P((const struct uuconf_system *qsys, int bgrade)); /* Get the next command to be executed for a remote system. The bgrade argument will be the same as for fsysdep_get_work_init; probably only one of these functions will use it, namely the function for which it is more convenient. This should return FALSE on error. The structure pointed to by qcmd should be filled in. The strings may point into a static buffer; they will be copied out if necessary. If there is no more work, this should set qcmd->bcmd to 'H' and return TRUE. This should set qcmd->pseq to something which can be passed to fsysdep_did_work to remove the job from the queue when it has been completed. This may set qcmd->bcmd to 'P' to represent a poll file; the main code will just pass the pseq element of such a structure to fsysdep_did_work if the system is called. */ extern boolean fsysdep_get_work P((const struct uuconf_system *qsys, int bgrade, struct scmd *qcmd)); /* Remove a job from the work queue. This must also remove the temporary file used for a send command, if there is one. It should return FALSE on error. */ extern boolean fsysdep_did_work P((pointer pseq)); /* Save the temporary file for a send command. This function should return a string that will be put into a mail message. On success this string should say something like ``The file has been saved as ...''. On failure it could say something like ``The file could not be saved because ...''. If there is no temporary file, or for some reason it's not appropriate to include a message, this function should just return NULL. This function is used when a file send fails for some reason, to make sure that we don't completely lost the file. */ extern const char *zsysdep_save_temp_file P((pointer pseq)); /* Cleanup anything left over by fsysdep_get_work_init and fsysdep_get_work. This may be called even though fsysdep_get_work_init has not been. */ extern void usysdep_get_work_free P((const struct uuconf_system *qsys)); /* Add a base name to a file if it is a directory. If zfile names a directory, then return a string naming a file within the directory with the base file name of zname. This should return NULL on error. */ extern char *zsysdep_add_base P((const char *zfile, const char *zname)); /* Get a file name from the spool directory. This should return NULL on error. The pseq argument is TRUE if the file was found from searching the work directory; this is, unfortunately, needed to support SVR4 spool directories. */ extern char *zsysdep_spool_file_name P((const struct uuconf_system *qsys, const char *zfile, pointer pseq)); /* Make necessary directories. This should create all non-existent directories for a file. If the fpublic argument is TRUE, anybody should be permitted to create and remove files in the directory; otherwise anybody can list the directory, but only the UUCP system can create and remove files. It should return FALSE on error. */ extern boolean fsysdep_make_dirs P((const char *zfile, boolean fpublic)); /* Create a stdio file, setting appropriate protection. If the fpublic argument is TRUE, the file is made publically accessible; otherwise it is treated as a private data file. If the fappend argument is TRUE, the file is opened in append mode; otherwise any previously existing file of the same name is removed. If the fmkdirs argument is TRUE, then any necessary directories should also be created. On a system in which file protections are unimportant and the necessary directories exist, this may be implemented as fopen (zfile, fappend ? "a" : "w"); */ extern FILE *esysdep_fopen P((const char *zfile, boolean fpublic, boolean fappend, boolean fmkdirs)); /* Open a file, using the access permission of the user who invoked the program. The frd argument is TRUE if the file should be opened for reading, and the fbinary argument is TRUE if the file should be opened as a binary file (this is ignored on Unix, since there all files are binary files). This returns an openfile_t, not a FILE *. This is supposed to be able to open a file even if it can not be read by the uucp user. This is not possible on some older Unix systems. */ extern openfile_t esysdep_user_fopen P((const char *zfile, boolean frd, boolean fbinary)); /* Open a file to send to another system; the qsys argument is the system the file is being sent to. If fcheck is TRUE, it should make sure that the file is readable by zuser (if zuser is NULL the file must be readable by anybody). This is to eliminate a window between fsysdep_in_directory and esysdep_open_send. If an error occurs, it should return EFILECLOSED. */ extern openfile_t esysdep_open_send P((const struct uuconf_system *qsys, const char *zname, boolean fcheck, const char *zuser)); /* Return a temporary file name to receive into. This file will be opened by esysdep_open_receive. The qsys argument is the system the file is coming from, the zto argument is the name the file will have after it has been fully received, and the ztemp argument, if it is not NULL, is from the command sent by the remote system. The return value must be freed using ubuffree. The function should return NULL on error. */ extern char *zsysdep_receive_temp P((const struct uuconf_system *qsys, const char *zfile, const char *ztemp)); /* Open a file to receive from another system. The zreceive argument is the return value of zsysdep_receive_temp with the same qsys, zfile and ztemp arguments. If the function can determine that this file has already been partially received, it should set *pcrestart to the number of bytes that have been received. If the file has not been partially received, *pcrestart should be set to -1. The function should return EFILECLOSED on error. After the file is written, fsysdep_move_file will be called to move the file to its final destination, and to set the correct file mode. */ extern openfile_t esysdep_open_receive P((const struct uuconf_system *qsys, const char *zto, const char *ztemp, const char *zreceive, long *pcrestart)); /* Move a file. This is used to move a received file to its final location. The zto argument is the file to create. The zorig argument is the name of the file to move. If fmkdirs is TRUE, then any necessary directories are created; fpublic indicates whether they should be publically writeable or not. If fcheck is TRUE, this should make sure the directory is writeable by the user zuser (if zuser is NULL, then it must be writeable by any user); this is to avoid a window of vulnerability between fsysdep_in_directory and fsysdep_move_file. This function should return FALSE on error; the zorig file should be removed even if an error occurs. */ extern boolean fsysdep_move_file P((const char *zorig, const char *zto, boolean fmkdirs, boolean fpublic, boolean fcheck, const char *zuser)); /* Change the mode of a file. The imode argument is a Unix mode. This should return FALSE on error. */ extern boolean fsysdep_change_mode P((const char *zfile, unsigned int imode)); /* Truncate a file which we are receiving into. This may be done by closing the original file, removing it and reopening it. This should return FALSE on error. */ extern openfile_t esysdep_truncate P((openfile_t e, const char *zname)); /* It is possible for the acknowledgement of a received file to be lost. The sending system will then now know that the file was correctly received, and will send it again. This can be a problem particularly with protocols which support channels, since they may send several small files in a single window, all of which may be received correctly although the sending system never sees the acknowledgement. If these files involve an execution, the execution will happen twice, which will be bad. This function is called when a file is completely received. It is supposed to try and remember the reception, in case the connection is lost. It is passed the system, the file name to receive to, and the temporary file name from the sending system. It should return FALSE on error. */ extern boolean fsysdep_remember_reception P((const struct uuconf_system *qsys, const char *zto, const char *ztemp)); /* This function is called to see if a file has already been received successfully. It gets the same arguments as fsysdep_remember_reception. It should return TRUE if the file was already received, FALSE otherwise. There is no way to report error. */ extern boolean fsysdep_already_received P((const struct uuconf_system *qsys, const char *zto, const char *ztemp)); /* This function is called when it is no longer necessary to remember that a file has been received. This will be called when the protocol knows that the receive message has been acknowledged. It gets the same arguments as fsysdep_remember_reception. it should return FALSE on error. */ extern boolean fsysdep_forget_reception P((const struct uuconf_system *qsys, const char *zto, const char *ztemp)); /* Start expanding a wildcarded file name. This should return FALSE on error; otherwise subsequent calls to zsysdep_wildcard should return file names. */ extern boolean fsysdep_wildcard_start P((const char *zfile)); /* Get the next wildcard name. This should return NULL when there are no more names to return. The return value should be freed using ubuffree. The argument should be the same as that to fsysdep_wildcard_start. There is no way to return error. */ extern char *zsysdep_wildcard P((const char *zfile)); /* Finish getting wildcard names. This may be called before or after zsysdep_wildcard has returned NULL. It should return FALSE on error. */ extern boolean fsysdep_wildcard_end P((void)); /* Prepare to execute a bunch of file transfer requests. This should make an entry in the spool directory so that the next time uucico is started up it will transfer these files. The bgrade argument specifies the grade of the commands. The commands themselves are in the pascmds array, which has ccmds entries. The function should return NULL on error, or the jobid on success. The jobid is a string that may be printed or passed to fsysdep_kill_job and related functions, but is otherwise uninterpreted. */ extern char *zsysdep_spool_commands P((const struct uuconf_system *qsys, int bgrade, int ccmds, const struct scmd *pascmds)); /* Get a file name to use for a data file to be copied to another system. The ztname, zdname and zxname arguments will all either be NULL or point to an array of CFILE_NAME_LEN characters in length. The ztname array should be set to a temporary file name that could be passed to zsysdep_spool_file_name to retrieve the return value of this function; this will be appropriate for the temporary name in a send request. The zdname array should be set to a data file name that is appropriate for the spool directory of the other system; this will be appropriate for the name of the destination file in a send request of a data file for an execution of some sort. The zxname array should be set to an execute file name that is appropriate for the other system. The zlocalname argument is the name of the local system as seen by the remote system, the bgrade argument is the grade, and fxqt is TRUE if this file is going to become an execution file. This should return NULL on error. */ #define CFILE_NAME_LEN (15) extern char *zsysdep_data_file_name P((const struct uuconf_system *qsys, const char *zlocalname, int bgrade, boolean fxqt, char *ztname, char *zdname, char *zxname)); /* Get a name for a local execute file. This is used by uux for a local command with remote files. Returns NULL on error. */ extern char *zsysdep_xqt_file_name P((void)); /* Beginning getting execute files. To get a list of execute files, first fsysdep_get_xqt_init is called, then zsysdep_get_xqt is called several times until it returns NULL, then finally usysdep_get_xqt_free is called. */ extern boolean fsysdep_get_xqt_init P((void)); /* Get the next execute file. This should return NULL when finished (with *pferr set to FALSE). On an error this should return NULL with *pferr set to TRUE. This should set *pzsystem to the name of the system for which the execute file was created. Both the return value and *pzsystem should be freed using ubuffree. */ extern char *zsysdep_get_xqt P((char **pzsystem, boolean *pferr)); /* Clean up after getting execute files. */ extern void usysdep_get_xqt_free P((void)); /* Get the absolute pathname of a command to execute. This is given the legal list of commands (which may be the special case "ALL") and the path. It must return an absolute pathname to the command. If it gets an error it should set *pferr to TRUE and return NULL; if the command is not found it should set *pferr to FALSE and return NULL. */ extern char *zsysdep_find_command P((const char *zcmd, char **pzcmds, char **pzpath, boolean *pferr)); /* Expand file names for uuxqt. This exists because uuxqt on Unix has to expand file names which begin with a ~. It does not want to expand any other type of file name, and it turns a double ~ into a single one without expanding. If this returns NULL, the file does not need to be changed; otherwise it returns a zbufalc'ed string. There is no way to report error. */ extern char *zsysdep_xqt_local_file P((const struct uuconf_system *qsys, const char *zfile)); #if ! ALLOW_FILENAME_ARGUMENTS /* Check an argument to an execution command to make sure that it doesn't refer to a file name that may not be accessed. This should check the argument to see if it is a filename. If it is, it should either reject it out of hand or it should call fin_directory_list on the file with both qsys->zremote_receive and qsys->zremote_send. If the file is rejected, it should log an error and return FALSE. Otherwise it should return TRUE. */ extern boolean fsysdep_xqt_check_file P((const struct uuconf_system *qsys, const char *zfile)); #endif /* ! ALLOW_FILENAME_ARGUMENTS */ /* Run an execute file. The arguments are: qsys -- system for which execute file was created zuser -- user who requested execution pazargs -- list of arguments to command (element 0 is command) zfullcmd -- command and arguments stuck together in one string zinput -- file name for standard input (may be NULL) zoutput -- file name for standard output (may be NULL) fshell -- if TRUE, use /bin/sh to execute file ilock -- return value of ixsysdep_lock_uuxqt pzerror -- set to name of standard error file pftemp -- set to TRUE if error is temporary, FALSE otherwise If fshell is TRUE, the command should be executed with /bin/sh (obviously, this can only really be done on Unix systems). If an error occurs this should return FALSE and set *pftemp appropriately. *pzerror should be freed using ubuffree. */ extern boolean fsysdep_execute P((const struct uuconf_system *qsys, const char *zuser, const char **pazargs, const char *zfullcmd, const char *zinput, const char *zoutput, boolean fshell, int ilock, char **pzerror, boolean *pftemp)); /* Lock for uuxqt execution. If the cmaxuuxqts argument is not zero, this should make sure that no more than cmaxuuxqts uuxqt processes are running at once. Also, only one uuxqt may execute a particular command (specified by the -c option) at a time. If zcmd is not NULL, it is a command that must be locked. This should return a nonnegative number which will be passed to other routines, including fsysdep_unlock_uuxqt, or -1 on error. */ extern int ixsysdep_lock_uuxqt P((const char *zcmd, int cmaxuuxqts)); /* Unlock a uuxqt process. This is passed the return value of ixsysdep_lock_uuxqt, as well as the arguments passed to ixsysdep_lock_uuxqt. It may return FALSE on error, but at present the return value is ignored. */ extern boolean fsysdep_unlock_uuxqt P((int iseq, const char *zcmd, int cmaxuuxqts)); /* See whether a particular uuxqt command is locked. This should return TRUE if the command is locked (because ixsysdep_lock_uuxqt was called with it as an argument), FALSE otherwise. There is no way to return error. */ extern boolean fsysdep_uuxqt_locked P((const char *zcmd)); /* Lock an execute file in order to execute it. This should return FALSE if the execute file is already locked. There is no way to return error. */ extern boolean fsysdep_lock_uuxqt_file P((const char *zfile)); /* Unlock an execute file. This should return FALSE on error. */ extern boolean fsysdep_unlock_uuxqt_file P((const char *zfile)); /* Lock the execution directory. The ilock argument is the return value of ixsysdep_lock_uuxqt. This should return FALSE if the directory is already locked. There is no way to return error. */ extern boolean fsysdep_lock_uuxqt_dir P((int ilock)); /* Remove all files in the execution directory, and unlock it. This should return FALSE on error. */ extern boolean fsysdep_unlock_uuxqt_dir P((int ilock)); /* Move files into or out of the execution directory. The code will already have checked that all the files exist. The elements in the pzfrom array will be complete filenames, and the elements in the pzto array will be either NULL (in which case the file should not be moved) or simple base names. If fto is TRUE, the files in pzfrom should be moved to pzto; otherwise, the files in pzto should be moved to pzfrom (this is used if a temporary failure occurs, in which case the execution will be retried later). If pzinput and *pzinput are not NULL, then it is the name of the standard input file; if it is the same as any element of pzfrom, then *pzinput should be set to the zbufcpy of the corresponding pzto value, if any. */ extern boolean fsysdep_move_uuxqt_files P((int cfiles, const char *const *pzfrom, const char *const *pzto, boolean fto, int ilock, char **pzinput)); /* Expand a file name on the local system, defaulting to the current directory. This is just like zsysdep_local_file, except that relative files are placed in the working directory the program started in rather than in the public directory. This should return NULL on error. */ extern char *zsysdep_local_file_cwd P((const char *zname, const char *zpubdir)); /* Add the working directory to a file name. The named file is actually on a remote system. If the file already has a directory, it should not be changed. This should return NULL on error. */ extern char *zsysdep_add_cwd P((const char *zfile)); /* See whether a file name will need the current working directory when zsysdep_local_file_cwd or zsysdep_add_cwd is called on it. This will be called before usysdep_initialize. It should just check whether the argument is an absolute path. See the comment above usysdep_initialize in this file for an explanation of why things are done this way. */ extern boolean fsysdep_needs_cwd P((const char *zfile)); /* Get the base name of a file. The file will be a local file name, and this function should return the base file name, ideally in a form which will make sense on most systems; it will be used if the destination of a uucp is a directory. */ extern char *zsysdep_base_name P((const char *zfile)); /* Return a filename within a directory. */ extern char *zsysdep_in_dir P((const char *zdir, const char *zfile)); /* Get the mode of a file. This should return a Unix style file mode. It should return 0 on error. */ extern unsigned int ixsysdep_file_mode P((const char *zfile)); /* See whether the user has access to a file. This is called by uucp and uux to prevent copying of a file which uucp can read but the user cannot. If access is denied, this should log an error message and return FALSE. */ extern boolean fsysdep_access P((const char *zfile)); /* See whether the daemon has access to a file. This is called by uucp and uux when a file is queued up for transfer without being copied into the spool directory. It is merely an early error check, as the daemon would of course discover the error itself when it tried the transfer. If access would be denied, this should log an error message and return FALSE. */ extern boolean fsysdep_daemon_access P((const char *zfile)); /* Translate a destination from system!user to a place in the public directory where uupick will get the file. On Unix this produces system!~/receive/user/localname, and that's probably what it has to produce on any other system as well. Returns NULL on a usage error, or otherwise returns string allocated by zbufcpy. */ extern char *zsysdep_uuto P((const char *zdest, const char *zlocalname)); /* Return TRUE if a pathname exists and is a directory. */ extern boolean fsysdep_directory P((const char *zpath)); /* Walk a directory tree. The zdir argument is the directory to walk. The pufn argument is a function to call on each regular file in the tree. The first argument to pufn should be the full filename; the second argument to pufn should be the filename relative to zdir; the third argument to pufn should be the pinfo argument to usysdep_walk_tree. The usysdep_walk_tree function should return FALSE on error. */ extern boolean usysdep_walk_tree P((const char *zdir, void (*pufn) P((const char *zfull, const char *zrelative, pointer pinfo)), pointer pinfo)); /* Return the jobid of a work file, given the sequence value. On error this should log an error and return NULL. The jobid is a string which may be printed out and read in and passed to fsysdep_kill_job, etc., but is not otherwise interpreted. */ extern char *zsysdep_jobid P((const struct uuconf_system *qsys, pointer pseq)); /* See whether the current user is permitted to kill jobs submitted by another user. This should return TRUE if permission is granted, FALSE otherwise. */ extern boolean fsysdep_privileged P((void)); /* Kill a job, given the jobid. This should remove all associated files and in general eliminate the job completely. On error it should log an error message and return FALSE. */ extern boolean fsysdep_kill_job P((pointer puuconf, const char *zjobid)); /* Rejuvenate a job, given the jobid. If possible, this should update the time associated with the job such that it will not be eliminated by uustat -K or similar programs that check the creation time. This should affect the return value of ixsysdep_work_time. On error it should log an error message and return FALSE. */ extern boolean fsysdep_rejuvenate_job P((pointer puuconf, const char *zjobid)); /* Get the time a job was queued, given the sequence number. There is no way to indicate error. The return value must use the same epoch as ixsysdep_time. */ extern long ixsysdep_work_time P((const struct uuconf_system *qsys, pointer pseq)); /* Get the time a file was created. This is called by uustat on execution files. There is no way to indicate error. The return value must use the same epoch as ixsysdep_time. */ extern long ixsysdep_file_time P((const char *zfile)); /* Get the size in bytes of a file. If this file does not exist, this should not give an error message, but should return -1. If some other error occurs, this should return -2. */ extern long csysdep_size P((const char *zfile)); /* Return the amount of free space on the containing the given file name (the file may or may not exist). If the amount of free space cannot be determined, the function should return -1. */ extern long csysdep_bytes_free P((const char *zfile)); /* Start getting status information for all systems with available status information. There may be status information for unknown systems, which is why this series of functions is used. The phold argument is used to pass information around, to possibly avoid the use of static variables. On error this should log an error and return FALSE. */ extern boolean fsysdep_all_status_init P((pointer *phold)); /* Get status information for the next system. This should return the system name and fill in the qstat argument. The phold argument will be that set by fsysdep_all_status_init. On error this should log an error, set *pferr to TRUE, and return NULL. */ extern char *zsysdep_all_status P((pointer phold, boolean *pferr, struct sstatus *qstat)); /* Free up anything allocated by fsysdep_all_status_init and zsysdep_all_status. The phold argument is that set by fsysdep_all_status_init. */ extern void usysdep_all_status_free P((pointer phold)); /* Display the process status of all processes holding lock files. This is uustat -p. The return value is passed to usysdep_exit. */ extern boolean fsysdep_lock_status P((void)); /* Return TRUE if the user has legitimate access to the port. This is used by cu to control whether the user can open a port directly, rather than merely being able to dial out on it. Opening a port directly allows the modem to be reprogrammed. */ extern boolean fsysdep_port_access P((struct uuconf_port *qport)); /* Return whether the given port could be named by the given line. On Unix, the line argument would be something like "ttyd0", and this function should return TRUE if the named port is "/dev/ttyd0". */ extern boolean fsysdep_port_is_line P((struct uuconf_port *qport, const char *zline)); /* Set the terminal into raw mode. In this mode no input characters should be treated specially, and characters should be made available as they are typed. The original terminal mode should be saved, so that it can be restored by fsysdep_terminal_restore. If flocalecho is TRUE, then local echoing should still be done; otherwise echoing should be disabled. This function returns FALSE on error. */ extern boolean fsysdep_terminal_raw P((boolean flocalecho)); /* Restore the terminal back to the original setting, before fsysdep_terminal_raw was called. Returns FALSE on error. */ extern boolean fsysdep_terminal_restore P((void)); /* Read a line from the terminal. The fsysdep_terminal_raw function will have been called. This should print the zprompt argument (unless it is NULL) and return the line, allocated by zbufcpy, or NULL on error. */ extern char *zsysdep_terminal_line P((const char *zprompt)); /* Write a line to the terminal, ending with a newline. This is basically just puts (zline, stdout), except that the terminal will be in raw mode, so on ASCII Unix systems the line needs to end with \r\n. */ extern boolean fsysdep_terminal_puts P((const char *zline)); /* If faccept is TRUE, permit the user to generate signals from the terminal. If faccept is FALSE, turn signals off again. After fsysdep_terminal_raw is called, signals should be off. Return FALSE on error. */ extern boolean fsysdep_terminal_signals P((boolean faccept)); /* The cu program expects the system dependent code to handle the details of copying data from the communications port to the terminal. This should be set up by fsysdep_cu_init, and done while fsysdep_cu is called. It is permissible to do it on a continual basis (on Unix a subprocess handles it) so long as the copying can be stopped by the fsysdep_cu_copy function. The fsysdep_cu_init function does any system dependent initialization needed for this. */ extern boolean fsysdep_cu_init P((struct sconnection *qconn)); /* Copy all data from the communications port to the terminal, and all data from the terminal to the communications port. Keep this up until the escape character *zCuvar_escape is seen. Set *pbcmd to the character following the escape character; after the escape character, zlocalname should be printed, possibly after a delay. If two escape characters are entered in sequence, this function should send a single escape character to the port, and not return. Returns FALSE on error. */ extern boolean fsysdep_cu P((struct sconnection *qconn, char *pbcmd, const char *zlocalname)); /* If fcopy is TRUE, start copying data from the communications port to the terminal. If fcopy is FALSE, stop copying data. This function may be called several times during a cu session. It should return FALSE on error. */ extern boolean fsysdep_cu_copy P((boolean fcopy)); /* Stop copying data from the communications port to the terminal, and generally clean up after fsysdep_cu_init and fsysdep_cu. Returns FALSE on error. */ extern boolean fsysdep_cu_finish P((void)); /* Run a shell command. If zcmd is NULL, or *zcmd == '\0', just start up a shell. The second argument is one of the following values. This should return FALSE on error. */ enum tshell_cmd { /* Attach stdin and stdout to the terminal. */ SHELL_NORMAL, /* Attach stdout to the communications port, stdin to the terminal. */ SHELL_STDOUT_TO_PORT, /* Attach stdin to the communications port, stdout to the terminal. */ SHELL_STDIN_FROM_PORT, /* Attach both stdin and stdout to the communications port. */ SHELL_STDIO_ON_PORT }; extern boolean fsysdep_shell P((struct sconnection *qconn, const char *zcmd, enum tshell_cmd tcmd)); /* Change directory. If zdir is NULL, or *zdir == '\0', change to the user's home directory. Return FALSE on error. */ extern boolean fsysdep_chdir P((const char *zdir)); /* Suspend the current process. This is only expected to work on Unix versions that support SIGTSTP. In general, people can just shell out. */ extern boolean fsysdep_suspend P((void)); /* Start getting files for uupick. The zsystem argument may be NULL to get files from all systems, or it may specify a particular system. The zpubdir argument is the public directory to use. This returns FALSE on error. */ extern boolean fsysdep_uupick_init P((const char *zsystem, const char *zpubdir)); /* Get the next file for uupick. This returns the basic file name. It sets *pzfull to the full name, and *pzfrom to the name of the system which sent this file over; both should be freed using ubuffree. *pzfull should be passed to ubuffree after it is no longer needed. The zsystem and zpubdir arguments should be the same as the arguments to fsysdep_uupick_init. This returns NULL when all files been returned. */ extern char *zsysdep_uupick P((const char *zsystem, const char *zpubdir, char **pzfrom, char **pzfull)); /* Clean up after getting files for uupick. */ extern boolean fsysdep_uupick_free P((const char *zsystem, const char *zpubdir)); /* Translate a local file name for uupick. On Unix this is just like zsysdep_local_file_cwd except that a file beginning with ~/ is placed in the user's home directory rather than in the public directory. */ extern char *zsysdep_uupick_local_file P((const char *zfile)); /* Remove a directory and all the files in it. */ extern boolean fsysdep_rmdir P((const char *zdir)); #endif /* ! defined (SYSTEM_H) */ 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)uucp-1.04/tcp.c1004440004150000170000002736505337263515010334 037777777777 1 0 /* 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.28 1992/11/14 16:10:27 ian Rel $"; #endif #if HAVE_TCP #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "conn.h" #include "system.h" #include #if HAVE_SYS_TYPES_TCP_H #include #endif #include #include #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif /* This code handles TCP connections. It assumes a Berkeley socket interface. */ /* The normal "uucp" port number. */ #define IUUCP_PORT (540) /* Local functions. */ static void utcp_free P((struct sconnection *qconn)); static boolean ftcp_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean ftcp_close P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, boolean fsuccess)); static boolean ftcp_reset P((struct sconnection *qconn)); static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf, const struct uuconf_system *qsys, const char *zphone, struct uuconf_dialer *qdialer, enum tdialerfound *ptdialer)); static int itcp_port_number P((const char *zport)); /* The command table for a TCP connection. */ static const struct sconncmds stcpcmds = { utcp_free, NULL, /* pflock */ NULL, /* pfunlock */ ftcp_open, ftcp_close, ftcp_reset, ftcp_dial, fsysdep_conn_read, fsysdep_conn_write, fsysdep_conn_io, NULL, /* pfbreak */ NULL, /* pfset */ NULL, /* pfcarrier */ fsysdep_conn_chat, NULL /* pibaud */ }; /* Initialize a TCP connection. */ boolean fsysdep_tcp_init (qconn) struct sconnection *qconn; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); q->o = -1; q->zdevice = NULL; q->iflags = -1; q->istdout_flags = -1; q->fterminal = FALSE; q->ftli = FALSE; q->ibaud = 0; qconn->psysdep = (pointer) q; qconn->qcmds = &stcpcmds; return TRUE; } /* Free a TCP connection. */ static void utcp_free (qconn) struct sconnection *qconn; { xfree (qconn->psysdep); } /* Open a TCP connection. If the fwait argument is TRUE, we are running as a server. Otherwise we are just trying to reach another system. */ static boolean ftcp_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { struct ssysdep_conn *qsysdep; struct sockaddr_in s; const char *zport; uid_t iuid, ieuid; ulog_device ("TCP"); qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = socket (AF_INET, SOCK_STREAM, 0); if (qsysdep->o < 0) { ulog (LOG_ERROR, "socket: %s", strerror (errno)); return FALSE; } if (fcntl (qsysdep->o, F_SETFD, fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); if (qsysdep->iflags < 0) { ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } /* If we aren't waiting for a connection, we're done. */ if (! fwait) return TRUE; /* Run as a server and wait for a new connection. The code in uucico.c has already detached us from our controlling terminal. From this point on if the server gets an error we exit; we only return if we have received a connection. It would be more robust to respawn the server if it fails; someday. */ bzero ((pointer) &s, sizeof s); s.sin_family = AF_INET; zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; s.sin_port = itcp_port_number (zport); s.sin_addr.s_addr = htonl (INADDR_ANY); /* Swap to our real user ID when doing the bind call. This will permit the server to use privileged TCP ports when invoked by root. We only swap if our effective user ID is not root, so that the program can also be made suid root in order to get privileged ports when invoked by anybody. */ iuid = getuid (); ieuid = geteuid (); if (ieuid != 0) { #if HAVE_SETREUID /* Swap the effective user id and the real user id. We can then swap them back again when we want to return to the uucp user's permissions. */ if (setreuid (ieuid, iuid) < 0) { ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", (long) ieuid, (long) iuid, strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } #else /* ! HAVE_SETREUID */ #if HAVE_SAVED_SETUID /* Set the effective user id to the real user id. Since the effective user id is the saved setuid we will able to set back to it later. If the real user id is root we will not be able to switch back and forth, but that doesn't matter since we only want to switch once. */ if (setuid (iuid) < 0) { ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } #else /* ! HAVE_SAVED_SETUID */ /* There's no way to switch between real permissions and effective permissions. Just try the bind with the uucp permissions. */ #endif /* ! HAVE_SAVED_SETUID */ #endif /* ! HAVE_SETREUID */ } if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) ulog (LOG_FATAL, "bind: %s", strerror (errno)); /* Now swap back to the uucp user ID. */ if (ieuid != 0) { #if HAVE_SETREUID if (setreuid (iuid, ieuid) < 0) { ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", (long) iuid, (long) ieuid, strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } #else /* ! HAVE_SETREUID */ #if HAVE_SAVED_SETUID /* Set ourselves back to our original effective user id. */ if (setuid ((uid_t) ieuid) < 0) { ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno)); (void) close (qsysdep->o); qsysdep->o = -1; return FALSE; } #else /* ! HAVE_SAVED_SETUID */ /* We didn't switch, no need to switch back. */ #endif /* ! HAVE_SAVED_SETUID */ #endif /* ! HAVE_SETREUID */ } if (listen (qsysdep->o, 5) < 0) ulog (LOG_FATAL, "listen: %s", strerror (errno)); while (! FGOT_SIGNAL ()) { size_t clen; int onew; pid_t ipid; DEBUG_MESSAGE0 (DEBUG_PORT, "ftcp_open: Waiting for connections"); clen = sizeof s; onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen); if (onew < 0) ulog (LOG_FATAL, "accept: %s", strerror (errno)); DEBUG_MESSAGE0 (DEBUG_PORT, "ftcp_open: Got connection; forking"); ipid = ixsfork (); if (ipid < 0) ulog (LOG_FATAL, "fork: %s", strerror (errno)); if (ipid == 0) { (void) close (qsysdep->o); qsysdep->o = onew; /* Now we fork and let our parent die, so that we become a child of init. This lets the main server code wait for its child and then continue without accumulating zombie children. */ ipid = ixsfork (); if (ipid < 0) { ulog (LOG_ERROR, "fork: %s", strerror (errno)); _exit (EXIT_FAILURE); } if (ipid != 0) _exit (EXIT_SUCCESS); ulog_id (getpid ()); return TRUE; } (void) close (onew); /* Now wait for the child. */ (void) ixswait ((unsigned long) ipid, (const char *) NULL); } /* We got a signal. */ usysdep_exit (FALSE); /* Avoid compiler warnings. */ return FALSE; } /* Close the port. */ /*ARGSUSED*/ static boolean ftcp_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { struct ssysdep_conn *qsysdep; boolean fret; qsysdep = (struct ssysdep_conn *) qconn->psysdep; fret = TRUE; if (qsysdep->o >= 0 && close (qsysdep->o) < 0) { ulog (LOG_ERROR, "close: %s", strerror (errno)); fret = FALSE; } qsysdep->o = -1; return fret; } /* Reset the port. This will be called by a child which was forked off in ftcp_open, above. We don't want uucico to continue looping and giving login prompts, so we pretend that we received a SIGINT signal. This should probably be handled more cleanly. The signal will not be recorded in the log file because we don't set afLog_signal[INDEXSIG_SIGINT]. */ /*ARGSUSED*/ static boolean ftcp_reset (qconn) struct sconnection *qconn; { afSignal[INDEXSIG_SIGINT] = TRUE; return TRUE; } /* Dial out on a TCP port, so to speak: connect to a remote computer. */ /*ARGSUSED*/ static boolean ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) struct sconnection *qconn; pointer puuconf; const struct uuconf_system *qsys; const char *zphone; struct uuconf_dialer *qdialer; enum tdialerfound *ptdialer; { struct ssysdep_conn *qsysdep; const char *zhost; struct hostent *q; struct sockaddr_in s; const char *zport; qsysdep = (struct ssysdep_conn *) qconn->psysdep; *ptdialer = DIALERFOUND_FALSE; zhost = zphone; if (zhost == NULL) { if (qsys == NULL) { ulog (LOG_ERROR, "No address for TCP connection"); return FALSE; } zhost = qsys->uuconf_zname; } errno = 0; q = gethostbyname ((char *) zhost); if (q == NULL) { if (errno == 0) ulog (LOG_ERROR, "%s: unknown host name", zhost); else ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno)); return FALSE; } s.sin_family = q->h_addrtype; zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; s.sin_port = itcp_port_number (zport); memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) { ulog (LOG_ERROR, "connect: %s", strerror (errno)); return FALSE; } return TRUE; } /* Get the port number given a name. The argument will almost always be "uucp" so we cache that value. The return value is always in network byte order. This returns -1 on error. */ static int itcp_port_number (zname) const char *zname; { boolean fuucp; static int iuucp; int i; char *zend; struct servent *q; fuucp = strcmp (zname, "uucp") == 0; if (fuucp && iuucp != 0) return iuucp; /* Try it as a number first. */ i = strtol ((char *) zname, &zend, 10); if (i != 0 && *zend == '\0') return htons (i); q = getservbyname ((char *) zname, (char *) "tcp"); if (q == NULL) { /* We know that the "uucp" service should be 540, even if isn't in /etc/services. */ if (fuucp) { iuucp = htons (IUUCP_PORT); return iuucp; } ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno)); return -1; } if (fuucp) iuucp = q->s_port; return q->s_port; } #endif /* HAVE_TCP */ conn, 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 ftcpuucp-1.04/time.c1004440004150000170000000634305337263515010475 037777777777 1 0 /* 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.16 1992/07/26 03:53:00 ian Rel $"; #endif #include #if HAVE_TIME_H #include #endif #include "uudefs.h" #include "uuconf.h" /* External functions. */ #ifndef time extern time_t time (); #endif #ifndef localtime extern struct tm *localtime (); #endif /* See if the current time matches a time span. If it does, return TRUE, set *pival to the value for the matching span, and set *pcretry to the retry for the matching span. Otherwise return FALSE. */ boolean ftimespan_match (qspan, pival, pcretry) const struct uuconf_timespan *qspan; long *pival; int *pcretry; { time_t inow; struct tm *qtm; int itm; const struct uuconf_timespan *q; if (qspan == NULL) return FALSE; time (&inow); qtm = localtime (&inow); /* Get the number of minutes since Sunday for the time. */ itm = qtm->tm_wday * 24 * 60 + qtm->tm_hour * 60 + qtm->tm_min; for (q = qspan; q != NULL; q = q->uuconf_qnext) { if (q->uuconf_istart <= itm && itm <= q->uuconf_iend) { if (pival != NULL) *pival = q->uuconf_ival; if (pcretry != NULL) *pcretry = q->uuconf_cretry; return TRUE; } } return FALSE; } /* Determine the maximum size that may ever be transferred, according to a timesize span. This returns -1 if there is no limit. */ long cmax_size_ever (qtimesize) const struct uuconf_timespan *qtimesize; { long imax; const struct uuconf_timespan *q; if (qtimesize == NULL) return -1; /* Look through the list of spans. If there is any gap larger than 1 hour, we assume there are no restrictions. Otherwise we keep track of the largest value we see. I picked 1 hour arbitrarily, on the theory that a 1 hour span to transfer large files might actually occur, and is probably not an accident. */ if (qtimesize->uuconf_istart >= 60) return -1; imax = -1; for (q = qtimesize; q != NULL; q = q->uuconf_qnext) { if (q->uuconf_qnext == NULL) { if (q->uuconf_iend <= 6 * 24 * 60 + 23 * 60) return -1; } else { if (q->uuconf_iend + 60 <= q->uuconf_qnext->uuconf_istart) return -1; } if (imax < q->uuconf_ival) imax = q->uuconf_ival; } return imax; } 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 (qsysdepuucp-1.04/tli.c1004440004150000170000003671205337263516010333 037777777777 1 0 /* 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.8 1993/01/24 00:46:53 ian Rel $"; #endif #if HAVE_TLI #include "sysdep.h" #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "system.h" #include #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_TIUSER_H #include #else #if HAVE_XTI_H #include #else #if HAVE_SYS_TLI_H #include #endif #endif #endif #if HAVE_STROPTS_H #include #endif #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif /* The arguments to t_alloca have two different names. I want the SVID ones, not the XPG3 ones. */ #ifndef T_BIND #define T_BIND T_BIND_STR #endif #ifndef T_CALL #define T_CALL T_CALL_STR #endif /* Hopefully these externs will not cause any trouble. This is how they are shown in the SVID. */ extern int t_errno; extern char *t_errlist[]; extern int t_nerr; #ifndef t_alloc extern pointer t_alloc (); #endif /* This code handles TLI connections. It's Unix specific. It's largely based on code from Unix Network Programming, by W. Richard Stevens. */ /* Local functions. */ static const char *ztlierror P((void)); static void utli_free P((struct sconnection *qconn)); static boolean ftli_push P((struct sconnection *qconn)); static boolean ftli_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean ftli_close P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, boolean fsuccess)); static boolean ftli_reset P((struct sconnection *qconn)); static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf, const struct uuconf_system *qsys, const char *zphone, struct uuconf_dialer *qdialer, enum tdialerfound *ptdialer)); /* The command table for a TLI connection. */ static const struct sconncmds stlicmds = { utli_free, NULL, /* pflock */ NULL, /* pfunlock */ ftli_open, ftli_close, ftli_reset, ftli_dial, fsysdep_conn_read, fsysdep_conn_write, fsysdep_conn_io, NULL, /* pfbreak */ NULL, /* pfset */ NULL, /* pfcarrier */ fsysdep_conn_chat, NULL /* pibaud */ }; /* Get a TLI error string. */ static const char * ztlierror () { if (t_errno == TSYSERR) return strerror (errno); if (t_errno < 0 || t_errno >= t_nerr) return "Unknown TLI error"; return t_errlist[t_errno]; } /* Initialize a TLI connection. */ boolean fsysdep_tli_init (qconn) struct sconnection *qconn; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); q->o = -1; q->zdevice = NULL; q->iflags = -1; q->istdout_flags = -1; q->fterminal = FALSE; q->ftli = TRUE; q->ibaud = 0; qconn->psysdep = (pointer) q; qconn->qcmds = &stlicmds; return TRUE; } /* Free a TLI connection. */ static void utli_free (qconn) struct sconnection *qconn; { xfree (qconn->psysdep); } /* Push all desired modules onto a TLI stream. If the user requests a STREAMS connection without giving a list of modules, we just push tirdwr. If the I_PUSH ioctl is not defined on this system, we just ignore any list of modules. */ static boolean ftli_push (qconn) struct sconnection *qconn; { #ifdef I_PUSH struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL) { char **pz; for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush; *pz != NULL; pz++) { if (ioctl (qsysdep->o, I_PUSH, *pz) < 0) { ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz, strerror (errno)); return FALSE; } } } else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) { if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0) { ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s", strerror (errno)); return FALSE; } } /* If we have just put the connection into stream mode, we must turn off the TLI flag to avoid using TLI calls on it. */ if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) qsysdep->ftli = FALSE; #endif /* defined (I_PUSH) */ return TRUE; } /* Open a TLI connection. If the fwait argument is TRUE, we are running as a server. Otherwise we are just trying to reach another system. */ static boolean ftli_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { struct ssysdep_conn *qsysdep; const char *zdevice; char *zfreedev; const char *zservaddr; char *zfreeaddr; struct t_bind *qtbind; struct t_call *qtcall; /* Unlike most other device types, we don't bother to call ulog_device here, because fconn_open calls it with the name of the port anyhow. */ qsysdep = (struct ssysdep_conn *) qconn->psysdep; zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice; if (zdevice == NULL) zdevice = qconn->qport->uuconf_zname; zfreedev = NULL; if (*zdevice != '/') { zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice)); sprintf (zfreedev, "/dev/%s", zdevice); zdevice = zfreedev; } qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL); if (qsysdep->o < 0) { ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ()); ubuffree (zfreedev); return FALSE; } if (fcntl (qsysdep->o, F_SETFD, fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); ubuffree (zfreedev); (void) t_close (qsysdep->o); qsysdep->o = -1; return FALSE; } qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); if (qsysdep->iflags < 0) { ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); ubuffree (zfreedev); (void) t_close (qsysdep->o); qsysdep->o = -1; return FALSE; } /* If we aren't waiting for a connection, we can bind to any local address, and then we're finished. */ if (! fwait) { ubuffree (zfreedev); if (t_bind (qsysdep->o, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0) { ulog (LOG_ERROR, "t_bind: %s", ztlierror ()); (void) t_close (qsysdep->o); qsysdep->o = -1; return FALSE; } return TRUE; } /* Run as a server and wait for a new connection. The code in uucico.c has already detached us from our controlling terminal. From this point on if the server gets an error we exit; we only return if we have received a connection. It would be more robust to respawn the server if it fails; someday. */ qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL); if (qtbind == NULL) ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ()); zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr; if (zservaddr == NULL) ulog (LOG_FATAL, "Can't run as TLI server; no server address"); zfreeaddr = zbufcpy (zservaddr); qtbind->addr.len = cescape (zfreeaddr); if (qtbind->addr.len > qtbind->addr.maxlen) ulog (LOG_FATAL, "%s: TLI server address too long (max %d)", zservaddr, qtbind->addr.maxlen); memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len); ubuffree (zfreeaddr); qtbind->qlen = 5; if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0) ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ()); (void) t_free ((pointer) qtbind, T_BIND); qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL); if (qtcall == NULL) ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ()); while (! FGOT_SIGNAL ()) { int onew; pid_t ipid; DEBUG_MESSAGE0 (DEBUG_PORT, "ftli_open: Waiting for connections"); if (t_listen (qsysdep->o, qtcall) < 0) ulog (LOG_FATAL, "t_listen: %s", ztlierror ()); onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL); if (onew < 0) ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ()); if (fcntl (onew, F_SETFD, fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno)); if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0) ulog (LOG_FATAL, "t_bind: %s", ztlierror ()); if (t_accept (qsysdep->o, onew, qtcall) < 0) { /* We may have received a disconnect. */ if (t_errno != TLOOK) ulog (LOG_FATAL, "t_accept: %s", ztlierror ()); if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ()); (void) t_close (onew); continue; } DEBUG_MESSAGE0 (DEBUG_PORT, "ftli_open: Got connection; forking"); ipid = ixsfork (); if (ipid < 0) ulog (LOG_FATAL, "fork: %s", strerror (errno)); if (ipid == 0) { ulog_close (); (void) t_close (qsysdep->o); qsysdep->o = onew; /* Push any desired modules. */ if (! ftli_push (qconn)) _exit (EXIT_FAILURE); /* Now we fork and let our parent die, so that we become a child of init. This lets the main server code wait for its child and then continue without accumulating zombie children. */ ipid = ixsfork (); if (ipid < 0) { ulog (LOG_ERROR, "fork: %s", strerror (errno)); _exit (EXIT_FAILURE); } if (ipid != 0) _exit (EXIT_SUCCESS); ulog_id (getpid ()); return TRUE; } (void) t_close (onew); /* Now wait for the child. */ (void) ixswait ((unsigned long) ipid, (const char *) NULL); } /* We got a signal. */ usysdep_exit (FALSE); /* Avoid compiler warnings. */ return FALSE; } /* Close the port. */ /*ARGSUSED*/ static boolean ftli_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { struct ssysdep_conn *qsysdep; boolean fret; qsysdep = (struct ssysdep_conn *) qconn->psysdep; fret = TRUE; if (qsysdep->o >= 0) { if (qsysdep->ftli) { if (t_close (qsysdep->o) < 0) { ulog (LOG_ERROR, "t_close: %s", ztlierror ()); fret = FALSE; } } else { if (close (qsysdep->o) < 0) { ulog (LOG_ERROR, "close: %s", strerror (errno)); fret = FALSE; } } qsysdep->o = -1; } return fret; } /* Reset the port. This will be called by a child which was forked off in ftli_open, above. We don't want uucico to continue looping and giving login prompts, so we pretend that we received a SIGINT signal. This should probably be handled more cleanly. The signal will not be recorded in the log file because we don't set afLog_signal[INDEXSIG_SIGINT]. */ /*ARGSUSED*/ static boolean ftli_reset (qconn) struct sconnection *qconn; { afSignal[INDEXSIG_SIGINT] = TRUE; return TRUE; } /* Dial out on a TLI port, so to speak: connect to a remote computer. */ /*ARGSUSED*/ static boolean ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) struct sconnection *qconn; pointer puuconf; const struct uuconf_system *qsys; const char *zphone; struct uuconf_dialer *qdialer; enum tdialerfound *ptdialerfound; { struct ssysdep_conn *qsysdep; char **pzdialer; const char *zaddr; struct t_call *qtcall; char *zescape; qsysdep = (struct ssysdep_conn *) qconn->psysdep; *ptdialerfound = DIALERFOUND_FALSE; pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer; if (*pzdialer == NULL) pzdialer = NULL; /* If the first dialer is "TLI" or "TLIS", we use the first token (pzdialer[1]) as the address to connect to. */ zaddr = zphone; if (pzdialer != NULL && (strcmp (pzdialer[0], "TLI") == 0 || strcmp (pzdialer[0], "TLIS") == 0)) { if (pzdialer[1] == NULL) ++pzdialer; else { if (strcmp (pzdialer[1], "\\D") != 0 && strcmp (pzdialer[1], "\\T") != 0) zaddr = pzdialer[1]; pzdialer += 2; } } if (zaddr == NULL) { ulog (LOG_ERROR, "No address for TLI connection"); return FALSE; } qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR); if (qtcall == NULL) { ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ()); return FALSE; } zescape = zbufcpy (zaddr); qtcall->addr.len = cescape (zescape); if (qtcall->addr.len > qtcall->addr.maxlen) { ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr, qtcall->addr.maxlen); ubuffree (zescape); return FALSE; } memcpy (qtcall->addr.buf, zescape, qtcall->addr.len); ubuffree (zescape); if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0) { if (t_errno != TLOOK) ulog (LOG_ERROR, "t_connect: %s", ztlierror ()); else { if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ()); else ulog (LOG_ERROR, "Connection refused"); } return FALSE; } /* We've connected to the remote. Push any desired modules. */ if (! ftli_push (qconn)) return FALSE; /* Handle the rest of the dialer sequence. This is similar to fmodem_dial, and they should, perhaps, be combined somehow. */ if (pzdialer != NULL) { boolean ffirst; ffirst = TRUE; while (*pzdialer != NULL) { int iuuconf; struct uuconf_dialer *q; struct uuconf_dialer s; const char *ztoken; boolean ftranslate; if (! ffirst) q = &s; else q = qdialer; iuuconf = uuconf_dialer_info (puuconf, *pzdialer, q); if (iuuconf == UUCONF_NOT_FOUND) { ulog (LOG_ERROR, "%s: Dialer not found", *pzdialer); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } ++pzdialer; ztoken = *pzdialer; ftranslate = FALSE; if (ztoken == NULL || strcmp (ztoken, "\\D") == 0) ztoken = zphone; else if (strcmp (ztoken, "\\T") == 0) { ztoken = zphone; ftranslate = TRUE; } if (! fchat (qconn, puuconf, &q->uuconf_schat, (const struct uuconf_system *) NULL, q, zphone, ftranslate, qconn->qport->uuconf_zname, (long) 0)) { (void) uuconf_dialer_free (puuconf, q); if (! ffirst) (void) uuconf_dialer_free (puuconf, qdialer); return FALSE; } if (ffirst) { *ptdialerfound = DIALERFOUND_FREE; ffirst = FALSE; } else (void) uuconf_dialer_free (puuconf, q); if (*pzdialer != NULL) ++pzdialer; } } return TRUE; } #endif /* HAVE_TLI */ qconn; long ibaud; boolean fwait; { structuucp-1.04/trans.c1004440004150000170000010521505337263516010665 037777777777 1 0 /* 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.23 1993/01/24 06:26:00 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "prot.h" #include "system.h" #include "trans.h" /* Local functions. */ static void utqueue P((struct stransfer **, struct stransfer *, boolean fhead)); static void utdequeue P((struct stransfer *)); static void utchanalc P((struct sdaemon *qdaemon, struct stransfer *qtrans)); __inline__ static struct stransfer *qtchan P((int ichan)); __inline__ static void utchanfree P((struct stransfer *qtrans)); static boolean ftcharge P((struct sdaemon *qdaemon, struct stransfer *qtrans, boolean fsend, boolean fforce)); static boolean fcheck_queue P((struct sdaemon *qdaemon)); static boolean ftadd_cmd P((struct sdaemon *qdaemon, const char *z, size_t cdata, int iremote, boolean flast)); static boolean fremote_hangup_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean flocal_poll_file P((struct stransfer *qtrans, struct sdaemon *qdaemon)); /* Queue of transfer structures that are ready to start which have been requested by the local system. These are only permitted to start when the local system is the master. */ static struct stransfer *qTlocal; /* Queue of transfer structures that are ready to start which have been requested by the remote system. These are responses to commands received from the remote system, and should be started as soon as possible. */ static struct stransfer *qTremote; /* Queue of transfer structures that have been started and want to send information. This should be static, but the 'a' protocol looks at it, at least for now. */ struct stransfer *qTsend; /* Queue of transfer structures that have been started and are waiting to receive information. */ static struct stransfer *qTreceive; /* Queue of free transfer structures. */ static struct stransfer *qTavail; /* Array of transfer structures indexed by local channel number. This is maintained for local jobs. */ static struct stransfer *aqTchan[IMAX_CHAN + 1]; /* Number of local channel numbers currently allocated. */ static int cTchans; /* Next channel number to allocate. */ static int iTchan; /* Array of transfer structures indexed by remote channel number. This is maintained for remote jobs. */ static struct stransfer *aqTremote[IMAX_CHAN + 1]; /* A structure used to charge time to file transfers. */ struct scharge { /* The transfer we are currently charging. */ struct stransfer *qtrans; /* The time at the last update. */ long isecs; long imicros; }; /* We are always charging one send and one receive. */ static struct scharge sTsend; static struct scharge sTreceive; /* The minimum amount of time, in seconds, to wait between times we check the spool directory, if we are busy transferring data. If we have nothing to do, we will check the spool directory regardless of how long ago the last check was. This should probably be configurable. */ #define CCHECKWAIT (600) /* The time we last checked the spool directory for work. This is set from the return value of ixsysdep_process_time, not ixsysdep_time, for convenience in the routines which use it. */ static long iTchecktime; /* The size of the command we have read so far in ftadd_cmd. */ static size_t cTcmdlen; /* The structure we use when waiting for an acknowledgement of a confirmed received file in fsent_receive_ack, and a list of those structures. */ struct sreceive_ack { struct sreceive_ack *qnext; char *zto; char *ztemp; boolean fmarked; }; static struct sreceive_ack *qTreceive_ack; /* Queue up a transfer structure before *pq. This puts it at the head or the tail of the list headed by *pq. */ static void utqueue (pq, q, fhead) struct stransfer **pq; struct stransfer *q; boolean fhead; { if (*pq == NULL) { *pq = q; q->qprev = q->qnext = q; } else { q->qnext = *pq; q->qprev = (*pq)->qprev; q->qprev->qnext = q; q->qnext->qprev = q; if (fhead) *pq = q; } q->pqqueue = pq; } /* Dequeue a transfer structure. */ static void utdequeue (q) struct stransfer *q; { if (q->pqqueue != NULL) { if (*(q->pqqueue) == q) { if (q->qnext == q) *(q->pqqueue) = NULL; else *(q->pqqueue) = q->qnext; } q->pqqueue = NULL; } if (q->qprev != NULL) q->qprev->qnext = q->qnext; if (q->qnext != NULL) q->qnext->qprev = q->qprev; q->qprev = NULL; q->qnext = NULL; } /* Queue up a transfer structure requested by the local system. */ /*ARGSIGNORED*/ boolean fqueue_local (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { utdequeue (qtrans); utqueue (&qTlocal, qtrans, FALSE); return TRUE; } /* Queue up a transfer structure requested by the remote system. The stransfer structure should have the iremote field set. We need to record it, so that any subsequent data associated with this channel can be routed to the right place. */ boolean fqueue_remote (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fqueue_remote: Channel %d", qtrans->iremote); if (qtrans->iremote > 0) aqTremote[qtrans->iremote] = qtrans; utdequeue (qtrans); utqueue (&qTremote, qtrans, FALSE); /* We just received data for this transfer, so start charging. */ return ftcharge (qdaemon, qtrans, FALSE, FALSE); } /* Queue up a transfer with something to send. */ boolean fqueue_send (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { #if DEBUG > 0 if (qtrans->psendfn == NULL) ulog (LOG_FATAL, "fqueue_send: Bad call"); #endif utdequeue (qtrans); utqueue (&qTsend, qtrans, FALSE); /* Since we're now going to wait to send data, don't charge this transfer for receive time. */ if (qtrans == sTreceive.qtrans) return ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, FALSE); return TRUE; } /* Queue up a transfer with something to receive. */ boolean fqueue_receive (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { #if DEBUG > 0 if (qtrans->precfn == NULL) ulog (LOG_FATAL, "fqueue_receive: Bad call"); #endif utdequeue (qtrans); utqueue (&qTreceive, qtrans, FALSE); /* Since we are now going to wait to receive data, don't charge this transfer for send time. */ if (qtrans == sTsend.qtrans) return ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, FALSE); return TRUE; } /* Get a new local channel number. */ static void utchanalc (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { do { ++iTchan; if (iTchan > qdaemon->qproto->cchans) iTchan = 1; } while (aqTchan[iTchan] != NULL); qtrans->ilocal = iTchan; aqTchan[iTchan] = qtrans; ++cTchans; } /* Return the transfer for a channel number. */ __inline__ static struct stransfer * qtchan (ic) int ic; { return aqTchan[ic]; } /* Clear the channel number for a transfer. */ __inline__ static void utchanfree (qt) struct stransfer *qt; { if (qt->ilocal != 0) { aqTchan[qt->ilocal] = NULL; qt->ilocal = 0; --cTchans; } } /* Allocate a new transfer structure. */ struct stransfer * qtransalc (qcmd) struct scmd *qcmd; { register struct stransfer *q; q = qTavail; if (q != NULL) utdequeue (q); else q = (struct stransfer *) xmalloc (sizeof (struct stransfer)); q->qnext = NULL; q->qprev = NULL; q->pqqueue = NULL; q->psendfn = NULL; q->precfn = NULL; q->pinfo = NULL; q->fsendfile = FALSE; q->frecfile = FALSE; q->e = EFILECLOSED; q->ipos = 0; q->fcmd = FALSE; q->zcmd = NULL; q->ccmd = 0; q->ilocal = 0; q->iremote = 0; if (qcmd != NULL) { q->s = *qcmd; q->s.zfrom = zbufcpy (qcmd->zfrom); q->s.zto = zbufcpy (qcmd->zto); q->s.zuser = zbufcpy (qcmd->zuser); q->s.zoptions = zbufcpy (qcmd->zoptions); q->s.ztemp = zbufcpy (qcmd->ztemp); q->s.znotify = zbufcpy (qcmd->znotify); q->s.zcmd = zbufcpy (qcmd->zcmd); } else { q->s.zfrom = NULL; q->s.zto = NULL; q->s.zuser = NULL; q->s.zoptions = NULL; q->s.ztemp = NULL; q->s.znotify = NULL; q->s.zcmd = NULL; } q->isecs = 0; q->imicros = 0; q->cbytes = 0; return q; } /* Free a transfer structure. This does not free any pinfo information that may have been allocated. */ void utransfree (q) struct stransfer *q; { ubuffree (q->zcmd); ubuffree ((char *) q->s.zfrom); ubuffree ((char *) q->s.zto); ubuffree ((char *) q->s.zuser); ubuffree ((char *) q->s.zoptions); ubuffree ((char *) q->s.ztemp); ubuffree ((char *) q->s.znotify); ubuffree ((char *) q->s.zcmd); utchanfree (q); if (q->iremote > 0) { aqTremote[q->iremote] = NULL; q->iremote = 0; } #if DEBUG > 0 q->zcmd = NULL; q->s.zfrom = NULL; q->s.zto = NULL; q->s.zuser = NULL; q->s.zoptions = NULL; q->s.ztemp = NULL; q->s.znotify = NULL; q->s.zcmd = NULL; q->psendfn = NULL; q->precfn = NULL; #endif /* Don't try to charge time to this structure any longer. */ if (sTsend.qtrans == q) sTsend.qtrans = NULL; if (sTreceive.qtrans == q) sTreceive.qtrans = NULL; utdequeue (q); utqueue (&qTavail, q, FALSE); } /* Handle timing of file tranfers. This is called when processing starts for a transfer structure. All time up to the next call to this function is charged to that transfer structure. Sending time and receiving time are charged separately. Normally if we are about to start charging the same structure we are already charging, we do nothing; but if the fforce argument is TRUE, we charge the time anyhow. */ static boolean ftcharge (qdaemon, qtrans, fsend, fforce) struct sdaemon *qdaemon; struct stransfer *qtrans; boolean fsend; boolean fforce; { struct scharge *qcharge, *qother; long inextsecs, inextmicros; if (fsend) { qcharge = &sTsend; qother = &sTreceive; } else { qcharge = &sTreceive; qother = &sTsend; } if (! fforce && qtrans == qcharge->qtrans) return TRUE; inextsecs = ixsysdep_process_time (&inextmicros); if (qcharge->qtrans != NULL) { qcharge->qtrans->isecs += inextsecs - qcharge->isecs; qcharge->qtrans->imicros += inextmicros - qcharge->imicros; /* If we are charging the same structure for both send and receive, update the time we are not currently charging so that we don't charge twice for the same time. */ if (qcharge->qtrans == qother->qtrans) { qother->isecs = inextsecs; qother->imicros = inextmicros; } } qcharge->qtrans = qtrans; qcharge->isecs = inextsecs; qcharge->imicros = inextmicros; /* If enough time has elapsed since the last time we checked the queue, check it again. We do this here because we have already gone to the trouble of getting the time. */ if (inextsecs - iTchecktime >= CCHECKWAIT) { if (! fcheck_queue (qdaemon)) return FALSE; } return TRUE; } /* Gather local commands and queue them up for later processing. Also recompute time based control values. */ boolean fqueue (qdaemon, pfany) struct sdaemon *qdaemon; boolean *pfany; { const struct uuconf_system *qsys; int bgrade; struct uuconf_timespan *qlocal_size, *qremote_size; if (pfany != NULL) *pfany = FALSE; qsys = qdaemon->qsys; /* If we are not the caller, the grade will be set during the initial handshake. */ if (! qdaemon->fcaller) bgrade = qdaemon->bgrade; else { long ival; if (! ftimespan_match (qsys->uuconf_qtimegrade, &ival, (int *) NULL)) bgrade = '\0'; else bgrade = (char) ival; } /* Determine the maximum sizes we can send and receive. */ if (qdaemon->fcaller) { qlocal_size = qsys->uuconf_qcall_local_size; qremote_size = qsys->uuconf_qcall_remote_size; } else { qlocal_size = qsys->uuconf_qcalled_local_size; qremote_size = qsys->uuconf_qcalled_remote_size; } if (! ftimespan_match (qlocal_size, &qdaemon->clocal_size, (int *) NULL)) qdaemon->clocal_size = (long) -1; if (! ftimespan_match (qremote_size, &qdaemon->cremote_size, (int *) NULL)) qdaemon->cremote_size = (long) -1; if (bgrade == '\0') return TRUE; if (! fsysdep_get_work_init (qsys, bgrade)) return FALSE; while (TRUE) { struct scmd s; if (! fsysdep_get_work (qsys, bgrade, &s)) return FALSE; if (s.bcmd == 'H') { ulog_user ((const char *) NULL); break; } if (s.bcmd == 'P') { struct stransfer *qtrans; /* A poll file. */ ulog_user ((const char *) NULL); qtrans = qtransalc (&s); qtrans->psendfn = flocal_poll_file; if (! fqueue_local (qdaemon, qtrans)) return FALSE; continue; } ulog_user (s.zuser); switch (s.bcmd) { case 'S': case 'E': if (! flocal_send_file_init (qdaemon, &s)) return FALSE; break; case 'R': if (! flocal_rec_file_init (qdaemon, &s)) return FALSE; break; case 'X': if (! flocal_xcmd_init (qdaemon, &s)) return FALSE; break; #if DEBUG > 0 default: ulog (LOG_FATAL, "fqueue: Can't happen"); break; #endif } } if (pfany != NULL) *pfany = qTlocal != NULL; iTchecktime = ixsysdep_process_time ((long *) NULL); return TRUE; } /* Clear everything off the work queue. This is used when the call is complete, or if the call is never made. */ void uclear_queue (qdaemon) struct sdaemon *qdaemon; { int i; usysdep_get_work_free (qdaemon->qsys); qTlocal = NULL; qTremote = NULL; qTsend = NULL; qTreceive = NULL; cTchans = 0; iTchan = 0; sTsend.qtrans = NULL; sTreceive.qtrans = NULL; cTcmdlen = 0; qTreceive_ack = NULL; for (i = 0; i < IMAX_CHAN + 1; i++) { aqTchan[i] = NULL; aqTremote[i] = NULL; } } /* Recheck the work queue during a conversation. This is only called if it's been more than CCHECKWAIT seconds since the last time the queue was checked. */ static boolean fcheck_queue (qdaemon) struct sdaemon *qdaemon; { int cchans; /* Only check if we are the master, or if there are multiple channels, or if we aren't already trying to get the other side to hang up. Otherwise, there's nothing we can do with any new jobs we might find. */ if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0) cchans = 1; else cchans = qdaemon->qproto->cchans; if (qdaemon->fmaster || cchans > 1 || ! qdaemon->frequest_hangup) { boolean fany; DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fcheck_queue: Rechecking work queue"); if (! fqueue (qdaemon, &fany)) return FALSE; /* If we found something to do, and we're not the master, and we don't have multiple channels to send new jobs over, try to get the other side to hang up. */ if (fany && ! qdaemon->fmaster && cchans <= 1) qdaemon->frequest_hangup = TRUE; } return TRUE; } /* The main transfer loop. The uucico daemon spends essentially all its time in this function. */ boolean floop (qdaemon) struct sdaemon *qdaemon; { int cchans; boolean fret; /* If we are using a half-duplex line, act as though we have only a single channel; otherwise we might start a send and a receive at the same time. */ if ((qdaemon->ireliable & UUCONF_RELIABLE_FULLDUPLEX) == 0) cchans = 1; else cchans = qdaemon->qproto->cchans; fret = TRUE; while (! qdaemon->fhangup) { register struct stransfer *q; #if DEBUG > 1 /* If we're doing any debugging, close the log and debugging files regularly. This will let people copy them off and remove them while the conversation is in progresss. */ if (iDebug != 0) { ulog_close (); ustats_close (); } #endif if (qdaemon->fmaster) { boolean fhangup; /* We've managed to become the master, so we no longer want to request a hangup. */ qdaemon->frequest_hangup = FALSE; fhangup = FALSE; if (qdaemon->fhangup_requested && qTsend == NULL) { /* The remote system has requested that we transfer control by sending CYM after receiving a file. */ DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: Transferring control at remote request"); fhangup = TRUE; } else if (qTremote == NULL && qTlocal == NULL && qTsend == NULL && qTreceive == NULL) { /* We don't have anything to do. Try to find some new jobs. If we can't, transfer control. */ if (! fqueue (qdaemon, (boolean *) NULL)) { fret = FALSE; break; } if (qTlocal == NULL) { DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: No work for master"); fhangup = TRUE; } } if (fhangup) { if (! (*qdaemon->qproto->pfsendcmd) (qdaemon, "H", 0, 0)) { fret = FALSE; break; } qdaemon->fmaster = FALSE; } } /* If we are no long the master, clear any requested hangup. We may have already hung up before checking this variable in the block above. */ if (! qdaemon->fmaster) qdaemon->fhangup_requested = FALSE; /* Immediately queue up any remote jobs. We don't need local channel numbers for them, since we can disambiguate based on the remote channel number. */ while (qTremote != NULL) { q = qTremote; utdequeue (q); utqueue (&qTsend, q, TRUE); } /* If we are the master, or if we have multiple channels, try to queue up additional local jobs. */ if (qdaemon->fmaster || cchans > 1) { while (qTlocal != NULL && cTchans < cchans) { /* We have room for an additional channel. */ q = qTlocal; if (! fqueue_send (qdaemon, q)) { fret = FALSE; break; } utchanalc (qdaemon, q); } if (! fret) break; } q = qTsend; if (q == NULL) { ulog_user ((const char *) NULL); DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "floop: Waiting for data"); if (! (*qdaemon->qproto->pfwait) (qdaemon)) { fret = FALSE; break; } } else { ulog_user (q->s.zuser); if (! q->fsendfile) { if (! ftcharge (qdaemon, q, TRUE, TRUE)) { fret = FALSE; break; } if (! (*q->psendfn) (q, qdaemon)) { fret = FALSE; break; } } else { if (! ftcharge (qdaemon, q, TRUE, FALSE)) { fret = FALSE; break; } if (q->zlog != NULL) { ulog (LOG_NORMAL, "%s", q->zlog); ubuffree (q->zlog); q->zlog = NULL; } /* We can read the file in a tight loop until qTremote changes or until we have transferred the entire file. We can disregard any changes to qTlocal since we already have something to send anyhow. */ while (qTremote == NULL) { char *zdata; size_t cdata; long ipos; zdata = (*qdaemon->qproto->pzgetspace) (qdaemon, &cdata); if (zdata == NULL) { fret = FALSE; break; } if (ffileeof (q->e)) cdata = 0; else { cdata = cfileread (q->e, zdata, cdata); if (ffilereaderror (q->e, cdata)) { /* There is no way to report a file reading error, so we just drop the connection. */ ulog (LOG_ERROR, "read: %s", strerror (errno)); fret = FALSE; break; } } ipos = q->ipos; q->ipos += cdata; q->cbytes += cdata; if (! (*qdaemon->qproto->pfsenddata) (qdaemon, zdata, cdata, q->ilocal, q->iremote, ipos)) { fret = FALSE; break; } /* It is possible that this transfer has just been cancelled. */ if (q != qTsend || ! q->fsendfile) break; if (cdata == 0) { /* We must update the time now, because this call may make an entry in the statistics file. */ if (! ftcharge (qdaemon, q, TRUE, TRUE)) fret = FALSE; q->fsendfile = FALSE; if (! (*q->psendfn) (q, qdaemon)) fret = FALSE; break; } } if (! fret) break; } } } ulog_user ((const char *) NULL); (void) (*qdaemon->qproto->pfshutdown) (qdaemon); if (fret) uwindow_acked (qdaemon, TRUE); else ufailed (qdaemon); return fret; } /* This is called by the protocol routines when they have received some data. If pfexit is not NULL, *pfexit should be set to TRUE if the protocol receive loop should exit back to the main floop routine, above. It is only important to set *pfexit to TRUE if the main loop called the pfwait entry point, so we need never set it to TRUE if we just receive data for a file. This routine never sets *pfexit to FALSE. */ boolean fgot_data (qdaemon, zfirst, cfirst, zsecond, csecond, ilocal, iremote, ipos, fallacked, pfexit) struct sdaemon *qdaemon; const char *zfirst; size_t cfirst; const char *zsecond; size_t csecond; int ilocal; int iremote; long ipos; boolean fallacked; boolean *pfexit; { struct stransfer *q; int cwrote; boolean fret; if (fallacked && qTreceive_ack != NULL) uwindow_acked (qdaemon, TRUE); /* Now we have to decide which transfer structure gets the data. If ilocal is -1, it means that the protocol does not know where to route the data. In that case we route it to the first transfer that is waiting for data, or, if none, as a new command. If ilocal is 0, we either select based on the remote channel number or we have a new command. */ if (ilocal == -1 && qTreceive != NULL) q = qTreceive; else if (ilocal == 0 && iremote > 0 && aqTremote[iremote] != NULL) q = aqTremote[iremote]; else if (ilocal <= 0) { const char *znull; ulog_user ((const char *) NULL); /* This data is part of a command. If there is no null character in the data, this string will be continued by the next packet. Otherwise this must be the last string in the command, and we don't care about what comes after the null byte. */ znull = (const char *) memchr (zfirst, '\0', cfirst); if (znull != NULL) fret = ftadd_cmd (qdaemon, zfirst, (size_t) (znull - zfirst), iremote, TRUE); else { fret = ftadd_cmd (qdaemon, zfirst, cfirst, iremote, FALSE); if (fret && csecond > 0) { znull = (const char *) memchr (zsecond, '\0', csecond); if (znull != NULL) fret = ftadd_cmd (qdaemon, zsecond, (size_t) (znull - zsecond), iremote, TRUE); else fret = ftadd_cmd (qdaemon, zsecond, csecond, iremote, FALSE); } } if (pfexit != NULL && (qdaemon->fhangup || qTremote != NULL)) *pfexit = TRUE; return fret; } else { /* Get the transfer structure this data is intended for. */ q = qtchan (ilocal); } #if DEBUG > 0 if (q == NULL || q->precfn == NULL) { ulog (LOG_ERROR, "Protocol error: %lu bytes remote %d local %d", (unsigned long) (cfirst + csecond), iremote, ilocal); return FALSE; } #endif ulog_user (q->s.zuser); fret = TRUE; /* If we're receiving a command, then accumulate it up to the null byte. */ if (q->fcmd) { const char *znull; znull = NULL; while (cfirst > 0) { size_t cnew; char *znew; znull = (const char *) memchr (zfirst, '\0', cfirst); if (znull != NULL) cnew = znull - zfirst; else cnew = cfirst; znew = zbufalc (q->ccmd + cnew + 1); memcpy (znew, q->zcmd, q->ccmd); memcpy (znew + q->ccmd, zfirst, cnew); znew[q->ccmd + cnew] = '\0'; ubuffree (q->zcmd); q->zcmd = znew; q->ccmd += cnew; if (znull != NULL) break; zfirst = zsecond; cfirst = csecond; csecond = 0; } if (znull != NULL) { char *zcmd; size_t ccmd; if (! ftcharge (qdaemon, q, FALSE, TRUE)) fret = FALSE; zcmd = q->zcmd; ccmd = q->ccmd; q->fcmd = FALSE; q->zcmd = NULL; q->ccmd = 0; if (! (*q->precfn) (q, qdaemon, zcmd, ccmd + 1)) fret = FALSE; ubuffree (zcmd); } else { if (! ftcharge (qdaemon, q, FALSE, FALSE)) fret = FALSE; } if (pfexit != NULL && (qdaemon->fhangup || qdaemon->fmaster || qTsend != NULL)) *pfexit = TRUE; } else if (! q->frecfile || cfirst == 0) { /* We're either not receiving a file or the file transfer is complete. */ if (! ftcharge (qdaemon, q, FALSE, TRUE)) fret = FALSE; q->frecfile = FALSE; if (! (*q->precfn) (q, qdaemon, zfirst, cfirst)) fret = FALSE; if (fret && csecond > 0) return fgot_data (qdaemon, zsecond, csecond, (const char *) NULL, (size_t) 0, ilocal, iremote, ipos + (long) cfirst, FALSE, pfexit); if (pfexit != NULL && (qdaemon->fhangup || qdaemon->fmaster || qTsend != NULL)) *pfexit = TRUE; } else { if (! ftcharge (qdaemon, q, FALSE, FALSE)) fret = FALSE; if (q->zlog != NULL) { ulog (LOG_NORMAL, "%s", q->zlog); ubuffree (q->zlog); q->zlog = NULL; } if (ipos != -1 && ipos != q->ipos) { DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fgot_data: Seeking to %ld", ipos); if (! ffileseek (q->e, ipos)) { ulog (LOG_ERROR, "seek: %s", strerror (errno)); fret = FALSE; } q->ipos = ipos; } if (fret) { while (cfirst > 0) { cwrote = cfilewrite (q->e, (char *) zfirst, cfirst); if (cwrote == cfirst) { #if FREE_SPACE_DELTA > 0 long cfree_space; /* Check that there is still enough space on the disk. If there isn't, we drop the connection, because we have no way to abort a file transfer in progress. */ cfree_space = qdaemon->qsys->uuconf_cfree_space; if (cfree_space > 0 && ((q->cbytes / FREE_SPACE_DELTA) != (q->cbytes + cfirst) / FREE_SPACE_DELTA) && ! frec_check_free (q, cfree_space)) { fret = FALSE; break; } #endif q->cbytes += cfirst; q->ipos += cfirst; } else { if (cwrote < 0) ulog (LOG_ERROR, "write: %s", strerror (errno)); else ulog (LOG_ERROR, "Wrote %d to file when trying to write %lu", cwrote, (unsigned long) cfirst); /* Any write error is almost certainly a temporary condition, or else UUCP would not be functioning at all. If we continue to accept the file, we will wind up rejecting it at the end (what else could we do?) and the remote system will throw away the request. We're better off just dropping the connection, which is what happens when we return FALSE, and trying again later. */ fret = FALSE; break; } zfirst = zsecond; cfirst = csecond; csecond = 0; } } if (pfexit != NULL && qdaemon->fhangup) *pfexit = TRUE; } return fret; } /* Accumulate a string into a command. If the command is complete, start up a new transfer. */ static boolean ftadd_cmd (qdaemon, z, clen, iremote, flast) struct sdaemon *qdaemon; const char *z; size_t clen; int iremote; boolean flast; { static char *zbuf; static size_t cbuf; size_t cneed; struct scmd s; cneed = cTcmdlen + clen + 1; if (cneed > cbuf) { zbuf = (char *) xrealloc ((pointer) zbuf, cneed); cbuf = cneed; } memcpy (zbuf + cTcmdlen, z, clen); zbuf[cTcmdlen + clen] = '\0'; if (! flast) { cTcmdlen += clen; return TRUE; } /* Don't save this string for next time. */ cTcmdlen = 0; DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "ftadd_cmd: Got command \"%s\"", zbuf); if (! fparse_cmd (zbuf, &s)) { ulog (LOG_ERROR, "Received garbled command \"%s\"", zbuf); return TRUE; } if (s.bcmd != 'H' && s.bcmd != 'Y' && s.bcmd != 'N') ulog_user (s.zuser); else ulog_user ((const char *) NULL); switch (s.bcmd) { case 'S': case 'E': return fremote_send_file_init (qdaemon, &s, iremote); case 'R': return fremote_rec_file_init (qdaemon, &s, iremote); case 'X': return fremote_xcmd_init (qdaemon, &s, iremote); case 'H': /* This is a remote request for a hangup. We close the log files so that they may be moved at this point. */ ulog_close (); ustats_close (); { struct stransfer *q; q = qtransalc ((struct scmd *) NULL); q->psendfn = fremote_hangup_reply; q->iremote = iremote; return fqueue_remote (qdaemon, q); } case 'N': /* This means a hangup request is being denied; we just ignore this and wait for further commands. */ return TRUE; case 'Y': /* This is a remote confirmation of a hangup. We reconfirm. */ if (qdaemon->fhangup) return TRUE; #if DEBUG > 0 if (qdaemon->fmaster) ulog (LOG_ERROR, "Got hangup reply as master"); #endif /* Don't check errors rigorously here, since the other side might jump the gun and hang up. The fLog_sighup variable will get set TRUE again when the port is closed. */ fLog_sighup = FALSE; (void) (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, iremote); qdaemon->fhangup = TRUE; return TRUE; #if DEBUG > 0 default: ulog (LOG_FATAL, "ftadd_cmd: Can't happen"); return FALSE; #endif } } /* The remote system is requesting a hang up. If we have something to do, send an HN. Otherwise send two HY commands (the other side is presumed to send an HY command between the first and second, but we don't bother to wait for it) and hang up. */ static boolean fremote_hangup_reply (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { boolean fret; utransfree (qtrans); if (qTremote == NULL && qTlocal == NULL && qTsend == NULL && qTreceive == NULL) { if (! fqueue (qdaemon, (boolean *) NULL)) return FALSE; if (qTlocal == NULL) { DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: No work"); fret = ((*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0) && (*qdaemon->qproto->pfsendcmd) (qdaemon, "HY", 0, 0)); qdaemon->fhangup = TRUE; return fret; } } DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fremote_hangup_reply: Found work"); fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, "HN", 0, 0); qdaemon->fmaster = TRUE; return fret; } /* As described in system.h, we need to keep track of which files have been successfully received for which we do not know that the other system has received our acknowledgement. This routine is called to keep a list of such files. */ static struct sreceive_ack *qTfree_receive_ack; void usent_receive_ack (qdaemon, qtrans) struct sdaemon *qdaemon; struct stransfer *qtrans; { struct sreceive_ack *q; if (qTfree_receive_ack == NULL) q = (struct sreceive_ack *) xmalloc (sizeof (struct sreceive_ack)); else { q = qTfree_receive_ack; qTfree_receive_ack = q->qnext; } q->qnext = qTreceive_ack; q->zto = zbufcpy (qtrans->s.zto); q->ztemp = zbufcpy (qtrans->s.ztemp); q->fmarked = FALSE; qTreceive_ack = q; } /* This routine is called by the protocol code when either all outstanding data has been acknowledged or one complete window has passed. It may be called directly by the protocol, or it may be called via fgot_data. If one complete window has passed, then all unmarked receives are marked, and we know that all marked ones have been acked. */ void uwindow_acked (qdaemon, fallacked) struct sdaemon *qdaemon; boolean fallacked; { register struct sreceive_ack **pq; pq = &qTreceive_ack; while (*pq != NULL) { if (fallacked || (*pq)->fmarked) { struct sreceive_ack *q; q = *pq; (void) fsysdep_forget_reception (qdaemon->qsys, q->zto, q->ztemp); ubuffree (q->zto); ubuffree (q->ztemp); *pq = q->qnext; q->qnext = qTfree_receive_ack; qTfree_receive_ack = q; } else { (*pq)->fmarked = TRUE; pq = &(*pq)->qnext; } } } /* This routine is called when an error occurred and we are crashing out of the connection. It is used to report statistics on failed transfers to the statistics file, and it also discards useless temporary files for file receptions. Note that the number of bytes we report as having been sent has little or nothing to do with the number of bytes the remote site actually received. */ void ufailed (qdaemon) struct sdaemon *qdaemon; { register struct stransfer *q; /* Update the transfer times, but avoid looking in the queue. */ iTchecktime = ixsysdep_process_time ((long *) NULL); (void) ftcharge (qdaemon, (struct stransfer *) NULL, TRUE, TRUE); (void) ftcharge (qdaemon, (struct stransfer *) NULL, FALSE, TRUE); if (qTsend != NULL) { q = qTsend; do { if ((q->fsendfile || q->frecfile) && q->cbytes > 0) ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname, q->fsendfile, q->cbytes, q->isecs, q->imicros, FALSE); if (q->frecfile) (void) frec_discard_temp (qdaemon, q); q = q->qnext; } while (q != qTsend); } if (qTreceive != NULL) { q = qTreceive; do { if ((q->fsendfile || q->frecfile) && q->cbytes > 0) ustats (FALSE, q->s.zuser, qdaemon->qsys->uuconf_zname, q->fsendfile, q->cbytes, q->isecs, q->imicros, FALSE); if (q->frecfile) (void) frec_discard_temp (qdaemon, q); q = q->qnext; } while (q != qTreceive); } } /* When a local poll file is found, it is entered on the queue like any other job. When it is pulled off the queue, this function is called. It just calls fsysdep_did_work, which will remove the poll file. This ensures that poll files are only removed if the system is actually called. */ /*ARGSUSED*/ static boolean flocal_poll_file (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { boolean fret; fret = fsysdep_did_work (qtrans->s.pseq); utransfree (qtrans); return fret; } ALSE, 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->fuucp-1.04/trans.h1004440004150000170000002351205337263517010672 037777777777 1 0 /* 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)); 1 0 uucp-1.04/tstuu.c1004440004150000170000010131105337263517010714 037777777777 1 0 /* 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.74 1993/01/26 06:02:11 ian Rel $"; #endif #include "sysdep.h" #include "system.h" #include "getopt.h" #include #include #include #if HAVE_SYS_TIMES_H #include #endif #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_SELECT #include #if HAVE_SYS_SELECT_H #include #endif #endif #if HAVE_POLL #if HAVE_STROPTS_H #include #endif #if HAVE_POLL_H #include #endif #endif #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_SELECT) #include #endif #if HAVE_SYS_WAIT_H #include #endif #if HAVE_UNION_WAIT typedef union wait wait_status; #else typedef int wait_status; #endif #if HAVE_STREAMS_PTYS #include extern char *ptsname (); #endif /* Get definitions for both O_NONBLOCK and O_NDELAY. */ #ifndef O_NDELAY #ifdef FNDELAY #define O_NDELAY FNDELAY #else /* ! defined (FNDELAY) */ #define O_NDELAY 0 #endif /* ! defined (FNDELAY) */ #endif /* ! defined (O_NDELAY) */ #ifndef O_NONBLOCK #ifdef FNBLOCK #define O_NONBLOCK FNBLOCK #else /* ! defined (FNBLOCK) */ #define O_NONBLOCK 0 #endif /* ! defined (FNBLOCK) */ #endif /* ! defined (O_NONBLOCK) */ #if O_NDELAY == 0 && O_NONBLOCK == 0 #error No way to do nonblocking I/O #endif /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ #ifndef EAGAIN #ifndef EWOULDBLOCK #define EAGAIN (-1) #define EWOULDBLOCK (-1) #else /* defined (EWOULDBLOCK) */ #define EAGAIN EWOULDBLOCK #endif /* defined (EWOULDBLOCK) */ #else /* defined (EAGAIN) */ #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif /* ! defined (EWOULDBLOCK) */ #endif /* defined (EAGAIN) */ #ifndef ENODATA #define ENODATA EAGAIN #endif /* Make sure we have a CLK_TCK definition, even if it makes no sense. This is in case TIMES_TICK is defined as CLK_TCK. */ #ifndef CLK_TCK #define CLK_TCK (60) #endif /* Don't try too hard to get a TIMES_TICK value; it doesn't matter that much. */ #if TIMES_TICK == 0 #undef TIMES_TICK #define TIMES_TICK CLK_TCK #endif #if TIMES_DECLARATION_OK extern long times (); #endif #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif #if 1 #define ZUUCICO_CMD "login uucp" #define UUCICO_EXECL "/bin/login", "login", "uucp" #else #define ZUUCICO_CMD "su - nuucp" #define UUCICO_EXECL "/bin/su", "su", "-", "nuucp" #endif #if ! HAVE_SELECT && ! HAVE_POLL #error You need select or poll #endif #if ! HAVE_REMOVE #undef remove #define remove unlink #endif /* Buffer chain to hold data read from a uucico. */ #define BUFCHARS (512) struct sbuf { struct sbuf *qnext; int cstart; int cend; char ab[BUFCHARS]; }; /* Local functions. */ static void umake_file P((const char *zfile, int cextra)); static void uprepare_test P((boolean fmake, int itest, boolean fcall_uucico, const char *zsys)); static void ucheck_file P((const char *zfile, const char *zerr, int cextra)); static void ucheck_test P((int itest, boolean fcall_uucico)); static RETSIGTYPE uchild P((int isig)); static int cpshow P((char *z, int bchar)); static void uchoose P((int *po1, int *po2)); static long cread P((int o, struct sbuf **)); static boolean fsend P((int o, int oslave, struct sbuf **)); static boolean fwritable P((int o)); static void xsystem P((const char *zcmd)); static FILE *xfopen P((const char *zname, const char *zmode)); static char *zDebug; static int iTest; static boolean fCall_uucico; static int iPercent; static pid_t iPid1, iPid2; static int cFrom1, cFrom2; static char abLogout1[sizeof "tstout /dev/ptyp0"]; static char abLogout2[sizeof "tstout /dev/ptyp0"]; static char *zProtocols; int main (argc, argv) int argc; char **argv; { int iopt; const char *zcmd1, *zcmd2; const char *zsys; boolean fmake = TRUE; int omaster1, oslave1, omaster2, oslave2; char abpty1[sizeof "/dev/ptyp0"]; char abpty2[sizeof "/dev/ptyp0"]; struct sbuf *qbuf1, *qbuf2; zcmd1 = NULL; zcmd2 = NULL; zsys = "test2"; while ((iopt = getopt (argc, argv, "c:np:s:t:ux:1:2:")) != EOF) { switch (iopt) { case 'c': zProtocols = optarg; break; case 'n': fmake = FALSE; break; case 'p': iPercent = (int) strtol (optarg, (char **) NULL, 10); srand ((unsigned int) ixsysdep_time ((long *) NULL)); break; case 's': zsys = optarg; break; case 't': iTest = (int) strtol (optarg, (char **) NULL, 10); break; case 'u': fCall_uucico = TRUE; break; case 'x': zDebug = optarg; break; case '1': zcmd1 = optarg; break; case '2': zcmd2 = optarg; break; default: fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: tstuu [-xn] [-t #] [-u] [-1 cmd] [-2 cmd]\n"); exit (EXIT_FAILURE); } } if (fCall_uucico && zcmd2 == NULL) zcmd2 = ZUUCICO_CMD; uprepare_test (fmake, iTest, fCall_uucico, zsys); (void) remove ("/usr/tmp/tstuu/spool1/core"); (void) remove ("/usr/tmp/tstuu/spool2/core"); omaster1 = -1; oslave1 = -1; omaster2 = -1; oslave2 = -1; #if ! HAVE_STREAMS_PTYS { char *zptyname; const char *zpty; zptyname = abpty1; for (zpty = "pqrs"; *zpty != '\0'; ++zpty) { int ipty; for (ipty = 0; ipty < 16; ipty++) { int om, os; FILE *e; sprintf (zptyname, "/dev/pty%c%c", *zpty, "0123456789abcdef"[ipty]); om = open (zptyname, O_RDWR); if (om < 0) continue; zptyname[5] = 't'; os = open (zptyname, O_RDWR); if (os < 0) { (void) close (om); continue; } if (omaster1 == -1) { omaster1 = om; oslave1 = os; e = fopen ("/usr/tmp/tstuu/pty1", "w"); if (e == NULL) { perror ("fopen"); exit (EXIT_FAILURE); } fprintf (e, "%s", zptyname + 5); if (fclose (e) != 0) { perror ("fclose"); exit (EXIT_FAILURE); } zptyname = abpty2; } else { omaster2 = om; oslave2 = os; e = fopen ("/usr/tmp/tstuu/pty2", "w"); if (e == NULL) { perror ("fopen"); exit (EXIT_FAILURE); } fprintf (e, "%s", zptyname + 5); if (fclose (e) != 0) { perror ("fclose"); exit (EXIT_FAILURE); } break; } } if (omaster1 != -1 && omaster2 != -1) break; } } #else /* HAVE_STREAMS_PTYS */ { int ipty; for (ipty = 0; ipty < 2; ipty++) { int om, os; FILE *e; char *znam; struct termio stio; om = open ((char *) "/dev/ptmx", O_RDWR); if (om < 0) break; znam = ptsname (om); if (znam == NULL) break; if (unlockpt (om) != 0 || grantpt (om) != 0) break; os = open (znam, O_RDWR); if (os < 0) { (void) close (om); om = -1; break; } if (ioctl (os, I_PUSH, "ptem") < 0 || ioctl(os, I_PUSH, "ldterm") < 0) { perror ("ioctl"); exit (EXIT_FAILURE); } /* Can this really be right? */ memset (&stio, 0, sizeof (stio)); stio.c_cflag = B9600 | CS8 | CREAD | HUPCL; if (ioctl(os, TCSETA, &stio) < 0) { perror ("TCSETA"); exit (EXIT_FAILURE); } if (omaster1 == -1) { strcpy (abpty1, znam); omaster1 = om; oslave1 = os; e = fopen ("/usr/tmp/tstuu/pty1", "w"); if (e == NULL) { perror ("fopen"); exit (EXIT_FAILURE); } fprintf (e, "%s", znam + 5); if (fclose (e) != 0) { perror ("fclose"); exit (EXIT_FAILURE); } } else { strcpy (abpty2, znam); omaster2 = om; oslave2 = os; e = fopen ("/usr/tmp/tstuu/pty2", "w"); if (e == NULL) { perror ("fopen"); exit (EXIT_FAILURE); } fprintf (e, "%s", znam + 5); if (fclose (e) != 0) { perror ("fclose"); exit (EXIT_FAILURE); } } } } #endif /* HAVE_STREAMS_PTYS */ if (omaster2 == -1) { fprintf (stderr, "No pseudo-terminals available\n"); exit (EXIT_FAILURE); } /* Make sure we can or these into an int for the select call. Most systems could use 31 instead of 15, but it should never be a problem. */ if (omaster1 > 15 || omaster2 > 15) { fprintf (stderr, "File descriptors are too large\n"); exit (EXIT_FAILURE); } /* Prepare to log out the command if it is a login command. On Ultrix 4.0 uucico can only be run from login for some reason. */ if (zcmd1 == NULL || strncmp (zcmd1, "login", sizeof "login" - 1) != 0) abLogout1[0] = '\0'; else sprintf (abLogout1, "tstout %s", abpty1); if (zcmd2 == NULL || strncmp (zcmd2, "login", sizeof "login" - 1) != 0) abLogout2[0] = '\0'; else sprintf (abLogout2, "tstout %s", abpty2); iPid1 = fork (); if (iPid1 < 0) { perror ("fork"); exit (EXIT_FAILURE); } else if (iPid1 == 0) { if (close (0) < 0 || close (1) < 0 || close (omaster1) < 0 || close (omaster2) < 0 || close (oslave2) < 0) perror ("close"); if (dup2 (oslave1, 0) < 0 || dup2 (oslave1, 1) < 0) perror ("dup2"); if (close (oslave1) < 0) perror ("close"); if (zDebug != NULL) fprintf (stderr, "About to exec first process\n"); if (zcmd1 != NULL) exit (system ((char *) zcmd1)); else { (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config1", "-q", "-S", zsys, "-pstdin", (const char *) NULL); perror ("execl failed"); exit (EXIT_FAILURE); } } iPid2 = fork (); if (iPid2 < 0) { perror ("fork"); kill (iPid1, SIGTERM); exit (EXIT_FAILURE); } else if (iPid2 == 0) { if (close (0) < 0 || close (1) < 0 || close (omaster1) < 0 || close (oslave1) < 0 || close (omaster2) < 0) perror ("close"); if (dup2 (oslave2, 0) < 0 || dup2 (oslave2, 1) < 0) perror ("dup2"); if (close (oslave2) < 0) perror ("close"); if (zDebug != NULL) fprintf (stderr, "About to exec second process\n"); if (fCall_uucico) { (void) execl (UUCICO_EXECL, (const char *) NULL); perror ("execl failed"); exit (EXIT_FAILURE); } else if (zcmd2 != NULL) exit (system ((char *) zcmd2)); else { (void) execl ("uucico", "uucico", "-I", "/usr/tmp/tstuu/Config2", "-lq", (const char *)NULL); perror ("execl failed"); exit (EXIT_FAILURE); } } signal (SIGCHLD, uchild); if (fcntl (omaster1, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 && errno == EINVAL) (void) fcntl (omaster1, F_SETFL, O_NONBLOCK); if (fcntl (omaster2, F_SETFL, O_NDELAY | O_NONBLOCK) < 0 && errno == EINVAL) (void) fcntl (omaster2, F_SETFL, O_NONBLOCK); qbuf1 = NULL; qbuf2 = NULL; while (TRUE) { int o1, o2; boolean fcont; o1 = omaster1; o2 = omaster2; uchoose (&o1, &o2); if (o1 == -1 && o2 == -1) { if (zDebug != NULL) fprintf (stderr, "Five second pause\n"); continue; } if (o1 != -1) cFrom1 += cread (omaster1, &qbuf1); if (o2 != -1) cFrom2 += cread (omaster2, &qbuf2); do { fcont = FALSE; if (qbuf1 != NULL && fwritable (omaster2) && fsend (omaster2, oslave2, &qbuf1)) fcont = TRUE; if (qbuf2 != NULL && fwritable (omaster1) && fsend (omaster1, oslave1, &qbuf2)) fcont = TRUE; if (! fcont && (qbuf1 != NULL || qbuf2 != NULL)) { long cgot1, cgot2; cgot1 = cread (omaster1, &qbuf1); cFrom1 += cgot1; cgot2 = cread (omaster2, &qbuf2); cFrom2 += cgot2; fcont = TRUE; } } while (fcont); } /*NOTREACHED*/ } /* When a child dies, kill them both. */ static RETSIGTYPE uchild (isig) int isig; { struct tms sbase, s1, s2; signal (SIGCHLD, SIG_DFL); /* Give the processes a chance to die on their own. */ sleep (2); (void) kill (iPid1, SIGTERM); (void) kill (iPid2, SIGTERM); (void) times (&sbase); #if HAVE_WAITPID (void) waitpid (iPid1, (pointer) NULL, 0); #else /* ! HAVE_WAITPID */ #if HAVE_WAIT4 (void) wait4 (iPid1, (pointer) NULL, 0, (struct rusage *) NULL); #else /* ! HAVE_WAIT4 */ (void) wait ((wait_status *) NULL); #endif /* ! HAVE_WAIT4 */ #endif /* ! HAVE_WAITPID */ (void) times (&s1); #if HAVE_WAITPID (void) waitpid (iPid2, (pointer) NULL, 0); #else /* ! HAVE_WAITPID */ #if HAVE_WAIT4 (void) wait4 (iPid2, (wait_status *) NULL, 0, (struct rusage *) NULL); #else /* ! HAVE_WAIT4 */ (void) wait ((wait_status *) NULL); #endif /* ! HAVE_WAIT4 */ #endif /* ! HAVE_WAITPID */ (void) times (&s2); fprintf (stderr, " First child: user: %g; system: %g\n", (double) (s1.tms_cutime - sbase.tms_cutime) / (double) TIMES_TICK, (double) (s1.tms_cstime - sbase.tms_cstime) / (double) TIMES_TICK); fprintf (stderr, "Second child: user: %g; system: %g\n", (double) (s2.tms_cutime - s1.tms_cutime) / (double) TIMES_TICK, (double) (s2.tms_cstime - s1.tms_cstime) / (double) TIMES_TICK); ucheck_test (iTest, fCall_uucico); if (abLogout1[0] != '\0') { if (zDebug != NULL) fprintf (stderr, "Executing %s\n", abLogout1); (void) system (abLogout1); } if (abLogout2[0] != '\0') { if (zDebug != NULL) fprintf (stderr, "Executing %s\n", abLogout2); (void) system (abLogout2); } fprintf (stderr, "Wrote %d bytes from 1 to 2\n", cFrom1); fprintf (stderr, "Wrote %d bytes from 2 to 1\n", cFrom2); if (access ("/usr/tmp/tstuu/spool1/core", R_OK) == 0) fprintf (stderr, "core file 1 exists\n"); if (access ("/usr/tmp/tstuu/spool2/core", R_OK) == 0) fprintf (stderr, "core file 2 exists\n"); exit (EXIT_SUCCESS); } /* Open a file without error. */ static FILE * xfopen (zname, zmode) const char *zname; const char *zmode; { FILE *eret; eret = fopen (zname, zmode); if (eret == NULL) { perror (zname); exit (EXIT_FAILURE); } return eret; } /* Close a file without error. */ static void xfclose P((FILE *e)); static void xfclose (e) FILE *e; { if (fclose (e) != 0) { perror ("fclose"); exit (EXIT_FAILURE); } } /* Create a test file. */ static void umake_file (z, c) const char *z; int c; { int i; FILE *e; e = xfopen (z, "w"); for (i = 0; i < 256; i++) { int i2; for (i2 = 0; i2 < 256; i2++) putc (i, e); } for (i = 0; i < c; i++) putc (i, e); xfclose (e); } /* Check a test file. */ static void ucheck_file (z, zerr, c) const char *z; const char *zerr; int c; { int i; FILE *e; e = xfopen (z, "r"); for (i = 0; i < 256; i++) { int i2; for (i2 = 0; i2 < 256; i2++) { int bread; bread = getc (e); if (bread == EOF) { fprintf (stderr, "%s: Unexpected EOF at position %d,%d\n", zerr, i, i2); xfclose (e); return; } if (bread != i) fprintf (stderr, "%s: At position %d,%d got %d expected %d\n", zerr, i, i2, bread, i); } } for (i = 0; i < c; i++) { int bread; bread = getc (e); if (bread == EOF) { fprintf (stderr, "%s: Unexpected EOF at extra %d\n", zerr, i); xfclose (e); return; } if (bread != i) fprintf (stderr, "%s: At extra %d got %d expected %d\n", zerr, i, bread, i); } if (getc (e) != EOF) fprintf (stderr, "%s: File is too long", zerr); xfclose (e); } /* Prepare all the configuration files for testing. */ static void uprepare_test (fmake, itest, fcall_uucico, zsys) boolean fmake; int itest; boolean fcall_uucico; const char *zsys; { FILE *e; const char *zuucp1, *zuucp2; const char *zuux1, *zuux2; char ab[1000]; const char *zfrom; const char *zto; /* We must make /usr/tmp/tstuu world writeable or we won't be able to receive files into it. */ (void) umask (0); #ifndef S_IWOTH #define S_IWOTH 02 #endif if (mkdir ((char *) "/usr/tmp/tstuu", IPUBLIC_DIRECTORY_MODE | S_IWOTH) != 0 && errno != EEXIST) { perror ("mkdir"); exit (EXIT_FAILURE); } if (mkdir ((char *) "/usr/tmp/tstuu/spool1", IPUBLIC_DIRECTORY_MODE) != 0 && errno != EEXIST) { perror ("mkdir"); exit (EXIT_FAILURE); } if (mkdir ((char *) "/usr/tmp/tstuu/spool2", IPUBLIC_DIRECTORY_MODE) != 0 && errno != EEXIST) { perror ("mkdir"); exit (EXIT_FAILURE); } if (fmake) { e = xfopen ("/usr/tmp/tstuu/Config1", "w"); fprintf (e, "# First test configuration file\n"); fprintf (e, "nodename test1\n"); fprintf (e, "spool /usr/tmp/tstuu/spool1\n"); fprintf (e, "lockdir /usr/tmp/tstuu/spool1\n"); fprintf (e, "sysfile /usr/tmp/tstuu/System1\n"); fprintf (e, "sysfile /usr/tmp/tstuu/System1.2\n"); fprintf (e, "portfile /usr/tmp/tstuu/Port1\n"); (void) remove ("/usr/tmp/tstuu/Log1"); #if ! HAVE_HDB_LOGGING fprintf (e, "logfile /usr/tmp/tstuu/Log1\n"); #else fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log1/%s/%s"); #endif fprintf (e, "statfile /usr/tmp/tstuu/Stats1\n"); fprintf (e, "debugfile /usr/tmp/tstuu/Debug1\n"); fprintf (e, "callfile /usr/tmp/tstuu/Call1\n"); fprintf (e, "pubdir /usr/tmp/tstuu\n"); #if HAVE_V2_CONFIG fprintf (e, "v2-files no\n"); #endif #if HAVE_HDB_CONFIG fprintf (e, "hdb-files no\n"); #endif if (zDebug != NULL) fprintf (e, "debug %s\n", zDebug); xfclose (e); e = xfopen ("/usr/tmp/tstuu/System1", "w"); fprintf (e, "# This file is ignored, to test multiple system files\n"); fprintf (e, "time never\n"); xfclose (e); e = xfopen ("/usr/tmp/tstuu/System1.2", "w"); fprintf (e, "# First test system file\n"); fprintf (e, "time any\n"); fprintf (e, "port stdin\n"); fprintf (e, "# That was the defaults\n"); fprintf (e, "system %s\n", zsys); if (! fcall_uucico) { FILE *eprog; eprog = xfopen ("/usr/tmp/tstuu/Chat1", "w"); /* Wait for the other side to open the port and flush input. */ fprintf (eprog, "sleep 2\n"); fprintf (eprog, "echo password $1 speed $2 1>&2\n"); fprintf (eprog, "echo test1\n"); fprintf (eprog, "exit 0\n"); xfclose (eprog); if (chmod ("/usr/tmp/tstuu/Chat1", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) { perror ("chmod (/usr/tmp/tstuu/Chat1)"); exit (EXIT_FAILURE); } fprintf (e, "chat-program /usr/tmp/tstuu/Chat1 \\P \\S\n"); fprintf (e, "chat word: \\P\n"); fprintf (e, "chat-fail login;\n"); fprintf (e, "call-login *\n"); fprintf (e, "call-password *\n"); } else fprintf (e, "chat \"\"\n"); fprintf (e, "call-transfer yes\n"); fprintf (e, "commands cat\n"); if (! fcall_uucico && iPercent == 0) { fprintf (e, "protocol-parameter g window 7\n"); fprintf (e, "protocol-parameter g packet-size 4096\n"); fprintf (e, "protocol-parameter j avoid \\377\n"); } if (zProtocols != NULL) fprintf (e, "protocol %s\n", zProtocols); xfclose (e); e = xfopen ("/usr/tmp/tstuu/Port1", "w"); fprintf (e, "port stdin\n"); fprintf (e, "type stdin\n"); fprintf (e, "pty true\n"); xfclose (e); e = xfopen ("/usr/tmp/tstuu/Call1", "w"); fprintf (e, "Call out password file\n"); fprintf (e, "%s test1 pass1\n", zsys); xfclose (e); if (! fcall_uucico) { FILE *eprog; e = xfopen ("/usr/tmp/tstuu/Config2", "w"); fprintf (e, "# Second test configuration file\n"); fprintf (e, "nodename test2\n"); fprintf (e, "spool /usr/tmp/tstuu/spool2\n"); fprintf (e, "lockdir /usr/tmp/tstuu/spool2\n"); fprintf (e, "sysfile /usr/tmp/tstuu/System2\n"); (void) remove ("/usr/tmp/tstuu/Log2"); #if ! HAVE_HDB_LOGGING fprintf (e, "logfile /usr/tmp/tstuu/Log2\n"); #else fprintf (e, "%s\n", "logfile /usr/tmp/tstuu/Log2/%s/%s"); #endif fprintf (e, "statfile /usr/tmp/tstuu/Stats2\n"); fprintf (e, "debugfile /usr/tmp/tstuu/Debug2\n"); fprintf (e, "passwdfile /usr/tmp/tstuu/Pass2\n"); fprintf (e, "pubdir /usr/tmp/tstuu\n"); #if HAVE_V2_CONFIG fprintf (e, "v2-files no\n"); #endif #if HAVE_HDB_CONFIG fprintf (e, "hdb-files no\n"); #endif if (zDebug != NULL) fprintf (e, "debug %s\n", zDebug); xfclose (e); e = xfopen ("/usr/tmp/tstuu/System2", "w"); fprintf (e, "# Second test system file\n"); fprintf (e, "system test1\n"); fprintf (e, "called-login test1\n"); fprintf (e, "request true\n"); fprintf (e, "commands cat\n"); if (zProtocols != NULL) fprintf (e, "protocol %s\n", zProtocols); eprog = xfopen ("/usr/tmp/tstuu/Chat2", "w"); fprintf (eprog, "echo port $1 1>&2\n"); fprintf (eprog, "exit 0\n"); xfclose (eprog); if (chmod ("/usr/tmp/tstuu/Chat2", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) { perror ("chmod (/usr/tmp/tstuu/Chat2"); exit (EXIT_FAILURE); } fprintf (e, "called-chat-program /bin/sh /usr/tmp/tstuu/Chat2 \\Y\n"); fprintf (e, "time any\n"); xfclose (e); e = xfopen ("/usr/tmp/tstuu/Pass2", "w"); fprintf (e, "# Call in password file\n"); fprintf (e, "test1 pass1\n"); xfclose (e); } } zuucp1 = "./uucp -I /usr/tmp/tstuu/Config1 -r"; zuux1 = "./uux -I /usr/tmp/tstuu/Config1 -r"; if (fcall_uucico) { zuucp2 = "/usr/bin/uucp -r"; zuux2 = "/usr/bin/uux -r"; } else { zuucp2 = "./uucp -I /usr/tmp/tstuu/Config2 -r"; zuux2 = "./uux -I /usr/tmp/tstuu/Config2 -r"; } /* Test transferring a file from the first system to the second. */ if (itest == 0 || itest == 1) { zfrom = "/usr/tmp/tstuu/from1"; if (fcall_uucico) zto = "/usr/spool/uucppublic/to1"; else zto = "/usr/tmp/tstuu/to1"; (void) remove (zto); umake_file (zfrom, 0); sprintf (ab, "%s %s %s!%s", zuucp1, zfrom, zsys, zto); xsystem (ab); } /* Test having the first system request a file from the second. */ if (itest == 0 || itest == 2) { if (fcall_uucico) zfrom = "/usr/spool/uucppublic/from2"; else zfrom = "/usr/tmp/tstuu/from2"; zto = "/usr/tmp/tstuu/to2"; (void) remove (zto); umake_file (zfrom, 3); sprintf (ab, "%s %s!%s %s", zuucp1, zsys, zfrom, zto); xsystem (ab); } /* Test having the second system send a file to the first. */ if (itest == 0 || itest == 3) { if (fcall_uucico) zfrom = "/usr/spool/uucppublic/from3"; else zfrom = "/usr/tmp/tstuu/from3"; zto = "/usr/tmp/tstuu/to3"; (void) remove (zto); umake_file (zfrom, 5); sprintf (ab, "%s -c \\~/from3 test1!~/to3", zuucp2); xsystem (ab); } /* Test having the second system request a file from the first. */ if (itest == 0 || itest == 4) { zfrom = "/usr/tmp/tstuu/from4"; if (fcall_uucico) zto = "/usr/spool/uucppublic/to4"; else zto = "/usr/tmp/tstuu/to4"; (void) remove (zto); umake_file (zfrom, 7); sprintf (ab, "%s test1!%s %s", zuucp2, zfrom, zto); xsystem (ab); } /* Test having the second system make an execution request. */ if (itest == 0 || itest == 5) { zfrom = "/usr/tmp/tstuu/from5"; if (fcall_uucico) zto = "/usr/spool/uucppublic/to5"; else zto = "/usr/tmp/tstuu/to5"; (void) remove (zto); umake_file (zfrom, 11); sprintf (ab, "%s test1!cat '<%s' '>%s'", zuux2, zfrom, zto); xsystem (ab); } /* Test having the first system request a wildcard. */ if (itest == 0 || itest == 6) { const char *zfrom1, *zfrom2; if (fcall_uucico) { zfrom = "/usr/spool/uucppublic/to6\\*"; zfrom1 = "/usr/spool/uucppublic/to6.1"; zfrom2 = "/usr/spool/uucppublic/to6.2"; } else { zfrom = "/usr/tmp/tstuu/spool2/to6\\*"; zfrom1 = "/usr/tmp/tstuu/spool2/to6.1"; zfrom2 = "/usr/tmp/tstuu/spool2/to6.2"; } umake_file (zfrom1, 100); umake_file (zfrom2, 101); (void) remove ("/usr/tmp/tstuu/to6.1"); (void) remove ("/usr/tmp/tstuu/to6.2"); sprintf (ab, "%s %s!%s /usr/tmp/tstuu", zuucp1, zsys, zfrom); xsystem (ab); } /* Test having the second system request a wildcard. */ if (itest == 0 || itest == 7) { const char *zto1, *zto2; if (fcall_uucico) { zto = "/usr/spool/uucppublic"; zto1 = "/usr/spool/uucppublic/to7.1"; zto2 = "/usr/spool/uucppublic/to7.2"; } else { zto = "/usr/tmp/tstuu"; zto1 = "/usr/tmp/tstuu/to7.1"; zto2 = "/usr/tmp/tstuu/to7.2"; } umake_file ("/usr/tmp/tstuu/spool1/to7.1", 150); umake_file ("/usr/tmp/tstuu/spool1/to7.2", 155); (void) remove (zto1); (void) remove (zto2); sprintf (ab, "%s test1!/usr/tmp/tstuu/spool1/to7.\\* %s", zuucp2, zto); xsystem (ab); } /* Test an E command. This runs cat, discarding the output. */ if ((itest == 0 || itest == 8) && ! fcall_uucico) { umake_file ("/usr/tmp/tstuu/from8", 30); sprintf (ab, "%s - test2!cat < /usr/tmp/tstuu/from8", zuux1); xsystem (ab); } } /* Try to make sure the file transfers were successful. */ static void ucheck_test (itest, fcall_uucico) int itest; boolean fcall_uucico; { if (itest == 0 || itest == 1) { if (fcall_uucico) ucheck_file ("/usr/spool/uucppublic/to1", "test 1", 0); else ucheck_file ("/usr/tmp/tstuu/to1", "test 1", 0); } if (itest == 0 || itest == 2) ucheck_file ("/usr/tmp/tstuu/to2", "test 2", 3); if (itest == 0 || itest == 3) ucheck_file ("/usr/tmp/tstuu/to3", "test 3", 5); if (itest == 0 || itest == 4) { if (fcall_uucico) ucheck_file ("/usr/spool/uucppublic/to4", "test 4", 7); else ucheck_file ("/usr/tmp/tstuu/to4", "test 4", 7); } if (itest == 0 || itest == 6) { ucheck_file ("/usr/tmp/tstuu/to6.1", "test 6.1", 100); ucheck_file ("/usr/tmp/tstuu/to6.2", "test 6.2", 101); } if (itest == 0 || itest == 7) { const char *zto1, *zto2; if (fcall_uucico) { zto1 = "/usr/spool/uucppublic/to7.1"; zto2 = "/usr/spool/uucppublic/to7.2"; } else { zto1 = "/usr/tmp/tstuu/to7.1"; zto2 = "/usr/tmp/tstuu/to7.2"; } ucheck_file (zto1, "test 7.1", 150); ucheck_file (zto2, "test 7.2", 155); } } /* A debugging routine used when displaying buffers. */ static int cpshow (z, ichar) char *z; int ichar; { if (isprint (BUCHAR (ichar)) && ichar != '\"') { *z = (char) ichar; return 1; } *z++ = '\\'; switch (ichar) { case '\n': *z = 'n'; return 2; case '\r': *z = 'r'; return 2; case '\"': *z = '\"'; return 2; default: sprintf (z, "%03o", (unsigned int)(ichar & 0xff)); return strlen (z) + 1; } } /* Pick one of two file descriptors which is ready for reading, or return in five seconds. If the argument is ready for reading, leave it alone; otherwise set it to -1. */ static void uchoose (po1, po2) int *po1; int *po2; { #if HAVE_SELECT int iread; struct timeval stime; iread = (1 << *po1) | (1 << *po2); stime.tv_sec = 5; stime.tv_usec = 0; if (select ((*po1 > *po2 ? *po1 : *po2) + 1, (pointer) &iread, (pointer) NULL, (pointer) NULL, &stime) < 0) { perror ("select"); uchild (SIGCHLD); } if ((iread & (1 << *po1)) == 0) *po1 = -1; if ((iread & (1 << *po2)) == 0) *po2 = -1; #else /* ! HAVE_SELECT */ #if HAVE_POLL struct pollfd as[2]; as[0].fd = *po1; as[0].events = POLLIN; as[1].fd = *po2; as[1].events = POLLIN; if (poll (as, 2, 5 * 1000) < 0) { perror ("poll"); uchild (SIGCHLD); } if ((as[0].revents & POLLIN) == 0) *po1 = -1; if ((as[1].revents & POLLIN) == 0) *po2 = -1; #endif /* HAVE_POLL */ #endif /* ! HAVE_SELECT */ } /* Read some data from a file descriptor. This keeps reading until one of the reads gets no data. */ static long cread (o, pqbuf) int o; struct sbuf **pqbuf; { long ctotal; while (*pqbuf != NULL && (*pqbuf)->qnext != NULL) pqbuf = &(*pqbuf)->qnext; ctotal = 0; while (TRUE) { int cgot; if (*pqbuf != NULL && (*pqbuf)->cend >= sizeof (*pqbuf)->ab) pqbuf = &(*pqbuf)->qnext; if (*pqbuf == NULL) { *pqbuf = (struct sbuf *) malloc (sizeof (struct sbuf)); if (*pqbuf == NULL) { fprintf (stderr, "Out of memory\n"); uchild (SIGCHLD); } (*pqbuf)->qnext = NULL; (*pqbuf)->cstart = 0; (*pqbuf)->cend = 0; } cgot = read (o, (*pqbuf)->ab + (*pqbuf)->cend, (sizeof (*pqbuf)->ab) - (*pqbuf)->cend); if (cgot < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) cgot = 0; else { perror ("read"); uchild (SIGCHLD); } } if (cgot == 0) return ctotal; ctotal += cgot; if (zDebug != NULL) { char abshow[325]; char *zfrom; char *zshow; int i; zfrom = (*pqbuf)->ab + (*pqbuf)->cend; zshow = abshow; for (i = 0; i < cgot && i < 80; i++, zfrom++) zshow += cpshow (zshow, *zfrom); if (i < cgot) { *zshow++ = '.'; *zshow++ = '.'; *zshow++ = '.'; } *zshow = '\0'; fprintf (stderr, "Read from %d: %d \"%s\"\n", o, cgot, abshow); fflush (stderr); } if (iPercent > 0) { int i; int c; c = 0; for (i = 0; i < cgot; i++) { if (rand () % 1000 < iPercent) { ++(*pqbuf)->ab[(*pqbuf)->cend + i]; ++c; } } if (zDebug != NULL && c > 0) fprintf (stderr, "Clobbered %d bytes\n", c); } (*pqbuf)->cend += cgot; if (ctotal > 256) return ctotal; } } /* Write data to a file descriptor until one of the writes gets no data. */ static boolean fsend (o, oslave, pqbuf) int o; int oslave; struct sbuf **pqbuf; { long ctotal; ctotal = 0; while (*pqbuf != NULL) { int cwrite, cwrote; if ((*pqbuf)->cstart >= (*pqbuf)->cend) { struct sbuf *qfree; qfree = *pqbuf; *pqbuf = (*pqbuf)->qnext; free ((pointer) qfree); continue; } #ifdef FIONREAD { long cunread; if (ioctl (oslave, FIONREAD, &cunread) < 0) { perror ("FIONREAD"); uchild (SIGCHLD); } if (zDebug != NULL) fprintf (stderr, "%ld unread\n", cunread); cwrite = 256 - cunread; if (cwrite <= 0) break; } #else /* ! FIONREAD */ if (! fwritable (o)) break; cwrite = 1; #endif /* ! FIONREAD */ if (cwrite > (*pqbuf)->cend - (*pqbuf)->cstart) cwrite = (*pqbuf)->cend - (*pqbuf)->cstart; cwrote = write (o, (*pqbuf)->ab + (*pqbuf)->cstart, cwrite); if (cwrote < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA) cwrote = 0; else { perror ("write"); uchild (SIGCHLD); } } if (cwrote == 0) break; ctotal += cwrote; (*pqbuf)->cstart += cwrote; } if (zDebug != NULL && ctotal > 0) fprintf (stderr, "Wrote %ld to %d\n", ctotal, o); return ctotal > 0; } /* Check whether a file descriptor can be written to. */ static boolean fwritable (o) int o; { #if HAVE_SELECT int iwrite; struct timeval stime; int cfds; iwrite = 1 << o; stime.tv_sec = 0; stime.tv_usec = 0; cfds = select (o + 1, (pointer) NULL, (pointer) &iwrite, (pointer) NULL, &stime); if (cfds < 0) { perror ("select"); uchild (SIGCHLD); } return cfds > 0; #else /* ! HAVE_SELECT */ #if HAVE_POLL struct pollfd s; int cfds; s.fd = o; s.events = POLLOUT; cfds = poll (&s, 1, 0); if (cfds < 0) { perror ("poll"); uchild (SIGCHLD); } return cfds > 0; #endif /* HAVE_POLL */ #endif /* ! HAVE_SELECT */ } /* A version of the system command that checks for errors. */ static void xsystem (zcmd) const char *zcmd; { int istat; istat = system ((char *) zcmd); if (istat != 0) { fprintf (stderr, "Command failed with status %d\n", istat); fprintf (stderr, "%s\n", zcmd); exit (EXIT_FAILURE); } } 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", zuuuucp-1.04/util.c1004440004150000170000000667005337263517010521 037777777777 1 0 /* 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.2 1992/07/26 03:53:00 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "system.h" /* Get information for an unknown system. This will leave the name allocated on the heap. We could fix this by breaking the abstraction and adding the name to qsys->palloc. It makes sure the name is not too long, but takes no other useful action. */ boolean funknown_system (puuconf, zsystem, qsys) pointer puuconf; const char *zsystem; struct uuconf_system *qsys; { char *z; int iuuconf; if (strlen (zsystem) <= cSysdep_max_name_len) z = zbufcpy (zsystem); else { char **pznames, **pz; boolean ffound; z = zbufalc (cSysdep_max_name_len + 1); memcpy (z, zsystem, cSysdep_max_name_len); z[cSysdep_max_name_len] = '\0'; iuuconf = uuconf_system_names (puuconf, &pznames, TRUE); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); ffound = FALSE; for (pz = pznames; *pz != NULL; pz++) { if (strcmp (*pz, z) == 0) ffound = TRUE; xfree ((pointer) *pz); } xfree ((pointer) pznames); if (ffound) { ubuffree (z); return FALSE; } } iuuconf = uuconf_system_unknown (puuconf, qsys); if (iuuconf == UUCONF_NOT_FOUND) { ubuffree (z); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); for (; qsys != NULL; qsys = qsys->uuconf_qalternate) qsys->uuconf_zname = z; return TRUE; } /* See whether a file is in a directory list, and make sure the user has appropriate access. */ boolean fin_directory_list (zfile, pzdirs, zpubdir, fcheck, freadable, zuser) const char *zfile; char **pzdirs; const char *zpubdir; boolean fcheck; boolean freadable; const char *zuser; { boolean fmatch; char **pz; fmatch = FALSE; for (pz = pzdirs; *pz != NULL; pz++) { char *zuse; if (pz[0][0] == '!') { zuse = zsysdep_local_file (*pz + 1, zpubdir); if (zuse == NULL) return FALSE; if (fsysdep_in_directory (zfile, zuse, FALSE, FALSE, (const char *) NULL)) fmatch = FALSE; } else { zuse = zsysdep_local_file (*pz, zpubdir); if (zuse == NULL) return FALSE; if (fsysdep_in_directory (zfile, zuse, fcheck, freadable, zuser)) fmatch = TRUE; } ubuffree (zuse); } return fmatch; } 0); ucheck_file (zto2, "test 7.2", 155); } } /* A debugging uucp-1.04/uuchk.c1004440004150000170000005423405337263520010654 037777777777 1 0 /* 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.37 1992/10/16 05:10:26 ian Rel $"; #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); } } 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"); uucp-1.04/uucico.81004440004150000170000001250705337263520010746 037777777777 1 0 ''' $Id: uucico.8,v 1.10 1993/01/24 00:52:31 ian Rel $ .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) f_pzfail != NULL) { printf ("%s failure strings", zhdr); for (pz = qchat->uuconf_pzfail; *pz != NULL; pz++) printf (" %s", *pz); printf ("\n"); } if (qchat->uuconfuucp-1.04/uucico.c1004440004150000170000020161705337263521011024 037777777777 1 0 /* 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.140 1993/01/18 05:03:06 ian Rel $"; #endif #include #if HAVE_LIMITS_H #include #else #define LONG_MAX 2147483647L #endif #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "conn.h" #include "prot.h" #include "trans.h" #include "system.h" /* The program name. */ char abProgram[] = "uucico"; /* Define the known protocols. */ #define TCP_PROTO \ (UUCONF_RELIABLE_ENDTOEND \ | UUCONF_RELIABLE_RELIABLE \ | UUCONF_RELIABLE_EIGHT) static const struct sprotocol asProtocols[] = { { 't', TCP_PROTO, 1, asTproto_params, ftstart, ftshutdown, ftsendcmd, ztgetspace, ftsenddata, ftwait, ftfile }, { 'e', TCP_PROTO, 1, asEproto_params, festart, feshutdown, fesendcmd, zegetspace, fesenddata, fewait, fefile }, { 'i', UUCONF_RELIABLE_EIGHT, 7, asIproto_params, fistart, fishutdown, fisendcmd, zigetspace, fisenddata, fiwait, NULL }, { 'a', UUCONF_RELIABLE_EIGHT, 1, asZproto_params, fzstart, fzshutdown, fzsendcmd, zzgetspace, fzsenddata, fzwait, fzfile }, { 'g', UUCONF_RELIABLE_EIGHT, 1, asGproto_params, fgstart, fgshutdown, fgsendcmd, zggetspace, fgsenddata, fgwait, NULL }, { 'G', UUCONF_RELIABLE_EIGHT, 1, asGproto_params, fbiggstart, fgshutdown, fgsendcmd, zggetspace, fgsenddata, fgwait, NULL }, { 'j', UUCONF_RELIABLE_EIGHT, 7, asIproto_params, fjstart, fjshutdown, fisendcmd, zigetspace, fisenddata, fiwait, NULL }, { 'f', UUCONF_RELIABLE_RELIABLE, 1, asFproto_params, ffstart, ffshutdown, ffsendcmd, zfgetspace, ffsenddata, ffwait, fffile }, }; #define CPROTOCOLS (sizeof asProtocols / sizeof asProtocols[0]) /* Locked system. */ static boolean fLocked_system; static struct uuconf_system sLocked_system; /* Daemon structure holding information about the remote system (must be global so the error handler can see it. */ static struct sdaemon sDaemon; /* Open connection. */ static struct sconnection *qConn; /* uuconf global pointer; need to close the connection after a fatal error. */ static pointer pUuconf; /* This structure is passed to iuport_lock via uuconf_find_port. */ struct spass { boolean fmatched; boolean flocked; struct sconnection *qconn; }; /* Local functions. */ static void uusage P((void)); static void uabort P((void)); static boolean fcall P((pointer puuconf, const struct uuconf_system *qsys, struct uuconf_port *qport, boolean fifwork, boolean fforce, boolean fdetach, boolean ftimewarn)); static boolean fconn_call P((struct sdaemon *qdaemon, struct uuconf_port *qport, struct sstatus *qstat, int cretry, boolean *pfcalled)); static boolean fdo_call P((struct sdaemon *qdaemon, struct sstatus *qstat, const struct uuconf_dialer *qdialer, boolean *pfcalled, enum tstatus_type *pterr)); static int iuport_lock P((struct uuconf_port *qport, pointer pinfo)); static boolean flogin_prompt P((pointer puuconf, struct sconnection *qconn)); static boolean faccept_call P((pointer puuconf, const char *zlogin, struct sconnection *qconn, const char **pzsystem)); static void uapply_proto_params P((pointer puuconf, int bproto, struct uuconf_cmdtab *qcmds, struct uuconf_proto_param *pas)); static boolean fsend_uucp_cmd P((struct sconnection *qconn, const char *z)); static char *zget_uucp_cmd P((struct sconnection *qconn, boolean frequired)); static char *zget_typed_line P((struct sconnection *qconn)); /* Long getopt options. */ static const struct option asLongopts[] = { { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* -c: Whether to warn if a call is attempted at a bad time. */ boolean ftimewarn = TRUE; /* -D: don't detach from controlling terminal. */ boolean fdetach = TRUE; /* -e: Whether to do an endless loop of accepting calls. */ boolean fendless = FALSE; /* -f: Whether to force a call despite status of previous call. */ boolean fforce = FALSE; /* -I file: configuration file name. */ const char *zconfig = NULL; /* -l: Whether to give a single login prompt. */ boolean flogin = FALSE; /* -P port: port to use; in master mode, call out on this port. In slave mode, accept logins on this port. If port not specified, then in master mode figure it out for each system, and in slave mode use stdin and stdout. */ const char *zport = NULL; /* -q: Whether to start uuxqt when done. */ boolean fuuxqt = TRUE; /* -r1: Whether we are the master. */ boolean fmaster = FALSE; /* -s,-S system: system to call. */ const char *zsystem = NULL; /* -w: Whether to wait for a call after doing one. */ boolean fwait = FALSE; int iopt; struct uuconf_port *qport; struct uuconf_port sport; boolean fret = TRUE; pointer puuconf; int iuuconf; #if DEBUG > 1 int iholddebug; #endif while ((iopt = getopt_long (argc, argv, "cDefI:lp:qr:s:S:u:x:X:w", asLongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'c': /* Don't warn if a call is attempted at a bad time. */ ftimewarn = FALSE; break; case 'D': /* Don't detach from controlling terminal. */ fdetach = FALSE; break; case 'e': /* Do an endless loop of accepting calls. */ fendless = TRUE; break; case 'f': /* Force a call even if it hasn't been long enough since the last failed call. */ fforce = TRUE; break; case 'I': /* Set configuration file name (default is in sysdep.h). */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'l': /* Prompt for login name and password. */ flogin = TRUE; break; case 'p': /* Port to use */ zport = optarg; break; case 'q': /* Don't start uuxqt. */ fuuxqt = FALSE; break; case 'r': /* Set mode: -r1 for master, -r0 for slave (default) */ if (strcmp (optarg, "1") == 0) fmaster = TRUE; else if (strcmp (optarg, "0") == 0) fmaster = FALSE; else uusage (); break; case 's': /* Set system name */ zsystem = optarg; fmaster = TRUE; break; case 'S': /* Set system name and force call like -f */ zsystem = optarg; fforce = TRUE; fmaster = TRUE; break; case 'u': /* Some versions of uucpd invoke uucico with a -u argument specifying the login name. I'm told it is safe to ignore this value, although perhaps we should use it rather than zsysdep_login_name (). */ break; case 'x': case 'X': #if DEBUG > 1 /* Set debugging level */ iDebug |= idebug_parse (optarg); #endif break; case 'w': /* Call out and then wait for a call in */ fwait = TRUE; break; case 0: /* Long option found, and flag value set. */ break; default: uusage (); break; } } if (optind != argc) uusage (); if (fwait && zport == NULL) { ulog (LOG_ERROR, "-w requires -e"); uusage (); } iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); pUuconf = puuconf; #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif /* If a port was named, get its information. */ if (zport == NULL) qport = NULL; else { iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0, (int (*) P((struct uuconf_port *, pointer))) NULL, (pointer) NULL, &sport); if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_FATAL, "%s: Port not found", zport); else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); qport = &sport; } #ifdef SIGINT usysdep_signal (SIGINT); #endif #ifdef SIGHUP usysdep_signal (SIGHUP); #endif #ifdef SIGQUIT usysdep_signal (SIGQUIT); #endif #ifdef SIGTERM usysdep_signal (SIGTERM); #endif #ifdef SIGPIPE usysdep_signal (SIGPIPE); #endif usysdep_initialize (puuconf, INIT_SUID); ulog_to_file (puuconf, TRUE); ulog_fatal_fn (uabort); if (fmaster) { if (zsystem != NULL) { /* A system was named. Call it. */ iuuconf = uuconf_system_info (puuconf, zsystem, &sLocked_system); if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_FATAL, "%s: System not found", zsystem); else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); /* Detach from the controlling terminal for the call. This probably makes sense only on Unix. We want the modem line to become the controlling terminal. */ if (fdetach && (qport == NULL || qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)) usysdep_detach (); ulog_system (sLocked_system.uuconf_zname); #if DEBUG > 1 iholddebug = iDebug; if (sLocked_system.uuconf_zdebug != NULL) iDebug |= idebug_parse (sLocked_system.uuconf_zdebug); #endif if (! fsysdep_lock_system (&sLocked_system)) { ulog (LOG_ERROR, "System already locked"); fret = FALSE; } else { fLocked_system = TRUE; fret = fcall (puuconf, &sLocked_system, qport, FALSE, fforce, fdetach, ftimewarn); if (fLocked_system) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; } } #if DEBUG > 1 iDebug = iholddebug; #endif ulog_system ((const char *) NULL); (void) uuconf_system_free (puuconf, &sLocked_system); } else { char **pznames, **pz; int c, i; boolean fdidone; /* Call all systems which have work to do. */ fret = TRUE; fdidone = FALSE; iuuconf = uuconf_system_names (puuconf, &pznames, 0); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); /* Randomize the order in which we call the systems. */ c = 0; for (pz = pznames; *pz != NULL; pz++) c++; srand ((unsigned int) ixsysdep_time ((long *) NULL)); for (i = c - 1; i > 0; i--) { int iuse; char *zhold; iuse = rand () % (i + 1); zhold = pznames[i]; pznames[i] = pznames[iuse]; pznames[iuse] = zhold; } for (pz = pznames; *pz != NULL && ! FGOT_SIGNAL (); pz++) { iuuconf = uuconf_system_info (puuconf, *pz, &sLocked_system); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); xfree ((pointer) *pz); continue; } if (fsysdep_has_work (&sLocked_system)) { fdidone = TRUE; /* Detach from the controlling terminal. On Unix this means that we will wind up forking a new process for each system we call. */ if (fdetach && (qport == NULL || qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)) usysdep_detach (); ulog_system (sLocked_system.uuconf_zname); #if DEBUG > 1 iholddebug = iDebug; if (sLocked_system.uuconf_zdebug != NULL) iDebug |= idebug_parse (sLocked_system.uuconf_zdebug); #endif if (! fsysdep_lock_system (&sLocked_system)) { ulog (LOG_ERROR, "System already locked"); fret = FALSE; } else { fLocked_system = TRUE; if (! fcall (puuconf, &sLocked_system, qport, TRUE, fforce, fdetach, ftimewarn)) fret = FALSE; /* Now ignore any SIGHUP that we got. */ afSignal[INDEXSIG_SIGHUP] = FALSE; if (fLocked_system) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; } } #if DEBUG > 1 iDebug = iholddebug; #endif ulog_system ((const char *) NULL); } (void) uuconf_system_free (puuconf, &sLocked_system); xfree ((pointer) *pz); } xfree ((pointer) pznames); if (! fdidone) ulog (LOG_NORMAL, "No work"); } /* If requested, wait for calls after dialing out. */ if (fwait) { fendless = TRUE; fmaster = FALSE; } } if (! fmaster) { struct sconnection sconn; boolean flocked; /* If a port was specified by name, we go into endless loop mode. In this mode, we wait for calls and prompt them with "login:" and "Password:", so that they think we are a regular UNIX system. If we aren't in endless loop mode, we have been called by some other system. If flogin is TRUE, we prompt with "login:" and "Password:" a single time. */ fret = TRUE; zsystem = NULL; if (! fconn_init (qport, &sconn)) fret = FALSE; if (qport != NULL) { /* We are not using standard input. Detach from the controlling terminal, so that the port we are about to use becomes our controlling terminal. */ if (fdetach && qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) usysdep_detach (); /* If a port was given, we loop forever. */ fendless = TRUE; } if (fconn_lock (&sconn, TRUE)) flocked = TRUE; else { flocked = FALSE; ulog (LOG_ERROR, "%s: Port already locked", qport->uuconf_zname); fret = FALSE; } if (fret) { if (! fconn_open (&sconn, (long) 0, (long) 0, TRUE)) fret = FALSE; qConn = &sconn; } if (fret) { if (fendless) { while (! FGOT_SIGNAL () && flogin_prompt (puuconf, &sconn)) { /* Now ignore any SIGHUP that we got. */ afSignal[INDEXSIG_SIGHUP] = FALSE; if (fLocked_system) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; } if (! fconn_reset (&sconn)) break; } fret = FALSE; } else { if (flogin) fret = flogin_prompt (puuconf, &sconn); else { #if DEBUG > 1 iholddebug = iDebug; #endif fret = faccept_call (puuconf, zsysdep_login_name (), &sconn, &zsystem); #if DEBUG > 1 iDebug = iholddebug; #endif } } } if (qConn != NULL) { if (! fconn_close (&sconn, puuconf, (struct uuconf_dialer *) NULL, fret)) fret = FALSE; qConn = NULL; } if (flocked) (void) fconn_unlock (&sconn); if (fLocked_system) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; } uconn_free (&sconn); } ulog_close (); ustats_close (); /* If we got a SIGTERM, perhaps because the system is going down, don't run uuxqt. We go ahead and run it for any other signal, since I think they indicate more temporary conditions. */ if (afSignal[INDEXSIG_SIGTERM]) fuuxqt = FALSE; if (fuuxqt) { /* Detach from the controlling terminal before starting up uuxqt, so that it runs as a true daemon. */ if (fdetach) usysdep_detach (); if (zsystem == NULL) { if (! fsysdep_run ("uuxqt", (const char *) NULL, (const char *) NULL)) fret = FALSE; } else { if (! fsysdep_run ("uuxqt", "-s", zsystem)) fret = FALSE; } } usysdep_exit (fret); /* Avoid complaints about not returning. */ return 0; } /* Print out a usage message. */ static void uusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uucico [options]\n"); fprintf (stderr, " -s,-S system: Call system (-S implies -f)\n"); fprintf (stderr, " -f: Force call despite system status\n"); fprintf (stderr, " -r state: 1 for master, 0 for slave (default)\n"); fprintf (stderr, " -p port: Specify port (implies -e)\n"); fprintf (stderr, " -l: prompt for login name and password\n"); fprintf (stderr, " -e: Endless loop of login prompts and daemon execution\n"); fprintf (stderr, " -w: After calling out, wait for incoming calls\n"); fprintf (stderr, " -q: Don't start uuxqt when done\n"); fprintf (stderr, " -x,-X debug: Set debugging level\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* This function is called when a LOG_FATAL error occurs. */ static void uabort () { if (fLocked_system) ufailed (&sDaemon); ulog_user ((const char *) NULL); if (qConn != NULL) { (void) fconn_close (qConn, pUuconf, (struct uuconf_dialer *) NULL, FALSE); (void) fconn_unlock (qConn); uconn_free (qConn); } if (fLocked_system) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; } ulog_system ((const char *) NULL); ulog_close (); ustats_close (); usysdep_exit (FALSE); } /* Call another system, trying all the possible sets of calling instructions. The qsys argument is the system to call. The qport argument is the port to use, and may be NULL. If the fifwork argument is TRUE, the call is only placed if there is work to be done. If the fforce argument is TRUE, a call is forced even if not enough time has passed since the last failed call. If the ftimewarn argument is TRUE (the normal case), then a warning is given if calls are not permitted at this time. */ static boolean fcall (puuconf, qorigsys, qport, fifwork, fforce, fdetach, ftimewarn) pointer puuconf; const struct uuconf_system *qorigsys; struct uuconf_port *qport; boolean fifwork; boolean fforce; boolean fdetach; boolean ftimewarn; { struct sstatus sstat; long inow; boolean fbadtime, fnevertime; const struct uuconf_system *qsys; if (! fsysdep_get_status (qorigsys, &sstat, (boolean *) NULL)) return FALSE; /* Make sure it's been long enough since the last failed call, and that we haven't exceeded the maximum number of retries. Even if we are over the limit on retries, we permit a call to be made if 24 hours have passed. This 24 hour limit is still controlled by the retry time. */ inow = ixsysdep_time ((long *) NULL); if (! fforce) { if (qorigsys->uuconf_cmax_retries > 0 && sstat.cretries >= qorigsys->uuconf_cmax_retries && sstat.ilast + 24 * 60 * 60 < inow) { ulog (LOG_ERROR, "Too many retries"); return FALSE; } if (sstat.ttype == STATUS_COMPLETE ? sstat.ilast + qorigsys->uuconf_csuccess_wait > inow : sstat.ilast + sstat.cwait > inow) { ulog (LOG_NORMAL, "Retry time not reached"); return FALSE; } } sDaemon.puuconf = puuconf; sDaemon.qsys = NULL; sDaemon.zlocalname = NULL; sDaemon.qconn = NULL; sDaemon.qproto = NULL; sDaemon.clocal_size = -1; sDaemon.cremote_size = -1; sDaemon.cmax_ever = -2; sDaemon.cmax_receive = -1; sDaemon.ifeatures = 0; sDaemon.frequest_hangup = FALSE; sDaemon.fhangup_requested = FALSE; sDaemon.fhangup = FALSE; sDaemon.fmaster = TRUE; sDaemon.fcaller = TRUE; sDaemon.ireliable = 0; sDaemon.bgrade = '\0'; fbadtime = TRUE; fnevertime = TRUE; for (qsys = qorigsys; qsys != NULL; qsys = qsys->uuconf_qalternate) { int cretry; boolean fany, fret, fcalled; if (FGOT_SIGNAL ()) return FALSE; if (! qsys->uuconf_fcall || qsys->uuconf_qtimegrade == NULL) continue; fnevertime = FALSE; /* Make sure this is a legal time to call. */ if (! ftimespan_match (qsys->uuconf_qtimegrade, (long *) NULL, &cretry)) continue; sDaemon.qsys = qsys; /* Queue up any work there is to do. */ if (! fqueue (&sDaemon, &fany)) return FALSE; /* If we are only supposed to call if there is work, and there isn't any work, check the next alternates. We can't give up at this point because there might be some other alternates with fewer restrictions on grade or file transfer size. */ if (fifwork && ! fany) { uclear_queue (&sDaemon); continue; } fbadtime = FALSE; fret = fconn_call (&sDaemon, qport, &sstat, cretry, &fcalled); uclear_queue (&sDaemon); if (fret) return TRUE; if (fcalled) return FALSE; /* Now we have to dump that port so that we can aquire a new one. On Unix this means that we will fork and get a new process ID, so we must unlock and relock the system. */ if (fdetach) { (void) fsysdep_unlock_system (&sLocked_system); fLocked_system = FALSE; usysdep_detach (); if (! fsysdep_lock_system (&sLocked_system)) return FALSE; fLocked_system = TRUE; } } if (fbadtime && ftimewarn) { ulog (LOG_NORMAL, "Wrong time to call"); /* Update the status, unless the system can never be called. If the system can never be called, there is little point to putting in a ``wrong time to call'' message. We don't change the number of retries, although we do set the wait until the next retry to 0. */ if (! fnevertime) { sstat.ttype = STATUS_WRONG_TIME; sstat.ilast = inow; sstat.cwait = 0; (void) fsysdep_set_status (qorigsys, &sstat); } } return FALSE; } /* Find a port to use when calling a system, open a connection, and dial the system. The actual call is done in fdo_call. This routine is responsible for opening and closing the connection. */ static boolean fconn_call (qdaemon, qport, qstat, cretry, pfcalled) struct sdaemon *qdaemon; struct uuconf_port *qport; struct sstatus *qstat; int cretry; boolean *pfcalled; { pointer puuconf; const struct uuconf_system *qsys; struct uuconf_port sport; struct sconnection sconn; enum tstatus_type terr; boolean fret; puuconf = qdaemon->puuconf; qsys = qdaemon->qsys; *pfcalled = FALSE; /* Ignore any SIGHUP signal we may have received up to this point. This is needed on Unix because we may have gotten one from the shell before we detached from the controlling terminal. */ afSignal[INDEXSIG_SIGHUP] = FALSE; /* If no port was specified on the command line, use any port defined for the system. To select the system port: 1) see if port information was specified directly; 2) see if a port was named; 3) get an available port given the baud rate. We don't change the system status if a port is unavailable; i.e. we don't force the system to wait for the retry time. */ if (qport == NULL) qport = qsys->uuconf_qport; if (qport != NULL) { if (! fconn_init (qport, &sconn)) return FALSE; if (! fconn_lock (&sconn, FALSE)) { ulog (LOG_ERROR, "%s: Port already locked", qport->uuconf_zname); return FALSE; } } else { struct spass s; int iuuconf; s.fmatched = FALSE; s.flocked = FALSE; s.qconn = &sconn; iuuconf = uuconf_find_port (puuconf, qsys->uuconf_zport, qsys->uuconf_ibaud, qsys->uuconf_ihighbaud, iuport_lock, (pointer) &s, &sport); if (iuuconf == UUCONF_NOT_FOUND) { if (s.fmatched) ulog (LOG_ERROR, "All matching ports in use"); else ulog (LOG_ERROR, "No matching ports"); return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); if (s.flocked) { (void) fconn_unlock (&sconn); uconn_free (&sconn); } return FALSE; } } if (! fconn_open (&sconn, qsys->uuconf_ibaud, qsys->uuconf_ihighbaud, FALSE)) { terr = STATUS_PORT_FAILED; fret = FALSE; } else { struct uuconf_dialer *qdialer; struct uuconf_dialer sdialer; enum tdialerfound tdialer; if (qsys->uuconf_zalternate == NULL) ulog (LOG_NORMAL, "Calling system %s (port %s)", qsys->uuconf_zname, zLdevice == NULL ? (char *) "unknown" : zLdevice); else ulog (LOG_NORMAL, "Calling system %s (alternate %s, port %s)", qsys->uuconf_zname, qsys->uuconf_zalternate, zLdevice == NULL ? (char *) "unknown" : zLdevice); qdialer = NULL; if (! fconn_dial (&sconn, puuconf, qsys, qsys->uuconf_zphone, &sdialer, &tdialer)) { terr = STATUS_DIAL_FAILED; fret = FALSE; } else { qdaemon->qconn = &sconn; if (tdialer == DIALERFOUND_FALSE) qdialer = NULL; else qdialer = &sdialer; fret = fdo_call (qdaemon, qstat, qdialer, pfcalled, &terr); } (void) fconn_close (&sconn, puuconf, qdialer, fret); if (tdialer == DIALERFOUND_FREE) (void) uuconf_dialer_free (puuconf, &sdialer); } if (! fret) { DEBUG_MESSAGE2 (DEBUG_HANDSHAKE, "Call failed: %d (%s)", (int) terr, azStatus[(int) terr]); qstat->ttype = terr; qstat->cretries++; qstat->ilast = ixsysdep_time ((long *) NULL); if (cretry == 0) qstat->cwait = CRETRY_WAIT (qstat->cretries); else qstat->cwait = cretry * 60; (void) fsysdep_set_status (qsys, qstat); } (void) fconn_unlock (&sconn); uconn_free (&sconn); if (qport == NULL) (void) uuconf_port_free (puuconf, &sport); return fret; } /* Do the actual work of calling another system. The qsys argument is the system to call, the qconn argument is the connection to use, the qstat argument holds the current status of the ssystem, and the qdialer argument holds the dialer being used (it may be NULL). If we log in successfully, set *pfcalled to TRUE; this is used to distinguish a failed dial from a failure during the call. If an error occurs *pterr is set to the status type to record. */ static boolean fdo_call (qdaemon, qstat, qdialer, pfcalled, pterr) struct sdaemon *qdaemon; struct sstatus *qstat; const struct uuconf_dialer *qdialer; boolean *pfcalled; enum tstatus_type *pterr; { pointer puuconf; const struct uuconf_system *qsys; struct sconnection *qconn; const char *zport; int iuuconf; char *zstr; long istart_time; char *zlog; puuconf = qdaemon->puuconf; qsys = qdaemon->qsys; qconn = qdaemon->qconn; *pterr = STATUS_LOGIN_FAILED; if (qconn->qport == NULL) zport = "unknown"; else zport = qconn->qport->uuconf_zname; if (! fchat (qconn, puuconf, &qsys->uuconf_schat, qsys, (const struct uuconf_dialer *) NULL, (const char *) NULL, FALSE, zport, iconn_baud (qconn))) return FALSE; *pfcalled = TRUE; istart_time = ixsysdep_time ((long *) NULL); *pterr = STATUS_HANDSHAKE_FAILED; /* We should now see "Shere" from the other system. Newer systems send "Shere=foo" where foo is the remote name. */ zstr = zget_uucp_cmd (qconn, TRUE); if (zstr == NULL) return FALSE; if (strncmp (zstr, "Shere", 5) != 0) { ulog (LOG_ERROR, "Bad initialization string"); ubuffree (zstr); return FALSE; } ulog (LOG_NORMAL, "Login successful"); qstat->ttype = STATUS_TALKING; qstat->ilast = ixsysdep_time ((long *) NULL); qstat->cretries = 0; qstat->cwait = 0; if (! fsysdep_set_status (qsys, qstat)) return FALSE; if (zstr[5] == '=') { const char *zheresys; size_t clen; int icmp; /* Some UUCP packages only provide seven characters in the Shere machine name. Others only provide fourteen. */ zheresys = zstr + 6; clen = strlen (zheresys); if (clen == 7 || clen == 14) icmp = strncmp (zheresys, qsys->uuconf_zname, clen); else icmp = strcmp (zheresys, qsys->uuconf_zname); if (icmp != 0) { if (qsys->uuconf_pzalias != NULL) { char **pz; for (pz = qsys->uuconf_pzalias; *pz != NULL; pz++) { if (clen == 7 || clen == 14) icmp = strncmp (zheresys, *pz, clen); else icmp = strcmp (zheresys, *pz); if (icmp == 0) break; } } if (icmp != 0) { ulog (LOG_ERROR, "Called wrong system (%s)", zheresys); ubuffree (zstr); return FALSE; } } } #if DEBUG > 1 else if (zstr[5] != '\0') DEBUG_MESSAGE1 (DEBUG_HANDSHAKE, "fdo_call: Strange Shere: %s", zstr); #endif ubuffree (zstr); /* We now send "S" name switches, where name is our UUCP name. If we are using sequence numbers with this system, we send a -Q argument with the sequence number. If the call-timegrade command was used, we send a -p argument and a -vgrade= argument with the grade to send us (we send both argument to make it more likely that one is recognized). We always send a -N (for new) switch indicating what new features we support. */ { long ival; char bgrade; char *zsend; boolean fret; /* Determine the grade we should request of the other system. A '\0' means that no restrictions have been made. */ if (! ftimespan_match (qsys->uuconf_qcalltimegrade, &ival, (int *) NULL)) bgrade = '\0'; else bgrade = (char) ival; /* Determine the name we will call ourselves. */ if (qsys->uuconf_zlocalname != NULL) qdaemon->zlocalname = qsys->uuconf_zlocalname; else { iuuconf = uuconf_localname (puuconf, &qdaemon->zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { qdaemon->zlocalname = zsysdep_localname (); if (qdaemon->zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } } zsend = zbufalc (strlen (qdaemon->zlocalname) + 70); if (! qsys->uuconf_fsequence) { if (bgrade == '\0') sprintf (zsend, "S%s -R -N0%o", qdaemon->zlocalname, (unsigned int) (FEATURE_SIZES | FEATURE_EXEC | FEATURE_RESTART)); else sprintf (zsend, "S%s -p%c -vgrade=%c -R -N0%o", qdaemon->zlocalname, bgrade, bgrade, (unsigned int) (FEATURE_SIZES | FEATURE_EXEC | FEATURE_RESTART)); } else { long iseq; iseq = ixsysdep_get_sequence (qsys); if (iseq < 0) return FALSE; if (bgrade == '\0') sprintf (zsend, "S%s -Q%ld -R -N0%o", qdaemon->zlocalname, iseq, (unsigned int) (FEATURE_SIZES | FEATURE_EXEC | FEATURE_RESTART)); else sprintf (zsend, "S%s -Q%ld -p%c -vgrade=%c -R -N0%o", qdaemon->zlocalname, iseq, bgrade, bgrade, (unsigned int) (FEATURE_SIZES | FEATURE_EXEC | FEATURE_RESTART)); } fret = fsend_uucp_cmd (qconn, zsend); ubuffree (zsend); if (! fret) return FALSE; } /* Now we should see ROK or Rreason where reason gives a cryptic reason for failure. If we are talking to a counterpart, we will get back ROKN, possibly with a feature bitfield attached. */ zstr = zget_uucp_cmd (qconn, TRUE); if (zstr == NULL) return FALSE; if (zstr[0] != 'R') { ulog (LOG_ERROR, "Bad reponse to handshake string (%s)", zstr); ubuffree (zstr); return FALSE; } if (strncmp (zstr + 1, "OKN", sizeof "OKN" - 1) == 0) { if (zstr[sizeof "ROKN" - 1] == '\0') qdaemon->ifeatures |= FEATURE_SIZES | FEATURE_V103; else qdaemon->ifeatures |= (int) strtol (zstr + sizeof "ROKN" - 1, (char **) NULL, 0); } else if (strncmp (zstr + 1, "OK", sizeof "OK" - 1) == 0) { if (zstr[sizeof "ROK" - 1] != '\0') { char *zopt; /* SVR4 UUCP returns options following the ROK string. */ zopt = zstr + sizeof "ROK" - 1; while (*zopt != '\0') { char b; long c; char *zend; b = *zopt++; if (isspace (b) || b != '-') continue; switch (*zopt) { case 'R': qdaemon->ifeatures |= (FEATURE_RESTART | FEATURE_SVR4 | FEATURE_SIZES); break; case 'U': c = strtol (zopt, &zend, 0); if (c > 0 && c <= LONG_MAX / (long) 512) qdaemon->cmax_receive = c * (long) 512; zopt = zend; break; } while (*zopt != '\0' && ! isspace (*zopt)) ++zopt; } } } else if (strcmp (zstr + 1, "CB") == 0) { ulog (LOG_NORMAL, "Remote system will call back"); qstat->ttype = STATUS_COMPLETE; (void) fsysdep_set_status (qsys, qstat); ubuffree (zstr); return TRUE; } else { ulog (LOG_ERROR, "Handshake failed (%s)", zstr + 1); ubuffree (zstr); return FALSE; } ubuffree (zstr); /* The slave should now send \020Pprotos\0 where protos is a list of supported protocols. Each protocol is a single character. */ zstr = zget_uucp_cmd (qconn, TRUE); if (zstr == NULL) return FALSE; if (zstr[0] != 'P') { ulog (LOG_ERROR, "Bad protocol handshake (%s)", zstr); ubuffree (zstr); return FALSE; } /* Determine the reliability characteristics of the connection by combining information for the port and the dialer. If we have no information, default to a reliable eight-bit full-duplex connection. */ if (qconn->qport != NULL && (qconn->qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) qdaemon->ireliable = qconn->qport->uuconf_ireliable; if (qdialer != NULL && (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) { if (qdaemon->ireliable != 0) qdaemon->ireliable &= qdialer->uuconf_ireliable; else qdaemon->ireliable = qdialer->uuconf_ireliable; } if (qdaemon->ireliable == 0) qdaemon->ireliable = (UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); /* Now decide which protocol to use. The system and the port may have their own list of protocols. */ { int i; char ab[5]; i = CPROTOCOLS; if (qsys->uuconf_zprotocols != NULL || (qconn->qport != NULL && qconn->qport->uuconf_zprotocols != NULL)) { const char *zproto; if (qsys->uuconf_zprotocols != NULL) zproto = qsys->uuconf_zprotocols; else zproto = qconn->qport->uuconf_zprotocols; for (; *zproto != '\0'; zproto++) { if (strchr (zstr + 1, *zproto) != NULL) { for (i = 0; i < CPROTOCOLS; i++) if (asProtocols[i].bname == *zproto) break; if (i < CPROTOCOLS) break; } } } else { /* If neither the system nor the port specified a list of protocols, we want only protocols that match the known reliability of the dialer and the port. */ for (i = 0; i < CPROTOCOLS; i++) { int ipr; ipr = asProtocols[i].ireliable; if ((ipr & qdaemon->ireliable) != ipr) continue; if (strchr (zstr + 1, asProtocols[i].bname) != NULL) break; } } ubuffree (zstr); if (i >= CPROTOCOLS) { (void) fsend_uucp_cmd (qconn, "UN"); ulog (LOG_ERROR, "No mutually supported protocols"); return FALSE; } qdaemon->qproto = &asProtocols[i]; sprintf (ab, "U%c", qdaemon->qproto->bname); if (! fsend_uucp_cmd (qconn, ab)) return FALSE; } /* Run any protocol parameter commands. */ if (qdaemon->qproto->qcmds != NULL) { if (qsys->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, qdaemon->qproto->bname, qdaemon->qproto->qcmds, qsys->uuconf_qproto_params); if (qconn->qport != NULL && qconn->qport->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, qdaemon->qproto->bname, qdaemon->qproto->qcmds, qconn->qport->uuconf_qproto_params); if (qdialer != NULL && qdialer->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, qdaemon->qproto->bname, qdaemon->qproto->qcmds, qdialer->uuconf_qproto_params); } /* Turn on the selected protocol. */ if (! (*qdaemon->qproto->pfstart) (qdaemon, &zlog)) return FALSE; if (zlog == NULL) { zlog = zbufalc (sizeof "protocol ''" + 1); sprintf (zlog, "protocol '%c'", qdaemon->qproto->bname); } ulog (LOG_NORMAL, "Handshake successful (%s)", zlog); ubuffree (zlog); *pterr = STATUS_FAILED; { boolean fret; long iend_time; fret = floop (qdaemon); /* Now send the hangup message. As the caller, we send six O's and expect to receive seven O's. We send the six O's twice to help the other side. We don't worry about errors here. */ if (fsend_uucp_cmd (qconn, "OOOOOO") && fsend_uucp_cmd (qconn, "OOOOOO")) { int i, fdone; /* We look for the remote hangup string to ensure that the modem has sent out our hangup string. This is only necessary because some versions of UUCP complain if they don't get the hangup string. The remote site should send 7 O's, but some versions of UUCP only send 6. We look for the string several times because supposedly some implementations send some garbage after the last packet but before the hangup string. */ for (i = 0; i < 25; i++) { zstr = zget_uucp_cmd (qconn, FALSE); if (zstr == NULL) break; fdone = strstr (zstr, "OOOOOO") != NULL; ubuffree (zstr); if (fdone) break; } } iend_time = ixsysdep_time ((long *) NULL); ulog (LOG_NORMAL, "Call complete (%ld seconds)", iend_time - istart_time); if (fret) { qstat->ttype = STATUS_COMPLETE; qstat->ilast = iend_time; (void) fsysdep_set_status (qsys, qstat); } return fret; } } /* This routine is called via uuconf_find_port when a matching port is found. It tries to lock the port. If it fails, it returns UUCONF_NOT_FOUND to force uuconf_find_port to continue searching for the next matching port. */ static int iuport_lock (qport, pinfo) struct uuconf_port *qport; pointer pinfo; { struct spass *q = (struct spass *) pinfo; q->fmatched = TRUE; if (! fconn_init (qport, q->qconn)) return UUCONF_NOT_FOUND; else if (! fconn_lock (q->qconn, FALSE)) { uconn_free (q->qconn); return UUCONF_NOT_FOUND; } else { q->flocked = TRUE; return UUCONF_SUCCESS; } } /* Prompt for a login name and a password, and run as the slave. */ static boolean flogin_prompt (puuconf, qconn) pointer puuconf; struct sconnection *qconn; { char *zuser, *zpass; boolean fret; int iuuconf; DEBUG_MESSAGE0 (DEBUG_HANDSHAKE, "flogin_prompt: Waiting for login"); zuser = NULL; do { ubuffree (zuser); if (! fconn_write (qconn, "login: ", sizeof "login: " - 1)) return FALSE; zuser = zget_typed_line (qconn); } while (zuser != NULL && *zuser == '\0'); if (zuser == NULL) return TRUE; if (! fconn_write (qconn, "Password:", sizeof "Password:" - 1)) { ubuffree (zuser); return FALSE; } zpass = zget_typed_line (qconn); if (zpass == NULL) { ubuffree (zuser); return TRUE; } fret = TRUE; iuuconf = uuconf_callin (puuconf, zuser, zpass); ubuffree (zpass); if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_ERROR, "Bad login"); else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; } else { #if DEBUG > 1 int iholddebug; #endif /* We ignore the return value of faccept_call because we really don't care whether the call succeeded or not. We are going to reset the port anyhow. */ #if DEBUG > 1 iholddebug = iDebug; #endif (void) faccept_call (puuconf, zuser, qconn, (const char **) NULL); #if DEBUG > 1 iDebug = iholddebug; #endif } ubuffree (zuser); return fret; } /* Accept a call from a remote system. If pqsys is not NULL, *pqsys will be set to the system that called in if known. */ static boolean faccept_call (puuconf, zlogin, qconn, pzsystem) pointer puuconf; const char *zlogin; struct sconnection *qconn; const char **pzsystem; { long istart_time; const char *zport; struct uuconf_port *qport; struct uuconf_port sport; int iuuconf; struct uuconf_dialer *qdialer; struct uuconf_dialer sdialer; boolean ftcp_port; char *zsend, *zspace; boolean fret; char *zstr; struct uuconf_system ssys; const struct uuconf_system *qsys; const struct uuconf_system *qany; char *zloc; struct sstatus sstat; boolean fgotseq, fgotn; int i; char *zlog; char *zgrade; if (pzsystem != NULL) *pzsystem = NULL; ulog (LOG_NORMAL, "Incoming call (login %s port %s)", zlogin, zLdevice == NULL ? (char *) "unknown" : zLdevice); istart_time = ixsysdep_time ((long *) NULL); /* Figure out protocol parameters determined by the port. If no port was specified we're reading standard input, so try to get the port name and read information from the port file. We only use the port information to get protocol parameters; we don't want to start treating the port as though it were a modem, for example. */ if (qconn->qport != NULL) { qport = qconn->qport; zport = qport->uuconf_zname; ftcp_port = FALSE; } else { zport = zsysdep_port_name (&ftcp_port); if (zport == NULL) { qport = NULL; zport = "unknown"; } else { iuuconf = uuconf_find_port (puuconf, zport, (long) 0, (long) 0, (int (*) P((struct uuconf_port *, pointer pinfo))) NULL, (pointer) NULL, &sport); if (iuuconf == UUCONF_NOT_FOUND) qport = NULL; else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } else qport = &sport; } } /* If we've managed to figure out that this is a modem port, now try to get protocol parameters from the dialer. */ qdialer = NULL; if (qport != NULL) { if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) { if (qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) { const char *zdialer; zdialer = qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]; iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer); if (iuuconf == UUCONF_SUCCESS) qdialer = &sdialer; } else qdialer = qport->uuconf_u.uuconf_smodem.uuconf_qdialer; } else if (qport->uuconf_ttype == UUCONF_PORTTYPE_TCP || (qport->uuconf_ttype == UUCONF_PORTTYPE_TLI && (qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) == 0)) ftcp_port = TRUE; } sDaemon.puuconf = puuconf; sDaemon.qsys = NULL; sDaemon.zlocalname = NULL; sDaemon.qconn = qconn; sDaemon.qproto = NULL; sDaemon.clocal_size = -1; sDaemon.cremote_size = -1; sDaemon.cmax_ever = -2; sDaemon.cmax_receive = -1; sDaemon.ifeatures = 0; sDaemon.frequest_hangup = FALSE; sDaemon.fhangup_requested = FALSE; sDaemon.fhangup = FALSE; sDaemon.fmaster = FALSE; sDaemon.fcaller = FALSE; sDaemon.ireliable = 0; sDaemon.bgrade = UUCONF_GRADE_LOW; /* Get the local name to use. If uuconf_login_localname returns a value, it is not always freed up, although it should be. */ iuuconf = uuconf_login_localname (puuconf, zlogin, &zloc); if (iuuconf == UUCONF_SUCCESS) sDaemon.zlocalname = zloc; else if (iuuconf == UUCONF_NOT_FOUND) { sDaemon.zlocalname = zsysdep_localname (); if (sDaemon.zlocalname == NULL) return FALSE; } else { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } /* Tell the remote system who we are. */ zsend = zbufalc (strlen (sDaemon.zlocalname) + sizeof "Shere="); sprintf (zsend, "Shere=%s", sDaemon.zlocalname); fret = fsend_uucp_cmd (qconn, zsend); ubuffree (zsend); if (! fret) return FALSE; zstr = zget_uucp_cmd (qconn, TRUE); if (zstr == NULL) return FALSE; if (zstr[0] != 'S') { ulog (LOG_ERROR, "Bad introduction string"); ubuffree (zstr); return FALSE; } zspace = strchr (zstr, ' '); if (zspace != NULL) *zspace = '\0'; iuuconf = uuconf_system_info (puuconf, zstr + 1, &ssys); if (iuuconf == UUCONF_NOT_FOUND) { char *zscript; /* Run the remote.unknown script, if appropriate. */ iuuconf = uuconf_remote_unknown (puuconf, &zscript); if (iuuconf == UUCONF_SUCCESS) { if (! fsysdep_unknown_caller (zscript, zstr + 1)) { xfree ((pointer) zscript); (void) fsend_uucp_cmd (qconn, "RYou are unknown to me"); ubuffree (zstr); return FALSE; } xfree ((pointer) zscript); } else if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (zstr); return FALSE; } if (! funknown_system (puuconf, zstr + 1, &ssys)) { (void) fsend_uucp_cmd (qconn, "RYou are unknown to me"); ulog (LOG_ERROR, "Call from unknown system %s", zstr + 1); ubuffree (zstr); return FALSE; } } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (zstr); return FALSE; } qany = NULL; for (qsys = &ssys; qsys != NULL; qsys = qsys->uuconf_qalternate) { if (! qsys->uuconf_fcalled) continue; if (qsys->uuconf_zcalled_login == NULL || strcmp (qsys->uuconf_zcalled_login, "ANY") == 0) { if (qany == NULL) qany = qsys; } else if (strcmp (qsys->uuconf_zcalled_login, zlogin) == 0) break; } if (qsys == NULL && qany != NULL) { iuuconf = uuconf_validate (puuconf, qany, zlogin); if (iuuconf == UUCONF_SUCCESS) qsys = qany; else if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (zstr); return FALSE; } } if (qsys == NULL) { (void) fsend_uucp_cmd (qconn, "RLOGIN"); ulog (LOG_ERROR, "System %s used wrong login name %s", zstr + 1, zlogin); ubuffree (zstr); return FALSE; } sDaemon.qsys = qsys; if (pzsystem != NULL) *pzsystem = zbufcpy (qsys->uuconf_zname); ulog_system (qsys->uuconf_zname); #if DEBUG > 1 if (qsys->uuconf_zdebug != NULL) iDebug |= idebug_parse (qsys->uuconf_zdebug); #endif /* See if we are supposed to call the system back. This will queue up an empty command. It would be better to actually call back directly at this point as well. */ if (qsys->uuconf_fcallback) { (void) fsend_uucp_cmd (qconn, "RCB"); ulog (LOG_NORMAL, "Will call back"); /* Clear any existing status. */ sstat.ttype = STATUS_COMPLETE; sstat.cretries = 0; sstat.ilast = ixsysdep_time ((long *) NULL); sstat.cwait = 0; (void) fsysdep_set_status (qsys, &sstat); ubuffree (zsysdep_spool_commands (qsys, UUCONF_GRADE_HIGH, 0, (const struct scmd *) NULL)); ubuffree (zstr); return TRUE; } /* We only permit one call at a time from a remote system. Lock it. */ if (! fsysdep_lock_system (qsys)) { (void) fsend_uucp_cmd (qconn, "RLCK"); ulog (LOG_ERROR, "System already locked"); ubuffree (zstr); return FALSE; } sLocked_system = *qsys; fLocked_system = TRUE; /* Set the system status. We don't care what the status was before. We also don't want to kill the conversation just because we can't output the .Status file, so we ignore any errors. */ sstat.ttype = STATUS_TALKING; sstat.cretries = 0; sstat.ilast = ixsysdep_time ((long *) NULL); sstat.cwait = 0; (void) fsysdep_set_status (qsys, &sstat); /* Check the arguments of the remote system, if any. */ fgotseq = FALSE; fgotn = FALSE; if (zspace != NULL) { char **paz; char **pzset; ++zspace; /* Break the introduction line up into arguments. */ paz = (char **) xmalloc ((strlen (zspace) / 2 + 2) * sizeof (char *)); pzset = paz; *pzset++ = NULL; while (TRUE) { while (*zspace != '\0' && isspace (BUCHAR (*zspace))) ++zspace; if (*zspace == '\0') break; *pzset++ = zspace; ++zspace; while (*zspace != '\0' && ! isspace (BUCHAR (*zspace))) ++zspace; if (*zspace == '\0') break; *zspace++ = '\0'; } if (pzset != paz + 1) { int iopt; *pzset = NULL; /* We are going to use getopt to parse the arguments. We must clear optind to force getopt to reinitialize, and clear opterr to prevent getopt from printing an error message. This approach assumes we are using the GNU getopt, which is distributed with the program anyhow. */ optind = 0; opterr = 0; while ((iopt = getopt (pzset - paz, paz, "N::p:Q:RU:v:x:")) != EOF) { long iseq; long c; char b; int iwant; switch (iopt) { case 'N': /* This is used to indicate support for Taylor UUCP extensions. An plain -N mean support for size negotiation. If -N is followed by a number (with no intervening space), the number is a bit field of feature flags as defined in trans.h. Note that the argument may start with 0x for hex or 0 for octal. */ fgotn = TRUE; if (optarg == NULL) sDaemon.ifeatures |= FEATURE_SIZES | FEATURE_V103; else sDaemon.ifeatures |= (int) strtol (optarg, (char **) NULL, 0); break; case 'p': /* The argument is the lowest grade of work the local system should send. */ if (UUCONF_GRADE_LEGAL (optarg[0])) sDaemon.bgrade = optarg[0]; break; case 'Q': /* The conversation sequence number. */ iseq = strtol (optarg, (char **) NULL, 10); if (qsys->uuconf_fsequence && iseq != ixsysdep_get_sequence (qsys)) { (void) fsend_uucp_cmd (qconn, "RBADSEQ"); ulog (LOG_ERROR, "Out of sequence call rejected"); sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); xfree ((pointer) paz); ubuffree (zstr); return FALSE; } fgotseq = TRUE; break; case 'R': /* The remote system supports file restart. */ sDaemon.ifeatures |= FEATURE_RESTART; break; case 'U': /* The maximum file size the remote system is prepared to received, in blocks where each block is 512 bytes. */ c = strtol (optarg, (char **) NULL, 0); if (c > 0 && c < LONG_MAX / (long) 512) sDaemon.cmax_receive = c * (long) 512; break; case 'v': /* -vgrade=X can be used to set the lowest grade of work the local system should send. */ if (strncmp (optarg, "grade=", sizeof "grade=" - 1) == 0) { b = optarg[sizeof "grade=" - 1]; if (UUCONF_GRADE_LEGAL (b)) sDaemon.bgrade = b; } break; case 'x': iwant = (int) strtol (optarg, (char **) NULL, 10); #if DEBUG > 1 if (iwant <= 9) iwant = (1 << iwant) - 1; if (qsys->uuconf_zmax_remote_debug != NULL) iwant &= idebug_parse (qsys->uuconf_zmax_remote_debug); if ((iDebug | iwant) != iDebug) { iDebug |= iwant; ulog (LOG_NORMAL, "Setting debugging mode to 0%o", iDebug); } #endif break; default: break; } } } xfree ((pointer) paz); } ubuffree (zstr); if (qsys->uuconf_fsequence && ! fgotseq) { (void) fsend_uucp_cmd (qconn, "RBADSEQ"); ulog (LOG_ERROR, "No sequence number (call rejected)"); sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); return FALSE; } /* We recognized the system, and the sequence number (if any) was OK. Send an ROK, and send a list of protocols. If we got the -N switch, send ROKN to confirm it; if the -N switch was followed by a feature bitfield, return our own feature bitfield. */ { char ab[20]; const char *zreply; if (! fgotn) { if ((sDaemon.ifeatures & FEATURE_RESTART) == 0) zreply = "ROK"; else { /* We got -R without -N, so assume that this is SVR4 UUCP. SVR4 UUCP expects ROK -R to signal support for file restart. */ sDaemon.ifeatures |= FEATURE_SVR4 | FEATURE_SIZES; zreply = "ROK -R"; } } else if ((sDaemon.ifeatures & FEATURE_V103) != 0) zreply = "ROKN"; else { sprintf (ab, "ROKN0%o", (unsigned int) (FEATURE_SIZES | FEATURE_EXEC | FEATURE_RESTART)); zreply = ab; } if (! fsend_uucp_cmd (qconn, zreply)) { sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); return FALSE; } } /* Determine the reliability of the connection based on the reliability of the port and the dialer. If we have no information, default to a reliable eight-bit full-duplex connection. */ if (ftcp_port) sDaemon.ireliable = (UUCONF_RELIABLE_SPECIFIED | UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX); else { if (qport != NULL && (qport->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) sDaemon.ireliable = qport->uuconf_ireliable; if (qdialer != NULL && (qdialer->uuconf_ireliable & UUCONF_RELIABLE_SPECIFIED) != 0) { if (sDaemon.ireliable != 0) sDaemon.ireliable &= qdialer->uuconf_ireliable; else sDaemon.ireliable = qdialer->uuconf_ireliable; } if (sDaemon.ireliable == 0) sDaemon.ireliable = (UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); } if (qsys->uuconf_zprotocols != NULL || (qport != NULL && qport->uuconf_zprotocols != NULL)) { const char *zprotos; if (qsys->uuconf_zprotocols != NULL) zprotos = qsys->uuconf_zprotocols; else zprotos = qport->uuconf_zprotocols; zsend = zbufalc (strlen (zprotos) + 2); sprintf (zsend, "P%s", zprotos); } else { char *zset; zsend = zbufalc (CPROTOCOLS + 2); zset = zsend; *zset++ = 'P'; /* If the system did not specify a list of protocols, we want only protocols that match the known reliability of the dialer and the port. */ for (i = 0; i < CPROTOCOLS; i++) { int ipr; ipr = asProtocols[i].ireliable; if ((ipr & sDaemon.ireliable) != ipr) continue; *zset++ = asProtocols[i].bname; } *zset = '\0'; } fret = fsend_uucp_cmd (qconn, zsend); ubuffree (zsend); if (! fret) { sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); return FALSE; } /* The master will now send back the selected protocol. */ zstr = zget_uucp_cmd (qconn, TRUE); if (zstr == NULL) { sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); return FALSE; } if (zstr[0] != 'U' || zstr[2] != '\0') { ulog (LOG_ERROR, "Bad protocol response string"); sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); ubuffree (zstr); return FALSE; } if (zstr[1] == 'N') { ulog (LOG_ERROR, "No supported protocol"); sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); ubuffree (zstr); return FALSE; } for (i = 0; i < CPROTOCOLS; i++) if (asProtocols[i].bname == zstr[1]) break; ubuffree (zstr); if (i >= CPROTOCOLS) { ulog (LOG_ERROR, "No supported protocol"); sstat.ttype = STATUS_FAILED; (void) fsysdep_set_status (qsys, &sstat); return FALSE; } sDaemon.qproto = &asProtocols[i]; /* Run the chat script for when a call is received. */ if (! fchat (qconn, puuconf, &qsys->uuconf_scalled_chat, qsys, (const struct uuconf_dialer *) NULL, (const char *) NULL, FALSE, zport, iconn_baud (qconn))) { sstat.ttype = STATUS_FAILED; sstat.ilast = ixsysdep_time ((long *) NULL); (void) fsysdep_set_status (qsys, &sstat); return FALSE; } /* Run any protocol parameter commands. */ if (sDaemon.qproto->qcmds != NULL) { if (qsys->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, sDaemon.qproto->bname, sDaemon.qproto->qcmds, qsys->uuconf_qproto_params); if (qport != NULL && qport->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, sDaemon.qproto->bname, sDaemon.qproto->qcmds, qport->uuconf_qproto_params); if (qdialer != NULL && qdialer->uuconf_qproto_params != NULL) uapply_proto_params (puuconf, sDaemon.qproto->bname, sDaemon.qproto->qcmds, qdialer->uuconf_qproto_params); } /* We don't need the dialer information any more. */ if (qdialer == &sdialer) (void) uuconf_dialer_free (puuconf, &sdialer); /* Get any jobs queued for the system, and turn on the selected protocol. */ if (! fqueue (&sDaemon, (boolean *) NULL) || ! (*sDaemon.qproto->pfstart) (&sDaemon, &zlog)) { uclear_queue (&sDaemon); sstat.ttype = STATUS_FAILED; sstat.ilast = ixsysdep_time ((long *) NULL); (void) fsysdep_set_status (qsys, &sstat); return FALSE; } if (zlog == NULL) { zlog = zbufalc (sizeof "protocol ''" + 1); sprintf (zlog, "protocol '%c'", sDaemon.qproto->bname); } zgrade = zbufalc (sizeof "grade " + 1); if (sDaemon.bgrade == UUCONF_GRADE_LOW) *zgrade = '\0'; else sprintf (zgrade, "grade %c ", sDaemon.bgrade); /* If we are using HAVE_HDB_LOGGING, then the previous ``incoming call'' message went to the general log, since we didn't know the system name at that point. In that case, we repeat the port and login names. */ #if HAVE_HDB_LOGGING ulog (LOG_NORMAL, "Handshake successful (login %s port %s %s%s)", zlogin, zLdevice == NULL ? "unknown" : zLdevice, zgrade, zlog); #else /* ! HAVE_HDB_LOGGING */ ulog (LOG_NORMAL, "Handshake successful (%s%s)", zgrade, zlog); #endif /* ! HAVE_HDB_LOGGING */ ubuffree (zlog); ubuffree (zgrade); { long iend_time; fret = floop (&sDaemon); /* Hangup. As the answerer, we send seven O's and expect to receive six O's. We send the seven O's twice to help the other side. We don't worry about errors here. */ if (fsend_uucp_cmd (qconn, "OOOOOOO") && fsend_uucp_cmd (qconn, "OOOOOOO")) { int fdone; /* We look for the remote hangup string to ensure that the modem has sent out our hangup string. This is only necessary because some versions of UUCP complain if they don't get the hangup string. We look for the string several times because supposedly some implementations send some garbage after the last packet but before the hangup string. */ for (i = 0; i < 25; i++) { zstr = zget_uucp_cmd (qconn, FALSE); if (zstr == NULL) break; fdone = strstr (zstr, "OOOOOO") != NULL; ubuffree (zstr); if (fdone) break; } } iend_time = ixsysdep_time ((long *) NULL); ulog (LOG_NORMAL, "Call complete (%ld seconds)", iend_time - istart_time); uclear_queue (&sDaemon); if (fret) sstat.ttype = STATUS_COMPLETE; else sstat.ttype = STATUS_FAILED; sstat.ilast = iend_time; (void) fsysdep_set_status (qsys, &sstat); (void) uuconf_system_free (puuconf, &ssys); if (qport == &sport) (void) uuconf_port_free (puuconf, &sport); xfree ((pointer) zloc); return fret; } } /* Apply protocol parameters, once we know the protocol. */ static void uapply_proto_params (puuconf, bproto, qcmds, pas) pointer puuconf; int bproto; struct uuconf_cmdtab *qcmds; struct uuconf_proto_param *pas; { struct uuconf_proto_param *qp; for (qp = pas; qp->uuconf_bproto != '\0'; qp++) { if (qp->uuconf_bproto == bproto) { struct uuconf_proto_param_entry *qe; for (qe = qp->uuconf_qentries; qe->uuconf_cargs > 0; qe++) { int iuuconf; iuuconf = uuconf_cmd_args (puuconf, qe->uuconf_cargs, qe->uuconf_pzargs, qcmds, (pointer) NULL, (uuconf_cmdtabfn) NULL, 0, (pointer) NULL); if (UUCONF_ERROR_VALUE (iuuconf) != UUCONF_SUCCESS) { ulog (LOG_ERROR, "Error in %c protocol parameters", bproto); ulog_uuconf (LOG_ERROR, puuconf, iuuconf); } } break; } } } /* Send a string to the other system beginning with a DLE character and terminated with a null byte. This is only used when no protocol is in force. */ static boolean fsend_uucp_cmd (qconn, z) struct sconnection *qconn; const char *z; { size_t cwrite; char *zalc; boolean fret; DEBUG_MESSAGE1 (DEBUG_HANDSHAKE, "fsend_uucp_cmd: Sending \"%s\"", z); cwrite = strlen (z) + 2; zalc = zbufalc (cwrite); zalc[0] = '\020'; memcpy (zalc + 1, z, cwrite - 1); fret = fconn_write (qconn, zalc, cwrite); ubuffree (zalc); return fret; } /* Get a UUCP command beginning with a DLE character and ending with a null byte. This is only used when no protocol is in force. This implementation has the potential of being seriously slow. It also doesn't have any real error recovery. The frequired argument is passed as TRUE if we need the string; we don't care that much if we're closing down the connection anyhow. */ #define CTIMEOUT (120) #define CSHORTTIMEOUT (10) #define CINCREMENT (100) static char * zget_uucp_cmd (qconn, frequired) struct sconnection *qconn; boolean frequired; { char *zalc; size_t calc; size_t cgot; boolean fintro; long iendtime; int ctimeout; #if DEBUG > 1 int cchars; int iolddebug; #endif iendtime = ixsysdep_time ((long *) NULL); if (frequired) iendtime += CTIMEOUT; else iendtime += CSHORTTIMEOUT; #if DEBUG > 1 cchars = 0; iolddebug = iDebug; if (FDEBUGGING (DEBUG_HANDSHAKE)) { ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \""); iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); } #endif zalc = NULL; calc = 0; cgot = 0; fintro = FALSE; while ((ctimeout = (int) (iendtime - ixsysdep_time ((long *) NULL))) > 0) { int b; b = breceive_char (qconn, ctimeout, frequired); /* Now b == -1 on timeout, -2 on error. */ if (b < 0) { #if DEBUG > 1 if (FDEBUGGING (DEBUG_HANDSHAKE)) { ulog (LOG_DEBUG_END, "\" (%s)", b == -1 ? "timeout" : "error"); iDebug = iolddebug; } #endif if (b == -1 && frequired) ulog (LOG_ERROR, "Timeout"); ubuffree (zalc); return NULL; } /* Apparently some systems use parity on these strings, so we strip the parity bit. This may need to be configurable at some point, although only if system names can have eight bit characters. */ if (! isprint (BUCHAR (b))) b &= 0x7f; #if DEBUG > 1 if (FDEBUGGING (DEBUG_HANDSHAKE)) { char ab[5]; ++cchars; if (cchars > 60) { ulog (LOG_DEBUG_END, "\""); ulog (LOG_DEBUG_START, "zget_uucp_cmd: Got \""); cchars = 0; } (void) cdebug_char (ab, b); ulog (LOG_DEBUG_CONTINUE, "%s", ab); } #endif if (! fintro) { if (b == '\020') fintro = TRUE; continue; } /* If we see another DLE, something has gone wrong; continue as though this were the first one we saw. */ if (b == '\020') { cgot = 0; continue; } /* Some systems send a trailing \n on the Shere line. As far as I can tell this line can never contain a \n, so this modification should be safe enough. */ if (b == '\r' || b == '\n') b = '\0'; if (cgot >= calc) { char *znew; calc += CINCREMENT; znew = zbufalc (calc); memcpy (znew, zalc, cgot); ubuffree (zalc); zalc = znew; } zalc[cgot] = (char) b; ++cgot; if (b == '\0') { #if DEBUG > 1 if (FDEBUGGING (DEBUG_HANDSHAKE)) { ulog (LOG_DEBUG_END, "\""); iDebug = iolddebug; } #endif return zalc; } } #if DEBUG > 1 if (FDEBUGGING (DEBUG_HANDSHAKE)) { ulog (LOG_DEBUG_END, "\" (timeout)"); iDebug = iolddebug; } #endif ubuffree (zalc); if (frequired) ulog (LOG_ERROR, "Timeout"); return NULL; } /* Read a sequence of characters up to a newline or carriage return, and return the line without the line terminating character. */ static char * zget_typed_line (qconn) struct sconnection *qconn; { char *zalc; size_t calc; size_t cgot; #if DEBUG > 1 int cchars; int iolddebug; cchars = 0; iolddebug = iDebug; if (FDEBUGGING (DEBUG_CHAT)) { ulog (LOG_DEBUG_START, "zget_typed_line: Got \""); iDebug &=~ (DEBUG_INCOMING | DEBUG_PORT); } #endif zalc = NULL; calc = 0; cgot = 0; while (TRUE) { int b; b = breceive_char (qconn, CTIMEOUT, FALSE); /* Now b == -1 on timeout, -2 on error. */ if (b == -2 || FGOT_SIGNAL ()) { #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { ulog (LOG_DEBUG_END, "\" (error)"); iDebug = iolddebug; } #endif ubuffree (zalc); return NULL; } if (b == -1) continue; #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { char ab[5]; ++cchars; if (cchars > 60) { ulog (LOG_DEBUG_END, "\""); ulog (LOG_DEBUG_START, "zget_typed_line: Got \""); cchars = 0; } (void) cdebug_char (ab, b); ulog (LOG_DEBUG_CONTINUE, "%s", ab); } #endif if (cgot >= calc) { char *znew; calc += CINCREMENT; znew = zbufalc (calc); memcpy (znew, zalc, cgot); ubuffree (zalc); zalc = znew; } if (b == '\r' || b == '\n') b = '\0'; zalc[cgot] = (char) b; ++cgot; if (b == '\0') { #if DEBUG > 1 if (FDEBUGGING (DEBUG_CHAT)) { ulog (LOG_DEBUG_END, "\""); iDebug = iolddebug; } #endif return zalc; } } } a call is received. */ if (! fchat (qconn, puuconf, &qsys->uuconf_scalled_chat, qsys, (const struct uuucp-1.04/uuconf.h1004440004150000170000017424105337263522011044 037777777777 1 0 /* uuconf.h Header file for UUCP configuration routines. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP uuconf library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The use of an object file which uses material from this header file, and from no other portion of the uuconf library, is unrestricted, as described in paragraph 4 of section 5 of version 2 of the GNU Library General Public License (this sentence is merely informative, and does not modify the License in any way). The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #ifndef UUCONF_H #define UUCONF_H #include /* The macro UUCONF_ANSI_C may be used to override __STDC__. */ #ifndef UUCONF_ANSI_C #ifdef __STDC__ #define UUCONF_ANSI_C 1 #else /* ! defined (__STDC__) */ #define UUCONF_ANSI_C 0 #endif /* ! defined (__STDC__) */ #endif /* ! defined (UUCONF_ANSI_C) */ #if UUCONF_ANSI_C #define UUCONF_CONST const typedef void *UUCONF_POINTER; #include typedef size_t UUCONF_SIZE_T; #else #define UUCONF_CONST typedef char *UUCONF_POINTER; typedef unsigned int UUCONF_SIZE_T; #endif /* The field names of each of the following structures begin with "uuconf_". This is to avoid any conflicts with user defined macros. The first character following the "uuconf_" string indicates the type of the field. z -- a string (char *) c -- a count (normally int) i -- an integer value (normally int) f -- a boolean value (normally int) b -- a single character value (char or int) t -- an enum (enum XX) s -- a structure (struct XX) u -- a union (union XX) q -- a pointer to a structure (struct XX *) p -- a pointer to something other than a string */ /* The information which is kept for a chat script. */ struct uuconf_chat { /* The script itself. This is a NULL terminated list of expect/send pairs. The first string is an expect string. A string starting with a '-' indicates subsend string; the following strings which start with '-' are subexpect/subsend strings. This field may be NULL, in which case there is no chat script (but pzprogram may hold a program to run). */ char **uuconf_pzchat; /* The chat program to run. This is a NULL terminated list of arguments; element 0 if the program. May be NULL, in which case there is no program. */ char **uuconf_pzprogram; /* The timeout in seconds to use for expect strings in the chat script. */ int uuconf_ctimeout; /* The NULL terminated list of failure strings. If any of these strings appear, the chat script is aborted. May be NULL, in which case there are no failure strings. */ char **uuconf_pzfail; /* Non-zero if incoming characters should be stripped to seven bits (by anding with 0x7f). */ int uuconf_fstrip; }; /* The information which is kept for a time specification. This is a linked list of structures. Each element of the list represents a span of time, giving a starting time and an ending time. The time only depends on the day of the week, not on the day of the month or of the year. The time is only specified down to the minute, not down to the second or below. The list is sorted by starting time. The starting and ending time are expressed in minutes since the beginning of the week, which is considered to be 12 midnight on Sunday. Thus 60 is 1 am on Sunday, 1440 (== 60 * 24) is 12 midnight on Monday, and the largest possible value is 10080 (== 60 * 24 * 7) which is 12 midnight on the following Sunday. Each span of time has a value associated with it. This is the lowest grade or the largest file size that may be transferred during that time, depending on the source of the time span. When time specifications overlap, the value used for the overlap is the higher grade or the smaller file size. Thus specifying ``call-timegrade z Any'' and ``call-timegrade Z Mo'' means that only grade Z or higher may be sent on Monday, since Z is the higer grade of the overlapping spans. The final array wil have no overlaps. Each span also has a retry time associated with it. This permits different retry times to be used at different times of day. The retry time is only relevant if the span came from a ``time'' or ``timegrade'' command for a system. */ struct uuconf_timespan { /* Next element in list. */ struct uuconf_timespan *uuconf_qnext; /* Starting minute (-1 at the end of the array). */ int uuconf_istart; /* Ending minute. */ int uuconf_iend; /* Value for this span (lowest grade or largest file that may be transferred at this time). */ long uuconf_ival; /* Retry time. */ int uuconf_cretry; }; /* The information which is kept for protocol parameters. Protocol parameter information is stored as an array of the following structures. */ struct uuconf_proto_param { /* The name of the protocol to which this entry applies. This is '\0' for the last element of the array. */ int uuconf_bproto; /* Specific entries for this protocol. This points to an array ending in an element with a uuconf_cargs field of 0. */ struct uuconf_proto_param_entry *uuconf_qentries; }; /* Each particular protocol parameter entry is one of the following structures. */ struct uuconf_proto_param_entry { /* The number of arguments to the ``protocol-parameter'' command (not counting ``protocol-parameter'' itself). This is 0 for the last element of the array. */ int uuconf_cargs; /* The actual arguments to the ``protocol-parameter'' command; this is an array with cargs entries. */ char **uuconf_pzargs; }; /* The information which is kept for a system. The zname and zalias fields will be the same for all alternates. Every other fields is specific to the particular alternate in which it appears (although most will be the same for all alternates). */ struct uuconf_system { /* The name of the system. */ char *uuconf_zname; /* A list of aliases for the system. This is a NULL terminated list of strings. May be NULL, in which case there are no aliases. */ char **uuconf_pzalias; /* A linked list of alternate call in or call out information. Each alternative way to call this system occupies an element of this list. May be NULL, in which case there are no alternates. */ struct uuconf_system *uuconf_qalternate; /* The name for this particular alternate. May be NULL, in which case this alternate does not have a name. */ char *uuconf_zalternate; /* If non-zero, this alternate may be used for calling out. */ int uuconf_fcall; /* If non-zero, this alternate may be used for accepting a call. */ int uuconf_fcalled; /* The times at which this system may be called. The ival field of each uuconf_timespan structure is the lowest grade which may be transferred at that time. The cretry field is the number of minutes to wait before retrying the call, or 0 if it was not specified. May be NULL, in which case the system may never be called. */ struct uuconf_timespan *uuconf_qtimegrade; /* The times at which to request a particular grade of the system when calling it, and the grades to request. The ival field of each uuconf_timespan structure is the lowest grade which the other system should transfer at that time. May be NULL, in which case there are no grade restrictions. */ struct uuconf_timespan *uuconf_qcalltimegrade; /* The maximum number of times to retry calling this system. If this is 0, there is no limit. */ int uuconf_cmax_retries; /* The number of minutes to wait between successful calls to a system. */ int uuconf_csuccess_wait; /* The size restrictions by time for local requests during a locally placed call. The ival field of each uuconf_timespan structure is the size in bytes of the largest file which may be transferred at that time. May be NULL, in which case there are no size restrictions. */ struct uuconf_timespan *uuconf_qcall_local_size; /* The size restrictions by time for remote requests during a locally placed call. May be NULL. */ struct uuconf_timespan *uuconf_qcall_remote_size; /* The size restrictions by time for local requests during a remotely placed call. May be NULL. */ struct uuconf_timespan *uuconf_qcalled_local_size; /* The size restrictions by time for remote requests during a remotely placed call. May be NULL. */ struct uuconf_timespan *uuconf_qcalled_remote_size; /* Baud rate, or speed. Zero means any baud rate. If ihighbaud is non-zero, this is the low baud rate of a range. */ long uuconf_ibaud; /* If non-zero, ibaud is the low baud rate of a range and ihighbaud is the high baud rate. */ long uuconf_ihighbaud; /* Port name to use. May be NULL. If an HDB configuration file contains a modem class (alphabetic characters preceeding the baud rate), the class is appended to the port name. */ char *uuconf_zport; /* Specific port information, if the system entry includes port information. May be NULL. */ struct uuconf_port *uuconf_qport; /* Phone number to call, or address to use for a TCP connection. May be NULL, in which case a dialer script may not use \D or \T for this system, and a TCP port will use the system name. */ char *uuconf_zphone; /* Chat script to use when logging in to the system. */ struct uuconf_chat uuconf_schat; /* Login name to use for \L in the login chat script. This should normally be accessed via uuconf_callout. If it is "*", uuconf_callout will look it up in the call out file. This may be NULL, in which case the login script may not use \L. */ char *uuconf_zcall_login; /* Password to use for \P in the login chat script. This should normally be accessed via uuconf_callout. If it is "*", uuconf_callout will look it up in the call out file. This may be NULL, in which case the login script may not use \P. */ char *uuconf_zcall_password; /* The login name this system must use when calling in. This may be different for different alternates. This should only be examined if uuconf_fcalled is TRUE. If this is NULL or "ANY" then uuconf_validate must be called to make sure that whatever login name was used is permitted for this machine. */ char *uuconf_zcalled_login; /* If non-zero, then when this system calls in the call should not be allowed to proceed and the system should be called back. */ int uuconf_fcallback; /* If non-zero, then conversation sequence numbers should be used with this system. */ int uuconf_fsequence; /* A list of protocols to use with this system. Each protocol has a single character name. May be NULL, in which case any known protocol may be used. */ char *uuconf_zprotocols; /* Array of protocol parameters. Ends in an entry with a uuconf_bproto field of '\0'. May be NULL. */ struct uuconf_proto_param *uuconf_qproto_params; /* Chat script to run when called by this system. */ struct uuconf_chat uuconf_scalled_chat; /* Debugging level to set during a conversation. May be NULL. */ char *uuconf_zdebug; /* Maximum remote debugging level this system may request. May be NULL. */ char *uuconf_zmax_remote_debug; /* Non-zero if the remote system may request us to send files from the local system to the remote. */ int uuconf_fsend_request; /* Non-zero if the remote system may request us to receive files from the remote system to the local. */ int uuconf_frec_request; /* Non-zero if local requests are permitted when calling this system. */ int uuconf_fcall_transfer; /* Non-zero if local requests are permitted when this system calls in. */ int uuconf_fcalled_transfer; /* NULL terminated list of directories from which files may be sent by local request. */ char **uuconf_pzlocal_send; /* NULL terminated list of directories from which files may be sent by remote request. */ char **uuconf_pzremote_send; /* NULL terminated list of directories into which files may be received by local request. */ char **uuconf_pzlocal_receive; /* NULL terminated list of directories into which files may be received by remote request. */ char **uuconf_pzremote_receive; /* Path to use for command execution. This is a NULL terminated list of directories. */ char **uuconf_pzpath; /* NULL terminated List of commands that may be executed. */ char **uuconf_pzcmds; /* Amount of free space to leave when accepting a file from this system, in bytes. */ long uuconf_cfree_space; /* NULL terminated list of systems that this system may forward from. May be NULL if there are no systems from which files may be forwarded. The list may include "ANY". */ char **uuconf_pzforward_from; /* NULL terminated list of systems that this system may forward to. May be NULL if there are no systems to which files may be forwarded. The list may include "ANY". */ char **uuconf_pzforward_to; /* The public directory to use for this sytem. */ const char *uuconf_zpubdir; /* The local name to use for this remote system. May be NULL if the usual local name should be used. */ char *uuconf_zlocalname; /* Memory allocation block for the system. */ UUCONF_POINTER uuconf_palloc; }; /* Types of ports. */ enum uuconf_porttype { /* Unknown port type. A port of this type should never be returned by the uuconf functions. */ UUCONF_PORTTYPE_UNKNOWN, /* Read from standard input and write to standard output. Not normally used. */ UUCONF_PORTTYPE_STDIN, /* A modem port. */ UUCONF_PORTTYPE_MODEM, /* A direct connect port. */ UUCONF_PORTTYPE_DIRECT, /* A TCP port. Not supported on all systems. */ UUCONF_PORTTYPE_TCP, /* A TLI port. Not supported on all systems. */ UUCONF_PORTTYPE_TLI }; /* Additional information for a stdin port (there is none). */ struct uuconf_stdin_port { int uuconf_idummy; }; /* Additional information for a modem port. */ struct uuconf_modem_port { /* The device name. May be NULL, in which case the port name is used instead. */ char *uuconf_zdevice; /* The device name to send the dialer chat script to. May be NULL, in which case the chat script is sent to the usual device. */ char *uuconf_zdial_device; /* The default baud rate (speed). If zero, there is no default. */ long uuconf_ibaud; /* The low baud rate, if a range is used. If zero, a range is not used and ihighbaud should be ignored. */ long uuconf_ilowbaud; /* The high baud rate, if ilowbaud is non-zero. */ long uuconf_ihighbaud; /* Non-zero if the port supports carrier detect. */ int uuconf_fcarrier; /* A NULL terminated sequence of dialer/token pairs (element 0 is a dialer name, element 1 is a token, etc.) May be NULL, in which case qdialer should not be NULL. */ char **uuconf_pzdialer; /* Specific dialer information. Only used if pzdialer is NULL. */ struct uuconf_dialer *uuconf_qdialer; }; /* Additional information for a direct connect port. */ struct uuconf_direct_port { /* The device name. May be NULL, in which case the port name is used instead. */ char *uuconf_zdevice; /* The baud rate (speed). */ long uuconf_ibaud; }; /* Additional information for a TCP port. */ struct uuconf_tcp_port { /* The TCP port number to use. May be a name or a number. May be NULL, in which case "uucp" is looked up using getservbyname. */ char *uuconf_zport; }; /* Additional information for a TLI port. */ struct uuconf_tli_port { /* Device name to open. May be NULL, in which case the port name is used. */ char *uuconf_zdevice; /* Whether this port should be turned into a stream, permitting the read and write calls instead of the t_rcv and t_send calls. */ int uuconf_fstream; /* A NULL terminated list of modules to push after making the connection. May be NULL, in which case if fstream is non-zero, then "tirdwr" is pushed onto the stream, and otherwise nothing is pushed. */ char **uuconf_pzpush; /* A NULL terminated sequence of dialer/token pairs (element 0 is a dialer name, element 1 is a token, etc.) May be NULL. If element 0 is TLI or TLIS, element 1 is used as the address to connect to; otherwise uuconf_zphone from the system information is used. */ char **uuconf_pzdialer; /* Address to use when operating as a server. This may contain escape sequences. */ char *uuconf_zservaddr; }; /* Information kept for a port. */ struct uuconf_port { /* The name of the port. */ char *uuconf_zname; /* The type of the port. */ enum uuconf_porttype uuconf_ttype; /* The list of protocols supported by the port. The name of each protocol is a single character. May be NULL, in which case any protocol is permitted. */ char *uuconf_zprotocols; /* Array of protocol parameters. Ends in an entry with a uuconf_bproto field of '\0'. May be NULL. */ struct uuconf_proto_param *uuconf_qproto_params; /* The set of reliability bits. */ int uuconf_ireliable; /* The lock file name to use. */ char *uuconf_zlockname; /* Memory allocation block for the port. */ UUCONF_POINTER uuconf_palloc; /* The type specific information. */ union { struct uuconf_stdin_port uuconf_sstdin; struct uuconf_modem_port uuconf_smodem; struct uuconf_direct_port uuconf_sdirect; struct uuconf_tcp_port uuconf_stcp; struct uuconf_tli_port uuconf_stli; } uuconf_u; }; /* Information kept about a dialer. */ struct uuconf_dialer { /* The name of the dialer. */ char *uuconf_zname; /* The chat script to use when dialing out. */ struct uuconf_chat uuconf_schat; /* The string to send when a `=' appears in the phone number. */ char *uuconf_zdialtone; /* The string to send when a `-' appears in the phone number. */ char *uuconf_zpause; /* Non-zero if the dialer supports carrier detect. */ int uuconf_fcarrier; /* The number of seconds to wait for carrier after the chat script is complete. Only used if fcarrier is non-zero. Only supported on some systems. */ int uuconf_ccarrier_wait; /* If non-zero, DTR should be toggled before dialing. Only supported on some systems. */ int uuconf_fdtr_toggle; /* If non-zero, sleep for 1 second after toggling DTR. Ignored if fdtr_toggle is zero. */ int uuconf_fdtr_toggle_wait; /* The chat script to use when a call is complete. */ struct uuconf_chat uuconf_scomplete; /* The chat script to use when a call is aborted. */ struct uuconf_chat uuconf_sabort; /* Array of protocol parameters. Ends in an entry with a uuconf_bproto field of '\0'. May be NULL. */ struct uuconf_proto_param *uuconf_qproto_params; /* The set of reliability bits. */ int uuconf_ireliable; /* Memory allocation block for the dialer. */ UUCONF_POINTER uuconf_palloc; }; /* Reliability bits for the ireliable field of ports and dialers. These bits are used to decide which protocol to run. A given protocol will have a set of these bits, and each of them must be turned on for the port before we will permit that protocol to be used. This will be overridden by the zprotocols field. */ /* Whether a set of reliability bits is given. If this bit is not set, then there is no reliability information. */ #define UUCONF_RELIABLE_SPECIFIED (01) /* Set if the connection is eight bit transparent. */ #define UUCONF_RELIABLE_EIGHT (02) /* Set if the connection is error-free. */ #define UUCONF_RELIABLE_RELIABLE (04) /* Set if the connection is end-to-end reliable (e.g. TCP). */ #define UUCONF_RELIABLE_ENDTOEND (010) /* Set if the connection is full-duplex; that is, no time consuming line turnaround is required before sending data in the reverse direction. If the connection is truly half-duplex, in the sense that communication can only flow in one direction, UUCP can not be used. */ #define UUCONF_RELIABLE_FULLDUPLEX (020) /* UUCP grades range from 0 to 9, A to Z, a to z in order from highest to lowest (work of higher grades is done before work of lower grades). */ /* The highest grade. */ #define UUCONF_GRADE_HIGH ('0') /* The lowest grade. */ #define UUCONF_GRADE_LOW ('z') /* Whether a character is a legal grade (requires ). */ #define UUCONF_GRADE_LEGAL(b) (isalnum ((unsigned) (b))) /* Return < 0 if the first grade should be done before the second grade, == 0 if they are the same, or > 0 if the first grade should be done after the second grade. On an ASCII system, this can just be b1 - b2. */ #define UUCONF_GRADE_CMP(b1, b2) (uuconf_grade_cmp ((b1), (b2))) /* Most of the uuconf functions returns an error code. A value of zero (UUCONF_SUCCESS) indicates success. */ /* If this bit is set in the returned error code, then the uuconf_errno function may be used to obtain the errno value as set by the function which caused the failure. */ #define UUCONF_ERROR_ERRNO (0x100) /* If this bit is set in the returned error code, then the uuconf_filename function may be used to get the name of a file associated with the error. */ #define UUCONF_ERROR_FILENAME (0x200) /* If this bit is set in the returned error code, then the uuconf_lineno function may be used to get a line number associated with the error; normally if this is set UUCONF_ERROR_FILENAME will also be set. */ #define UUCONF_ERROR_LINENO (0x400) /* There are two UUCONF_CMDTABRET bits that may be set in the return value of uuconf_cmd_line or uuconf_cmd_args, described below. They do not indicate an error, but instead give instructions to the calling function, often uuconf_cmd_file. They may also be set in the return value of a user function listed in a uuconf_cmdtab table, in which case they will be honored by uuconf_cmd_file. */ /* This bit means that the memory occupied by the arguments passed to the function should be preserved, and not overwritten or freed. It refers only to the contents of the arguments; the contents of the argv array itself may always be destroyed. If this bit is set in the return value of uuconf_cmd_line or uuconf_cmd_args, it must be honored. It will be honored by uuconf_cmd_file. This may be combined with an error code or with UUCONF_CMDTABRET_EXIT, although neither uuconf_cmd_file or uuconf_cmd_line will do so. */ #define UUCONF_CMDTABRET_KEEP (0x800) /* This bit means that uuconf_cmd_file should exit, rather than go on to read and process the next line. If uuconf_cmd_line or uuconf_cmd_args encounter an error, the return value will have this bit set along with the error code. A user function may set this bit with or without an error; the return value of the user function will be returned by uuconf_cmd_file, except that the UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT bits will be cleared. */ #define UUCONF_CMDTABRET_EXIT (0x1000) /* This macro may be used to extract the specific error value. */ #define UUCONF_ERROR_VALUE(i) ((i) & 0xff) /* UUCONF_ERROR_VALUE will return one of the following values. */ /* Function succeeded. */ #define UUCONF_SUCCESS (0) /* Named item not found. */ #define UUCONF_NOT_FOUND (1) /* A call to fopen failed. */ #define UUCONF_FOPEN_FAILED (2) /* A call to fseek failed. */ #define UUCONF_FSEEK_FAILED (3) /* A call to malloc or realloc failed. */ #define UUCONF_MALLOC_FAILED (4) /* Syntax error in file. */ #define UUCONF_SYNTAX_ERROR (5) /* Unknown command. */ #define UUCONF_UNKNOWN_COMMAND (6) #if UUCONF_ANSI_C /* For each type of configuration file (Taylor, V2, HDB), there are separate routines to read various sorts of information. There are also generic routines, which call on the appropriate type specific routines. The library can be compiled to read any desired combination of the configuration file types. This affects only the generic routines, as it determines which type specific routines they call. Thus, on a system which, for example, does not have any V2 configuration files, there is no need to include the overhead of the code to parse the files and the time to look for them. However, a program which specifically wants to be able to parse them can call the V2 specific routines. The uuconf functions all take as an argument a pointer to uuconf global information. This must be initialized by any the initialization routines (the generic one and the three file type specific ones) before any of the other uuconf functions may be called. */ /* Initialize the configuration file reading routines. The ppglobal argument should point to a generic pointer (a void *, or, on older compilers, a char *) which will be initialized and may then be passed to the other uuconf routines. The zprogram argument is the name of the program for which files should be read. A NULL is taken as "uucp", and reads the standard UUCP configuration files. The only other common argument is "cu", but any string is permitted. The zname argument is the name of the Taylor UUCP config file; if it is NULL, the default config file will be read. If not reading Taylor UUCP configuration information, the argument is ignored. This function must be called before any of the other uuconf functions. Note that if the zname argument is obtained from the user running the program, the program should be careful to revoke any special privileges it may have (e.g. on Unix call setuid (getuid ()) and setgid (getgid ())). Otherwise various sorts of spoofing become possible. */ extern int uuconf_init (void **uuconf_ppglobal, const char *uuconf_zprogram, const char *uuconf_zname); /* Adjust the configuration file global pointer for a new thread. The library is fully reentrant (with the exception of the function uuconf_error_string, which calls strerror, which on some systems is not reentrant), provided that each new thread that wishes to call the library calls this function and uses the new global pointer value. The ppglobal argument should be set to the address of the global pointer set by any of the init functions; it will be modified to become a new global pointer. */ extern int uuconf_init_thread (void **uuconf_ppglobal); /* Get the names of all known systems. This sets sets *ppzsystems to point to an array of system names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array, and they may all be passed to free when they are no longer needed. If the falias argument is 0, the list will not include any aliases; otherwise, it will. */ extern int uuconf_system_names (void *uuconf_pglobal, char ***uuconf_ppzsystems, int uuconf_falias); /* Get the information for the system zsystem. This sets the fields in *qsys. This will work whether zsystem is the official name of the system or merely an alias. */ extern int uuconf_system_info (void *uuconf_pglobal, const char *uuconf_zsystem, struct uuconf_system *uuconf_qsys); /* Get information for an unknown (anonymous) system. The uuconf_zname field of the returned system information will be NULL. If no information is available for unknown systems, this will return UUCONF_NOT_FOUND. This does not run the HDB remote.unknown shell script. */ extern int uuconf_system_unknown (void *uuconf_pglobal, struct uuconf_system *uuconf_qsys); /* Get information for the local system. Normally the local system name should first be looked up using uuconf_system_info. If that returns UUCONF_NOT_FOUND, this function may be used to get an appropriate set of defaults. The uuconf_zname field of the returned system information may be NULL. */ extern int uuconf_system_local (void *uuconf_pglobal, struct uuconf_system *uuconf_qsys); /* Free the memory occupied by system information returned by uuconf_system_info, uuconf_system_unknown, uuconf_system_local, or any of the configuration file type specific routines described below. After this is called, the contents of the structure shall not be referred to. */ extern int uuconf_system_free (void *uuconf_pglobal, struct uuconf_system *uuconf_qsys); #ifdef __OPTIMIZE__ #define uuconf_system_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #endif /* Find a matching port. This will consider each port in turn. If the zname argument is not NULL, the port's uuconf_zname field must match it. If the ibaud argument is not zero and the ihighbaud argument is zero, the port's baud rate, if defined, must be the same (if the port has a range of baud rates, ibaud must be within the range). If ibaud and ihighbaud are both not zero, the port's baud rate, if defined, must be between ibaud and ihighbaud inclusive (if the port has a range of baud rates, the ranges must intersect). If the port has no baud rate, either because it is a type of port for which baud rate is not defined (e.g. a TCP port) or because the uuconf_ibaud field is 0, the ibaud and ihighbaud arguments are ignored. If the pifn argument is not NULL, the port is passed to pifn, along with the pinfo argument (which is otherwise ignored). If pifn returns UUCONF_SUCCESS, the port matches. If pifn returns UUCONF_NOT_FOUND, a new port is sought. Otherwise the return value of pifn is returned from uuconf_find_port. The pifn function may be used to further restrict the port, such as by modem class or device name. It may also be used to lock the port, if appropriate; in this case, if the lock fails, pifn may return UUCONF_NOT_FOUND to force uuconf_find_port to continue searching for a port. If the port matches, the information is set into uuconf_qport, and uuconf_find_port returns UUCONF_SUCCESS. */ extern int uuconf_find_port (void *uuconf_pglobal, const char *uuconf_zname, long uuconf_ibaud, long uuconf_ihighbaud, int (*uuconf_pifn) (struct uuconf_port *, void *uuconf_pinfo), void *uuconf_pinfo, struct uuconf_port *uuconf_qport); /* Free the memory occupied by system information returned by uuconf_find_port (or any of the configuration file specific routines described below). After this is called, the contents of the structure shall not be referred to. */ extern int uuconf_port_free (void *uuconf_pglobal, struct uuconf_port *uuconf_qport); #ifdef __OPTIMIZE__ #define uuconf_port_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #endif /* Get the names of all known dialers. This sets sets *ppzdialers to point to an array of dialer names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array, and they may all be passed to free when they are no longer needed. */ extern int uuconf_dialer_names (void *uuconf_pglobal, char ***uuconf_ppzdialers); /* Get the information for the dialer zdialer. This sets the fields in *qdialer. */ extern int uuconf_dialer_info (void *uuconf_pglobal, const char *uuconf_zdialer, struct uuconf_dialer *uuconf_qdialer); /* Free the memory occupied by system information returned by uuconf_dialer_info (or any of the configuration file specific routines described below). After this is called, the contents of the structure shall not be referred to. */ extern int uuconf_dialer_free (void *uuconf_pglobal, struct uuconf_dialer *uuconf_qsys); #ifdef __OPTIMIZE__ #define uuconf_dialer_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #endif /* Get the local node name. If the node name is not specified (because no ``nodename'' command appeared in the config file) this will return UUCONF_NOT_FOUND, and some system dependent function must be used to determine the node name. Otherwise it will return a pointer to a constant string, which should not be freed. */ extern int uuconf_localname (void *uuconf_pglobal, const char **pzname); /* Get the local node name that should be used, given a login name. This function will check for any special local name that may be associated with the login name zlogin (as set by the ``myname'' command in a Taylor configuration file, or the MYNAME field in a Permissions entry). This will set *pzname to the node name. If no node name can be determined, *pzname will be set to NULL and the function will return UUCONF_NOT_FOUND; in this case some system dependent function must be used to determine the node name. If the function returns UUCONF_SUCCESS, *pzname will be point to an malloced buffer. */ extern int uuconf_login_localname (void *uuconf_pglobal, const char *uuconf_zlogin, char **pzname); /* Get the name of the UUCP spool directory. This will set *pzspool to a constant string, which should not be freed. */ extern int uuconf_spooldir (void *uuconf_pglobal, const char **uuconf_pzspool); /* Get the name of the default UUCP public directory. This will set *pzpub to a constant string, which should not be freed. Note that particular systems may use a different public directory. */ extern int uuconf_pubdir (void *uuconf_pglobal, const char **uuconf_pzpub); /* Get the name of the UUCP lock directory. This will set *pzlock to a constant string, which should not be freed. */ extern int uuconf_lockdir (void *uuconf_pglobal, const char **uuconf_pzlock); /* Get the name of the UUCP log file. This will set *pzlog to a constant string, which should not be freed. */ extern int uuconf_logfile (void *uuconf_pglobal, const char **uuconf_pzlog); /* Get the name of the UUCP statistics file. This will set *pzstats to a constant string, which should not be freed. */ extern int uuconf_statsfile (void *uuconf_pglobal, const char **uuconf_pzstats); /* Get the name of the UUCP debugging file. This will set *pzdebug to a constant string, which should not be freed. */ extern int uuconf_debugfile (void *uuconf_pglobal, const char **uuconf_pzdebug); /* Get the default debugging level to use. This basically gets the argument of the ``debug'' command from the Taylor UUCP config file. It will set *pzdebug to a constant string, which should not be freed. */ extern int uuconf_debuglevel (void *uuconf_pglobal, const char **uuconf_pzdebug); /* Get the maximum number of simultaneous uuxqt executions. This will set *pcmaxuuxqt to the number. Zero indicates no maximum. */ extern int uuconf_maxuuxqts (void *uuconf_pglobal, int *uuconf_pcmaxuuxqt); /* Check a login name and password. This checks the Taylor UUCP password file (not /etc/passwd). It will work even if uuconf_taylor_init was not called. If the login name exists and the password is correct, this returns UUCONF_SUCCESS. If the login does not exist, or the password is wrong, this returns UUCONF_NOT_FOUND. Other errors are also possible. */ extern int uuconf_callin (void *uuconf_pglobal, const char *uuconf_zlogin, const char *uuconf_zpassword); /* Get the callout login name and password for a system. This will set both *pzlog and *pzpass to a string allocated by malloc, or to NULL if the value is not found. If neither value is found, the function will return UUCONF_NOT_FOUND. */ extern int uuconf_callout (void *uuconf_pglobal, const struct uuconf_system *uuconf_qsys, char **uuconf_pzlog, char **uuconf_pzpass); /* See if a login name is permitted for a system. This will return UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is invalid. This simply calls uuconf_taylor_validate or returns UUCONF_SUCCESS, depending on the value of HAVE_TAYLOR_CONFIG. */ extern int uuconf_validate (void *uuconf_pglobal, const struct uuconf_system *uuconf_qsys, const char *uuconf_zlogin); /* Get the name of the HDB remote.unknown shell script, if using HAVE_HDB_CONFIG. This does not actually run the shell script. If the function returns UUCONF_SUCCESS, the name will be in *pzname, which will point to an malloced buffer. If it returns UUCONF_NOT_FOUND, then there is no script to run. */ extern int uuconf_remote_unknown (void *uuconf_pglobal, char **pzname); /* Translate a dial code. This sets *pznum to an malloced string. This will look up the entire zdial string in the dialcode file, so for normal use the alphabetic prefix should be separated. */ extern int uuconf_dialcode (void *uuconf_pglobal, const char *uuconf_zdial, char **uuconf_pznum); /* Compare two grades, returning < 0 if b1 should be executed before b2, == 0 if they are the same, or > 0 if b1 should be executed after b2. This can not fail, and does not return a standard uuconf error code; it is normally called via the macro UUCONF_GRADE_CMP, defined above. */ extern int uuconf_grade_cmp (int uuconf_b1, int uuconf_b2); #else /* ! UUCONF_ANSI_C */ extern int uuconf_init (); extern int uuconf_init_thread (); extern int uuconf_system_names (); extern int uuconf_system_info (); extern int uuconf_system_unknown (); extern int uuconf_system_local (); extern int uuconf_system_free (); extern int uuconf_find_port (); extern int uuconf_port_free (); extern int uuconf_dialer_names (); extern int uuconf_dialer_info (); extern int uuconf_dialer_free (); extern int uuconf_localname (); extern int uuconf_login_localname (); extern int uuconf_spooldir (); extern int uuconf_lockdir (); extern int uuconf_pubdir (); extern int uuconf_logfile (); extern int uuconf_statsfile (); extern int uuconf_debugfile (); extern int uuconf_debuglevel (); extern int uuconf_maxuuxqts (); extern int uuconf_callin (); extern int uuconf_callout (); extern int uuconf_remote_unknown (); extern int uuconf_validate (); extern int uuconf_grade_cmp (); #ifdef __OPTIMIZE__ #define uuconf_system_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #define uuconf_port_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #define uuconf_dialer_free(qglob, q) \ (uuconf_free_block ((q)->uuconf_palloc), UUCONF_SUCCESS) #endif #endif /* ! UUCONF_ANSI_C */ #if UUCONF_ANSI_C /* Initialize the Taylor UUCP configuration file reading routines. This must be called before calling any of the Taylor UUCP configuration file specific routines. The ppglobal argument should point to a generic pointer. Moreover, before calling this function the pointer either must be set to NULL, or must have been passed to one of the other uuconf init routines. The zprogram argument is the name of the program for which files should be read. If NULL, it is taken as "uucp", which means to read the standard UUCP files. The zname argument is the name of the config file. If it is NULL, the default config file will be used. Note that if the zname argument is obtained from the user running the program, the program should be careful to revoke any special privileges it may have (e.g. on Unix call setuid (getuid ()) and setgid (getgid ())). Otherwise various sorts of spoofing become possible. */ extern int uuconf_taylor_init (void **uuconf_pglobal, const char *uuconf_zprogram, const char *uuconf_zname); /* Get the names of all systems listed in the Taylor UUCP configuration files. This sets *ppzsystems to point to an array of system names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array. If the falias argument is 0, the list will not include any aliases; otherwise, it will. */ extern int uuconf_taylor_system_names (void *uuconf_pglobal, char ***uuconf_ppzsystems, int uuconf_falias); /* Get the information for system zsystem from the Taylor UUCP configuration files. This will set *qsys. */ extern int uuconf_taylor_system_info (void *uuconf_pglobal, const char *uuconf_zsystem, struct uuconf_system *uuconf_qsys); /* Get information for an unknown (anonymous) system. This returns the values set by the ``unknown'' command in the main configuration file. If the ``unknown'' command was not used, this will return UUCONF_NOT_FOUND. */ extern int uuconf_taylor_system_unknown (void *uuconf_pglobal, struct uuconf_system *uuconf_qsys); /* Find a port from the Taylor UUCP configuration files. The arguments and return values are identical to those of uuconf_find_port. */ extern int uuconf_taylor_find_port (void *uuconf_pglobal, const char *uuconf_zname, long uuconf_ibaud, long uuconf_ihighbaud, int (*uuconf_pifn) (struct uuconf_port *, void *uuconf_pinfo), void *uuconf_pinfo, struct uuconf_port *uuconf_qport); /* Get the names of all dialers listed in the Taylor UUCP configuration files. This sets *ppzdialers to point to an array of dialer names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array. */ extern int uuconf_taylor_dialer_names (void *uuconf_pglobal, char ***uuconf_ppzdialers); /* Get the information for the dialer zdialer from the Taylor UUCP configuration files. This sets the fields in *qdialer. */ extern int uuconf_taylor_dialer_info (void *uuconf_pglobal, const char *uuconf_zdialer, struct uuconf_dialer *uuconf_qdialer); /* Get the local node name that should be used, given a login name, considering only the ``myname'' command in the Taylor UUCP configuration files. If the function returns UUCONF_SUCCESS, *pzname will point to an malloced buffer. */ extern int uuconf_taylor_login_localname (void *uuconf_pglobal, const char *uuconf_zlogin, char **pzname); /* Get the callout login name and password for a system from the Taylor UUCP configuration files. This will set both *pzlog and *pzpass to a string allocated by malloc, or to NULL if the value is not found. If neither value is found, the function will return UUCONF_NOT_FOUND. */ extern int uuconf_taylor_callout (void *uuconf_pglobal, const struct uuconf_system *uuconf_qsys, char **uuconf_pzlog, char **uuconf_pzpass); /* See if a login name is permitted for a system. This will return UUCONF_SUCCESS if it is permitted or UUCONF_NOT_FOUND if it is invalid. This checks whether the login name appears in a called-login command with a list of system which does not include the system qsys. */ extern int uuconf_taylor_validate (void *uuconf_pglobal, const struct uuconf_system *uuconf_qsys, const char *uuconf_zlogin); #else /* ! UUCONF_ANSI_C */ extern int uuconf_taylor_init (); extern int uuconf_taylor_system_names (); extern int uuconf_taylor_system_info (); extern int uuconf_taylor_system_unknown (); extern int uuconf_taylor_find_port (); extern int uuconf_taylor_dialer_names (); extern int uuconf_taylor_dialer_info (); extern int uuconf_taylor_login_localname (); extern int uuconf_taylor_callout (); extern int uuconf_taylor_validate (); #endif /* ! UUCONF_ANSI_C */ #if UUCONF_ANSI_C /* Initialize the V2 configuration file reading routines. This must be called before any of the other V2 routines are called. The ppglobal argument should point to a generic pointer. Moreover, before calling this function the pointer either must be set to NULL, or must have been passed to one of the other uuconf init routines. */ extern int uuconf_v2_init (void **uuconf_ppglobal); /* Get the names of all systems listed in the V2 configuration files. This sets *ppzsystems to point to an array of system names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array. If the falias argument is 0, the list will not include any aliases; otherwise, it will. */ extern int uuconf_v2_system_names (void *uuconf_pglobal, char ***uuconf_ppzsystems, int uuconf_falias); /* Get the information for system zsystem from the V2 configuration files. This will set *qsys. */ extern int uuconf_v2_system_info (void *uuconf_pglobal, const char *uuconf_zsystem, struct uuconf_system *uuconf_qsys); /* Find a port from the V2 configuration files. The arguments and return values are identical to those of uuconf_find_port. */ extern int uuconf_v2_find_port (void *uuconf_pglobal, const char *uuconf_zname, long uuconf_ibaud, long uuconf_ihighbaud, int (*uuconf_pifn) (struct uuconf_port *, void *uuconf_pinfo), void *uuconf_pinfo, struct uuconf_port *uuconf_qport); #else /* ! UUCONF_ANSI_C */ extern int uuconf_v2_init (); extern int uuconf_v2_system_names (); extern int uuconf_v2_system_info (); extern int uuconf_v2_find_port (); #endif /* ! UUCONF_ANSI_C */ #if UUCONF_ANSI_C /* Initialize the HDB configuration file reading routines. This should be called before any of the other HDB routines are called. The ppglobal argument should point to a generic pointer. Moreover, before calling this function the pointer either must be set to NULL, or must have been passed to one of the other uuconf init routines. The zprogram argument is used to match against a "services" string in Sysfiles. A NULL or "uucp" argument is taken as "uucico". */ extern int uuconf_hdb_init (void **uuconf_ppglobal, const char *uuconf_zprogram); /* Get the names of all systems listed in the HDB configuration files. This sets *ppzsystems to point to an array of system names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array. If the falias argument is 0, the list will not include any aliases; otherwise, it will (an alias is created by using the ALIAS= keyword in the Permissions file). */ extern int uuconf_hdb_system_names (void *uuconf_pglobal, char ***uuconf_ppzsystems, int uuconf_falias); /* Get the information for system zsystem from the HDB configuration files. This will set *qsys. */ extern int uuconf_hdb_system_info (void *uuconf_pglobal, const char *uuconf_zsystem, struct uuconf_system *uuconf_qsys); /* Get information for an unknown (anonymous) system. If no information is available for unknown systems, this will return UUCONF_NOT_FOUND. This does not run the remote.unknown shell script. */ extern int uuconf_hdb_system_unknown (void *uuconf_pglobal, struct uuconf_system *uuconf_qsys); /* Find a port from the HDB configuration files. The arguments and return values are identical to those of uuconf_find_port. */ extern int uuconf_hdb_find_port (void *uuconf_pglobal, const char *uuconf_zname, long uuconf_ibaud, long uuconf_ihighbaud, int (*uuconf_pifn) (struct uuconf_port *, void *uuconf_pinfo), void *uuconf_pinfo, struct uuconf_port *uuconf_qport); /* Get the names of all dialers listed in the HDB configuration files. This sets *ppzdialers to point to an array of dialer names. The list of names is NULL terminated. The array is allocated using malloc, as is each element of the array. */ extern int uuconf_hdb_dialer_names (void *uuconf_pglobal, char ***uuconf_ppzdialers); /* Get the information for the dialer zdialer from the HDB configuration files. This sets the fields in *qdialer. */ extern int uuconf_hdb_dialer_info (void *uuconf_pglobal, const char *uuconf_zdialer, struct uuconf_dialer *uuconf_qdialer); /* Get the local node name that should be used, given a login name, considering only the MYNAME field in the HDB Permissions file. If the function returns UUCONF_SUCCESS, *pzname will point to an malloced buffer. */ extern int uuconf_hdb_login_localname (void *uuconf_pglobal, const char *uuconf_zlogin, char **pzname); /* Get the name of the HDB remote.unknown shell script. This does not actually run the shell script. If the function returns UUCONF_SUCCESS, the name will be in *pzname, which will point to an malloced buffer. */ extern int uuconf_hdb_remote_unknown (void *uuconf_pglobal, char **pzname); #else /* ! UUCONF_ANSI_C */ extern int uuconf_hdb_init (); extern int uuconf_hdb_system_names (); extern int uuconf_hdb_system_info (); extern int uuconf_hdb_system_unknown (); extern int uuconf_hdb_find_port (); extern int uuconf_hdb_dialer_names (); extern int uuconf_hdb_dialer_info (); extern int uuconf_hdb_localname (); extern int uuconf_hdb_remote_unknown (); #endif /* ! UUCONF_ANSI_C */ #if UUCONF_ANSI_C /* This function will set an appropriate error message into the buffer zbuf, given a uuconf error code. The buffer will always be null terminated, and will never be accessed beyond the length cbuf. This function will return the number of characters needed for the complete message, including the null byte. If this is less than the cbytes argument, the buffer holds a truncated string. */ extern int uuconf_error_string (void *uuconf_pglobal, int ierror, char *zbuf, UUCONF_SIZE_T cbuf); /* If UUCONF_ERROR_ERRNO is set in a return value, this function may be used to retrieve the errno value. This will be the value of errno as set by the system function which failed. However, some system functions, notably some stdio routines, may not set errno, in which case the value will be meaningless. This function does not return a uuconf error code, and it cannot fail. */ extern int uuconf_error_errno (void *uuconf_pglobal); /* If UUCONF_ERROR_FILENAME is set in a return value, this function may be used to retrieve the file name. This function does not return a uuconf error code, and it cannot fail. The string that it returns a pointer to is not guaranteed to remain allocated across the next call to a uuconf function (other than one of the three error retrieving functions). */ extern const char *uuconf_error_filename (void *uuconf_pglobal); /* If UUCONF_ERROR_LINENO is set in a return value, this function may be used to retrieve the line number. This function does not return a uuconf error code, and it cannot fail. */ extern int uuconf_error_lineno (void *uuconf_pglobal); #else /* ! UUCONF_ANSI_C */ extern int uuconf_error_string (); extern int uuconf_error_errno (); extern UUCONF_CONST char *uuconf_error_filename (); extern int uuconf_error_lineno (); #endif /* ! UUCONF_ANSI_C */ /* The uuconf package also provides a few functions which can accept commands and parcel them out according to a table. These are publically visible, partially in the hopes that they will be useful, but mostly because the rest of the Taylor UUCP package uses them. */ /* The types of entries allowed in a command table (struct uuconf_cmdtab). Each type defines how a particular command is interpreted. Each type will either assign a value to a variable or call a function. In all cases, a line of input is parsed into separate fields, separated by whitespace; comments beginning with '#' are discarded, except that a '#' preceeded by a backslash is retained. The first field is taken as the command to execute, and the remaining fields are its arguments. */ /* A boolean value. Used for a command which accepts a single argument, which must begin with 'y', 'Y', 't', or 'T' for true (1) or 'n', 'N', 'f', or 'F' for false (0). The corresponding variable must be an int. */ #define UUCONF_CMDTABTYPE_BOOLEAN (0x12) /* An integer value. Used for a command which accepts a single argument, which must be an integer. The corresponding variable must be an int. */ #define UUCONF_CMDTABTYPE_INT (0x22) /* A long value. Used for a command which accepts a single value, which must be an integer. The corresponding variable must be a long. */ #define UUCONF_CMDTABTYPE_LONG (0x32) /* A string value. Used for a command which accepts a string argument. If there is no argument, the variable will be set to point to a zero byte. Otherwise the variable will be set to point to the string. The corresponding variable must be a char *. The memory pointed to by the variable after it is set must not be modified. */ #define UUCONF_CMDTABTYPE_STRING (0x40) /* A full string value. Used for a command which accepts a series of string arguments separated by whitespace. The corresponding variable must be a char **. It will be set to an NULL terminated array of the arguments. The memory occupied by the array itself, and by the strings within it, must not be modified. */ #define UUCONF_CMDTABTYPE_FULLSTRING (0x50) /* A function. If this command is encountered, the command and its arguments are passed to the corresponding function. They are passed as an array of strings, in which the first string is the command itself, along with a count of strings. This value may be or'red with a specific number of required arguments; UUCONF_CMDTABTYPE_FN | 1 accepts no additional arguments besides the command itself, UUCONF_CMDTABTYPE_FN | 2 accepts 1 argument, etc. UUCONF_CMDTABTYPE_FN | 0, accepts any number of additional arguments. */ #define UUCONF_CMDTABTYPE_FN (0x60) /* A prefix function. The string in the table is a prefix; if a command is encountered with the same prefix, the corresponding function will be called as for UUCONF_CMDTABTYPE_FN. The number of arguments may be or'red in as with UUCONF_CMDTABTYPE_FN. */ #define UUCONF_CMDTABTYPE_PREFIX (0x70) /* This macro will return the particular type of a CMDTABTYPE. */ #define UUCONF_TTYPE_CMDTABTYPE(i) ((i) & 0x70) /* This macro will return the required number of arguments of a CMDTABTYPE. If it is zero, there is no restriction. */ #define UUCONF_CARGS_CMDTABTYPE(i) ((i) & 0x0f) /* When a function is called via UUCONF_CMDTABTYPE_FN or UUCONF_CMDTABTYPE_PREFIX, it may return any uuconf error code (see above). However, it will normally return one of the following: UUCONF_CMDTABRET_CONTINUE: Take no special action. In particular, the arguments passed to the function may be overwritten or freed. UUCONF_CMDTABRET_KEEP: The memory occupied by the arguments passed to the function must be preserved. Continue processing commands. UUCONF_CMDTABRET_EXIT: If reading commands from a file, stop processing. The arguments passed to the function may be overwritten or freed. UUCONF_CMDTABRET_KEEP_AND_EXIT: Stop processing any file. The memory occupied by the arguments passed to the function must be preserved. These values are interpreted by uuconf_cmd_file. The uuconf_cmd_line and uuconf_cmd_args functions may return UUCONF_CMDTABRET_KEEP. It they get an error, they will return an error code with UUCONF_CMDTABRET_EXIT set. Also, of course, they may return any value that is returned by one of the user functions in the uuconf_cmdtab table. */ /* UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT are defined above, with the error codes. */ #define UUCONF_CMDTABRET_CONTINUE UUCONF_SUCCESS #define UUCONF_CMDTABRET_KEEP_AND_EXIT \ (UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT) /* When a function is called via CMDTABTYPE_FN or CMDTABTYPE_PREFIX, it is passed five arguments. This is the type of a pointer to such a function. The uuconf global information structure is passed in for convenience in calling another uuconf function. The arguments to the command are passed in (the command itself is the first argument) along with a count and the value of the pvar field from the uuconf_cmdtab structure in which the function pointer was found. The pinfo argument to the function is taken from the argument to uuconf_cmd_*. */ #if UUCONF_ANSI_C typedef int (*uuconf_cmdtabfn) (void *uuconf_pglobal, int uuconf_argc, char **uuconf_argv, void *uuconf_pvar, void *uuconf_pinfo); #else typedef int (*uuconf_cmdtabfn) (); #endif /* A table of commands is an array of the following structures. The final element of the table should have uuconf_zcmd == NULL. */ struct uuconf_cmdtab { /* Command name. */ UUCONF_CONST char *uuconf_zcmd; /* Command type (one of CMDTABTYPE_*). */ int uuconf_itype; /* If not CMDTABTYPE_FN or CMDTABTYPE_PREFIX, the address of the associated variable. Otherwise, a pointer value to pass to the function pifn. */ UUCONF_POINTER uuconf_pvar; /* The function to call if CMDTABTYPE_FN or CMDTABTYPE_PREFIX. */ uuconf_cmdtabfn uuconf_pifn; }; /* Bit flags to pass to uuconf_processcmds. */ /* If set, case is significant when checking commands. Normally case is ignored. */ #define UUCONF_CMDTABFLAG_CASE (0x1) /* If set, a backslash at the end of a line may be used to include the next physical line in the logical line. */ #define UUCONF_CMDTABFLAG_BACKSLASH (0x2) #if UUCONF_ANSI_C /* Read commands from a file, look them up in a table, and take the appropriate action. This continues reading lines from the file until EOF, or until a function returns with UUCONF_CMDTABRET_EXIT set, or until an error occurs. The qtab argument must point to a table of struct uuconf_cmdtab; the last element in the table should have uuconf_zcmd == NULL. When a UUCONF_CMDTABTYPE_FN or UUCONF_CMDTABTYPE_PREFIX command is found, the pinfo argument will be passed to the called function. If an a command is found that is not in the table, then if pfiunknownfn is NULL the unknown command is ignored; otherwise it is passed to pfiunknownfn, which should return a uuconf return code which is handled as for any other function (the pvar argument to pfiunknownfn will always be NULL). The iflags argument is any combination of the above UUCONF_CMDTABFLAG bits. The pblock argument may also be a memory block, as returned by uuconf_malloc_block (described below), in which case all memory preserved because of UUCONF_CMDTABRET_KEEP will be added to the block so that it may be freed later; it may also be NULL, in which case any such memory is permanently lost. This function initially sets the internal line number to 0, and then increments it as each line is read. It is permitted for any called function to use the uuconf_lineno function to obtain it. If this function is called when not at the start of a file, the value returned by uuconf_lineno (which is, in any case, only valid if an error code with UUCONF_ERROR_LINENO set is returned) must be adjusted by the caller. This returns a normal uuconf return value, as described above. */ extern int uuconf_cmd_file (void *uuconf_pglobal, FILE *uuconf_e, const struct uuconf_cmdtab *uuconf_qtab, void *uuconf_pinfo, uuconf_cmdtabfn uuconf_pfiunknownfn, int uuconf_iflags, void *pblock); /* This utility function is just like uuconf_cmd_file, except that it only operates on a single string. If a function is called via qtab, its return value will be the return value of this function. UUCONF_CMDTABFLAG_BACKSLASH is ignored in iflags. The string z is modified in place. The return value may include the UUCONF_CMDTABRET_KEEP and, on error, the UUCONF_CMDTABRET_EXIT bits, which should be honored by the calling code. */ extern int uuconf_cmd_line (void *uuconf_pglobal, char *uuconf_z, const struct uuconf_cmdtab *uuconf_qtab, void *uuconf_pinfo, uuconf_cmdtabfn uuconf_pfiunknownfn, int uuconf_iflags, void *pblock); /* This utility function is just like uuconf_cmd_line, except it is given a list of already parsed arguments. */ extern int uuconf_cmd_args (void *uuconf_pglobal, int uuconf_cargs, char **uuconf_pzargs, const struct uuconf_cmdtab *uuconf_qtab, void *uuconf_pinfo, uuconf_cmdtabfn uuconf_pfiunknownfn, int uuconf_iflags, void *pblock); #else /* ! UUCONF_ANSI_C */ extern int uuconf_cmd_file (); extern int uuconf_cmd_line (); extern int uuconf_cmd_args (); #endif /* ! UUCONF_ANSI_C */ #if UUCONF_ANSI_C /* The uuconf_cmd_file function may allocate memory permanently, as for setting a UUCONF_CMDTABTYPE_STRING value, in ways which are difficult to free up. A memory block may be used to record all allocated memory, so that it can all be freed up at once at some later time. These functions do not take a uuconf global pointer, and are independent of the rest of the uuconf library. */ /* Allocate a block of memory. If this returns NULL, then malloc returned NULL, and errno is whatever malloc set it to. */ extern void *uuconf_malloc_block (void); /* Allocate memory within a memory block. If this returns NULL, then malloc returned NULL, and errno is whatever malloc set it to. */ extern void *uuconf_malloc (void *uuconf_pblock, UUCONF_SIZE_T uuconf_cbytes); /* Add a block returned by the generic malloc routine to a memory block. This returns zero on success, non-zero on failure. If this fails (returns non-zero), then malloc returned NULL, and errno is whatever malloc set it to. */ extern int uuconf_add_block (void *uuconf_pblock, void *uuconf_padd); /* Free a value returned by uuconf_malloc from a memory block. In the current implementation, this will normally not do anything, but it doesn't hurt. No errors can occur. */ extern void uuconf_free (void *uuconf_pblock, void *uuconf_pfree); /* Free an entire memory block, including all values returned by uuconf_malloc from it and all values added to it with uuconf_add_block. No errors can occur. */ extern void uuconf_free_block (void *uuconf_pblock); #else /* ! UUCONF_ANSI_C */ extern UUCONF_POINTER uuconf_malloc_block (); extern UUCONF_POINTER uuconf_malloc (); extern int uuconf_add_block (); extern /* void */ uuconf_free (); extern /* void */ uuconf_free_block (); #endif /* ! UUCONF_ANSI_C */ #endif /* ! defined (UUCONF_H) */ 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 mustuucp-1.04/uuconv.c1004440004150000170000015340005337263523011052 037777777777 1 0 /* 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.11 1992/12/30 05:07:59 ian Rel $"; #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); } LL) 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) { spuucp-1.04/uucp.11004440004150000170000001077505337263523010434 037777777777 1 0 ''' $Id: uucp.1,v 1.7 1993/01/24 00:52:55 ian Rel $ .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) ntfuucp-1.04/uucp.c1004440004150000170000007062605337263523010517 037777777777 1 0 /* 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.43 1993/01/01 16:31:03 ian Rel $"; #endif #include #include #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* Local functions. */ static void ucusage P((void)); static void ucdirfile P((const char *zdir, const char *zfile, pointer pinfo)); static void uccopy P((const char *zfile, const char *zdest)); static void ucadd_cmd P((const struct uuconf_system *qsys, const struct scmd *qcmd, const char *zlog)); static void ucspool_cmds P((boolean fjobid)); static const char *zcone_system P((boolean *pfany)); static void ucrecord_file P((const char *zfile)); static void ucabort P((void)); /* The program name. */ char abProgram[] = "uucp"; /* Long getopt options. */ static const struct option asClongopts[] = { { NULL, 0, NULL, 0 } }; /* Local variables. There are a bunch of these, mostly set by the options and the last (the destination) argument. These have file scope so that they may be easily passed into uccopy; they could for the most part also be wrapped up in a structure and passed in. */ /* The uuconf global pointer. */ static pointer pCuuconf; /* TRUE if source files should be copied to the spool directory. */ static boolean fCcopy = TRUE; /* Grade to use. */ static char bCgrade = BDEFAULT_UUCP_GRADE; /* Whether to send mail to the requesting user when the copy is complete. */ static boolean fCmail = FALSE; /* User to notify on remote system. */ static const char *zCnotify = ""; /* TRUE if remote files should be prefixed with the current working directory. */ static boolean fCexpand = TRUE; /* TRUE if necessary directories should be created on the destination system. */ static boolean fCmkdirs = TRUE; /* Local name. */ static const char *zClocalname; /* User name. */ static const char *zCuser = NULL; /* TRUE if this is a remote request. */ static boolean fCremote = FALSE; /* TRUE if the destination is this system. */ static boolean fClocaldest; /* Destination system. */ static struct uuconf_system sCdestsys; /* Systems to forward to, if not NULL. */ static char *zCforward; /* Options to use when sending a file. */ static char abCsend_options[20]; /* Options to use when receiving a file. */ static char abCrec_options[20]; /* TRUE if the current file being copied from is in the cwd. */ static boolean fCneeds_cwd; /* The main program. */ int main (argc, argv) int argc; char **argv; { /* -I: configuration file name. */ const char *zconfig = NULL; /* -j: output job id. */ boolean fjobid = FALSE; /* -r: don't start uucico when finished. */ boolean fuucico = TRUE; /* -R: copy directories recursively. */ boolean frecursive = FALSE; /* -s: report status to named file. */ const char *zstatus_file = NULL; /* -t: emulate uuto. */ boolean fuuto = FALSE; int iopt; pointer puuconf; int iuuconf; int i; boolean fgetcwd; char *zexclam; char *zdestfile; const char *zdestsys; char *zoptions; boolean fexit; while ((iopt = getopt_long (argc, argv, "cCdfg:I:jmn:prRs:tu:Wx:", asClongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'c': /* Do not copy local files to spool directory. */ fCcopy = FALSE; break; case 'p': case 'C': /* Copy local files to spool directory. */ fCcopy = TRUE; break; case 'd': /* Create directories if necessary. */ fCmkdirs = TRUE; break; case 'f': /* Do not create directories if they don't exist. */ fCmkdirs = FALSE; break; case 'g': /* Set job grade. */ bCgrade = optarg[0]; break; case 'I': /* Name configuration file. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'j': /* Output job id. */ fjobid = TRUE; break; case 'm': /* Mail to requesting user. */ fCmail = TRUE; break; case 'n': /* Notify remote user. */ zCnotify = optarg; break; case 'r': /* Don't start uucico when finished. */ fuucico = FALSE; break; case 'R': /* Copy directories recursively. */ frecursive = TRUE; break; case 's': /* Report status to named file. */ zstatus_file = optarg; break; case 't': /* Emulate uuto. */ fuuto = TRUE; break; case 'u': /* Set user name. */ zCuser = optarg; break; case 'W': /* Expand only local file names. */ fCexpand = FALSE; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 0: /* Long option found and flag set. */ break; default: ucusage (); break; } } if (! UUCONF_GRADE_LEGAL (bCgrade)) { ulog (LOG_ERROR, "Ignoring illegal grade"); bCgrade = BDEFAULT_UUCP_GRADE; } /* The user name must contain a '!', which is treated as a remote name, to avoid spoofing of other users (there is no advantage to spoofing remote users, except to send them random bits of mail, which you can do anyhow). */ if (zCuser != NULL) { if (strchr (zCuser, '!') != NULL) fCremote = TRUE; else { ulog (LOG_ERROR, "Ignoring local user name"); zCuser = NULL; } } if (argc - optind < 2) ucusage (); iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); pCuuconf = puuconf; #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif /* See if we are going to need to know the current directory. We just check each argument to see whether it's an absolute pathname. We actually aren't going to need the cwd if fCexpand is FALSE and the file is remote, but so what. */ fgetcwd = FALSE; for (i = optind; i < argc; i++) { zexclam = strrchr (argv[i], '!'); if (zexclam == NULL) zexclam = argv[i]; else ++zexclam; if (fsysdep_needs_cwd (zexclam)) { fgetcwd = TRUE; break; } } #ifdef SIGINT usysdep_signal (SIGINT); #endif #ifdef SIGHUP usysdep_signal (SIGHUP); #endif #ifdef SIGQUIT usysdep_signal (SIGQUIT); #endif #ifdef SIGTERM usysdep_signal (SIGTERM); #endif #ifdef SIGPIPE usysdep_signal (SIGPIPE); #endif usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0)); ulog_fatal_fn (ucabort); if (zCuser == NULL) zCuser = zsysdep_login_name (); iuuconf = uuconf_localname (puuconf, &zClocalname); if (iuuconf == UUCONF_NOT_FOUND) { zClocalname = zsysdep_localname (); if (zClocalname == NULL) exit (EXIT_FAILURE); } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); /* If we are emulating uuto, translate the destination argument, and notify the destination user. This had better not turn into something that requires the current directory, or we may have passed INIT_GETCWD incorrectly. */ if (fuuto) { if (*zCnotify == '\0') { zexclam = strrchr (argv[argc - 1], '!'); if (zexclam == NULL) ucusage (); zCnotify = zexclam + 1; } argv[argc - 1] = zsysdep_uuto (argv[argc - 1], zClocalname); if (argv[argc - 1] == NULL) ucusage (); } /* Set up the file transfer options. */ zoptions = abCsend_options; if (fCcopy) *zoptions++ = 'C'; else *zoptions++ = 'c'; if (fCmkdirs) *zoptions++ = 'd'; else *zoptions++ = 'f'; if (fCmail) *zoptions++ = 'm'; if (*zCnotify != '\0') *zoptions++ = 'n'; *zoptions = '\0'; zoptions = abCrec_options; if (fCmkdirs) *zoptions++ = 'd'; else *zoptions++ = 'f'; if (fCmail) *zoptions++ = 'm'; *zoptions = '\0'; zexclam = strchr (argv[argc - 1], '!'); if (zexclam == NULL) { zdestsys = zClocalname; zdestfile = argv[argc - 1]; fClocaldest = TRUE; } else { size_t clen; char *zcopy; clen = zexclam - argv[argc - 1]; zcopy = zbufalc (clen + 1); memcpy (zcopy, argv[argc - 1], clen); zcopy[clen] = '\0'; zdestsys = zcopy; zdestfile = zexclam + 1; fClocaldest = FALSE; } iuuconf = uuconf_system_info (puuconf, zdestsys, &sCdestsys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (fClocaldest) { iuuconf = uuconf_system_local (puuconf, &sCdestsys); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); sCdestsys.uuconf_zname = (char *) zClocalname; } else { if (! funknown_system (puuconf, zdestsys, &sCdestsys)) ulog (LOG_FATAL, "%s: System not found", zdestsys); } } /* Here zdestfile is the destination file name following the destination system name (if any); it may contain other systems to forward the files through. Isolate the file from the list of systems. */ zexclam = strrchr (zdestfile, '!'); if (zexclam == NULL) zCforward = NULL; else { size_t clen; #if DEBUG > 0 if (fClocaldest) ulog (LOG_FATAL, "Can't happen"); #endif clen = zexclam - zdestfile; zCforward = zbufalc (clen + 1); memcpy (zCforward, zdestfile, clen); zCforward[clen] = '\0'; zdestfile = zexclam + 1; } /* Turn the destination into an absolute path, unless it is on a remote system and -W was used. */ if (fClocaldest) zdestfile = zsysdep_local_file_cwd (zdestfile, sCdestsys.uuconf_zpubdir); else if (fCexpand) zdestfile = zsysdep_add_cwd (zdestfile); if (zdestfile == NULL) { ulog_close (); usysdep_exit (FALSE); } /* Process each source argument. */ for (i = optind; i < argc - 1 && ! FGOT_SIGNAL (); i++) { boolean flocal; char *zfrom; fCneeds_cwd = FALSE; if (strchr (argv[i], '!') != NULL) { flocal = FALSE; zfrom = zbufcpy (argv[i]); } else { /* This is a local file. Make sure we get it out of the original directory. We don't support local wildcards, leaving that to the shell. */ flocal = TRUE; if (fsysdep_needs_cwd (argv[i])) fCneeds_cwd = TRUE; zfrom = zsysdep_local_file_cwd (argv[i], sCdestsys.uuconf_zpubdir); if (zfrom == NULL) ucabort (); } if (! flocal || ! fsysdep_directory (zfrom)) uccopy (zfrom, zdestfile); else { char *zbase, *zindir; if (! frecursive) ulog (LOG_FATAL, "%s: directory without -R", zfrom); zbase = zsysdep_base_name (zfrom); if (zbase == NULL) ucabort (); zindir = zsysdep_in_dir (zdestfile, zbase); ubuffree (zbase); if (zindir == NULL) ucabort (); usysdep_walk_tree (zfrom, ucdirfile, zindir); ubuffree (zindir); } ubuffree (zfrom); } /* See if we got an interrupt, presumably from the user. */ if (FGOT_SIGNAL ()) ucabort (); /* Now push out the actual commands, making log entries for them. */ ulog_to_file (puuconf, TRUE); ulog_user (zCuser); ucspool_cmds (fjobid); ulog_close (); if (! fuucico) fexit = TRUE; else { const char *zsys; boolean fany; zsys = zcone_system (&fany); if (zsys != NULL) fexit = fsysdep_run ("uucico", "-s", zsys); else if (fany) fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL); else fexit = TRUE; } usysdep_exit (fexit); /* Avoid error about not returning. */ return 0; } static void ucusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uucp [options] file1 [file2 ...] dest\n"); fprintf (stderr, " -c: Do not copy local files to spool directory\n"); fprintf (stderr, " -C, -p: Copy local files to spool directory (default)\n"); fprintf (stderr, " -d: Create necessary directories (default)\n"); fprintf (stderr, " -f: Do not create directories (fail if they do not exist)\n"); fprintf (stderr, " -g grade: Set job grade (must be alphabetic)\n"); fprintf (stderr, " -m: Report status of copy by mail\n"); fprintf (stderr, " -n user: Report status of copy by mail to remote user\n"); fprintf (stderr, " -R: Copy directories recursively\n"); fprintf (stderr, " -r: Do not start uucico daemon\n"); fprintf (stderr, " -s file: Report completion status to file\n"); fprintf (stderr, " -j: Report job id\n"); fprintf (stderr, " -W: Do not add current directory to remote filenames\n"); fprintf (stderr, " -t: Emulate uuto\n"); fprintf (stderr, " -u name: Set user name\n"); fprintf (stderr, " -x debug: Set debugging level\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* This is called for each file in a directory heirarchy. */ static void ucdirfile (zfull, zrelative, pinfo) const char *zfull; const char *zrelative; pointer pinfo; { const char *zdestfile = (const char *) pinfo; char *zto; zto = zsysdep_in_dir (zdestfile, zrelative); if (zto == NULL) ucabort (); uccopy (zfull, zto); ubuffree (zto); } /* Handle the copying of one regular file. The zdest argument is the destination file; if we are recursively copying a directory, it will be extended by any subdirectory names. Note that zdest is an absolute path. */ static void uccopy (zfile, zdest) const char *zfile; const char *zdest; { struct scmd s; char *zexclam; char *zto; zexclam = strchr (zfile, '!'); if (zexclam == NULL) { openfile_t efrom; /* Copy from a local file. Make sure the user has access to this file, since we are running setuid. */ if (! fsysdep_access (zfile)) ucabort (); /* If this copy is being requested by a remote system, we may transfer the file if it needs the current working directory (meaning, I hope, that it is in the execution directory) or it is on the permitted transfer list. Note that unlike most of the other checks, this one is not double-checked by uucico. */ if (fCremote && ! fCneeds_cwd && ! fin_directory_list (zfile, sCdestsys.uuconf_pzremote_send, sCdestsys.uuconf_zpubdir, TRUE, TRUE, (const char *) NULL)) ulog (LOG_FATAL, "Not permitted to send %s", zfile); if (fClocaldest) { boolean fok; /* Copy one local file to another. */ /* Check that we have permission to receive into the desired directory. */ if (fCremote) fok = fin_directory_list (zdest, sCdestsys.uuconf_pzremote_receive, sCdestsys.uuconf_zpubdir, TRUE, FALSE, (const char *) NULL); else fok = fin_directory_list (zdest, sCdestsys.uuconf_pzlocal_receive, sCdestsys.uuconf_zpubdir, TRUE, FALSE, zCuser); if (! fok) ulog (LOG_FATAL, "Not permitted to receive to %s", zdest); zto = zsysdep_add_base (zdest, zfile); if (zto == NULL) ucabort (); efrom = esysdep_user_fopen (zfile, TRUE, TRUE); if (! ffileisopen (efrom)) ucabort (); if (! fcopy_open_file (efrom, zto, FALSE, fCmkdirs)) ucabort (); (void) ffileclose (efrom); ubuffree (zto); } else { const char *zloc; char abtname[CFILE_NAME_LEN]; unsigned int imode; char *ztemp; /* Copy a local file to a remote file. We may have to copy the local file to the spool directory. */ imode = ixsysdep_file_mode (zfile); if (imode == 0) ucabort (); zloc = sCdestsys.uuconf_zlocalname; if (zloc == NULL) zloc = zClocalname; ztemp = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade, FALSE, abtname, (char *) NULL, (char *) NULL); if (ztemp == NULL) ucabort (); if (! fCcopy) { /* If we are copying the file, we don't actually use the temporary file; we still want to get a name for the other system to use as a key for file restart. */ ubuffree (ztemp); /* Make sure the daemon will be permitted to send this file. */ if (! fsysdep_daemon_access (zfile)) ucabort (); if (! fin_directory_list (zfile, sCdestsys.uuconf_pzlocal_send, sCdestsys.uuconf_zpubdir, TRUE, TRUE, (fCremote ? (const char *) NULL : zCuser))) ulog (LOG_FATAL, "Not permitted to send %s", zfile); } else { efrom = esysdep_user_fopen (zfile, TRUE, TRUE); if (! ffileisopen (efrom)) ucabort (); ucrecord_file (ztemp); if (! fcopy_open_file (efrom, ztemp, FALSE, TRUE)) ucabort (); (void) ffileclose (efrom); } if (zCforward == NULL) { /* We're not forwarding. Just send the file. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (zfile); s.zto = zbufcpy (zdest); s.zuser = zCuser; s.zoptions = abCsend_options; s.ztemp = zbufcpy (abtname); s.imode = imode; s.znotify = zCnotify; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ucadd_cmd (&sCdestsys, &s, (const char *) NULL); } else { char *zbase; char *zxqt; char abxtname[CFILE_NAME_LEN]; char abdname[CFILE_NAME_LEN]; char abxname[CFILE_NAME_LEN]; FILE *e; char *zlog; /* We want to forward this file through sCdestsys to some other system(s). We set up a remote execution of uucp on sCdestsys to forward the file along. */ zbase = zsysdep_base_name (zfile); if (zbase == NULL) ucabort (); zxqt = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade, TRUE, abxtname, abdname, abxname); if (zxqt == NULL) ucabort (); e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); if (e == NULL) ucabort (); ucrecord_file (zxqt); fprintf (e, "U %s %s\n", zCuser, zloc); fprintf (e, "F %s %s\n", abdname, zbase); fprintf (e, "C uucp -C"); if (fCmkdirs) fprintf (e, " -d"); else fprintf (e, " -f"); fprintf (e, " -g %c", bCgrade); if (fCmail) fprintf (e, " -m"); if (*zCnotify != '\0') fprintf (e, " -n %s", zCnotify); if (! fCexpand) fprintf (e, " -W"); fprintf (e, " %s %s!%s\n", zbase, zCforward, zdest); ubuffree (zbase); if (fclose (e) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); /* Send the execution file. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (abxtname); s.zto = zbufcpy (abxname); s.zuser = zCuser; s.zoptions = "C"; s.ztemp = s.zfrom; s.imode = 0666; s.znotify = NULL; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; zlog = zbufalc (sizeof "Queuing uucp !" + strlen (zfile) + strlen (zCforward) + strlen (zdest)); sprintf (zlog, "Queuing uucp %s %s!%s", zfile, zCforward, zdest); ucadd_cmd (&sCdestsys, &s, zlog); /* Send the data file. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (zfile); s.zto = zbufcpy (abdname); s.zuser = zCuser; s.zoptions = fCcopy ? "C" : "c"; s.ztemp = zbufcpy (abtname); s.imode = 0666; s.znotify = NULL; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ucadd_cmd (&sCdestsys, &s, ""); } } } else { char *zfrom; char *zforward; size_t clen; char *zcopy; struct uuconf_system *qfromsys; int iuuconf; const char *zloc; /* Copy from a remote file. Get the file name after any systems we may need to forward the file from. */ zfrom = strrchr (zfile, '!'); if (zfrom == zexclam) zforward = NULL; else { clen = zfrom - zexclam - 1; zforward = zbufalc (clen + 1); memcpy (zforward, zexclam + 1, clen); } ++zfrom; if (fCexpand) { /* Add the current directory to the filename if it's not already there. */ zfrom = zsysdep_add_cwd (zfrom); if (zfrom == NULL) ucabort (); } /* Read the system information. */ clen = zexclam - zfile; zcopy = zbufalc (clen + 1); memcpy (zcopy, zfile, clen); zcopy[clen] = '\0'; qfromsys = ((struct uuconf_system *) xmalloc (sizeof (struct uuconf_system))); iuuconf = uuconf_system_info (pCuuconf, zcopy, qfromsys); if (iuuconf == UUCONF_NOT_FOUND) { if (! funknown_system (pCuuconf, zcopy, qfromsys)) ulog (LOG_FATAL, "%s: System not found", zcopy); } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, pCuuconf, iuuconf); ubuffree (zcopy); zloc = qfromsys->uuconf_zlocalname; if (zloc == NULL) zloc = zClocalname; if (zforward == NULL && fClocaldest) { boolean fok; /* The file is to come directly from qfromsys to the local system. */ /* Check that we have permission to receive into the desired directory. If we don't have permission, uucico will fail. */ if (fCremote) fok = fin_directory_list (zdest, qfromsys->uuconf_pzremote_receive, qfromsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL); else fok = fin_directory_list (zdest, qfromsys->uuconf_pzlocal_receive, qfromsys->uuconf_zpubdir, TRUE, FALSE, zCuser); if (! fok) ulog (LOG_FATAL, "Not permitted to receive to %s", zdest); /* If the remote filespec is wildcarded, we must generate an 'X' request. We currently check for Unix shell wildcards. Note that it should do no harm to mistake a non-wildcard for a wildcard. */ if (zfrom[strcspn (zfrom, "*?[")] != '\0') { s.bcmd = 'X'; zto = zbufalc (strlen (zloc) + strlen (zdest) + sizeof "!"); sprintf (zto, "%s!%s", zloc, zdest); } else { s.bcmd = 'R'; zto = zbufcpy (zdest); } s.pseq = NULL; s.zfrom = zfrom; s.zto = zto; s.zuser = zCuser; s.zoptions = abCrec_options; s.ztemp = ""; s.imode = 0; s.znotify = ""; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ucadd_cmd (qfromsys, &s, (const char *) NULL); } else { char *zxqt; char abtname[CFILE_NAME_LEN]; char abxname[CFILE_NAME_LEN]; FILE *e; char *zcmd; char *zlog; /* The file either comes from some other system through qfromsys or is intended for some other system. Send an execution request to qfromsys to handle everything. */ zxqt = zsysdep_data_file_name (qfromsys, zloc, bCgrade, TRUE, abtname, (char *) NULL, abxname); if (zxqt == NULL) ucabort (); e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); if (e == NULL) ucabort (); ucrecord_file (zxqt); fprintf (e, "U %s %s\n", zCuser, zloc); fprintf (e, "C uucp -C"); if (fCmkdirs) fprintf (e, " -d"); else fprintf (e, " -f"); fprintf (e, " -g %c", bCgrade); if (fCmail) fprintf (e, " -m"); if (*zCnotify != '\0') fprintf (e, " -n %s", zCnotify); if (! fCexpand) fprintf (e, " -W"); clen = (strlen (zfrom) + strlen (zloc) + strlen (sCdestsys.uuconf_zname) + strlen (zdest)); if (zforward != NULL) clen += strlen (zforward); if (zCforward != NULL) clen += strlen (zCforward); zcmd = zbufalc (sizeof "! !!!" + clen); *zcmd = '\0'; if (zforward != NULL) sprintf (zcmd + strlen (zcmd), "%s!", zforward); sprintf (zcmd + strlen (zcmd), "%s %s!", zfrom, zloc); if (! fClocaldest) sprintf (zcmd + strlen (zcmd), "%s!", sCdestsys.uuconf_zname); if (zCforward != NULL) sprintf (zcmd + strlen (zcmd), "%s!", zCforward); sprintf (zcmd + strlen (zcmd), "%s", zdest); fprintf (e, " %s\n", zcmd); if (fclose (e) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); /* Send the execution file. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (abtname); s.zto = zbufcpy (abxname); s.zuser = zCuser; s.zoptions = "C"; s.ztemp = s.zfrom; s.imode = 0666; s.znotify = NULL; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; zlog = zbufalc (sizeof "Queueing uucp " + strlen (zcmd)); sprintf (zlog, "Queueing uucp %s", zcmd); ucadd_cmd (qfromsys, &s, zlog); ubuffree (zcmd); ubuffree (zforward); } } } /* We keep a list of jobs for each system. */ struct sjob { struct sjob *qnext; const struct uuconf_system *qsys; int ccmds; struct scmd *pascmds; const char **pazlogs; }; static struct sjob *qCjobs; static void ucadd_cmd (qsys, qcmd, zlog) const struct uuconf_system *qsys; const struct scmd *qcmd; const char *zlog; { struct sjob *qjob; if (! qsys->uuconf_fcall_transfer && ! qsys->uuconf_fcalled_transfer) ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", qsys->uuconf_zname); for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext) if (strcmp (qjob->qsys->uuconf_zname, qsys->uuconf_zname) == 0) break; if (qjob == NULL) { qjob = (struct sjob *) xmalloc (sizeof (struct sjob)); qjob->qnext = qCjobs; qjob->qsys = qsys; qjob->ccmds = 0; qjob->pascmds = NULL; qjob->pazlogs = NULL; qCjobs = qjob; } qjob->pascmds = ((struct scmd *) xrealloc ((pointer) qjob->pascmds, (qjob->ccmds + 1) * sizeof (struct scmd))); qjob->pascmds[qjob->ccmds] = *qcmd; qjob->pazlogs = ((const char **) xrealloc ((pointer) qjob->pazlogs, (qjob->ccmds + 1) * sizeof (const char *))); qjob->pazlogs[qjob->ccmds] = zlog; ++qjob->ccmds; } static void ucspool_cmds (fjobid) boolean fjobid; { struct sjob *qjob; char *zjobid; for (qjob = qCjobs; qjob != NULL; qjob = qjob->qnext) { ulog_system (qjob->qsys->uuconf_zname); zjobid = zsysdep_spool_commands (qjob->qsys, bCgrade, qjob->ccmds, qjob->pascmds); if (zjobid != NULL) { int i; struct scmd *qcmd; const char **pz; for (i = 0, qcmd = qjob->pascmds, pz = qjob->pazlogs; i < qjob->ccmds; i++, qcmd++, pz++) { if (*pz != NULL) { if (**pz != '\0') ulog (LOG_NORMAL, "%s", *pz); } else if (qcmd->bcmd == 'S') ulog (LOG_NORMAL, "Queuing send of %s to %s", qcmd->zfrom, qcmd->zto); else if (qcmd->bcmd == 'R') ulog (LOG_NORMAL, "Queuing request of %s to %s", qcmd->zfrom, qcmd->zto); else { const char *zto; zto = strrchr (qcmd->zto, '!'); if (zto != NULL) ++zto; else zto = qcmd->zto; ulog (LOG_NORMAL, "Queuing request of %s to %s", qcmd->zfrom, zto); } } if (fjobid) printf ("%s\n", zjobid); ubuffree (zjobid); } } } /* Return the system name for which we have created commands, or NULL if we've created commands for more than one system. Set *pfany to FALSE if we didn't create work for any system. */ static const char * zcone_system (pfany) boolean *pfany; { if (qCjobs == NULL) { *pfany = FALSE; return NULL; } *pfany = TRUE; if (qCjobs->qnext == NULL) return qCjobs->qsys->uuconf_zname; else return NULL; } /* Keep track of all files we have created so that we can delete them if we get a signal. The argument will be on the heap. */ static int cCfiles; static const char **pCaz; static void ucrecord_file (zfile) const char *zfile; { pCaz = (const char **) xrealloc ((pointer) pCaz, (cCfiles + 1) * sizeof (const char *)); pCaz[cCfiles] = zfile; ++cCfiles; } /* Delete all the files we have recorded and exit. */ static void ucabort () { int i; for (i = 0; i < cCfiles; i++) (void) remove (pCaz[i]); ulog_close (); usysdep_exit (FALSE); } zxqt = zsysdep_data_file_name (&sCdestsys, zloc, bCgrade, TRUE, abxtname, abdname, uucp-1.04/uucp.h1004440004150000170000002453705337263524010525 037777777777 1 0 /* uucp.h Header file for the UUCP package. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ /* Get the system configuration parameters. */ #include "conf.h" #include "policy.h" /* Get a definition for ANSI_C if we weren't given one. */ #ifndef ANSI_C #ifdef __STDC__ #define ANSI_C 1 #else /* ! defined (__STDC__) */ #define ANSI_C 0 #endif /* ! defined (__STDC__) */ #endif /* ! defined (ANSI_C) */ /* Pass this definition into uuconf.h. */ #define UUCONF_ANSI_C ANSI_C /* We always include some standard header files. We need to define sig_atomic_t. */ #if HAVE_STDDEF_H #include #endif #include #include /* On some systems we need to get sig_atomic_t or size_t or time_t. */ #if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && HAVE_SIG_ATOMIC_T_IN_TYPES_H #define USE_TYPES_H 1 #else #if ! HAVE_SIZE_T_IN_STDDEF_H && HAVE_SIZE_T_IN_TYPES_H #define USE_TYPES_H 1 #else #if ! HAVE_TIME_T_IN_TIME_H && HAVE_TIME_T_IN_TYPES_H #define USE_TYPES_H 1 #endif #endif #endif #ifndef USE_TYPES_H #define USE_TYPES_H 0 #endif #if USE_TYPES_H #include #endif /* Make sure we have sig_atomic_t. */ #if ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H #ifndef SIG_ATOMIC_T /* There is no portable definition for sig_atomic_t. */ #define SIG_ATOMIC_T char #endif /* ! defined (SIG_ATOMIC_T) */ typedef SIG_ATOMIC_T sig_atomic_t; #endif /* ! HAVE_SIG_ATOMIC_T_IN_SIGNAL_H && ! HAVE_SIG_ATOMIC_T_IN_TYPES_H */ /* Make sure we have size_t. We use int as the default because the main use of this type is to provide an argument to malloc and realloc. On a system which does not define size_t, int is certainly the correct type to use. */ #if ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H #ifndef SIZE_T #define SIZE_T unsigned #endif /* ! defined (SIZE_T) */ typedef SIZE_T size_t; #endif /* ! HAVE_SIZE_T_IN_STDDEF_H && ! HAVE_SIZE_T_IN_TYPES_H */ /* Make sure we have time_t. We use long as the default. We don't bother to let conf.h override this, since on a system which doesn't define time_t long must be correct. */ #if ! HAVE_TIME_T_IN_TIME_H && ! HAVE_TIME_T_IN_TYPES_H typedef long time_t; #endif /* Set up some definitions for both ANSI C and Classic C. P() -- for function prototypes (e.g. extern int foo P((int)) ). pointer -- for a generic pointer (i.e. void *). constpointer -- for a generic pointer to constant data. BUCHAR -- to convert a character to unsigned. */ #if ANSI_C #if ! HAVE_VOID || ! HAVE_UNSIGNED_CHAR #error ANSI C compiler without void or unsigned char #endif #define P(x) x typedef void *pointer; typedef const void *constpointer; #define BUCHAR(b) ((unsigned char) (b)) #else /* ! ANSI_C */ /* Handle uses of const, volatile and void in Classic C. */ #define const #define volatile #if ! HAVE_VOID #define void int #endif #define P(x) () typedef char *pointer; typedef const char *constpointer; #if HAVE_UNSIGNED_CHAR #define BUCHAR(b) ((unsigned char) (b)) #else /* ! HAVE_UNSIGNED_CHAR */ /* This should work on most systems, but not necessarily all. */ #define BUCHAR(b) ((b) & 0xff) #endif /* ! HAVE_UNSIGNED_CHAR */ #endif /* ! ANSI_C */ /* Make sure we have a definition for offsetof. */ #ifndef offsetof #define offsetof(type, field) \ ((size_t) ((char *) &(((type *) 0)->field) - (char *) (type *) 0)) #endif /* Only use inline with gcc. */ #ifndef __GNUC__ #define __inline__ #endif /* Get the string functions, which are used throughout the code. */ #if HAVE_MEMORY_H #include #else /* We really need a definition for memchr, and this should not conflict with anything in . I hope. */ extern pointer memchr (); #endif #if HAVE_STRING_H #include #else /* ! HAVE_STRING_H */ #if HAVE_STRINGS_H #include #else /* ! HAVE_STRINGS_H */ extern char *strcpy (), *strncpy (), *strchr (), *strrchr (), *strtok (); extern char *strcat (), *strerror (), *strstr (); extern size_t strlen (), strspn (), strcspn (); #if ! HAVE_MEMORY_H extern pointer memcpy (), memchr (); #endif /* ! HAVE_MEMORY_H */ #endif /* ! HAVE_STRINGS_H */ #endif /* ! HAVE_STRING_H */ /* Get what we need from . */ #if HAVE_STDLIB_H #include #else /* ! HAVE_STDLIB_H */ extern pointer malloc (), realloc (), bsearch (); extern long strtol (); extern char *getenv (); #endif /* ! HAVE_STDLIB_H */ /* NeXT uses to declare a bunch of functions. */ #if HAVE_LIBC_H #include #endif /* Make sure we have the EXIT_ macros. */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS (0) #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE (1) #endif /* If we need to declare errno, do so. I don't want to always do this, because some system might theoretically have a different declaration for errno. On a POSIX system this is sure to work. */ #if ! HAVE_ERRNO_DECLARATION extern int errno; #endif /* If the system has the socket call, guess that we can compile the TCP code. */ #define HAVE_TCP HAVE_SOCKET /* If the system has the t_open call, guess that we can compile the TLI code. */ #define HAVE_TLI HAVE_T_OPEN /* The boolean type holds boolean values. */ typedef int boolean; #undef TRUE #undef FALSE #define TRUE (1) #define FALSE (0) /* The openfile_t type holds an open file. This depends on whether we are using stdio or not. */ #if USE_STDIO typedef FILE *openfile_t; #define EFILECLOSED ((FILE *) NULL) #define ffileisopen(e) ((e) != NULL) #define ffileeof(e) feof (e) #define cfileread(e, z, c) fread ((z), 1, (c), (e)) #define ffilereaderror(e, c) ferror (e) #define cfilewrite(e, z, c) fwrite ((z), 1, (c), (e)) #ifdef SEEK_SET #define ffileseek(e, i) (fseek ((e), (long) (i), SEEK_SET) == 0) #define ffilerewind(e) (fseek ((e), (long) 0, SEEK_SET) == 0) #else #define ffileseek(e, i) (fseek ((e), (long) (i), 0) == 0) #define ffilerewind(e) (fseek ((e), (long) 0, 0) == 0) #endif #define ffileclose(e) (fclose (e) == 0) #else /* ! USE_STDIO */ #if HAVE_UNISTD_H #include #endif typedef int openfile_t; #define EFILECLOSED (-1) #define ffileisopen(e) ((e) >= 0) #define ffileeof(e) (FALSE) #define cfileread(e, z, c) read ((e), (z), (c)) #define ffilereaderror(e, c) ((c) < 0) #define cfilewrite(e, z, c) write ((e), (z), (c)) #ifdef SEEK_SET #define ffileseek(e, i) (lseek ((e), (long) i, SEEK_SET) >= 0) #define ffilerewind(e) (lseek ((e), (long) 0, SEEK_SET) >= 0) #else #define ffileseek(e, i) (lseek ((e), (long) i, 0) >= 0) #define ffilerewind(e) (lseek ((e), (long) 0, 0) >= 0) #endif #define ffileclose(e) (close (e) >= 0) #endif /* ! USE_STDIO */ /* A prototype for main to avoid warnings from gcc 2.0 -Wmissing-prototype option. */ extern int main P((int argc, char **argv)); /* Some standard routines which we only define if they are not present on the system we are compiling on. */ #if ! HAVE_GETLINE /* Read a line from a file. */ extern int getline P((char **pz, size_t *pc, FILE *e)); #endif #if ! HAVE_REMOVE /* Erase a file. */ #undef remove extern int remove P((const char *zfile)); #endif #if ! HAVE_STRDUP /* Copy a string into memory. */ extern char *strdup P((const char *z)); #endif #if ! HAVE_STRSTR /* Look for one string within another. */ extern char *strstr P((const char *zouter, const char *zinner)); #endif #if ! HAVE_STRCASECMP #if HAVE_STRICMP #define strcasecmp stricmp #else /* ! HAVE_STRICMP */ /* Rename strcasecmp to avoid ANSI C name space. */ #define strcasecmp xstrcasecmp extern int strcasecmp P((const char *z1, const char *z2)); #endif /* ! HAVE_STRICMP */ #endif /* ! HAVE_STRCASECMP */ #if ! HAVE_STRNCASECMP #if HAVE_STRNICMP #define strncasecmp strnicmp #else /* ! HAVE_STRNICMP */ /* Rename strncasecmp to avoid ANSI C name space. */ #define strncasecmp xstrncasecmp extern int strncasecmp P((const char *z1, const char *z2, size_t clen)); #endif /* ! HAVE_STRNICMP */ #endif /* ! HAVE_STRNCASECMP */ #if ! HAVE_STRERROR /* Get a string corresponding to an error message. */ #undef strerror extern char *strerror P((int ierr)); #endif /* Get the appropriate definitions for memcmp, memcpy, memchr and bzero. */ #if ! HAVE_MEMCMP #if HAVE_BCMP #define memcmp(p1, p2, c) bcmp ((p1), (p2), (c)) #else /* ! HAVE_BCMP */ extern int memcmp P((constpointer p1, constpointer p2, size_t c)); #endif /* ! HAVE_BCMP */ #endif /* ! HAVE_MEMCMP */ #if ! HAVE_MEMCPY #if HAVE_BCOPY #define memcpy(pto, pfrom, c) bcopy ((pfrom), (pto), (c)) #else /* ! HAVE_BCOPY */ extern pointer memcpy P((pointer pto, constpointer pfrom, size_t c)); #endif /* ! HAVE_BCOPY */ #endif /* ! HAVE_MEMCPY */ #if ! HAVE_MEMCHR extern pointer memchr P((constpointer p, int b, size_t c)); #endif #if ! HAVE_BZERO #if HAVE_MEMSET #define bzero(p, c) memset ((p), 0, (c)) #else /* ! HAVE_MEMSET */ extern void bzero P((pointer p, int c)); #endif /* ! HAVE_MEMSET */ #endif /* ! HAVE_BZERO */ /* Look up a character in a string. */ #if ! HAVE_STRCHR #if HAVE_INDEX #define strchr index extern char *index (); #else /* ! HAVE_INDEX */ extern char *strchr P((const char *z, int b)); #endif /* ! HAVE_INDEX */ #endif /* ! HAVE_STRCHR */ #if ! HAVE_STRRCHR #if HAVE_RINDEX #define strrchr rindex extern char *rindex (); #else /* ! HAVE_RINDEX */ extern char *strrchr P((const char *z, int b)); #endif /* ! HAVE_RINDEX */ #endif /* ! HAVE_STRRCHR */ /* Turn a string into a long integer. */ #if ! HAVE_STRTOL extern long strtol P((const char *, char **, int)); #endif /* Lookup a key in a sorted array. */ #if ! HAVE_BSEARCH extern pointer bsearch P((constpointer pkey, constpointer parray, size_t celes, size_t cbytes, int (*pficmp) P((constpointer, constpointer)))); #endif ense, 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 imuucp-1.04/uucp.texi1006440004150000170000062010405337263526011243 037777777777 1 0 \input texinfo @c -*-texinfo-*- @c %**start of header @setfilename uucp.info @settitle Taylor UUCP @setchapternewpage odd @c %**end of header @iftex @finalout @end iftex @ignore ----------------------------------------------------------------------> Franc,ois Pinard says: Hi, Ian! This is the promised merging of the current documents from Taylor UUCP 1.01, plus the patches to documentation you sent to me, into a taylor.texi file. Many things remain to do, among which: - merging in the Taylor UUCP program man pages. ----------------------------------------------------------------------< @end ignore @ifinfo This file documents Taylor UUCP, version 1.04. Copyright @copyright{} 1992, 1993 Ian Lance Taylor Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. @ignore Permission is granted to process this file through TeX and print the results, provided the printed document carries a copying permission notice identical to this one except for the removal of this paragraph (this paragraph not being relevant to the printed manual). @end ignore Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the section entitled ``Copying'' are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the section entitled ``Copying'' may be included in a translation approved by the author instead of in the original English. @end ifinfo @titlepage @title Taylor UUCP @subtitle Version 1.04 @author Ian Lance Taylor @code{} @page @vskip 0pt plus 1filll Copyright @copyright{} 1992, 1993 Ian Lance Taylor Published by Ian Lance Taylor @code{}. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the section entitled ``Copying'' are included exactly as in the original, and provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that the section entitled ``Copying'' may be included in a translation approved by the author instead of in the original English. @end titlepage @node Top, Copying, (dir), (dir) @top Taylor UUCP 1.04 This is the documentation for the Taylor UUCP package, version 1.04. The programs were written by Ian Lance Taylor. The author can be reached at @code{}, or @samp{c/o Cygnus Support, 4th Floor, Building 200, 1 Kendall Square, Cambridge, MA, 02139}. There is a mailing list for discussion of the package. To join (or get off) the list, send mail to @code{}. Mail to this address is answered by a person, not a program. When joining the list, please give the address at which you wish to receive mail; do not rely on the message headers. To send a message to the list, send it to @code{}. @menu * Copying:: Taylor UUCP copying conditions * Introduction:: Introduction to Taylor UUCP * Overall Installation:: Taylor UUCP installation * Configuration Files:: Taylor UUCP configuration files * Protocols:: UUCP protocol internals * Hacking:: Hacking Taylor UUCP * Acknowledgements:: Acknowledgements * Index (concepts):: Concept index * Index (configuration file):: Index to new configuration files --- The Detailed Node Listing --- Taylor UUCP Overall Installation * Configuration:: Configuring Taylor UUCP * Compilation:: Compiling Taylor UUCP * Testing:: Testing Taylor UUCP * Installation:: Installing Taylor UUCP * TCP:: TCP together with Taylor UUCP Installing Taylor UUCP * Running uucico:: Running uucico * Using UUCP for mail and news:: Using UUCP for mail and news. * Trimming UUCP Log Files:: Trimming UUCP Log Files Using UUCP for mail and news. * Sending mail or news:: Sending mail or news via UUCP * Receiving mail or news:: Receiving mail or news via UUCP Taylor UUCP Configuration Files * Configuration File Format:: Configuration file format * Configuration Examples:: Examples of configuration files * Time Strings:: How to write time strings * Chat Scripts:: How to write chat scripts * config File:: The main configuration file * sys File:: The system configuration file * port File:: The port configuration files * dial File:: The dialer configuration files * Security:: Security issues Examples of Configuration Files * config File Examples:: Examples of the main configuration file * Leaf Example:: Call a single remote site * Gateway Example:: The gateway for several local systems The Main Configuration File * Miscellaneous (config):: Miscellaneous config file commands * Configuration File Names:: Using different configuration files * Log File Names:: Using different log files * Debugging Levels:: Debugging levels The System Configuration File * Defaults and Alternates:: Using defaults and alternates * Naming the System:: Naming the system * Calling Out:: Calling out * Accepting a Call:: Accepting a call * Protocol Selection:: Protocol selection * File Transfer Control:: File transfer control * Miscellaneous (sys):: Miscellaneous sys file commands * Default sys File Values:: Default values Calling Out * When to Call:: When to call * Placing the Call:: Placing the call * Logging In:: Logging in UUCP protocol internals * Grades:: UUCP grades * Lock Files:: UUCP lock file format * UUCP Protocol:: The common UUCP protocol * g Protocol:: The UUCP @samp{g} protocol * f Protocol:: The UUCP @samp{f} protocol * t Protocol:: The UUCP @samp{t} protocol * e Protocol:: The UUCP @samp{e} protocol * x Protocol:: The UUCP @samp{x} protocol * d Protocol:: The UUCP @samp{d} protocol * Capital G Protocol:: The UUCP @samp{G} protocol * Documentation References:: Documentation references The Common UUCP Protocol * Initial Handshake:: Initial handshake * File Requests:: File requests * Final Handshake:: Final handshake File Requests * S Request:: S request * R Request:: R request * X Request:: X request * H Request:: H request Hacking Taylor UUCP * System Dependence:: System Dependence * Naming Conventions:: Naming Conventions * Patches:: Patches @end menu @node Copying, Introduction, Top, Top @unnumbered Taylor UUCP Copying Conditions This package is covered by the GNU Public License. See the file @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. Here is some propaganda from the Free Software Foundation. If you find this stuff offensive or annoying, remember that you probably did not spend any money to get this code. I did not write this code to make life easier for developers of UUCP packages, I wrote it to help end users, and I believe that these are the most appropriate conditions for distribution. All the programs, scripts and documents relating to Taylor UUCP are @dfn{free}; this means that everyone is free to use them and free to redistribute them on a free basis. The Taylor UUCP-related programs are not in the public domain; they are copyrighted and there are restrictions on their distribution, but these restrictions are designed to permit everything that a good cooperating citizen would want to do. What is not allowed is to try to prevent others from further sharing any version of these programs that they might get from you. Specifically, we want to make sure that you have the right to give away copies of the programs that relate to Taylor UUCP, that you receive source code or else can get it if you want it, that you can change these programs or use pieces of them in new free programs, and that you know you can do these things. To make sure that everyone has such rights, we have to forbid you to deprive anyone else of these rights. For example, if you distribute copies of the Taylor UUCP related programs, 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 tell them their rights. Also, for our own protection, we must make certain that everyone finds out that there is no warranty for the programs that relate to Taylor UUCP. If these programs are modified by someone else and passed on, we want their recipients to know that what they have is not what we distributed, so that any problems introduced by others will not reflect on our reputation. The precise conditions of the licenses for the programs currently being distributed that relate to Taylor UUCP are found in the General Public Licenses that accompany them. @node Introduction, Overall Installation, Copying, Top @chapter Introduction to Taylor UUCP General introductions to UUCP are available, and perhaps one day I will write one. In the meantime, here is a very brief one that concentrates on the programs provided by Taylor UUCP. Taylor UUCP is a complete UUCP package. It is covered by the GNU Public License, which means that the source code is always available. It is composed of several programs; most of the names of these programs are based on earlier UUCP packages. @table @code @item uucp The @code{uucp} program is used to copy file between systems. It is similar to the standard Unix @code{cp} program, except that you can refer to a file on a remote system by using @samp{system!} before the file name. For example, to copy the file @file{notes.txt} to the system @samp{airs}, you would say @samp{uucp notes.txt airs!~/notes.txt}. In this example @samp{~} is used to name the UUCP public directory on @samp{airs}. @item uux The @code{uux} program is used to request a program to be executed on a remote system. This is how mail and news are transferred over UUCP. As with @code{uucp}, programs and files on remote systems may be named by using @samp{system!}. For example, to run the @code{rnews} program on @samp{airs} passing it standard input, you would say @samp{uux - airs!rnews}. The @samp{-} means to read standard input and set things up such that when @code{rnews} runs on @samp{airs} it will receive the same standard input. @end table Neither @code{uucp} nor @code{uux} actually do any work immediately. Instead, they queue up requests for later processing. They then start a daemon process which processes the requests and calls up the appropriate systems. Normally the system will also start the daemon periodically to check if there is any work to be done. The advantage of this approach is that it all happens automatically. You don't have to sit around waiting for the files to be transferred. The disadvantage is that if anything goes wrong it might be a while before anybody notices. @table @code @item uustat The @code{uustat} program does many things. By default it will simply list all the jobs you have queued with @code{uucp} or @code{uux} that have not yet been processed. You can use @code{uustat} to remove any of your jobs from the queue. You can also it use it to show the status of the UUCP system in various ways, such as showing the connection status of all the remote systems your system knows about. The system administrator can use @code{uustat} to automatically discard old jobs while sending mail to the user who requested them. @item uuname The @code{uuname} program by default lists all the remote systems your system knows about. You can also use it to get the name of your local system. It is mostly useful for shell scripts. @item uulog The @code{uulog} program can be used to display entries in the UUCP log file. It can select the entries for a particular system or a particular user. You can use it to see what has happened to your queued jobs in the past. @item uuto @item uupick @code{uuto} is a simple shell script interface to @code{uucp}. It will transfer a file, or the contents of a directory, to a remote system, and notify a particular user on the remote system when it arrives. The remote user can then retrieve the file(s) with @code{uupick}. @item cu The @code{cu} program can be used to call up another system and communicate with it as though you were directly connected. It can also do simple file transfers, though it does not provide any error checking. @end table These eight programs just described, @code{uucp}, @code{uux}, @code{uuto}, @code{uupick}, @code{uustat}, @code{uuname}, @code{uulog}, and @code{cu} are the user programs provided by Taylor UUCP@. @code{uucp}, @code{uux}, and @code{uuto} add requests to the work queue, @code{uupick} extracts files from the UUCP public directory, @code{uustat} examines the work queue, @code{uuname} examines the configuration files, @code{uulog} examines the log files, and @code{cu} just uses the UUCP configuration files. The real work is actually done by two daemon processes, which are normally run automatically rather than by a user. @table @code @item uucico The @code{uucico} daemon is the program which actually calls the remote system and transfers files and requests. @code{uucico} is normally started automatically by @code{uucp} and @code{uux}. Most systems will also start it periodically to make sure that all work requests are handled. @code{uucico} checks the queue to see what work needs to be done, and then calls the appropriate systems. If the call fails, perhaps because the phone line is busy, @code{uucico} leaves the requests in the queue and goes on to the next system to call. It is also possible to force @code{uucico} to call a remote system even if there is no work to be done for it, so that it can pick up any work that may be queued up remotely. @item uuxqt The @code{uuxqt} daemon processes execution requests made by the @code{uux} program on remote systems. It also processes requests made on the local system which require files from a remote system. It is normally started by @code{uucico}. @end table Suppose you, on the system @samp{bantam}, want to copy a file to the system @samp{airs}. You would run the @code{uucp} command locally, with a command like @samp{uucp notes.txt airs!~/notes.txt}. This would queue up a request on @samp{bantam} for @samp{airs}, and would then start the @code{uucico} daemon. @code{uucico} would see that there was a request for @samp{airs} and attempt to call it. When the call succeeded, another copy of @code{uucico} would be started on @samp{airs}. The two copies of @code{uucico} would tell each other what they had to do and transfer the file from @samp{bantam} to @samp{airs}. When the file transfer was complete the @code{uucico} on @samp{airs} would move it into the UUCP public directory. UUCP is often used to transfer mail. This is normally done automatically by mailer programs. When @samp{bantam} has a mail message to send to @samp{ian} at @samp{airs}, it executes @samp{uux - airs!rmail ian} and writes the mail message to the @code{uux} process as standard input. The @code{uux} program, running on @samp{bantam}, will read the standard input and store it, as well as the @code{rmail} request itself, on the work queue for @samp{airs}. @code{uux} will then start the @code{uucico} daemon. The @code{uucico} daemon will call up @samp{airs}, just as in the @code{uucp} example, and transfer the work request and the mail message. The @code{uucico} daemon on @samp{airs} will put the files on a local work queue. When the communication session is over, the @code{uucico} daemon on @samp{airs} will start the @code{uuxqt} daemon. @code{uuxqt} will see the request to run, and will run @samp{rmail ian} with the mail message as standard input. The @code{rmail} program, which is not part of the UUCP package, is then responsible for either putting the message in the right mailbox on @samp{airs} or forwarding the message on to another system. Taylor UUCP comes with a few other programs that are useful when installing and configuring UUCP. @table @code @item uuchk The @code{uuchk} program reads the UUCP configuration files and displays a rather lengthy description of what it finds. This is useful when configuring UUCP to make certain that the UUCP package will do what you expect it to do. @item uuconv The @code{uuconv} program can be used to convert UUCP configuration files from one support format to another. This can be useful for administrators converting from an older UUCP. Taylor UUCP is able to read and use old configuration file formats, but some new features can not be selected using the old formats. @item uusched The @code{uusched} script is just provided for compatibility with older UUCP releases. It starts @code{uucico} to call, one at a time, all the systems for which work has been queued. @item tstuu The @code{tstuu} program is a test harness for the UUCP package, which will help ensure that it has been configured and compiled correctly. It does not test everything, however. It only runs on Unix systems which support Berkeley style pseudo-terminals or STREAMS style pseudo-terminals. It can be useful when initially installing Taylor UUCP. @end table @node Overall Installation, Configuration Files, Introduction, Top @chapter Taylor UUCP Overall Installation These are the installation instructions for the Taylor UUCP package. @menu * Configuration:: Configuring Taylor UUCP * Compilation:: Compiling Taylor UUCP * Testing:: Testing Taylor UUCP * Installation:: Installing Taylor UUCP * TCP:: TCP together with Taylor UUCP @end menu @node Configuration, Compilation, Overall Installation, Overall Installation @section Configuring Taylor UUCP You will have to decide what types of configuration files you want to use. This package supports a new sort of configuration file; see @ref{Configuration Files}. It also supports V2 configuration files (@file{L.sys}, @file{L-devices}, etc.) and HDB configuration files (@file{Systems}, @file{Devices}, etc.). No documentation is provided for V2 or HDB configuration files. All types of configuration files can be used at once, if you are so inclined. Currently using just V2 configuration files is not really possible, because there is no way to specify a dialer (there are no built in dialers, and the program does not know how to read @file{acucap} or @file{modemcap}); however, V2 configuration files can be used with a new style dialer file (@pxref{dial File}), or with a HDB @file{Dialers} file. Use of HDB configuration files has two known bugs. A blank line in the middle of an entry in the @file{Permissions} file will not be ignored as it should be. Dialer programs, as found in some versions of HDB, are not recognized directly. If you must use a dialer program, rather than an entry in @file{Devices}, you must use the @code{chat-program} command in a new style dialer file; see @ref{dial File}. You will have to invoke the dialer program via a shell script, since an exit code of 0 is required to recognize success. The @code{uuconv} program can be used to convert from V2 or HDB configuration files to the new style (it can also do the reverse translation, if you are so inclined). It will not do all of the work, and the results should be carefully checked, but it can be quite useful. If you are installing a new system, you will, of course, have to write the configuration files; see @ref{Configuration Files}. You must also decide what sort of spool directory you want to use. If you will only be using these programs, I recommend @samp{SPOOLDIR_TAYLOR}; otherwise select the spool directory corresponding to your existing UUCP package. The details of the spool directory choices are described at somewhat tedious length in @file{unix/spool.c}. @node Compilation, Testing, Configuration, Overall Installation @section Compiling Taylor UUCP @enumerate @item Take a look at the top of @file{Makefile.in} and set the appropriate values for your system. These control where the programs are installed and which user on the system owns them (normally they will be owned by a special user @code{uucp} rather than a real person; they should probably not be owned by @code{root}). @item Run the shell script @code{configure}. This script was generated using the @code{autoconf} program written by David MacKenzie of the Free Software Foundation. It takes a while to run. It will generate the file @file{conf.h} based on @file{conf.h.in}, and, for each source code directory, will generate @file{Makefile} based on @file{Makefile.in}. You can pass certain arguments to @code{configure} in the environment. Because @code{configure} will compile little test programs to see what is available on your system, you must tell it how to run your compiler. It recognizes the following environment variables: @table @samp @item CC The C compiler. If this is not set, then if @code{configure} can find @samp{gcc} it will use it, otherwise it will use @samp{cc}. @item CFLAGS Flags to pass to the C compiler when compiling the actual code. If this is not set, @code{configure} will use @samp{-g}. @item LDFLAGS Flags to pass to the C compiler when only linking, not compiling. If this is not set, @code{configure} will use the empty string. @item LIBS Libraries to pass to the C compiler. If this is not set, @code{configure} will use the empty string. @item INSTALL The program to run to install UUCP in the binary directory. If this is not set, then if @code{configure} finds the BSD @code{install} program, it will set this to @samp{install -c}; otherwise, it will use @samp{cp}. @item INSTALLDATA The program to run to install UUCP data files, such as the man pages and the info pages. If this is not set, then if @code{configure} finds the BSD @code{install} program, it will set this to @samp{install -c -m 644}; otherwise, it will use @samp{cp}. @end table Suppose you want to set the environment variable @samp{CC} to @samp{rcc}. If you are using @code{sh} or @code{bash}, invoke @code{configure} as @samp{CC=rcc configure}. If you are using @code{csh}, do @samp{setenv CC rcc; sh configure}. On some systems you will want to use @samp{LIBS=-lmalloc}. On Xenix derived versions of Unix do not use @samp{LIBS=-lx} because this will bring in the wrong versions of certain routines; if you want to use @samp{-lx} you must specify @samp{LIBS=-lc -lx}. If @code{configure} fails for some reason, or if you have a very wierd system, you may have to configure the package by hand. To do this, copy the file @file{conf.h.in} to @file{conf.h} and edit it for your system. Then for each source directory (the top directory, and the subdirectories @file{lib}, @file{unix}, and @file{uuconf}) copy @file{Makefile.in} to @file{Makefile}, find the words within @kbd{@@} characters, and set them correctly for your system. @item Igor V. Semenyuk provided this (lightly edited) note about ISC Unix 3.0. The @code{configure} script will default to passing @samp{-posix} to @code{gcc}. However, using @samp{-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 @file{mailertable.@{dir,pag@}}. Notice these names are 15 characters long. When uuxqt compiled with @samp{-posix} executes rmail, which in turn executes sendmail, the later is run under POSIX environment too! This leads to sendmail bombing out with @samp{'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 @samp{-posix}, instead I run @code{gcc} with @samp{-D_POSIX_SOURCE}, and add @samp{-lcposix} to @samp{LIBS}. @item You should verify that @code{configure} worked correctly by checking @file{conf.h} and the instances of @file{Makefile}. @item Edit @file{policy.h} for your local system. The comments should explain the various choices. The default values are intended to be reasonable, so you may not have to make any changes. @item Type @samp{make} to compile everything. The @file{tstuu.c} file is not particularly portable; if you can't figure out how to compile it you can safely ignore it, as it is only used for testing (to use STREAMS pseudo-terminals, tstuu.c must be compiled with @samp{-DHAVE_STREAMS_PTYS}; this is not automatically determined at the moment). If you have any other problems there is probably a bug in the @code{configure} script. @item Please report any problems you have. That is the only way they will get fixed for other people. Supply a patch if you can (@pxref{Patches}), or just ask for help. @end enumerate @node Testing, Installation, Compilation, Overall Installation @section Testing Taylor UUCP This package is in use at many sites, and has been running at @file{airs.com} for over a year. However, it will doubtless fail in some situations. Do not rely on this code until you have proven to yourself that it will work. You can use the @code{uuchk} program to test your configuration files. It will read them and print out a verbose description. This program should not be made setuid, because it will display passwords if it can read them. If your system supports pseudo-terminals, and you compiled the code to support the new style of configuration files, you should be able to use the @code{tstuu} program to test the @code{uucico} daemon (if your system supports STREAMS based pseudo-terminals, you must compile tstuu.c with @samp{-DHAVE_STREAMS_PTYS}, at least at the moment; the STREAMS based code was contributed by Marc Boucher). To run @code{tstuu}, just type @samp{tstuu} with no arguments while logged in to the compilation directory (since it runs @file{./uucp}, @file{./uux} and @file{./uucico}). It will run a lengthy series of tests (it takes over ten minutes on a slow VAX). You will need a fair amount of space available in @file{/usr/tmp}. You will probably want to put it in the background. Do not use @kbd{^Z}, because the program traps on @code{SIGCHLD} and winds up dying. It will create a directory @file{/usr/tmp/tstuu} and fill it with configuration files, and create spool directories @file{/usr/tmp/tstuu/spool1} and @file{/usr/tmp/tstuu/spool2}. If your system does not support the @code{FIONREAD} call, the @samp{tstuu} program will run very slowly. This may or may not get fixed in a later version. The @samp{tstuu} program does not seem to work under SunOS 4.1.1. This seems to be due to a bug in the implementation of ptys. The program will finish with an execute file named @file{X.@var{something}} and a data file named @file{D.@var{something}} in the directory @file{/usr/tmp/tstuu/spool1} (or, more likely, in subdirectories, depending on the choice of @code{SPOOLDIR} in @file{policy.h}). Two log files will be created in the directory @file{/usr/tmp/tstuu}. They will be named @file{Log1} and @file{Log2}, or, if you have selected @code{HAVE_HDB_LOGGING} in @file{policy.h}, @file{Log1/uucico/test2} and @file{Log2/uucico/test1}. You can test @code{uuxqt} by running the command @samp{./uuxqt -I /usr/tmp/tstuu/Config1}. This should leave a command file @file{C.@var{something}} and a data file @file{D.@var{something}} in @file{/usr/tmp/tstuu/spool1} or in subdirectories. Again, there should be no errors in the log file. Assuming you compiled the code with debugging enabled, the @samp{-x} switch can be used to set debugging modes; see the @code{debug} command for details (@pxref{Debugging Levels}). Use @samp{-x all} to turn on all debugging and generate far more output than you will ever want to see. The @code{uucico} daemons will put debugging output in the files @file{Debug1} and @file{Debug2} in the directory @file{/usr/tmp/tstuu}. After that, you're pretty much on your own. On some systems you can also use @code{tstuu} to test @code{uucico} against the system @code{uucico}, by using the @samp{-u} switch. For this to work, change the definitions of @code{ZUUCICO_CMD} and @code{UUCICO_EXECL} at the top of @file{tstuu.c} to something appropriate for your system. The definitions in @file{tstuu.c} are what I used for Ultrix 4.0, on which @file{/usr/lib/uucp/uucico} is particularly obstinate about being run as a child; I was only able to run it by creating a login name with no password whose shell was @file{/usr/lib/uucp/uucico}. Calling login in this way will leave fake entries in @file{wtmp} and @file{utmp}; if you compile @file{tstout.c} (in the @file{contrib} directory) as a setuid @code{root} program, @code{tstuu} will run it to clear those entries out. On most systems, such hackery should not be necessary, although on SCO I had to su to @code{root} (@code{uucp} might also have worked) before I could run @file{/usr/lib/uucp/uucico}. You can test @code{uucp} and @code{uux} (give them the @samp{-r} switch to keep them from starting @code{uucico}) to make sure they create the right sorts of files. Unfortunately, if you don't know what the right sorts of files are, I'm not going to tell you here. If @code{tstuu} passes, or you can't run it for some reason or other, move on to testing with some other system. Set up the configuration files (@pxref{Configuration Files}), or use an existing configuration. Tell @code{uucico} to dial out to the system by using the @samp{-s} system switch (e.g. @samp{uucico -s uunet}). The log file should tell you what happens. If you compiled the code with debugging enabled, you can use debugging mode to get a great deal of information about what sort of data is flowing back and forth; the various possibilities are described under the @code{debug} command (@pxref{Debugging Levels}). When initially setting up a connection @samp{-x chat} is probably the most useful (e.g. @samp{uucico -s uunet -x chat}); you may also want to use @samp{-x handshake,incoming,outgoing}. You can use @samp{-x} multiple times on one command line, or you can give it comma separated arguments as in the last example. Use @samp{-x all} to turn on all possible debugging information. The debugging information is written to a file, normally @file{/usr/spool/uucp/Debug}, although the default can be changed in @file{policy.h} and the configuration file can override the name with the @code{debugfile} command. The debugging file may contain passwords and some file contents as they are transmitted over the line, so the debugging file is only readable by the @code{uucp} user. You can use the @samp{-f} switch to force @code{uucico} to call out even if the last call failed recently; using @samp{-S} when naming a system has the same effect. Otherwise the status file (in the @file{.Status} subdirectory of the main spool directory, normally @file{/usr/spool/uucp}) will prevent too many attempts from occurring in rapid succession. Again, please let me know about any problems you have and how you got around them. If you do report a problem, please include the version number of the package you are using, and a sample of the debugging file showing the problem. General questions such as ``why doesn't uucico dial out'' are impossible to answer without much more information. @node Installation, TCP, Testing, Overall Installation @section Installing Taylor UUCP You can install the executable files by becoming @code{root} and typing @samp{make install}. Or you can look at what @samp{make install} does and do it by hand. It tries to preserve your old programs, if any, but it only does this the first time Taylor UUCP is installed (so that if you install several versions of Taylor UUCP, you can still go back to your original UUCP programs). You can retrieve the original programs by typing @samp{make uninstall}. Simply installing the executable files is not enough, however. You must also arrange for them to be used correctly. @menu * Running uucico:: Running uucico * Using UUCP for mail and news:: Using UUCP for mail and news. * Trimming UUCP Log Files:: Trimming UUCP Log Files @end menu @node Running uucico, Using UUCP for mail and news, Installation, Installation @subsection Running uucico By default @code{uucp} and @code{uux} will automatically start up @code{uucico} to call another system whenever work is queued up. However, the call may fail, or there may be time restrictions which prevent the call at that time (perhaps because telephone rates are high) (@pxref{When to Call}). Also, a remote system may have work queued up for your system, but may not be calling you for some reason (perhaps you have agreed that your system should always place the call). To make sure that works get transferred between the systems withing a reasonable time period, you should arrange to periodically invoke @code{uucico}. These periodic invocations are normally caused by entries in the @file{crontab} file. The exact format of @file{crontab} files, and how new entries are added, varies from system to system; check your local documentation (try @samp{man cron}). To attempt to call all systems with outstanding work, use the command @samp{uucico -r1}. To attempt to call a particular system, use the command @samp{uucico -s SYSTEM}. A common case is to want to try to call a system at a certain time, with periodic retries if the call fails. A simple way to do this is to create an UUCP command file, known as a @dfn{poll file}. If a poll file exists for a system, then @samp{uucico -r1} will place a call to it. If the call succeeds, the poll file will be deleted. The file can be easily created using the @samp{touch} command. The name of a poll file currently depends on the type of spool directory you are using, as set in @file{policy.h}. If you are using @code{SPOOLDIR_TAYLOR} (the default), put something like this in your @file{crontab} file: @example touch /usr/spool/uucp/@var{sys}/C./C.A0000 @end example In this example @var{sys} is the system you wish to call, and @samp{/usr/spool/uucp} is your UUCP spool directory. If you are using @code{SPOOLDIR_HDB}, use @example touch /usr/spool/uucp/@var{sys}/C.@var{sys}A0000 @end example For example, I use the following crontab entries locally: @example 45 * * * * /bin/echo /usr/lib/uucp/uucico -r1 | /bin/su uucpa 40 4,10,15 * * * touch /usr/spool/uucp/uunet/C./C.A0000 @end example Every hour, at 45 minutes past, this will check if there is any work to be done, and, if there is, will call the appropriate system. Also, at 4:40am, 10:40am and 3:40pm this will create a poll file file for @samp{uunet}, forcing the next check to call @samp{uunet}. @node Using UUCP for mail and news, Trimming UUCP Log Files, Running uucico, Installation @subsection Using UUCP for mail and news. Taylor UUCP does not include a mail package. All Unix systems come with some sort of mail delivery agent, typically @code{sendmail} or @code{MMDF}. Source code is available for some mail delivery agents, such as @code{IDA sendmail} and @code{smail}. Taylor UUCP also does not include a news package. The two major Unix news packages are @code{C-news} and @code{INN}. Both are available in source code form. Configuring and using mail delivery agents is a notoriously complex topic, and I will not be discussing it here. Configuring news systems is usually simpler, but I will not be discussing that either. I will merely describe the interactions between the mail and news systems and UUCP. A mail or news system interacts with UUCP in two ways. @menu * Sending mail or news:: Sending mail or news via UUCP * Receiving mail or news:: Receiving mail or news via UUCP @end menu @node Sending mail or news, Receiving mail or news, Using UUCP for mail and news, Using UUCP for mail and news @unnumberedsubsubsec Sending mail or news via UUCP When mail is to be sent from your machine to another machine via UUCP, the mail delivery agent will invoke @code{uux}. It will generally run a command such as @samp{uux - @var{system}!rmail}, where @var{system} is the remote system to which the mail is being sent. It may pass other options to @code{uux}, such as @samp{-r} or @samp{-g}. News also invokes @code{uux} in order to transfer articles to another system. The only difference is that news will use @code{uux} to invoke @code{rnews} on the remote system, rather than @code{rmail}. You should arrange for your mail and news systems to invoke the Taylor UUCP version of @code{uux} when sending mail via UUCP. If you simply replace any existing version of @code{uux} with the Taylor UUCP version, this will probably happen automatically. However, if both versions exist on your system, you will probably have to modify the mail and news configuration files in some way. Actually, if both the system UUCP and Taylor UUCP are using the same spool directory format, the system @code{uux} will probably work fine with the Taylor @code{uucico} (the reverse is not the case: the Taylor @code{uux} requires the Taylor @code{uucico}). However, data transfer will be somewhat more efficient if the Taylor @code{uux} is used. @node Receiving mail or news, , Sending mail or news, Using UUCP for mail and news @unnumberedsubsubsec Receiving mail or news via UUCP As noted in @ref{Sending mail or news}, mail is sent by requesting a remote execution of @code{rmail}. To receive mail, then, all that is necessary is for UUCP to invoke @code{rmail} itself. Any mail delivery agent will provide an appropriate version of @code{rmail}; you must simply make sure that it is in the command path used by UUCP (it almost certainly already is). The default command path is set in @file{policy.h}, and it may be overridden for a particular system by the @code{command-path} command (@pxref{Miscellaneous (sys)}). Similarly, for news UUCP must be able to invoke @code{rnews}. Any news system will provide a version of @code{rnews}, and you must ensure that is in a directory on the path that UUCP will search. @node Trimming UUCP Log Files, , Using UUCP for mail and news, Installation @subsection Trimming UUCP Log Files You should also periodically trim the log files, as they will otherwise continue to grow without limit. The names of the log files are set in @file{policy.h}, and may be overridden in the configuration file (@pxref{config File}). By default they are are @file{/usr/spool/uucp/Log} and @file{/usr/spool/uucp/Stats}. You may find the @code{savelog} program in the @file{contrib} directory may be of use. There is a manual page for it in @file{contrib} as well. @node TCP, , Installation, Overall Installation @section TCP together with Taylor UUCP If your system has a Berkeley style socket library, or a System V style TLI interface library, you can compile the code to permit making connections over TCP. Specifying that a system should be reached via TCP is easy, but nonobvious. If you are using the new style configuration files, see @ref{Configuration Files}. Basically, you can just add the line @samp{port type tcp} to the entry in the system configuration file. By default UUCP will get the port number by looking up @samp{uucp} in @file{/etc/services}; if @samp{uucp} is not found, port 540 will be used. You can set the port number to use with the command @samp{port service @var{xxx}}, where @var{xxx} can be either a number or a name to look up in @file{/etc/services}. You can specify the address of the remote host with @samp{address @var{a.b.c}}; if you don't give an address, the remote system name will be used. You should give an explicit chat script for the system when you use TCP; the default chat script begins with a carriage return, which will not work with some UUCP TCP servers. If you are using V2 configuration files, add a line like this to @file{L.sys}: @example @var{sys} Any TCP uucp @var{host}.@var{domain} chat-script @end example This will make an entry for system @var{sys}, to be called at any time, over TCP, using port number @samp{uucp} (as found in @file{/etc/services}; this may be specified as a number), using remote host @file{@var{host}.@var{domain}}, with some chat script. If you are using HDB configuration files, add a line like this to Systems: @example @var{sys} Any TCP - @var{host}.@var{domain} chat-script @end example and a line like this to Devices: @example TCP uucp - - @end example You only need one line in Devices regardless of how many systems you contact over TCP. This will make an entry for system @var{sys}, to be called at any time, over TCP, using port number @samp{uucp} (as found in @file{/etc/services}; this may be specified as a number), using remote host @file{@var{host}.@var{domain}}, with some chat script. The @code{uucico} daemon can also be run as a TCP server. To use the default port number, which is a reserved port, @code{uucico} must be invoked by root (or it must be set user ID to root, but I don't recommend doing that). Basically, you must define a port, either using the port file (@pxref{port File}) if you are using the new configuration method or with an entry in Devices if you are using HDB; there is no way to define a port using V2. If you are using HDB the port must be named @samp{TCP}; a line as shown above will suffice. You can then start @code{uucico} as @samp{uucico -p TCP} (after the @samp{-p}, name the port; in HDB it must be @samp{TCP}). This will wait for incoming connections, and fork off a child for each one. Each connection will be prompted with @samp{login:} and @samp{Password:}; the results will be checked against the UUCP (not the system) password file (@pxref{Configuration File Names}). Of course, you can get a similar effect by using the BSD @code{uucpd} program. You can also have @code{inetd} start up @code{uucico} with the @samp{-l} switch, which will cause it to prompt with @samp{login:} and @samp{Password:} and check the results against the UUCP (not the system) password file. This may be used in place of @code{uucpd}. @node Configuration Files, Protocols, Overall Installation, Top @chapter Taylor UUCP Configuration Files This chapter describes the configuration files accepted by the Taylor UUCP package if compiled with @code{HAVE_TAYLOR_CONFIG} defined in @file{policy.h}. The configuration files are normally found in the directory @var{newconfigdir}, which is defined by the @file{Makefile} variable @file{newconfigdir}; by default @var{newconfigdir} is @file{/usr/local/conf/uucp}. However, the main configuration file, @file{config}, is the only one which must be in that directory, since it may specify a different location for any or all of the other files. You may run any of the UUCP programs with a different main configuration file by using the @samp{-I} option; this can be useful when testing a new configuration. When you use the @samp{-I} option the programs will revoke any setuid privileges. @menu * Configuration File Format:: Configuration file format * Configuration Examples:: Examples of configuration files * Time Strings:: How to write time strings * Chat Scripts:: How to write chat scripts * config File:: The main configuration file * sys File:: The system configuration file * port File:: The port configuration files * dial File:: The dialer configuration files * Security:: Security issues @end menu @node Configuration File Format, Configuration Examples, Configuration Files, Configuration Files @section Configuration File Format All the configuration files follow a simple line-oriented @samp{@var{keyword} @var{value}} format. Empty lines are ignored, as are leading spaces; unlike HDB, lines with leading spaces are read. The first word on each line is a keyword. The rest of the line is interpreted according to the keyword. Most keywords are followed by numbers, boolean values or simple strings with no embedded spaces. The @kbd{#} character is used for comments. Everything from a @kbd{#} to the end of the line is ignored unless the @kbd{#} is preceded by a @kbd{\} (backslash); if the @kbd{#} is preceeded by a @kbd{\}, the @kbd{\} is removed but the @kbd{#} remains in the line. This can be useful for a phone number containing a @kbd{#}. To enter the sequence @samp{\#}, use @samp{\\#}. The backslash character may be used to continue lines. If the last character in a line is a backslash, the backslash is removed and the line is continued by the next line. The second line is attached to the first with no intervening characters; if you want any whitespace between the end of the first line and the start of the second line, you must insert it yourself. However, the backslash is not a general quoting character. For example, you cannot use it to get an embedded space in a string argument. Everything after the keyword must be on the same line. A @var{boolean} may be specified as @kbd{y}, @kbd{Y}, @kbd{t}, or @kbd{T} for true and @kbd{n}, @kbd{N}, @kbd{f}, or @kbd{F} for false; any trailing characters are ignored, so @code{true}, @code{false}, etc., are also acceptable. @node Configuration Examples, Time Strings, Configuration File Format, Configuration Files @section Examples of Configuration Files All the configuration commands are explained in the following sections. However, I'll start by giving a few examples of configuration files. For a more complete description of any of the commands used here see the appropriate section of this chapter. There are also sample configuration files in the @file{sample} subdirectory of the distribution. @menu * config File Examples:: Examples of the main configuration file * Leaf Example:: Call a single remote site * Gateway Example:: The gateway for several local systems @end menu @node config File Examples, Leaf Example, Configuration Examples, Configuration Examples @subsection config File Examples @cindex config file examples To start with, here are some examples of uses of the main configuration file, @file{config}. For a complete description of the commands that are permitted in @file{config}, see @ref{config File}. In many cases you will not need to create a @file{config} file at all. The most common reason to create one is to give your machine a special UUCP name. Other reasons might be to change the UUCP spool directory or to permit any remote system to call in. If you have an internal network of machines, then it is likely that the internal name of your UUCP machine is not the name you want to use when calling other systems. For example, here at @file{airs.com} our mail/news gateway machine is named @file{elmer.airs.com} (it is one of several machines all named @file{@var{localname}.airs.com}). If we did not provide a @file{config} file, then our UUCP name would be @file{elmer}; however, we actually want it to be @file{airs}. Therefore, we use the following line in @file{config}: @example nodename airs @end example @cindex changing spool directory @cindex spool directory (changing) The UUCP spool directory name is set in @file{policy.h} when the code is compiled. You might at some point decide that it is appropriate to move the spool directory, perhaps to put it on a different disk partition. You would use the following commands in @file{config} to change to directories on the partition @file{/uucp}: @example spool /uucp/spool pubdir /uucp/uucppublic logfile /uucp/spool/Log debugfile /uucp/spool/Debug @end example You would then move the contents of the current spool directory to @file{/uucp/spool}. If you do this, make sure that no UUCP processes are running while you change @file{config} and move the spool directory. @cindex anonymous UUCP Suppose you wanted to permit any system to call in to your system and request files. This is generally known as @dfn{anonymous UUCP}, since the systems which call in are effectively anonymous. By default, unknown systems are not permitted to call in. To permit this you must use the @code{unknown} command in @file{config}. The @code{unknown} command is followed by any command that may appear in the system file; for full details, see @ref{sys File}. I will show two possible anonymous UUCP configurations. The first will let any system call in and download files, but will not permit them to upload files to your system. @example # No files may be transferred to this system unknown receive-request no # The public directory is /usr/spool/anonymous unknown pubdir /usr/spool/anonymous # Only files in the public directory may be sent (the default anyhow) unknown remote-send ~ @end example @noindent Setting the public directory is convenient for the systems which call in. It permits to request a file by prefixing it with @file{~/}. For example, assuming your system is known as @samp{server}, then to retrieve the file @file{/usr/spool/anonymous/INDEX} a user on a remote site could just enter @samp{uucp server!~/INDEX ~}; this would transfer @file{INDEX} from @samp{server}'s public directory to the user's local public directory. Note that when using @samp{csh} or @samp{bash} the @kbd{!} and the second @kbd{~} must be quoted. The next example will permit remote systems to upload files to a special directory named @file{/usr/spool/anonymous/upload}. Permitting a remote system to upload files permits it to send work requests as well; this example is careful to prohibit commands from unknown systems. @example # 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 @end example @node Leaf Example, Gateway Example, config File Examples, Configuration Examples @subsection Leaf Example @cindex leaf site @cindex sys file example (leaf) A relatively common simple case is a @dfn{leaf site}, a system which only calls or is called by a single remote site. Here is a typical @file{sys} file that might be used in such a case. For full details on what commands can appear in the @file{sys} file, see @ref{sys File}. This is the @file{sys} file that is used at @file{airs.com}. We use a single modem to dial out to @file{uunet}. This example shows how you can specify the port and dialer information directly in the @file{sys} file for simple cases. It also shows the use of the following: @table @code @item call-login Using @code{call-login} and @code{call-password} allows the default login chat script to be used. In this case, the login name is specified in the call-out login file (@pxref{Configuration File Names}). @item call-timegrade @file{uunet} is requested to not send us news during the daytime. @item chat-fail If the modem returns @samp{BUSY} or @samp{NO CARRIER} the call is immediately aborted. @item protocol-parameter Since @file{uunet} tends to be slow, the default timeout has been increased. @end table This @file{sys} file relies on certain defaults. It will allow @file{uunet} to queue up @samp{rmail} and @samp{rnews} commands. It will allow users to request files from @file{uunet} into the UUCP public directory. It will also @file{uunet} to request files from the UUCP public directory; in fact @file{uunet} never requests files, but for additional security we could add the line @samp{request false}. @example # The following information is for uunet system uunet # The login name and password are kept in the callout password file 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. phone 7389449 # uunet tends to be slow, so we increase the timeout chat-timeout 120 # We are using a preconfigured Telebit 2500. port type modem port device /dev/ttyd0 port baud 19200 port carrier true port dialer chat "" ATZ\r\d\c OK ATDT\D CONNECT port dialer chat-fail BUSY port dialer chat-fail NO\sCARRIER port dialer complete \d\d+++\d\dATH\r\c port dialer abort \d\d+++\d\dATH\r\c # Increase the timeout and the number of retries. protocol-parameter g timeout 20 protocol-parameter g retries 10 @end example @node Gateway Example, , Leaf Example, Configuration Examples @subsection Gateway Example @cindex gateway @cindex sys file example (gateway) Many organizations have several local machines which are connected by UUCP, and a single machine which connects to the outside world. This single machine is often referred to as a @dfn{gateway} machine. For this example I will assume a fairly simple case. It should still provide a good general example. There are three machines, @file{elmer}, @file{comton} and @file{bugs}. @file{elmer} is the gateway machine for which I will show the configuration file. @file{elmer} calls out to @file{uupsi}. As an additional complication, @file{uupsi} knows @file{elmer} as @file{airs}; this will show how a machine can have one name on an internal network but a different name to the external world. @file{elmer} has two modems. It also has an TCP/IP connection to @file{uupsi}, but since that is supposed to be reserved for interactive work (it is, perhaps, only a 9600 baud SLIP line) it will only use it if the modems are not available. A network this small would normally use a single @file{sys} file. However, for pedagogical purposes I will show two separate @file{sys} files, one for the local systems and one for @file{uupsi}. This is done with the @code{sysfile} command in the @file{config} file. Here is the @file{config} file. @example # This is config # The local sys file sysfile /usr/local/lib/uucp/sys.local # The remote sys file sysfile /usr/local/lib/uucp/sys.remote @end example Using the defaults feature of the @file{sys} file can greatly simplify the listing of local systems. Here is @file{sys.local}. Note that this assumes that the local systems are trusted; they are permited to request any world readable file and to write files into any world writable directory. @example # This is sys.local # Get the login name and password to use from the call-out file call-login * call-password * # The systems must use a particular login called-login Ulocal # Permit sending any world readable file local-send / remote-send / # Permit requesting into any world writable directory local-receive / remote-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 @end example The @file{sys.remote} file describes the @file{uupsi} connection. The @code{myname} command is used to change the UUCP name to @file{airs} when talking to @file{uupsi}. @example # This is sys.remote # Define uupsi system uupsi # The login name and password are in the call-out file call-login * call-password * # We can call out at any time time any # uupsi uses a special login name called-login Uuupsi # uuspi thinks of us as `airs' myname airs # The phone number phone 5554848 # We use port2 first, then port1, then TCP port port2 alternate port port1 alternate # We don't bother to make a special entry in the port file for TCP, we # just describe the entire port right here. We use a special chat # script over TCP because the usual one confuses some TCP servers. port type TCP address uu.psi.com chat ogin: \L word: \P @end example The ports are defined in the file @file{port} (@pxref{port File}). For this example they are both connected to the same type of 2400 baud Hayes-compatible modem. @example # This is port port port1 type modem device /dev/ttyd0 dialer hayes speed 2400 port port2 type modem device /dev/ttyd1 dialer hayes speed 2400 @end example Dialers are described in the @file{dial} file (@pxref{dial File}). @example # This is dial dialer hayes # The chat script used to dial the phone. \D is the phone number. chat "" ATZ\r\d\c OK ATDT\D CONNECT # If we get BUSY or NO CARRIER 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 @end example @node Time Strings, Chat Scripts, Configuration Examples, Configuration Files @section Time Strings @cindex time strings Several commands use time strings to specify a range of times. This section describes how to write time strings. A time string may be a list of simple time strings separated with a vertical bar @kbd{|} or a comma @kbd{,}. Each simple time string must begin with @samp{Su}, @samp{Mo}, @samp{Tu}, @samp{We}, @samp{Th}, @samp{Fr}, or @samp{Sa}, or @samp{Wk} for any weekday, or @samp{Any} for any day. Following the day may be a range of hours separated with a hyphen using 24 hour time. The range of hours may cross 0; for example @samp{2300-0700} means any time except 7 AM to 11 PM. If no time is given, calls may be made at any time on the specified day(s). The time string may also consist of the single word @samp{Never}, which does not match any time, or a single word with a name defined in a previous @code{timetable} command (@pxref{Miscellaneous (config)}). Here are a few sample time strings with an explanation of what they mean. @table @samp @item Wk2305-0855,Sa,Su2305-1655 This means weekdays before 8:55 AM or after 11:05 PM, any time Saturday, or Sunday before 4:55 PM or after 11:05 PM. These are approximately the times during which night rates apply to phone calls in the U.S.A. Note that this time string uses, for example, @samp{2305} rather than @samp{2300}; this will ensure a cheap rate phone call even if the computer clock is running up to five minutes ahead of the real time. @item Wk0905-2255,Su1705-2255 This means weekdays from 9:05 AM to 10:55 PM, or Sunday from 5:05 PM to 10:55 PM. This is approximately the opposite of the previous example. @item Any This means any day. Since no time is specified, it means any time on any day. @end table @node Chat Scripts, config File, Time Strings, Configuration Files @section Chat Scripts @cindex chat scripts Chat scripts are used in several different places, such as dialing out on modems or logging in to remote systems. Chat scripts are made up of pairs of strings. The program waits until it sees the first string, known as the @dfn{expect} string, and then sends out the second string, the @dfn{send} string. Each chat script is defined using a set of commands. These commands always end in a string beginning with @code{chat}, but may start with different strings. For example, in the @file{sys} file there is one set of commands beginning with @code{chat} and another set beginning with @code{called-chat}. The prefixes are only used to disambiguate different types of chat scripts, and this section ignores the prefixes when describing the commands. @table @code @item chat @var{strings} @findex chat Specify a chat script. The arguments to the @code{chat} command are pairs of strings separated by whitespace. The first string of each pair is an expect string, the second is a send string. The program will wait for the expect string to appear; when it does, the program will send the send string. If the expect string does not appear within a certain number of seconds (as set by the @code{chat-timeout} command) the chat script fails and, typically, the call is aborted. If the final expect string is seen (and the optional final send string has been sent), the chat script is successful. An expect string may contain additional subsend and subexpect strings, separated by hyphens. If the expect string is not seen, the subsend string is sent and the chat script continues by waiting for the subexpect string. This means that a hyphen may not appear in an expect string; on an ASCII system, use @samp{\055} instead. An expect string may simply be @samp{""}, meaning to skip the expect phase. Otherwise, the following escape characters may appear in expect strings: @table @samp @item \b a backspace character @item \n a newline or line feed character @item \N a null character (for HDB compatibility) @item \r a carriage return character @item \s a space character @item \t a tab character @item \\ a backslash character @item \@var{ddd} character @var{ddd}, where @var{ddd} are up to three octal digits @item \x@var{ddd} character @var{ddd}, where @var{ddd} are hexadecimal digits. @end table As in C, there may be up to three octal digits following a backslash, but the hexadecimal escape sequence continues as far as possible. To follow a hexadecimal escape sequence with a hex digit, interpose a send string of @samp{""}. A send string may simply be @samp{""} to skip the send phase. Otherwise, all of the escape characters legal for expect strings may be used, and the following escape characters are also permitted: @table @samp @item EOT send an end of transmission character (@kbd{^D}) @item BREAK send a break character (may not work on all systems) @item \c suppress trailing carriage return at end of send string @item \d delay sending for 1 or 2 seconds @item \e disable echo checking @item \E enable echo checking @item \K same as @samp{BREAK} (for HDB compatibility) @item \p pause sending for a fraction of a second @end table Some specific types of chat scripts also define additional escape sequences that may appear in the send string. For example, the login chat script defines @samp{\L} and @samp{\P} to send the login name and password, respectively. A carriage return will be sent at the end of each send string, unless the @kbd{\c} escape sequence appears in the string. Note that some UUCP packages use @kbd{\b} for break, but here it means backspace. Echo checking means that after writing each character the program will wait until the character is echoed. Echo checking must be turned on separately for each send string for which it is desired; it will be turned on for characters following @kbd{\E} and turned off for characters following @kbd{\e}. @item chat-timeout @var{number} @findex chat-timeout The number of seconds to wait for an expect string in the chat script before timing out and sending the next subsend or failing the chat script entirely. The default value is 10 for a login chat or 60 for any other type of chat. @item chat-fail @var{string} @findex chat-fail If the @var{string} is seen at any time during a chat script, the chat script is aborted. The string may not contain any whitespace characters; escape sequences must be used for them. Multiple @code{chat-fail} commands may appear in a single chat script. The default is to have none. This permits a chat script to be quickly aborted if an error string is seen. For example, a script used to dial out on a modem might use the command @samp{chat-fail BUSY} to stop the chat script immediately if the string @samp{BUSY} was seen. @item chat-seven-bit @var{boolean} @findex chat-seven-bit If the argument is true, all incoming characters are stripped to seven bits when being compared to the expect string. Otherwise all eight bits are used in the comparison. The default is true, because some Unix systems generate parity bits during the login prompt which must be ignored while running a chat script. This has no effect on any @code{chat-program}, which must ignore parity by itself if necessary. @item chat-program @var{strings} @findex chat-program Specify a program to run before executing the chat script. This program could run its own version of a chat script, or it could do whatever it wants. If both @code{chat-program} and @code{chat} are specified, the program is executed first followed by the chat script. The first argument to the @code{chat-program} command is the program name to run. The remaining arguments are passed to the program. The following escape sequences are recognized in the arguments: @table @kbd @item \Y port device name @item \S port speed @item \\ backslash @end table Some specific uses of @code{chat-program} define additional escape sequences. Arguments other than escape sequences are passed exactly as they appear in the configuration file, except that sequences of whitespace are compressed to a single space character (this exception may be removed in the future). If the @code{chat-program} command is not used, no program is run. On Unix, the standard input and standard output of the program will be attached to the port in use. Anything the program writes to standard error will be written to the UUCP log file. No other file descriptors will be open. If the program does not exit with a status of 0, it will be assumed to have failed; this means that the dialing programs used by some versions of HDB may not be used directly, although of course a shell script could be used as an interface. The program will be run as the @code{uucp} user, and the environment will be that of the process that started @code{uucico}, so care must be taken to maintain security. No search path is used to find the program; a full path name must be given. If the program is an executable shell script, it will be passed to @file{/bin/sh} even on systems which are unable to execute shell scripts. It is also easy to invoke @file{/bin/sh} directly. @end table Here is a simple example of a chat script that might be used to reset a Hayes compatible modem. @example chat "" ATZ OK-ATZ-OK @end example The first expect string is @samp{""}, so it is ignored. The chat script then sends @samp{ATZ}. If the modem responds with @samp{OK}, the chat script finishes. If 60 seconds (the default timeout) pass before seeing @samp{OK}, the chat script sends another @samp{ATZ}. If it then sees @samp{OK}, the chat script succeeds. Otherwise, the chat script fails. For a more complex chat script example, see @ref{Logging In}. @node config File, sys File, Chat Scripts, Configuration Files @section The Main Configuration File @cindex config file @cindex main configuration file @cindex configuration file (config) The main configuration file is named @file{config}. Since all the values that may be specified in the main configuration file also have defaults, there need not be a main configuration file at all. @menu * Miscellaneous (config):: Miscellaneous config file commands * Configuration File Names:: Using different configuration files * Log File Names:: Using different log files * Debugging Levels:: Debugging levels @end menu @node Miscellaneous (config), Configuration File Names, config File, config File @subsection Miscellaneous config File Commands @table @code @item nodename @var{string} @findex nodename @itemx hostname @var{string} @findex hostname @itemx uuname @var{string} @findex uuname @cindex UUCP system name @cindex system name These keywords are equivalent. They specify the UUCP name of the local host. If there is no configuration file, an appropriate system function will be used to get the host name, if possible. @item spool @var{string} @findex spool @cindex spool directory @cindex /usr/spool/uucp Specify the spool directory. The default is from @file{policy.h}. This is where UUCP files are queued. Status files and various sorts of temporary files are also stored in this directory and subdirectories of it. @item pubdir @var{string} @findex pubdir in config file @cindex public directory @cindex uucppublic @cindex /usr/spool/uucppublic Specify the public directory. The default is from @file{policy.h}. When a file is named using a leading @kbd{~/}, it is taken from or to the public directory. Each system may use a separate public directory by using the @code{pubdir} command in the system configuration file; see @ref{Miscellaneous (sys)}. @item lockdir @var{string} @findex lockdir @cindex lock directory Specify the directory to place lock files in. The default is from @file{policy.h}; see the information in that file. Normally the lock directory should be set correctly in @file{policy.h}, and not changed here. However, changing the lock directory is sometimes useful for testing purposes. @item unknown @var{string} @dots{} @findex unknown @cindex unknown systems The @var{string} and subsequent arguments are treated as though they appeared in the system file (@pxref{sys File}). They are used to apply to any unknown systems that may call in, probably to set file transfer permissions and the like. If the @code{unknown} command is not used, unknown systems are not permitted to call in. @item max-uuxqts @var{number} @findex max-uuxqts Specify the maximum number of @code{uuxqt} processes which may run at the same time. Having several @code{uuxqt} processes running at once can significantly slow down a system, but since @code{uuxqt} is automatically started by @code{uucico}, it can happen quite easily. The default for @code{max-uuxqts} is 0, which means that there is no limit. If HDB configuration files are being read and the code was compiled without @code{HAVE_TAYLOR_CONFIG}, then if the file @file{Maxuuxqts} in the configuration directory contains a readable number it will be used as the value for @code{max-uuxqts}. @item timetable @var{string} @var{string} @findex timetable The @code{timetable} defines a timetable that may be used in subsequently appearing time strings; @ref{Time Strings}. The first string names the timetable entry; the second is a time string. The following @code{timetable} commands are predefined. The NonPeak timetable is included for compatibility. It originally described the offpeak hours of Tymnet and Telenet, but both have since changed their schedules. @example timetable Evening Wk1705-0755,Sa,Su timetable Night Wk2305-0755,Sa,Su2305-1655 timetable NonPeak Wk1805-0655,Sa,Su @end example If this command does not appear, then obviously no additional timetables will be defined. @item v2-files @var{boolean} @findex v2-files If the code was compiled to be able to read V2 configuration files, a false argument to this command will prevent them from being read. This can be useful while testing. The default is true. @item hdb-files @var{boolean} @findex hdb-files If the code was compiled to be able to read HDB configuration files, a false argument to this command will prevent them from being read. This can be useful while testing. The default is true. @end table @node Configuration File Names, Log File Names, Miscellaneous (config), config File @subsection Configuration File Names @table @code @item sysfile @var{strings} @findex sysfile Specify the system file(s). The default is the file @file{sys} in the directory @var{newconfigdir}. These files hold information about other systems with which this system communicates; see @ref{sys File}. Multiple system files may be given on the line, and the @code{sysfile} command may be repeated; each system file has its own set of defaults. @item portfile @var{strings} @findex portfile Specify the port file(s). The default is the file @file{port} in the directory @var{newconfigdir}. These files describe ports which are used to call other systems and accept calls from other systems; see @ref{port File}. No port files need be named at all. Multiple port files may be given on the line, and the @code{portfile} command may be repeated. @item dialfile @var{strings} @findex dialfile Specify the dial file(s). The default is the file @file{dial} in the directory @var{newconfigdir}. These files describe dialing devices (modems); @xref{dial File}. No dial files need be named at all. Multiple dial files may be given on the line, and the @code{dialfile} command may be repeated. @item dialcodefile @var{strings} @findex dialcodefile @cindex configuration file (dialcode) @cindex dialcode file @cindex dialcode configuration file Specify the dialcode file(s). The default is the file @file{dialcode} in the directory @var{newconfigdir}. These files specify dialcodes that may be used when sending phone numbers to a modem. This permits using the same set of phone numbers in different area-codes or with different phone systems, by using dialcodes to specify the calling sequence. When a phone number goes through dialcode translation, the leading alphabetic characters are stripped off. The dialcode files are read line by line, just like any other configuration file, and when a line is found whose first word is the same as the leading characters from the phone number, the second word on the line (which would normally consist of numbers) replaces the dialcode in the phone number. No dialcode file need be used. Multiple dialcode files may be specified on the line, and the @code{dialcodefile} command may be repeated; all the dialcode files will be read in turn until a dialcode is located. @item callfile @var{strings} @findex callfile @cindex call out file @cindex call configuration file @cindex call out login name @cindex call out password @cindex configuration file (call) Specify the call out login name and password file(s). The default is the file @file{call} in the directory @var{newconfigdir}. If the call out login name or password for a system are given as @kbd{*} (@pxref{Logging In}), these files are read to get the real login name or password. Each line in the file(s) has three words: the system name, the login name, and the password. This file is only used when placing calls to remote systems; the password file described under @code{passwdfile} below is used for incoming calls. The intention of the call out file is to permit the system file to be publically readable; the call out files must obviously be kept secure. These files need not be used. Multiple call out files may be specified on the line, and the @code{callfile} command may be repeated; all the files will be read in turn until the system is found. @item passwdfile @var{strings} @findex passwdfile @cindex passwd file @cindex passwd configuration file @cindex configuration file (passwd) @cindex call in login name @cindex call in password Specify the password file(s) to use for login names when @code{uucico} is doing its own login prompting, which it does when given the @samp{-e}, @samp{-l} or @samp{-w} switches. The default is the file @file{passwd} in the directory @var{newconfigdir}. Each line in the file(s) has two words: the login name and the password (e.g. @code{Ufoo foopas}). The login name is accepted before the system name is known, so these are independent of which system is calling in; a particular login may be required for a system by using the @code{called-login} command in the system file (@pxref{Accepting a Call}). These password files are optional, although one must exist if @code{uucico} is to present its own login prompts. Multiple password files may be specified on the line, and the @code{passwdfile} command may be repeated; all the files will be read in turn until the login name is found. @end table @node Log File Names, Debugging Levels, Configuration File Names, config File @subsection Log File Names @table @code @item logfile @var{string} @findex logfile @cindex log file Name the log file. The default is from @file{policy.h}. Logging information is written to this file. If @code{HAVE_HDB_LOGGING} is defined in @file{conf.h}, then by default a separate log file is used for each system. Using this command to name a log file will cause all the systems to use it. @item statfile @var{string} @findex statfile @cindex statistics file Name the statistics file. The default is from @file{policy.h}. Statistical information about file transfers is written to this file. @item debugfile @var{string} @findex debugfile @cindex debugging file Name the file to which debugging information is written. The default is from @file{policy.h}. This command is only effective if the code has been compiled to include debugging (this is controlled by the @code{DEBUG} variable in @file{policy.h}). After the first debugging message has been written, messages written to the log file are also written to the debugging file to make it easier to keep the order of actions straight. The debugging file is different from the log file because information such as passwords can appear in it, so it must be not be publically readable. @end table @node Debugging Levels, , Log File Names, config File @subsection Debugging Levels @table @code @item debug @var{string} @dots{} @findex debug in config file Set the debugging level. This command is only effective if the code has been compiled to include debugging. The default is to have no debugging. The arguments are strings which name the types of debugging to be turned on. The following types of debugging are defined: @table @samp @item abnormal Output debugging messages for abnormal situations, such as recoverable errors. @item chat Output debugging messages for chat scripts. @item handshake Output debugging messages for the initial handshake. @item uucp-proto Output debugging messages for the UUCP session protocol. @item proto Output debugging messages for the individual link protocols. @item port Output debugging messages for actions on the communication port. @item config Output debugging messages while reading the configuration files. @item spooldir Output debugging messages for actions in the spool directory. @item execute Output debugging messages whenever another program is executed. @item incoming List all incoming data in the debugging file. @item outgoing List all outgoing data in the debugging file. @item all All of the above. @end table The debugging level may also be specified as a number. A 1 will set @samp{chat} debugging, a 2 will set both @samp{chat} and @samp{handshake} debugging, and so on down the possibilities. Currently an 11 will turn on all possible debugging, since there are 11 types of debugging messages listed above; more debugging types may be added in the future. The @code{debug} command may be used several times in the configuration file; every debugging type named will be turned on. When running any of the programs, the @samp{-x} switch (actually, for @code{uulog} it's the @samp{-X} switch) may be used to turn on debugging. The argument to the @samp{-x} switch is one of the strings listed above, or a number as described above, or a comma separated list of strings (e.g. @samp{-x chat,handshake}). The @samp{-x} switch may also appear several times on the command line, in which case all named debugging types will be turned on. The @samp{-x} debugging is in addition to any debugging specified by the @code{debug} command; there is no way to cancel debugging information. The debugging level may also be set specifically for calls to or from a specific system with the @code{debug} command in the system file (@pxref{Miscellaneous (sys)}). The debugging messages are somewhat idiosyncratic; it may be necessary to refer to the source code for additional information in some cases. @end table @node sys File, port File, config File, Configuration Files @section The System Configuration File @cindex sys file @cindex system configuration file @cindex configuration file (sys) By default there is a single system configuration, named @file{sys} in the directory @var{newconfigdir}. This may be overridden by the @code{sysfile} command in the main configuration file; see @ref{Configuration File Names}. These files describe all remote systems known to the UUCP package. @menu * Defaults and Alternates:: Using defaults and alternates * Naming the System:: Naming the system * Calling Out:: Calling out * Accepting a Call:: Accepting a call * Protocol Selection:: Protocol selection * File Transfer Control:: File transfer control * Miscellaneous (sys):: Miscellaneous sys file commands * Default sys File Values:: Default values @end menu @node Defaults and Alternates, Naming the System, sys File, sys File @subsection Defaults and Alternates The first set of commands in the file, up to the first @code{system} command, specify defaults to be used for all systems in that file. Each system file uses a different set of defaults. Subsequently, each set of commands from @code{system} up to the next @code{system} command describe a particular system. Default values may be overridden for specific systems. Each system may then have a series of alternate choices to use when calling out or calling in. The first set of commands for a particular system, up to the first @code{alternate} command, provide the first choice. Subsequently, each set of commands from @code{alternate} up to the next @code{alternate} command describe an alternate choice for calling out or calling in. When a system is called, the commands before the first @code{alternate} are used to select a phone number, port, and so forth; if the call fails for some reason, the commands between the first @code{alternate} and the second are used, and so forth. Well, not quite. Actually, each succeeding alternate will only be used if it is different in some relevant way (different phone number, different chat script, etc.). If you want to force the same alternate to be used again (to retry a phone call more than once, for example), enter the phone number (or any other relevant field) again to make it appear different. The alternates can also be used to give different permissions to an incoming call based on the login name. This will only be done if the first set of commands, before the first @code{alternate} command, uses the @code{called-login} command. The list of alternates will be searched, and the first alternate with a matching @code{called-login} command will be used. If no alternates match, the call will be rejected. The @code{alternate} command may also be used in the file-wide defaults (the set of commands before the first @code{system} command). This might be used to specify a list of ports which are available for all systems (for an example of this, see @ref{Gateway Example}) or to specify permissions based on the login name used by the remote system when it calls in. The first alternate for each system will default to the first alternate for the file-wide defaults (as modified by the commands used before the first @code{alternate} command for this system), the second alternate for each system to the second alternate for the file-wide defaults (as modified the same way), and so forth. If a system specifies more alternates than the file-wide defaults, the trailing ones will default to the last file-wide default alternate. If a system specifies fewer alternates than the file-wide defaults, the trailing file-wide default alternates will be used unmodified. The @code{default-alternates} command may be used to modify this behaviour. This can all get rather confusing, although it's easier to use than to describe concisely; the @code{uuchk} program may be used to ensure that you are getting what you want. @node Naming the System, Calling Out, Defaults and Alternates, sys File @subsection Naming the System @table @code @item system @var{string} @findex system Specify the remote system name. Subsequent commands up to the next @code{system} command refer to this system. @item alternate [@var{string}] @findex alternate Start an alternate set of commands (@pxref{Defaults and Alternates}). An optional argument may be used to name the alternate. This name will be put in the log file if the alternate is used to call the system. There is no way to name the first alternate (the commands before the first @code{alternate} command). @item default-alternates @var{boolean} @findex default-alternates If the argument is false, any remaining default alternates (from the defaults specified at the top of the current system file) will not be used. The default is true. @item alias @var{string} @findex alias Specify an alias for the current system. The alias may be used by local @code{uucp} and @code{uux} commands, as well as by the remote system (which can be convenient if a remote system changes its name). The default is to have no aliases. @item myname @var{string} @findex myname Specifies a different system name to use when calling the remote system. Also, if @code{called-login} is used and is not @samp{ANY}, then, when a system logs in with that login name, @var{string} is used as the system name. Because the local system name must be determined before the remote system has identified itself, using @code{myname} and @code{called-login} together for any system will set the local name for that login; this means that each locally used system name must have a unique login name associated with it. This allows a system to have different names for an external and an internal network. The default is to not use a special local name. @end table @node Calling Out, Accepting a Call, Naming the System, sys File @subsection Calling Out This section describes commands used when placing a call to another system. @menu * When to Call:: When to call * Placing the Call:: Placing the call * Logging In:: Logging in @end menu @node When to Call, Placing the Call, Calling Out, Calling Out @subsubsection When to Call @table @code @item time @var{string} [@var{number}] @findex time Specify when the system may be called. The first argument is a time string; see @ref{Time Strings}. The optional second argument specifies a retry time in minutes. If a call made during a time that matches the time string fails, no more calls are permitted until the retry time has passed. By default an exponentially increasing retry time is used: after each failure the next retry period is longer. A retry time specified in the @code{time} command is always a fixed amount of time. The @code{time} command may appear multiple times in a single alternate, in which case if any time string matches the system may be called. When the @code{time} command is used for a particular system, any @code{time} or @code{timegrade} commands that appeared in the system defaults are ignored. The default time string is @samp{Never}. @item timegrade @var{character} @var{string} [@var{number}] @findex timegrade The @var{character} specifies a grade. It must be a single letter or digit. The @var{string} is a time string (@pxref{Time Strings}). All jobs of grade @var{character} or higher (where @kbd{0} > @kbd{9} > @kbd{A} > @kbd{Z} > @kbd{a} > @kbd{z}) may be run at the specified time. An ordinary @code{time} command is equivalent to using @code{timegrade} with a grade of @kbd{z}, permitting all jobs. If there are no jobs of a sufficiently high grade according to the time string, the system will not be called. Giving the @samp{-s} switch to @code{uucico} to force it to call a system causes it to assume there is a job of grade @kbd{0} waiting to be run. The optional third argument specifies a retry time in minutes. See the @code{time} command, above, for more details. Note that the @code{timegrade} command serves two purposes: 1) if there is no job of sufficiently high grade the system will not be called, and 2) if the system is called anyway (because the @samp{-s} switch was given to @code{uucico}) only jobs of sufficiently high grade will be transferred. However, if the other system calls in, the @code{timegrade} commands are ignored, and jobs of any grade may be transferred (but see @code{call-timegrade} below). Also, the @code{timegrade} command will not prevent the other system from transferring any job it chooses, regardless of who placed the call. The @code{timegrade} command may appear multiple times without using @code{alternate}. When the @code{timegrade} command is used for a particular system, any @code{time} or @code{timegrade} commands that appeared in the system defaults are ignored. If this command does not appear, there are no restrictions on what grade of work may be done at what time. @item max-retries @var{number} @findex max-retries Gives the maximum number of times this system may be retried. If this many calls to the system fail, it will be called at most once a day whatever the retry time is. The default is 26. @item success-wait @var{number} A retry time, in seconds, which applies after a successful call. This can be used to put a limit on how frequently the system is called. For example, an argument of 1800 means that the system will not be called more than once every half hour. The default is 0, which means that there is no limit. @item call-timegrade @var{character} @var{string} @findex call-timegrade The @var{character} is a single character @kbd{A} to @kbd{Z}, @kbd{a} to @kbd{z}, or @kbd{0} to @kbd{9} and specifies a grade. The @var{string} is a time string as described under the @code{time} command. If a call is placed to the other system during a time which matches the time string, the remote system will be requested to only run jobs of grade @var{character} or higher. Unfortunately, there is no way to guarantee that the other system will obey the request (this UUCP package will, but there are others which will not); moreover job grades are historically somewhat arbitrary, so specifying a grade will only be meaningful if the other system cooperates in assigning grades. This grade restriction only applies when the other system is called, not when the other system calls in. The @code{call-timegrade} command may appear multiple times without using @code{alternate}. If this command does not appear, or if none of the time strings match, the remote system will be allowed to send whatever grades of work it chooses. @end table @node Placing the Call, Logging In, When to Call, Calling Out @subsubsection Placing the Call @table @code @item baud @var{number} @findex baud in sys file @itemx speed @var{number} @findex speed in sys file Specify the speed (the term @dfn{baud} is technically incorrect, but widely understood) at which to call the system. This will try all available ports with that baud rate until an unlocked port is found. The ports are defined in the port file. If both @code{baud} and @code{port} commands appear, both are used when selecting a port. To allow calls at more than one baud rate, the @code{alternate} command must be used (@pxref{Defaults and Alternates}). If this command does not appear, there is no default; the baud rate may be specified in the port file, but if it is not then the natural baud rate of the port will be used (whatever that means on the system). Specifying an explicit baud rate of 0 will request the natural baud rate of the port, overriding any default baud rate from the defaults at the top of the file. @item port @var{string} @findex port in sys file Name a particular port or type of port to use when calling the system. The information for this port is obtained from the port file. If this command does not appear, there is no default; a port must somehow be specified in order to call out (it may be specified implicitly using the @code{baud} command or explicitly using the next version of @code{port}). There may be many ports with the same name; each will be tried in turn until an unlocked one is found which matches the desired baud rate. @item port @var{string} @dots{} If more than one string follows the @code{port} command, the strings are treated as a command that might appear in the port file (@pxref{port File}). If a port is named (by using a single string following @code{port}) these commands are ignored; their purpose is to permit defining the port completely in the system file rather than always requiring entries in two different files. In order to call out, a port must be specified using some version of the @code{port} command, or by using the @code{baud} command to select ports from the port file. @item phone @var{string} @findex phone @itemx address @var{string} @findex address Give a phone number to call (when using a modem port) or a remote host to contact (when using a TCP or TLI port). The commands @code{phone} and @code{address} are equivalent; the duplication is intended to provide a mnemonic choice depending on the type of port in use. When used with a modem port, an @kbd{=} character in the phone number means to wait for a secondary dial tone (although only some modems support this); a @kbd{-} character means to pause while dialing for 1 second (again, only some modems support this). If the system has more than one phone number, each one must appear in a different alternate. The @code{phone} command must appear in order to call out on a modem; there is no default. When used with a TCP port, the string names the host to contact. It may be a domain name or a numeric Internet address. If no address is specified, the system name is used. When used with a TLI port, the string is treated as though it were an expect string in a chat script, allowing the use of escape characters (@pxref{Chat Scripts}). The @code{dialer-sequence} command in the port file may override this address (@pxref{port File}). When used with a port that not a modem or TCP or TLI, this command is ignored. @end table @node Logging In, , Placing the Call, Calling Out @subsubsection Logging In @table @code @item chat @var{strings} @findex chat in sys file @item chat-timeout @var{number} @findex chat-timeout in sys file @item chat-fail @var{string} @findex chat-fail in sys file @item chat-seven-bit @var{boolean} @findex chat-seven-bit in sys file @item chat-program @var{strings} @findex chat-program in sys file These commands describe a chat script to use when logging on to a remote system. Chat scripts are explained in @ref{Chat Scripts}. Two additional escape sequences may be used in send strings. @table @samp @item \L Send the login name, as set by the @code{call-login} command. @item \P Send the password, as set by the @code{call-password} command. @end table Three additional escape sequences may be used with the @code{chat-program} command. These are @samp{\L} and @samp{\P}, which become the login name and password, respectively, and @samp{\Z}, which becomes the name of the system of being called. The default chat script is: @example chat "" \r\c ogin:-BREAK-ogin:-BREAK-ogin: \L word: \P @end example This will send a carriage return (the @kbd{\c} suppresses the additional trailing carriage return that would otherwise be sent) and waits for the string @samp{ogin:} (which would be the last part of the @samp{login:} prompt supplied by a Unix system). If it doesn't see @samp{ogin:}, it sends a break and waits for @samp{ogin:} again. If it still doesn't see @samp{ogin:}, it sends another break and waits for @samp{ogin:} again. If it still doesn't see @samp{ogin:}, the chat script aborts and hangs up the phone. If it does see @samp{ogin:} at some point, it sends the login name (as specified by the @code{call-login} command) followed by a carriage return (since all send strings are followed by a carriage return unless @kbd{\c} is used) and waits for the string @samp{word:} (which would be the last part of the @samp{Password:} prompt supplied by a Unix system). If it sees @samp{word:}, it sends the password and a carriage return, completing the chat script. The program will then enter the handshake phase of the UUCP protocol. This chat script will work for most systems, so you will only be required to use the @code{call-login} and @code{call-password} commands. In fact, in the file-wide defaults you could set defaults of @samp{call-login *} and @samp{call-password *}; you would then just have to make an entry for each system in the call-out login file. Some systems seem to flush input after the @samp{login:} prompt, so they may need a version of this chat script with a @kbd{\d} before the @kbd{\L}. When using UUCP over TCP, some servers will not be handle the initial carriage return sent by this chat script; in this case you may have to specify the simple chat script @samp{ogin: \L word: \P}. @item call-login @var{string} @findex call-login Specify the login name to send with @kbd{\L} in the chat script. If the string is @samp{*} (e.g. @samp{call-login *}) the login name will be fetched from the call out login name and password file (@pxref{Configuration File Names}). There is no default. @item call-password @var{string} @findex call-password Specify the password to send with @kbd{\P} in the chat script. If the string is @samp{*} (e.g. @samp{call-password *}) the password will be fetched from the call-out login name and password file (@pxref{Configuration File Names}). There is no default. @end table @node Accepting a Call, Protocol Selection, Calling Out, sys File @subsection Accepting a Call @table @code @item called-login @var{strings} @findex called-login The first @var{string} specifies the login name that the system must use when calling in. If it is @samp{ANY} (e.g. @samp{called-login ANY}) any login name may be used; this is useful to override a file-wide default and to indicate that future alternates may have different login names. Case is significant. The default value is @samp{ANY}. Different alternates (@pxref{Defaults and Alternates}) may use different @code{called-login} commands, in which case the login name will be used to select which alternate is in effect; this will only work if the first alternate (before the first @code{alternate} command) uses the @code{called-login} command. Additional strings may be specified after the login name; they are a list of which systems are permitted to use this login name. If this feature is used, then normally the login name will only be given in a single @code{called-login} command. Only systems which appear on the list, or which use an explicit @code{called-login} command, will be permitted to use that login name. If the same login name is used more than once with a list of systems, all the lists are concatenated together. This feature permits you to restrict a login name to a particular set of systems without requiring you to use the @code{called-login} command for every single system; you can achieve a similar effect by using a different system file for each permitted login name with an appropriate @code{called-login} command in the file-wide defaults. @item callback @var{boolean} @findex callback If @var{boolean} is true, then when the remote system calls @code{uucico} will hang up the connection and prepare to call it back. The default is false. @item called-chat @var{strings} @findex called-chat @item called-chat-timeout @var{number} @findex called-chat-timeout @item called-chat-fail @var{string} @findex called-chat-fail @item called-chat-seven-bit @var{boolean} @findex called-chat-seven-bit @item called-chat-program @var{strings} @findex called-chat-program These commands may be used to define a chat script (@pxref{Chat Scripts}) that is run whenever the local system is called by the system being defined. The chat script defined by the @code{chat} command (@pxref{Logging In}), on the other hand, is used when the remote system is called. This called chat script might be used to set special modem parameters that are appropriate to a particular system. It is run after protocol negotiation is complete, but before the protocol has been started. See @ref{Logging In} for additional escape sequence which may be used besides those defined for all chat scripts. There is no default called chat script. If the called chat script fails, the incoming call will be aborted. @end table @node Protocol Selection, File Transfer Control, Accepting a Call, sys File @subsection Protocol Selection @table @code @item protocol @var{string} @findex protocol in sys file Specifies which protocols to use for the other system, and in which order to use them. This would not normally be used. For example, @samp{protocol tfg}. The default depends on the characteristics of the port and the dialer, as specified by the @code{seven-bit} and @code{reliable} commands. If neither the port nor the dialer use either of these commands, the default is to assume an eight-bit reliable connection. The commands @samp{seven-bit true} or @samp{reliable false} might be used in either the port or the dialer to change this. Each protocol has particular requirements that must be met before it will be considered during negotiation with the remote side. The @samp{t} and @samp{e} protocols are intended for use over TCP or some other communication path with end to end reliability, as they do no checking of the data at all. They will only be considered on a TCP port which is both reliable and eight bit. The @samp{i} protocol is a bidirectional protocol. It requires an eight-bit connection. It will run over a half-duplex link, such as Telebit modems in PEP mode, but for efficient use of such a connection you must use the @code{half-duplex} command (@pxref{port File}). The @samp{g} protocol is robust, but requires an eight-bit connection. The @samp{G} protocol is the System V Release 4 version of the @samp{g} protocol. The @samp{a} protocol is a Zmodem like protocol, contributed by Doug Evans. It requires an eight-bit connection, but unlike the @samp{g} or @samp{i} protocol it will work if certain control characters may not be transmitted. The @samp{j} protocol is a variant of the @samp{i} protocol which can avoid certain control characters. The set of characters it avoids can be set by a parameter. While it technically does not require an eight bit connection (it could be configured to avoid all characters with the high bit set) it would be very inefficient to use it over one. It is useful over a eight-bit connection that will not transmit certain control characters. The @samp{f} protocol is intended for use with X.25 connections; it checksums each file as a whole, so any error causes the entire file to be retransmitted. It requires a reliable connection, but only uses seven-bit transmissions. It is a streaming protocol, so, while it can be used on a serial port, the port must be completely reliable and flow controlled; many aren't. The protocols will be considered in the order shown above. This means that if neither the @code{seven-bit} nor the @code{reliable} command are used, the @samp{t} protocol will be used over a TCP connection and the @samp{i} protocol will be used over any other type of connection (subject, of course, to what is supported by the remote system; it may be assumed that all systems support the @samp{g} protocol). Note that currently specifying both @samp{seven-bit true} and @samp{reliable false} will not match any protocol. If this occurs through a combination of port and dialer specifications, you will have to use the @code{protocol} command for the system or no protocol will be selected at all (the only reasonable choice would be @samp{protocol f}). A protocol list may also be specified for a port (@pxref{port File}), but if there is a list for the system the list for the port is ignored. @item protocol-parameter @var{character} @var{string} @dots{} @findex protocol-parameter in sys file @var{character} is a single character specifying a protocol. The remaining strings are a command specific to that protocol which will be executed if that protocol is used. A typical command is something like @samp{window 7}. The particular commands are protocol specific. The @samp{i} protocol supports the following commands, all of which take numeric arguments: @table @code @item window The window size to request the remote system to use. This must be between 1 and 31 inclusive. The default is 16. @item packet-size The packet size to request the remote system to use. This must be between 1 and 4095 inclusive. The default is 1024. @item remote-window If this is between 1 and 31 inclusive, the window size requested by the remote system is ignored and this is used instead. The default is 0, which means that the remote system's request is honored. @item remote-packet-size If this is between 1 and 4095 inclusive, the packet size requested by the remote system is ignored and this is used instead. The default is 0, which means that the remote system's request is honored. @item sync-timeout The length of time, in seconds, to wait for a SYNC packet from the remote system. SYNC packets are exchanged when the protocol is started. The default is 10. @item sync-retries The number of times to retry sending a SYNC packet before giving up. The default is 6. @item timeout The length of time, in seconds, to wait for an incoming packet before sending a negative acknowledgement. The default is 10. @item retries The number of times to retry sending a packet or a negative acknowledgement before giving up and closing the connection. The default is 6. @item errors The maximum number of errors to permit before closing the connection. The default is 100. @item error-decay The rate at which to ignore errors. Each time this many packets are received, the error count is decreased by one, so that a long connection with an occasional error will not exceed the limit set by @code{errors}. The default is 10. @end table The @samp{g} and @samp{G} protocols support the following commands, all of which take numeric arguments, except @code{short-packets} which takes a boolean argument: @table @code @item window The window size to request the remote system to use. This must be between 1 and 7 inclusive. The default is 7. @item packet-size The packet size to request the remote system to use. This must be a power of 2 between 32 and 4096 inclusive. The default is 64, which is the only packet size supported by many older UUCP packages. Some UUCP packages will even dump core if a larger packet size is requested. @item startup-retries The number of times to retry the initialization sequence. The default is 8. @item init-retries The number of times to retry one phase of the initialization sequence (there are three phases). The default is 4. @item init-timeout The timeout in seconds for one phase of the initialization sequence. The default is 10. @item retries The number of times to retry sending either a data packet or a request for the next packet. The default is 6. @item timeout The timeout in seconds when waiting for either a data packet or an acknowledgement. The default is 10. @item garbage The number of unrecognized bytes to permit before dropping the connection. This must be larger than the packet size. The default is 10000. @item errors The number of errors (malformed packets, out of order packets, bad checksums, or packets rejected by the remote system) to permit before dropping the connection. The default is 100. @item error-decay The rate at which to ignore errors. Each time this many packets are received, the error count is decreased by one, so that a long connection with an occasional error will not exceed the limit set by @code{errors}. The default is 10. @item remote-window If this is between 1 and 7 inclusive, the window size requested by the remote system is ignored and this is used instead. This can be useful when dealing with some poor UUCP packages. The default is 0, which means that the remote system's request is honored. @item remote-packet-size If this is between 32 and 4096 inclusive the packet size requested by the remote system is ignored and this is used instead. There is probably no good reason to use this. The default is 0, which means that the remote system's request is honored. @item short-packets If this is true, then the code will optimize by sending shorter packets when there is less data to send. This confuses some UUCP packages, such as System V Release 4 (when using the @samp{G} protocol) and Waffle; when connecting to such a package, this parameter must be set to false. The default is true for the @samp{g} protocol and false for the @samp{G} protocol. @end table The @samp{a} protocol is a Zmodem like protocol contributed by Doug Evans. It supports the following commands, all of which take numeric arguments except for @code{escape-control}, which takes a boolean argument: @table @code @item timeout Number of seconds to wait for a packet to arrive. The default is 10. @item retries The number of times to retry sending a packet. The default is 10. @item startup-retries The number of times to retry sending the initialization packet. The default is 4. @item garbage The number of garbage characters to accept before closing the connection. The default is 2400. @item send-window The number of characters that may be sent before waiting for an acknowledgement. The default is 1024. @item escape-control Whether to escape control characters. If this is true, the protocol may be used over a connection which does not transmit certain control characters, such as @code{XON} or @code{XOFF}. The connection must still transmit eight bit characters other than control characters. The default is false. @end table The @samp{j} protocol can be used over an eight bit connection that will not transmit certain control characters. It accepts the same protocol parameters that the @samp{i} protocol accepts, as well as one more: @table @code @item avoid A list of characters to avoid. This is a string which is interpreted as an escape sequence (@pxref{Chat Scripts}). The protocol does not have a way to avoid printable ASCII characters (byte values from 32 to 126, inclusive); only ASCII control characters and eight-bit characters may be avoided. The default value is @samp{\021\023}; these are the characters @code{XON} and @code{XOFF} which many connections use for flow control. If the package is configured to use @code{HAVE_BSD_TTY}, then on some versions of Unix you may have to avoid @samp{\377} as well, due to the way some implementations of the BSD terminal driver handle signals. @end table The @samp{f} protocol is intended for use with error-correcting modems only; it checksums each file as a whole, so any error causes the entire file to be retransmitted. It supports the following commands, both of which take numeric arguments: @table @code @item timeout The timeout in seconds before giving up. The default is 120. @item retries How many times to retry sending a file. The default is 2. @end table The @samp{t} and @samp{e} protocols are intended for use over TCP or some other communication path with end to end reliability, as they do no checking of the data at all. They both support a single command, which takes a numeric argument: @table @code @item timeout The timeout in seconds before giving up. The default is 120. @end table The protocol parameters are reset to their default values after each call. @end table @node File Transfer Control, Miscellaneous (sys), Protocol Selection, sys File @subsection File Transfer Control @table @code @item send-request @var{boolean} @findex send-request The @var{boolean} determines whether the remote system is permitted to request files from the local system. The default is yes. @item receive-request @var{boolean} @findex receive-request The @var{boolean} determines whether the remote system is permitted to send files to the local system. The default is yes. @item request @var{boolean} @findex request A shorthand command, equivalent to specifying both @samp{send-request @var{boolean}} and @samp{receive-request @var{boolean}}. @item call-transfer @var{boolean} @findex call-transfer The @var{boolean} is checked when the local system places the call. It determines whether the local system may do file transfers queued up for the remote system. The default is yes. @item called-transfer @var{boolean} @findex called-transfer The @var{boolean} is checked when the remote system calls in. It determines whether the local system may do file transfers queued up for the remote system. The default is yes. @item transfer @var{boolean} @findex transfer Equivalent to specifying both @samp{call-transfer @var{boolean}} @samp{called-transfer @var{boolean}}. @item call-local-size @var{number} @var{string} @findex call-local-size The @var{string} is a time string (@pxref{Time Strings}). The @var{number} is the size in bytes of the largest file that should be transferred at a time matching the time string if the local system placed the call and the request was made by the local system. This command may appear multiple times in a single alternate. If this command does not appear, or if none of the time strings match, there are no size restrictions. With all the size control commands, the size of a file from the remote system (as opposed to a file from the local system) will only be checked if the other system is running this package; other UUCP packages will not understand a maximum size request, nor will they inform this package of the size of remote files. @item call-remote-size @var{number} @var{string} @findex call-remote-size Specify the size in bytes of the largest file that should be transferred at a given time by remote request when the local system placed the call. This command may appear multiple times in a single alternate. If this command does not appear, there are no size restrictions. @item called-local-size @var{number} @var{string} @findex called-local-size Specify the size in bytes of the largest file that should be transferred at a given time by local request when the remote system placed the call. This command may appear multiple times in a single alternate. If this command does not appear, there are no size restrictions. @item called-remote-size @var{number} @var{string} @findex called-remote-size Specify the size in bytes of the largest file that should be transferred at a given time by remote request when the remote system placed the call. This command may appear multiple times in a single alternate. If this command does not appear, there are no size restrictions. @item local-send @var{strings} @findex local-send Specifies that files in the directories named by the @var{strings} may be sent to the remote system when requested locally (using @code{uucp} or @code{uux}). The directories in the list should be separated by whitespace. A @kbd{~} may be used for the public directory. On a Unix system, this is typically @file{/usr/spool/uucppublic}; the public directory may be set with the @code{pubdir} command. Here is an example of @code{local-send}: @example local-send ~ /usr/spool/ftp/pub @end example Listing a directory allows all files within the directory and all subdirectories to be sent. Directories may be excluded by preceding them with an exclamation point. For example: @example local-send /usr/ftp !/usr/ftp/private ~ @end example @noindent means that all files in @file{/usr/ftp} or the public directory may be sent, except those files in @file{/usr/ftp/private}. The list of directories is read from left to right, and the last directory to apply takes effect; this means that directories should be listed from top down. The default is the root directory (i.e., any file at all may be sent by local request). @item remote-send @var{strings} @findex remote-send Specifies that files in the named directories may be sent to the remote system when requested by the remote system. The default is @kbd{~}. @item local-receive @var{strings} @findex local-receive Specifies that files may be received into the named directories when requested by a local user. The default is @kbd{~}. @item remote-receive @var{strings} @findex remote-receive Specifies that files may be received into the named directories when requested by the remote system. The default is @kbd{~}. On Unix, the remote system may only request that files be received into directories that are writeable by the world, regardless of how this is set. @item forward-to @var{strings} @findex forward-to Specifies a list of systems to which files may be forwarded. The remote system may forward files through the local system on to any of the systems in this list. The string @samp{ANY} may be used to permit forwarding to any system. The default is to not permit forwarding to other systems. Note that if the remote system is permitted to execute the @code{uucp} command, it effectively has the ability to forward to any system. @item forward-from @var{strings} @findex forward-from Specifies a list of systems from which files may be forwarded. The remote system may request files via the local system from any of the systems in this list. The string @samp{ANY} may be used to permit forwarding to any system. The default is to not permit forwarding from other systems. Note that if a remote system is permitted to execute the @code{uucp} command, it effectively has the ability to request files from any system. @item forward @var{strings} @findex forward Equivalent to specifying both @samp{forward-to @var{strings}} and @samp{forward-from @var{strings}}. This would normally be used rather than either of the more specific commands. @end table @node Miscellaneous (sys), Default sys File Values, File Transfer Control, sys File @subsection Miscellaneous sys File Commands @table @code @item sequence @var{boolean} @findex sequence If @var{boolean} is true, then conversation sequencing is automatically used for the remote system, so that if somebody manages to spoof as the remote system, it will be detected the next time the remote system actually calls. This is false by default. @item command-path @var{string} @findex command-path Specifies the path (a list of whitespace separated directories) to be searched to locate commands to execute. This is only used for commands requested by @code{uux}, not for chat programs. The default is from @file{policy.h}. @item commands @var{strings} @findex commands The list of commands which the remote system is permitted to execute locally. For example: @samp{commands rnews rmail}. If the value is @samp{ALL} (case significant), all commands may be executed. The default is @samp{rnews rmail}. @item free-space @var{number} @findex free-space Specify the minimum amount of file system space (in bytes) to leave free after receiving a file. If the incoming file will not fit, it will be rejected. This initial rejection will only work when talking to another instance of this package, since older UUCP packages do not provide the file size of incoming files. Also, while a file is being received, @code{uucico} will periodically check the amount of free space. If it drops below the amount given by the @code{free-space} command, the file transfer will be aborted. The default amount of space to leave free is from @file{policy.h}. This file space checking may not work on all systems. @item pubdir @var{string} @findex pubdir in sys file Specifies the public directory that is used when @kbd{~} is specifed in a file transfer or a list of directories. This essentially overrides the public directory specified in the main configuration file for this system only. The default is the public directory specified in the main configuration file (which defaults to a value from @file{policy.h}). @item debug @var{string} @dots{} @findex debug in sys file Set additional debugging for calls to or from the system. This may be used to debug a connection with a specific system. It is particularly useful when debugging incoming calls, since debugging information will be generated whenever the call comes in. See the @code{debug} command in the main configuration file (@pxref{Debugging Levels}) for more details. The debugging information specified here is in addition to that specified in the main configuration file or on the command line. @item max-remote-debug @var{string} @dots{} @findex max-remote-debug When the system calls in, it may request that the debugging level be set to a certain value. This command may be used to put a limit on the debugging level which the system may request, to avoid filling up the disk with debugging information. Only the debugging types named in the @code{max-remote-debug} command may be turned on by the remote system. To prohibit any debugging, use @samp{max-remote-debug none}. The default is @samp{abnormal,chat,handshake}; to turn off these default entries, you must use @samp{max-remote-debug none} followed by other @code{max-remote-debug} commands specifying the settings you want. @end table @node Default sys File Values, , Miscellaneous (sys), sys File @subsection Default sys File Values The following are used as default values for all systems; they can be considered as appearing before the start of the file. @example time Never chat "" \r\c ogin:-BREAK-ogin:-BREAK-ogin: \L word: \P chat-timeout 10 callback n sequence n request y transfer y local-send / remote-send ~ local-receive ~ remove-receive ~ command-path [ from @file{policy.h} ] commands rnews rmail max-remote-debug abnormal,chat,handshake @end example @node port File, dial File, sys File, Configuration Files @section The Port Configuration File @cindex port file @cindex port configuration file @cindex configuration file (port) The port files may be used to name and describe ports. Any commands in the file before the first @code{port} command specify defaults for all ports in the file. All commands after a @code{port} command up to the next @code{port} command then describe that port. There are different types of ports; each type supports its own set of commands. Each command indicates which types of ports support it. There may be many ports with the same name; if a system requests a port by name then each port with that name will be tried until an unlocked one is found. @table @code @item port @var{string} @findex port in port file Introduces and names a port. @item type @var{string} @findex type Define the type of port. The default is @samp{modem}. If this command appears, it must immediately follow the @code{port} command. The type defines what commands are subsequently allowed. Currently the types are: @table @samp @item modem For a modem hookup. @item stdin For a connection through standard input and standard output, as when @code{uucico} is run as a login shell. @item direct For a direct connection to another system. @item tcp For a connection using TCP. @item tli For a connection using TLI. @end table @item protocol @var{string} @findex protocol in port file Specify a list of protocols to use for this port. This is just like the corresponding command for a system (@pxref{Protocol Selection}). A protocol list for a system takes precedence over a list for a port. @item protocol-parameter @var{character} @var{strings} [ any type ] @findex protocol-parameter in port file The same command as the @code{protocol-parameter} command used for systems (@pxref{Protocol Selection}). This one takes precedence. @item seven-bit @var{boolean} [ any type ] @findex seven-bit in port file This is only used during protocol negotiation; if the argument is true, it forces the selection of a protocol which works across a seven-bit link. It does not prevent eight bit characters from being transmitted. The default is false. @item reliable @var{boolean} [ any type ] @findex reliable in port file This is only used during protocol negotiation; if the argument is false, it forces the selection of a protocol which works across an unreliable communication link. The default is true. It would be more common to specify this for a dialer rather than a port. @item half-duplex @var{boolean} [ any type ] @findex half-duplex in port file If the argument is true, it means that the port only supports half-duplex connections. This only affects bidirectional protocols, and causes them to not do bidirectional transfers. @item device @var{string} [ modem, direct and tli only ] @findex device Names the device associated with this port. If the device is not named, the port name is taken as the device. Device names are system dependent. On Unix, a modem or direct connection might be something like @file{/dev/ttyd0}; a TLI port might be @file{/dev/inet/tcp}. @item baud @var{number} [ modem and direct only ] @findex baud in port file @itemx speed @var{number} [modem and direct only ] @findex speed in port file The speed this port runs at. If a system specifies a speed but no port name, then all ports which match the speed will be tried in order. If the speed is not specified here and is not specified by the system, the natural speed of the port will be used by default. @item baud-range @var{number} @var{number} [ modem only ] @findex baud-range @itemx speed-range @var{number} @var{number} [ modem only ] @findex speed-range Specify a range of speeds this port can run at. The first number is the minimum speed, the second number is the maximum speed. These numbers will be used when matching a system which specifies a desired speed. The simple @code{speed} (or @code{baud}) command is still used to determine the speed to run at if the system does not specify a speed. For example, the command @samp{speed-range 300 19200} means that the port will match any system which uses a speed from 300 to 19200 baud (and will use the speed specified by the system); this could be combined with @samp{speed 2400}, which means that when this port is used with a system that does not specify a speed, the port will be used at 2400 baud. @item carrier @var{boolean} [ modem only ] @findex carrier in port file The argument indicates whether the port supports carrier. If it does not, carrier will never be required on this port, regardless of what the modem chat script indicates. The default is true. @item dial-device @var{string} [ modem only ] @findex dial-device Dialing instructions should be output to the named device, rather than to the normal port device. The default is to output to the normal port device. @item dialer @var{string} [ modem only ] @findex dialer in port file Name a dialer to use. The information is looked up in the dialer file. There is no default. Some sort of dialer information must be specified to call out on a modem. @item dialer @var{string} @dots{} [ modem only ] Execute a dialer command. If a dialer is named (by using the first form of this command, described just above), these commands are ignored. They may be used to specify dialer information directly in simple situations without needing to go to a separate file. There is no default. Some sort of dialer information must be specified to call out on a modem. @item dialer-sequence @var{strings} [ modem or tli only ] @findex dialer-sequence Name a sequence of dialers and tokens (phone numbers) to use. The first argument names a dialer, and the second argument names a token. The third argument names another dialer, and so on. If there are an odd number of arguments, the phone number specified with a @code{phone} command in the system file is used as the final token. The token is what is used for @kbd{\D} or @kbd{\T} in the dialer chat script. If the token in this string is @kbd{\D}, the system phone number will be used; if it is @kbd{\T}, the system phone number will be used after undergoing dialcodes translation. A missing final token is taken as @kbd{\D}. This command currently does not work if @code{dial-device} is specified; to handle this correctly will require a more systematic notion of chat scripts. Moreover, only the @code{complete} and @code{abort} chat scripts from the first dialer specified are used, and only the protocol parameters from the first dialer are used. This command basically lets you specify a sequence of chat scripts to use. For example, the first dialer might get you to a local network and the second dialer might describe how to select a machine from the local network. This lets you break your dialing sequence into simple modules, and may make it easier to share dialer entries between machines. When this command is used with a TLI port, then if the first dialer is @samp{TLI} or @samp{TLIS} the first token is used as the address to connect to. If the first dialer is something else, or if there is no token, the address given by the @code{address} command is used (@pxref{Placing the Call}). Escape sequences in the address are expanded as they are for chat script expect strings (@pxref{Chat Scripts}). The different between @samp{TLI} and @samp{TLIS} is that the latter implies the command @samp{stream true}. These contortions are all for HDB compatibility. Any subsequent dialers are treated as they are for a modem. @item lockname @var{string} [ modem and direct only ] @findex lockname Give the name to use when locking this port. On Unix, this is the name of the file that will be created in the lock directory. It is used as is, so on Unix it should generally start with @samp{LCK..}. For example, if a single port were named both @file{/dev/ttycu0} and @file{/dev/tty0} (perhaps with different characteristics keyed on the minor device number), then the command @code{lockname LCK..ttycu0} could be used to force the latter to use the same lock file name as the former. @item service @var{string} [ tcp only ] @findex service Name the TCP port number to use. This may be a number. If not, it will be looked up in @file{/etc/services}. If this is not specified, the string @samp{uucp} is looked up in @file{/etc/services}. If it is not found, port number 540 (the standard UUCP-over-TCP port number) will be used. @item push @var{strings} [ tli only ] @findex push Give a list of modules to push on to the TLI stream. @item stream @var{boolean} [ tli only ] @findex stream If this is true, and the @code{push} command was not used, the @samp{tirdwr} module is pushed on to the TLI stream. @item server-address @var{string} [ tli only ] Give the address to use when running as a TLI server. Escape sequences in the address are expanded as they are for chat script expect strings (@pxref{Chat Scripts}). @end table @node dial File, Security, port File, Configuration Files @section The Dialer Configuration File @cindex dial file @cindex dialer configuration file @cindex configuration file (dial) The dialer configuration files define dialers. Any commands in the file before the first @code{dialer} command specify defaults for all the dialers in the file. All commands after a @code{dialer} command up to the next @code{dialer} command are associated with the named dialer. @table @code @item dialer @var{string} @findex dialer in dial file Introduces and names a dialer. @item chat @var{strings} @findex chat in dial file @item chat-timeout @var{number} @findex chat-timeout in dial file @item chat-fail @var{string} @findex chat-fail in dial file @item chat-seven-bit @var{boolean} @findex chat-seven-bit in dial file @item chat-program @var{strings} @findex chat-program in dial file Specify a chat script to be used to dial the phone. See @ref{Chat Scripts} for full details on chat scripts. Taylor UUCP will sleep for one second between attempts to dial out on a modem. If your modem requires a longer wait period, you must start your chat script with delays (@samp{\d} in a send string). The chat script will be read from and sent to the port specified by the @code{dial-device} command for the port, if there is one. The following escape addition escape sequences may appear in send strings: @table @kbd @item \D send phone number without dialcode translation @item \T send phone number with dialcode translation @item \M do not require carrier @item \m require carrier (fail if not present) @end table See the description of the dialcodes file (@pxref{Configuration File Names}) for a description of dialcode translation. If the port does not support carrier (as set by the @code{carrier} command in the port file) @kbd{\M} and @kbd{\m} are ignored. If both the port and the dialer support carrier (as set by the @code{carrier} command in the port file and the @code{carrier} command in the dialer file), then every chat script implicitly begins with @kbd{\M} and ends with @kbd{\m}. There is no default chat script for dialers. The following additional escape sequences may be used in @code{chat-program}: @table @kbd @item \D phone number without dialcode translation @item \T phone number with dialcode translation @end table If the program changes the port in any way (e.g., sets parity) the changes will be preserved during protocol negotiation, but once the protocol is selected it will change the port settings. @item dialtone @var{string} @findex dialtone A string to output when dialing the phone number which causes the modem to wait for a secondary dial tone. This is used to translate the @kbd{=} character in a phone number. The default is a comma. @item pause @var{string} @findex pause A string to output when dialing the phone number which causes the modem to wait for 1 second. This is used to translate the @kbd{-} character in a phone number. The default is a comma. @item carrier @var{boolean} @findex carrier in dial file If the argument is true, the dialer supports the modem carrier signal. After the phone number is dialed, @code{uucico} will require that carrier be on. One some systems, it will be able to wait for it. If the argument is false, carrier will not be required. The default is true. @item carrier-wait @var{number} @findex carrier-wait If the port is supposed to wait for carrier, this may be used to indicate how many seconds to wait. The default is 60 seconds. Only some systems support waiting for carrier. @item dtr-toggle @var{boolean} @var{boolean} @findex dtr-toggle If the first argument is true, then DTR is toggled before using the modem. This is only supported on some systems and some ports. The second @var{boolean} need not be present; if it is, and it is true, the program will sleep for 1 second after toggling DTR. The default is not to toggle DTR. @item complete-chat @var{strings} @findex complete-chat @item complete-chat-timeout @var{number} @findex complete-chat-timeout @item complete-chat-fail @var{string} @findex complete-chat-fail @item complete-chat-seven-bit @var{boolean} @findex complete-chat-seven-bit @item complete-chat-program @var{strings} @findex complete-chat-program These commands define a chat script (@pxref{Chat Scripts}) which is run when a call is finished normally. This allows the modem to be reset. There is no default. No additional escape sequences may be used. @item complete @var{string} @findex complete This is a simple use of @code{complete-chat}. It is equivalent to @code{complete-chat "" @var{string}}; this has the effect of sending @var{string} to the modem when a call finishes normally. @item abort-chat @var{strings} @findex abort-chat @item abort-chat-timeout @var{number} @findex abort-chat-timeout @item abort-chat-fail @var{string} @findex abort-chat-fail @item abort-chat-seven-bit @var{boolean} @findex abort-chat-seven-bit @item abort-chat-program @var{strings} @findex abort-chat-program These commands define a chat script (@pxref{Chat Scripts}) to be run when a call is aborted. They may be used to interrupt and reset the modem. There is no default. No additional escape sequences may be used. @item abort @var{string} @findex abort This is a simple use of @code{abort-chat}. It is equivalent to @code{abort-chat "" @var{string}}; this has the effect of sending @var{string} to the modem when a call is aborted. @item protocol-parameter @var{character} @var{strings} @findex protocol-parameter in dial file Set protocol parameters, just like the @code{protocol-parameter} command in the system configuration file or the port configuration file; see @ref{Protocol Selection}. These parameters take precedence, then those for the port, then those for the system. @item seven-bit @var{boolean} @findex seven-bit in dial file This is only used during protocol negotiation; if it is true, it forces selection of a protocol which works across a seven-bit link. It does not prevent eight bit characters from being transmitted. The default is false. It would be more common to specify this for a port than for a dialer. @item reliable @var{boolean} @findex reliable in dial file This is only used during protocol negotiation; if it is false, it forces selection of a protocol which works across an unreliable communication link. The default is true. @item half-duplex @var{boolean} [ any type ] @findex half-duplex in dial file If the argument is true, it means that the dialer only supports half-duplex connections. This only affects bidirectional protocols, and causes them to not do bidirectional transfers. @end table @node Security, , dial File, Configuration Files @section Security This discussion of UUCP security applies only to Unix. It is a bit cursory; suggestions for improvement are solicited. UUCP is traditionally not very secure. Taylor UUCP addresses some security issues, but is still far from being a secure system. If security is very important to you, then you should not permit any external access to your computer, including UUCP. Any opening to the outside world is a potential security risk. By default Taylor UUCP provides few mechanisms to secure local users of the system from each other. You can allow increased security by putting the owner of the UUCP programs (normally @code{uucp}) into a separate group; the use of this is explained in the following paragraphs, which refer to this separate group as @code{uucp-group}. When the @code{uucp} program is invoked to copy a file to a remote system, it will by default copy the file into the UUCP spool directory. When the @code{uux} program is used, the @samp{-C} switch must be used to copy the file into the UUCP spool directory. In any case, once the file has been copied into the spool directory, other local users will not be able to access it. When a file is requested from a remote system, UUCP will only permit it to be placed in a directory which is writable by the requesting user. The directory must also be writable by UUCP. A local user can create a directory with a group of @code{uucp-group} and set the mode to permit group write access. This will allow the file be requested without permitting it to be viewed by any other user. There is no provision for security for @code{uucp} requests (as opposed to @code{uux} requests) made by a user on a remote system. A file sent over by a remote request may only be placed in a directory which is world writable, and the file will be world readable and writable. This will permit any local user to destroy or replace the contents of the file. A file requested by a remote system must be world readable, and the directory it is in must be world readable. Any local user will be able to examine, although not necessarily modify, the file before it is sent. There are some security holes and race conditions that apply to the above discussion which I will not elaborate on. They are not hidden from anybody who reads the source code, but they are somewhat technical and difficult (though scarcely impossible) to exploit. Suffice it to say that even under the best of conditions UUCP is not completely secure. For many sites, security from remote sites is a more important consideration. Fortunately, Taylor UUCP does provide some support in this area. The greatest security is provided by always dialing out to the other site. This prevents anybody from pretending to be the other site. Of course, only one side of the connection can do this. If remote dialins must be permitted, then it is best if the dialin line is used only for UUCP. If this is the case, then you should create a call-in password file (@pxref{Configuration File Names}) and let @code{uucico} do its own login prompting. For example, to let remote sites log in on a port named @samp{entry} in the port file (@pxref{port File}) you might invoke @samp{uucico -p entry}. This would cause @code{uucico} to enter an endless loop of login prompts and daemon executions. The advantage of this approach is that even if remote users break into the system by guessing or learning the password, they will only be able to do whatever @code{uucico} permits them to do. They will not be able to start a shell on your system. If remote users can dial in and log on to your system, then you have a security hazard more serious than that posed by UUCP. But then, you probably knew that already. Once your system has connected with the remote UUCP, there is a fair amount of control you can exercise. You can use the @code{remote-send} and @code{remote-receive} commands to control the directories the remote UUCP can access. You can use the @code{request} command to prevent the remote UUCP from making any requests of your system at all; however, if you do this it will not even be able to send you mail or news. If you do permit remote requests, you should be careful to restrict what commands may be executed at the remote system's request. The default is @code{rmail} and @code{rnews}, which will suffice for most systems. If different remote systems call in and they must be granted different privileges (perhaps some systems are within the same organization and some are not) then the @code{called-login} command should be used for each system to require that they different login names. Otherwise it would be simple for a remote system to use the @code{myname} command and pretend to be a different system. The @code{sequence} command can be used to detect when one system pretended to be another, but since the sequence numbers must be reset manually after a failed handshake this can sometimes be more trouble than it's worth. @node Protocols, Hacking, Configuration Files, Top @chapter UUCP protocol internals This chapter describes how the various UUCP protocols work, and discusses some other internal UUCP issues. This chapter is quite technical. You do not need to understand it, or even read it, in order to use Taylor UUCP. It is intended for people who are interested in how UUCP code works. This chapter is also, unfortunately, somewhat out of date, although I believe that is incomplete rather than inaccurate. I post this information to the newsgroups @samp{comp.mail.uucp} and @samp{news.answers} each month; if you want to write code based on this information, please get the most recent copy. Most of the discussion covers the protocols used by all UUCP packages, not just Taylor UUCP. Any information specific to Taylor UUCP is indicated as such. There are some pointers to the actual functions in the Taylor UUCP source code, for those who are extremely interested in actual UUCP implementation. @menu * Grades:: UUCP grades * Lock Files:: UUCP lock file format * UUCP Protocol:: The common UUCP protocol * g Protocol:: The UUCP @samp{g} protocol * f Protocol:: The UUCP @samp{f} protocol * t Protocol:: The UUCP @samp{t} protocol * e Protocol:: The UUCP @samp{e} protocol * x Protocol:: The UUCP @samp{x} protocol * d Protocol:: The UUCP @samp{d} protocol * Capital G Protocol:: The UUCP @samp{G} protocol * Documentation References:: Documentation references @end menu @node Grades, Lock Files, Protocols, Protocols @section UUCP Grades @cindex grades Modern UUCP packages support grades for each command. The grades generally range from @samp{A} (the highest) to @samp{Z} followed by @samp{a} to @samp{z}. Taylor UUCP also supports @samp{0} to @samp{9} before @samp{A}. Some UUCP packages may permit any ASCII character as a grade. On Unix, these grades are encoded in the name of the command file. A command file name generally has the form @example C.nnnngssss @end example @noindent where @var{nnnn} is the remote system name for which the command is queued, @var{g} is a single character grade, and @var{ssss} is a four character sequence number. For example, a command file created for the system @file{airs} at grade @samp{Z} might be named @example C.airsZ2551 @end example The remote system name will be truncated to seven characters, to ensure that the command file name will fit in the 14 character file name limit of the traditional Unix file system. UUCP packages which have no other means of distinguishing which command files are intended for which systems thus require all @emph{systems they connect to} to have names that are unique in the first seven characters. Some UUCP packages use a variant of this format which truncates the system name to six characters. HDB uses a different spool directory format, which allows up to fourteen characters to be used for each system name. The Taylor UUCP spool directory format is configurable. The new Taylor spool directory format permits system names to be as long as file names; the maximum length of a file name depends on the particular Unix file system being used. The sequence number in the command file name may be a decimal integer, or it may be a hexadecimal integer, or it may contain any alphanumeric character. Different UUCP packages are different. Taylor UUCP creates command files in the function @code{zsysdep_spool_commands}. The file name is constructed by the function @code{zsfile_name}, which knows about all the different types of spool directories supported by Taylor UUCP. The Taylor UUCP sequence number can contain any alphanumeric character; the next sequence number is determined by the function @code{fscmd_seq}. I do not know how command grades are handled in non-Unix UUCP packages. Modern UUCP packages allow you to restrict file transfer by grade depending on the time of day. Typically this is done with a line in the @file{Systems} (or @file{L.sys}) file like this: @example airs Any/Z,Any2305-0855 ... @end example This allows only grades @samp{Z} and above to be transferred at any time. Lower grades may only be transferred at night. I believe that this grade restriction applies to local commands as well as to remote commands, but I am not sure. It may only apply if the UUCP package places the call, not if it is called by the remote system. Taylor UUCP can use the @code{timegrade} and @code{call-timegrade} commands (@pxref{When to Call}) to achieve the same effect (and supports the above format when reading @file{Systems} or @file{L.sys}). This sort of grade restriction is most useful if you know what grades are being used at the remote site. The default grades used depend on the UUCP package. Generally @code{uucp} and @code{uux} have different defaults. A particular grade can be specified with the @samp{-g} option to @code{uucp} or @code{uux}. For example, to request execution of rnews on airs with grade @samp{d}, you might use something like @example uux -gd - airs!rnews
= 128}, let @code{b2} be the second byte in the data field. Then there are @code{l - ((b1 & 0x7f) + (b2 << 7))} valid bytes of data in the data field, beginning with the third byte. In all cases @code{l} bytes of data are sent (and all data bytes participate in the checksum calculation) but some of the trailing bytes may be dropped by the receiver. The @var{xxx} and @var{yyy} fields are described below. @end table In a data packet (short or not) the @var{xxx} field gives the sequence number of the packet. Thus sequence numbers can range from 0 to 7, inclusive. The @var{yyy} field gives the sequence number of the last correctly received packet. Each communication direction uses a window which indicates how many unacknowledged packets may be transmitted before waiting for an acknowledgement. The window may range from 1 to 7 packets, and may be different in each direction. For example, if the window is 3 and the last packet acknowledged was packet number 6, packet numbers 7, 0 and 1 may be sent but the sender must wait for an acknowledgement before sending packet number 2. This acknowledgement could come as the @var{yyy} field of a data packet or as the @var{yyy} field of a @code{RJ} or @code{RR} control packet (described below). Each packet must be transmitted in order (the sender may not skip sequence numbers). Each packet must be acknowledged, and each packet must be acknowledged in order. In a control packet, the @var{xxx} field takes on the following values: @table @asis @item 1 @code{CLOSE} The connection should be closed immediately. This is typically sent when one side has seen too many errors and wants to give up. It is also sent when shutting down the protocol. If an unexpected @code{CLOSE} packet is received, a @code{CLOSE} packet should be sent in reply and the @samp{g} protocol should halt, causing UUCP to enter the final handshake. @item 2 @code{RJ} or @code{NAK} The last packet was not received correctly. The @var{yyy} field contains the sequence number of the last correctly received packet. @item 3 @code{SRJ} Selective reject. The @var{yyy} field contains the sequence number of a packet that was not received correctly, and should be retransmitted. This is not used by UUCP, and most implementations will not recognize it. Taylor UUCP will recognize it but not generate it. @item 4 @code{RR} or @code{ACK} Packet acknowledgement. The @var{yyy} field contains the sequence number of the last correctly received packet. @item 5 @code{INITC} Third initialization packet. The @var{yyy} field contains the maximum window size to use. @item 6 @code{INITB} @ifinfo Second initialization packet. The @var{yyy} field contains the packet size to use. It requests a size of 2 ** (@var{yyy} + 5). Note that this is not the same coding used for the @var{k} byte in the packet header (it is 1 less). Some UUCP implementations can handle any packet size up to that specified; some can only handled exactly the size specified. Taylor UUCP will always accept any packet size. @end ifinfo @iftex Second initialization packet. The @var{yyy} field contains the packet size to use. It requests a size of @math{2^{@var{yyy}+5}}. Note that this is not the same coding used for the @var{k} byte in the packet header (it is 1 less). Some UUCP implementations can handle any packet size up to that specified; some can only handled exactly the size specified. Taylor UUCP will always accept any packet size. @end iftex @item 7 @code{INITA} First initialization packet. The @var{yyy} field contains the maximum window size to use. @end table To compute the checksum, call the control byte (the fifth byte in the header) @code{c}. The checksum of a control packet is simply @code{0xaaaa - c}. The checksum of a data packet is @code{0xaaaa - (@var{check} ^ c)} (@code{^} denotes exclusive or, as in C), and @code{@var{check}} is the result of the following routine run on the contents of the data field (every byte in the data field participates in the checksum, even for a short data packet). Below is the routine used by Taylor UUCP; it is a slightly modified version of a routine which John Gilmore patched from G.L. Chesson's original paper. The @code{z} argument points to the data and the @code{c} argument indicates how much data there is. @example int igchecksum (z, c) register const char *z; register int c; @{ register unsigned int ichk1, ichk2; ichk1 = 0xffff; ichk2 = 0; do @{ register unsigned int b; /* Rotate ichk1 left. */ if ((ichk1 & 0x8000) == 0) ichk1 <<= 1; else @{ ichk1 <<= 1; ++ichk1; @} /* Add the next character to ichk1. */ b = *z++ & 0xff; ichk1 += b; /* Add ichk1 xor the character position in the buffer counting from the back to ichk2. */ ichk2 += ichk1 ^ c; /* If the character was zero, or adding it to ichk1 caused an overflow, xor ichk2 to ichk1. */ if (b == 0 || (ichk1 & 0xffff) < b) ichk1 ^= ichk2; @} while (--c > 0); return ichk1 & 0xffff; @} @end example When the @samp{g} protocol is started, the calling UUCP sends an INITA control packet with the window size it wishes the called UUCP to use. The called UUCP responds with an INITA packet with the window size it wishes the calling UUCP to use. Pairs of INITB and INITC packets are then similarly exchanged. When these exchanges are completed, the protocol is considered to have been started. The window size is sent twice, with both the INITA and the INITC packets. When a UUCP package transmits a command, it sends one or more data packets. All the data packets will normally be complete, although some UUCP packages may send the last one as a short packet. The command string is sent with a trailing null byte, to let the receiving package know when the command is finished. Some UUCP packages require the last byte of the last packet sent to be null, even if the command ends earlier in the packet. Some packages may require all the trailing bytes in the last packet to be null, but I have not confirmed this. When a UUCP package sends a file, it will send a sequence of data packets. The end of the file is signalled by a short data packet containing zero valid bytes (it will normally be preceeded by a short data packet containing the last few bytes in the file). Note that the sequence numbers cover the entire communication session, including both command and file data. When the protocol is shut down, each UUCP package sends a @code{CLOSE} control packet. @node f Protocol, t Protocol, g Protocol, Protocols @section The UUCP @samp{f} Protocol @cindex f protocol @cindex protocol (f) The @samp{f} protocol is a seven bit protocol which checksums an entire file at a time. It only uses the characters between \040 and \176 (ASCII space and @samp{~}) inclusive as well as the carriage return character. It can be very efficient for transferring text only data, but it is very inefficient at transferring eight bit data (such as compressed news). It is not flow controlled, and the checksum is fairly insecure over large files, so using it over a serial connection requires handshaking (@code{XON}/@code{XOFF} can be used) and error correcting modems. Some people think it should not be used even under those circumstances. I believe the @samp{f} protocol originated in BSD versions of UUCP. It was originally intended for transmission over X.25 PAD links. The Taylor UUCP code for the @samp{f} protocol is in @file{protf.c}. The @samp{f} protocol has no startup or finish protocol. However, both sides typically sleep for a couple of seconds before starting up, because they switch the terminal into @code{XON}/@code{XOFF} mode and want to allow the changes to settle before beginning transmission. When a UUCP package transmits a command, it simply sends a string terminated by a carriage return. When a UUCP package transmits a file, each byte b of the file is translated according to the following table: @example 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) @end example That is, a byte between \040 and \171 inclusive is transmitted as is, and all other bytes are prefixed and modified as shown. When all the file data is sent, a seven byte sequence is sent: two bytes of \176 followed by four ASCII bytes of the checksum as printed in base 16 followed by a carriage return. For example, if the checksum was 0x1234, this would be sent: "\176\1761234\r". The checksum is initialized to 0xffff. For each byte that is sent it is modified as follows (where @code{b} is the byte before it has been transformed as described above): @example /* Rotate the checksum left. */ if ((ichk & 0x8000) == 0) ichk <<= 1; else @{ ichk <<= 1; ++ichk; @} /* Add the next byte into the checksum. */ ichk += b; @end example When the receiving UUCP sees the checksum, it compares it against its own calculated checksum and replies with a single character followed by a carriage return. @table @samp @item G The file was received correctly. @item R The checksum did not match, and the file should be resent from the beginning. @item Q The checksum did not match, but too many retries have occurred and the communication session should be abandoned. @end table The sending UUCP checks the returned character and acts accordingly. @node t Protocol, e Protocol, f Protocol, Protocols @section The UUCP @samp{t} Protocol @cindex t protocol @cindex protocol (t) The @samp{t} protocol is intended for TCP links. It does no error checking or flow control, and requires an eight bit clear channel. I believe the @samp{t} protocol originated in BSD versions of UUCP. The Taylor UUCP code for the @samp{t} protocol is in @file{prott.c}. When a UUCP package transmits a command, it first gets the length of the command string, @var{c}. It then sends ((@var{c} / 512) + 1) * 512 bytes (the smallest multiple of 512 which can hold @var{c} bytes plus a null byte) consisting of the command string itself followed by trailing null bytes. When a UUCP package sends a file, it sends it in blocks. Each block contains at most 1024 bytes of data. Each block consists of four bytes containing the amount of data in binary (most significant byte first, the same format as used by the Unix function @code{htonl}) followed by that amount of data. The end of the file is signalled by a block containing zero bytes of data. @node e Protocol, x Protocol, t Protocol, Protocols @section The UUCP @samp{e} Protocol @cindex e protocol @cindex protocol (e) The @samp{e} protocol is similar to the @samp{t} protocol. It does no flow control or error checking and is intended for use over TCP. The @samp{e} protocol originated in versions of HDB UUCP. The Taylor UUCP code for the @samp{e} protocol is in @file{prote.c}. When a UUCP package transmits a command, it simply sends the command as an ASCII string terminated by a null byte. When a UUCP package transmits a file, it sends the complete size of the file as an ASCII decimal number. The ASCII string is padded out to 20 bytes with null bytes (i.e., if the file is 1000 bytes long, it sends @samp{1000\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0}). It then sends the entire file. @node x Protocol, d Protocol, e Protocol, Protocols @section The UUCP @samp{x} Protocol I believe that the @samp{x} protocol was intended for use over X.25 virtual circuits. It relies on a write of zero bytes being read as zero bytes without stopping communication. I have heard that it does not work correctly. If someone would care to fill this in more, I would be grateful. Taylor UUCP does not implement the @samp{x} protocol. @node d Protocol, Capital G Protocol, x Protocol, Protocols @section The UUCP @samp{d} Protocol This is apparently used for DataKit connections, and relies on a write of zero bytes being read as zero bytes, much as the @samp{x} protocol does. I don't really know anything else about it. Taylor UUCP does not implement the @samp{d} protocol. @node Capital G Protocol, Documentation References, d Protocol, Protocols @section The UUCP @samp{G} Protocol The @samp{G} protocol is apparently simply the @samp{g} protocol, except that it is known to support all possible window and packet sizes. It was introduced by SVR4 UUCP; the SVR4 implementation of the @samp{g} protocol is apparently fixed at a packet size of 64 and a window size of 7. Taylor UUCP does not recognize the @samp{G} protocol. It does support all window and packet sizes for the @samp{g} protocol. @node Documentation References, , Capital G Protocol, Protocols @section Documentation References I took a lot of the information from Jamie E. Hanrahan's paper in the Fall 1990 DECUS Symposium, and from Managing UUCP and Usenet by Tim O'Reilly and Grace Todino (with contributions by several other people). The latter includes most of the former, and is published by O'Reilly & Associates, Inc. Some information is originally due to a Usenet article by Chuck Wegrzyn. The information on the @samp{g} protocol comes partially from a paper by G.L. Chesson of Bell Laboratories, partially from Jamie E. Hanrahan's paper, and partially from source code by John Gilmore. The information on the @samp{f} protocol comes from the source code by Piet Berteema. The information on the @samp{t} protocol comes from the source code by Rick Adams. The information on the @samp{e} protocol comes from a Usenet article by Matthias Urlichs. @node Hacking, Acknowledgements, Protocols, Top @chapter Hacking Taylor UUCP This chapter provides the briefest of guides to the Taylor UUCP source code itself. @menu * System Dependence:: System Dependence * Naming Conventions:: Naming Conventions * Patches:: Patches @end menu @node System Dependence, Naming Conventions, Hacking, Hacking @section System Dependence The code is carefully segregated into a system independent portion and a system dependent portion. The system dependent code is in the @file{unix} subdirectory, and also in the files @file{tcp.c}, @file{tli.c} and @file{sysh.unx} (also known as @file{sysdep.h}). With the right configuration parameters, the system independent code calls only ANSI C functions. Some of the less common ANSI C functions are also provided in the @file{lib} directory. The replacement function @code{strtol} in @file{lib/strtol.c} assumes that the characters @kbd{A} to @kbd{F} and @kbd{a} to @kbd{f} appear in strictly sequential order. The function @code{igradecmp} in @file{uuconf/grdcmp.c} assumes that the upper and lower case letters appear in order. Both assumptions are true for ASCII and EBCDIC, but neither is guaranteed by ANSI C. Disregarding these caveats, I believe that the system independent portion of the code is strictly conforming. That's not too exciting, since all the work is done in the system dependent code. I think that this code can conform to POSIX 1003.1, given the right compilation parameters. I'm a bit less certain about this, though. The code is in use on a 16 bit segmented system with no function prototypes, so I'm certain that all casts to long and pointers are done when necessary. @node Naming Conventions, Patches, System Dependence, Hacking @section Naming Conventions I use a modified Hungarian naming convention for my variables and functions. As with all naming conventions, the code is rather opaque if you are not familiar with it, but becomes clear and easy to use with time. The first character indicates the type of the variable (or function return value). Sometimes additional characters are used. I use the following type prefixes: @table @samp @item a array; the next character is the type of an element @item b byte or character @item c count of something @item e stdio FILE * @item f boolean @item i generic integer @item l double @item o file descriptor (as returned by open, creat, etc.) @item p generic pointer @item q pointer to structure @item s structure @item u void (function return values only) @item z character string @end table A generic pointer ('p') is sometimes a @code{void *}, sometimes a function pointer in which case the prefix is pf, and sometimes a pointer to another type, in which case the next character is the type to which it points (pf is overloaded). An array of strings (@code{char *[]}) would be named @code{az} (array of string). If this array were passed to a function, the function parameter would be named @code{paz} (pointer to array of string). Note that the variable name prefixes do not necessarily indicate the type of the variable. For example, a variable prefixed with i may be int, long or short. Similarly, a variable prefixed with b may be a char or an int; for example, the return value of getchar would be caught in an int variable prefixed with b. For a non-local variable (extern or file static), the first character after the type prefix is capitalized. Most static variables and functions use another letter after the type prefix to indicate which module they come from. This is to help distinguish different names in the debugger. For example, all static functions in @file{protg.c}, the @samp{g} protocol source code, use a module prefix of @samp{g}. This isn't too useful, as a number of modules use a module prefix of @samp{s}. @node Patches, , Naming Conventions, Hacking @section Patches I am always grateful for any patches sent in. Much of the flexibility and portability of the code is due to other people. Please do not hesitate to send me any changes you have found necessary or useful. When sending a patch, please send the output of the Unix @code{diff} program invoked with the @samp{-c} option (if you have the GNU version of @code{diff}, use the @samp{-p} option). Always invoke @code{diff} with the original file first and the modified file second. If your @code{diff} does not support @samp{-c} (or you don't have @code{diff}), send a complete copy of the modified file (if you have just changed a single function, you can just send the new version of the function). In particular, please do not send @code{diff} output without the @samp{-c} option, as it is useless. If you have made a number of changes, it is very convenient for me if you send each change as a separate mail message. Sometimes I will think that one change is useful but another one is not. If they are in different messages it is much easier for me to apply one but not the other. I rarely apply the patches directly. Instead I work my way through the hunks and apply each one separately. This ensures that the naming remains consistent, and that I understand all the code. If you can not follow all these rules, then don't. But if you do, it makes it more likely that I will incorporate your changes. I am not paid for my UUCP work, and my available time is unfortunately very restricted. The package is important to me, and I do what I can, but I can not do all that I would like, much less all that everybody else would like. Finally, please do not be offended if I do not reply to messages for some time, even a few weeks. I am often behind on my mail, and if I think your message deserves a considered reply I will often put it aside until I have time to deal with it. @node Acknowledgements, Index (concepts), Hacking, Top @chapter Acknowledgements This is a list of people who gave help or suggestions while I was working on the Taylor UUCP project. Appearance on this list does not constitute endorsement of the program, particularly since some of the comments were criticisms. I've probably left some people off, and I apologize for any oversight; it does not mean your contribution was unappreciated. @ifinfo First of all, I would like to thank the people at Infinity Development Systems (formerly AIRS, which lives on in the domain name, at least for now) for permitting me to use their computers and @file{uunet} access. I would also like to thank Richard Stallman @code{} for founding the Free Software Foundation and John Gilmore @code{} for writing the initial version of gnuucp which was a direct inspiration for this somewhat larger project. Chip Salzenberg @code{} has contributed many patches. Franc,ois Pinard @code{} tirelessly tested the code and suggested many improvements. He also put together the initial version of this document. Doug Evans contributed the zmodem protocol. Finally, Verbus M. Counts @code{} and Centel Federal Systems, Inc. deserve special thanks, since they actually paid me money to port this code to System III. @end ifinfo @iftex First of all, I would like to thank the people at Infinity Development Systems (formerly AIRS, which lives on in the domain name, at least for now) for permitting me to use their computers and @file{uunet} access. I would also like to thank Richard Stallman @code{} for founding the Free Software Foundation and John Gilmore @code{} for writing the initial version of gnuucp which was a direct inspiration for this somewhat larger project. Chip Salzenberg @code{} has contributed many patches. @tex Fran\c cois Pinard @end tex @code{} tirelessly tested the code and suggested many improvements. He also put together the initial version of this document. Doug Evans contributed the zmodem protocol. Finally, Verbus M. Counts @code{} and Centel Federal Systems, Inc. deserve special thanks, since they actually paid me money to port this code to System III. @end iftex In alphabetical order: @example "Earle F. Ake - SAIC" @code{} @code{mra@@searchtech.com} (Michael Almond) @code{cambler@@zeus.calpoly.edu} (Christopher J. Ambler) Brian W. Antoine @code{} @code{jantypas@@soft21.s21.com} (John Antypas) @code{nba@@sysware.DK} (Niels Baggesen) @code{uunet!hotmomma!sdb} (Scott Ballantyne) Zacharias Beckman @code{} @code{mike@@mbsun.ann-arbor.mi.us} (Mike Bernson) @code{bob@@usixth.sublink.org} (Roberto Biancardi) @code{statsci!scott@@coco.ms.washington.edu} (Scott Blachowicz) @code{bag%wood2.cs.kiev.ua@@relay.ussr.eu.net} (Andrey G Blochintsev) Gregory Bond @code{} Marc Boucher @code{} @code{dean@@coplex.com} (Dean Brooks) @code{dave@@dlb.com} (Dave Buck) @code{gordon@@sneaky.lonestar.org} (Gordon Burditt) @code{mib@@gnu.ai.mit.edu} (Michael I Bushnell) Brian Campbell @code{} Andrew A. Chernov @code{} @code{mafc!frank@@bach.helios.de} (Frank Conrad) Ed Carp @code{} @code{verbus@@westmark.westmark.com} (Verbus M. Counts) @code{cbmvax!snark.thyrsus.com!cowan} (John Cowan) Bob Cunningham @code{} @code{hubert@@arakis.fdn.org} (Hubert Delahaye) @code{denny@@dakota.alisa.com} (Bob Denny) @code{ssd@@nevets.oau.org} (Steven S. Dick) @code{gert@@greenie.gold.sub.org} (Gert Doering) Hans-Dieter Doll @code{} Andrew Evans @code{} @code{dje@@cygnus.com} (Doug Evans) Marc Evans @code{} @code{kksys!kegworks!lfahnoe@@cs.umn.edu} (Larry Fahnoe) @code{fenner@@jazz.psu.edu} (Bill Fenner) "David J. Fiander" @code{} Thomas Fischer @code{} @code{erik@@eab.retix.com} (Erik Forsberg) Lele Gaifax @code{} @code{Peter.Galbavy@@micromuse.co.uk} @code{hunter@@phoenix.pub.uu.oz.au} (James Gardiner [hunter]) Terry Gardner @code{} @code{ol@@infopro.spb.su} (Oleg Girko) @code{jimmy@@tokyo07.info.com} (Jim Gottlieb) @code{ryan@@cs.umb.edu} (Daniel R. Guilderson) @code{greg@@gagme.chi.il.us} (Gregory Gulik) Richard H. Gumpertz @code{} Michael Haberler @code{} @code{jh@@moon.nbn.com} (John Harkin) @code{guy@@auspex.auspex.com} (Guy Harris) Petri Helenius @code{} Bob Hemedinger @code{} Andrew Herbert @code{} Peter Honeyman @code{} @code{pmcgw!personal-media.co.jp!ishikawa} (Chiaki Ishikawa) @code{bei@@dogface.austin.tx.us} (Bob Izenberg) Rob Janssen @code{} @code{harvee!esj} (Eric S Johansson) Alan Judge @code{} @code{chris@@cj_net.in-berlin.de} (Christof Junge) @code{tron@@Veritas.COM} (Ronald S. Karr) Brendan Kehoe @code{} @code{kersing@@nlmug.nl.mugnet.org} (Jac Kersing) @code{rob@@pact.nl} (Rob Kurver) @code{kent@@sparky.IMD.Sterling.COM} (Kent Landfield) @code{lebaron@@inrs-telecom.uquebec.ca} (Gregory LeBaron) @code{karl@@sugar.NeoSoft.Com} (Karl Lehenbauer) @code{merlyn@@digibd.com} (Merlyn LeRoy) @code{clewis@@ferret.ocunix.on.ca} (Chris Lewis) @code{gdonl@@ssi1.com} (Don Lewis) @code{libove@@libove.det.dec.com} (Jay Vassos-Libove) @code{bruce%blilly@@Broadcast.Sony.COM} (Bruce Lilly) Ted Lindgreen @code{} @code{andrew@@cubetech.com} (Andrew Loewenstern) "Arne Ludwig" @code{} Matthew Lyle @code{} @code{djm@@eng.umd.edu} (David J. MacKenzie) John R MacMillan @code{} Giles D Malet @code{} @code{mem@@mv.MV.COM} (Mark E. Mallett) @code{pepe@@dit.upm.es} (Jose A. Manas) @code{martelli@@cadlab.sublink.org} (Alex Martelli) Yanek Martinson @code{} @code{jm@@aristote.univ-paris8.fr} (Jean Mehat) @code{les@@chinet.chi.il.us} (Leslie Mikesell) @code{mmitchel@@digi.lonestar.org} (Mitch Mitchell) @code{rmohr@@infoac.rmi.de} (Rupert Mohr) @code{ianm@@icsbelf.co.uk} (Ian Moran) @code{brian@@ilinx.wimsey.bc.ca} (Brian J. Murrell) @code{service@@infohh.rmi.de} (Dirk Musstopf) @code{lyndon@@cs.athabascau.ca} (Lyndon Nerenberg) @code{rolf@@saans.north.de} (Rolf Nerstheimer) @code{tom@@smart.bo.open.de} (Thomas Neumann) @code{mnichols@@pacesetter.com} @code{nolan@@helios.unl.edu} (Michael Nolan) david nugent @code{} Petri Ojala @code{} @code{abekas!dragoman!mikep@@decwrl.dec.com} (Mike Park) Tim Peiffer @code{peiffer@@cs.umn.edu} @code{don@@blkhole.resun.com} (Don Phillips) "Mark Pizzolato 415-369-9366" @code{} @code{dplatt@@ntg.com} (Dave Platt) @code{eldorado@@tharr.UUCP} (Mark Powell) Mark Powell @code{} @code{pozar@@kumr.lns.com} (Tim Pozar) @code{putsch@@uicc.com} (Jeff Putsch) Jarmo Raiha @code{} Scott Reynolds @code{} @code{mcr@@Sandelman.OCUnix.On.Ca} (Michael Richardson) @code{arnold@@cc.gatech.edu} (Arnold Robbins) @code{ross@@sun490.fdu.edu} (Jeff Ross) Aleksey P. Rudnev @code{} "Heiko W.Rupp" @code{} @code{wolfgang@@wsrcc.com} (Wolfgang S. Rupprecht) @code{tbr@@tfic.bc.ca} (Tom Rushworth) @code{rsalz@@bbn.com} (Rich Salz) @code{sojurn!mike@@hobbes.cert.sei.cmu.edu} (Mike Sangrey) Nickolay Saukh @code{} Eric Schnoebelen @code{} @code{scott@@geom.umn.edu} Igor V. Semenyuk @code{} @code{uunet!gold.sub.org!root} (Christian Seyb) @code{s4mjs!mjs@@nirvo.nirvonics.com} (M. J. Shannon Jr.) @code{peter@@ficc.ferranti.com} (Peter da Silva) @code{frumious!pat} (Patrick Smith) @code{roscom!monty@@bu.edu} (Monty Solomon) Harlan Stenn @code{} Ralf Stephan @code{} @code{chs@@antic.apu.fi} (Hannu Strang) @code{ralf@@reswi.ruhr.de} (Ralf E. Stranzenbach) Shigeya Suzuki @code{} @code{swiers@@plains.NoDak.edu} Oleg Tabarovsky @code{} John Theus @code{} Karsten Thygesen @code{} Graham Toal @code{} @code{rmtodd@@servalan.servalan.com} (Richard Todd) Len Tower @code{} Mark Towfiq @code{} @code{mju@@mudos.ann-arbor.mi.us} (Marc Unangst) Tomi Vainio @code{} @code{vogel@@omega.ssw.de} (Andreas Vogel) @code{jv@@mh.nl} (Johan Vromans) @code{steve@@nshore.org} (Stephen J. Walick) @code{gerben@@rna.indiv.nluug.nl} (Gerben Wierda) @code{frnkmth!twwells.com!bill} (T. William Wells) Peter Wemm @code{} @code{mauxci!eci386!woods@@apple.com} (Greg A. Woods) Michael Yu.Yaroslavtsev @code{} @code{jon@@console.ais.org} (Jon Zeeff) Matthias Zepf @code{} Eric Ziegast @code{} @end example @node Index (concepts), Index (configuration file), Acknowledgements, Top @unnumbered Concept Index @printindex cp @node Index (configuration file), , Index (concepts), Top @unnumbered Configuration File Index @printindex fn @contents @bye se rules, then don't. But if you do, it makes it more likely that I will incorporate your changes. I am not paid for my UUCP work, and my available time is unfortunately very restricted. The package is important to me, and I do what I can, but I can not do all that I would like, much less all that everybody else would like. Finally, please do not be offended if I do not reply to messages for some time, even a few weeks. I am often behiuucp-1.04/uudefs.h1004440004150000170000003571205337263526011043 037777777777 1 0 /* 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)); n iDebug. We only check for prefixes, so these namuucp-1.04/uudir.c1004440004150000170000000624505337263526010672 037777777777 1 0 /* uudir.c Create a directory owned by uucp. This is Unix specific. 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. */ #if USE_RCS_ID const char uudir_rcsid[] = "$Id: uudir.c,v 1.3 1992/08/24 04:58:40 ian Rel $"; #endif #include "sysdep.h" #include /* External functions. */ #if GETPWNAM_DECLARATION_OK #ifndef getpwnam extern struct passwd *getpwnam (); #endif #endif /* This is a simple program which sets its real uid to uucp and then invokes /bin/mkdir. It is only used if the system does not support the mkdir system call. It must be installed suid to root. This program is needed because the UUCP programs will be run suid to uucp. On a system without the mkdir system call, /bin/mkdir is a suid root program. This means that /bin/mkdir always creates directories using the real uid, rather than the effective uid. This is wrong, since the UUCP programs always want to create directories that are owned by uucp. Therefore, this simple suid root program is used to force /bin/mkdir into making a directory owned by uucp. If we made the program publically executable, this would mean that anybody could create a directory owned by uucp. This is probably not a good thing, but since the program must be owned by root we can't simply make it executable only by uucp. Therefore, the Makefile hides the program away in /usr/lib/uucp/util, and makes that directory searchable only by uucp. This should prevent anybody else from getting to the program. This is not a perfect solution, since any suid root program is by definition a potential security hole. I really can't see any way to avoid this, though. */ int main (argc, argv) int argc; char **argv; { struct passwd *q; const char *zprog, *zname; /* We don't print any error messages, since this program should never be run directly by a user. */ if (argc != 2) exit (EXIT_FAILURE); /* OWNER is passed in from the Makefile. It will normally be "uucp". */ q = getpwnam (OWNER); if (q == NULL) exit (EXIT_FAILURE); if (setuid (q->pw_uid) < 0) exit (EXIT_FAILURE); zprog = MKDIR_PROGRAM; zname = strrchr (zprog, '/'); if (zname == NULL) zname = zprog; else ++zname; (void) execl (zprog, zname, argv[1], (char *) NULL); exit (EXIT_FAILURE); } olean 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 GNUCuucp-1.04/uulog.c1004440004150000170000002410705337263527010673 037777777777 1 0 /* 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.11 1992/12/17 05:23:00 ian Rel $"; #endif #include #include #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* This is a pretty bad implementation of uulog, which I don't think is a very useful program anyhow. It only takes a single -s and/or -u switch. When using HAVE_HDB_LOGGING it requires a system. */ /* The program name. */ char abProgram[] = "uulog"; /* Local functions. */ static void ulusage P((void)); /* Long getopt options. */ static const struct option asLlongopts[] = { { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* -D: display Debug file */ boolean fdebug = FALSE; /* -f: keep displaying lines forever. */ boolean fforever = FALSE; /* -n lines: number of lines to display. */ int cshow = 0; /* -s: system name. */ const char *zsystem = NULL; /* -S: display Stats file */ boolean fstats = FALSE; /* -u: user name. */ const char *zuser = NULL; /* -I: configuration file name. */ const char *zconfig = NULL; /* -x: display uuxqt log file. */ boolean fuuxqt = FALSE; int i; int iopt; pointer puuconf; int iuuconf; const char *zlogfile; const char *zstatsfile; const char *zdebugfile; const char *zfile; FILE *e; char **pzshow = NULL; int ishow = 0; size_t csystem = 0; size_t cuser = 0; char *zline; size_t cline; /* Look for a straight number argument, and convert it to -n before passing the arguments to getopt. */ for (i = 0; i < argc; i++) { if (argv[i][0] == '-' && isdigit (argv[i][1])) { size_t clen; char *znew; clen = strlen (argv[i]); znew = zbufalc (clen + 2); znew[0] = '-'; znew[1] = 'n'; memcpy (znew + 2, argv[i] + 1, clen); argv[i] = znew; } } while ((iopt = getopt_long (argc, argv, "Df:FI:n:s:Su:xX:", asLlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'D': /* Show debugging file. */ fdebug = TRUE; break; case 'f': /* Keep displaying lines forever for a particular system. */ fforever = TRUE; zsystem = optarg; if (cshow == 0) cshow = 10; break; case 'F': /* Keep displaying lines forever. */ fforever = TRUE; if (cshow == 0) cshow = 10; break; case 'I': /* Configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'n': /* Number of lines to display. */ cshow = (int) strtol (optarg, (char **) NULL, 10); break; case 's': /* System name. */ zsystem = optarg; break; case 'S': /* Show statistics file. */ fstats = TRUE; break; case 'u': /* User name. */ zuser = optarg; break; case 'x': /* Display uuxqt log file. */ fuuxqt = TRUE; break; case 'X': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 0: /* Long option found and flag set. */ break; default: ulusage (); break; } } if (optind != argc || (fstats && fdebug)) ulusage (); iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif iuuconf = uuconf_logfile (puuconf, &zlogfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); iuuconf = uuconf_statsfile (puuconf, &zstatsfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); iuuconf = uuconf_debugfile (puuconf, &zdebugfile); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); usysdep_initialize (puuconf, 0); if (zsystem != NULL) { #if HAVE_HDB_LOGGING if (strcmp (zsystem, "ANY") != 0) #endif { struct uuconf_system ssys; iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); ulog (LOG_FATAL, "%s: System not found", zsystem); } zsystem = zbufcpy (ssys.uuconf_zname); (void) uuconf_system_free (puuconf, &ssys); } } if (fstats) zfile = zstatsfile; else if (fdebug) zfile = zdebugfile; else { #if ! HAVE_HDB_LOGGING zfile = zlogfile; #else const char *zprogram; char *zalc; /* We need a system to find a HDB log file. */ if (zsystem == NULL) ulusage (); if (fuuxqt) zprogram = "uuxqt"; else zprogram = "uucico"; zalc = zbufalc (strlen (zlogfile) + strlen (zprogram) + strlen (zsystem) + 1); sprintf (zalc, zlogfile, zprogram, zsystem); zfile = zalc; if (strcmp (zsystem, "ANY") == 0) zsystem = NULL; #endif } e = fopen (zfile, "r"); if (e == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); usysdep_exit (FALSE); } if (cshow > 0) { pzshow = (char **) xmalloc (cshow * sizeof (char *)); for (ishow = 0; ishow < cshow; ishow++) pzshow[ishow] = NULL; ishow = 0; } /* Read the log file and output the appropriate lines. */ if (zsystem != NULL) csystem = strlen (zsystem); if (zuser != NULL) cuser = strlen (zuser); zline = NULL; cline = 0; while (TRUE) { while (getline (&zline, &cline, e) > 0) { char *zluser, *zlsys, *znext; size_t cluser, clsys; /* Skip any leading whitespace (not that there should be any). */ znext = zline + strspn (zline, " \t"); if (! fstats) { #if ! HAVE_TAYLOR_LOGGING /* The user name is the first field on the line. */ zluser = znext; cluser = strcspn (znext, " \t"); #endif /* Skip the first field. */ znext += strcspn (znext, " \t"); znext += strspn (znext, " \t"); /* The system is the second field on the line. */ zlsys = znext; clsys = strcspn (znext, " \t"); /* Skip the second field. */ znext += clsys; znext += strspn (znext, " \t"); #if HAVE_TAYLOR_LOGGING /* The user is the third field on the line. */ zluser = znext; cluser = strcspn (znext, " \t"); #endif } else { #if ! HAVE_HDB_LOGGING /* The user name is the first field on the line, and the system name is the second. */ zluser = znext; cluser = strcspn (znext, " \t"); znext += cluser; znext += strspn (znext, " \t"); zlsys = znext; clsys = strcspn (znext, " \t"); #else /* The first field is system!user. */ zlsys = znext; clsys = strcspn (znext, "!"); znext += clsys + 1; zlsys = znext; clsys = strcspn (znext, " \t"); #endif } /* See if we should print this line. */ if (zsystem != NULL && (csystem != clsys || strncmp (zsystem, zlsys, clsys) != 0)) continue; if (zuser != NULL && (cuser != cluser || strncmp (zuser, zluser, cluser) != 0)) continue; /* Output the line, or save it if we are outputting only a particular number of lines. */ if (cshow <= 0) printf ("%s", zline); else { ubuffree ((pointer) pzshow[ishow]); pzshow[ishow] = zbufcpy (zline); ishow = (ishow + 1) % cshow; } } /* Output the number of lines requested by the -n option. */ if (cshow > 0) { for (i = 0; i < cshow; i++) { if (pzshow[ishow] != NULL) printf ("%s", pzshow[ishow]); ishow = (ishow + 1) % cshow; } } /* If -f was not specified, or an error occurred while reading the file, get out. */ if (! fforever || ferror (e)) break; clearerr (e); cshow = 0; /* Sleep 1 second before going around the loop again. */ usysdep_sleep (1); } (void) fclose (e); ulog_close (); usysdep_exit (TRUE); /* Avoid errors about not returning a value. */ return 0; } /* Print a usage message and die. */ static void ulusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uulog [-n #] [-sf system] [-u user] [-xDSF] [-I file] [-X debug]\n"); fprintf (stderr, " -n: show given number of lines from end of log\n"); fprintf (stderr, " -s: print entries for named system\n"); fprintf (stderr, " -f: follow entries for named system\n"); fprintf (stderr, " -u: print entries for named user\n"); #if HAVE_HDB_LOGGING fprintf (stderr, " -x: print uuxqt log rather than uucico log\n"); #else fprintf (stderr, " -F: follow entries for any system\n"); #endif fprintf (stderr, " -S: show statistics file\n"); fprintf (stderr, " -D: show debugging file\n"); fprintf (stderr, " -X debug: Set debugging level (0 for none, 9 is max)\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } an 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 uucp-1.04/uuname.c1004440004150000170000001046405337263527011033 037777777777 1 0 /* 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.12 1992/10/07 04:20:18 ian Rel $"; #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); } f, &ssys); } } if (fstats) zfile = zstatsfile; else if (fdebug) zfile = zdebugfile; else { #if ! HAVE_HDB_LOGGING zfile = zlogfile; #else const char *zprogram; chuucp-1.04/uupick.c1004440004150000170000001572705337263527011050 037777777777 1 0 /* 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.5 1992/12/17 05:30:06 ian Rel $"; #endif #include #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* Local functions. */ static void upmovedir P((const char *zfull, const char *zrelative, pointer pinfo)); static void upmove P((const char *zfrom, const char *zto)); /* The program name. */ char abProgram[] = "uupick"; /* Long getopt options. */ static const struct option asPlongopts[] = { { NULL, 0, NULL, 0 } }; /* Local functions. */ static void upusage P((void)); int main (argc, argv) int argc; char **argv; { /* -s: system name. */ const char *zsystem = NULL; /* -I: configuration file name. */ const char *zconfig = NULL; int iopt; pointer puuconf; int iuuconf; struct uuconf_system ssys; const char *zpubdir; char *zfile, *zfrom, *zfull; char *zallsys; char ab[1000]; boolean fquit; while ((iopt = getopt_long (argc, argv, "I:s:x:", asPlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 's': /* System name to get files from. */ zsystem = optarg; break; case 'I': /* Name configuration file. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 0: /* Long option found and flag set. */ break; default: upusage (); break; } } if (argc != optind) upusage (); iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); usysdep_initialize (puuconf, INIT_GETCWD | INIT_NOCHDIR); zpubdir = NULL; if (zsystem != NULL) { iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); if (iuuconf == UUCONF_SUCCESS) { zpubdir = zbufcpy (ssys.uuconf_zpubdir); (void) uuconf_system_free (puuconf, &ssys); } else if (iuuconf != UUCONF_NOT_FOUND) (void) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } if (zpubdir == NULL) { iuuconf = uuconf_pubdir (puuconf, &zpubdir); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } if (! fsysdep_uupick_init (zsystem, zpubdir)) usysdep_exit (FALSE); zallsys = NULL; fquit = FALSE; while (! fquit && ((zfile = zsysdep_uupick (zsystem, zpubdir, &zfrom, &zfull)) != NULL)) { boolean fdir; char *zto, *zlocal; FILE *e; boolean fcontinue; fdir = fsysdep_directory (zfull); do { fcontinue = FALSE; if (zallsys == NULL || strcmp (zallsys, zfrom) != 0) { if (zallsys != NULL) { ubuffree (zallsys); zallsys = NULL; } printf ("from %s: %s %s ?\n", zfrom, fdir ? "dir" : "file", zfile); if (fgets (ab, sizeof ab, stdin) == NULL) break; } if (ab[0] == 'q') { fquit = TRUE; break; } switch (ab[0]) { case '\n': break; case 'd': if (fdir) (void) fsysdep_rmdir (zfull); else { if (remove (zfull) != 0) ulog (LOG_ERROR, "remove (%s): %s", zfull, strerror(errno)); } break; case 'm': case 'a': zto = ab + 1 + strspn (ab + 1, " \t"); zto[strcspn (zto, " \t\n")] = '\0'; zlocal = zsysdep_uupick_local_file (zto); if (zlocal == NULL) usysdep_exit (FALSE); zto = zsysdep_in_dir (zlocal, zfile); ubuffree (zlocal); if (zto == NULL) usysdep_exit (FALSE); if (! fdir) upmove (zfull, zto); else { usysdep_walk_tree (zfull, upmovedir, (pointer) zto); (void) fsysdep_rmdir (zfull); } ubuffree (zto); if (ab[0] == 'a') { zallsys = zbufcpy (zfrom); ab[0] = 'm'; } break; case 'p': if (fdir) ulog (LOG_ERROR, "Can't print directory"); else { e = fopen (zfull, "r"); if (e == NULL) ulog (LOG_ERROR, "fopen (%s): %s", zfull, strerror (errno)); else { while (fgets (ab, sizeof ab, e) != NULL) (void) fputs (ab, stdout); (void) fclose (e); } } fcontinue = TRUE; break; case '!': (void) system (ab + 1); fcontinue = TRUE; break; default: printf ("uupick commands:\n"); printf ("q: quit\n"); printf (": skip file\n"); printf ("m [dir]: move file to directory\n"); printf ("a [dir]: move all files from this system to directory\n"); printf ("p: list file to stdout\n"); printf ("! command: shell escape\n"); fcontinue = TRUE; break; } } while (fcontinue); ubuffree (zfull); ubuffree (zfrom); ubuffree (zfile); } (void) fsysdep_uupick_free (zsystem, zpubdir); usysdep_exit (TRUE); /* Avoid error about not returning. */ return 0; } /* Print usage message. */ static void upusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uupick [-s system] [-I config] [-x debug]\n"); fprintf (stderr, " -s system: Only consider files from named system\n"); fprintf (stderr, " -x debug: Set debugging level\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* This routine is called by usysdep_walk_tree when moving the contents of an entire directory. */ static void upmovedir (zfull, zrelative, pinfo) const char *zfull; const char *zrelative; pointer pinfo; { const char *ztodir = (const char *) pinfo; char *zto; zto = zsysdep_in_dir (ztodir, zrelative); if (zto == NULL) usysdep_exit (FALSE); upmove (zfull, zto); ubuffree (zto); } /* Move a file. */ static void upmove (zfrom, zto) const char *zfrom; const char *zto; { (void) fsysdep_move_file (zfrom, zto, TRUE, TRUE, FALSE, (const char *) NULL); } flocal = TRUE; break; case 'I': uucp-1.04/uusched.in1004440004150000170000000045005337263527011357 037777777777 1 0 : # 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 $* ocal) { const char *zlocalname; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) usysuucp-1.04/uustat.11004440004150000170000002155505337263530011001 037777777777 1 0 ''' $Id: uustat.1,v 1.7 1993/01/24 00:59:14 ian Rel $ .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) uucp-1.04/uustat.c1004440004150000170000014647005337263532011071 037777777777 1 0 /* 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.32 1992/12/17 04:43:27 ian Rel $"; #endif #include #include #if HAVE_TIME_H #include #endif #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* The uustat program permits various listings and manipulations of files in the spool directory. This implementation supports the following switches: -a list all jobs -Blines number of lines of standard input to mail -ccommand list only executions of specified command -Ccommand list only jobs other than executions of specified command -e list execute jobs rather than command requests -i ask user whether to kill each listed job -Ifile set configuration file name -kjobid kill job with specified ID -K kill each listed job -m report status for all remote machines -M mail uucp about each job killed with -K -N mail requestor about each job killed with -K -ohour report jobs older than specified number of hours -p do "ps -flp" on all processes holding lock files (Unix specific) -q list number of jobs for all systems -Q don't list jobs, just do -K processing -rjobid rejuvenate job with specified ID -ssystem report on all jobs for specified system -Ssystem report on all jobs other than for specified system -uuser report on all jobs for specified user -Uuser report on all jobs other than for specified user -Wcomment comment to include in mail messages -xdebug set debugging level -yhour report jobs younger than specified number of hours */ /* The program name. */ char abProgram[] = "uustat"; /* What to do with a job that matches the selection criteria; these values may be or'red together. */ #define JOB_SHOW (01) #define JOB_INQUIRE (02) #define JOB_KILL (04) #define JOB_MAIL (010) #define JOB_NOTIFY (020) /* This structure is used to accumulate all the lines in a single command file, so that they can all be displayed at once and so that executions can be displayed reasonably. */ struct scmdlist { struct scmdlist *qnext; struct scmd s; long itime; }; /* Local functions. */ static void ususage P((void)); static boolean fsxqt_file_read P((pointer puuconf, const char *zfile)); static void usxqt_file_free P((void)); static int isxqt_cmd P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int isxqt_file P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int isxqt_user P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static boolean fsworkfiles P((pointer puuconf, int icmd, int csystems, char **pazsystems, boolean fnotsystems, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsworkfiles_system P((pointer puuconf,int icmd, const struct uuconf_system *qsys, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsworkfile_show P((pointer puuconf, int icmd, const struct uuconf_system *qsys, const struct scmd *qcmd, long itime, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static void usworkfile_header P((const struct uuconf_system *qsys, const struct scmd *qcmd, const char *zjobid, long itime, boolean ffirst)); static boolean fsexecutions P((pointer puuconf, int icmd, int csystems, char **pazsystems, boolean fnotsystems, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsnotify P((pointer puuconf, int icmd, const char *zcomment, int cstdin, boolean fkilled, const char *zcmd, struct scmdlist *qcmd, const char *zid, const char *zuser, const struct uuconf_system *qsys, const char *zstdin, pointer pstdinseq, const char *zrequestor)); static boolean fsquery P((pointer puuconf)); static int csunits_show P((long idiff)); static boolean fsmachines P((void)); /* Long getopt options. */ static const struct option asSlongopts[] = { { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* -a: list all jobs. */ boolean fall = FALSE; /* -B lines: number of lines of standard input to mail. */ int cstdin = 100; /* -c,-C command: list only specified command. */ int ccommands = 0; char **pazcommands = NULL; boolean fnotcommands = FALSE; /* -e: list execute jobs. */ boolean fexecute = FALSE; /* -k jobid: kill specified job. */ int ckills = 0; char **pazkills = NULL; /* -m: report machine status. */ boolean fmachine = FALSE; /* -o hour: report jobs older than given number of hours. */ int ioldhours = -1; /* -p: report status of jobs holding lock files. */ boolean fps = FALSE; /* -q: list number of jobs for each system. */ boolean fquery = FALSE; /* -r jobid: rejuvenate specified job. */ int crejuvs = 0; char **pazrejuvs = NULL; /* -s,-S system: list all jobs for specified system. */ int csystems = 0; char **pazsystems = NULL; boolean fnotsystems = FALSE; /* -u,-U user: list all jobs for specified user. */ int cusers = 0; char **pazusers = NULL; boolean fnotusers = FALSE; /* -W comment: comment to include in mail messages. */ const char *zcomment = NULL; /* -y hour: report jobs younger than given number of hours. */ int iyounghours = -1; /* -I file: set configuration file. */ const char *zconfig = NULL; /* -Q, -i, -K, -M, -N: what to do with each job. */ int icmd = JOB_SHOW; int ccmds; int iopt; pointer puuconf; int iuuconf; long iold; long iyoung; const char *azoneuser[1]; boolean fret; while ((iopt = getopt_long (argc, argv, "aB:c:C:eiI:k:KmMNo:pqQr:s:S:u:U:W:x:y:", asSlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'a': /* List all jobs. */ fall = TRUE; break; case 'B': /* Number of lines of standard input to mail. */ cstdin = (int) strtol (optarg, (char **) NULL, 10); break; case 'C': /* List jobs for other than specified command. */ fnotcommands = TRUE; /* Fall through. */ case 'c': /* List specified command. */ ++ccommands; pazcommands = (char **) xrealloc ((pointer) pazcommands, ccommands * sizeof (char *)); pazcommands[ccommands - 1] = optarg; break; case 'e': /* List execute jobs. */ fexecute = TRUE; break; case 'i': /* Prompt the user whether to kill each job. */ icmd |= JOB_INQUIRE; break; case 'I': /* Set configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'k': /* Kill specified job. */ ++ckills; pazkills = (char **) xrealloc ((pointer) pazkills, ckills * sizeof (char *)); pazkills[ckills - 1] = optarg; break; case 'K': /* Kill each listed job. */ icmd |= JOB_KILL; break; case 'm': /* Report machine status. */ fmachine = TRUE; break; case 'M': /* Mail to uucp action taken on each job. */ icmd |= JOB_MAIL; break; case 'N': /* Mail to requestor action taken on each job. */ icmd |= JOB_NOTIFY; break; case 'o': /* Report old jobs. */ ioldhours = (int) strtol (optarg, (char **) NULL, 10); break; case 'p': /* Get status of processes holding locks. */ fps = TRUE; break; case 'q': /* List number of jobs for each system. */ fquery = TRUE; break; case 'Q': /* Don't list jobs, just do -K processing. */ icmd &=~ JOB_SHOW; break; case 'r': /* Rejuvenate specified job. */ ++crejuvs; pazrejuvs = (char **) xrealloc ((pointer) pazrejuvs, crejuvs * sizeof (char *)); pazrejuvs[crejuvs - 1] = optarg; break; case 'S': /* List jobs for other than specified system. */ fnotsystems = TRUE; /* Fall through. */ case 's': /* List jobs for specified system. */ ++csystems; pazsystems = (char **) xrealloc ((pointer) pazsystems, csystems * sizeof (char *)); pazsystems[csystems - 1] = optarg; break; case 'U': /* List jobs for other than specified user. */ fnotusers = TRUE; /* Fall through. */ case 'u': /* List jobs for specified user. */ ++cusers; pazusers = (char **) xrealloc ((pointer) pazusers, cusers * sizeof (char *)); pazusers[cusers - 1] = optarg; break; case 'W': /* Comment to include in mail messages. */ zcomment = optarg; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 'y': /* List jobs younger than given number of hours. */ iyounghours = (int) strtol (optarg, (char **) NULL, 10); break; case 0: /* Long option found and flag set. */ break; default: ususage (); break; } } if (optind != argc) ususage (); /* To avoid confusion, most options are only permitted by themselves. This restriction might be removed later, but it is imposed by most implementations. We do permit any combination of -c, -s, -u, -o and -y, and any combination of -k and -r. */ ccmds = 0; if (fall) ++ccmds; if (ckills > 0 || crejuvs > 0) ++ccmds; if (fmachine) ++ccmds; if (fps) ++ccmds; if (fquery) ++ccmds; if (fexecute || csystems > 0 || cusers > 0 || ioldhours != -1 || iyounghours != -1 || ccommands > 0) ++ccmds; if (ccmds > 1) { ulog (LOG_ERROR, "Too many options"); ususage (); } iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif usysdep_initialize (puuconf, INIT_SUID); /* If no commands were specified, we list all commands for the given user. */ if (ccmds == 0) { cusers = 1; azoneuser[0] = zsysdep_login_name (); pazusers = (char **) azoneuser; } /* Canonicalize the system names. */ if (csystems > 0) { int i; for (i = 0; i < csystems; i++) { struct uuconf_system ssys; iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_FATAL, "%s: System not found", pazsystems[i]); else ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } if (strcmp (pazsystems[i], ssys.uuconf_zname) != 0) pazsystems[i] = zbufcpy (ssys.uuconf_zname); (void) uuconf_system_free (puuconf, &ssys); } } if (ioldhours == -1) iold = (long) -1; else { iold = (ixsysdep_time ((long *) NULL) - (long) ioldhours * (long) 60 * (long) 60); if (iold < 0L) iold = 0L; } if (iyounghours == -1) iyoung = (long) -1; else { iyoung = (ixsysdep_time ((long *) NULL) - (long) iyounghours * (long) 60 * (long) 60); if (iyoung < 0L) iyoung = 0L; } if (! fexecute && (fall || csystems > 0 || cusers > 0 || ioldhours != -1 || iyounghours != -1 || ccommands > 0)) fret = fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin); else if (fexecute) fret = fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin); else if (icmd != JOB_SHOW) { ulog (LOG_ERROR, "-i, -K, -M, -N, -Q not supported with -k, -m, -p, -q, -r"); ususage (); fret = FALSE; } else if (fquery) fret = fsquery (puuconf); else if (fmachine) fret = fsmachines (); else if (ckills > 0 || crejuvs > 0) { int i; fret = TRUE; for (i = 0; i < ckills; i++) if (! fsysdep_kill_job (puuconf, pazkills[i])) fret = FALSE; for (i = 0; i < crejuvs; i++) if (! fsysdep_rejuvenate_job (puuconf, pazrejuvs[i])) fret = FALSE; } else if (fps) fret = fsysdep_lock_status (); else { #if DEBUG > 0 ulog (LOG_FATAL, "Can't happen"); #endif fret = FALSE; } ulog_close (); usysdep_exit (fret); /* Avoid errors about not returning a value. */ return 0; } /* Print a usage message and die. */ static void ususage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uustat [options]\n"); fprintf (stderr, " -a: list all UUCP jobs\n"); fprintf (stderr, " -B num: number of lines to return in -M or -N mail message\n"); fprintf (stderr, " -c command: list requests for named command\n"); fprintf (stderr, " -C command: list requests for other than named command\n"); fprintf (stderr, " -e: list queued executions rather than job requests\n"); fprintf (stderr, " -i: prompt for whether to kill each listed job\n"); fprintf (stderr, " -k job: kill specified UUCP job\n"); fprintf (stderr, " -K: kill each listed job\n"); fprintf (stderr, " -m: report status for all remote machines\n"); fprintf (stderr, " -M: mail report on each listed job to UUCP administrator\n"); fprintf (stderr, " -N: mail report on each listed job to requestor\n"); fprintf (stderr, " -o hours: list all jobs older than given number of hours\n"); fprintf (stderr, " -p: show status of all processes holding UUCP locks\n"); fprintf (stderr, " -q: list number of jobs for each system\n"); fprintf (stderr, " -Q: don't list jobs, just take actions (-i, -K, -M, -N)\n"); fprintf (stderr, " -r job: rejuvenate specified UUCP job\n"); fprintf (stderr, " -s system: list all jobs for specified system\n"); fprintf (stderr, " -S system: list all jobs for other than specified system\n"); fprintf (stderr, " -u user: list all jobs for specified user\n"); fprintf (stderr, " -U user: list all jobs for other than specified user\n"); fprintf (stderr, " -W comment: comment to include in mail messages\n"); fprintf (stderr, " -y hours: list all jobs younger than given number of hours\n"); fprintf (stderr, " -x debug: Set debugging level (0 for none, 9 is max)\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* We need to be able to read information from an execution file. */ /* The user name extracted from an execution file. */ static char *zSxqt_user; /* The system name from an execution file. */ static char *zSxqt_system; /* Address of requesting user (who to send mail to). */ static const char *zSxqt_requestor; /* The command (no arguments) from an execution file. */ static char *zSxqt_prog; /* The full command line from an execution file. */ static char *zSxqt_cmd; /* Number of files associated with an execution file. */ static int cSxqt_files; /* Names of files associated with execution file. */ static char **pazSxqt_files; /* Standard input file name. */ static const char *zSxqt_stdin; /* A command table used to dispatch an execution file. */ static const struct uuconf_cmdtab asSxqt_cmds[] = { { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_cmd }, { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_stdin, NULL }, { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_file }, { "R", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_requestor, NULL }, { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, isxqt_user }, { NULL, 0, NULL, NULL } }; /* Read an execution file, setting the above variables. */ static boolean fsxqt_file_read (puuconf, zfile) pointer puuconf; const char *zfile; { FILE *e; int iuuconf; boolean fret; e = fopen (zfile, "r"); if (e == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); return FALSE; } zSxqt_user = NULL; zSxqt_system = NULL; zSxqt_stdin = NULL; zSxqt_requestor = NULL; zSxqt_prog = NULL; zSxqt_cmd = NULL; cSxqt_files = 0; pazSxqt_files = NULL; iuuconf = uuconf_cmd_file (puuconf, e, asSxqt_cmds, (pointer) NULL, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_CASE, (pointer) NULL); (void) fclose (e); if (iuuconf == UUCONF_SUCCESS) fret = TRUE; else { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; } if (zSxqt_user == NULL) zSxqt_user = zbufcpy ("*unknown*"); if (zSxqt_system == NULL) zSxqt_system = zbufcpy ("*unknown*"); if (zSxqt_prog == NULL) { zSxqt_prog = zbufcpy ("*none*"); zSxqt_cmd = zbufcpy ("*none*"); } return fret; } /* Free up the information read from an execution file. */ static void usxqt_file_free () { int i; ubuffree (zSxqt_user); zSxqt_user = NULL; ubuffree (zSxqt_system); zSxqt_system = NULL; ubuffree (zSxqt_prog); zSxqt_prog = NULL; ubuffree (zSxqt_cmd); zSxqt_cmd = NULL; for (i = 0; i < cSxqt_files; i++) ubuffree (pazSxqt_files[i]); cSxqt_files = 0; xfree ((pointer) pazSxqt_files); pazSxqt_files = NULL; zSxqt_stdin = NULL; zSxqt_requestor = NULL; } /* Get the command from an execution file. */ /*ARGSUSED*/ static int isxqt_cmd (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { size_t clen; int i; if (argc <= 1) return UUCONF_CMDTABRET_CONTINUE; zSxqt_prog = zbufcpy (argv[1]); clen = 0; for (i = 1; i < argc; i++) clen += strlen (argv[i]) + 1; zSxqt_cmd = zbufalc (clen); zSxqt_cmd[0] = '\0'; for (i = 1; i < argc - 1; i++) { strcat (zSxqt_cmd, argv[i]); strcat (zSxqt_cmd, " "); } strcat (zSxqt_cmd, argv[i]); return UUCONF_CMDTABRET_CONTINUE; } /* Get the associated files from an execution file. */ /*ARGSUSED*/ static int isxqt_file (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { if (argc != 2 && argc != 3) return UUCONF_CMDTABRET_CONTINUE; /* If this file is not in the spool directory, just ignore it. */ if (! fspool_file (argv[1])) return UUCONF_CMDTABRET_CONTINUE; ++cSxqt_files; pazSxqt_files = (char **) xrealloc ((pointer) pazSxqt_files, cSxqt_files * sizeof (char *)); pazSxqt_files[cSxqt_files - 1] = zbufcpy (argv[1]); return UUCONF_CMDTABRET_CONTINUE; } /* Get the requesting user and system from an execution file. */ /*ARGSUSED*/ static int isxqt_user (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { zSxqt_user = zbufcpy (argv[1]); zSxqt_system = zbufcpy (argv[2]); return UUCONF_CMDTABRET_CONTINUE; } /* Handle various possible requests to look at work files. */ static boolean fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; int csystems; char **pazsystems; boolean fnotsystems; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { boolean fret; int i; int iuuconf; struct uuconf_system ssys; fret = TRUE; if (csystems > 0 && ! fnotsystems) { for (i = 0; i < csystems; i++) { iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_ERROR, "%s: System not found", pazsystems[i]); else ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); } } else { char **pznames, **pz; iuuconf = uuconf_system_names (puuconf, &pznames, 0); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } for (pz = pznames; *pz != NULL; pz++) { if (csystems > 0) { for (i = 0; i < csystems; i++) if (strcmp (*pz, pazsystems[i]) == 0) break; if (i < csystems) continue; } iuuconf = uuconf_system_info (puuconf, *pz, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); xfree ((pointer) *pz); } xfree ((pointer) pznames); } return fret; } /* Look at the work files for a particular system. */ static boolean fsworkfiles_system (puuconf, icmd, qsys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; const struct uuconf_system *qsys; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { boolean fret; if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) return FALSE; while (TRUE) { struct scmd s; long itime; if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) { usysdep_get_work_free (qsys); return FALSE; } if (s.bcmd == 'H') break; if (cusers > 0) { boolean fmatch; int i; fmatch = fnotusers; for (i = 0; i < cusers; i++) { if (s.zuser != NULL && strcmp (pazusers[i], s.zuser) == 0) { fmatch = ! fmatch; break; } } if (! fmatch) continue; } itime = ixsysdep_work_time (qsys, s.pseq); if (iold != (long) -1 && itime > iold) continue; if (iyoung != (long) -1 && itime < iyoung) continue; if (! fsworkfile_show (puuconf, icmd, qsys, &s, itime, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) { usysdep_get_work_free (qsys); return FALSE; } } fret = fsworkfile_show (puuconf, icmd, qsys, (const struct scmd *) NULL, 0L, ccommands, pazcommands, fnotcommands, zcomment, cstdin); usysdep_get_work_free (qsys); return fret; } /* Show a single workfile. This is actually called once for each line in the workfile, so we accumulate the lines and show them all at once. This lets us show an execution in a useful fashion. */ static boolean fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; const struct uuconf_system *qsys; const struct scmd *qcmd; long itime; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { static struct scmdlist *qlist; static char *zlistid; char *zid; if (qcmd == NULL) zid = NULL; else { zid = zsysdep_jobid (qsys, qcmd->pseq); if (zid == NULL) return FALSE; } /* If this is the same jobid as the list, put it on the end. */ if (qcmd != NULL && qlist != NULL && strcmp (zlistid, zid) == 0) { struct scmdlist *qnew, **pq; ubuffree (zid); qnew = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); qnew->qnext = NULL; qnew->s = *qcmd; qnew->itime = itime; for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) ; *pq = qnew; return TRUE; } /* Here we have found a different job ID, so we print the scmd structures that we have accumulated. We look for the special case of an execution (an E command, or one of the destination files begins with X.). We could be more clever about other situations as well. */ if (qlist != NULL) { boolean fmatch; const char *zprog, *zcmd, *zrequestor, *zstdin; char *zfree; struct scmdlist *qxqt; struct scmdlist *qfree; fmatch = FALSE; zprog = zcmd = zrequestor = zstdin = NULL; zfree = NULL; for (qxqt = qlist; qxqt != NULL; qxqt = qxqt->qnext) if (qxqt->s.bcmd == 'E' || (qxqt->s.bcmd == 'S' && qxqt->s.zto[0] == 'X' && qxqt->s.zto[1] == '.' && fspool_file (qxqt->s.zfrom))) break; if (qxqt == NULL) { if (ccommands == 0 || (fnotcommands && strcmp (pazcommands[0], "ALL") == 0)) { /* Show all the lines in a regular work file. */ fmatch = TRUE; if ((icmd & JOB_SHOW) != 0) { struct scmdlist *qshow; for (qshow = qlist; qshow != NULL; qshow = qshow->qnext) { char *zfile; long cbytes; usworkfile_header (qsys, &qshow->s, zlistid, qshow->itime, qshow == qlist); switch (qshow->s.bcmd) { case 'S': if (strchr (qshow->s.zoptions, 'C') != NULL || fspool_file (qshow->s.zfrom)) zfile = zsysdep_spool_file_name (qsys, qshow->s.ztemp, qshow->s.pseq); else zfile = zbufcpy (qshow->s.zfrom); if (zfile == NULL) cbytes = 0; else { cbytes = csysdep_size (zfile); if (cbytes < 0) cbytes = 0; } printf ("Sending %s (%ld bytes) to %s", qshow->s.zfrom, cbytes, qshow->s.zto); ubuffree (zfile); break; case 'R': printf ("Requesting %s to %s", qshow->s.zfrom, qshow->s.zto); break; case 'X': printf ("Requesting %s to %s", qshow->s.zfrom, qshow->s.zto); break; case 'P': printf ("(poll file)"); break; #if DEBUG > 0 default: printf ("Bad line %d", qshow->s.bcmd); break; #endif } printf ("\n"); } } } } else { long csize; struct scmdlist *qsize; /* Show the command for an execution file. */ if (qxqt->s.bcmd == 'E') { zfree = zbufcpy (qxqt->s.zcmd); zfree[strcspn (zfree, " \t")] = '\0'; zprog = zfree; zcmd = qxqt->s.zcmd; if (strchr (qxqt->s.zoptions, 'R') != NULL) zrequestor = qxqt->s.znotify; } else { char *zxqt; zxqt = zsysdep_spool_file_name (qsys, qxqt->s.zfrom, qxqt->s.pseq); if (zxqt == NULL) return FALSE; if (! fsxqt_file_read (puuconf, zxqt)) { ubuffree (zxqt); return FALSE; } ubuffree (zxqt); zprog = zSxqt_prog; zcmd = zSxqt_cmd; zrequestor = zSxqt_requestor; } csize = 0L; for (qsize = qlist; qsize != NULL; qsize = qsize->qnext) { if (qsize->s.bcmd == 'S' || qsize->s.bcmd == 'E') { char *zfile; if (strchr (qsize->s.zoptions, 'C') != NULL || fspool_file (qsize->s.zfrom)) zfile = zsysdep_spool_file_name (qsys, qsize->s.ztemp, qsize->s.pseq); else zfile = zbufcpy (qsize->s.zfrom); if (zfile != NULL) { long cbytes; cbytes = csysdep_size (zfile); if (cbytes > 0) csize += cbytes; ubuffree (zfile); } } } if (ccommands == 0) fmatch = TRUE; else { int i; fmatch = fnotcommands; for (i = 0; i < ccommands; i++) { if (strcmp (pazcommands[i], "ALL") == 0 || strcmp (pazcommands[i], zprog) == 0) { fmatch = ! fmatch; break; } } } /* To get the name of the standard input file on this system we have to look through the list of file transfers to find the right one on the remote system. */ if (fmatch) { struct scmdlist *qstdin; if (qxqt->s.bcmd == 'E') qstdin = qxqt; else if (zSxqt_stdin != NULL) { for (qstdin = qlist; qstdin != NULL; qstdin = qstdin->qnext) if (qstdin->s.bcmd == 'S' && strcmp (qstdin->s.zto, zSxqt_stdin) == 0) break; } else qstdin = NULL; if (qstdin != NULL) { if (strchr (qstdin->s.zoptions, 'C') != NULL || fspool_file (qstdin->s.zfrom)) zstdin = qstdin->s.ztemp; else zstdin = qstdin->s.zfrom; } } if (fmatch && (icmd & JOB_SHOW) != 0) { usworkfile_header (qsys, &qxqt->s, zlistid, qxqt->itime, TRUE); printf ("Executing %s (sending %ld bytes)\n", zcmd, csize); } } if (fmatch) { boolean fkill; fkill = FALSE; if ((icmd & JOB_INQUIRE) != 0) { int b; /* Ask stdin whether this job should be killed. */ fprintf (stderr, "%s: Kill %s? ", abProgram, zlistid); (void) fflush (stderr); b = getchar (); fkill = b == 'y' || b == 'Y'; while (b != EOF && b != '\n') b = getchar (); } else if ((icmd & JOB_KILL) != 0) fkill = TRUE; if (fkill && (qlist->s.zuser == NULL || strcmp (zsysdep_login_name (), qlist->s.zuser) != 0) && ! fsysdep_privileged ()) ulog (LOG_ERROR, "%s: Not submitted by you", zlistid); else { if ((icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) { if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill, zcmd, qlist, zlistid, qlist->s.zuser, qsys, zstdin, qlist->s.pseq, zrequestor)) return FALSE; } if (fkill) { if (! fsysdep_kill_job (puuconf, zlistid)) return FALSE; } } } if (qxqt != NULL) { if (qxqt->s.bcmd == 'E') ubuffree (zfree); else usxqt_file_free (); } /* Free up the list of entries. */ qfree = qlist; while (qfree != NULL) { struct scmdlist *qnext; qnext = qfree->qnext; xfree ((pointer) qfree); qfree = qnext; } ubuffree (zlistid); qlist = NULL; zlistid = NULL; } /* Start a new list with the entry we just got. */ if (qcmd != NULL) { qlist = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); qlist->qnext = NULL; qlist->s = *qcmd; qlist->itime = itime; zlistid = zid; } return TRUE; } /* Show the header of the line describing a workfile. */ static void usworkfile_header (qsys, qcmd, zjobid, itime, ffirst) const struct uuconf_system *qsys; const struct scmd *qcmd; const char *zjobid; long itime; boolean ffirst; { const char *zshowid; struct tm stime; if (ffirst) zshowid = zjobid; else zshowid = "-"; printf ("%s %s %s ", zshowid, qsys->uuconf_zname, qcmd->zuser != NULL ? qcmd->zuser : OWNER); usysdep_localtime (itime, &stime); printf ("%02d-%02d %02d:%02d ", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); } /* List queued executions that have not been processed by uuxqt for one reason or another. */ static boolean fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; int csystems; char **pazsystems; boolean fnotsystems; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { const char *zlocalname; int iuuconf; char *zfile; char *zsystem; boolean ferr; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } if (! fsysdep_get_xqt_init ()) return FALSE; while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL) { boolean fmatch; int i; long itime; if (csystems > 0) { fmatch = fnotsystems; for (i = 0; i < csystems; i++) { if (strcmp (pazsystems[i], zsystem) == 0) { fmatch = ! fmatch; break; } } if (! fmatch) { ubuffree (zfile); ubuffree (zsystem); continue; } } itime = ixsysdep_file_time (zfile); if ((iold != (long) -1 && itime > iold) || (iyoung != (long) -1 && itime < iyoung)) { ubuffree (zfile); ubuffree (zsystem); continue; } /* We need to read the execution file before we can check the user name. */ if (! fsxqt_file_read (puuconf, zfile)) { ubuffree (zfile); ubuffree (zsystem); continue; } if (cusers == 0) fmatch = TRUE; else { fmatch = fnotusers; for (i = 0; i < cusers; i++) { if (strcmp (zSxqt_user, pazusers[i]) == 0 || (zSxqt_requestor != NULL && strcmp (zSxqt_requestor, pazusers[i]) == 0)) { fmatch = ! fmatch; break; } } } if (fmatch && ccommands > 0) { fmatch = fnotcommands; for (i = 0; i < ccommands; i++) { if (strcmp (pazcommands[i], "ALL") == 0 || strcmp (pazcommands[i], zSxqt_prog) == 0) { fmatch = ! fmatch; break; } } } if (fmatch) { boolean fbad, fkill; struct uuconf_system ssys; fbad = FALSE; if ((icmd & JOB_SHOW) != 0) { struct tm stime; printf ("%s %s!", zsystem, zSxqt_system); if (zSxqt_requestor != NULL) printf ("%s", zSxqt_requestor); else printf ("%s", zSxqt_user); usysdep_localtime (itime, &stime); printf (" %02d-%02d %02d:%02d ", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); printf ("%s\n", zSxqt_cmd); } fkill = FALSE; if ((icmd & JOB_INQUIRE) != 0) { int b; /* Ask stdin whether this job should be killed. */ fprintf (stderr, "%s: Kill %s? ", abProgram, zSxqt_cmd); (void) fflush (stderr); b = getchar (); fkill = b == 'y' || b == 'Y'; while (b != EOF && b != '\n') b = getchar (); } else if ((icmd & JOB_KILL) != 0) fkill = TRUE; if (fkill) { if ((strcmp (zSxqt_user, zsysdep_login_name ()) != 0 || strcmp (zsystem, zlocalname) != 0) && ! fsysdep_privileged ()) { ulog (LOG_ERROR, "Job not submitted by you\n"); fbad = TRUE; } } if (! fbad) { iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fbad = TRUE; } else if (strcmp (zsystem, zlocalname) == 0) { iuuconf = uuconf_system_local (puuconf, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fbad = TRUE; } } else if (! funknown_system (puuconf, zsystem, &ssys)) { ulog (LOG_ERROR, "Job for unknown system %s", zsystem); fbad = TRUE; } } } if (! fbad && (icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) { if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill, zSxqt_cmd, (struct scmdlist *) NULL, (const char *) NULL, zSxqt_user, &ssys, zSxqt_stdin, (pointer) NULL, zSxqt_requestor)) { ferr = TRUE; usxqt_file_free (); ubuffree (zfile); ubuffree (zsystem); break; } } if (! fbad && fkill) { for (i = 0; i < cSxqt_files; i++) { char *z; z = zsysdep_spool_file_name (&ssys, pazSxqt_files[i], (pointer) NULL); if (z != NULL) { (void) remove (z); ubuffree (z); } } if (remove (zfile) != 0) ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); } if (! fbad) (void) uuconf_system_free (puuconf, &ssys); } usxqt_file_free (); ubuffree (zfile); ubuffree (zsystem); } usysdep_get_xqt_free (); return ferr; } /* When a job is killed, send mail to the appropriate people. */ static boolean fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, zuser, qsys, zstdin, pstdinseq, zrequestor) pointer puuconf; int icmd; const char *zcomment; int cstdin; boolean fkilled; const char *zcmd; struct scmdlist *qcmd; const char *zid; const char *zuser; const struct uuconf_system *qsys; const char *zstdin; pointer pstdinseq; const char *zrequestor; { const char **pz; int cgot; int i, istdin; const char *zsubject; boolean fret; pz = (const char **) xmalloc (20 * sizeof (const char *)); cgot = 20; i = 0; if (zid == NULL) pz[i++] = "A UUCP execution request"; else { pz[i++] = "UUCP job\n\t"; pz[i++] = zid; pz[i++] = "\nfor system\n\t"; pz[i++] = qsys->uuconf_zname; } pz[i++] = "\nrequested by\n\t"; pz[i++] = zuser != NULL ? zuser : OWNER; if (zid == NULL) { pz[i++] = "\non system\n\t"; pz[i++] = qsys->uuconf_zname; } pz[i++] = "\n"; if (fkilled) pz[i++] = "has been killed.\n"; if (zcomment != NULL) { pz[i++] = zcomment; pz[i++] = "\n"; } pz[i++] = "The job "; if (fkilled) pz[i++] = "was\n"; else pz[i++] = "is\n"; if (zcmd != NULL) { pz[i++] = "\t"; pz[i++] = zcmd; } else { struct scmdlist *qshow; for (qshow = qcmd; qshow != NULL; qshow = qshow->qnext) { if (i + 10 > cgot) { cgot += 20; pz = (const char **) xrealloc ((pointer) pz, cgot * sizeof (const char *)); } switch (qshow->s.bcmd) { case 'S': pz[i++] = "\tsend "; break; default: case 'R': case 'X': pz[i++] = "\trequest "; break; case 'P': pz[i++] = "\tpoll "; #if DEBUG > 0 case 'E': ulog (LOG_FATAL, "fsnotify: Can't happen"); break; #endif } if (qshow->s.zfrom != NULL && qshow->s.zto != NULL) { pz[i++] = qshow->s.zfrom; pz[i++] = " to "; pz[i++] = qshow->s.zto; } } } istdin = i; if (cstdin > 0 && zstdin != NULL) { boolean fspool; char *zfile; FILE *e; fspool = fspool_file (zstdin); if (fspool) zfile = zsysdep_spool_file_name (qsys, zstdin, pstdinseq); else zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir); if (zfile != NULL && (fspool || fin_directory_list (zfile, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, TRUE, (const char *) NULL))) { e = fopen (zfile, "r"); if (e != NULL) { int clines, clen; char *zline; size_t cline; pz[i++] = "\n"; istdin = i; clines = 0; zline = NULL; cline = 0; while ((clen = getline (&zline, &cline, e)) > 0) { if (memchr (zline, '\0', (size_t) clen) != NULL) { int ifree; /* A null character means this is probably a binary file. */ for (ifree = istdin; ifree < i; ifree++) ubuffree ((char *) pz[ifree]); i = istdin - 1; break; } ++clines; if (clines > cstdin) break; if (i >= cgot) { cgot += 20; pz = (const char **) xrealloc ((pointer) pz, (cgot * sizeof (char *))); } pz[i++] = zbufcpy (zline); } xfree ((pointer) zline); (void) fclose (e); } } ubuffree (zfile); } if (fkilled) zsubject = "UUCP job killed"; else zsubject = "UUCP notification"; fret = TRUE; if ((icmd & JOB_MAIL) != 0) { if (! fsysdep_mail (OWNER, zsubject, i, pz)) fret = FALSE; } if ((icmd & JOB_NOTIFY) != 0 && (zrequestor != NULL || zuser != NULL)) { const char *zmail; char *zfree; if (zrequestor != NULL) zmail = zrequestor; else zmail = zuser; zfree = NULL; if (zid == NULL) { int iuuconf; const char *zloc; /* This is an execution request, which may be from another system. If it is, we must prepend that system name to the user name extracted from the X. file. */ iuuconf = uuconf_localname (puuconf, &zloc); if (iuuconf == UUCONF_NOT_FOUND) { zloc = zsysdep_localname (); if (zloc == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (strcmp (qsys->uuconf_zname, zloc) != 0 #if HAVE_INTERNET_MAIL && strchr (zmail, '@') == NULL #endif ) { zfree = zbufalc (strlen (qsys->uuconf_zname) + strlen (zmail) + sizeof "!"); sprintf (zfree, "%s!%s", qsys->uuconf_zname, zmail); zmail = zfree; } } if (! fsysdep_mail (zmail, zsubject, i, pz)) fret = FALSE; ubuffree (zfree); } while (istdin < i) { ubuffree ((char *) pz[istdin]); istdin++; } xfree ((pointer) pz); return fret; } /* Handle the -q option. For each remote system this lists the number of jobs queued, the number of executions queued, and the current call status. We get the executions all at once, because they are not accessed by system. They could be, but it is possible to have executions pending for an unknown system, so special handling would still be required. */ struct sxqtlist { struct sxqtlist *qnext; char *zsystem; int cxqts; long ifirst; }; /* These local functions need the definition of sxqtlist for the prototype. */ static boolean fsquery_system P((const struct uuconf_system *qsys, struct sxqtlist **pq, long inow, const char *zlocalname)); static boolean fsquery_show P((const struct uuconf_system *qsys, int cwork, long ifirstwork, struct sxqtlist *qxqt, long inow, const char *zlocalname)); static boolean fsquery (puuconf) pointer puuconf; { int iuuconf; const char *zlocalname; struct sxqtlist *qlist; char *zfile, *zsystem; boolean ferr; long inow; char **pznames, **pz; boolean fret; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } /* Get a count of all the execution files. */ if (! fsysdep_get_xqt_init ()) return FALSE; qlist = NULL; while ((zfile = zsysdep_get_xqt (&zsystem, &ferr)) != NULL) { struct sxqtlist *qlook; for (qlook = qlist; qlook != NULL; qlook = qlook->qnext) if (strcmp (zsystem, qlook->zsystem) == 0) break; if (qlook != NULL) { long itime; ubuffree (zsystem); ++qlook->cxqts; itime = ixsysdep_file_time (zfile); if (itime < qlook->ifirst) qlook->ifirst = itime; } else { struct sxqtlist *qnew; qnew = (struct sxqtlist *) xmalloc (sizeof (struct sxqtlist)); qnew->qnext = qlist; qnew->zsystem = zsystem; qnew->cxqts = 1; qnew->ifirst = ixsysdep_file_time (zfile); qlist = qnew; } ubuffree (zfile); } usysdep_get_xqt_free (); if (ferr) return FALSE; inow = ixsysdep_time ((long *) NULL); /* Show the information for each system. */ iuuconf = uuconf_system_names (puuconf, &pznames, 0); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } fret = TRUE; for (pz = pznames; *pz != NULL; pz++) { struct uuconf_system ssys; iuuconf = uuconf_system_info (puuconf, *pz, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsquery_system (&ssys, &qlist, inow, zlocalname)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); xfree ((pointer) *pz); } /* Check for the local system in the list of execution files. */ if (qlist != NULL) { struct sxqtlist **pq; for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) { if (strcmp ((*pq)->zsystem, zlocalname) == 0) { struct uuconf_system ssys; struct sxqtlist *qfree; iuuconf = uuconf_system_info (puuconf, zlocalname, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } iuuconf = uuconf_system_local (puuconf, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } ssys.uuconf_zname = (char *) zlocalname; } if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); qfree = *pq; *pq = qfree->qnext; ubuffree (qfree->zsystem); xfree ((pointer) qfree); break; } } } /* Print out information for any unknown systems for which we have execution files. */ while (qlist != NULL) { struct uuconf_system ssys; struct sxqtlist *qnext; if (! funknown_system (puuconf, qlist->zsystem, &ssys)) { ulog (LOG_ERROR, "Executions queued up for unknown systems"); fret = FALSE; break; } if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); qnext = qlist->qnext; ubuffree (qlist->zsystem); xfree ((pointer) qlist); qlist = qnext; } return fret; } /* Query a single known system. */ static boolean fsquery_system (qsys, pq, inow, zlocalname) const struct uuconf_system *qsys; struct sxqtlist **pq; long inow; const char *zlocalname; { int cwork; long ifirstwork; char *zid; boolean fret; if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) return FALSE; cwork = 0; ifirstwork = 0L; zid = NULL; while (TRUE) { struct scmd s; long itime; char *zthisid; if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) return FALSE; if (s.bcmd == 'H') break; zthisid = zsysdep_jobid (qsys, s.pseq); if (zid != NULL && strcmp (zid, zthisid) == 0) ubuffree (zthisid); else { ++cwork; ubuffree (zid); zid = zthisid; } itime = ixsysdep_work_time (qsys, s.pseq); if (ifirstwork == 0L || ifirstwork > itime) ifirstwork = itime; } usysdep_get_work_free (qsys); ubuffree (zid); /* Find the execution information, if any. */ while (*pq != NULL) { if (strcmp ((*pq)->zsystem, qsys->uuconf_zname) == 0) break; pq = &(*pq)->qnext; } /* If there are no commands and no executions, don't print any information for this system. */ if (cwork == 0 && *pq == NULL) return TRUE; fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow, zlocalname); if (*pq != NULL) { struct sxqtlist *qfree; qfree = *pq; *pq = qfree->qnext; ubuffree (qfree->zsystem); xfree ((pointer) qfree); } return fret; } /* Print out the query information for a single system. We handle the local system specially. */ static boolean fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname) const struct uuconf_system *qsys; int cwork; long ifirstwork; struct sxqtlist *qxqt; long inow; const char *zlocalname; { boolean flocal; struct sstatus sstat; boolean fnostatus; struct tm stime; int cpad; flocal = strcmp (qsys->uuconf_zname, zlocalname) == 0; if (! flocal) { if (! fsysdep_get_status (qsys, &sstat, &fnostatus)) return FALSE; } printf ("%-10s %3dC (", qsys->uuconf_zname, cwork); if (cwork == 0) { printf ("0 secs"); cpad = 3; } else cpad = csunits_show (inow - ifirstwork); printf (") "); while (cpad-- != 0) printf (" "); if (qxqt == NULL) printf (" 0X (0 secs) "); else { printf ("%3dX (", qxqt->cxqts); cpad = csunits_show (inow - qxqt->ifirst); printf (")"); while (cpad-- != 0) printf (" "); } if (flocal || fnostatus) { printf ("\n"); return TRUE; } usysdep_localtime (sstat.ilast, &stime); printf (" %02d-%02d %02d:%02d ", stime.tm_mon + 1,stime.tm_mday, stime.tm_hour, stime.tm_min); printf ("%s\n", azStatus[(int) sstat.ttype]); return TRUE; } /* Print a time difference in the largest applicable units. */ static int csunits_show (idiff) long idiff; { const char *zunit; long iunits; int cpad; if (idiff > (long) 24 * (long) 60 * (long) 60) { iunits = idiff / ((long) 24 * (long) 60 * (long) 60); zunit = "day"; cpad = 4; } else if (idiff > (long) 60 * 60) { iunits = idiff / (long) (60 * 60); zunit = "hour"; cpad = 3; } else if (idiff > (long) 60) { iunits = idiff / (long) 60; zunit = "min"; cpad = 4; } else { iunits = idiff; zunit = "sec"; cpad = 4; } printf ("%ld %s%s", iunits, zunit, iunits == 1 ? "" : "s"); if (iunits != 1) --cpad; if (iunits > 99) --cpad; if (iunits > 9) --cpad; return cpad; } /* Give a list of all status entries for all machines that we have status entries for. We need to get a list of status entries in a system dependent fashion, since we may have status for unknown systems. */ static boolean fsmachines () { pointer phold; char *zsystem; boolean ferr; struct sstatus sstat; if (! fsysdep_all_status_init (&phold)) return FALSE; while ((zsystem = zsysdep_all_status (phold, &ferr, &sstat)) != NULL) { struct tm stime; usysdep_localtime (sstat.ilast, &stime); printf ("%-14s %02d-%02d %02d:%02d %s", zsystem, stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min, azStatus[(int) sstat.ttype]); ubuffree (zsystem); if (sstat.ttype != STATUS_TALKING && sstat.cwait > 0) { printf (" (%d %s", sstat.cretries, sstat.cretries == 1 ? "try" : "tries"); if (sstat.ilast + sstat.cwait > ixsysdep_time ((long *) NULL)) { usysdep_localtime (sstat.ilast + sstat.cwait, &stime); printf (", next after %02d-%02d %02d:%02d", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); } printf (")"); } printf ("\n"); } usysdep_all_status_free (phold); return ! ferr; } SE; } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (strcmp (qsys->uuconf_zname, zloc) != 0 #if HAVE_INTERNET_MAIL && strchr (zmail, '@') ==uucp-1.04/lib/0407750004150000170000000000005337265116007330 5 0 1 0 uucp-1.04/lib/Makefile.in1004440004150000170000000276205337263633012210 037777777777 1 0 # This is the Makefile for the lib subdirectory of Taylor UUCP # # The file Makefile.in should be processed by configure to generate # Makefile. If you want to generate Makefile by hand, you must find # all variables surrounded by @ and replace them with the correct # value (e.g. @CC@ must be replaced by something like cc or gcc). SHELL=/bin/sh # These are overridden by the call from the top level Makefile CC = @CC@ CFLAGS = @CFLAGS@ RANLIB = @RANLIB@ srcdir = @srcdir@ VPATH = @srcdir@ MORECFLAGS = -I$(srcdir)/.. -I.. OBJS = buffer.o crc.o debug.o escape.o getopt.o getop1.o parse.o spool.o \ status.o xfree.o xmall.o xreall.o \ @LIBOBJS@ all: libuucp.a clean: rm -f $(OBJS) libuucp.a distclean: clean rm -f Makefile mostlyclean: clean realclean: distclean libuucp.a: $(OBJS) rm -f libuucp.a ar qc libuucp.a $(OBJS) -$(RANLIB) libuucp.a .c.o: $(CC) -c $(CFLAGS) $(MORECFLAGS) $< dist: mkdir ../uucp-$(VERSION)/lib ln `cat MANIFEST` ../uucp-$(VERSION)/lib Makefile: Makefile.in (cd ..; sh config.status) # Header file dependencies. $(OBJS): $(srcdir)/../uucp.h ../conf.h $(srcdir)/../policy.h buffer.o: $(srcdir)/../uudefs.h crc.o: $(srcdir)/../prot.h debug.o: $(srcdir)/../uudefs.h escape.o: $(srcdir)/../uudefs.h getopt.o: $(srcdir)/../getopt.h $(srcdir)/../uudefs.h getop1.o: $(srcdir)/../getopt.h parse.o: $(srcdir)/../uudefs.h spool.o: $(srcdir)/../uudefs.h status.o: $(srcdir)/../uudefs.h xfree.o: $(srcdir)/../uudefs.h xmall.o: $(srcdir)/../uudefs.h xreall.o: $(srcdir)/../uudefs.h s = 1; qnewuucp-1.04/lib/MANIFEST1004440004150000170000000035405337263633011267 037777777777 1 0 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 et = 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)->qneuucp-1.04/lib/bsrch.c1004440004150000170000000321605337263634011404 037777777777 1 0 /* 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; } == 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 ((*puucp-1.04/lib/buffer.c1004440004150000170000000453405337263634011560 037777777777 1 0 /* 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; } er phold; char *zsystem; boolean ferr; struct sstatus sstat; if (! fsysdep_all_status_init (&phold)) return FALSE; while ((zsystem = zsysdep_all_stauucp-1.04/lib/bzero.c1004440004150000170000000025605337263634011425 037777777777 1 0 /* 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; } our, stime.tm_min); } printf (")"); } printf ("\n"); } usysdep_all_status_free (phold); return ! ferr; } SE; } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (strcmp (qsys->uuconf_zname, zloc) != 0 #if HAVE_INTERNET_MAIL && strchr (zmail, '@') ==uucp-1.04/lib/crc.c1004440004150000170000001520505337263634011053 037777777777 1 0 /* * 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; } ils. 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 "uucp-1.04/lib/debug.c1004440004150000170000000637005337263634011375 037777777777 1 0 /* debug.c UUCP debugging functions. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include #include "uudefs.h" /* The debugging level. */ int iDebug; /* Parse a debugging string. This may be a simple number, which sets the given number of bits in iDebug, or it may be a series of single letters. */ static const char * const azDebug_names[] = DEBUG_NAMES; int idebug_parse (z) const char *z; { char *zend; int i, iret; char *zcopy, *ztok; if (strncasecmp (z, DEBUG_NONE, sizeof DEBUG_NONE - 1) == 0) return 0; i = (int) strtol ((char *) z, &zend, 0); if (*zend == '\0') { if (i > 15) i = 15; else if (i < 0) i = 0; return (1 << i) - 1; } zcopy = zbufcpy (z); iret = 0; for (ztok = strtok (zcopy, ","); ztok != NULL; ztok = strtok ((char *) NULL, ",")) { if (strcasecmp (ztok, "all") == 0) { iret = DEBUG_MAX; break; } for (i = 0; azDebug_names[i] != NULL; i++) { if (strncasecmp (ztok, azDebug_names[i], strlen (azDebug_names[i])) == 0) { iret |= 1 << i; break; } } if (azDebug_names[i] == NULL) ulog (LOG_ERROR, "Unrecognized debugging option \"%s\"", ztok); } ubuffree (zcopy); return iret; } /* A debugging routine used when displaying buffers. */ size_t cdebug_char (z, ichar) char *z; int ichar; { char b; if (isprint (BUCHAR (ichar)) && ichar != '\"' && ichar != '\\') { *z++ = (char) ichar; *z = '\0'; return 1; } *z++ = '\\'; switch (ichar) { case '\n': b = 'n'; break; case '\r': b = 'r'; break; case '\"': b = '\"'; break; case '\\': b = '\\'; break; default: sprintf (z, "%03o", (unsigned int) BUCHAR (ichar)); return strlen (z) + 1; } *z++ = b; *z = '\0'; return 2; } /* Display a buffer when debugging. */ void udebug_buffer (zhdr, zbuf, clen) const char *zhdr; const char *zbuf; size_t clen; { char *z, *zalc; int i; zalc = zbufalc (clen * 4 + 1); z = zalc; for (i = 0; i < clen && i < 80; i++) z += cdebug_char (z, zbuf[i]); if (i < clen) { *z++ = '.'; *z++ = '.'; *z++ = '.'; } *z = '\0'; ulog (LOG_DEBUG, "%s %lu \"%s\"", zhdr, (unsigned long) clen, zalc); ubuffree (zalc); } */ /* 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 */ /* implementuucp-1.04/lib/escape.c1004440004150000170000000300605337263635011541 037777777777 1 0 /* escape.c Translate escape sequences. */ #include "uucp.h" #include #include "uudefs.h" size_t cescape (z) char *z; { char *zto, *zfrom; zto = z; zfrom = z; while (*zfrom != '\0') { if (*zfrom != '\\') { *zto++ = *zfrom++; continue; } ++zfrom; switch (*zfrom) { case '-': *zto++ = '-'; break; case 'b': *zto++ = '\b'; break; case 'n': *zto++ = '\n'; break; case 'N': *zto++ = '\0'; break; case 'r': *zto++ = '\r'; break; case 's': *zto++ = ' '; break; case 't': *zto++ = '\t'; break; case '\0': --zfrom; /* Fall through. */ case '\\': *zto++ = '\\'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int i; i = *zfrom - '0'; if (zfrom[1] >= '0' && zfrom[1] <= '7') i = 8 * i + *++zfrom - '0'; if (zfrom[1] >= '0' && zfrom[1] <= '7') i = 8 * i + *++zfrom - '0'; *zto++ = (char) i; } break; case 'x': { int i; i = 0; while (isxdigit (BUCHAR (zfrom[1]))) { if (isdigit (BUCHAR (zfrom[1]))) i = 16 * i + *++zfrom - '0'; else if (isupper (BUCHAR (zfrom[1]))) i = 16 * i + *++zfrom - 'A' + 10; else i = 16 * i + *++zfrom - 'a' + 10; } *zto++ = (char) i; } break; default: ulog (LOG_ERROR, "Unrecognized escape sequence \\%c", *zfrom); *zto++ = *zfrom; break; } ++zfrom; } *zto = '\0'; return (size_t) (zto - z); } 5a8faL, 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, 0xe6uucp-1.04/lib/getlin.c1004440004150000170000000365305337263635011573 037777777777 1 0 /* 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; } e. * * Programmers may incorporate any or all code into their programs, * givinguucp-1.04/lib/getopt.c1004440004150000170000004311705337263635011612 037777777777 1 0 /* 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 */ 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-elemenuucp-1.04/lib/getop1.c1004440004150000170000000627405337263635011512 037777777777 1 0 /* Getopt for GNU. Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. This file was modified slightly by Ian Lance Taylor, June 1992, for Taylor UUCP. */ #include "uucp.h" #include "getopt.h" int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == EOF) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ ing 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 */ )) { conuucp-1.04/lib/memchr.c1004440004150000170000001201405337263635011553 037777777777 1 0 /* 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; } ++]); printf ("\n"); } exit (0); } #endif /* TEST */ 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-elemenuucp-1.04/lib/memcmp.c1004440004150000170000000053505337263636011564 037777777777 1 0 /* 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; } am is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICUuucp-1.04/lib/memcpy.c1004440004150000170000000047505337263636011603 037777777777 1 0 /* 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; } atch 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 *ouucp-1.04/lib/parse.c1004440004150000170000001212405337263636011415 037777777777 1 0 /* 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.2 1992/10/28 05:25:14 ian Rel $"; #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; } 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 uucp-1.04/lib/spool.c1004440004150000170000000144205337263636011440 037777777777 1 0 /* spool.c See whether a filename is legal for the spool directory. */ #include "uucp.h" #include #include "uudefs.h" /* See whether a file is a spool file. Spool file names are specially crafted to hand around to other UUCP packages. They always begin with 'C', 'D' or 'X', and the second character is always a period. The remaining characters may be any printable characters, since they may include a grade set by another system. */ boolean fspool_file (zfile) const char *zfile; { const char *z; if (*zfile != 'C' && *zfile != 'D' && *zfile != 'X') return FALSE; if (zfile[1] != '.') return FALSE; for (z = zfile + 2; *z != '\0'; z++) if (*z == '/' || ! isprint (BUCHAR (*z)) || isspace (BUCHAR (*z))) return FALSE; return TRUE; } 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; } retuucp-1.04/lib/status.c1004440004150000170000000052005337263636011623 037777777777 1 0 /* 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" }; 1 0 uucp-1.04/lib/strcas.c1004440004150000170000000101305337263636011575 037777777777 1 0 /* strcas.c Compare two strings case insensitively. */ #include "uucp.h" #include int strcasecmp (z1, z2) const char *z1; const char *z2; { char b1, b2; while ((b1 = *z1++) != '\0') { b2 = *z2++; if (b2 == '\0') return 1; if (b1 != b2) { if (isupper (BUCHAR (b1))) b1 = tolower (BUCHAR (b1)); if (isupper (BUCHAR (b2))) b2 = tolower (BUCHAR (b2)); if (b1 != b2) return b1 - b2; } } if (*z2 == '\0') return 0; else return -1; } 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; } atch 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 *ouucp-1.04/lib/strchr.c1004440004150000170000000037705337263636011617 037777777777 1 0 /* 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; } blic 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 implieuucp-1.04/lib/strdup.c1004440004150000170000000040305337263637011622 037777777777 1 0 /* 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; } 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 uucp-1.04/lib/strncs.c1004440004150000170000000116005337263637011616 037777777777 1 0 /* strncs.c Compare two strings case insensitively up to a point. */ #include "uucp.h" #include int strncasecmp (z1, z2, c) const char *z1; const char *z2; size_t c; { char b1, b2; if (c == 0) return 0; while ((b1 = *z1++) != '\0') { b2 = *z2++; if (b2 == '\0') return 1; if (b1 != b2) { if (isupper (BUCHAR (b1))) b1 = tolower (BUCHAR (b1)); if (isupper (BUCHAR (b2))) b2 = tolower (BUCHAR (b2)); if (b1 != b2) return b1 - b2; } --c; if (c == 0) return 0; } if (*z2 == '\0') return 0; else return -1; } 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;uucp-1.04/lib/strrch.c1004440004150000170000000060505337263637011612 037777777777 1 0 /* 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; } if (*zend != '\0') qcmd->ipos = 0; } } } } return TRUE; } z = strtok ((char *) NULLuucp-1.04/lib/strstr.c1004440004150000170000000341605337263637011651 037777777777 1 0 /* 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; } 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 charuucp-1.04/lib/strtol.c1004440004150000170000000762405337263637011644 037777777777 1 0 /* Copyright (C) 1991 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. This file was modified slightly by Ian Lance Taylor, May 1992, for Taylor UUCP. */ #include "uucp.h" #include #include #if HAVE_LIMITS_H #include #else #define ULONG_MAX 4294967295 #define LONG_MIN (- LONG_MAX - 1) #define LONG_MAX 2147483647 #endif #ifndef UNSIGNED #define UNSIGNED 0 #endif /* Convert NPTR to an `unsigned long int' or `long int' in base BASE. If BASE is 0 the base is determined by the presence of a leading zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. If BASE is < 2 or > 36, it is reset to 10. If ENDPTR is not NULL, a pointer to the character after the last one converted is stored in *ENDPTR. */ #if UNSIGNED unsigned long int #define strtol strtoul #else long int #endif strtol (nptr, endptr, base) const char *nptr; char **endptr; int base; { int negative; register unsigned long int cutoff; register unsigned int cutlim; register unsigned long int i; register const char *s; register unsigned int c; const char *save; int overflow; if (base < 0 || base == 1 || base > 36) base = 10; s = nptr; /* Skip white space. */ while (isspace(BUCHAR (*s))) ++s; if (*s == '\0') goto noconv; /* Check for a sign. */ if (*s == '-') { negative = 1; ++s; } else if (*s == '+') { negative = 0; ++s; } else negative = 0; if (base == 16 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; /* If BASE is zero, figure it out ourselves. */ if (base == 0) if (*s == '0') { if (s[1] == 'x' || s[1] == 'X') { s += 2; base = 16; } else base = 8; } else base = 10; /* Save the pointer so we can check later if anything happened. */ save = s; cutoff = ULONG_MAX / (unsigned long int) base; cutlim = ULONG_MAX % (unsigned long int) base; overflow = 0; i = 0; for (c = BUCHAR (*s); c != '\0'; c = BUCHAR (*++s)) { if (isdigit(c)) c -= '0'; else if (islower(c)) c = c - 'a' + 10; else if (isupper(c)) c = c - 'A' + 10; else break; if (c >= base) break; /* Check for overflow. */ if (i > cutoff || (i == cutoff && c > cutlim)) overflow = 1; else { i *= (unsigned long int) base; i += c; } } /* Check if anything actually happened. */ if (s == save) goto noconv; /* Store in ENDPTR the address of one character past the last character we converted. */ if (endptr != NULL) *endptr = (char *) s; #if !UNSIGNED /* Check for a value that is within the range of `unsigned long int', but outside the range of `long int'. */ if (i > (negative ? - (unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX)) overflow = 1; #endif if (overflow) { errno = ERANGE; #if UNSIGNED return ULONG_MAX; #else return negative ? LONG_MIN : LONG_MAX; #endif } /* Return the result of the appropriate sign. */ return (negative ? - i : i); noconv: /* There was no number to convert. */ if (endptr != NULL) *endptr = (char *) nptr; return 0L; } uucp-1.04/lib/xfree.c1004440004150000170000000037705337263640011416 037777777777 1 0 /* 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); } 37777777777 1 0 uucp-1.04/lib/xmall.c1004440004150000170000000040705337263640011414 037777777777 1 0 /* 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; } 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;uucp-1.04/lib/xreall.c1004440004150000170000000066005337263640011567 037777777777 1 0 /* 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; } } } } } return TRUE; } z = strtok ((char *) NULLuucp-1.04/uuto.in1004440004150000170000000075205337263532010714 037777777777 1 0 : # 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 $* HANTABILITY or FITNESSuucp-1.04/uux.11004440004150000170000001522505337263532010274 037777777777 1 0 ''' $Id: uux.1,v 1.8 1993/01/24 01:02:41 ian Rel $ .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) 11414 037777777777 1 0 uucp-1.04/uux.c1004440004150000170000011266405337263533010364 037777777777 1 0 /* 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.56 1993/01/21 05:11:34 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "sysdep.h" #include "getopt.h" #include #include /* These character lists should, perhaps, be in sysdep.h. */ /* This is the list of shell metacharacters that we check for. If one of these is present, we request uuxqt to execute the command with /bin/sh. Otherwise we let it execute using execve. */ #define ZSHELLCHARS "\"'`*?[;&()|<>\\$" /* This is the list of word separators. We break filename arguments at these characters. */ #define ZSHELLSEPS ";&*|<> \t" /* This is the list of word separators without the redirection operators. */ #define ZSHELLNONREDIRSEPS ";&*| \t" /* The program name. */ char abProgram[] = "uux"; /* The name of the execute file. */ const char *zXxqt_name; /* The execute file we are creating. */ static FILE *eXxqt_file; /* A list of commands to be spooled. */ static struct scmd *pasXcmds; static int cXcmds; /* A file to close if we're forced to exit. */ static FILE *eXclose; /* Local functions. */ static void uxusage P((void)); static void uxadd_xqt_line P((int bchar, const char *z1, const char *z2)); static void uxadd_send_file P((const char *zfrom, const char *zto, const char *zoptions, const char *ztemp, const char *zforward, const struct uuconf_system *qxqtsys, const char *zxqtloc, int bgrade)); static void uxcopy_stdin P((FILE *e)); static void uxrecord_file P((const char *zfile)); static void uxabort P((void)); /* Long getopt options. */ static const struct option asXlongopts[] = { { NULL, 0, NULL, 0 } }; /* The main routine. */ int main (argc, argv) int argc; char **argv; { /* -a: requestor address for status reports. */ const char *zrequestor = NULL; /* -b: if true, return standard input on error. */ boolean fretstdin = FALSE; /* -c,-C: if true, copy to spool directory. */ boolean fcopy = FALSE; /* -c: set if -c appears explicitly; if it and -l appear, then if the link fails we don't copy the file. */ boolean fdontcopy = FALSE; /* -I: configuration file name. */ const char *zconfig = NULL; /* -j: output job id. */ boolean fjobid = FALSE; /* -g: job grade. */ char bgrade = BDEFAULT_UUX_GRADE; /* -l: link file to spool directory. */ boolean flink = FALSE; /* -n: do not notify upon command completion. */ boolean fno_ack = FALSE; /* -p: read standard input for command standard input. */ boolean fread_stdin = FALSE; /* -r: do not start uucico when finished. */ boolean fuucico = TRUE; /* -s: report status to named file. */ const char *zstatus_file = NULL; /* -W: only expand local file names. */ boolean fexpand = TRUE; /* -z: report status only on error. */ boolean ferror_ack = FALSE; int iopt; pointer puuconf; int iuuconf; const char *zlocalname; const char *zxqtloc; int i; size_t clen; char *zargs; char *zarg; char *zcmd; const char *zsys; char *zexclam; boolean fgetcwd; const char *zuser; struct uuconf_system sxqtsys; boolean fxqtlocal; char *zforward; char **pzargs; int calloc_args; int cargs; char abxqt_tname[CFILE_NAME_LEN]; char abxqt_xname[CFILE_NAME_LEN]; const char *zinput_from; const char *zinput_to; const char *zinput_temp; boolean finputcopied; char *zcall_system; boolean fcall_any; struct uuconf_system slocalsys; boolean fneedshell; char *zfullcmd; boolean fexit; /* We need to be able to read a single - as an option, which getopt won't do. So that we can still use getopt, we run through the options looking for an option "-"; if we find one we change it to "-p", which is equivalent to "-". */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; if (argv[i][1] == '\0') argv[i] = zbufcpy ("-p"); else { const char *z; for (z = argv[i] + 1; *z != '\0'; z++) { /* If the option takes an argument, and the argument is not appended, then skip the next argument. */ if (*z == 'a' || *z == 'g' || *z == 'I' || *z == 's' || *z == 'x') { if (z[1] == '\0') i++; break; } } } } /* The leading + in the getopt string means to stop processing options as soon as a non-option argument is seen. */ while ((iopt = getopt_long (argc, argv, "+a:bcCg:I:jlnprs:Wx:z", asXlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'a': /* Set requestor name: mail address to which status reports should be sent. */ zrequestor = optarg; break; case 'b': /* Return standard input on error. */ fretstdin = TRUE; break; case 'c': /* Do not copy local files to spool directory. */ fcopy = FALSE; fdontcopy = TRUE; break; case 'C': /* Copy local files to spool directory. */ fcopy = TRUE; break; case 'I': /* Configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'j': /* Output jobid. */ fjobid = TRUE; break; case 'g': /* Set job grade. */ bgrade = optarg[0]; break; case 'l': /* Link file to spool directory. */ flink = TRUE; break; case 'n': /* Do not notify upon command completion. */ fno_ack = TRUE; break; case 'p': /* Read standard input for command standard input. */ fread_stdin = TRUE; break; case 'r': /* Do not start uucico when finished. */ fuucico = FALSE; break; case 's': /* Report status to named file. */ zstatus_file = optarg; break; case 'W': /* Only expand local file names. */ fexpand = FALSE; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 'z': /* Report status only on error. */ ferror_ack = TRUE; break; case 0: /* Long option found and flag set. */ break; default: uxusage (); break; } } if (! UUCONF_GRADE_LEGAL (bgrade)) { ulog (LOG_ERROR, "Ignoring illegal grade"); bgrade = BDEFAULT_UUX_GRADE; } if (optind == argc) uxusage (); iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif /* The command and files arguments could be quoted in any number of ways, so we split them apart ourselves. We do this before calling usysdep_initialize because we want to set fgetcwd correctly. */ clen = 1; for (i = optind; i < argc; i++) clen += strlen (argv[i]) + 1; zargs = zbufalc (clen); *zargs = '\0'; for (i = optind; i < argc; i++) { strcat (zargs, argv[i]); strcat (zargs, " "); } /* The first argument is the command to execute. */ clen = strcspn (zargs, ZSHELLSEPS); zcmd = zbufalc (clen + 1); strncpy (zcmd, zargs, clen); zcmd[clen] = '\0'; zargs += clen; /* Split the arguments out into an array. We break the arguments into alternating sequences of characters not in ZSHELLSEPS and characters in ZSHELLSEPS. We remove whitespace. We separate the redirection characters '>' and '<' into their own arguments to make them easier to process below. */ calloc_args = 10; pzargs = (char **) xmalloc (calloc_args * sizeof (char *)); cargs = 0; for (zarg = strtok (zargs, " \t"); zarg != NULL; zarg = strtok ((char *) NULL, " \t")) { while (*zarg != '\0') { if (cargs + 1 >= calloc_args) { calloc_args += 10; pzargs = (char **) xrealloc ((pointer) pzargs, calloc_args * sizeof (char *)); } clen = strcspn (zarg, ZSHELLSEPS); if (clen > 0) { pzargs[cargs] = zbufalc (clen + 1); memcpy (pzargs[cargs], zarg, clen); pzargs[cargs][clen] = '\0'; ++cargs; zarg += clen; } /* We deliberately separate '>' and '<' out. */ if (*zarg != '\0') { clen = strspn (zarg, ZSHELLNONREDIRSEPS); if (clen == 0) clen = 1; pzargs[cargs] = zbufalc (clen + 1); memcpy (pzargs[cargs], zarg, clen); pzargs[cargs][clen] = '\0'; ++cargs; zarg += clen; } } } /* Now look through the arguments to see if we are going to need the current working directory. We don't try to make a precise determination, just a conservative one. The basic idea is that we don't want to get the cwd for 'foo!rmail - user' (note that we don't examine the command itself). */ fgetcwd = FALSE; for (i = 0; i < cargs; i++) { if (pzargs[i][0] == '(') continue; zexclam = strrchr (pzargs[i], '!'); if (zexclam != NULL && fsysdep_needs_cwd (zexclam + 1)) { fgetcwd = TRUE; break; } if ((pzargs[i][0] == '<' || pzargs[i][0] == '>') && i + 1 < cargs && strchr (pzargs[i + 1], '!') == NULL && fsysdep_needs_cwd (pzargs[i + 1])) { fgetcwd = TRUE; break; } } #ifdef SIGINT usysdep_signal (SIGINT); #endif #ifdef SIGHUP usysdep_signal (SIGHUP); #endif #ifdef SIGQUIT usysdep_signal (SIGQUIT); #endif #ifdef SIGTERM usysdep_signal (SIGTERM); #endif #ifdef SIGPIPE usysdep_signal (SIGPIPE); #endif usysdep_initialize (puuconf, INIT_SUID | (fgetcwd ? INIT_GETCWD : 0)); ulog_fatal_fn (uxabort); zuser = zsysdep_login_name (); /* Get the local system name. */ iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) exit (EXIT_FAILURE); } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); /* Get the local system information. */ iuuconf = uuconf_system_info (puuconf, zlocalname, &slocalsys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); iuuconf = uuconf_system_local (puuconf, &slocalsys); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } /* Figure out which system the command is to be executed on. Some mailers apparently pass local!rmail, so we must explicitly check for that. */ zexclam = strchr (zcmd, '!'); while (zexclam != NULL) { *zexclam = '\0'; if (strcmp (zcmd, zlocalname) == 0) ; else if (slocalsys.uuconf_pzalias == NULL) break; else { char **pzal; for (pzal = slocalsys.uuconf_pzalias; *pzal != NULL; pzal++) if (strcmp (zcmd, *pzal) == 0) break; if (*pzal == NULL) break; } zcmd = zexclam + 1; zexclam = strchr (zcmd, '!'); } if (zexclam == NULL) { zsys = zlocalname; fxqtlocal = TRUE; zforward = NULL; } else { zsys = zcmd; zcmd = zexclam + 1; fxqtlocal = FALSE; /* See if we must forward this command through other systems (e.g. uux a!b!cmd). */ zexclam = strrchr (zcmd, '!'); if (zexclam == NULL) zforward = NULL; else { clen = zexclam - zcmd; zforward = zbufalc (clen); memcpy (zforward, zcmd, clen); zforward[clen] = '\0'; zcmd = zexclam + 1; } } if (fxqtlocal) sxqtsys = slocalsys; else { iuuconf = uuconf_system_info (puuconf, zsys, &sxqtsys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (! funknown_system (puuconf, zsys, &sxqtsys)) ulog (LOG_FATAL, "%s: System not found", zsys); } } /* Get the local name the remote system know us as. */ zxqtloc = sxqtsys.uuconf_zlocalname; if (zxqtloc == NULL) zxqtloc = zlocalname; /* We can send this as an E command if the execution is on a different, directly connected, system and the only file used is the standard input and comes from this system. This is true of the common cases of rmail and rnews. We get an execute file name here in case we need it. */ if (fxqtlocal) zXxqt_name = zsysdep_xqt_file_name (); else zXxqt_name = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, TRUE, abxqt_tname, (char *) NULL, abxqt_xname); if (zXxqt_name == NULL) uxabort (); uxrecord_file (zXxqt_name); /* Look through the arguments. Any argument containing an exclamation point character is interpreted as a file name, and is sent to the appropriate system. */ zinput_from = NULL; zinput_to = NULL; zinput_temp = NULL; finputcopied = FALSE; zcall_system = NULL; fcall_any = FALSE; for (i = 0; i < cargs; i++) { const char *zsystem; char *zfile; char *zforw; boolean finput, foutput; boolean flocal, fonxqt; /* Check for a parenthesized argument; remove the parentheses and otherwise ignore it (this is how an exclamation point is quoted). */ if (pzargs[i][0] == '(') { clen = strlen (pzargs[i]); if (pzargs[i][clen - 1] != ')') ulog (LOG_ERROR, "Mismatched parentheses"); else pzargs[i][clen - 1] = '\0'; ++pzargs[i]; continue; } /* Check whether we are doing a redirection. */ finput = FALSE; foutput = FALSE; if (i + 1 < cargs) { if (pzargs[i][0] == '<') finput = TRUE; else if (pzargs[i][0] == '>') foutput = TRUE; if (finput || foutput) { pzargs[i] = NULL; i++; } } zexclam = strchr (pzargs[i], '!'); /* If there is no exclamation point and no redirection, this argument is left untouched. */ if (zexclam == NULL && ! finput && ! foutput) continue; /* Get the system name and file name for this file. */ if (zexclam == NULL) { zsystem = zlocalname; zfile = pzargs[i]; flocal = TRUE; zforw = NULL; } else { *zexclam = '\0'; zsystem = pzargs[i]; if (*zsystem != '\0') flocal = FALSE; else { zsystem = zlocalname; flocal = TRUE; } zfile = zexclam + 1; zexclam = strrchr (zfile, '!'); if (zexclam == NULL) zforw = NULL; else { if (flocal) ulog (LOG_FATAL, "!%s: Can't figure out where to get file", zfile); *zexclam = '\0'; zforw = zfile; zfile = zexclam + 1; } } /* Check if the file is already on the execution system. */ if (flocal) fonxqt = fxqtlocal; else if (fxqtlocal) fonxqt = FALSE; else if (zforward == NULL ? zforw != NULL : zforw == NULL) fonxqt = FALSE; else if (zforward != NULL && zforw != NULL && strcmp (zforward, zforw) != 0) fonxqt = FALSE; else if (strcmp (zsystem, sxqtsys.uuconf_zname) == 0) fonxqt = TRUE; else if (sxqtsys.uuconf_pzalias == NULL) fonxqt = FALSE; else { char **pzal; fonxqt = FALSE; for (pzal = sxqtsys.uuconf_pzalias; *pzal != NULL; pzal++) { if (strcmp (zsystem, *pzal) == 0) { fonxqt = TRUE; break; } } } /* Turn the file into an absolute path. */ if (flocal) zfile = zsysdep_local_file_cwd (zfile, sxqtsys.uuconf_zpubdir); else if (fexpand) zfile = zsysdep_add_cwd (zfile); if (zfile == NULL) uxabort (); /* Check for output redirection. */ if (foutput) { if (flocal) { if (! fin_directory_list (zfile, sxqtsys.uuconf_pzremote_receive, sxqtsys.uuconf_zpubdir, TRUE, FALSE, (const char *) NULL)) ulog (LOG_FATAL, "Not permitted to create %s", zfile); } /* There are various cases of output redirection. uux cmd >out: The command is executed on the local system, and the output file is placed on the local system (fonxqt is TRUE). uux cmd >a!out: The command is executed on the local system, and the output file is sent to a. uux a!cmd >out: The command is executed on a, and the output file is returned to the local system (flocal is TRUE). uux a!cmd >a!out: The command is executed on a, and the output file is left on a (fonxqt is TRUE). uux a!cmd >b!out: The command is executed on a, and the output file is sent to b; traditionally, I believe that b is relative to a, rather than to the local system. However, this essentially contradicts the previous two cases, in which the output file is relative to the local system. Now, the cases that we don't handle. uux cmd >a!b!out: The command is executed on the local system, and the output file is sent to b via a. This requires the local uuxqt to support forwarding of the output file. uux a!b!cmd >out: The command is executed on b, which is reached via a. Probably the output file is intended for the local system, in which case the uuxqt on b must support forwarding of the output file. uux a!b!cmd >c!out: Is c relative to b or to the local system? If it's relative to b this is easy to handle. Otherwise, we must arrange for the file to be sent back to the local system and for the local system to send it on to c. There are many variations of the last case. It's not at all clear to me how they should be handled. */ if (zforward != NULL || zforw != NULL) ulog (LOG_FATAL, "May not forward standard output"); if (fonxqt) uxadd_xqt_line ('O', zfile, (const char *) NULL); else if (flocal) uxadd_xqt_line ('O', zfile, zxqtloc); else uxadd_xqt_line ('O', zfile, zsystem); pzargs[i] = NULL; continue; } if (finput) { if (fread_stdin) ulog (LOG_FATAL, "Standard input specified twice"); pzargs[i] = NULL; } if (flocal) { char *zuse; char *zdata; char abtname[CFILE_NAME_LEN]; char abdname[CFILE_NAME_LEN]; /* It's a local file. If requested by -C, copy the file to the spool directory. If requested by -l, link the file to the spool directory; if the link fails, we copy the file, unless -c was explictly used. If the execution is occurring on the local system, we force the copy as well, because otherwise we would have to have some way to tell uuxqt not to move the file. If the file is being shipped to another system, we must set up a transfer request. First make sure the user has legitimate access, since we are running setuid. */ if (! fsysdep_access (zfile)) uxabort (); zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, abtname, abdname, (char *) NULL); if (zdata == NULL) uxabort (); if (fcopy || flink || fxqtlocal) { boolean fdid; uxrecord_file (zdata); fdid = FALSE; if (flink) { boolean fworked; if (! fsysdep_link (zfile, zdata, &fworked)) uxabort (); if (fworked) fdid = TRUE; else if (fdontcopy) ulog (LOG_FATAL, "%s: Can't link to spool directory", zfile); } if (! fdid) { openfile_t efile; efile = esysdep_user_fopen (zfile, TRUE, TRUE); if (! ffileisopen (efile)) uxabort (); if (! fcopy_open_file (efile, zdata, FALSE, TRUE)) uxabort (); (void) ffileclose (efile); } zuse = abtname; } else { /* We don't actually use the spool file name, but we need a name to use as the destination. */ ubuffree (zdata); /* Make sure the daemon can access the file. */ if (! fsysdep_daemon_access (zfile)) uxabort (); if (! fin_directory_list (zfile, sxqtsys.uuconf_pzlocal_send, sxqtsys.uuconf_zpubdir, TRUE, TRUE, zuser)) ulog (LOG_FATAL, "Not permitted to send from %s", zfile); zuse = zfile; } if (fxqtlocal) { if (finput) uxadd_xqt_line ('I', zuse, (char *) NULL); else pzargs[i] = zuse; } else { finputcopied = fcopy || flink; if (finput) { zinput_from = zuse; zinput_to = zbufcpy (abdname); zinput_temp = zbufcpy (abtname); } else { char *zbase; uxadd_send_file (zuse, abdname, finputcopied ? "C" : "c", abtname, zforward, &sxqtsys, zxqtloc, bgrade); zbase = zsysdep_base_name (zfile); if (zbase == NULL) uxabort (); uxadd_xqt_line ('F', abdname, zbase); pzargs[i] = zbase; } } } else if (fonxqt) { /* The file is already on the system where the command is to be executed. */ if (finput) uxadd_xqt_line ('I', zfile, (const char *) NULL); else pzargs[i] = zfile; } else { struct uuconf_system sfromsys; char abtname[CFILE_NAME_LEN]; struct scmd s; char *zjobid; /* We need to request a remote file. */ iuuconf = uuconf_system_info (puuconf, zsystem, &sfromsys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (! funknown_system (puuconf, zsystem, &sfromsys)) ulog (LOG_FATAL, "%s: System not found", zsystem); } if (fonxqt) { /* The file is already on the system where the command is to be executed. */ if (finput) uxadd_xqt_line ('I', zfile, (const char *) NULL); else pzargs[i] = zfile; } else { char *zdata; if (! sfromsys.uuconf_fcall_transfer && ! sfromsys.uuconf_fcalled_transfer) ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", sfromsys.uuconf_zname); if (zforw != NULL) { /* This is ``uux cmd a!b!file''. To make this work, we would have to be able to set up a request to a to fetch file from b and send it to us. But it turns out that that will not work, because when a sends us the file we will put it in a's spool directory, not the local system spool directory. So we won't have any way to find it. This is not a conceptual problem, and it could doubtless be solved. Please feel free to solve it and send me the solution. */ ulog (LOG_FATAL, "File forwarding not supported"); } /* We must request the file from the remote system to this one. */ zdata = zsysdep_data_file_name (&slocalsys, zxqtloc, bgrade, FALSE, abtname, (char *) NULL, (char *) NULL); if (zdata == NULL) uxabort (); ubuffree (zdata); /* Request the file. The special option '9' is a signal to uucico that it's OK to receive a file into the spool directory; normally such requests are rejected. This privilege is easy to abuse. */ s.bcmd = 'R'; s.pseq = NULL; s.zfrom = zfile; s.zto = zbufcpy (abtname); s.zuser = zuser; s.zoptions = "9"; s.ztemp = ""; s.imode = 0600; s.znotify = ""; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; zjobid = zsysdep_spool_commands (&sfromsys, bgrade, 1, &s); if (zjobid == NULL) uxabort (); if (fjobid) printf ("%s\n", zjobid); ubuffree (zjobid); if (fcall_any) { ubuffree (zcall_system); zcall_system = NULL; } else { fcall_any = TRUE; zcall_system = zbufcpy (sfromsys.uuconf_zname); } if (fxqtlocal) { /* Tell the command execution to wait until the file has been received, and tell it the real file name. */ if (finput) { uxadd_xqt_line ('F', abtname, (char *) NULL); uxadd_xqt_line ('I', abtname, (char *) NULL); } else { char *zbase; zbase = zsysdep_base_name (zfile); if (zbase == NULL) uxabort (); uxadd_xqt_line ('F', abtname, zbase); pzargs[i] = zbase; } } else { char abxtname[CFILE_NAME_LEN]; char *zbase; char *zxqt; FILE *e; /* Now we must arrange to forward the file on to the execution system. We need to get a name to give the file on the execution system (abxtname). */ zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, TRUE, abxtname, (char *) NULL, (char *) NULL); if (zdata == NULL) uxabort (); ubuffree (zdata); zbase = zsysdep_base_name (zfile); if (zbase == NULL) uxabort (); zxqt = zsysdep_xqt_file_name (); if (zxqt == NULL) uxabort (); e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); if (e == NULL) uxabort (); uxrecord_file (zxqt); fprintf (e, "U %s %s\n", zsysdep_login_name (), zlocalname); fprintf (e, "F %s %s\n", abtname, zbase); fprintf (e, "C uucp -C -W -d -g %c %s %s!", bgrade, zbase, sxqtsys.uuconf_zname); if (zforward != NULL) fprintf (e, "%s!", zforward); fprintf (e, "%s\n", abxtname); if (fclose (e) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); if (finput) { uxadd_xqt_line ('F', abxtname, (char *) NULL); uxadd_xqt_line ('I', abxtname, (char *) NULL); ubuffree (zbase); } else { uxadd_xqt_line ('F', abxtname, zbase); pzargs[i] = zbase; } } } (void) uuconf_system_free (puuconf, &sfromsys); } } /* If standard input is to be read from the stdin of uux, we read it here into a temporary file and send it to the execute system. */ if (fread_stdin) { char *zdata; char abtname[CFILE_NAME_LEN]; char abdname[CFILE_NAME_LEN]; FILE *e; zdata = zsysdep_data_file_name (&sxqtsys, zxqtloc, bgrade, FALSE, abtname, abdname, (char *) NULL); if (zdata == NULL) uxabort (); e = esysdep_fopen (zdata, FALSE, FALSE, TRUE); if (e == NULL) uxabort (); eXclose = e; uxrecord_file (zdata); uxcopy_stdin (e); eXclose = NULL; if (fclose (e) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); if (fxqtlocal) uxadd_xqt_line ('I', abtname, (const char *) NULL); else { zinput_from = zbufcpy (abtname); zinput_to = zbufcpy (abdname); zinput_temp = zinput_from; finputcopied = TRUE; } } /* If we are returning standard input, or we're putting the status in a file, we can't use an E command. */ if (fretstdin) uxadd_xqt_line ('B', (const char *) NULL, (const char *) NULL); if (zstatus_file != NULL) uxadd_xqt_line ('M', zstatus_file, (const char *) NULL); /* Get the complete command line, and decide whether the command needs to be executed by the shell. */ fneedshell = FALSE; if (zcmd[strcspn (zcmd, ZSHELLCHARS)] != '\0') fneedshell = TRUE; clen = strlen (zcmd) + 1; for (i = 0; i < cargs; i++) { if (pzargs[i] != NULL) { clen += strlen (pzargs[i]) + 1; if (pzargs[i][strcspn (pzargs[i], ZSHELLCHARS)] != '\0') fneedshell = TRUE; } } zfullcmd = zbufalc (clen); strcpy (zfullcmd, zcmd); for (i = 0; i < cargs; i++) { if (pzargs[i] != NULL) { strcat (zfullcmd, " "); strcat (zfullcmd, pzargs[i]); } } /* If we haven't written anything to the execution file yet, and we have a standard input file, and we're not forwarding, then every other option can be handled in an E command. */ if (eXxqt_file == NULL && zinput_from != NULL && zforward == NULL) { struct scmd s; char aboptions[10]; char *zoptions; /* Set up an E command. */ s.bcmd = 'E'; s.pseq = NULL; s.zuser = zuser; s.zfrom = zinput_from; s.zto = zinput_to; s.zoptions = aboptions; zoptions = aboptions; *zoptions++ = finputcopied ? 'C' : 'c'; if (fno_ack) *zoptions++ = 'N'; if (ferror_ack) *zoptions++ = 'Z'; if (zrequestor != NULL) *zoptions++ = 'R'; if (fneedshell) *zoptions++ = 'e'; *zoptions = '\0'; s.ztemp = zinput_temp; s.imode = 0666; if (zrequestor == NULL) zrequestor = "\"\""; s.znotify = zrequestor; s.cbytes = -1; s.zcmd = zfullcmd; s.ipos = 0; ++cXcmds; pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, cXcmds * sizeof (struct scmd)); pasXcmds[cXcmds - 1] = s; } else { /* Finish up the execute file. */ uxadd_xqt_line ('U', zuser, zxqtloc); if (zinput_from != NULL) { uxadd_xqt_line ('F', zinput_to, (char *) NULL); uxadd_xqt_line ('I', zinput_to, (char *) NULL); uxadd_send_file (zinput_from, zinput_to, finputcopied ? "C" : "c", zinput_temp, zforward, &sxqtsys, zxqtloc, bgrade); } if (fno_ack) uxadd_xqt_line ('N', (const char *) NULL, (const char *) NULL); if (ferror_ack) uxadd_xqt_line ('Z', (const char *) NULL, (const char *) NULL); if (zrequestor != NULL) uxadd_xqt_line ('R', zrequestor, (const char *) NULL); if (fneedshell) uxadd_xqt_line ('e', (const char *) NULL, (const char *) NULL); uxadd_xqt_line ('C', zfullcmd, (const char *) NULL); if (fclose (eXxqt_file) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); eXxqt_file = NULL; /* If the execution is to occur on another system, we must now arrange to copy the execute file to this system. */ if (! fxqtlocal) uxadd_send_file (abxqt_tname, abxqt_xname, "C", abxqt_tname, zforward, &sxqtsys, zxqtloc, bgrade); } /* If we got a signal, get out before spooling anything. */ if (FGOT_SIGNAL ()) uxabort (); /* From here on in, it's too late. We don't call uxabort. */ if (cXcmds > 0) { char *zjobid; if (! sxqtsys.uuconf_fcall_transfer && ! sxqtsys.uuconf_fcalled_transfer) ulog (LOG_FATAL, "Not permitted to transfer files to or from %s", sxqtsys.uuconf_zname); zjobid = zsysdep_spool_commands (&sxqtsys, bgrade, cXcmds, pasXcmds); if (zjobid == NULL) { ulog_close (); usysdep_exit (FALSE); } if (fjobid) printf ("%s\n", zjobid); ubuffree (zjobid); if (fcall_any) { ubuffree (zcall_system); zcall_system = NULL; } else { fcall_any = TRUE; zcall_system = zbufcpy (sxqtsys.uuconf_zname); } } /* If all that worked, make a log file entry. All log file reports up to this point went to stderr. */ ulog_to_file (puuconf, TRUE); ulog_system (sxqtsys.uuconf_zname); ulog_user (zuser); ulog (LOG_NORMAL, "Queuing %s", zfullcmd); ulog_close (); if (! fuucico) fexit = TRUE; else { if (zcall_system != NULL) fexit = fsysdep_run ("uucico", "-s", zcall_system); else if (fcall_any) fexit = fsysdep_run ("uucico", "-r1", (const char *) NULL); else fexit = TRUE; } usysdep_exit (fexit); /* Avoid error about not returning a value. */ return 0; } /* Report command usage. */ static void uxusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uux [options] [-] command\n"); fprintf (stderr, " -,-p: Read standard input for standard input of command\n"); fprintf (stderr, " -c: Do not copy local files to spool directory (default)\n"); fprintf (stderr, " -C: Copy local files to spool directory\n"); fprintf (stderr, " -l: link local files to spool directory\n"); fprintf (stderr, " -g grade: Set job grade (must be alphabetic)\n"); fprintf (stderr, " -n: Do not report completion status\n"); fprintf (stderr, " -z: Report completion status only on error\n"); fprintf (stderr, " -r: Do not start uucico daemon\n"); fprintf (stderr, " -a address: Address to mail status report to\n"); fprintf (stderr, " -b: Return standard input with status report\n"); fprintf (stderr, " -s file: Report completion status to file\n"); fprintf (stderr, " -j: Report job id\n"); fprintf (stderr, " -x debug: Set debugging level\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* Add a line to the execute file. */ static void uxadd_xqt_line (bchar, z1, z2) int bchar; const char *z1; const char *z2; { if (eXxqt_file == NULL) { eXxqt_file = esysdep_fopen (zXxqt_name, FALSE, FALSE, TRUE); if (eXxqt_file == NULL) uxabort (); } if (z1 == NULL) fprintf (eXxqt_file, "%c\n", bchar); else if (z2 == NULL) fprintf (eXxqt_file, "%c %s\n", bchar, z1); else fprintf (eXxqt_file, "%c %s %s\n", bchar, z1, z2); } /* Add a file to be sent to the execute system. */ static void uxadd_send_file (zfrom, zto, zoptions, ztemp, zforward, qxqtsys, zxqtloc, bgrade) const char *zfrom; const char *zto; const char *zoptions; const char *ztemp; const char *zforward; const struct uuconf_system *qxqtsys; const char *zxqtloc; int bgrade; { struct scmd s; if (zforward != NULL) { char *zbase; char *zxqt; char abtname[CFILE_NAME_LEN]; char abdname[CFILE_NAME_LEN]; char abxname[CFILE_NAME_LEN]; FILE *e; /* We want to forward this file through the first execution system to other systems. We set up a remote execution of uucp to forward the file. */ zbase = zsysdep_base_name (zfrom); if (zbase == NULL) uxabort (); zxqt = zsysdep_data_file_name (qxqtsys, zxqtloc, bgrade, TRUE, abtname, abdname, abxname); if (zxqt == NULL) uxabort (); e = esysdep_fopen (zxqt, FALSE, FALSE, TRUE); if (e == NULL) uxabort (); uxrecord_file (zxqt); fprintf (e, "U %s %s\n", zsysdep_login_name (), zxqtloc); fprintf (e, "F %s %s\n", abdname, zbase); fprintf (e, "C uucp -C -W -d -g %c %s %s!%s\n", bgrade, zbase, zforward, zto); ubuffree (zbase); if (fclose (e) != 0) ulog (LOG_FATAL, "fclose: %s", strerror (errno)); /* Send the execution file. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (abtname); s.zto = zbufcpy (abxname); s.zuser = zsysdep_login_name (); s.zoptions = "C"; s.ztemp = s.zfrom; s.imode = 0666; s.znotify = NULL; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ++cXcmds; pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, cXcmds * sizeof (struct scmd)); pasXcmds[cXcmds - 1] = s; /* Send the data file to abdname where the execution file will expect it. */ zto = abdname; } s.bcmd = 'S'; s.pseq = NULL; s.zfrom = zbufcpy (zfrom); s.zto = zbufcpy (zto); s.zuser = zsysdep_login_name (); s.zoptions = zbufcpy (zoptions); s.ztemp = zbufcpy (ztemp); s.imode = 0666; s.znotify = ""; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ++cXcmds; pasXcmds = (struct scmd *) xrealloc ((pointer) pasXcmds, cXcmds * sizeof (struct scmd)); pasXcmds[cXcmds - 1] = s; } /* Copy stdin to a file. This is a separate function because it may call setjmp. */ static void uxcopy_stdin (e) FILE *e; { CATCH_PROTECT size_t cread; char ab[1024]; do { size_t cwrite; /* I want to use fread here, but there is a bug in some versions of SVR4 which causes fread to return less than a complete buffer even if EOF has not been reached. This is not online time, so speed is not critical, but it's still quite annoying to have to use an inefficient algorithm. */ cread = 0; if (fsysdep_catch ()) { usysdep_start_catch (); while (cread < sizeof (ab)) { int b; if (FGOT_SIGNAL ()) uxabort (); /* There's an unimportant race here. If the user hits ^C between the FGOT_SIGNAL we just did and the time we enter getchar, we won't know about the signal (unless we're doing a longjmp, but we normally aren't). It's not a big problem, because the user can just hit ^C again. */ b = getchar (); if (b == EOF) break; ab[cread] = b; ++cread; } } usysdep_end_catch (); if (FGOT_SIGNAL ()) uxabort (); if (cread > 0) { cwrite = fwrite (ab, sizeof (char), cread, e); if (cwrite != cread) ulog (LOG_FATAL, "fwrite: Wrote %d when attempted %d", (int) cwrite, (int) cread); } } while (cread == sizeof ab); } /* Keep track of all files we have created so that we can delete them if we get a signal. The argument will be on the heap. */ static int cXfiles; static const char **pXaz; static void uxrecord_file (zfile) const char *zfile; { pXaz = (const char **) xrealloc ((pointer) pXaz, (cXfiles + 1) * sizeof (const char *)); pXaz[cXfiles] = zfile; ++cXfiles; } /* Delete all the files we have recorded and exit. */ static void uxabort () { int i; if (eXxqt_file != NULL) (void) fclose (eXxqt_file); if (eXclose != NULL) (void) fclose (eXclose); for (i = 0; i < cXfiles; i++) (void) remove (pXaz[i]); ulog_close (); usysdep_exit (FALSE); } trcspn (pzargs[i], ZSHELLCHARS)] != '\0') fneedshell = TRUE; } } uucp-1.04/uuxqt.81004440004150000170000000422005337263533010642 037777777777 1 0 ''' $Id: uuxqt.8,v 1.5 1993/01/24 01:03:58 ian Rel $ .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) bid; 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 ("%uucp-1.04/uuxqt.c1004440004150000170000011123405337263534010722 037777777777 1 0 /* 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.65 1993/01/17 04:22:26 ian Rel $"; #endif #include #include #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* The program name. */ char abProgram[] = "uuxqt"; /* Static variables used to unlock things if we get a fatal error. */ static int iQlock_seq = -1; static const char *zQunlock_cmd; static const char *zQunlock_file; static boolean fQunlock_directory; int cQmaxuuxqts; /* Static variables to free in uqcleanup. */ static char *zQoutput; static char *zQmail; /* Local functions. */ static void uqusage P((void)); static void uqabort P((void)); static void uqdo_xqt_file P((pointer puuconf, const char *zfile, const char *zbase, const struct uuconf_system *qsys, const char *zlocalname, const char *zcmd, boolean *pfprocessed)); static void uqcleanup P((const char *zfile, int iflags)); static boolean fqforward P((const char *zfile, char **pzallowed, const char *zlog, const char *zmail)); /* Long getopt options. */ static const struct option asQlongopts[] = { { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* The type of command to execute (NULL for any type). */ const char *zcmd = NULL; /* The configuration file name. */ const char *zconfig = NULL; /* The system to execute commands for. */ const char *zdosys = NULL; int iopt; pointer puuconf; int iuuconf; const char *zlocalname; boolean fany; char *z, *zgetsys; boolean ferr; boolean fsys; struct uuconf_system ssys; while ((iopt = getopt_long (argc, argv, "c:I:s:x:", asQlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'c': /* Set the type of command to execute. */ zcmd = optarg; break; case 'I': /* Set the configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 's': zdosys = optarg; break; case 'x': #if DEBUG > 1 /* Set the debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 0: /* Long option found and flag set. */ break; default: uqusage (); break; } } if (optind != argc) uqusage (); iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif iuuconf = uuconf_maxuuxqts (puuconf, &cQmaxuuxqts); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #ifdef SIGINT usysdep_signal (SIGINT); #endif #ifdef SIGHUP usysdep_signal (SIGHUP); #endif #ifdef SIGQUIT usysdep_signal (SIGQUIT); #endif #ifdef SIGTERM usysdep_signal (SIGTERM); #endif #ifdef SIGPIPE usysdep_signal (SIGPIPE); #endif usysdep_initialize (puuconf, INIT_SUID); ulog_to_file (puuconf, TRUE); ulog_fatal_fn (uqabort); iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) exit (EXIT_FAILURE); } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); fsys = FALSE; /* If we were given a system name, canonicalize it, since the system dependent layer will not be returning aliases. */ if (zdosys != NULL) { iuuconf = uuconf_system_info (puuconf, zdosys, &ssys); if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_FATAL, "%s: System not found", zdosys); else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); zdosys = zbufcpy (ssys.uuconf_zname); fsys = TRUE; } /* Limit the number of uuxqt processes, and make sure we're the only uuxqt daemon running for this command. */ iQlock_seq = ixsysdep_lock_uuxqt (zcmd, cQmaxuuxqts); if (iQlock_seq < 0) { ulog_close (); usysdep_exit (TRUE); } zQunlock_cmd = zcmd; /* Keep scanning the execute files until we don't process any of them. */ do { fany = FALSE; /* Look for each execute file, and run it. */ if (! fsysdep_get_xqt_init ()) { ulog_close (); usysdep_exit (FALSE); } while ((z = zsysdep_get_xqt (&zgetsys, &ferr)) != NULL) { const char *zloc; boolean fprocessed; char *zbase; /* It would be more efficient to pass zdosys down to the routines which retrieve execute files. */ if (zdosys != NULL && strcmp (zdosys, zgetsys) != 0) { ubuffree (z); ubuffree (zgetsys); continue; } if (! fsys || strcmp (ssys.uuconf_zname, zgetsys) != 0) { if (fsys) (void) uuconf_system_free (puuconf, &ssys); iuuconf = uuconf_system_info (puuconf, zgetsys, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (z); ubuffree (zgetsys); continue; } else if (strcmp (zgetsys, zlocalname) == 0) { iuuconf = uuconf_system_local (puuconf, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (z); ubuffree (zgetsys); continue; } } else { if (! funknown_system (puuconf, zgetsys, &ssys)) { ulog (LOG_ERROR, "%s: Execute file for unknown system %s", z, zgetsys); (void) remove (z); ubuffree (z); ubuffree (zgetsys); continue; } } } fsys = TRUE; } /* If we've received a signal, get out of the loop. */ if (FGOT_SIGNAL ()) { ubuffree (z); ubuffree (zgetsys); break; } zloc = ssys.uuconf_zlocalname; if (zloc == NULL) zloc = zlocalname; ulog_system (ssys.uuconf_zname); zbase = zsysdep_base_name (z); uqdo_xqt_file (puuconf, z, zbase, &ssys, zloc, zcmd, &fprocessed); ubuffree (zbase); ulog_system ((const char *) NULL); ulog_user ((const char *) NULL); if (fprocessed) fany = TRUE; ubuffree (z); ubuffree (zgetsys); } usysdep_get_xqt_free (); } while (fany && ! FGOT_SIGNAL ()); (void) fsysdep_unlock_uuxqt (iQlock_seq, zcmd, cQmaxuuxqts); iQlock_seq = -1; ulog_close (); if (FGOT_SIGNAL ()) ferr = TRUE; usysdep_exit (! ferr); /* Avoid errors about not returning a value. */ return 0; } static void uqusage () { fprintf (stderr, "Taylor UUCP version %s, copyright (C) 1991, 1992 Ian Lance Taylor\n", VERSION); fprintf (stderr, "Usage: uuxqt [-c cmd] [-I file] [-s system] [-x debug]\n"); fprintf (stderr, " -c cmd: Set type of command to execute\n"); fprintf (stderr, " -s system: Execute commands only for named system\n"); fprintf (stderr, " -x debug: Set debugging level (0 for none, 9 is max)\n"); #if HAVE_TAYLOR_CONFIG fprintf (stderr, " -I file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ exit (EXIT_FAILURE); } /* This is the abort function called when we get a fatal error. */ static void uqabort () { #if ! HAVE_HDB_LOGGING /* When using HDB logging, it's a pain to have no system name. */ ulog_system ((const char *) NULL); #endif ulog_user ((const char *) NULL); if (fQunlock_directory) (void) fsysdep_unlock_uuxqt_dir (iQlock_seq); if (zQunlock_file != NULL) (void) fsysdep_unlock_uuxqt_file (zQunlock_file); if (iQlock_seq >= 0) (void) fsysdep_unlock_uuxqt (iQlock_seq, zQunlock_cmd, cQmaxuuxqts); ulog_close (); usysdep_exit (FALSE); } /* An execute file is a series of lines. The first character of each line is a command. The following commands are defined: C command-line I standard-input O standard-output [ system ] F required-file filename-to-use R requestor-address U user system Z (acknowledge if command failed; default) N (no acknowledgement on failure) n (acknowledge if command succeeded) B (return command input on error) e (process with sh) E (process with exec) M status-file # comment Unrecognized commands are ignored. We actually do not recognize the Z command, since it requests default behaviour. We always send mail on failure, unless the N command appears. We never send mail on success, unless the n command appears. This code does not currently support the B or M commands. */ /* Command arguments. */ static char **azQargs; /* Command as a complete string. */ static char *zQcmd; /* Standard input file name. */ static char *zQinput; /* Standard output file name. */ static char *zQoutfile; /* Standard output system. */ static char *zQoutsys; /* Number of required files. */ static int cQfiles; /* Names of required files. */ static char **azQfiles; /* Names required files should be renamed to (NULL if original is OK). */ static char **azQfiles_to; /* Requestor address (this is where mail should be sent). */ static char *zQrequestor; /* User name. */ static const char *zQuser; /* System name. */ static const char *zQsystem; /* This is set by the N flag, meaning that no acknowledgement should be mailed on failure. */ static boolean fQno_ack; /* This is set by the n flag, meaning that acknowledgement should be mailed if the command succeeded. */ static boolean fQsuccess_ack; /* This is set by the B flag, meaning that command input should be mailed to the requestor if an error occurred. */ static boolean fQsend_input; /* This is set by the E flag, meaning that exec should be used to execute the command. */ static boolean fQuse_exec; /* The status should be copied to this file on the requesting host. */ static const char *zQstatus_file; #if ALLOW_SH_EXECUTION /* This is set by the e flag, meaning that sh should be used to execute the command. */ static boolean fQuse_sh; #endif /* ALLOW_SH_EXECUTION */ static int iqcmd P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int iqout P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int iqfile P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int iqrequestor P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int iquser P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int iqset P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static const struct uuconf_cmdtab asQcmds[] = { { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, iqcmd }, { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zQinput, NULL }, { "O", UUCONF_CMDTABTYPE_FN | 0, NULL, iqout }, { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, iqfile }, { "R", UUCONF_CMDTABTYPE_FN, NULL, iqrequestor }, { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, iquser }, { "N", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQno_ack, iqset }, { "n", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQsuccess_ack, iqset }, /* Some systems create execution files in which B takes an argument; I don't know what it means, so I just ignore it. */ { "B", UUCONF_CMDTABTYPE_FN | 0, (pointer) &fQsend_input, iqset }, #if ALLOW_SH_EXECUTION { "e", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_sh, iqset }, #endif { "E", UUCONF_CMDTABTYPE_FN | 1, (pointer) &fQuse_exec, iqset }, { "M", UUCONF_CMDTABTYPE_STRING, (pointer) &zQstatus_file, NULL }, { NULL, 0, NULL, NULL } }; /* Handle the C command: store off the arguments. */ /*ARGSUSED*/ static int iqcmd (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { int i; size_t clen; if (argc <= 1) return UUCONF_CMDTABRET_CONTINUE; azQargs = (char **) xmalloc (argc * sizeof (char *)); clen = 0; for (i = 1; i < argc; i++) { azQargs[i - 1] = zbufcpy (argv[i]); clen += strlen (argv[i]) + 1; } azQargs[i - 1] = NULL; zQcmd = (char *) xmalloc (clen); zQcmd[0] = '\0'; for (i = 1; i < argc - 1; i++) { strcat (zQcmd, argv[i]); strcat (zQcmd, " "); } strcat (zQcmd, argv[i]); return UUCONF_CMDTABRET_CONTINUE; } /* Handle the O command, which may have one or two arguments. */ /*ARGSUSED*/ static int iqout (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { const char *zbase = (const char *) pinfo; if (argc != 2 && argc != 3) { ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zbase, argv[0]); return UUCONF_CMDTABRET_CONTINUE; } zQoutfile = zbufcpy (argv[1]); if (argc == 3) zQoutsys = zbufcpy (argv[2]); return UUCONF_CMDTABRET_CONTINUE; } /* Handle the F command, which may have one or two arguments. */ /*ARGSUSED*/ static int iqfile (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { const char *zbase = (const char *) pinfo; if (argc != 2 && argc != 3) { ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zbase, argv[0]); return UUCONF_CMDTABRET_CONTINUE; } /* If this file is not in the spool directory, just ignore it. */ if (! fspool_file (argv[1])) return UUCONF_CMDTABRET_CONTINUE; ++cQfiles; azQfiles = (char **) xrealloc ((pointer) azQfiles, cQfiles * sizeof (char *)); azQfiles_to = (char **) xrealloc ((pointer) azQfiles_to, cQfiles * sizeof (char *)); azQfiles[cQfiles - 1] = zbufcpy (argv[1]); if (argc == 3) azQfiles_to[cQfiles - 1] = zbufcpy (argv[2]); else azQfiles_to[cQfiles - 1] = NULL; return UUCONF_CMDTABRET_CONTINUE; } /* Handle the R command, which may have one or two arguments. */ /*ARGSUSED*/ static int iqrequestor (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { const char *zbase = (const char *) pinfo; if (argc != 2 && argc != 3) { ulog (LOG_ERROR, "%s: %s: Wrong number of arguments", zbase, argv[0]); return UUCONF_CMDTABRET_CONTINUE; } /* We normally have a single argument, which is the ``requestor'' address, to which we should send any success or error messages. Apparently the DOS program UUPC sends two arguments, which are the username and the host. */ if (argc == 2) zQrequestor = zbufcpy (argv[1]); else { zQrequestor = zbufalc (strlen (argv[1]) + strlen (argv[2]) + sizeof "!"); sprintf (zQrequestor, "%s!%s", argv[2], argv[1]); } return UUCONF_CMDTABRET_CONTINUE; } /* Handle the U command, which takes two arguments. */ /*ARGSUSED*/ static int iquser (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { zQuser = argv[1]; zQsystem = argv[2]; return UUCONF_CMDTABRET_KEEP; } /* Handle various commands which just set boolean variables. */ /*ARGSUSED*/ static int iqset (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { boolean *pf = (boolean *) pvar; *pf = TRUE; return UUCONF_CMDTABRET_CONTINUE; } /* The execution processing does a lot of things that have to be cleaned up. Rather than try to add the appropriate statements to each return point, we keep a set of flags indicating what has to be cleaned up. The actual clean up is done by the function uqcleanup. */ #define REMOVE_FILE (01) #define REMOVE_NEEDED (02) #define FREE_QINPUT (04) #define FREE_OUTPUT (010) #define FREE_MAIL (020) /* Process an execute file. The zfile argument is the name of the execute file. The zbase argument is the base name of zfile. The qsys argument describes the system it came from. The zcmd argument is the name of the command we are executing (from the -c option) or NULL if any command is OK. This sets *pfprocessed to TRUE if the file is ready to be executed. */ static void uqdo_xqt_file (puuconf, zfile, zbase, qsys, zlocalname, zcmd, pfprocessed) pointer puuconf; const char *zfile; const char *zbase; const struct uuconf_system *qsys; const char *zlocalname; const char *zcmd; boolean *pfprocessed; { char *zabsolute; boolean ferr; FILE *e; int iuuconf; int i; int iclean; const char *zmail; char *zoutput; char *zinput; char abtemp[CFILE_NAME_LEN]; char abdata[CFILE_NAME_LEN]; char *zerror; struct uuconf_system soutsys; const struct uuconf_system *qoutsys; boolean fshell; size_t clen; char *zfullcmd; boolean ftemp; *pfprocessed = FALSE; e = fopen (zfile, "r"); if (e == NULL) return; azQargs = NULL; zQcmd = NULL; zQinput = NULL; zQoutfile = NULL; zQoutsys = NULL; cQfiles = 0; azQfiles = NULL; azQfiles_to = NULL; zQrequestor = NULL; zQuser = NULL; zQsystem = NULL; fQno_ack = FALSE; fQsuccess_ack = FALSE; fQsend_input = FALSE; fQuse_exec = FALSE; zQstatus_file = NULL; #if ALLOW_SH_EXECUTION fQuse_sh = FALSE; #endif iuuconf = uuconf_cmd_file (puuconf, e, asQcmds, (pointer) zbase, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_CASE, (pointer) NULL); (void) fclose (e); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return; } iclean = 0; if (azQargs == NULL) { ulog (LOG_ERROR, "%s: No command given", zbase); uqcleanup (zfile, iclean | REMOVE_FILE); return; } if (zcmd != NULL) { if (strcmp (zcmd, azQargs[0]) != 0) { uqcleanup (zfile, iclean); return; } } else { /* If there is a lock file for this particular command already, it means that some other uuxqt is supposed to handle it. */ if (fsysdep_uuxqt_locked (azQargs[0])) { uqcleanup (zfile, iclean); return; } } /* Lock this particular file. */ if (! fsysdep_lock_uuxqt_file (zfile)) { uqcleanup (zfile, iclean); return; } zQunlock_file = zfile; /* Now that we have the file locked, make sure it still exists. Otherwise another uuxqt could have just finished processing it and removed the lock file. */ if (! fsysdep_file_exists (zfile)) { uqcleanup (zfile, iclean); return; } if (zQuser != NULL) ulog_user (zQuser); else if (zQrequestor != NULL) ulog_user (zQrequestor); else ulog_user ("unknown"); /* Make sure that all the required files exist, and get their full names in the spool directory. */ for (i = 0; i < cQfiles; i++) { char *zreal; zreal = zsysdep_spool_file_name (qsys, azQfiles[i], (pointer) NULL); if (zreal == NULL) { uqcleanup (zfile, iclean); return; } if (! fsysdep_file_exists (zreal)) { uqcleanup (zfile, iclean); return; } ubuffree (azQfiles[i]); azQfiles[i] = zbufcpy (zreal); ubuffree (zreal); } /* Lock the execution directory. */ if (! fsysdep_lock_uuxqt_dir (iQlock_seq)) { ulog (LOG_ERROR, "Could not lock execute directory"); uqcleanup (zfile, iclean); return; } fQunlock_directory = TRUE; iclean |= REMOVE_FILE | REMOVE_NEEDED; *pfprocessed = TRUE; /* Get the address to mail results to. Prepend the system from which the execute file originated, since mail addresses are relative to it. */ zmail = NULL; if (zQrequestor != NULL) zmail = zQrequestor; else if (zQuser != NULL) zmail = zQuser; if (zmail != NULL && zQsystem != NULL #if HAVE_INTERNET_MAIL && strchr (zmail, '@') == NULL #endif && strcmp (zQsystem, zlocalname) != 0) { char *zset; zset = zbufalc (strlen (zQsystem) + strlen (zmail) + 2); sprintf (zset, "%s!%s", zQsystem, zmail); zmail = zset; zQmail = zset; iclean |= FREE_MAIL; } /* The command "uucp" is handled specially. We make sure that the appropriate forwarding is permitted, and we add a -u argument to specify the user. */ if (strcmp (azQargs[0], "uucp") == 0) { char *zfrom, *zto; boolean fmany; char **azargs; const char *zuser, *zsystem; zfrom = NULL; zto = NULL; fmany = FALSE; /* Skip all the options, and get the from and to specs. We don't permit multiple arguments. */ for (i = 1; azQargs[i] != NULL; i++) { if (azQargs[i][0] == '-') { char *zopts; for (zopts = azQargs[i] + 1; *zopts != '\0'; zopts++) { /* The -g, -n, and -s options take an argument. */ if (*zopts == 'g' || *zopts == 'n' || *zopts == 's') { if (zopts[1] == '\0') ++i; break; } /* The -I, -u and -x options are not permitted. */ if (*zopts == 'I' || *zopts == 'u' || *zopts == 'x') { *zopts = 'r'; if (zopts[1] != '\0') zopts[1] = '\0'; else { ++i; azQargs[i] = zbufcpy ("-r"); } break; } } } else if (zfrom == NULL) zfrom = azQargs[i]; else if (zto == NULL) zto = azQargs[i]; else { fmany = TRUE; break; } } /* Add the -u argument. This is required to let uucp do the correct permissions checking on the file transfer. */ for (i = 0; azQargs[i] != NULL; i++) ; azargs = (char **) xmalloc ((i + 2) * sizeof (char *)); azargs[0] = azQargs[0]; zuser = zQuser; if (zuser == NULL) zuser = "uucp"; zsystem = zQsystem; if (zsystem == NULL) zsystem = qsys->uuconf_zname; azargs[1] = zbufalc (strlen (zsystem) + strlen (zuser) + sizeof "-u!"); sprintf (azargs[1], "-u%s!%s", zsystem, zuser); memcpy (azargs + 2, azQargs + 1, i * sizeof (char *)); xfree ((pointer) azQargs); azQargs = azargs; /* Find the uucp binary. */ zabsolute = zsysdep_find_command ("uucp", qsys->uuconf_pzcmds, qsys->uuconf_pzpath, &ferr); if (zabsolute == NULL && ! ferr) { const char *azcmds[2]; /* If "uucp" is not a permitted command, then the forwarding entries must be set. */ if (! fqforward (zfrom, qsys->uuconf_pzforward_from, "from", zmail) || ! fqforward (zto, qsys->uuconf_pzforward_to, "to", zmail)) { uqcleanup (zfile, iclean); return; } /* If "uucp" is not a permitted command, then only uucp requests with a single source are permitted, since that is all that will be generated by uucp or uux. */ if (fmany) { ulog (LOG_ERROR, "Bad uucp request %s", zQcmd); if (zmail != NULL && ! fQno_ack) { const char *az[20]; i = 0; az[i++] = "Your execution request failed because it was an"; az[i++] = " unsupported uucp request.\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } uqcleanup (zfile, iclean); return; } azcmds[0] = "uucp"; azcmds[1] = NULL; zabsolute = zsysdep_find_command ("uucp", (char **) azcmds, qsys->uuconf_pzpath, &ferr); } if (zabsolute == NULL) { if (! ferr) ulog (LOG_ERROR, "Can't find uucp executable"); uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } } else { /* Get the pathname to execute. */ zabsolute = zsysdep_find_command (azQargs[0], qsys->uuconf_pzcmds, qsys->uuconf_pzpath, &ferr); if (zabsolute == NULL) { if (ferr) { /* If we get an error, try again later. */ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } /* Not permitted. Send mail to requestor. */ ulog (LOG_ERROR, "Not permitted to execute %s", azQargs[0]); if (zmail != NULL && ! fQno_ack) { const char *az[20]; i = 0; az[i++] = "Your execution request failed because you are not"; az[i++] = " permitted to execute\n\t"; az[i++] = azQargs[0]; az[i++] = "\non this system.\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } uqcleanup (zfile, iclean); return; } } ubuffree (azQargs[0]); azQargs[0] = zabsolute; for (i = 1; azQargs[i] != NULL; i++) { char *zlocal; zlocal = zsysdep_xqt_local_file (qsys, azQargs[i]); if (zlocal != NULL) { ubuffree (azQargs[i]); azQargs[i] = zlocal; } } #if ! ALLOW_FILENAME_ARGUMENTS /* Check all the arguments to make sure they don't try to specify files they are not permitted to access. */ for (i = 1; azQargs[i] != NULL; i++) { if (! fsysdep_xqt_check_file (qsys, azQargs[i])) { if (zmail != NULL && ! fQno_ack) { const char *az[20]; const char *zfailed; zfailed = azQargs[i]; i = 0; az[i++] = "Your execution request failed because you are not"; az[i++] = " permitted to refer to file\n\t"; az[i++] = zfailed; az[i++] = "\non this system.\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } uqcleanup (zfile, iclean); return; } } #endif /* ! ALLOW_FILENAME_ARGUMENTS */ ulog (LOG_NORMAL, "Executing %s (%s)", zbase, zQcmd); if (zQinput != NULL) { boolean fspool; char *zreal; fspool = fspool_file (zQinput); if (fspool) zreal = zsysdep_spool_file_name (qsys, zQinput, (pointer) NULL); else zreal = zsysdep_local_file (zQinput, qsys->uuconf_zpubdir); if (zreal == NULL) { /* If we get an error, try again later. */ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } zQinput = zreal; iclean |= FREE_QINPUT; if (! fspool && ! fin_directory_list (zQinput, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, TRUE, (const char *) NULL)) { ulog (LOG_ERROR, "Not permitted to read %s", zQinput); if (zmail != NULL && ! fQno_ack) { const char *az[20]; i = 0; az[i++] = "Your execution request failed because you are"; az[i++] = " not permitted to read\n\t"; az[i++] = zQinput; az[i++] = "\non this system.\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } uqcleanup (zfile, iclean); return; } } zoutput = NULL; if (zQoutfile == NULL) qoutsys = NULL; else if (zQoutsys != NULL && strcmp (zQoutsys, zlocalname) != 0) { char *zdata; /* The output file is destined for some other system, so we must use a temporary file to catch standard output. */ if (strcmp (zQoutsys, qsys->uuconf_zname) == 0) qoutsys = qsys; else { iuuconf = uuconf_system_info (puuconf, zQoutsys, &soutsys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } if (! funknown_system (puuconf, zQoutsys, &soutsys)) { ulog (LOG_ERROR, "Can't send standard output to unknown system %s", zQoutsys); /* We don't send mail to unknown systems, either. Maybe we should. */ uqcleanup (zfile, iclean); return; } } qoutsys = &soutsys; } zdata = zsysdep_data_file_name (qoutsys, zlocalname, BDEFAULT_UUX_GRADE, FALSE, abtemp, abdata, (char *) NULL); if (zdata == NULL) { /* If we get an error, try again later. */ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } zoutput = zdata; zQoutput = zoutput; iclean |= FREE_OUTPUT; } else { boolean fok; qoutsys = NULL; /* If we permitted the standard output to be redirected into the spool directory, people could set up phony commands. */ if (fspool_file (zQoutfile)) fok = FALSE; else { zoutput = zsysdep_local_file (zQoutfile, qsys->uuconf_zpubdir); if (zoutput == NULL) { /* If we get an error, try again later. */ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } ubuffree (zQoutfile); zQoutfile = zoutput; /* Make sure it's OK to receive this file. */ fok = fin_directory_list (zQoutfile, qsys->uuconf_pzremote_receive, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL); } if (! fok) { ulog (LOG_ERROR, "Not permitted to write to %s", zQoutfile); if (zmail != NULL && ! fQno_ack) { const char *az[20]; i = 0; az[i++] = "Your execution request failed because you are"; az[i++] = " not permitted to write to\n\t"; az[i++] = zQoutfile; az[i++] = "\non this system.\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } uqcleanup (zfile, iclean); return; } } /* Move the required files to the execution directory if necessary. */ zinput = zQinput; if (! fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles, (const char **) azQfiles_to, TRUE, iQlock_seq, &zinput)) { /* If we get an error, try again later. */ uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } if (zQinput != NULL && strcmp (zQinput, zinput) != 0) { if ((iclean & FREE_QINPUT) != 0) ubuffree (zQinput); zQinput = zinput; iclean |= FREE_QINPUT; } #if ALLOW_SH_EXECUTION fshell = fQuse_sh; #else fshell = FALSE; #endif /* Get a shell command which uses the full path of the command to execute. */ clen = 0; for (i = 0; azQargs[i] != NULL; i++) clen += strlen (azQargs[i]) + 1; zfullcmd = zbufalc (clen); strcpy (zfullcmd, azQargs[0]); for (i = 1; azQargs[i] != NULL; i++) { strcat (zfullcmd, " "); strcat (zfullcmd, azQargs[i]); } if (! fsysdep_execute (qsys, zQuser == NULL ? (const char *) "uucp" : zQuser, (const char **) azQargs, zfullcmd, zQinput, zoutput, fshell, iQlock_seq, &zerror, &ftemp)) { ubuffree (zfullcmd); if (ftemp) { ulog (LOG_NORMAL, "Will retry later (%s)", zbase); if (zoutput != NULL) (void) remove (zoutput); if (zerror != NULL) { (void) remove (zerror); ubuffree (zerror); } (void) fsysdep_move_uuxqt_files (cQfiles, (const char **) azQfiles, (const char **) azQfiles_to, FALSE, iQlock_seq, (char **) NULL); uqcleanup (zfile, iclean &~ (REMOVE_FILE | REMOVE_NEEDED)); *pfprocessed = FALSE; return; } ulog (LOG_NORMAL, "Execution failed (%s)", zbase); if (zmail != NULL && ! fQno_ack) { const char **pz; int cgot; FILE *eerr; int istart; cgot = 20; pz = (const char **) xmalloc (cgot * sizeof (const char *)); i = 0; pz[i++] = "Execution request failed:\n\t"; pz[i++] = zQcmd; pz[i++] = "\n"; if (zerror == NULL) eerr = NULL; else eerr = fopen (zerror, "r"); if (eerr == NULL) { pz[i++] = "There was no output on standard error\n"; istart = i; } else { char *zline; size_t cline; pz[i++] = "Standard error output was:\n"; istart = i; zline = NULL; cline = 0; while (getline (&zline, &cline, eerr) > 0) { if (i >= cgot) { cgot += 20; pz = ((const char **) xrealloc ((pointer) pz, cgot * sizeof (const char *))); } pz[i++] = zbufcpy (zline); } (void) fclose (eerr); xfree ((pointer) zline); } (void) fsysdep_mail (zmail, "Execution failed", i, pz); for (; istart < i; istart++) ubuffree ((char *) pz[istart]); xfree ((pointer) pz); } if (qoutsys != NULL) (void) remove (zoutput); } else { ubuffree (zfullcmd); if (zmail != NULL && fQsuccess_ack) { const char *az[20]; i = 0; az[i++] = "\nExecution request succeeded:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution succeded", i, az); } /* Now we may have to uucp the output to some other machine. */ if (qoutsys != NULL) { struct scmd s; /* Fill in the command structure. */ s.bcmd = 'S'; s.pseq = NULL; s.zfrom = abtemp; s.zto = zQoutfile; if (zQuser != NULL) s.zuser = zQuser; else s.zuser = "uucp"; if (zmail != NULL && fQsuccess_ack) s.zoptions = "Cn"; else s.zoptions = "C"; s.ztemp = abtemp; s.imode = 0666; if (zmail != NULL && fQsuccess_ack) s.znotify = zmail; else s.znotify = ""; s.cbytes = -1; s.zcmd = NULL; s.ipos = 0; ubuffree (zsysdep_spool_commands (qoutsys, BDEFAULT_UUX_GRADE, 1, &s)); } } if (zerror != NULL) { (void) remove (zerror); ubuffree (zerror); } uqcleanup (zfile, iclean); } /* Clean up the results of uqdo_xqt_file. */ static void uqcleanup (zfile, iflags) const char *zfile; int iflags; { int i; DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, "uqcleanup: %s, %d", zfile, iflags); if (zQunlock_file != NULL) { (void) fsysdep_unlock_uuxqt_file (zQunlock_file); zQunlock_file = NULL; } if ((iflags & REMOVE_FILE) != 0) (void) remove (zfile); if ((iflags & REMOVE_NEEDED) != 0) { for (i = 0; i < cQfiles; i++) { if (azQfiles[i] != NULL) (void) remove (azQfiles[i]); } } if ((iflags & FREE_QINPUT) != 0) ubuffree (zQinput); if ((iflags & FREE_OUTPUT) != 0) ubuffree (zQoutput); if ((iflags & FREE_MAIL) != 0) ubuffree (zQmail); if (fQunlock_directory) { (void) fsysdep_unlock_uuxqt_dir (iQlock_seq); fQunlock_directory = FALSE; } for (i = 0; i < cQfiles; i++) { ubuffree (azQfiles[i]); ubuffree (azQfiles_to[i]); } ubuffree (zQoutfile); ubuffree (zQoutsys); ubuffree (zQrequestor); if (azQargs != NULL) { for (i = 0; azQargs[i] != NULL; i++) ubuffree (azQargs[i]); xfree ((pointer) azQargs); azQargs = NULL; } xfree ((pointer) zQcmd); zQcmd = NULL; xfree ((pointer) azQfiles); azQfiles = NULL; xfree ((pointer) azQfiles_to); azQfiles_to = NULL; } /* Check whether forwarding is permitted. */ static boolean fqforward (zfile, pzallowed, zlog, zmail) const char *zfile; char **pzallowed; const char *zlog; const char *zmail; { const char *zexclam; zexclam = strchr (zfile, '!'); if (zexclam != NULL) { size_t clen; char *zsys; boolean fret; clen = zexclam - zfile; zsys = zbufalc (clen + 1); memcpy (zsys, zfile, clen); zsys[clen] = '\0'; fret = FALSE; if (pzallowed != NULL) { char **pz; for (pz = pzallowed; *pz != NULL; pz++) { if (strcmp (*pz, "ANY") == 0 || strcmp (*pz, zsys) == 0) { fret = TRUE; break; } } } if (! fret) { ulog (LOG_ERROR, "Not permitted to forward %s %s (%s)", zlog, zsys, zQcmd); if (zmail != NULL && ! fQno_ack) { int i; const char *az[20]; i = 0; az[i++] = "Your execution request failed because you are"; az[i++] = " not permitted to forward files\n"; az[i++] = zlog; az[i++] = " the system\n\t"; az[i++] = zsys; az[i++] = "\n"; az[i++] = "Execution requested was:\n\t"; az[i++] = zQcmd; az[i++] = "\n"; (void) fsysdep_mail (zmail, "Execution failed", i, az); } } ubuffree (zsys); return fret; } return TRUE; } 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[iuucp-1.04/xcmd.c1004440004150000170000002322705337263534010473 037777777777 1 0 /* 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.9 1993/01/19 05:10:46 ian Rel $"; #endif #include #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "prot.h" #include "trans.h" /* Local functions. */ static boolean flocal_xcmd_request P((struct stransfer *qtrans, struct sdaemon *qdaemon)); static boolean flocal_xcmd_await_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon, const char *zdata, size_t cdata)); static boolean fremote_xcmd_reply P((struct stransfer *qtrans, struct sdaemon *qdaemon)); /* Handle a local work request. We just set up the request for transmission. */ boolean flocal_xcmd_init (qdaemon, qcmd) struct sdaemon *qdaemon; struct scmd *qcmd; { struct stransfer *qtrans; qtrans = qtransalc (qcmd); qtrans->psendfn = flocal_xcmd_request; return fqueue_local (qdaemon, qtrans); } /* Send the execution request to the remote system. */ static boolean flocal_xcmd_request (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { size_t clen; char *zsend; boolean fret; ulog (LOG_NORMAL, "Requesting work: %s to %s", qtrans->s.zfrom, qtrans->s.zto); /* We send the string X from to user options We put a dash in front of options. */ clen = (strlen (qtrans->s.zfrom) + strlen (qtrans->s.zto) + strlen (qtrans->s.zuser) + strlen (qtrans->s.zoptions) + 7); zsend = zbufalc (clen); sprintf (zsend, "X %s %s %s -%s", qtrans->s.zfrom, qtrans->s.zto, qtrans->s.zuser, qtrans->s.zoptions); fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, zsend, qtrans->ilocal, qtrans->iremote); ubuffree (zsend); if (! fret) { utransfree (qtrans); return FALSE; } qtrans->fcmd = TRUE; qtrans->precfn = flocal_xcmd_await_reply; return fqueue_receive (qdaemon, qtrans); } /* Get a reply to an execution request from the remote system. */ /*ARGSUSED*/ static boolean flocal_xcmd_await_reply (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struct sdaemon *qdaemon; const char *zdata; size_t cdata; { qtrans->precfn = NULL; if (zdata[0] != 'X' || (zdata[1] != 'Y' && zdata[1] != 'N')) { ulog (LOG_ERROR, "Bad response to work request"); utransfree (qtrans); return FALSE; } if (zdata[1] == 'N') { ulog (LOG_ERROR, "%s: work request denied", qtrans->s.zfrom); (void) fmail_transfer (FALSE, qtrans->s.zuser, (const char *) NULL, "work request denied", qtrans->s.zfrom, qdaemon->qsys->uuconf_zname, qtrans->s.zto, (const char *) NULL, (const char *) NULL); } (void) fsysdep_did_work (qtrans->s.pseq); utransfree (qtrans); return TRUE; } /* Handle a remote work request. This just queues up the requests for later processing. */ boolean fremote_xcmd_init (qdaemon, qcmd, iremote) struct sdaemon *qdaemon; struct scmd *qcmd; int iremote; { const struct uuconf_system *qsys; const char *zexclam; const struct uuconf_system *qdestsys; struct uuconf_system sdestsys; char *zdestfile; boolean fmkdirs; struct stransfer *qtrans; char *zuser; char aboptions[5]; char *zfrom; boolean fret; char *zfile; ulog (LOG_NORMAL, "Work requested: %s to %s", qcmd->zfrom, qcmd->zto); qsys = qdaemon->qsys; zexclam = strchr (qcmd->zto, '!'); if (zexclam == NULL || zexclam == qcmd->zto || strncmp (qdaemon->zlocalname, qcmd->zto, (size_t) (zexclam - qcmd->zto)) == 0) { const char *zconst; /* The files are supposed to be copied to the local system. */ qdestsys = NULL; if (zexclam == NULL) zconst = qcmd->zto; else zconst = zexclam + 1; zdestfile = zsysdep_local_file (zconst, qsys->uuconf_zpubdir); if (zdestfile == NULL) return FALSE; zuser = NULL; fmkdirs = strchr (qcmd->zoptions, 'f') != NULL; } else { size_t clen; char *zcopy; int iuuconf; char *zoptions; clen = zexclam - qcmd->zto; zcopy = zbufalc (clen + 1); memcpy (zcopy, qcmd->zto, clen); zcopy[clen] = '\0'; iuuconf = uuconf_system_info (qdaemon->puuconf, zcopy, &sdestsys); if (iuuconf == UUCONF_NOT_FOUND) { if (! funknown_system (qdaemon->puuconf, zcopy, &sdestsys)) { ulog (LOG_ERROR, "%s: System not found", zcopy); ubuffree (zcopy); qtrans = qtransalc (qcmd); qtrans->psendfn = fremote_xcmd_reply; qtrans->pinfo = (pointer) "XN"; qtrans->iremote = iremote; return fqueue_remote (qdaemon, qtrans); } } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, qdaemon->puuconf, iuuconf); ubuffree (zcopy); return FALSE; } ubuffree (zcopy); qdestsys = &sdestsys; zdestfile = zbufcpy (zexclam + 1); zuser = zbufalc (strlen (qdestsys->uuconf_zname) + strlen (qcmd->zuser) + sizeof "!"); sprintf (zuser, "%s!%s", qdestsys->uuconf_zname, qcmd->zuser); zoptions = aboptions; *zoptions++ = 'C'; if (strchr (qcmd->zoptions, 'd') != NULL) *zoptions++ = 'd'; if (strchr (qcmd->zoptions, 'm') != NULL) *zoptions++ = 'm'; *zoptions = '\0'; fmkdirs = TRUE; } /* At this point we prepare to confirm the remote request. We could actually fork here and let the child spool up the requests. */ qtrans = qtransalc (qcmd); qtrans->psendfn = fremote_xcmd_reply; qtrans->pinfo = (pointer) "XY"; qtrans->iremote = iremote; if (! fqueue_remote (qdaemon, qtrans)) { ubuffree (zdestfile); ubuffree (zuser); return FALSE; } /* Now we have to process each source file. The source specification may or may use wildcards. */ zfrom = zsysdep_local_file (qcmd->zfrom, qsys->uuconf_zpubdir); if (zfrom == NULL) { ubuffree (zdestfile); ubuffree (zuser); return FALSE; } if (! fsysdep_wildcard_start (zfrom)) { ubuffree (zfrom); ubuffree (zdestfile); ubuffree (zuser); return FALSE; } fret = TRUE; while ((zfile = zsysdep_wildcard (zfrom)) != NULL) { char *zto; char abtname[CFILE_NAME_LEN]; if (! fsysdep_file_exists (zfile)) { ulog (LOG_ERROR, "%s: no such file", zfile); continue; } /* Make sure the remote system is permitted to read the specified file. */ if (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, TRUE, (const char *) NULL)) { ulog (LOG_ERROR, "%s: not permitted to send", zfile); break; } if (qdestsys != NULL) { /* We really should get the original grade here. */ zto = zsysdep_data_file_name (qdestsys, qdaemon->zlocalname, BDEFAULT_UUCP_GRADE, FALSE, abtname, (char *) NULL, (char *) NULL); if (zto == NULL) { fret = FALSE; break; } } else { zto = zsysdep_add_base (zdestfile, zfile); if (zto == NULL) { fret = FALSE; break; } /* We only accept a local destination if the remote system has the right to create files there. */ if (! fin_directory_list (zto, qsys->uuconf_pzremote_receive, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL)) { ulog (LOG_ERROR, "%s: not permitted to receive", zto); ubuffree (zto); break; } } /* Copy the file either to the final destination or to the spool directory. */ if (! fcopy_file (zfile, zto, qdestsys == NULL, fmkdirs)) { ubuffree (zto); break; } ubuffree (zto); /* If there is a destination system, queue it up. */ if (qdestsys != NULL) { struct scmd ssend; char *zjobid; ssend.bcmd = 'S'; ssend.pseq = NULL; ssend.zfrom = zfile; ssend.zto = zdestfile; ssend.zuser = zuser; ssend.zoptions = aboptions; ssend.ztemp = abtname; ssend.imode = ixsysdep_file_mode (zfile); ssend.znotify = ""; ssend.cbytes = -1; ssend.zcmd = NULL; ssend.ipos = 0; zjobid = zsysdep_spool_commands (qdestsys, BDEFAULT_UUCP_GRADE, 1, &ssend); if (zjobid == NULL) break; ubuffree (zjobid); } ubuffree (zfile); } if (zfile != NULL) ubuffree (zfile); (void) fsysdep_wildcard_end (); ubuffree (zdestfile); if (qdestsys != NULL) (void) uuconf_system_free (qdaemon->puuconf, &sdestsys); ubuffree (zfrom); ubuffree (zuser); return fret; } /* Reply to a remote work request. */ static boolean fremote_xcmd_reply (qtrans, qdaemon) struct stransfer *qtrans; struct sdaemon *qdaemon; { boolean fret; fret = (*qdaemon->qproto->pfsendcmd) (qdaemon, (const char *) qtrans->pinfo, qtrans->ilocal, qtrans->iremote); utransfree (qtrans); return fret; } 473 037777777777 1 0 uucp-1.04/contrib/0407750004150000170000000000005337265077010230 5 0 1 0 uucp-1.04/contrib/Dial.Hayes1006640004150000170000000363305252524720012674 037777777777 1 0 #!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 # lean flocal_xcmd_await_reply (qtrans, qdaemon, zdata, cdata) struct stransfer *qtrans; struuucp-1.04/contrib/Hangup.Hayes1006640004150000170000000246105252524721013244 037777777777 1 0 #!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 = strchr (qcmd->zoptions, 'f') != NULL; } else { size_t clen; char *zcopy; int iuuconf; char *zoptions; clen = zexclam - qcmd->zto; zcopy = zbufalc (clen + 1);uucp-1.04/contrib/Login.LAT1006640004150000170000000612605252524721012443 037777777777 1 0 #!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 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 == uucp-1.04/contrib/Login.PortSel1006640004150000170000000573405252524722013420 037777777777 1 0 #!xchat # @(#) Login.PortSelUnix V1.0 Tue Sep 1 14:57:05 1992 (Bob Denny) # # NOTE: Untested with xchat V1.1. Taken from DECUS UUCP. # # From: "Kent C. Brodie" # uucp: {uunet!marque,csd4.milw.wisc.edu}!moocow!brodie # special script for "uwmcsd4", have to go through a port selector (and then # log in via standard Unix procedures). # # Also included is the ability to wait in the port selector queue. # Be forwarned that the debug log can get pretty big depending on # how many times you "wait" in the queue. # (C) 1989 Kent C. Brodie - Medical College of Wisconsin # P0 is systemname , P1 is username, P2 is password. zero # send a CR to get the selector's attention. Sleep a little bit # due to large login text of selector. It sends "Which System?" # when it's ready. getprtslct: count ifgtr noprtslct 6 break send \r sleep 2000 flush expect prtslctok ystem? timeout getprtslct 15000 noprtslct: logerr Sent cr, no "Which System?" from port selector failed # Send the system name. We either get "OK" (connected), or we # get "No ports available, would you like to wait?" (wait in queue) prtslctok: zero sendstr 0 send \r expect connected OK expect prtslctwait wait? timeout noconnect 10000 # Usually we get "nn Your place in queue" messages. JUST in case we # get a free port right away, check for 'Are you ready?' as well. prtslctwait: zero send Y\r expect prtslctque queue expect prtslctrdy ready? timeout prtwaitbad 70000 prtwaitbad: logerr Sent "Y" to wait in queue, did not get valid response. failed # Here's where we wait in the queue. The port selector sends us a status # message about once a minute. We either get "nn Your place in queue" # or we get "System Available. Are you Ready?". # If something goes wrong, we time out waiting for either response. # The reason we don't sleep for 40-50 seconds is because as SOON as the # port is ready, it informs us. If we wait too long, it drops us. # This setup is laid out for a maximum of 20 "tries" which is ABOUT # 20 minutes. Note: This constant retrying can make log files # kind of big.... prtslctque: count ifgtr prtslcttry 20 expect prtslctque queue expect prtslctrdy ready? timeout noportwait 70000 prtslcttry: logerr Too many (20) wait/retries -- queue too busy. failed prtslctrdy: send Y\r expect connected OK timeout noconnect 20000 noportwait: logerr Timed out awaiting place in port queue failed noconnect: logerr Sent system name, no "OK" from selector failed # standard Unix login stuff. Send cr, expect "ogin:", if no, send a break # (which tells Unix to try the next bit rate) and try again. connected: send \r zero goto waitlogin sendbreak: count ifgtr nolgi 6 flush break waitlogin: expect gotlogin ogin: timeout sendbreak 5000 nolgi: logerr No login: prompt failed gotlogin: sendstr 1 send \r expect gotword word: timeout nopwd 10000 nopwd: logerr No password: prompt failed gotword: sendstr 2 send \r success ial send \r flush timeout timeoutuucp-1.04/contrib/Login.VMS1006640004150000170000000411605252524722012466 037777777777 1 0 #!xchat # @(#) Login.VMS V1.1 Tue Sep 1 13:24:54 1992 (Bob Denny) # # # xchat script for logging into a VMS system. If no VMS password # parameter supplied, skips password phase of VMS login. If syspass # parameter given, will go through steps needed to log into a VMS # system where a "system password" was set on the port. # # Cannot handle situation where system password is required but # no password needed. # # # Usage: # xchat Login.VMS username [ password [ syspass ] ] # # Uncomment the lines starting with "###" to get debug logging. # start: ### dbgfile Login.Log ### dbgset 15 sleep 2000 # Wait 2 seconds zero flush # Flush typeahead ifnstr login 2 # Skip sys passwd if not given # # Need system password. Send to get bell. # Try 5 times at 2 sec. intervals. Skip to do # username if we see "Username:". # syspass: count ifgtr nobell 5 # Fail after 5 tries send \r timeout syspass 2000 # Wait 2 sec. and try again expect gotbell \007 expect gotlogin Username: # # Got the bell. Send the system password. Repeat 5 times # at 2 sec. intervals. Fail if we don't get Username: # gotbell: zero sleep 2000 l1: count ifgtr nologin 5 # Fail after 5 tries sendstr 2 send \r timeout l1 2000 # Wait 2 sec. and try again expect gotlogin Username: # # Start here if no system password supplied. # Send until we get Username: Try 5 times at 2 sec. intervals. # login: count ifgtr nologin 5 # Fail after 5 tries send \r timeout login 2000 # Wait 2 sec. and try again expect gotlogin Username: # # Got VMS "Username:" prompt. Send the username. If a password # was given, wait for the "Password:" prompt. Die after 10 seconds. # if no password was given, we're done! # gotlogin: sendstr 0 send \r ifnstr done 1 timeout nopasswd 10000 expect gotpasswd Password: # # Got VMS "Password:" prompt. Send the password and we're done! # gotpasswd: sendstr 1 send \r # # Success! # done: success # # ERROR HANDLERS # nobell: logerr No VMS system password prompt (bell) failed nologin: logerr No VMS Username: prompt failed nopasswd: logerr No VMS Password: prompt. failed 1006640004150000170000000612605252524721012443 037777777777 1 0 uucp-1.04/contrib/Makefile.uurt1006640004150000170000000073205277255100013463 037777777777 1 0 # # 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 # Skip server password if not given # uucp-1.04/contrib/Makefile.xchat1006640004150000170000000067305252524703013600 037777777777 1 0 # # 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 ername. Just give 'uucp'. # svrlogin: send uucp\r timeout deadmux uucp-1.04/contrib/README1006640004150000170000000352305277255272011720 037777777777 1 0 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. 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 # huucp-1.04/contrib/README-UURATE1006640004150000170000000106105277255217012715 037777777777 1 0 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. ailed # 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" wuucp-1.04/contrib/README-XCHAT1006640004150000170000000250605252525413012553 037777777777 1 0 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) # # Cannot handle situation where system password is required but # no password needed. # # # Usage: # xchat Login.VMS username [ password [ syspass ] ] # # Uncomment the lines startinguucp-1.04/contrib/savelog.man1006640004150000170000000530005155170426013160 037777777777 1 0 .\" @(#)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. 37777777777 1 0 uucp-1.04/contrib/savelog.sh1007750004150000170000001434005155170426013026 037777777777 1 0 #! /bin/sh # @(#)util/savelog.sh 1.4 26 Oct 1991 22:49:39 # # savelog - save a log file # # Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll # # See the file COPYING, distributed with smail, for restriction # and warranty information. # # usage: savelog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-l] file... # # -m mode - chmod log files to mode # -u user - chown log files to user # -g group - chgrp log files to group # -c cycle - save cycle versions of the logfile (default: 7) # -t - touch file # -l - don't compress any log files (default: compress) # file - log file names # # The savelog command saves and optionally compresses old copies of files # into an 'dir'/OLD sub-directory. The 'dir' directory is determined from # the directory of each 'file'. # # Older version of 'file' are named: # # OLD/'file'. # # where is the version number, 0 being the newest. By default, # version numbers > 0 are compressed (unless -l prevents it). The # version number 0 is never compressed on the off chance that a process # still has 'file' opened for I/O. # # If the 'file' does not exist or if it is zero length, no further processing # is performed. However if -t was also given, it will be created. # # For files that do exist and have lengths greater than zero, the following # actions are performed. # # 1) Version numered files are cycled. That is version 6 is moved to # version 7, version is moved to becomes version 6, ... and finally # version 0 is moved to version 1. Both compressed names and # uncompressed names are cycled, regardless of -t. Missing version # files are ignored. # # 2) The new OLD/file.1 is compressed and is changed subject to # the -m, -u and -g flags. This step is skipped if the -t flag # was given. # # 3) The main file is moved to OLD/file.0. # # 4) If the -m, -u, -g or -t flags are given, then file is created # (as an empty file) subject to the given flags. # # 5) The new OLD/file.0 is chanegd subject to the -m, -u and -g flags. # # Note: If the OLD sub-directory does not exist, it will be created # with mode 0755. # # Note: If no -m, -u or -g flag is given, then the primary log file is # not created. # # Note: Since the version numbers start with 0, version number # is never formed. The count must be at least 2. # # Bugs: If a process is still writing to the file.0 and savelog # moved it to file.1 and compresses it, data could be lost. # Smail does not have this problem in general because it # restats files often. # common location PATH="X_UTIL_PATH_X:X_SECURE_PATH_X"; export PATH COMPRESS="X_COMPRESS_X" COMP_FLAG="X_COMP_FLAG_X" DOT_Z="X_DOT_Z_X" CHOWN="X_CHOWN_X" GETOPT="X_UTIL_BIN_DIR_X/getopt" # parse args exitcode=0 # no problems to far prog=$0 mode= user= group= touch= count=7 set -- `$GETOPT m:u:g:c:lt $*` if [ $# -eq 0 -o $? -ne 0 ]; then echo "usage: $prog [-m mode][-u user][-g group][-t][-c cycle][-l] file ..." 1>&2 exit 1 fi for i in $*; do case $i in -m) mode=$2; shift 2;; -u) user=$2; shift 2;; -g) group=$2; shift 2;; -c) count=$2; shift 2;; -t) touch=1; shift;; -l) COMPRESS=""; shift;; --) shift; break;; esac done if [ "$count" -lt 2 ]; then echo "$prog: count must be at least 2" 1>&2 exit 2 fi # cycle thru filenames while [ $# -gt 0 ]; do # get the filename filename=$1 shift # catch bogus files if [ -b "$filename" -o -c "$filename" -o -d "$filename" ]; then echo "$prog: $filename is not a regular file" 1>&2 exitcode=3 continue fi # if not a file or empty, do nothing major if [ ! -s $filename ]; then # if -t was given and it does not exist, create it if [ ! -z "$touch" -a ! -f $filename ]; then touch $filename if [ "$?" -ne 0 ]; then echo "$prog: could not touch $filename" 1>&2 exitcode=4 continue fi if [ ! -z "$user" ]; then $CHOWN $user $filename fi if [ ! -z "$group" ]; then chgrp $group $filename fi if [ ! -z "$mode" ]; then chmod $mode $filename fi fi continue fi # be sure that the savedir exists and is writable savedir=`expr "$filename" : '\(.*\)/'` if [ -z "$savedir" ]; then savedir=./OLD else savedir=$savedir/OLD fi if [ ! -s $savedir ]; then mkdir $savedir if [ "$?" -ne 0 ]; then echo "$prog: could not mkdir $savedir" 1>&2 exitcode=5 continue fi chmod 0755 $savedir fi if [ ! -d $savedir ]; then echo "$prog: $savedir is not a directory" 1>&2 exitcode=6 continue fi if [ ! -w $savedir ]; then echo "$prog: directory $savedir is not writable" 1>&2 exitcode=7 continue fi # deterine our uncompressed file names newname=`expr "$filename" : '.*/\(.*\)'` if [ -z "$newname" ]; then newname=$savedir/$filename else newname=$savedir/$newname fi # cycle the old compressed log files cycle=`expr $count - 1` rm -f $newname.$cycle $newname.$cycle$DOT_Z while [ "$cycle" -gt 1 ]; do # --cycle oldcycle=$cycle cycle=`expr $cycle - 1` # cycle log if [ -f $newname.$cycle$DOT_Z ]; then mv -f $newname.$cycle$DOT_Z $newname.$oldcycle$DOT_Z fi if [ -f $newname.$cycle ]; then # file was not compressed for some reason move it anyway mv -f $newname.$cycle $newname.$oldcycle fi done # compress the old uncompressed log if needed if [ -f $newname.0 ]; then if [ -z "$COMPRESS" ]; then newfile=$newname.1 mv $newname.0 $newfile else newfile=$newname.1$DOT_Z $COMPRESS $COMP_FLAG < $newname.0 > $newfile rm -f $newname.0 fi if [ ! -z "$user" ]; then $CHOWN $user $newfile fi if [ ! -z "$group" ]; then chgrp $group $newfile fi if [ ! -z "$mode" ]; then chmod $mode $newfile fi fi # move the file into the file.0 holding place mv -f $filename $newname.0 # replace file if needed if [ ! -z "$touch" -o ! -z "$user" -o \ ! -z "$group" -o ! -z "$mode" ]; then touch $filename fi if [ ! -z "$user" ]; then $CHOWN $user $filename fi if [ ! -z "$group" ]; then chgrp $group $filename fi if [ ! -z "$mode" ]; then chmod $mode $filename fi # fix the permissions on the holding place file.0 file if [ ! -z "$user" ]; then $CHOWN $user $newname.0 fi if [ ! -z "$group" ]; then chgrp $group $newname.0 fi if [ ! -z "$mode" ]; then chmod $mode $newname.0 fi done exit $exitcode 37777777777 1 0 uucp-1.04/contrib/stats.sh1007750004150000170000000116505155242677012535 037777777777 1 0 #!/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); } ' 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 isuucp-1.04/contrib/tstout.c1006640004150000170000001107405155245774012547 037777777777 1 0 /* tstout.c Put together by Ian Lance Taylor This program is used to logout a program run by the tstuu program. I needed this because on Ultrix 4.0 I can't get the uucp program to run without invoking it via /bin/login and having it start up as a shell. If I don't do it this way, it gets a SIGSEGV trap for some reason. Most systems probably don't need to do things this way. It will only work on BSD systems anyhow, I suspect. The code for this comes from "UNIX Network Programming" by W. Richard Stevens, Prentice-Hall 1990. Most of it is from 4.3BSD, as noted in the comments. This program must run suid to root. */ #include #include #include #include #include #include #include static int logout P((const char *zdev)); static void logwtmp P((const char *zdev, const char *zname, const char *zhost)); int main (argc, argv) int argc; char **argv; { char *z; if (argc != 2 || strncmp (argv[1], "/dev/", sizeof "/dev/" - 1) != 0) { fprintf (stderr, "Usage: tstout device\n"); exit (EXIT_FAILURE); } z = argv[1] + 5; if (logout (z)) logwtmp (z, "", ""); chmod (argv[1], 0666); chown (argv[1], 0, 0); *z = 'p'; chmod (argv[1], 0666); chown (argv[1], 0, 0); exit (EXIT_SUCCESS); } /* * Copyright (c) 1988 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)logout.c 5.2 (Berkeley) 2/17/89"; #endif /* LIBC_SCCS and not lint */ #define UTMPFILE "/etc/utmp" /* 0 on failure, 1 on success */ static int logout(line) register const char *line; { register FILE *fp; struct utmp ut; int rval; time_t time(); if (!(fp = fopen(UTMPFILE, "r+"))) return(0); rval = 0; while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) { if (!ut.ut_name[0] || strncmp(ut.ut_line, line, sizeof(ut.ut_line))) continue; bzero(ut.ut_name, sizeof(ut.ut_name)); bzero(ut.ut_host, sizeof(ut.ut_host)); (void)time((time_t *)&ut.ut_time); (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR); (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp); (void)fseek(fp, (long)0, L_INCR); rval = 1; } (void)fclose(fp); return(rval); } /* * Copyright (c) 1988 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88"; #endif /* LIBC_SCCS and not lint */ #define WTMPFILE "/usr/adm/wtmp" static void logwtmp(line, name, host) const char *line, *name, *host; { struct utmp ut; struct stat buf; int fd; time_t time(); char *strncpy(); if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) return; if (!fstat(fd, &buf)) { (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); (void)time((time_t *)&ut.ut_time); if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp)) (void)ftruncate(fd, buf.st_size); } (void)close(fd); } 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 #uucp-1.04/contrib/uuclean1006640004150000170000000172705210564363012412 037777777777 1 0 # 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 \{\} \; en mv -f $newname.$cycle$DOT_Z $newnamuucp-1.04/contrib/uuq.sh1007750004150000170000000602005166433572012202 037777777777 1 0 #!/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 ut together by Ian Lance Taylor This program is used to logout a program run by the tstuu program. I needed this because on Ultrix 4.0 I can't get the uucp program to run without invoking it via /bin/login and having it start up as a shell. If I don't do it this way, it gets a SIGSEGV trap for some reason. Most systems probably don't need to do things this way. It will only work on BSD systems anyhow, I suspect. The code for this comes from "UNIX Netwuucp-1.04/contrib/uurate.c1006640004150000170000004016605301553551012502 037777777777 1 0 /* * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992 * * This program digests log and stats files in the "Taylor" format * and outputs various statistical data to standard out. * * Author: * Bob Denny (denny@alisa.com) * Fri Feb 7 13:38:36 1992 * * Original author: * Mark Pizzolato mark@infopiz.UUCP * * Edits: * Bob Denny - Fri Feb 7 15:04:54 1992 * Heavy rework for Taylor UUCP. This was the (very old) uurate from * DECUS UUCP, which had a single logfile for activity and stats. * Personally, I would have done things differently, with tables * and case statements, but in the interest of time, I preserved * Mark Pizzolato's techniques and style. * * Bob Denny - Sun Aug 30 14:18:50 1992 * Changes to report format suggested by Francois Pinard and others. * Add summary report, format from uutraf.pl (perl script), again * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP. */ char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2"; #include /* Character Classification */ #include #include #include "uucp.h" #define _DEBUG_ 0 /* * Direction of Calling and Data Transmission */ #define IN 0 /* Inbound */ #define OUT 1 /* Outbound */ /* * Data structures used to collect information */ struct File_Stats { int files; /* Files Transferred */ unsigned long bytes; /* Data Size Transferred*/ double time; /* Transmission Time */ }; struct Phone_Call { int calls; /* Call Count */ int succs; /* Successful calls */ double connect_time; /* Connect Time Spent */ struct File_Stats flow[2]; /* Rcvd & Sent Data */ }; struct Execution_Command { struct Execution_Command *next; char Commandname[64]; int count; }; struct Host_entry { struct Host_entry *next; char Hostname[32]; struct Execution_Command *cmds; /* Local Activities */ struct Phone_Call call[2]; /* In & Out Activities */ }; /* * Stuff for getopt() */ extern int optind; /* GETOPT : Option Index */ extern char *optarg; /* GETOPT : Option Value */ extern void *calloc(); static void fmtime(); static void fmbytes(); /* * Default files to read. Taken from Taylor compile-time configuration. * Must look like an argvec, hence the dummy argv[0]. */ static char *(def_logs[3]) = { "", LOGFILE, STATFILE }; /* * Misc. strings for reports */ static char *(file_hdr[2]) = { "\nReceived file statistics:\n", "\nSent file statistics\n" }; /* * BEGIN EXECUTION */ main(argc, argv) int argc; char *argv[]; { char c; char *p, *s; struct Host_entry *hosts = NULL; struct Host_entry *cur = NULL; struct Host_entry *e; struct Execution_Command *cmd; struct Execution_Command *ec; char Hostname[64]; FILE *Log = NULL; char logline[1024]; char *logmsg; int sent; int called; int show_files = 0; /* I prefer boolean, but... */ int show_calls = 0; int show_commands = 0; int show_efficiency = 0; int show_summary = 0; int have_files = 0; int have_calls = 0; int have_commands = 0; int use_stdin = 0; Hostname[0] = '\0'; /* * I wish the compiler had the #error directive! */ #if !HAVE_TAYLOR_LOGGING fprintf(stderr, "uurate cannot be used with your configuration of\n"); fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n"); fprintf(stderr, "TAYLOR_LOGGING configuration.\n"); exit(1); #endif /* * Process the command line arguments */ while((c = getopt(argc, argv, "h:cfexai")) != EOF) { switch(c) { case 'h': strcpy(Hostname, optarg); break; case 'c': show_calls = 1; break; case 'f': show_files = 1; break; case 'x': show_commands = 1; break; case 'e': show_efficiency = 1; break; case 'a': show_calls = show_files = show_commands = show_efficiency = 1; break; case 'i': use_stdin = 1; break; default : goto usage; } } /* * If no report switches given, show summary report. */ if (show_calls == 0 && show_files == 0 && show_efficiency == 0 && show_commands == 0) show_summary = 1; /* * Adjust argv and argc to account for the args processed above. */ argc -= (optind - 1); argv += (optind - 1); /* * If further args present, Assume rest are logfiles for us to process, * otherwise, take input from Log and Stat files provided in the * compilation environment of Taylor UUCP. If -i was given, Log already * points to stdin and no file args are accepted. */ if(argc == 1) /* No file arguments */ { if (use_stdin) /* If -i, read from stdin */ { argc = 2; Log = stdin; } else /* Read from current logs */ { argc = 3; /* Bash argvec to default log/stat files */ argv = &def_logs[0]; } } else if (use_stdin) /* File args with -i is an error */ { fprintf(stderr, "uurate (error): file args given with '-i'\n"); goto usage; } #if _DEBUG_ printf("\n"); #endif /* * MAIN LOGFILE PROCESSING LOOP */ while (argc > 1) { if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL) { perror(argv[1]); return; } #if _DEBUG_ printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1])); #endif /* * Read each line of the logfile and collect information */ while (fgets(logline, sizeof(logline), Log)) { /* * The host name of the other end of the connection is * always the second field of the log line, whether we * are reading a Log file or a Stats file. Set 'p' to * point to the second field, null-terminated. Skip * the line if something is funny. */ if (NULL == (p = strchr(logline, ' '))) continue; ++p; if (NULL != (s = strchr(p, ' '))) *s = '\0'; for (s = p; *s; ++s) if (isupper(*s)) *s = tolower(*s); /* * Skip this line if we got -h and * this line does not contain that host name. */ if (Hostname[0] != '\0') if (0 != strcmp(p, Hostname)) continue; /* * We are within a call block now. If this line is a file * transfer record, determine the direction. If not then * skip the line if it is not interesting. */ if ((s = strchr(++s, ')')) == NULL) continue; logmsg = s + 2; /* Message is 2 characters after ')' */ if (0 == strncmp(logmsg, "sent", 4)) sent = OUT; else if (0 == strncmp(logmsg, "received", 8)) sent = IN; else if ((0 != strncmp(logmsg, "Call complete", 13)) && (0 != strncmp(logmsg, "Calling system", 14)) && (0 != strncmp(logmsg, "Incoming call", 13)) && (0 != strncmp(logmsg, "Executing", 9))) continue; /* * Find the Host_entry for this host, or create a new * one and link it on to the list. */ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname))) { for (cur = hosts; cur != NULL ; cur = cur->next) if (0 == strcmp(cur->Hostname, p)) break; if (cur == NULL) { cur = (struct Host_entry *)calloc(1, sizeof(*hosts)); strcpy(cur->Hostname, p); if (hosts == NULL) hosts = cur; else { for (e = hosts; e->next != NULL; e = e->next); e->next = cur; } } } /* * OK, if this is a uuxqt record, find the Execution_Command * structure for the command being executed, or create a new * one. Then count an execution of this command. */ if (0 == strncmp(logmsg, "Executing", 9)) { if (NULL == (p = strchr(logmsg, '('))) continue; if ((s = strpbrk(++p, " )")) == NULL) continue; *s = '\0'; for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) if (0 == strcmp(cmd->Commandname, p)) break; if (cmd == NULL) { cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd)); strcpy(cmd->Commandname, p); if (cur->cmds == NULL) cur->cmds = cmd; else { for (ec = cur->cmds; ec->next != NULL; ec = ec->next); ec->next = cmd; } } ++cmd->count; have_commands = 1; continue; } /* * Count start of outgoing call. */ if (0 == strncmp(logmsg, "Calling system", 14)) { called = OUT; cur->call[called].calls += 1; have_calls = 1; continue; } /* * Count start of incoming call. */ if (0 == strncmp(logmsg, "Incoming call", 13)) { called = IN; cur->call[called].calls += 1; have_calls = 1; continue; } /* * Handle end of call. Pick up the connect time. */ if (0 == strncmp(logmsg, "Call complete", 13)) { cur->call[called].succs += 1; if (NULL == (s = strchr(logmsg, '('))) continue; cur->call[called].connect_time += atof(s+1); continue; } /* * If we reached here, this must have been a file transfer * record. Count it in the field corresponding to the * direction of the transfer. Count bytes transferred and * the time to transfer as well. */ have_files = 1; cur->call[called].flow[sent].files += 1; if (NULL == (s = strchr(logmsg, ' '))) continue; cur->call[called].flow[sent].bytes += atol(++s); if (NULL == (s = strchr(s, ' '))) continue; if (NULL == (s = strpbrk(s, "0123456789"))) continue; cur->call[called].flow[sent].time += atof(s); } argc -= 1; argv += 1; if(Log != stdin) fclose(Log); } /* * *********** * * REPORTS * * *********** */ /* * Truncate the Hostnames to 8 characters at most. */ for (cur = hosts; cur != NULL; cur = cur->next) cur->Hostname[8] = '\0'; #if _DEBUG_ printf("\n"); #endif /* * Summary report * * I know, this code could be tightened (rbd)... */ if(show_summary) { char t1[32], t2[32], t3[32], t4[32], t5[32]; long ib, ob, b, rf, sf; long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0; double it, ot, ir, or; double t_it=0.0, t_ot=0.0; int nhosts = 0; printf("\n\ Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n"); printf("\ Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n"); printf("\ -------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); for (cur = hosts; cur != NULL; cur = cur->next) { ib = (cur->call[IN].flow[IN].bytes + cur->call[OUT].flow[IN].bytes); fmbytes(ib, t1); t_ib += ib; ob = (cur->call[IN].flow[OUT].bytes + cur->call[OUT].flow[OUT].bytes); fmbytes(ob, t2); t_ob += ob; b = ib + ob; fmbytes(b, t3); t_b += b; it = cur->call[IN].flow[IN].time + cur->call[OUT].flow[IN].time; fmtime(it, t4); t_it += it; ot = cur->call[IN].flow[OUT].time + cur->call[OUT].flow[OUT].time; fmtime(ot, t5); t_ot += ot; rf = cur->call[IN].flow[IN].files + cur->call[OUT].flow[IN].files; t_rf += rf; sf = cur->call[IN].flow[OUT].files + cur->call[OUT].flow[OUT].files; t_sf += sf; ir = (it == 0.0) ? 0.0 : (ib / it); or = (ot == 0.0) ? 0.0 : (ob / ot); printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", cur->Hostname, t1, t2, t3, t4, t5, ir, or, rf, sf); } if(nhosts > 1) { fmbytes(t_ib, t1); fmbytes(t_ob, t2); fmbytes(t_b, t3); fmtime(t_it, t4); fmtime(t_ot, t5); ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it); or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot); printf("\ -------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); printf("\ Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", t1, t2, t3, t4, t5, ir, or, t_rf, t_sf); } } /* * Call statistics report */ if(show_calls && have_calls) { char t1[32], t2[32]; printf("\nCall statistics:\n"); printf("\ sysname callto failto totime callfm failfm fmtime\n"); printf("\ -------- ------ ------ -------- ------ ------ --------\n"); for (cur = hosts; cur != NULL; cur = cur->next) { fmtime(cur->call[OUT].connect_time, t1); fmtime(cur->call[IN].connect_time, t2), printf(" %-8s %6d %6d %8s %6d %6d %8s\n", cur->Hostname, cur->call[OUT].calls, cur->call[OUT].calls - cur->call[OUT].succs, t1, cur->call[IN].calls, cur->call[IN].calls - cur->call[IN].succs, t2); } } /* * File statistics report */ if(show_files && have_files) { char t1[32], t2[32]; for (sent = IN; sent <= OUT; ++sent) { printf(file_hdr[sent]); printf(" sysname files bytes xfr time byte/s\n"); printf(" -------- ------ -------- -------- ------\n"); for (cur = hosts; cur != NULL; cur = cur->next) { double rate; double time; time = cur->call[IN].flow[sent].time + cur->call[OUT].flow[sent].time; if (time == 0.0) continue; rate = (cur->call[IN].flow[sent].bytes + cur->call[OUT].flow[sent].bytes) / time; fmbytes((cur->call[IN].flow[sent].bytes + cur->call[OUT].flow[sent].bytes), t1); fmtime((cur->call[IN].flow[sent].time + cur->call[OUT].flow[sent].time), t2); printf(" %-8s %6d %8s %8s %6.1f\n", cur->Hostname, cur->call[IN].flow[sent].files + cur->call[OUT].flow[sent].files, t1, t2, rate); } } } /* * Efficiency report */ if (show_efficiency && have_files) { char t1[32], t2[32], t3[32]; double total, flow; printf("\nEfficiency:\n"); printf(" sysname conntime flowtime ovhdtime eff. %%\n"); printf(" -------- -------- -------- -------- ------\n"); for (cur = hosts; cur != NULL; cur = cur->next) { total = cur->call[IN].connect_time + cur->call[OUT].connect_time; flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time + cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time; fmtime(total, t1); fmtime(flow, t2); fmtime((total-flow), t3); printf(" %-8s %8s %8s %8s %5.1f%%\n", cur->Hostname, t1, t2, t3, ((flow / total) * 100.0)); } } /* * Command execution report */ if (show_commands & have_commands) { printf("\nCommand executions:\n"); printf(" sysname rmail rnews other\n"); printf(" -------- ------ ------ ------\n"); for (cur = hosts; cur != NULL; cur = cur->next) { int rmail, rnews, other; if (cur->cmds == NULL) continue; rmail = rnews = other = 0; for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) { if (strcmp(cmd->Commandname, "rmail") == 0) rmail += cmd->count; else if (strcmp(cmd->Commandname, "rnews") == 0) rnews += cmd->count; else other += cmd->count; } printf(" %-8s %6d %6d %6d\n", cur->Hostname, rmail, rnews, other); } } return; usage: fprintf(stderr, "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n"); fprintf(stderr,"where:\t-c\tReport call statistics\n"); fprintf(stderr, "\t-f\tReport file transfer statistics\n"); fprintf(stderr, "\t-e\tReport efficiency statistics\n"); fprintf(stderr, "\t-x\tReport command execution statistics\n"); fprintf(stderr, "\t-a\tAll of the above reports\n"); fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n"); fprintf(stderr, "\t-i\tRead log info from standard input\n"); fprintf(stderr, "If no report options given, a compact summary report is given.\n"); fprintf(stderr, "If neither -i nor logfiles given, defaults to reading from\n"); fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE); } /* * fmtime() - Format time in hours & minutes; */ static void fmtime(dsec, buf) double dsec; char *buf; { long hrs, min, lsec; lsec = dsec; hrs = lsec / 3600L; min = (lsec - (hrs * 3600L)) / 60L; sprintf(buf, "%02ld:%02ld", hrs, min); } /* * fmbytes - Format size in bytes */ static void fmbytes(n, buf) unsigned long n; char *buf; { char t; double s = n; if(s >= 10239897.6) /* More than 9999.9K ? */ { s = (double)n / 1048576.0; /* Yes, display in Megabytes */ t = 'M'; } else { s = (double)n / 1024.0; /* Display in Kilobytes */ t = 'K'; } sprintf(buf, "%.1f%c", s, t); } ction. 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 != suucp-1.04/contrib/uurate.man1006640004150000170000001364005263404716013035 037777777777 1 0 .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. t].bytes), t1); fmtime((cur->call[IN].flow[sent].time + cur->call[OUT].flow[sent]uucp-1.04/contrib/uureroute1007550004150000170000000421705267146632013022 037777777777 1 0 #!/usr/local/bin/perl eval ' exec /usr/local/bin/perl $0 "$@" ' if $running_under_some_shell; # From a script by # Newsgroups: comp.sources.misc # Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01 # Date: 26 Feb 92 02:28:37 GMT # # This is a Honey DanBer specific routine written in perl to reroute all # mail queued up for a specific host. It needs to be run as "root" since # uucp will not allow itself to remove others requests. # # Revision *** 92/21/09: Francois Pinard # 1. adapted for Taylor UUCP # # Revision 1.3 91/10/08 09:01:21 src # 1. Rewritten in perl # 2. Add -v option for debugging. # # Revision 1.2 91/10/07 23:57:42 root # 1. Fix mail program path. # 2. Truncate directory name to 7 characters ($progname = $0) =~ s!.*/!!; # save this very early $USAGE = " # Reroute uucp mail # # Usage: $progname [-v] host [host...] # # Options Argument Description # -v Verbose (doesn't execute /bin/sh) # "; $UUSTAT = "/usr/local/bin/uustat"; $SHELL = "/bin/sh"; $SMAIL = "/bin/smail"; sub usage { die join ("\n", @_) . "\n$USAGE\n"; } do "getopts.pl"; &usage ("Invalid Option") unless do Getopts ("vV"); $verbose = ($opt_v ? '-v' : ()); $suffix = ($verbose ? '' : $$); &usage ("No system specified") if $#ARGV < 0; if (!$verbose) { open (SHELL, "| $SHELL"); select SHELL; } while ($system = shift) { $sysprefix = substr ($system, 0, 7); $directory = "/usr/spool/uucp/$sysprefix"; open (UUSTAT, "$UUSTAT -s $system -c rmail |"); print "set -ex\n"; while () { ($jobid, ) = split; ($cfile) = substr ($jobid, length ($jobid) - 5); $cfilename = "$directory/C./C.$cfile"; open (CFILE, $cfilename) || die "Cannot open $cfilename\n"; $_ = ; close CFILE; if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/) { $datafile = "$directory/D./D.$1"; $address = $2; } else { print STDERR; die "Cannot parse previous line from $cfilename\n"; } print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n"; } close UUSTAT; } close SHELL unless $verbose; exit 0; 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 uucp-1.04/contrib/uusnap.c1006640004150000170000001704305217160623012506 037777777777 1 0 /* 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.9 92/05/05 22:51:50 hwr Exp Locker: hwr $"; #endif #include #include #include #include extern char *ctime(time_t*); struct sysInfo { char sysname[10]; /* name of the system to watch */ char *statfile; /* name of its status file */ char *spooldir; /* root of its spooldir */ int in; /* number of unprocessed in-files */ int out; /* number of files to send them */ time_t last; /* last poll time */ time_t next; /* time of next poll */ time_t lastidir; /* time of last in-spooldir access */ time_t lastodir; /* time of last outgoing spd acc */ time_t laststat; /* time of last status file access */ int status; /* status of the system */ int num_retries; /* number of retries */ }; struct sysInfo Systems[MAXSYS]; /* I have extend the system status. If time for the specified system is Never, I say so. To get this to work, one also should extend uucico.c. It is not important to do this. With the normal uucico, one only gets no status. */ const char *azStatus[] = /* Status codes as defined by uucico */ { /* listing them here instead of */ "Conversation complete", /* including the appropriate file */ "Port unavailable", /* reduces the size of the executable */ "Dial failed", "Login failed", "Handshake failed", "Call failed", "Talking", "Wrong time to call", "Time to call = Never !" }; main() { int i; i=get_systems(); display_info(i); exit(0); } int get_systems() { char filename[1024]; char fn[1024]; char line[80]; FILE *fp; int i=0; int j; struct stat stbuf; struct sysInfo sys; strcpy(filename,NEWCONFIGLIB); strcat(filename,"/uusnap.systems"); if ((fp=fopen(filename,"r"))!=NULL) { while (fgets(line,80,fp)!=NULL) { *(rindex(line,'\n'))='\0'; strcpy(sys.sysname,line); /* get the name of the system */ strcpy(fn,SPOOLDIR); /* get the name of the statusfile */ strcat(fn,"/.Status/"); strcat(fn,line); sys.statfile=malloc(strlen(fn)+1); strcpy(sys.statfile,fn); strcpy(fn,SPOOLDIR); /* get the name of the spooldir */ strcat(fn,"/"); strcat(fn,line); sys.spooldir=malloc(strlen(fn)+1); strcpy(sys.spooldir,fn); sys.laststat=0; sys.lastidir=sys.lastodir=0; Systems[i]=sys; /* get_stat_for_system needs it */ get_stat_for_system(i); /* now get the system status */ get_inq_num(i,TRUE); /* number of unprocessed files */ get_outq_num(i,TRUE); /* number of files to send */ i++; } fclose(fp); } else { fprintf(stderr,"Can't open %s \n",filename); exit(1); } return i; } display_info(int numSys) { char *filename; int sysnum; FILE *fp; char contentline[80]; char isTalking=FALSE; struct stat stbuf; struct sysInfo sys; time_t time; filename = (char*)malloc(1024); if (filename == NULL) { fprintf(stderr, "Can't malloc 1024 bytes"); exit(1); } while(TRUE) { display_headline(); for (sysnum=0;sysnum sys.laststat) { get_stat_for_system(sysnum); } if(display_status_line(sysnum)==1) isTalking=TRUE; } if (isTalking) { sleep(WAIT_TALKING); isTalking = FALSE; } else sleep(WAIT_NORMAL); /* wait a bit */ } return 0; } int display_status_line(int sn) { char *time_s; int sys_stat,num_retries,wait; int i; time_t last_time; time_t next_time; struct sysInfo sys; sys = Systems[sn]; printf("%10s ",sys.sysname); get_inq_num(sn); if (sys.in==0) printf(" "); else printf("%3d ",sys.in); get_outq_num(sn); if (sys.out==0) printf(" "); else printf("%3d ",sys.out); time_s = ctime(&sys.last); time_s = time_s + 11; *(time_s+8)='\0'; printf("%8s ",time_s); /* time of last poll */ time_s = ctime(&sys.next); time_s = time_s + 11; *(time_s+8)='\0'; if (sys.last == sys.next) printf(" "); else printf("%8s ",time_s); /* time of next poll */ if (sys.num_retries==0) printf(" "); else printf("%2d ",sys.num_retries); if (sys_stat==6) /* system is talking */ printf("\E[7m"); /* reverse video on */ printf("%s",azStatus[sys.status]); if (sys.status==6) { printf("\E[m\n"); /* reverse video off */ return 1; } else { printf("\n"); return 0; } } display_headline() { printf("\E[;H\E[2J"); /* clear screen */ printf("\E[7muusnap (press CTRL-C to escape)\E[m \n\n"); printf(" System #in #out last next #ret Status\n"); return 0; } get_inq_num(int num,char firstTime) { int i=0; char filename[1024]; struct stat stbuf; DIR *dirp; strcpy(filename,Systems[num].spooldir); strcat(filename,"/X./."); stat(filename,&stbuf); if ((stbuf.st_mtime > Systems[num].lastidir) || (firstTime)) { if ((dirp=opendir(filename))!=NULL) { while(readdir(dirp)) i++; closedir(dirp); stat(filename,&stbuf); Systems[num].lastidir=stbuf.st_mtime; } else { fprintf(stderr,"Can't open %s \n",filename); exit(1); } if (i>=2) i-=2; /* correct . and .. */ Systems[num].in=i; } return 0; } get_outq_num(int sys,char firstTime) { int i=0; char filename[1024]; struct stat stbuf; DIR *dirp; strcpy(filename,Systems[sys].spooldir); strcat(filename,"/C./."); stat(filename,&stbuf); if ((stbuf.st_mtime > Systems[sys].lastodir) || (firstTime)) { if ((dirp=opendir(filename))!=NULL) { while(readdir(dirp)) i++; closedir(dirp); stat(filename,&stbuf); Systems[sys].lastodir=stbuf.st_mtime; } else { fprintf(stderr,"Can't open %s \n",filename); exit(1); } if (i>=2) i-=2; /* correct . and .. */ Systems[sys].out=i; } return 0; } get_stat_for_system(int i) { char fn[80]; struct sysInfo sys; struct stat stbuf; FILE *fp; time_t wait; sys = Systems[i]; stat(sys.statfile,&stbuf); if (stbuf.st_atime > sys.laststat) { if ((fp=fopen(sys.statfile,"r"))!=NULL) { fgets(fn,80,fp); fclose(fp); sscanf(fn,"%d %d %ld %d", &sys.status, &sys.num_retries, &sys.last, &wait); sys.next=sys.last+wait; } else { sys.status=0; sys.num_retries=0; sys.last=0; sys.next=0; } stat(sys.statfile,&stbuf); sys.laststat=stbuf.st_atime; } Systems[i] = sys; return 0; } .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/shuucp-1.04/contrib/uutraf1006640004150000170000001260405277254551012270 037777777777 1 0 #!/usr/local/bin/perl # uutraf.pl -- UUCP Traffic Analyzer # SCCS Status : @(#)@ uutraf 1.7 # Author : Johan Vromans # Created On : *** # Last Modified By: Johan Vromans # Last Modified On: Wed Feb 26 08:52:56 1992 # Update Count : 4 # Status : OK # Requires: : Perl V4 or later # Reads UUCP syslog, and generates a report from it. # # Created by Johan Vromans # Loosely based on an idea by Greg Hackney (hack@texbell.swbt.com) # Usage: uutraf [-taylor|-hdb|-bnu|-bsd] [syslog] # Logfile formats: # # BSD: # # jv mhres (2/23-5:18) (698818735) received 135 b 2 secs # root mhres (2/23-5:19) (698818742) sent 2365 b 3 secs, Pk: 38, Rxmt: 0 # # HDB: # # uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, \ # 474 bytes/sec # # Taylor: # # jv mhres (1992-02-24 20:49:04.06) sent 16234 bytes in 148.780 seconds \ # (109 bytes/sec) # jv mhres (1992-02-24 21:04:05.76) received 449 bytes in 6.550 seconds \ # (68 bytes/sec) $uucp_type = "gnu"; %hosts = (); # hosts seen %bytes_in = (); # of bytes received from host %bytes_out = (); # of bytes sent to host %secs_in = (); # of seconds connect for recving %secs_out = (); # of seconds connect for sending %files_in = (); # of input requests %files_out = (); # of output requests # read info, break the lines and tally if ( $ARGV[0] =~ /^-/ ) { ($uucp_type = substr (shift (@ARGV), 1)) =~ tr/A-Z/a-z/; } if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) { @ARGV = ("/usr/spool/uucp/Stats") unless $#ARGV >= 0; $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " . "(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds"; $uucp_type = 0; $recv = "received"; } elsif ( $uucp_type eq "hdb" || $uucp_type eq "bnu" ) { @ARGV = ("/usr/spool/uucp/.Admin/xferstats") unless $#ARGV >= 0; $pat = "^([^!]+)![^(]+\\(([-0-9:\\/]+)\\).+([<>])-? " . "(\\d+) \\/ (\\d+)\\.(\\d+) secs"; $uucp_type = 1; $recv = "<"; } elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) { @ARGV = ("/usr/spool/uucp/SYSLOG") unless $#ARGV >= 0; $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/]+)\\) \\([^)]+\\) " . "(sent|received) (\\d+) b (\\d+) secs"; $uucp_type = 2; $recv = "received"; } else { die ("Unknown UUCP type: $uucp_type\n"); } $garbage = 0; while ( <> ) { unless ( /$pat/o ) { print STDERR "Possible garbage: $_"; if ( $garbage++ > 10 ) { die ("Too much garbage; wrong UUCP type?\n"); } next; } # gather timestamps $last_date = $2; $first_date = $last_date unless defined $first_date; # initialize new hosts unless ( defined $hosts{$1} ) { $hosts{$1} = $files_in{$1} = $files_out{$1} = $bytes_in{$1} = $bytes_out{$1} = $secs_in{$1} = $secs_out{$1} = 0; } # Taylor and HDB have milliseconds, BSD has not. $secs = ($uucp_type == 2) ? ($5 + ($5 == 0 ? 0.5 : 0)) : ($5 + $6/1000); # tally if ( $3 eq $recv ) { # recv $bytes_in{$1} += $4; $files_in{$1}++; $secs_in{$1} += $secs; } else { # xmit $bytes_out{$1} += $4; $files_out{$1}++; $secs_out{$1} += $secs; } $garbage = 0; } @hosts = keys (%hosts); die ("No info found, stopped\n") if $#hosts < 0; ################ report section ################ $thishost = &gethostname(); $thishost = (defined $thishost) ? "on node $thishost" : "report"; if ( $uucp_type eq 0 ) { # Taylor UUCP substr ($first_date, 16) = ""; substr ($last_date, 16) = ""; } format std_head = @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "UUCP traffic $thishost from $first_date to $last_date" Remote -----------K-Bytes----------- ----Hours---- --Avg CPS-- --Files-- Host Recv Sent Total Recv Sent Recv Sent Recv Sent . format std_out = @<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>> @>>>>> @>>>> @>>>> @>>> @>>> $Zhost, $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs, $Zi_acps, $Zo_acps, $Zi_count, $Zo_count . $^ = "std_head"; $~ = "std_out"; &print_dashes (); reset "T"; # reset totals foreach $host (@hosts) { &print_line ($host, $bytes_in{$host}, $bytes_out{$host}, $secs_in{$host}, $secs_out{$host}, $files_in{$host}, $files_out{$host}); } &print_dashes (); &print_line ("Total", $Ti_bytes, $To_bytes, $Ti_secs, $To_secs, $Ti_count, $To_count); ################ that's it ################ sub print_line { reset "Z"; # reset print fields local ($Zhost, $Zi_bytes, $Zo_bytes, $Zi_secs, $Zo_secs, $Zi_count, $Zo_count) = @_; $Ti_bytes += $Zi_bytes; $To_bytes += $Zo_bytes; $Zt_bytes = $Zi_bytes + $Zo_bytes; $Tt_bytes += $Zt_bytes; $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) : "0"; $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) : "0"; $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000); $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000); $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000); $Zi_hrs = sprintf ("%.1f", $Zi_secs/3600); $Zo_hrs = sprintf ("%.1f", $Zo_secs/3600); $Ti_secs += $Zi_secs; $To_secs += $Zo_secs; $Ti_count += $Zi_count; $To_count += $Zo_count; write; } sub print_dashes { $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes = $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count = "------------"; write; # easy, isn't it? } ################ missing ################ sub gethostname { $ENV{"SHELL"} = "/bin/sh"; $try = `uuname -l 2>/dev/null`; chop $try; return $+ if $try =~ /^[-.\w]+$/; return undef; } filename = (char*)malloc(1024); if (filename == NULL) { fprintf(stderr, "Can't malloc 1024 bytes"); exit(1); } uucp-1.04/contrib/uutry1006640004150000170000000167505211224321012134 037777777777 1 0 #!/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 ff */ return 1; } else { printf("\n"); return 0; } }uucp-1.04/contrib/xc-conf.h-dist1006640004150000170000000230505252524706013476 037777777777 1 0 /* * ************* * * 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 "/" */ n,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; } uucp-1.04/contrib/xchat.c1006640004150000170000010150705252526157012310 037777777777 1 0 /* * *********** * * XCHAT.C * * *********** * * Extended chat processor for Taylor UUCP. See accompanying documentation. * * Written by: * Bob Denny (denny@alisa.com) * Based on code in DECUS UUCP (for VAX/VMS) * * History: * Version 1.0 shipped with Taylor 1.03. No configuration info inside. * * Bob Denny - Sun Aug 30 18:41:30 1992 * V1.1 - long overdue changes for other systems. Rip out interval * timer code, use timer code from Taylor UUCP, use select() * for timed reads. Use Taylor UUCP "conf.h" file to set * configuration for this program. Add defaulting of script * and log file paths. * * Bugs: * Does not support BSD terminal I/O. Anyone care to add it? */ #include #include #include #include #include #include #include #include #include "xc-conf.h" /* * Pick a timing routine to use, as done in Taylor UUCP. */ #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL #define USE_SELECT_TIMER 0 #else #define USE_SELECT_TIMER HAVE_SELECT #if USE_SELECT_TIMER #include #endif #endif #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS #undef HAVE_POLL #define HAVE_POLL 0 #endif #if HAVE_USLEEP || HAVE_NAP #undef HAVE_NAPMS #define HAVE_NAPMS 0 #endif #if HAVE_USLEEP #undef HAVE_NAP #define HAVE_NAP 0 #endif static int ttblind(); static int ttcd(); /* script entry -- "compiled" form of dial, hangup, or login script */ struct script { struct script *next; /* pointer to next entry, or null */ int opcode; /* numeric opcode */ char *strprm; /* pointer to string param */ long intprm; /* integer parameter */ char *newstate; /* new state name */ }; /* opcode definition array element -- one for each possible opcode */ struct script_opdef { char *opname; int opcode; /* numeric opcode -- same as array index */ int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */ int newstate; /* one of SC_NONE, SC_NWST */ }; /* values for opcode */ #define SC_LABEL 0 /* "label" (state name) */ #define SC_CDLY 1 /* set char output delay in msec */ #define SC_PCHR 2 /* pause char for dial string (from P in input) */ #define SC_PTIM 3 /* seconds to allow for pause char */ #define SC_WCHR 4 /* wait char for dial string (from W in input) */ #define SC_WTIM 5 /* seconds to allow for wait char */ #define SC_ZERO 6 /* zero counter */ #define SC_INCR 7 /* increment counter */ #define SC_IFGT 8 /* change state if counter > int param */ #define SC_WAIT 9 /* wait for int param seconds */ #define SC_GOTO 10 /* unconditional change to new state */ #define SC_SEND 11 /* send strparam (after sprintf substitutions) */ #define SC_BRK 12 /* send a break */ #define SC_HANG 13 /* drop DTR */ #define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */ #define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */ /* default = 100 (one tenth second) */ #define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */ /* default = 45 seconds */ #define SC_EXIT 17 /* script done, success */ #define SC_FAIL 18 /* script done, failure */ #define SC_LOG 19 /* write strparam to uucp.log */ #define SC_LOGE 20 /* write strparam to uucp.log w/error ind */ #define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */ #define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */ #define SC_DBST 23 /* 'or' intparam into debug mask */ #define SC_DBCL 24 /* 'bicl' intparam into debug mask */ #define SC_TIMO 25 /* newstate if no match in intparam secs */ /* (uses calculated dial time if intparam is 0) */ #define SC_XPCT 26 /* wait for strparam, goto _newstate if found */ #define SC_CARR 27 /* goto _newstate if carrier detected */ #define SC_FLSH 28 /* flush typeahead buffer */ #define SC_IFBL 29 /* change state if controller is blind w/o CD */ #define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */ #define SC_SNDP 31 /* send parameter n */ #define SC_IF1P 32 /* if parameter n present */ #define SC_IF0P 33 /* if parameter n absent */ #define SC_DBOF 34 /* open debugging file */ #define SC_TELN 35 /* Set telno from parameter n */ #define SC_7BIT 36 /* Set port to 7-bit stripping */ #define SC_8BIT 37 /* Set port for 8-bit characters */ #define SC_PNON 38 /* Set port for 8-bit, no parity */ #define SC_PEVN 39 /* Set port for 7-bit, even parity */ #define SC_PODD 40 /* Set port for 7-bit, odd parity */ #define SC_HUPS 41 /* Change state on HUP signal */ #define SC_END 42 /* end of array */ /* values for prmtype, prm2type */ #define SC_NONE 0 /* no parameter */ #define SC_STR 1 /* simple string */ #define SC_INT 2 /* integer */ #define SC_NWST 3 /* new state name */ #define SC_XSTR 4 /* translated string */ /* opcode definition table for dial/login/hangup scripts */ static struct script_opdef sc_opdef[] = { {"label", SC_LABEL, SC_NONE, SC_NONE}, {"chrdly", SC_CDLY, SC_INT, SC_NONE}, {"pchar", SC_PCHR, SC_STR, SC_NONE}, {"ptime", SC_PTIM, SC_INT, SC_NONE}, {"wchar", SC_WCHR, SC_STR, SC_NONE}, {"wtime", SC_WTIM, SC_INT, SC_NONE}, {"zero", SC_ZERO, SC_NONE, SC_NONE}, {"count", SC_INCR, SC_NONE, SC_NONE}, {"ifgtr", SC_IFGT, SC_INT, SC_NWST}, {"sleep", SC_WAIT, SC_INT, SC_NONE}, {"goto", SC_GOTO, SC_NONE, SC_NWST}, {"send", SC_SEND, SC_XSTR, SC_NONE}, {"break", SC_BRK, SC_NONE, SC_NONE}, {"hangup", SC_HANG, SC_NONE, SC_NONE}, {"7bit", SC_7BIT, SC_NONE, SC_NONE}, {"8bit", SC_8BIT, SC_NONE, SC_NONE}, {"nopar", SC_PNON, SC_NONE, SC_NONE}, {"evenpar", SC_PEVN, SC_NONE, SC_NONE}, {"oddpar", SC_PODD, SC_NONE, SC_NONE}, {"telno", SC_TELN, SC_INT, SC_NONE}, {"dial", SC_DIAL, SC_NONE, SC_NONE}, {"dgttime", SC_DTIM, SC_INT, SC_NONE}, {"ctime", SC_CTIM, SC_INT, SC_NONE}, {"success", SC_EXIT, SC_NONE, SC_NONE}, {"failed", SC_FAIL, SC_NONE, SC_NONE}, {"log", SC_LOG, SC_XSTR, SC_NONE}, {"logerr", SC_LOGE, SC_XSTR, SC_NONE}, {"debug", SC_DBG, SC_XSTR, SC_NONE}, {"debuge", SC_DBGE, SC_XSTR, SC_NONE}, {"dbgset", SC_DBST, SC_INT, SC_NONE}, {"dbgclr", SC_DBCL, SC_INT, SC_NONE}, {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE}, {"timeout", SC_TIMO, SC_INT, SC_NWST}, {"expect", SC_XPCT, SC_XSTR, SC_NWST}, {"ifcarr", SC_CARR, SC_NONE, SC_NWST}, {"ifhang", SC_HUPS, SC_NONE, SC_NWST}, {"flush", SC_FLSH, SC_NONE, SC_NONE}, {"ifblind", SC_IFBL, SC_NONE, SC_NWST}, {"ifblgtr", SC_IFBG, SC_INT, SC_NWST}, {"sendstr", SC_SNDP, SC_INT, SC_NONE}, {"ifstr", SC_IF1P, SC_INT, SC_NWST}, {"ifnstr", SC_IF0P, SC_INT, SC_NWST}, {"table end", SC_END, SC_NONE, SC_NONE} }; #define SUCCESS 0 #define FAIL 1 #define ERROR -1 #define MAX_SCLINE 255 /* max length of a line in a script file */ #define MAX_EXPCT 127 /* max length of an expect string */ #define CTL_DELIM " \t\n\r" /* Delimiters for tokens */ #define SAME 0 /* if (strcmp(a,b) == SAME) ... */ #define SLOP 10 /* Slop space on arrays */ #define MAX_STRING 200 /* Max length string to send/expect */ #define DEBUG_LEVEL(level) \ (Debug & (1 << level)) #define DB_LOG 0 /* error messages and a copy of the LOGFILE output */ #define DB_LGIE 1 /* dial,login,init trace -- errors only */ #define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */ #define DB_LGII 3 /* script processing internals */ #define TRUE 1 #define FALSE 0 #define NONE 0 #define EVEN 1 #define ODD 2 #define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1) static char **paramv; /* Parameter vector */ static int paramc; /* Parameter count */ static char telno[64]; /* Telephone number w/meta-chars */ static int Debug; static int fShangup = FALSE; /* TRUE if HUP signal received */ static FILE *dbf = NULL; static struct termio old, new; extern int usignal(); extern int uhup(); static struct siglist { int signal; int (*o_catcher) (); int (*n_catcher) (); } sigtbl[] = { { SIGHUP, NULL, uhup }, { SIGINT, NULL, usignal }, { SIGIOT, NULL, usignal }, { SIGQUIT, NULL, usignal }, { SIGTERM, NULL, usignal }, { SIGALRM, NULL, usignal }, { 0, NULL, NULL } /* Table end */ }; extern struct script *read_script(); extern void msleep(); extern char xgetc(); extern void charlog(); extern void setup_tty(); extern void restore_tty(); extern void ttoslow(); extern void ttflui(); extern void tthang(); extern void ttbreak(); extern void tt7bit(); extern void ttpar(); extern void DEBUG(); extern void *malloc(); /* * ********************************** * * BEGIN EXECUTION - MAIN PROGRAM * * ********************************** * * This program is called by Taylor UUCP with a list of * arguments in argc/argv, and stdin/stdout mapped to the * tty device, and stderr mapped to the Taylor logfile, where * anything written to stdout will be logged as an error. * */ int main(argc, argv) int argc; char *argv[]; { int i, stat; FILE *sf; char sfname[256]; struct script *script; struct siglist *sigs; /* * The following is needed because my cpp does not have the * #error directive... */ #if ! HAVE_SELECT no_select_sorry(); /* Sad way to fail make */ #endif paramv = &argv[2]; /* Parameters start at 2nd arg */ paramc = argc - 2; /* Number of live parameters */ telno[0] = '\0'; if (argc < 2) { fprintf(stderr, "%s: no script file supplied\n", argv[0]); exit(FAIL); } /* * If the script file argument begins with '/', then we assume * it is an absolute pathname, otherwise, we prepend the * SCRIPT_DIR path. */ *sfname = '\0'; /* Empty name string */ if(argv[1][0] != '/') /* If relative path */ strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */ strcat(sfname, argv[1]); /* Add the script file name */ /* * Now open the script file. */ if ((sf = fopen(sfname, "r")) == NULL) { fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname); perror(" "); exit(FAIL); } /* * COMPILE SCRIPT */ if ((script = read_script(sf)) == NULL) { fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]); exit(FAIL); } /* * Set up a signal catcher so the line can be returned to * it's current state if something nasty happens. */ sigs = &sigtbl[0]; while(sigs->signal) { sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher); sigs += 1; } /* * Save current tty settings, then set up raw, single * character input processing, with 7-bit stripping. */ setup_tty(); /* * EXECUTE SCRIPT */ if ((stat = do_script(script)) != SUCCESS) fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]); /* * Clean up and exit. */ restore_tty(); #ifdef FIXSIGS sigs = &sigtbl[0]; while(sigs->signal) if(sigs->o_catcher != -1) signal(sigs->signal, sigs->o_catcher); #endif exit(stat); } /* * deal_script - deallocate a script and all strings it points to */ int deal_script(loc) struct script *loc; { /* * If pointer is null, just exit */ if (loc == (struct script *)NULL) return SUCCESS; /* * Deallocate the rest of the script */ deal_script(loc->next); /* * Deallocate the string parameter, if any */ if (loc->strprm != (char *)NULL) free(loc->strprm); /* * Deallocate the new state name parameter, if any */ if (loc->newstate != (char *)NULL) free(loc->newstate); /* * Deallocate this entry */ free(loc); return SUCCESS; } /* * read_script * * Read & compile a script, return pointer to first entry, or null if bad */ struct script *read_script(fd) FILE *fd; { struct script *this = NULL; struct script *prev = NULL; struct script *first = NULL; long len, i; char inpline[MAX_SCLINE]; char inpcopy[MAX_SCLINE]; char *c, *cln, *opc, *cp; /* * MAIN COMPILATION LOOP */ while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL) { /* * Skip comments and blank lines */ if (*c == '#' || *c == '\n') continue; /* * Get rid of the trailing newline, and copy the string */ inpline[strlen(inpline)-1] = '\0'; strcpy(inpcopy, inpline); /* * Look for text starting in the first col (a label) */ if ((!isspace(inpline[0])) && (cln = strchr (inpline, ':')) != (char *)NULL) { this = (struct script *)malloc (sizeof (struct script)); if (prev != (struct script *)NULL) prev->next = this; prev = this; if (first == (struct script *)NULL) first = this; this->next = (struct script *)NULL; this->opcode = SC_LABEL; len = cln - c; this->strprm = (char *)malloc(len+1); strncpy(this->strprm, c, len); (this->strprm)[len] = '\0'; this->intprm = 0; this->newstate = (char *)NULL; c = cln + 1; } /* * Now handle the opcode. Fold it to lower case. */ opc = strtok(c, CTL_DELIM); if (opc == (char *)NULL) /* If no opcode... */ continue; /* ...read the next line */ cp = opc; while(*cp) tolower(*cp++); /* * If we have an opcode but we haven't seen anything * else (like a label) yet, i.e., this is the first * entry, and there was no label. We need to * cobble up a label so that read_script is happy */ if (first == (struct script *)NULL) { this = (struct script *)malloc (sizeof (struct script)); prev = this; first = this; this->next = (struct script *)NULL; this->opcode = SC_LABEL; this->strprm = (char *)malloc(2); strcpy(this->strprm, ":"); this->intprm = 0; this->newstate = (char *)NULL; } /* * Find opcode - ndex through the opcode definition table */ for (i=1; sc_opdef[i].opcode != SC_END; i++) if (strcmp(opc, sc_opdef[i].opname) == SAME) break; if ((sc_opdef[i].opcode) == SC_END) { logit ("Bad opcode in script", opc); deal_script(first); return (struct script *)NULL; } /* * Found opcode. Allocate a new command node and initialize */ this = (struct script *)malloc(sizeof (struct script)); prev->next = this; prev = this; this->next = (struct script *)NULL; this->opcode = sc_opdef[i].opcode; this->strprm = (char *)NULL; this->intprm = 0; this->newstate = (char *)NULL; /* * Pick up new state parameter, if any */ if (sc_opdef[i].newstate == SC_NWST) { c = strtok((char *)NULL, CTL_DELIM); if (c == (char *)NULL) { logit("Missing new state", opc); deal_script(first); return (struct script *)NULL; } else { this->newstate = (char *)malloc(strlen(c)+1); strcpy(this->newstate, c); } } /* * Pick up the string or integer parameter. Handle missing * parameter gracefully. */ switch (sc_opdef[i].prmtype) { /* * INT parameter - convert and store in node */ case SC_INT: c = strtok((char *)NULL, CTL_DELIM); if (c == (char *)NULL) { logit("Missing script param", opc); deal_script(first); return (struct script *)NULL; } /* * If this is the parameter to DBST or DBCL, force * base-10 conversion, else convert per parameter. */ if (sc_opdef[i].opcode == SC_DBST || sc_opdef[i].opcode == SC_DBCL) this->intprm = strtol(c, (char **)NULL, 0); else this->intprm = strtol(c, (char **)NULL, 10); break; /* * STR/XSTR strings. */ case SC_STR: case SC_XSTR: c = strtok((char *)NULL, CTL_DELIM); if (c == (char *)NULL) { logit("Missing script param", opc); deal_script(first); return (struct script *)NULL; } /* * For XSTR opcode, use c to find out where * the string param begins in the copy of the * input line, and pick up all that's left of * the line (to allow imbedded blanks, etc.). */ if (sc_opdef[i].prmtype == SC_XSTR) c = &inpcopy[0] + (c - &inpline[0]); /* * Allocate a buffer for the string parameter */ this->strprm = (char *)malloc(strlen(c)+1); /* * For XSTR, Translate the string and store its * length. Note that, after escape sequences are * compressed, the resulting string may well be a * few bytes shorter than the input string (whose * length was the basis for the malloc above), * but it will never be longer. */ if (sc_opdef[i].prmtype == SC_XSTR) { this->intprm = xlat_str(this->strprm, c); this->strprm[this->intprm] = '\0'; } else strcpy(this->strprm, c); break; } } /* * EOF */ return first; } /* * xlat_str * * Translate embedded escape characters in a "send" or "expect" string. * * Called by read_script(), above. * * Returns the actual length of the resulting string. Note that imbedded * nulls (specified by \000 in the input) ARE allowed in the result. */ xlat_str(out, in) char *out, *in; { register int i = 0, j = 0; int byte, k; while (in[i]) { if (in[i] != '\\') { out[j++] = in[i++]; } else { switch (in[++i]) { case 'd': /* EOT */ out[j++] = 0x04; break; case 'N': /* null */ out[j++] = 0x00; break; case 'n': /* line feed */ out[j++] = 0x0a; break; case 'r': /* carriage return */ out[j++] = 0x0d; break; case 's': /* space */ out[j++] = ' '; break; case 't': /* tab */ out[j++] = '\t'; break; case '-': /* hyphen */ out[j++] = '-'; break; case '\\': /* back slash */ out[j++] = '\\'; break; case '0': /* '\nnn' format */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': byte = in[i] - '0'; k = 0; while (3 > ++k) if ((in[i+1] < '0') || (in[i+1] > '7')) break; else { byte = (byte<<3) + in[i+1] - '0'; ++i; } out[j++] = byte; break; default: /* don't know so skip it */ break; } ++i; } } return j; } /* find a state within a script */ struct script * find_state(begin, newstate) struct script *begin; char *newstate; { struct script *here; for (here=begin; here != (struct script *)NULL; here=here->next) { if (here->opcode == SC_LABEL && strcmp(here->strprm, newstate) == SAME) return here; } return (struct script *)NULL; } /* * do_script() - execute a script */ int do_script(begin) struct script *begin; { struct script *curstate, *newstate, *curscr; int dbgsave; char tempstr[MAX_SCLINE]; char dfname[256]; char *c, chr; int prmlen; int dbfd; time_t sc_carrtime = 45000; /* time to wf carr after dial */ time_t sc_chrdly = 100; /* delay time for ttoslow */ time_t sc_ptime = 2000; /* time to allow for pause char */ time_t sc_wtime = 10000; /* time to allow for wait char */ time_t sc_dtime = 100; /* time to allow for each digit */ time_t sc_dtmo; /* total time to dial number */ int sc_counter; /* random counter */ char sc_pchar = ','; /* modem pause character */ char sc_wchar = 'W'; /* modem wait-for-dialtone character */ time_t sc_begwait; /* time at beg of wait */ time_t sc_secs; /* timeout period */ int expcnt; int expin; static char expbuf[MAX_EXPCT]; dbgsave = Debug; curstate = begin; if (curstate == (struct script *)NULL) return SUCCESS; _newstate: /* * do all of curstate's actions. Enter with curstate pointing * to a label entry */ expin = 0; for (curscr = curstate->next; /* point to 1st scr after label */ (curscr != (struct script *)NULL) && /* do until end of scr */ (curscr->opcode != SC_LABEL); /* or next label */ curscr = curscr->next) { expcnt = 0; switch (curscr->opcode) { case SC_LABEL: logit("Script proc err", curstate->strprm); return FAIL; case SC_FLSH: DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0); ttflui(); break; case SC_CDLY: sc_chrdly = curscr->intprm; DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly); break; case SC_PCHR: sc_pchar = *(curscr->strprm); DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar); break; case SC_PTIM: sc_ptime = curscr->intprm; DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime); break; case SC_WCHR: sc_wchar = *(curscr->strprm); DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar); break; case SC_WTIM: sc_wtime = curscr->intprm; DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime); break; case SC_ZERO: sc_counter = 0; DEBUG(DB_LGII, "Set counter to %d\n", sc_counter); break; case SC_INCR: sc_counter++; DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter); break; case SC_WAIT: DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm); msleep(curscr->intprm); break; case SC_DTIM: sc_dtime = curscr->intprm; DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime); break; case SC_CTIM: sc_carrtime = curscr->intprm; DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime); break; case SC_EXIT: Debug = dbgsave; DEBUG(DB_LGI, "Script ended successfully\n", 0); return SUCCESS; case SC_FAIL: Debug = dbgsave; if (DEBUG_LEVEL(DB_LGI) && dbf != NULL) fprintf(dbf, "Script failed\n"); else if (expin) charlog(expbuf, expin, DB_LOG, "Script failed. Last received data"); return FAIL; case SC_LOG: logit(curscr->strprm, ""); break; case SC_LOGE: logit("ERROR: ", curscr->strprm); break; case SC_DBOF: /* * If the debug file name does not begin with "/", then * we prepend the LOG_DIR to the string. Then CREATE the * file. This WIPES OUT previous logs. */ *dfname = '\0'; /* Zero name string */ if(curscr->strprm[0] != '/') strcat(dfname, LOG_DIR); /* Prepend default directory */ strcat(dfname, curscr->strprm); /* Add given string */ DEBUG(DB_LGII, "Open debug file %s\n", dfname); if ((dbfd = creat (dfname, 0600)) <= 0) { logit("Failed to create debug log %s", dfname); perror(""); return FAIL; } if ((dbf = fdopen(dbfd, "w")) == NULL) { logit("Failed to open debug log fildes.", ""); perror(""); return FAIL; } break; case SC_DBG: DEBUG(DB_LGI, "<%s>\n", curscr->strprm); break; case SC_DBGE: DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm); break; case SC_DBST: Debug |= curscr->intprm; DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); break; case SC_DBCL: Debug &= ~(curscr->intprm); DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug); break; case SC_BRK: DEBUG(DB_LGI, "Sending break\n", 0); ttbreak(); break; case SC_HANG: DEBUG(DB_LGI, "Dropping DTR\n", 0); tthang(); break; case SC_7BIT: DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0); tt7bit(TRUE); break; case SC_8BIT: DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0); tt7bit(FALSE); break; case SC_PNON: DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0); ttpar(NONE); break; case SC_PEVN: DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0); ttpar(EVEN); break; case SC_PODD: DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0); ttpar(ODD); break; case SC_IFBL: if (ttblind()) { DEBUG(DB_LGI, "Blind mux,\n", 0); goto _chgstate; } break; case SC_IFBG: if (ttblind() && sc_counter > curscr->intprm) { DEBUG(DB_LGI, "Blind mux & ctr > %d\n", curscr->intprm); goto _chgstate; } break; case SC_IFGT: if (sc_counter > curscr->intprm) { DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm); goto _chgstate; } break; case SC_GOTO: _chgstate: DEBUG(DB_LGI, "Changing to state %s\n", curscr->newstate); curstate = find_state(begin, curscr->newstate); if (curstate == NULL) { logit("New state not found", curscr->newstate); return FAIL; } goto _newstate; case SC_SEND: ttoslow(curscr->strprm, curscr->intprm, sc_chrdly); break; case SC_TELN: if (curscr->intprm > paramc - 1) { sprintf(tempstr, "telno - param #%d", curscr->intprm); logit(tempstr, " not present"); return FAIL; } strcpy(telno, paramv[curscr->intprm]); DEBUG(DB_LGII, "telno set to %s\n", telno); break; case SC_SNDP: if (curscr->intprm > paramc - 1) { sprintf(tempstr, "sendstr - param #%d", curscr->intprm); logit(tempstr, " not present"); return FAIL; } prmlen = xlat_str(tempstr, paramv[curscr->intprm]); ttoslow(tempstr, prmlen, sc_chrdly); break; case SC_IF1P: if (curscr->intprm < paramc) goto _chgstate; break; case SC_IF0P: if (curscr->intprm >= paramc) goto _chgstate; break; case SC_DIAL: if(telno[0] == '\0') { logit("telno not set", ""); return(FAIL); } /* * Compute and set a default timeout for the 'timeout' * command. Some parameters in this computation may be * changed by the script. See the man page xchat(8) for * details. */ sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno) + sc_carrtime; c=strcpy(tempstr, telno); for (; *c!='\0'; c++) { if (*c == 'W') { *c = sc_wchar; sc_dtmo += sc_wtime; } else if (*c == 'P') { *c = sc_pchar; sc_dtmo += sc_ptime; } } DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo); ttoslow(tempstr, 0, sc_chrdly); break; case SC_TIMO: /* these are "expects", don't bother */ case SC_XPCT: /* with them yet, other than noting that */ case SC_CARR: /* they exist */ expcnt++; break; } } /* we've done the current state's actions, now do its expects, if any */ if (expcnt == 0) { if (curscr != (struct script *)NULL && (curscr->opcode == SC_LABEL)) { curstate = curscr; DEBUG(DB_LGI, "Fell through to state %s\n", curstate->strprm); goto _newstate; } else { logit("No way out of state", curstate->strprm); return FAIL; } } time(&sc_begwait); /* log time at beg of expect */ DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm); charlog((char *)NULL, 0, DB_LGI, "Received"); while (1) { chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */ charlog(&chr, 1, DB_LGI, (char *)NULL); if (chr != EOF) { if (expin < MAX_EXPCT) { expbuf[expin++] = chr & 0x7f; } else { strncpy(expbuf, &expbuf[1], MAX_EXPCT-1); expbuf[MAX_EXPCT-1] = chr & 0x7f; } } /* for each entry in the current state... */ for (curscr = curstate->next; (curscr != (struct script *)NULL) && (curscr->opcode != SC_LABEL); curscr = curscr->next) { switch (curscr->opcode) { case SC_TIMO: sc_secs = curscr->intprm; if (sc_secs == 0) sc_secs = sc_dtmo; sc_secs /= 1000; if (time(NULL)-sc_begwait > sc_secs) { DEBUG(DB_LGI, "\nTimed out (%d secs)\n", sc_secs); goto _chgstate; } break; case SC_CARR: if (ttcd()) { DEBUG(DB_LGI, "\nGot carrier\n", 0); goto _chgstate; } break; case SC_HUPS: if (fShangup) { DEBUG(DB_LGI, "\nGot data set hangup\n", 0); goto _chgstate; } break; case SC_XPCT: if ((expin >= curscr->intprm) && (strncmp(curscr->strprm, &expbuf[expin - curscr->intprm], curscr->intprm) == SAME)) { charlog(curscr->strprm, curscr->intprm, DB_LGI, "Matched"); goto _chgstate; } break; } } } } /* * SIGNAL HANDLERS */ /* * usignal - generic signal catcher */ static int usignal(isig) int isig; { DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig); restore_tty(); exit(FAIL); } /* * uhup - HUP catcher */ static int uhup(isig) int isig; { DEBUG(DB_LOG, "Data set hangup.\n"); fShangup = TRUE; } /* * TERMINAL I/O ROUTINES */ /* * xgetc - get a character with timeout * * Assumes that stdin is opened on a terminal or TCP socket * with O_NONBLOCK. */ static char xgetc(tmo) int tmo; /* Timeout, seconds */ { char c; struct timeval s; int f = 1; /* Select on stdin */ int result; if(read(0, &c, 1) <= 0) /* If no data available */ { s.tv_sec = (long)tmo; s.tv_usec = 0L; if(select (1, &f, (int *) NULL, &f, &s) == 1) read(0, &c, 1); else c = '\377'; } return(c); } /* * Pause for an interval in milliseconds */ void msleep(msec) long msec; { #if HAVE_USLEEP if(msec == 0) /* Skip all of this if delay = 0 */ return; usleep (msec * (long)1000); #endif /* HAVE_USLEEP */ #if HAVE_NAPMS if(msec == 0) /* Skip all of this if delay = 0 */ return; napms (msec); #endif /* HAVE_NAPMS */ #if HAVE_NAP if(msec == 0) /* Skip all of this if delay = 0 */ return; nap (msec); #endif /* HAVE_NAP */ #if HAVE_POLL struct pollfd sdummy; if(msec == 0) return; /* * We need to pass an unused pollfd structure because poll checks * the address before checking the number of elements. */ poll (&sdummy, 0, msec); #endif /* HAVE_POLL */ #if USE_SELECT_TIMER struct timeval s; if(msec == 0) return; s.tv_sec = msec / 1000L; s.tv_usec = (msec % 1000L) * 1000L; select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s); #endif /* USE_SELECT_TIMER */ #if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \ ! HAVE_POLL && ! USE_SELECT_TIMER if(msec == 0) return; sleep (1); /* Sleep for a whole second (UGH!) */ #endif /* HAVE_ and USE_ nothing */ } /* * Debugging output */ static void DEBUG(level, msg1, msg2) int level; char *msg1, *msg2; { if ((dbf != NULL) && DEBUG_LEVEL(level)) fprintf(dbf, msg1, msg2); } /* * charlog - log a string of characters * * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged * when read does its 1 sec. timeout. Log "<1 sec.>" * so user can see elapsed time */ static void charlog(buf, len, mask, msg) char *buf; int len, mask; char *msg; { char tbuf[256]; if (DEBUG_LEVEL(mask) && dbf != NULL) { if(msg == (char *)NULL) msg = ""; strncpy(tbuf, buf, len); tbuf[len] = '\0'; if(len == 1 && tbuf[0] == '\377') strcpy(tbuf, "<1 sec.>"); fprintf(dbf, "%s %s\n", msg, tbuf); } } /* * setup_tty() * * Save current tty settings, then set up raw, single * character input processing, with 7-bit stripping. */ static void setup_tty() { register int i; ioctl(0, TCGETA, &old); new = old; for(i = 0; i < 7; i++) new.c_cc[i] = '\0'; new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */ new.c_cc[VTIME] = 10; /* TIME = 1 sec. */ new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */ new.c_lflag = 0; /* No special line discipline */ ioctl(0, TCSETA, &new); } /* * restore_tty() - restore signal handlers and tty modes on exit. */ static void restore_tty(sig) int sig; { ioctl(0, TCSETA, &old); return; } /* * ttoslow() - Send characters with pacing delays */ static void ttoslow(s, len, delay) char *s; int len; time_t delay; { int i; if (len == 0) len = strlen(s); charlog (s, len, DB_LGI, "Sending slowly"); for (i = 0; i < len; i++, s++) { write(1, s, 1); msleep(delay); } } /* * ttflui - flush input buffer */ static void ttflui() { if(isatty(0)) (void) ioctl ( 0, TCFLSH, 0); } /* * ttcd - Test if carrier is present * * NOT IMPLEMENTED. I don't know how!!! */ static int ttcd() { return TRUE; } /* * tthang - Force DTR low for 1-2 sec. */ static void tthang() { if(!isatty()) return; #ifdef TCCLRDTR (void) ioctl (1, TCCLRDTR, 0); sleep (2); (void) ioctl (1, TCSETDTR, 0); #endif return; } /* * ttbreak - Send a "break" on the line */ static void ttbreak() { (void) ioctl (1, TCSBRK, 0); } /* * ttblind - return TRUE if tty is "blind" * * NOT IMPLEMENTED - Don't know how!!! */ static int ttblind() { return FALSE; } /* * tt7bit - enable/disable 7-bit stripping on line */ static void tt7bit(enable) int enable; { if(enable) new.c_iflag |= ISTRIP; else new.c_iflag &= ~ISTRIP; ioctl(0, TCSETA, &new); } /* * ttpar - Set parity mode on line. Ignore parity errors on input. */ static void ttpar(mode) int mode; { switch(mode) { case NONE: new.c_iflag &= ~(INPCK | IGNPAR); new.c_cflag &= ~(CSIZE | PARENB | PARODD); new.c_cflag |= CS8; break; case EVEN: new.c_iflag |= (INPCK | IGNPAR); new.c_cflag &= ~(CSIZE | PARODD); new.c_cflag |= (CS7 | PARENB); break; case ODD: new.c_iflag |= (INPCK | IGNPAR); new.c_cflag &= ~(CSIZE); new.c_cflag |= (CS7 | PARENB | PARODD); break; } ioctl(0, TCSETA, &new); } ", 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, uucp-1.04/contrib/xchat.man1006640004150000170000004302205252524704012632 037777777777 1 0 .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? 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 iuucp-1.04/sample/0407750004150000170000000000005337265077010051 5 0 1 0 uucp-1.04/sample/call1006640004150000170000000163705325204642011510 037777777777 1 0 # 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 rst. As a practical matter, the order of these statements is not significant; they are all interpuucp-1.04/sample/config1006660004150000170000001022405325165132012034 037777777777 1 0 # 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 ion 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 timeuucp-1.04/sample/dial1006640004150000170000000252005325204140011467 037777777777 1 0 # 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 ecifies 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 Specifiesuucp-1.04/sample/dialcode1006640004150000170000000150605325204354012334 037777777777 1 0 # 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. 1 0 uucp-1.04/sample/passwd1006640004150000170000000162605325205111012064 037777777777 1 0 # 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 s foobar rst. As a practical matter, the order of these statements is not significant; they are all interpuucp-1.04/sample/port1006640004150000170000000276205325203477011566 037777777777 1 0 # 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 icy.h (the defuucp-1.04/sample/sys11006640004150000170000000275505325202506011473 037777777777 1 0 # 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 h is not listed in uucp-1.04/sample/sys21006640004150000170000000277705325202706011502 037777777777 1 0 # 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 duucp-1.04/unix/0407750004150000170000000000005337265105007543 5 0 1 0 uucp-1.04/unix/Makefile.in1004440004150000170000001162305337263553012422 037777777777 1 0 # This is the Makefile for the unix subdirectory of Taylor UUCP. # This subdirectory contains Unix specific support functions. # # The file Makefile.in should be processed by configure to generate # Makefile. If you want to generate Makefile by hand, you must find # all variables surrounded by @ and replace them with the correct # value (e.g. @CC@ must be replaced by something like cc or gcc). SHELL=/bin/sh # These are overridden by the call from the top level Makefile CC = @CC@ CFLAGS = @CFLAGS@ RANLIB = @RANLIB@ prefix = /usr/local sbindir = $(prefix)/lib/uucp UUDIRFLAGS = srcdir = @srcdir@ VPATH = @srcdir@ MORECFLAGS = -I$(srcdir)/.. -I.. -DSBINDIR=\"$(sbindir)\" -DOWNER=\"$(owner)\" $(UUDIRFLAGS) OBJS = access.o addbas.o app3.o app4.o basnam.o bytfre.o cwd.o \ chmod.o cohtty.o cusub.o detach.o efopen.o epopen.o exists.o \ filnam.o fsusg.o indir.o init.o isdir.o isfork.o iswait.o \ jobid.o lcksys.o link.o locfil.o lock.o loctim.o mail.o \ mkdirs.o mode.o move.o opensr.o pause.o picksb.o portnm.o \ proctm.o recep.o run.o seq.o serial.o signal.o sindir.o size.o \ sleep.o spawn.o splcmd.o splnam.o spool.o srmdir.o statsb.o \ status.o time.o tmpfil.o trunc.o uacces.o ufopen.o ultspl.o \ unknwn.o uuto.o walk.o wldcrd.o work.o xqtfil.o xqtsub.o @UNIXOBJS@ all: libunix.a clean: rm -f $(OBJS) libunix.a distclean: clean rm -f Makefile mostlyclean: clean realclean: distclean libunix.a: $(OBJS) rm -f libunix.a ar qc libunix.a $(OBJS) -$(RANLIB) libunix.a .c.o: $(CC) -c $(CFLAGS) $(MORECFLAGS) $< dist: mkdir ../uucp-$(VERSION)/unix ln `cat MANIFEST` ../uucp-$(VERSION)/unix Makefile: Makefile.in (cd ..; sh config.status) # Header file dependencies. $(OBJS): $(srcdir)/../uucp.h ../conf.h $(srcdir)/../policy.h ../sysdep.h access.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h addbas.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h app3.o: $(srcdir)/../uudefs.h app4.o: $(srcdir)/../uudefs.h basnam.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h chmod.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h cusub.o: $(srcdir)/../cu.h $(srcdir)/../uudefs.h $(srcdir)/../conn.h cusub.o: $(srcdir)/../prot.h $(srcdir)/../system.h $(srcdir)/../uuconf.h cwd.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h detach.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h efopen.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h exists.o: $(srcdir)/../system.h filnam.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h indir.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h init.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h isdir.o: $(srcdir)/../system.h iswait.o: $(srcdir)/../uudefs.h jobid.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h lcksys.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h link.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h locfil.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h lock.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h loctim.o: $(srcdir)/../system.h mail.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h mkdirs.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h mode.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h move.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h opensr.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h pause.o: $(srcdir)/../system.h picksb.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h portnm.o: $(srcdir)/../system.h proctm.o: $(srcdir)/../system.h recep.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h run.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h seq.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h serial.o: $(srcdir)/../uudefs.h $(srcdir)/../conn.h $(srcdir)/../system.h serial.o: $(srcdir)/../uuconf.h signal.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h sindir.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h size.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h sleep.o: $(srcdir)/../system.h spawn.o: $(srcdir)/../uudefs.h splcmd.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h splnam.o: $(srcdir)/../system.h $(srcdir)/../uuconf.h spool.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h srmdir.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h statsb.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h status.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h time.o: $(srcdir)/../system.h tmpfil.o: $(srcdir)/../uuconf.h $(srcdir)/../system.h trunc.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h uacces.o: $(srcdir)/../uudefs.h ufopen.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h ultspl.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h unknwn.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h uuto.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h walk.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h wldcrd.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h work.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h xqtfil.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h xqtsub.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h cifies a particular baud rate. port port2 device /dev/ttyd1 dialer hayes speed-range 2400 9600 icy.h (the defuucp-1.04/unix/MANIFEST1004440004150000170000000117005337263552011501 037777777777 1 0 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 le 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 auucp-1.04/unix/access.c1004440004150000170000000470505337263553011765 037777777777 1 0 /* access.c Check access to files by the user and by the daemon. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* See if the user has access to a file, to prevent the setuid uucp and uux programs handing out unauthorized access. */ boolean fsysdep_access (zfile) const char *zfile; { if (access (zfile, R_OK) == 0) return TRUE; ulog (LOG_ERROR, "%s: %s", zfile, strerror (errno)); return FALSE; } /* See if the daemon has access to a file. This is called if a file is not being transferred to the spool directory, since if the daemon does not have access the later transfer will fail. We assume that the daemon will have the same euid (or egid) as the one we are running under. If our uid (gid) and euid (egid) are the same, we assume that we have access. Note that is not important for security, since the check will be (implicitly) done again when the daemon tries to transfer the file. This routine should work whether the UUCP programs are installed setuid or setgid. */ boolean fsysdep_daemon_access (zfile) const char *zfile; { struct stat s; uid_t ieuid, iuid, iegid, igid; boolean fok; ieuid = geteuid (); if (ieuid == 0) return TRUE; iuid = getuid (); iegid = getegid (); igid = getgid (); /* If our effective uid and gid are the same as our real uid and gid, we assume the daemon will have access to the file. */ if (ieuid == iuid && iegid == igid) return TRUE; if (stat ((char *) zfile, &s) != 0) { ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); return FALSE; } /* If our euid is not our uid, but it is the file's uid, see if the owner has read access. Otherwise, if our egid is not our gid, but it is the file's gid, see if the group has read access. Otherwise, see if the world has read access. We know from the above check that at least one of our euid and egid are different, so that is the only one we want to check. This check could fail if the UUCP programs were both setuid and setgid, but why would they be? */ if (ieuid != iuid && ieuid == s.st_uid) fok = (s.st_mode & S_IRUSR) != 0; else if (iegid != igid && iegid == s.st_gid) fok = (s.st_mode & S_IRGRP) != 0; else fok = (s.st_mode & S_IROTH) != 0; if (! fok) { ulog (LOG_ERROR, "%s: cannot be read by daemon", zfile); return FALSE; } return TRUE; } uucp-1.04/unix/addbas.c1004440004150000170000000161205337263553011734 037777777777 1 0 /* 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; } jobid.o lcksys.o link.o locfil.o lock.o loctim.o mail.o \ mkdirs.o mode.o move.o opensr.o pause.o picksb.o portnm.o uucp-1.04/unix/app3.c1004440004150000170000000120705337263553011361 037777777777 1 0 /* 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; } uconf.h cwd.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h detach.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h efopen.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h exists.o: $(srcdir)/../system.h filnam.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h indir.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h init.o: $(srcdir)/../uudefs.h $(srcdir)/../systemuucp-1.04/unix/app4.c1004440004150000170000000147405337263554011371 037777777777 1 0 /* 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; } awn.o: $(srcdir)/../uudefs.h splcmd.o: $(srcdir)/../uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h splnam.o: $(srcdir)/../system.h $(srcdir)/../uuconf.h spool.o: $(srcdir)/../uudefs.h $(srcduucp-1.04/unix/basnam.c1004440004150000170000000053505337263554011763 037777777777 1 0 /* 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); } /uudefs.h $(srcdir)/../system.h $(srcdir)/../uuconf.h cifies a particular baud rate. port port2 device /dev/ttyd1 dialer hayes speed-range 2400 9600 icy.h (the defuucp-1.04/unix/bytfre.c1004440004150000170000000052305337263554012012 037777777777 1 0 /* 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; } 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 statusuucp-1.04/unix/chmod.c1004440004150000170000000066005337263554011613 037777777777 1 0 /* chmod.c Change the mode of a file. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* Change the mode of a file. */ boolean fsysdep_change_mode (zfile, imode) const char *zfile; unsigned int imode; { if (chmod ((char *) zfile, imode) < 0) { ulog (LOG_ERROR, "chmod (%s): %s", zfile, strerror (errno)); return FALSE; } return TRUE; } uucp-1.04/unix/cohtty.c1004440004150000170000001515305337263555012037 037777777777 1 0 /* Coherent tty locking support. This file was contributed by Bob Hemedinger of Mark Williams Corporation and lightly edited by Ian Lance Taylor. */ /* The bottom part of this file is lock.c. * This is a hacked lock.c. A full lock.c can be found in the libmisc sources * under /usr/src/misc.tar.Z. * * These are for checking for the existence of locks: * lockexist(resource) * lockttyexist(ttyname) */ #include "uucp.h" #if HAVE_COHERENT_LOCKFILES /* cohtty.c: Given a serial device name, read /etc/ttys and determine if * the device is already enabled. If it is, disable the * device and return a string so that it can be re-enabled * at the completion of the uucico session as part of the * function that resets the serial device before uucico * terminates. * */ #include "uudefs.h" #include "sysdep.h" #include #include /* fscoherent_disable_tty() is a COHERENT specific function. It takes the name * of a serial device and then scans /etc/ttys for a match. If it finds one, * it checks the first field of the entry. If it is a '1', then it will disable * the port and set a flag. The flag will be checked later when uucico wants to * reset the serial device to see if the device needs to be re-enabled. */ boolean fscoherent_disable_tty (zdevice, pzenable) const char *zdevice; char **pzenable; { struct ttyentry{ /* this is an /etc/ttys entry */ char enable_disable[1]; char remote_local[1]; char baud_rate[1]; char tty_device[16]; }; struct ttyentry sought_tty; int x,y,z; /* dummy */ FILE * infp; /* this will point to /etc/ttys */ char disable_command[66]; /* this will be the disable command * passed to the system. */ char enable_device[16]; /* this will hold our device name * to enable. */ *pzenable = NULL; strcpy(enable_device,""); /* initialize our strings */ strcpy(sought_tty.tty_device,""); if( (infp = fopen("/etc/ttys","r")) == NULL){ ulog(LOG_ERROR,"Error: check_disable_tty: failed to open /etc/ttys\n"); return FALSE; } while (NULL !=(fgets(&sought_tty, sizeof (sought_tty), infp ))){ sought_tty.tty_device[strlen(sought_tty.tty_device) -1] = '\0'; strcpy(enable_device,sought_tty.tty_device); /* we must strip away the suffix to the com port name or * we will never find a match. For example, if we are passed * /dev/com4l to call out with and the port is already enabled, * 9/10 the port enabled will be com4r. After we strip away the * suffix of the port found in /etc/ttys, then we can test * if the base port name appears in the device name string * passed to us. */ for(z = strlen(sought_tty.tty_device) ; z > 0 ; z--){ if(isdigit(sought_tty.tty_device[z])){ break; } } y = strlen(sought_tty.tty_device); for(x = z+1 ; x <= y; x++){ sought_tty.tty_device[x] = '\0'; } /* ulog(LOG_NORMAL,"found device {%s}\n",sought_tty.tty_device); */ if(strstr(zdevice, sought_tty.tty_device)){ if(sought_tty.enable_disable[0] == '1'){ ulog(LOG_NORMAL, "coh_tty: Disabling device %s {%s}\n", zdevice, sought_tty.tty_device); sprintf(disable_command, "/etc/disable %s",enable_device); { pid_t ipid; const char *azargs[3]; int aidescs[3]; azargs[0] = "/etc/disable"; azargs[1] = enable_device; azargs[2] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, TRUE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) x = 1; else x = ixswait ((unsigned long) ipid, (const char *) NULL); } *pzenable = zbufalc (sizeof "/dev/" + strlen (enable_device)); sprintf(*pzenable,"/dev/%s", enable_device); /* ulog(LOG_NORMAL,"Enable string is {%s}",*pzenable); */ return(x==0? TRUE : FALSE); /* disable either failed or succeded */ }else{ return FALSE; /* device in tty entry not enabled */ } } } return FALSE; /* no ttys entry found */ } /* The following is COHERENT 4.0 specific. It is used to test for any * existing lockfiles on a port which would have been created by init * when a user logs into a port. */ #define LOCKSIG 9 /* Significant Chars of Lockable Resources. */ #define LOKFLEN 64 /* Max Length of UUCP Lock File Name. */ #define LOCKPRE "LCK.." #define PIDLEN 6 /* Maximum length of string representing a pid. */ #ifndef LOCKDIR #define LOCKDIR SPOOLDIR #endif /* There is a special version of DEVMASK for the PE multiport driver * because of the peculiar way it uses the minor device number. For * all other drivers, the lower 5 bits describe the physical port-- * the upper 3 bits give attributes for the port. */ #define PE_DRIVER 21 /* Major device number for the PE driver. */ #define PE_DEVMASK 0x3f /* PE driver minor device mask. */ #define DEVMASK 0x1f /* Minor device mask. */ /* * Generates a resource name for locking, based on the major number * and the lower 4 bits of the minor number of the tty device. * * Builds the name in buff as two "." separated decimal numbers. * Returns NULL on failure, buff on success. */ static char * gen_res_name(path, buff) char *path; char *buff; { struct stat sbuf; int status; if (0 != (status = stat(path, &sbuf))) { /* Can't stat the file. */ return (NULL); } if (PE_DRIVER == major(sbuf.st_rdev)) { sprintf(buff, "%d.%d", major(sbuf.st_rdev), PE_DEVMASK & minor(sbuf.st_rdev)); } else { sprintf(buff, "%d.%d", major(sbuf.st_rdev), DEVMASK & minor(sbuf.st_rdev)); } return(buff); } /* gen_res_name */ /* * lockexist(resource) char *resource; * * Test for existance of a lock on the given resource. * * Returns: (1) Resource is locked. * (0) Resource is not locked. */ static boolean lockexist(resource) const char *resource; { char lockfn[LOKFLEN]; if ( resource == NULL ) return(0); sprintf(lockfn, "%s/%s%.*s", LOCKDIR, LOCKPRE, LOCKSIG, resource); return (!access(lockfn, AEXISTS)); } /* lockexist() */ /* * lockttyexist(ttyname) char *ttyname; * * Test for existance of a lock on the given tty. * * Returns: (1) Resource is locked. * (0) Resource is not locked. */ boolean lockttyexist(ttyn) const char *ttyn; { char resource[LOKFLEN]; char filename[LOKFLEN]; sprintf(filename, "/dev/%s", ttyn); if (NULL == gen_res_name(filename, resource)){ return(0); /* Non-existent tty can not be locked :-) */ } return(lockexist(resource)); } /* lockttyexist() */ #endif /* HAVE_COHERENT_LOCKFILES */ 0004150000170000000053505337263554011763 037777777777 1 0 uucp-1.04/unix/cwd.c1004440004150000170000000242705337263555011302 037777777777 1 0 /* 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); } 1 0 uucp-1.04/unix/cusub.c1004440004150000170000006223305337263555011647 037777777777 1 0 /* 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.12 1993/01/07 02:07:39 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include "cu.h" #include "conn.h" #include "prot.h" #include /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ #ifndef EAGAIN #ifndef EWOULDBLOCK #define EAGAIN (-1) #define EWOULDBLOCK (-1) #else /* defined (EWOULDBLOCK) */ #define EAGAIN EWOULDBLOCK #endif /* defined (EWOULDBLOCK) */ #else /* defined (EAGAIN) */ #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif /* ! defined (EWOULDBLOCK) */ #endif /* defined (EAGAIN) */ #ifndef ENODATA #define ENODATA EAGAIN #endif /* Local variables. */ /* The EOF character, as set by fsysdep_terminal_raw. */ static char bSeof; /* The SUSP character, as set by fsysdep_terminal_raw. */ static char bStstp; /* Local functions. */ static const char *zsport_line P((const struct uuconf_port *qport)); static void uscu_child P((struct sconnection *qconn, int opipe)); static RETSIGTYPE uscu_alarm P((int isig)); static int cscu_escape P((char *pbcmd, const char *zlocalname)); static RETSIGTYPE uscu_alarm_kill P((int isig)); /* Return the device name for a port, or NULL if none. */ static const char * zsport_line (qport) const struct uuconf_port *qport; { const char *zline; if (qport == NULL) return NULL; switch (qport->uuconf_ttype) { default: case UUCONF_PORTTYPE_STDIN: return NULL; case UUCONF_PORTTYPE_MODEM: zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice; break; case UUCONF_PORTTYPE_DIRECT: zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice; break; case UUCONF_PORTTYPE_TCP: case UUCONF_PORTTYPE_TLI: return NULL; } if (zline == NULL) zline = qport->uuconf_zname; return zline; } /* Check whether the user has legitimate access to a port. */ boolean fsysdep_port_access (qport) struct uuconf_port *qport; { const char *zline; char *zfree; boolean fret; zline = zsport_line (qport); if (zline == NULL) return TRUE; zfree = NULL; if (*zline != '/') { zfree = zbufalc (sizeof "/dev/" + strlen (zline)); sprintf (zfree, "/dev/%s", zline); zline = zfree; } fret = access (zline, R_OK | W_OK) == 0; ubuffree (zfree); return fret; } /* Return whether the given port is named by the given line. */ boolean fsysdep_port_is_line (qport, zline) struct uuconf_port *qport; const char *zline; { const char *zpline; char *zfree1, *zfree2; boolean fret; zpline = zsport_line (qport); if (zpline == NULL) return FALSE; if (strcmp (zline, zpline) == 0) return TRUE; zfree1 = NULL; zfree2 = NULL; if (*zline != '/') { zfree1 = zbufalc (sizeof "/dev/" + strlen (zline)); sprintf (zfree1, "/dev/%s", zline); zline = zfree1; } if (*zpline != '/') { zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline)); sprintf (zfree2, "/dev/%s", zpline); zpline = zfree2; } fret = strcmp (zline, zpline) == 0; ubuffree (zfree1); ubuffree (zfree2); return fret; } /* The cu program wants the system dependent layer to handle the details of copying data from the communications port to the terminal. This copying need only be done while executing fsysdep_cu. On Unix, however, we set up a subprocess to do it all the time. This subprocess must be controllable via the fsysdep_cu_copy function. We keep a pipe open to the subprocess. When we want it to stop we send it a signal, and then wait for it to write a byte to us over the pipe. */ /* The subprocess pid. */ static volatile pid_t iSchild; /* The pipe from the subprocess. */ static int oSpipe; /* When we tell the child to stop, it sends this. */ #define CHILD_STOPPED ('S') /* When we tell the child to start, it sends this. */ #define CHILD_STARTED ('G') /* Initialize the subprocess, and have it start copying data. */ boolean fsysdep_cu_init (qconn) struct sconnection *qconn; { int ai[2]; /* Write out anything we may have buffered up during the chat script. We do this before forking the child only to make it easy to move the child into a separate executable. */ while (iPrecend != iPrecstart) { char *z; int c; z = abPrecbuf + iPrecstart; if (iPrecend > iPrecstart) c = iPrecend - iPrecstart; else c = CRECBUFLEN - iPrecstart; iPrecstart = (iPrecstart + c) % CRECBUFLEN; while (c > 0) { int cwrote; cwrote = write (1, z, c); if (cwrote <= 0) { if (cwrote < 0) ulog (LOG_ERROR, "write: %s", strerror (errno)); else ulog (LOG_ERROR, "Line disconnected"); return FALSE; } c -= cwrote; z += cwrote; } } if (pipe (ai) < 0) { ulog (LOG_ERROR, "pipe: %s", strerror (errno)); return FALSE; } iSchild = ixsfork (); if (iSchild < 0) { ulog (LOG_ERROR, "fork: %s", strerror (errno)); return FALSE; } if (iSchild == 0) { (void) close (ai[0]); uscu_child (qconn, ai[1]); /*NOTREACHED*/ } (void) close (ai[1]); oSpipe = ai[0]; return TRUE; } /* Copy all data from the terminal to the communications port. If we see an escape character following a newline character, read the next character and return it. */ boolean fsysdep_cu (qconn, pbcmd, zlocalname) struct sconnection *qconn; char *pbcmd; const char *zlocalname; { boolean fstart; char b; int c; fstart = TRUE; while (TRUE) { if (fsysdep_catch ()) usysdep_start_catch (); else { ulog (LOG_ERROR, (const char *) NULL); return FALSE; } c = read (0, &b, 1); usysdep_end_catch (); if (c <= 0) break; if (fstart && b == *zCuvar_escape) { c = cscu_escape (pbcmd, zlocalname); if (c <= 0) break; if (*pbcmd != b) { write (1, pbcmd, 1); /* For Unix, we let the eof character be the same as '.', and we let the suspend character (if any) be the same as 'z'. */ if (*pbcmd == bSeof) *pbcmd = '.'; if (*pbcmd == bStstp) *pbcmd = 'z'; return TRUE; } } if (! fconn_write (qconn, &b, (size_t) 1)) return FALSE; fstart = strchr (zCuvar_eol, b) != NULL; } if (c < 0) { if (errno != EINTR) ulog (LOG_ERROR, "read: %s", strerror (errno)); else ulog (LOG_ERROR, (const char *) NULL); return FALSE; } /* I'm not sure what's best in this case. */ ulog (LOG_ERROR, "End of file on terminal"); return FALSE; } /* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */ volatile sig_atomic_t fScu_alarm; static RETSIGTYPE uscu_alarm (isig) int isig; { #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET (void) signal (isig, uscu_alarm); #endif fScu_alarm = TRUE; #if HAVE_RESTARTABLE_SYSCALLS if (fSjmp) longjmp (sSjmp_buf, 1); #endif } /* We've just seen an escape character. We print the host name, optionally after a 1 second delay. We read the next character from the terminal and return it. The 1 second delay on the host name is mostly to be fancy; it lets ~~ look smoother. */ static int cscu_escape (pbcmd, zlocalname) char *pbcmd; const char *zlocalname; { CATCH_PROTECT int c; write (1, zCuvar_escape, 1); fScu_alarm = FALSE; usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL); if (fsysdep_catch ()) { usysdep_start_catch (); alarm (1); } c = 0; while (TRUE) { if (fScu_alarm) { char b; fScu_alarm = FALSE; b = '['; write (1, &b, 1); write (1, zlocalname, strlen (zlocalname)); b = ']'; write (1, &b, 1); } if (c <= 0) c = read (0, pbcmd, 1); if (c >= 0 || errno != EINTR) { usysdep_end_catch (); usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); return c; } } } /* A SIGALRM handler which does nothing but send a signal to the child process and schedule another alarm. POSIX.1 permits kill and alarm from a signal handler. The reference to static data may or may not be permissible. */ static volatile sig_atomic_t iSsend_sig; static RETSIGTYPE uscu_alarm_kill (isig) int isig; { #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET (void) signal (isig, uscu_alarm_kill); #endif (void) kill (iSchild, iSsend_sig); alarm (1); } /* Start or stop copying data from the communications port to the terminal. We send a signal to the child process to tell it what to do. Unfortunately, there are race conditions in the child, so we keep sending it a signal once a second until it responds. We send SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */ boolean fsysdep_cu_copy (fcopy) boolean fcopy; { int ierr; int c; usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); if (fcopy) iSsend_sig = SIGUSR1; else iSsend_sig = SIGUSR2; uscu_alarm_kill (SIGALRM); alarm (1); while (TRUE) { char b; c = read (oSpipe, &b, 1); #if DEBUG > 1 if (c > 0) DEBUG_MESSAGE1 (DEBUG_INCOMING, "fsysdep_cu_copy: Got '%d'", b); #endif if ((c < 0 && errno != EINTR) || c == 0 || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED))) break; /* If none of the above conditions were true, then we either got an EINTR error, in which case we probably timed out and the SIGALRM handler resent the signal, or we read the wrong character, in which case we will just read again from the pipe. */ } ierr = errno; usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); if (c > 0) return TRUE; if (c == 0) ulog (LOG_ERROR, "EOF on child pipe"); else ulog (LOG_ERROR, "read: %s", strerror (ierr)); return FALSE; } /* Shut down cu by killing the child process. */ boolean fsysdep_cu_finish () { (void) close (oSpipe); /* We hit the child with SIGTERM, give it two seconds to die, and then send a SIGKILL. */ if (kill (iSchild, SIGTERM) < 0) { /* Don't give an error if the child has already died. */ if (errno != ESRCH) ulog (LOG_ERROR, "kill: %s", strerror (errno)); } usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); iSsend_sig = SIGKILL; alarm (2); (void) ixswait ((unsigned long) iSchild, "child"); usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); return TRUE; } /* Code for the child process. */ /* This signal handler just records the signal. In this case we only care about which signal we received most recently. */ static volatile sig_atomic_t iSchild_sig; static RETSIGTYPE uscu_child_handler (isig) int isig; { #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET (void) signal (isig, uscu_child_handler); #endif iSchild_sig = isig; #if HAVE_RESTARTABLE_SYSCALLS if (fSjmp) longjmp (sSjmp_buf, 1); #endif /* HAVE_RESTARTABLE_SYSCALLS */ } /* The child process. This copies the port to the terminal, except when it is stopped by a signal. It would be reasonable to write a separate program for this, probably passing it the port on stdin. This would reduce the memory requirements, since we wouldn't need a second process holding all the configuration stuff, and also let it work reasonably on 680x0 versions of MINIX. */ static void uscu_child (qconn, opipe) struct sconnection *qconn; int opipe; { CATCH_PROTECT int oport; CATCH_PROTECT boolean fstopped, fgot; CATCH_PROTECT int cwrite; CATCH_PROTECT char abbuf[1024]; /* It would be nice if we could just use fsserial_read, but that will log signals that we don't want logged. There should be a generic way to extract the file descriptor from the port. */ if (qconn->qport == NULL) oport = 0; else { switch (qconn->qport->uuconf_ttype) { #if DEBUG > 0 default: ulog (LOG_FATAL, "uscu_child: Can't happen"); oport = -1; break; #endif case UUCONF_PORTTYPE_STDIN: oport = 0; break; case UUCONF_PORTTYPE_MODEM: case UUCONF_PORTTYPE_DIRECT: case UUCONF_PORTTYPE_TCP: case UUCONF_PORTTYPE_TLI: oport = ((struct ssysdep_conn *) qconn->psysdep)->o; break; } } usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL); usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL); usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL); usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL); usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL); usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL); fstopped = FALSE; fgot = FALSE; iSchild_sig = 0; cwrite = 0; if (fsysdep_catch ()) usysdep_start_catch (); while (TRUE) { int isig; int c; /* There is a race condition here between checking the signal and receiving a new and possibly different one. This is solved by having the parent resend the signal until it gets a response. */ isig = iSchild_sig; iSchild_sig = 0; if (isig != 0) { char b; if (isig == SIGTERM) exit (EXIT_SUCCESS); if (isig == SIGUSR1) { fstopped = FALSE; b = CHILD_STARTED; } else { fstopped = TRUE; b = CHILD_STOPPED; cwrite = 0; } c = write (opipe, &b, 1); /* Apparently on some systems we can get EAGAIN here. */ if (c < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) c = 0; if (c <= 0) { /* Should we give an error message here? */ (void) kill (getppid (), SIGHUP); exit (EXIT_FAILURE); } } if (fstopped) pause (); else if (cwrite > 0) { char *zbuf; zbuf = abbuf; while (cwrite > 0) { c = write (1, zbuf, cwrite); /* Apparently on some systems we can get EAGAIN here. */ if (c < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) c = 0; if (c < 0 && errno == EINTR) break; if (c <= 0) { /* Should we give an error message here? */ (void) kill (getppid (), SIGHUP); exit (EXIT_FAILURE); } cwrite -= c; zbuf += c; } } else { /* On some systems apparently read will return 0 until something has been written to the port. We therefore accept a 0 return until after we have managed to read something. Setting errno to 0 apparently avoids a problem on Coherent. */ errno = 0; c = read (oport, abbuf, sizeof abbuf); /* Apparently on some systems we can get EAGAIN here. */ if (c < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) c = 0; if ((c == 0 && fgot) || (c < 0 && errno != EINTR)) { /* This can be a normal way to exit, depending on just how the connection is dropped. */ (void) kill (getppid (), SIGHUP); exit (EXIT_SUCCESS); } if (c > 0) { fgot = TRUE; cwrite = c; } } } } /* Terminal control routines. */ /* Whether file descriptor 0 is attached to a terminal or not. */ static boolean fSterm; /* Whether we are doing local echoing. */ static boolean fSlocalecho; /* The original state of the terminal. */ static sterminal sSterm_orig; /* The new state of the terminal. */ static sterminal sSterm_new; #if ! HAVE_BSD_TTY #ifdef SIGTSTP /* Whether SIGTSTP is being ignored. */ static boolean fStstp_ignored; #endif #endif /* Set the terminal into raw mode. */ boolean fsysdep_terminal_raw (flocalecho) boolean flocalecho; { fSlocalecho = flocalecho; /* This defaults may be overriden below. */ bSeof = '\004'; bStstp = '\032'; if (! fgetterminfo (0, &sSterm_orig)) { fSterm = FALSE; return TRUE; } fSterm = TRUE; sSterm_new = sSterm_orig; #if HAVE_BSD_TTY /* We use CBREAK mode rather than RAW mode, because RAW mode turns off all output processing, which we don't want to do. This means that we have to disable the interrupt characters, which we do by setting them to -1. */ bSeof = sSterm_orig.stchars.t_eofc; sSterm_new.stchars.t_intrc = -1; sSterm_new.stchars.t_quitc = -1; sSterm_new.stchars.t_startc = -1; sSterm_new.stchars.t_stopc = -1; sSterm_new.stchars.t_eofc = -1; sSterm_new.stchars.t_brkc = -1; bStstp = sSterm_orig.sltchars.t_suspc; sSterm_new.sltchars.t_suspc = -1; sSterm_new.sltchars.t_dsuspc = -1; sSterm_new.sltchars.t_rprntc = -1; sSterm_new.sltchars.t_flushc = -1; sSterm_new.sltchars.t_werasc = -1; sSterm_new.sltchars.t_lnextc = -1; if (! flocalecho) { sSterm_new.stty.sg_flags |= (CBREAK | ANYP); sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM); } else { sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO); sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM); } #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO bSeof = sSterm_new.c_cc[VEOF]; if (! flocalecho) sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL); else sSterm_new.c_lflag &=~ (ICANON | ISIG); sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); sSterm_new.c_oflag &=~ (OPOST); sSterm_new.c_cc[VMIN] = 1; sSterm_new.c_cc[VTIME] = 0; #endif /* HAVE_SYSV_TERMIO */ #if HAVE_POSIX_TERMIOS bSeof = sSterm_new.c_cc[VEOF]; bStstp = sSterm_new.c_cc[VSUSP]; if (! flocalecho) sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL); else sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG); sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); sSterm_new.c_oflag &=~ (OPOST); sSterm_new.c_cc[VMIN] = 1; sSterm_new.c_cc[VTIME] = 0; #endif /* HAVE_POSIX_TERMIOS */ if (! fsetterminfo (0, &sSterm_new)) { ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno)); return FALSE; } return TRUE; } /* Restore the terminal to its original setting. */ boolean fsysdep_terminal_restore () { if (! fSterm) return TRUE; if (! fsetterminfo (0, &sSterm_orig)) { ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno)); return FALSE; } return TRUE; } /* Read a line from the terminal. This will be called after fsysdep_terminal_raw has been called. */ char * zsysdep_terminal_line (zprompt) const char *zprompt; { CATCH_PROTECT size_t cbuf = 0; CATCH_PROTECT char *zbuf = NULL; CATCH_PROTECT size_t cgot = 0; if (zprompt != NULL && *zprompt != '\0') (void) write (1, zprompt, strlen (zprompt)); /* Forgot about any previous SIGINT or SIGQUIT signals we may have received. We don't worry about the race condition here, since we can't get these signals from the terminal at the moment and it's not too likely that somebody else will be sending them to us. */ afSignal[INDEXSIG_SIGINT] = 0; afSignal[INDEXSIG_SIGQUIT] = 0; if (! fsysdep_terminal_restore ()) return NULL; if (fsysdep_catch ()) { usysdep_start_catch (); cbuf = 0; zbuf = NULL; cgot = 0; } while (TRUE) { char b; int c; if (afSignal[INDEXSIG_SIGINT] || afSignal[INDEXSIG_SIGQUIT]) { usysdep_end_catch (); /* Make sure the signal is logged. */ ulog (LOG_ERROR, (const char *) NULL); /* Return an empty string. */ cgot = 0; break; } /* There's a race here between checking the signals and calling read. It just means that the user will have to hit ^C more than once. */ c = read (0, &b, 1); if (c < 0) { if (errno == EINTR) continue; usysdep_end_catch (); ulog (LOG_ERROR, "read: %s", strerror (errno)); (void) fsysdep_terminal_raw (fSlocalecho); return NULL; } if (c == 0) { /* I'm not quite sure what to do here. */ usysdep_end_catch (); ulog (LOG_ERROR, "EOF on terminal"); (void) fsysdep_terminal_raw (fSlocalecho); return NULL; } if (cgot >= cbuf) { char *znew; cbuf += 64; znew = zbufalc (cbuf); if (zbuf != NULL) { memcpy (znew, zbuf, cgot); ubuffree (zbuf); } zbuf = znew; } zbuf[cgot] = b; ++cgot; if (b == '\n') { usysdep_end_catch (); break; } } if (cgot >= cbuf) { char *znew; ++cbuf; znew = zbufalc (cbuf); if (zbuf != NULL) { memcpy (znew, zbuf, cgot); ubuffree (zbuf); } zbuf = znew; } zbuf[cgot] = '\0'; if (! fsysdep_terminal_raw (fSlocalecho)) return NULL; return zbuf; } /* Write a line to the terminal with a trailing newline. */ boolean fsysdep_terminal_puts (zline) const char *zline; { char *zalc, *zprint; size_t clen; if (zline == NULL) { zalc = zbufalc (2); clen = 0; } else { clen = strlen (zline); zalc = zbufalc (clen + 2); memcpy (zalc, zline, clen); } if (fSterm) { zalc[clen] = '\r'; ++clen; } zalc[clen] = '\n'; ++clen; zprint = zalc; while (clen > 0) { int c; c = write (1, zprint, clen); if (c <= 0) { ubuffree (zalc); ulog (LOG_ERROR, "write: %s", strerror (errno)); return FALSE; } clen -= c; zprint += c; } ubuffree (zalc); return TRUE; } /* Allow or disallow signals from the terminal. */ boolean fsysdep_terminal_signals (faccept) boolean faccept; { #if HAVE_BSD_TTY if (faccept) { sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc; sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc; } else { sSterm_new.stchars.t_intrc = -1; sSterm_new.stchars.t_quitc = -1; } #else /* ! HAVE_BSD_TTY */ if (faccept) sSterm_new.c_lflag |= ISIG; else sSterm_new.c_lflag &=~ ISIG; #ifdef SIGTSTP /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This function will be called with faccept TRUE before it is called with faccept FALSE, so fStstp_ignored will be correctly initialized. */ if (faccept) usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored); else if (! fStstp_ignored) usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL); #endif #endif /* ! HAVE_BSD_TTY */ if (! fsetterminfo (0, &sSterm_new)) { ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno)); return FALSE; } return TRUE; } /* Start up a command, or possibly just a shell. Optionally attach stdin or stdout to the port. We attach directly to the port, rather than copying the data ourselves. */ boolean fsysdep_shell (qconn, zcmd, tcmd) struct sconnection *qconn; const char *zcmd; enum tshell_cmd tcmd; { const char *azargs[4]; int oread, owrite; int aidescs[3]; pid_t ipid; azargs[0] = "/bin/sh"; if (zcmd == NULL || *zcmd == '\0') azargs[1] = NULL; else { azargs[1] = "-c"; azargs[2] = zcmd; azargs[3] = NULL; } if (qconn->qport == NULL) { oread = 0; owrite = 1; } else { switch (qconn->qport->uuconf_ttype) { default: oread = owrite = -1; break; case UUCONF_PORTTYPE_STDIN: oread = 0; owrite = 1; break; case UUCONF_PORTTYPE_MODEM: case UUCONF_PORTTYPE_DIRECT: case UUCONF_PORTTYPE_TCP: case UUCONF_PORTTYPE_TLI: oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o; break; } } aidescs[0] = 0; aidescs[1] = 1; aidescs[2] = 2; if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT) aidescs[0] = oread; if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT) aidescs[1] = owrite; ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL, FALSE, FALSE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno)); return FALSE; } return ixswait ((unsigned long) ipid, "shell") == 0; } /* Change directories. */ boolean fsysdep_chdir (zdir) const char *zdir; { if (zdir == NULL || *zdir == '\0') { zdir = getenv ("HOME"); if (zdir == NULL) { ulog (LOG_ERROR, "HOME not defined"); return FALSE; } } if (chdir (zdir) < 0) { ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno)); return FALSE; } return TRUE; } /* Suspend the current process. */ boolean fsysdep_suspend () { #ifndef SIGTSTP return fsysdep_terminal_puts ("[process suspension not supported]"); #else return kill (getpid (), SIGTSTP) == 0; #endif } efore 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))uucp-1.04/unix/detach.c1004440004150000170000001275005337263556011756 037777777777 1 0 /* detach.c Detach from the controlling terminal. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "system.h" #include "sysdep.h" #include #if HAVE_SYS_IOCTL_H #include #endif #ifdef TIOCNOTTY #define HAVE_TIOCNOTTY 1 #else #define HAVE_TIOCNOTTY 0 #endif #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif /* Detach from the controlling terminal. This is called by uucico if it is calling out to another system, so that it can receive SIGHUP signals from the port it calls out on. It is also called by uucico just before it starts uuxqt, so that uuxqt is completely independent of the terminal. */ void usysdep_detach () { #if ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY pid_t igrp; /* First make sure we are not a process group leader. If we have TIOCNOTTY, this doesn't matter, since TIOCNOTTY sets our process group to 0 anyhow. */ #if HAVE_BSD_PGRP igrp = getpgrp (0); #else igrp = getpgrp (); #endif if (igrp == getpid ()) { boolean fignored; pid_t ipid; /* Ignore SIGHUP, since our process group leader is about to die. */ usset_signal (SIGHUP, SIG_IGN, FALSE, &fignored); ipid = ixsfork (); if (ipid < 0) ulog (LOG_FATAL, "fork: %s", strerror (errno)); if (ipid != 0) _exit (EXIT_SUCCESS); /* We'll always wind up as a child of process number 1, right? Right? We have to wait for our parent to die before reenabling SIGHUP. */ while (getppid () != 1) sleep (1); ulog_id (getpid ()); /* Restore SIGHUP catcher if it wasn't being ignored. */ if (! fignored) usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL); } #endif /* ! HAVE_BSD_PGRP || ! HAVE_TIOCNOTTY */ #if HAVE_TIOCNOTTY /* Lose the original controlling terminal. If standard input has been reopened to /dev/null, this will do no harm. If another port has been opened to become the controlling terminal, it should have been detached when it was closed. */ (void) ioctl (0, TIOCNOTTY, (char *) NULL); #endif /* Close stdin, stdout and stderr and reopen them on /dev/null, to make sure we have no connection at all to the terminal. */ (void) close (0); (void) close (1); (void) close (2); if (open ((char *) "/dev/null", O_RDONLY) != 0 || open ((char *) "/dev/null", O_WRONLY) != 1 || open ((char *) "/dev/null", O_WRONLY) != 2) ulog (LOG_FATAL, "open (/dev/null): %s", strerror (errno)); #if HAVE_BSD_PGRP /* Make sure our process group ID is set to 0. On BSD TIOCNOTTY should already have set it 0, so this will do no harm. On System V we presumably did not execute the TIOCNOTTY call, but the System V setpgrp will detach the controlling terminal anyhow. This lets us use the same code on both BSD and System V, provided it compiles correctly, which life easier for the configure script. We don't output an error if we got EPERM because some BSD variants don't permit this usage of setpgrp (which means they don't provide any way to pick up a new controlling terminal). */ if (setpgrp (0, 0) < 0) { if (errno != EPERM) ulog (LOG_ERROR, "setpgrp: %s", strerror (errno)); } #else /* ! HAVE_BSD_PGRP */ #if HAVE_SETSID /* Under POSIX the setsid call creates a new session for which we are the process group leader. It also detaches us from our controlling terminal. I'm using the BSD setpgrp call first because they should be equivalent for my purposes, but it turns out that on Ultrix 4.0 setsid prevents us from ever acquiring another controlling terminal (it does not change our process group, and Ultrix 4.0 prevents us from setting our process group to 0). */ (void) setsid (); #else /* ! HAVE_SETSID */ #if HAVE_SETPGRP /* Now we assume we have the System V setpgrp, which takes no arguments, and we couldn't compile the HAVE_BSD_PGRP code above because there was a prototype somewhere in scope. On System V setpgrp makes us the leader of a new process group and also detaches the controlling terminal. */ if (setpgrp () < 0) ulog (LOG_ERROR, "setpgrp: %s", strerror (errno)); #else /* ! HAVE_SETPGRP */ #error Must detach from controlling terminal #endif /* HAVE_SETPGRP */ #endif /* ! HAVE_SETSID */ #endif /* ! HAVE_BSD_PGRP */ /* At this point we have completely detached from our controlling terminal. The next terminal device we open will probably become our controlling terminal. */ } clen = strlen (zlineuucp-1.04/unix/dirent.c1004440004150000170000000501205337263556012004 037777777777 1 0 /* dirent.c Replacements for opendir, readdir and closedir for the original Unix filesystem only. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "sysdep.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif /* Simple emulations of opendir/readdir/closedir for systems which have the original format of Unix directories. It's probably better to get Doug Gwyn's public domain set of emulation functions. */ DIR * opendir (zdir) const char *zdir; { int o; struct stat s; DIR *qret; o = open ((char *) zdir, O_RDONLY | O_NOCTTY, 0); if (o < 0) return NULL; if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0 || fstat (o, &s) < 0) { int isave; isave = errno; (void) close (o); errno = isave; return NULL; } if (! S_ISDIR (s.st_mode)) { (void) close (o); errno = ENOTDIR; return NULL; } qret = (DIR *) xmalloc (sizeof (DIR)); qret->o = o; return qret; } struct dirent * readdir (q) DIR *q; { struct direct sdir; int cgot; do { cgot = read (q->o, &sdir, sizeof (struct direct)); if (cgot <= 0) return NULL; if (cgot != sizeof (struct direct)) { errno = ENOENT; return NULL; } } while (sdir.d_ino == 0); strncpy (q->s.d_name, sdir.d_name, DIRSIZ); q->s.d_name[DIRSIZ] = '\0'; return &q->s; } int closedir (q) DIR *q; { int o; o = q->o; xfree (q); return close (o); } 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_suucp-1.04/unix/dup2.c1004440004150000170000000333505337263556011377 037777777777 1 0 /* dup2.c The Unix dup2 function, for systems which only have dup. Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc. This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "sysdep.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif /* I basically took this from the emacs 18.57 distribution, although I cleaned it up a bit and made it POSIX compliant. */ int dup2 (oold, onew) int oold; int onew; { if (oold == onew) return onew; (void) close (onew); #ifdef F_DUPFD return fcntl (oold, F_DUPFD, onew); #else { int onext, oret, isave; onext = dup (oold); if (onext == onew) return onext; if (onext < 0) return -1; oret = dup2 (oold, onew); isave = errno; (void) close (onext); errno = isave; return oret; } #endif } l.h> #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif /* Detach from the controlling terminal. This is called by uucico if it is calling out to another system, so that it can receive SIGHUP uucp-1.04/unix/efopen.c1004440004150000170000000440005337263557011774 037777777777 1 0 /* efopen.c Open a stdio file with appropriate permissions. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_APPEND #ifdef FAPPEND #define O_APPEND FAPPEND #endif #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif FILE * esysdep_fopen (zfile, fpublic, fappend, fmkdirs) const char *zfile; boolean fpublic; boolean fappend; boolean fmkdirs; { int imode; int o; FILE *e; if (fpublic) imode = IPUBLIC_FILE_MODE; else imode = IPRIVATE_FILE_MODE; if (! fappend) o = creat ((char *) zfile, imode); else { #ifdef O_CREAT o = open ((char *) zfile, O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, imode); #else o = open ((char *) zfile, O_WRONLY | O_NOCTTY); if (o < 0 && errno == ENOENT) o = creat ((char *) zfile, imode); #endif /* ! defined (O_CREAT) */ } if (o < 0) { if (errno == ENOENT && fmkdirs) { if (! fsysdep_make_dirs (zfile, fpublic)) return NULL; if (! fappend) o = creat ((char *) zfile, imode); else { #ifdef O_CREAT o = open ((char *) zfile, O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, imode); #else o = creat ((char *) zfile, imode); #endif } } if (o < 0) { ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); return NULL; } } #ifndef O_CREAT #ifdef O_APPEND if (fappend) { if (fcntl (o, F_SETFL, O_APPEND) < 0) { ulog (LOG_ERROR, "fcntl (%s, O_APPEND): %s", zfile, strerror (errno)); (void) close (o); return NULL; } } #endif /* defined (O_APPEND) */ #endif /* ! defined (O_CREAT) */ if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (%s, FD_CLOEXEC): %s", zfile, strerror (errno)); (void) close (o); return NULL; } if (fappend) e = fdopen (o, (char *) "a"); else e = fdopen (o, (char *) "w"); if (e == NULL) { ulog (LOG_ERROR, "fdopen: %s", strerror (errno)); (void) close (o); } return e; } he 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 ouuucp-1.04/unix/epopen.c1004440004150000170000000431105337263557012007 037777777777 1 0 /* epopen.c A version of popen that goes through ixsspawn. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "sysdep.h" #include /* A version of popen that goes through ixsspawn. This actually takes an array of arguments rather than a string, and takes a boolean read/write value rather than a string. It sets *pipid to the process ID of the child. */ FILE * espopen (pazargs, frd, pipid) const char **pazargs; boolean frd; pid_t *pipid; { int aidescs[3]; pid_t ipid; FILE *eret; if (frd) { aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_READ_PIPE; } else { aidescs[0] = SPAWN_WRITE_PIPE; aidescs[1] = SPAWN_NULL; } aidescs[2] = SPAWN_NULL; ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) return NULL; if (frd) eret = fdopen (aidescs[1], (char *) "r"); else eret = fdopen (aidescs[0], (char *) "w"); if (eret == NULL) { int ierr; ierr = errno; (void) close (frd ? aidescs[1] : aidescs[0]); (void) kill (ipid, SIGKILL); (void) ixswait ((unsigned long) ipid, (const char *) NULL); errno = ierr; return NULL; } *pipid = ipid; return eret; } #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. */ DIRuucp-1.04/unix/exists.c1004440004150000170000000035005337263557012037 037777777777 1 0 /* 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; } 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 clouucp-1.04/unix/filnam.c1004440004150000170000002323205337263557011772 037777777777 1 0 /* filnam.c Get names to use for UUCP files. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* We need a definition for SEEK_SET. */ #ifndef SEEK_SET #define SEEK_SET 0 #endif /* External functions. */ #ifndef lseek extern off_t lseek (); #endif #define ZCHARS \ "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZabcdefghijklmnopqrstuvwxyz" /* Local functions. */ static boolean fscmd_seq P((const char *zsystem, char *zseq)); static char *zsfile_name P((int btype, const char *zsystem, const char *zlocalname, int bgrade, boolean fxqt, char *ztname, char *zdname, char *zxname)); /* Get a new command sequence number (this is not a sequence number to be used for communicating with another system, but a sequence number to be used when generating the name of a command file). The sequence number is placed into zseq, which should be five characters long. */ static boolean fscmd_seq (zsystem, zseq) const char *zsystem; char *zseq; { boolean ferr; char *zfree; const char *zfile; int o; int i; /* Lock the sequence file. This may not be correct for all systems, but it only matters if the system UUCP and this UUCP are running at the same time. */ while (! fsdo_lock ("LCK..SEQ", TRUE, &ferr)) { if (ferr || FGOT_SIGNAL ()) return FALSE; sleep (5); } zfree = NULL; #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 zfile = "SEQF"; #endif #if SPOOLDIR_HDB || SPOOLDIR_SVR4 zfree = zsysdep_in_dir (".Sequence", zsystem); zfile = zfree; #endif #if SPOOLDIR_ULTRIX if (! fsultrix_has_spool (zsystem)) zfile = "sys/DEFAULT/.SEQF"; else { zfree = zsappend3 ("sys", zsystem, ".SEQF"); zfile = zfree; } #endif /* SPOOLDIR_ULTRIX */ #if SPOOLDIR_TAYLOR zfree = zsysdep_in_dir (zsystem, "SEQF"); zfile = zfree; #endif /* SPOOLDIR_TAYLOR */ #ifdef O_CREAT o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE); #else o = open ((char *) zfile, O_RDWR | O_NOCTTY); if (o < 0 && errno == ENOENT) { o = creat ((char *) zfile, IPUBLIC_FILE_MODE); if (o >= 0) { (void) close (o); o = open ((char *) zfile, O_RDWR | O_NOCTTY); } } #endif if (o < 0) { if (errno == ENOENT) { if (! fsysdep_make_dirs (zfile, FALSE)) { (void) fsdo_unlock ("LCK..SEQ", TRUE); return FALSE; } #ifdef O_CREAT o = open ((char *) zfile, O_RDWR | O_CREAT | O_NOCTTY, IPUBLIC_FILE_MODE); #else o = creat ((char *) zfile, IPUBLIC_FILE_MODE); if (o >= 0) { (void) close (o); o = open ((char *) zfile, O_RDWR | O_NOCTTY); } #endif } if (o < 0) { ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); (void) fsdo_unlock ("LCK..SEQ", TRUE); return FALSE; } } if (read (o, zseq, CSEQLEN) != CSEQLEN) strcpy (zseq, "0000"); zseq[CSEQLEN] = '\0'; /* We must add one to the sequence number and return the new value. On Ultrix, arbitrary characters are allowed in the sequence number. On other systems, the sequence number apparently must be in hex. */ #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_HDB || SPOOLDIR_SVR4 i = (int) strtol (zseq, (char **) NULL, 16); ++i; if (i > 0xffff) i = 0; /* The sprintf argument has CSEQLEN built into it. */ sprintf (zseq, "%04x", (unsigned int) i); #endif #if SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR for (i = CSEQLEN - 1; i >= 0; i--) { const char *zdig; zdig = strchr (ZCHARS, zseq[i]); if (zdig == NULL || zdig[0] == '\0' || zdig[1] == '\0') zseq[i] = '0'; else { zseq[i] = zdig[1]; break; } } #endif /* SPOOLDIR_ULTRIX || SPOOLDIR_TAYLOR */ if (lseek (o, (off_t) 0, SEEK_SET) < 0 || write (o, zseq, CSEQLEN) != CSEQLEN || close (o) < 0) { ulog (LOG_ERROR, "lseek or write or close: %s", strerror (errno)); (void) close (o); (void) fsdo_unlock ("LCK..SEQ", TRUE); return FALSE; } (void) fsdo_unlock ("LCK..SEQ", TRUE); return TRUE; } /* Get the name of a command or data file for a remote system. The btype argument should be C for a command file or D for a data file. If the grade of a data file is X, it is assumed that this is going to become an execute file on some other system. The zsystem argument is the system that the file will be transferred to. The ztname argument will be set to a file name that could be passed to zsysdep_spool_file_name. The zdname argument, if not NULL, will be set to a data file name appropriate for the remote system. The zxname argument, if not NULL, will be set to the name of an execute file on the remote system. None of the names will be more than 14 characters long. */ /*ARGSUSED*/ static char * zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname) int btype; const char *zsystem; const char *zlocalname; int bgrade; boolean fxqt; char *ztname; char *zdname; char *zxname; { char abseq[CSEQLEN + 1]; char absimple[11 + CSEQLEN]; char *zname; if (zlocalname == NULL) zlocalname = zSlocalname; while (TRUE) { if (! fscmd_seq (zsystem, abseq)) return NULL; if (btype == 'C') { #if ! SPOOLDIR_TAYLOR sprintf (absimple, "C.%.7s%c%s", zsystem, bgrade, abseq); #else sprintf (absimple, "C.%c%s", bgrade, abseq); #endif } else if (btype == 'D') { /* This name doesn't really matter that much; it's just the name we use on the local system. The name we use on the remote system, which we return in zdname, should contain our system name so that remote UUCP's running SPOOLDIR_V2 and the like can distinguish while files come from which systems. */ #if SPOOLDIR_HDB || SPOOLDIR_SVR4 sprintf (absimple, "D.%.7s%c%s", zsystem, bgrade, abseq); #else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ #if ! SPOOLDIR_TAYLOR sprintf (absimple, "D.%.7s%c%s", zlocalname, bgrade, abseq); #else /* SPOOLDIR_TAYLOR */ if (fxqt) sprintf (absimple, "D.X%s", abseq); else sprintf (absimple, "D.%s", abseq); #endif /* SPOOLDIR_TAYLOR */ #endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ } #if DEBUG > 0 else ulog (LOG_FATAL, "zsfile_name: Can't happen"); #endif zname = zsfind_file (absimple, zsystem, bgrade); if (zname == NULL) return NULL; if (! fsysdep_file_exists (zname)) break; ubuffree (zname); } if (ztname != NULL) strcpy (ztname, absimple); if (zdname != NULL) sprintf (zdname, "D.%.7s%c%s", zlocalname, bgrade, abseq); if (zxname != NULL) sprintf (zxname, "X.%.7s%c%s", zlocalname, bgrade, abseq); return zname; } /* Return a name to use for a data file to be copied to another system. The name returned will be for a real file. The zlocalname argument is the local name as seen by the remote system, the bgrade argument is the file grade, and the fxqt argument is TRUE if this file will become an execution file. The ztname argument, if not NULL, will be set to a name that could be passed to zsysdep_spool_file_name to get back the return value of this function. The zdname argument, if not NULL, will be set to a name that the file could be given on another system. The zxname argument, if not NULL, will be set to a name for an execute file on another system. */ char * zsysdep_data_file_name (qsys, zlocalname, bgrade, fxqt, ztname, zdname, zxname) const struct uuconf_system *qsys; const char *zlocalname; int bgrade; boolean fxqt; char *ztname; char *zdname; char *zxname; { return zsfile_name ('D', qsys->uuconf_zname, zlocalname, bgrade, fxqt, ztname, zdname, zxname); } /* Get a command file name. */ char * zscmd_file (qsys, bgrade) const struct uuconf_system *qsys; int bgrade; { return zsfile_name ('C', qsys->uuconf_zname, (const char *) NULL, bgrade, FALSE, (char *) NULL, (char *) NULL, (char *) NULL); } /* Return a name for an execute file to be created locally. This is used by uux to execute a command locally with remote files. */ char * zsysdep_xqt_file_name () { char abseq[CSEQLEN + 1]; char absx[11 + CSEQLEN]; char *zname; while (TRUE) { if (! fscmd_seq (zSlocalname, abseq)) return NULL; sprintf (absx, "X.%.7sX%s", zSlocalname, abseq); zname = zsfind_file (absx, zSlocalname, -1); if (zname == NULL) return NULL; if (! fsysdep_file_exists (zname)) break; ubuffree (zname); } return zname; } 037777777777 1 0 uucp-1.04/unix/fsusg.c1004440004150000170000001261105337263560011644 037777777777 1 0 /* fsusage.c -- return space usage of mounted filesystems Copyright (C) 1991, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. This file was modified slightly by Ian Lance Taylor, December 1992, for use with Taylor UUCP. */ #include "uucp.h" #include "sysdep.h" #include "fsusg.h" int statfs (); #if STAT_STATFS2_BSIZE #ifndef _IBMR2 /* 4.3BSD, SunOS 4, HP-UX, AIX PS/2. */ #include #endif #endif #if STAT_STATFS2_FSIZE /* 4.4BSD. */ #include #endif #if STAT_STATFS2_FS_DATA /* Ultrix. */ #include #include #endif #if STAT_USTAT /* SVR2 and others. */ #include #endif #if STAT_STATFS4 /* SVR3, Dynix, Irix. */ #include #endif #ifdef _AIX #ifdef _IBMR2 /* AIX RS6000. */ #include #endif #endif #ifdef _AIX #ifdef _I386 /* AIX PS/2. */ #include #include #endif #endif #if STAT_STATVFS /* SVR4. */ #include int statvfs (); #endif #define STAT_NONE 0 #if ! STAT_STATVFS #if ! STAT_STATFS2_BSIZE #if ! STAT_STATFS2_FSIZE #if ! STAT_STATFS2_FS_DATA #if ! STAT_STATFS4 #if ! STAT_USTAT #undef STAT_NONE #define STAT_NONE 1 #endif #endif #endif #endif #endif #endif #if ! STAT_NONE /* Return the number of TOSIZE-byte blocks used by BLOCKS FROMSIZE-byte blocks, rounding up. */ static long adjust_blocks (blocks, fromsize, tosize) long blocks; int fromsize, tosize; { if (fromsize == tosize) /* E.g., from 512 to 512. */ return blocks; else if (fromsize > tosize) /* E.g., from 2048 to 512. */ return blocks * (fromsize / tosize); else /* E.g., from 256 to 512. */ return (blocks + 1) / (tosize / fromsize); } #endif /* Fill in the fields of FSP with information about space usage for the filesystem on which PATH resides. DISK is the device on which PATH is mounted, for space-getting methods that need to know it. Return 0 if successful, -1 if not. */ int get_fs_usage (path, disk, fsp) char *path, *disk; struct fs_usage *fsp; { #if STAT_NONE return -1; #endif #if STAT_STATFS2_FS_DATA /* Ultrix. */ struct fs_data fsd; if (statfs (path, &fsd) != 1) return -1; #define convert_blocks(b) adjust_blocks ((b), 1024, 512) fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot); fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree); fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen); fsp->fsu_files = fsd.fd_req.gtot; fsp->fsu_ffree = fsd.fd_req.gfree; #endif #if STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */ struct statfs fsd; if (statfs (path, &fsd) < 0) return -1; #define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512) #endif #if STAT_STATFS2_FSIZE /* 4.4BSD. */ struct statfs fsd; if (statfs (path, &fsd) < 0) return -1; #define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512) #endif #if STAT_STATFS4 /* SVR3, Dynix, Irix. */ struct statfs fsd; if (statfs (path, &fsd, sizeof fsd, 0) < 0) return -1; /* Empirically, the block counts on most SVR3 and SVR3-derived systems seem to always be in terms of 512-byte blocks, no matter what value f_bsize has. */ #define convert_blocks(b) (b) #ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */ #define f_bavail f_bfree #endif #endif #if STAT_STATVFS /* SVR4. */ struct statvfs fsd; if (statvfs (path, &fsd) < 0) return -1; /* f_frsize isn't guaranteed to be supported. */ #define convert_blocks(b) \ adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512) #endif #if STAT_USTAT { struct stat sstat; struct ustat s; if (stat (path, &sstat) < 0 || ustat (sstat.st_dev, &s) < 0) return -1; fsp->fsu_blocks = -1; fsp->fsu_bfree = f_tfree; fsp->fsu_bavail = f_tfree; fsp->fsu_files = -1; fsp->fsu_ffree = -1; } #endif #if ! STAT_STATFS2_FS_DATA /* ! Ultrix */ #if ! STAT_USTAT #if ! STAT_NONE fsp->fsu_blocks = convert_blocks (fsd.f_blocks); fsp->fsu_bfree = convert_blocks (fsd.f_bfree); fsp->fsu_bavail = convert_blocks (fsd.f_bavail); fsp->fsu_files = fsd.f_files; fsp->fsu_ffree = fsd.f_ffree; #endif #endif #endif return 0; } #ifdef _AIX #ifdef _I386 /* AIX PS/2 does not supply statfs. */ int statfs (path, fsb) char *path; struct statfs *fsb; { struct stat stats; struct dustat fsd; if (stat (path, &stats)) return -1; if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) return -1; fsb->f_type = 0; fsb->f_bsize = fsd.du_bsize; fsb->f_blocks = fsd.du_fsize - fsd.du_isize; fsb->f_bfree = fsd.du_tfree; fsb->f_bavail = fsd.du_tfree; fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; fsb->f_ffree = fsd.du_tinode; fsb->f_fsid.val[0] = fsd.du_site; fsb->f_fsid.val[1] = fsd.du_pckno; return 0; } #endif #endif /* _AIX && _I386 */ . */ /*ARGSUSED*/ static char * zsfile_name (btype, zsystem, zlocalname, bgrade, fxqt, ztname, zdname, zxname) iuucp-1.04/unix/fsusg.h1004440004150000170000000243405337263560011653 037777777777 1 0 /* 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)); seq); 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 bgruucp-1.04/unix/ftw.c1004440004150000170000001115405337263560011316 037777777777 1 0 /* Copyright (C) 1991, 1992 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ian Lance Taylor (ian@airs.com). The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Modified by Ian Lanc Taylor for Taylor UUCP, June 1992. */ #include "uucp.h" #include "sysdep.h" #include #if HAVE_LIMITS_H #include #endif #if HAVE_SYS_PARAM_H #include #endif #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ #if HAVE_FTW_H #include #endif #ifndef PATH_MAX #ifdef MAXPATHLEN #define PATH_MAX MAXPATHLEN #else #define PATH_MAX 1024 #endif #endif /* Traverse one level of a directory tree. */ static int ftw_dir (dirs, level, descriptors, dir, len, func) DIR **dirs; int level; int descriptors; char *dir; size_t len; int (*func) P((const char *file, const struct stat *status, int flag)); { int got; struct dirent *entry; got = 0; errno = 0; while ((entry = readdir (dirs[level])) != NULL) { size_t namlen; struct stat s; int flag, ret, newlev; ++got; namlen = strlen (entry->d_name); if (entry->d_name[0] == '.' && (namlen == 1 || (namlen == 2 && entry->d_name[1] == '.'))) { errno = 0; continue; } if (namlen + len + 1 > PATH_MAX) { #ifdef ENAMETOOLONG errno = ENAMETOOLONG; #else errno = ENOMEM; #endif return -1; } dir[len] = '/'; memcpy ((dir + len + 1), entry->d_name, namlen + 1); if (stat (dir, &s) < 0) { if (errno != EACCES) return -1; flag = FTW_NS; } else if (S_ISDIR (s.st_mode)) { newlev = (level + 1) % descriptors; if (dirs[newlev] != NULL) closedir (dirs[newlev]); dirs[newlev] = opendir (dir); if (dirs[newlev] != NULL) flag = FTW_D; else { if (errno != EACCES) return -1; flag = FTW_DNR; } } else flag = FTW_F; ret = (*func) (dir, &s, flag); if (flag == FTW_D) { if (ret == 0) ret = ftw_dir (dirs, newlev, descriptors, dir, namlen + len + 1, func); if (dirs[newlev] != NULL) { int save; save = errno; closedir (dirs[newlev]); errno = save; dirs[newlev] = NULL; } } if (ret != 0) return ret; if (dirs[level] == NULL) { int skip; dir[len] = '\0'; dirs[level] = opendir (dir); if (dirs[level] == NULL) return -1; skip = got; while (skip-- != 0) { errno = 0; if (readdir (dirs[level]) == NULL) return errno == 0 ? 0 : -1; } } errno = 0; } return errno == 0 ? 0 : -1; } /* Call a function on every element in a directory tree. */ int ftw (dir, func, descriptors) const char *dir; int (*func) P((const char *file, const struct stat *status, int flag)); int descriptors; { DIR **dirs; int c; DIR **p; size_t len; char buf[PATH_MAX + 1]; struct stat s; int flag, ret; if (descriptors <= 0) descriptors = 1; dirs = (DIR **) malloc (descriptors * sizeof (DIR *)); if (dirs == NULL) return -1; c = descriptors; p = dirs; while (c-- != 0) *p++ = NULL; len = strlen (dir); memcpy (buf, dir, len + 1); if (stat (dir, &s) < 0) { if (errno != EACCES) { free ((pointer) dirs); return -1; } flag = FTW_NS; } else if (S_ISDIR (s.st_mode)) { dirs[0] = opendir (dir); if (dirs[0] != NULL) flag = FTW_D; else { if (errno != EACCES) { free ((pointer) dirs); return -1; } flag = FTW_DNR; } } else flag = FTW_F; ret = (*func) (buf, &s, flag); if (flag == FTW_D) { if (ret == 0) ret = ftw_dir (dirs, 0, descriptors, buf, len, func); if (dirs[0] != NULL) { int save; save = errno; closedir (dirs[0]); errno = save; } } free ((pointer) dirs); return ret; } h, 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 = convertuucp-1.04/unix/getcwd.c1004440004150000170000000154105337263561011773 037777777777 1 0 /* getcwd.c Replacement for the getcwd function that just calls /bin/pwd. */ #include "uucp.h" #include "sysdep.h" #include char * getcwd (zbuf, cbuf) char *zbuf; size_t cbuf; { const char *azargs[2]; FILE *e; pid_t ipid; int cread; int ierr; azargs[0] = PWD_PROGRAM; azargs[1] = NULL; e = espopen (azargs, TRUE, &ipid); if (e == NULL) return NULL; ierr = 0; cread = fread (zbuf, sizeof (char), cbuf, e); if (cread == 0) ierr = errno; (void) fclose (e); if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) { ierr = EACCES; cread = 0; } if (cread != 0) { if (zbuf[cread - 1] == '\n') zbuf[cread - 1] = '\0'; else { ierr = ERANGE; cread = 0; } } if (cread == 0) { errno = ierr; return NULL; } return zbuf; } _bavail = f_tfree; fsp->fsu_files = -1; fsp->fsu_ffree = -1; } #endif #if ! STAT_STATFS2_FS_DATA /* ! Ultrix */ #if ! STAT_USTAT #if ! STAT_NONE fuucp-1.04/unix/indir.c1004440004150000170000000655005337263561011630 037777777777 1 0 /* indir.c See if a file is in a directory. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* See whether a file is in a directory, and optionally check access. */ boolean fsysdep_in_directory (zfile, zdir, fcheck, freadable, zuser) const char *zfile; const char *zdir; boolean fcheck; boolean freadable; const char *zuser; { size_t c; char *zcopy, *zslash; struct stat s; if (*zfile != '/') return FALSE; c = strlen (zdir); if (c > 0 && zdir[c - 1] == '/') c--; if (strncmp (zfile, zdir, c) != 0 || (zfile[c] != '/' && zfile[c] != '\0')) return FALSE; if (strstr (zfile + c, "/../") != NULL) return FALSE; /* If we're not checking access, get out now. */ if (! fcheck) return TRUE; zcopy = zbufcpy (zfile); /* Start checking directories after zdir. Otherwise, we would require that all directories down to /usr/spool/uucppublic be publically searchable; they probably are but it should not be a requirement. */ zslash = zcopy + c; do { char b; struct stat shold; b = *zslash; *zslash = '\0'; shold = s; if (stat (zcopy, &s) != 0) { if (errno != ENOENT) { ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno)); ubuffree (zcopy); return FALSE; } /* If this is the top directory, any problems will be caught later when we try to open it. */ if (zslash == zcopy + c) { ubuffree (zcopy); return TRUE; } /* Go back and check the last directory for read or write access. */ s = shold; break; } /* If this is not a directory, get out of the loop. */ if (! S_ISDIR (s.st_mode)) break; /* Make sure the directory is searchable. */ if (! fsuser_access (&s, X_OK, zuser)) { ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); ubuffree (zcopy); return FALSE; } /* If we've reached the end of the string, get out. */ if (b == '\0') break; *zslash = b; } while ((zslash = strchr (zslash + 1, '/')) != NULL); /* At this point s holds a stat on the last component of the path. We must check it for readability or writeability. */ if (! fsuser_access (&s, freadable ? R_OK : W_OK, zuser)) { ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); ubuffree (zcopy); return FALSE; } ubuffree (zcopy); return TRUE; } , 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 thuucp-1.04/unix/init.c1004440004150000170000002276205337263561011471 037777777777 1 0 /* init.c Initialize the system dependent routines. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "sysdep.h" #include #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #if ! HAVE_GETHOSTNAME && HAVE_UNAME #include #endif /* Use getcwd in preference to getwd; if we have neither, we will be using a getcwd replacement. */ #if HAVE_GETCWD #undef HAVE_GETWD #define HAVE_GETWD 0 #else /* ! HAVE_GETCWD */ #if ! HAVE_GETWD #undef HAVE_GETCWD #define HAVE_GETCWD 1 #endif /* ! HAVE_GETWD */ #endif /* ! HAVE_GETCWD */ #if HAVE_GETWD /* Get a value for MAXPATHLEN. */ #if HAVE_SYS_PARAMS_H #include #endif #if HAVE_LIMITS_H #include #endif #ifndef MAXPATHLEN #ifdef PATH_MAX #define MAXPATHLEN PATH_MAX #else /* ! defined (PATH_MAX) */ #define MAXPATHLEN 1024 #endif /* ! defined (PATH_MAX) */ #endif /* ! defined (MAXPATHLEN) */ #endif /* HAVE_GETWD */ /* External functions. */ #ifndef getlogin extern char *getlogin (); #endif #if GETPWNAM_DECLARATION_OK #ifndef getpwnam extern struct passwd *getpwnam (); #endif #endif #if GETPWUID_DECLARATION_OK #ifndef getpwuid extern struct passwd *getpwuid (); #endif #endif #if HAVE_GETCWD #ifndef getcwd extern char *getcwd (); #endif #endif #if HAVE_GETWD #ifndef getwd extern char *getwd (); #endif #endif #if HAVE_SYSCONF #ifndef sysconf extern long sysconf (); #endif #endif /* Initialize the system dependent routines. We will probably be running suid to uucp, so we make sure that nothing is obviously wrong. We save the login name since we will be losing the real uid. */ static char *zSlogin; /* The UUCP spool directory. */ const char *zSspooldir; /* The UUCP lock directory. */ const char *zSlockdir; /* The local UUCP name. */ const char *zSlocalname; /* We save the current directory since we will do a chdir to the spool directory. */ char *zScwd; /* The maximum length of a system name is controlled by the type of spool directory we use. */ #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX size_t cSysdep_max_name_len = 7; #endif #if SPOOLDIR_HDB || SPOOLDIR_SVR4 size_t cSysdep_max_name_len = 14; #endif #if SPOOLDIR_TAYLOR #if HAVE_LONG_FILE_NAMES size_t cSysdep_max_name_len = 255; #else /* ! HAVE_LONG_FILE_NAMES */ size_t cSysdep_max_name_len = 14; #endif /* ! HAVE_LONG_FILE_NAMES */ #endif /* SPOOLDIR_TAYLOR */ /* Initialize the system dependent routines. */ void usysdep_initialize (puuconf,iflags) pointer puuconf; int iflags; { int cdescs; int o; int iuuconf; char *z; struct passwd *q; ulog_id (getpid ()); /* Close everything but stdin, stdout and stderr. */ #if HAVE_GETDTABLESIZE cdescs = getdtablesize (); #else #if HAVE_SYSCONF cdescs = sysconf (_SC_OPEN_MAX); #else #ifdef OPEN_MAX cdescs = OPEN_MAX; #else #ifdef NOFILE cdescs = NOFILE; #else cdescs = 20; #endif /* ! defined (NOFILE) */ #endif /* ! defined (OPEN_MAX) */ #endif /* ! HAVE_SYSCONF */ #endif /* ! HAVE_GETDTABLESIZE */ for (o = 3; o < cdescs; o++) (void) close (o); /* Make sure stdin, stdout and stderr are open. */ if (fcntl (0, F_GETFD, 0) < 0 && open ((char *) "/dev/null", O_RDONLY, 0) != 0) exit (EXIT_FAILURE); if (fcntl (1, F_GETFD, 0) < 0 && open ((char *) "/dev/null", O_WRONLY, 0) != 1) exit (EXIT_FAILURE); if (fcntl (2, F_GETFD, 0) < 0 && open ((char *) "/dev/null", O_WRONLY, 0) != 2) exit (EXIT_FAILURE); iuuconf = uuconf_spooldir (puuconf, &zSspooldir); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); iuuconf = uuconf_lockdir (puuconf, &zSlockdir); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); iuuconf = uuconf_localname (puuconf, &zSlocalname); if (iuuconf == UUCONF_NOT_FOUND) { #if HAVE_GETHOSTNAME char ab[256]; if (gethostname (ab, sizeof ab - 1) < 0) ulog (LOG_FATAL, "gethostname: %s", strerror (errno)); ab[sizeof ab - 1] = '\0'; ab[strcspn (ab, ".")] = '\0'; zSlocalname = zbufcpy (ab); #else /* ! HAVE_GETHOSTNAME */ #if HAVE_UNAME struct utsname s; if (uname (&s) < 0) ulog (LOG_FATAL, "uname: %s", strerror (errno)); zSlocalname = zbufcpy (s.nodename); #else /* ! HAVE_UNAME */ ulog (LOG_FATAL, "Don't know how to get local node name"); #endif /* ! HAVE_UNAME */ #endif /* ! HAVE_GETHOSTNAME */ } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); /* We always set our file modes to exactly what we want. */ umask (0); /* Get the login name, making sure that it matches the uid. Many systems truncate the getlogin return value to 8 characters, but keep the full name in the password file, so we prefer the name in the password file. */ z = getenv ("LOGNAME"); if (z == NULL) z = getenv ("USER"); if (z == NULL) z = getlogin (); if (z == NULL) q = NULL; else { q = getpwnam (z); if (q != NULL) z = q->pw_name; } if (q == NULL || q->pw_uid != getuid ()) { q = getpwuid (getuid ()); if (q == NULL) z = NULL; else z = q->pw_name; } if (z != NULL) zSlogin = zbufcpy (z); /* On some old systems, an suid program run by root is started with an euid of 0. If this happens, we look up the uid we should have and set ourselves to it manually. This means that on such a system root will not be able to uucp or uux files that are not readable by uucp. */ if ((iflags & INIT_SUID) != 0 && geteuid () == 0) { q = getpwnam (OWNER); if (q != NULL) setuid (q->pw_uid); } if ((iflags & INIT_GETCWD) != 0) { const char *zenv; struct stat senv, sdot; /* Get the current working directory. We have to get it now, since we're about to do a chdir. We use PWD if it's defined and if it really names the working directory, since if it's not the same as whatever getcwd returns it's probably more appropriate. */ zenv = getenv ("PWD"); if (zenv != NULL && stat ((char *) zenv, &senv) == 0 && stat ((char *) ".", &sdot) == 0 && senv.st_ino == sdot.st_ino && senv.st_dev == sdot.st_dev) zScwd = zbufcpy (zenv); else { #if HAVE_GETCWD { size_t c; c = 128; while (TRUE) { zScwd = (char *) xmalloc (c); if (getcwd (zScwd, c) != NULL) break; xfree ((pointer) zScwd); zScwd = NULL; if (errno != ERANGE) break; c <<= 1; } } #endif /* HAVE_GETCWD */ #if HAVE_GETWD zScwd = (char *) xmalloc (MAXPATHLEN); if (getwd (zScwd) == NULL) { xfree ((pointer) zScwd); zScwd = NULL; } #endif /* HAVE_GETWD */ if (zScwd != NULL) zScwd = (char *) xrealloc ((pointer) zScwd, strlen (zScwd) + 1); } } if ((iflags & INIT_NOCHDIR) == 0) { /* Connect to the spool directory, and create it if it doesn't exist. */ if (chdir (zSspooldir) < 0) { if (errno == ENOENT && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0) ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir, strerror (errno)); if (chdir (zSspooldir) < 0) ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir, strerror (errno)); } } } /* Exit the program. */ void usysdep_exit (fsuccess) boolean fsuccess; { exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE); } /* This is called when a non-standard configuration file is used, to make sure the program doesn't hand out privileged file access. This means that to test non-standard configuration files, you should be logged in as uucp. This is called before usysdep_initialize. It ensures that someone can't simply use an alternate configuration file to steal UUCP transfers from other systems. This will still permit people to set up their own configuration file and pretend to be whatever system they choose. The only real security is to use a high level of protection on the modem ports. */ /*ARGSUSED*/ boolean fsysdep_other_config (z) const char *z; { (void) setuid (getuid ()); (void) setgid (getgid ()); return TRUE; } /* Get the node name to use if it was not specified in the configuration file. */ const char * zsysdep_localname () { return zSlocalname; } /* Get the login name. We actually get the login name in usysdep_initialize, because after that we may switch away from the real uid. */ const char * zsysdep_login_name () { if (zSlogin == NULL) ulog (LOG_FATAL, "Can't get login name"); return zSlogin; } ithout even thuucp-1.04/unix/isdir.c1004440004150000170000000042605337263561011631 037777777777 1 0 /* 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); } e 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 eveuucp-1.04/unix/jobid.c1004440004150000170000000523105337263562011606 037777777777 1 0 /* 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; } /* 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_SYSCOuucp-1.04/unix/isfork.c1004440004150000170000000047505337263562012021 037777777777 1 0 /* isfork.c Retry fork several times before giving up. */ #include "uucp.h" #include "sysdep.h" #include pid_t ixsfork () { int i; pid_t iret; for (i = 0; i < 10; i++) { iret = fork (); if (iret >= 0 || errno != EAGAIN) return iret; sleep (5); } return iret; } F_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';uucp-1.04/unix/iswait.c1004440004150000170000001124705337263562012023 037777777777 1 0 /* iswait.c Wait for a process to finish. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include #if HAVE_SYS_WAIT_H #include #endif /* We use a typedef wait_status for wait (waitpid, wait4) to put results into. We define the POSIX examination functions we need if they are not already defined (if they aren't defined, I assume that we have a standard wait status). */ #if HAVE_UNION_WAIT typedef union wait wait_status; #ifndef WIFEXITED #define WIFEXITED(u) ((u).w_termsig == 0) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(u) ((u).w_retcode) #endif #ifndef WTERMSIG #define WTERMSIG(u) ((u).w_termsig) #endif #else /* ! HAVE_UNION_WAIT */ typedef int wait_status; #ifndef WIFEXITED #define WIFEXITED(i) (((i) & 0xff) == 0) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(i) (((i) >> 8) & 0xff) #endif #ifndef WTERMSIG #define WTERMSIG(i) ((i) & 0x7f) #endif #endif /* ! HAVE_UNION_WAIT */ /* Wait for a particular process to finish. The ipid argument should be pid_t, but then we couldn't have a prototype. If the zreport argument is not NULL, then a wait error will be logged, and if the exit status is non-zero it will be logged with zreport as the header of the log message. If the zreport argument is NULL, no errors will be logged. This function returns the exit status if the process exited normally, or -1 on error or if the process was killed by a signal (I don't just always return the exit status because then the calling code would have to prepared to handle union wait status vs. int status, and none of the callers care which signal killed the program anyhow). This functions keeps waiting until the process finished, even if it is interrupted by a signal. I think this is right for all uses. The controversial one would be when called from uuxqt to wait for a requested process. Hitting uuxqt with SIGKILL will approximate the actions taken if we return from here with an error anyhow. If we do get a signal, we call ulog with a NULL argument to get it in the log file at about the right time. */ int ixswait (ipid, zreport) unsigned long ipid; const char *zreport; { wait_status istat; #if HAVE_WAITPID while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "waitpid: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } #else /* ! HAVE_WAITPID */ #if HAVE_WAIT4 while (wait4 ((pid_t) ipid, (pointer) &istat, 0, (struct rusage *) NULL) < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "wait4: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } #else /* ! HAVE_WAIT4 */ pid_t igot; /* We could theoretically get the wrong child here if we're in some kind of weird pipeline, so we don't give any error messages for it. */ while ((igot = wait ((pointer) &istat)) != (pid_t) ipid) { if (igot < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "wait: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } } #endif /* ! HAVE_WAIT4 */ #endif /* ! HAVE_WAITPID */ DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d", WIFEXITED (istat) ? "Exit status" : "Signal", WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat)); if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0) return 0; if (zreport != NULL) { if (! WIFEXITED (istat)) ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat)); else ulog (LOG_ERROR, "%s: Exit status %d", zreport, WEXITSTATUS (istat)); } if (WIFEXITED (istat)) return WEXITSTATUS (istat); else return -1; } har *z; { struct stat s; if (stat ((char *) z, &s) < 0) return FALSE; return S_ISDIR (s.st_mode); } e 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 eveuucp-1.04/unix/lcksys.c1004440004150000170000000143205337263562012026 037777777777 1 0 /* 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; } ndation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author 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 "uucuucp-1.04/unix/link.c1004440004150000170000000121605337263563011454 037777777777 1 0 /* link.c Link two files. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include boolean fsysdep_link (zfrom, zto, pfworked) const char *zfrom; const char *zto; boolean *pfworked; { *pfworked = FALSE; if (link (zfrom, zto) == 0) { *pfworked = TRUE; return TRUE; } if (errno == ENOENT) { if (! fsysdep_make_dirs (zto, TRUE)) return FALSE; if (link (zfrom, zto) == 0) { *pfworked = TRUE; return TRUE; } } if (errno == EXDEV) return TRUE; ulog (LOG_ERROR, "link (%s, %s): %s", zfrom, zto, strerror (errno)); return FALSE; } n 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); uucp-1.04/unix/locfil.c1004440004150000170000000427505337263563011777 037777777777 1 0 /* locfil.c Expand a file name on the local system. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if GETPWNAM_DECLARATION_OK #ifndef getpwnam extern struct passwd *getpwnam (); #endif #endif /* Turn a file name into an absolute path, by doing tilde expansion and moving any other type of file into the public directory. */ char * zsysdep_local_file (zfile, zpubdir) const char *zfile; const char *zpubdir; { const char *zdir; if (*zfile == '/') return zbufcpy (zfile); if (*zfile != '~') zdir = zpubdir; else { if (zfile[1] == '\0') return zbufcpy (zpubdir); if (zfile[1] == '/') { zdir = zpubdir; zfile += 2; } else { size_t cuserlen; char *zcopy; struct passwd *q; ++zfile; cuserlen = strcspn ((char *) zfile, "/"); zcopy = zbufalc (cuserlen + 1); memcpy (zcopy, zfile, cuserlen); zcopy[cuserlen] = '\0'; q = getpwnam (zcopy); if (q == NULL) { ulog (LOG_ERROR, "User %s not found", zcopy); ubuffree (zcopy); return NULL; } ubuffree (zcopy); if (zfile[cuserlen] == '\0') return zbufcpy (q->pw_dir); zdir = q->pw_dir; zfile += cuserlen + 1; } } return zsysdep_in_dir (zdir, zfile); } nse 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 "sysuucp-1.04/unix/lock.c1004440004150000170000002706105337263563011455 037777777777 1 0 /* 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.9 1992/11/14 16:14:07 ian Rel $"; #endif #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif /* Lock something. If the fspooldir argument is TRUE, the argument is a file name relative to the spool directory; otherwise the argument is a simple file name which should be created in the system lock directory (under HDB this is /etc/locks). */ boolean fsdo_lock (zlock, fspooldir, pferr) const char *zlock; boolean fspooldir; boolean *pferr; { char *zfree; const char *zpath, *zslash; size_t cslash; pid_t ime; char *ztempfile; char abtempfile[sizeof "TMP1234567890"]; int o; #if HAVE_V2_LOCKFILES int i; #else char ab[12]; #endif int cwrote; const char *zerr; boolean fret; if (pferr != NULL) *pferr = TRUE; if (fspooldir) { zfree = NULL; zpath = zlock; } else { zfree = zsysdep_in_dir (zSlockdir, zlock); zpath = zfree; } ime = getpid (); /* We do the actual lock by creating a file and then linking it to the final file name we want. This avoids race conditions due to one process checking the file before we have finished writing it, and also works even if we are somehow running as root. First, create the file in the right directory (we must create the file in the same directory since otherwise we might attempt a cross-device link). */ zslash = strrchr (zpath, '/'); if (zslash == NULL) cslash = 0; else cslash = zslash - zpath + 1; sprintf (abtempfile, "TMP%010lx", (unsigned long) ime); ztempfile = zbufalc (cslash + sizeof abtempfile); memcpy (ztempfile, zpath, cslash); memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile); o = creat (ztempfile, IPUBLIC_FILE_MODE); if (o < 0) { if (errno == ENOENT) { if (! fsysdep_make_dirs (ztempfile, FALSE)) { ubuffree (zfree); ubuffree (ztempfile); return FALSE; } o = creat (ztempfile, IPUBLIC_FILE_MODE); } if (o < 0) { ulog (LOG_ERROR, "creat (%s): %s", ztempfile, strerror (errno)); ubuffree (zfree); ubuffree (ztempfile); return FALSE; } } #if HAVE_V2_LOCKFILES i = ime; cwrote = write (o, &i, sizeof i); #else sprintf (ab, "%10d\n", (int) ime); cwrote = write (o, ab, strlen (ab)); #endif zerr = NULL; if (cwrote < 0) zerr = "write"; if (close (o) < 0) zerr = "close"; if (zerr != NULL) { ulog (LOG_ERROR, "%s (%s): %s", zerr, ztempfile, strerror (errno)); (void) remove (ztempfile); ubuffree (zfree); ubuffree (ztempfile); return FALSE; } /* Now try to link the file we just created to the lock file that we want. If it fails, try reading the existing file to make sure the process that created it still exists. We do this in a loop to make it easy to retry if the old locking process no longer exists. */ fret = TRUE; if (pferr != NULL) *pferr = FALSE; o = -1; zerr = NULL; while (link (ztempfile, zpath) != 0) { int cgot; int ipid; boolean freadonly; fret = FALSE; if (errno != EEXIST) { ulog (LOG_ERROR, "link (%s, %s): %s", ztempfile, zpath, strerror (errno)); if (pferr != NULL) *pferr = TRUE; break; } freadonly = FALSE; o = open ((char *) zpath, O_RDWR | O_NOCTTY, 0); if (o < 0) { if (errno == EACCES) { freadonly = TRUE; o = open ((char *) zpath, O_RDONLY, 0); } if (o < 0) { if (errno == ENOENT) { /* The file was presumably removed between the link and the open. Try the link again. */ fret = TRUE; continue; } zerr = "open"; break; } } /* The race starts here. See below for a discussion. */ #if HAVE_V2_LOCKFILES cgot = read (o, &i, sizeof i); #else cgot = read (o, ab, sizeof ab - 1); #endif if (cgot < 0) { zerr = "read"; break; } #if HAVE_V2_LOCKFILES ipid = i; #else ab[cgot] = '\0'; ipid = strtol (ab, (char **) NULL, 10); #endif /* On NFS, the link might have actually succeeded even though we got a failure return. This can happen if the original acknowledgement was lost or delayed and the operation was retried. In this case the pid will be our own. This introduces a rather improbable race condition: if a stale lock was left with our process ID in it, and another process just did the kill, below, but has not yet changed the lock file to hold its own process ID, we could start up and make it all the way to here and think we have the lock. I'm not going to worry about this possibility. */ if (ipid == ime) { fret = TRUE; break; } /* If the process still exists, we will get EPERM rather than ESRCH. We then return FALSE to indicate that we cannot make the lock. */ if (kill (ipid, 0) == 0 || errno == EPERM) break; ulog (LOG_ERROR, "Found stale lock %s held by process %d", zpath, ipid); /* This is a stale lock, created by a process that no longer exists. Now we could remove the file (and, if the file mode disallows writing, that's what we have to do), but we try to avoid doing so since it causes a race condition. If we remove the file, and are interrupted any time after we do the read until we do the remove, another process could get in, open the file, find that it was a stale lock, remove the file and create a new one. When we regained control we would remove the file the other process just created. These files are being generated partially for the benefit of cu, and it would be nice to avoid the race however cu avoids it, so that the programs remain compatible. Unfortunately, nobody seems to know how cu avoids the race, or even if it tries to avoid it at all. There are a few ways to avoid the race. We could use kernel locking primitives, but they may not be available. We could link to a special file name, but if that file were left lying around then no stale lock could ever be broken (Henry Spencer would think this was a good thing). Instead I've implemented the following procedure: seek to the start of the file, write our pid into it, sleep for five seconds, and then make sure our pid is still there. Anybody who checks the file while we're asleep will find our pid there and fail the lock. The only race will come from another process which has done the read by the time we do our write. That process will then have five seconds to do its own write. When we wake up, we'll notice that our pid is no longer in the file, and retry the lock from the beginning. This relies on the atomicity of write(2). If it possible for the writes of two processes to be interleaved, the two processes could livelock. POSIX unfortunately leaves this case explicitly undefined; however, given that the write is of less than a disk block, it's difficult to imagine an interleave occurring. Note that this is still a race. If it takes the second process more than five seconds to do the kill, the lseek, and the write, both processes will think they have the lock. Perhaps the length of time to sleep should be configurable. Even better, perhaps I should add a configuration option to use a permanent lock file, which eliminates any race and forces the installer to be aware of the existence of the permanent lock file. We stat the file after the sleep, to make sure some other program hasn't deleted it for us. */ if (freadonly) { (void) close (o); o = -1; (void) remove (zpath); continue; } if (lseek (o, (off_t) 0, SEEK_SET) != 0) { zerr = "lseek"; break; } #if HAVE_V2_LOCKFILES i = ime; cwrote = write (o, &i, sizeof i); #else sprintf (ab, "%10d\n", (int) ime); cwrote = write (o, ab, strlen (ab)); #endif if (cwrote < 0) { zerr = "write"; break; } (void) sleep (5); if (lseek (o, (off_t) 0, SEEK_SET) != 0) { zerr = "lseek"; break; } #if HAVE_V2_LOCKFILES cgot = read (o, &i, sizeof i); #else cgot = read (o, ab, sizeof ab - 1); #endif if (cgot < 0) { zerr = "read"; break; } #if HAVE_V2_LOCKFILES ipid = i; #else ab[cgot] = '\0'; ipid = strtol (ab, (char **) NULL, 10); #endif if (ipid == ime) { struct stat sfile, sdescriptor; /* It looks like we have the lock. Do the final stat check. */ if (stat ((char *) zpath, &sfile) < 0) { if (errno != ENOENT) { zerr = "stat"; break; } /* Loop around and try again. */ } else { if (fstat (o, &sdescriptor) < 0) { zerr = "fstat"; break; } if (sfile.st_ino == sdescriptor.st_ino && sfile.st_dev == sdescriptor.st_dev) { /* Close the file before assuming we've succeeded to pick up any trailing errors. */ if (close (o) < 0) { zerr = "close"; break; } o = -1; /* We have the lock. */ fret = TRUE; break; } } } /* Loop around and try the lock again. We keep doing this until the lock file holds a pid that exists. */ (void) close (o); o = -1; fret = TRUE; } if (zerr != NULL) { ulog (LOG_ERROR, "%s (%s): %s", zerr, zpath, strerror (errno)); if (pferr != NULL) *pferr = TRUE; } if (o >= 0) (void) close (o); ubuffree (zfree); /* It would be nice if we could leave the temporary file around for future calls, but considering that we create lock files in various different directories it's probably more trouble than it's worth. */ if (remove (ztempfile) != 0) ulog (LOG_ERROR, "remove (%s): %s", ztempfile, strerror (errno)); ubuffree (ztempfile); return fret; } /* Unlock something. The fspooldir argument is as in fsdo_lock. */ boolean fsdo_unlock (zlock, fspooldir) const char *zlock; boolean fspooldir; { char *zfree; const char *zpath; if (fspooldir) { zfree = NULL; zpath = zlock; } else { zfree = zsysdep_in_dir (zSlockdir, zlock); zpath = zfree; } if (remove (zpath) == 0 || errno == ENOENT) { ubuffree (zfree); return TRUE; } else { ulog (LOG_ERROR, "remove (%s): %s", zpath, strerror (errno)); ubuffree (zfree); return FALSE; } } 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 chauucp-1.04/unix/loctim.c1004440004150000170000000054305337263564012011 037777777777 1 0 /* loctim.c Turn a time epoch into a struct tm. This is trivial on Unix. */ #include "uucp.h" #if HAVE_TIME_H #include #endif #include "system.h" #ifndef localtime extern struct tm *localtime (); #endif void usysdep_localtime (itime, q) long itime; struct tm *q; { time_t i; i = (time_t) itime; *q = *localtime (&i); } = zbufalc (cslash + sizeof abtempfile); memcpy (ztempfile, zpath, cslash); memcpy (ztempfile + cslash, abtempfile, sizeof abtempfile); o = creat (ztemuucp-1.04/unix/mail.c1004440004150000170000000374505337263564011453 037777777777 1 0 /* mail.c Send mail to a user. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_TIME_H #include #endif #ifndef ctime extern char *ctime (); #endif /* Mail a message to a user. */ boolean fsysdep_mail (zto, zsubject, cstrs, paz) const char *zto; const char *zsubject; int cstrs; const char **paz; { const char *az[3]; FILE *e; pid_t ipid; time_t itime; int i; az[0] = MAIL_PROGRAM; az[1] = zto; az[2] = NULL; e = espopen (az, FALSE, &ipid); if (e == NULL) { ulog (LOG_ERROR, "espopen (%s): %s", MAIL_PROGRAM, strerror (errno)); return FALSE; } fprintf (e, "Subject: %s\n", zsubject); fprintf (e, "To: %s\n", zto); fprintf (e, "\n"); (void) time (&itime); /* Remember that ctime includes a \n, so this skips a line. */ fprintf (e, "Message from UUCP on %s %s\n", zSlocalname, ctime (&itime)); for (i = 0; i < cstrs; i++) fputs (paz[i], e); (void) fclose (e); return ixswait ((unsigned long) ipid, MAIL_PROGRAM) == 0; } ion was retried. In thisuucp-1.04/unix/mkdir.c1004440004150000170000000235705337263564011635 037777777777 1 0 /* mkdir.c Create a directory. We must go through a subsidiary program to force our real uid to be the uucp owner before invoking the setuid /bin/mkdir program. */ #include "uucp.h" #include "sysdep.h" #include int mkdir (zdir, imode) const char *zdir; int imode; { struct stat s; const char *azargs[3]; int aidescs[3]; pid_t ipid; /* Make sure the directory does not exist, since we will otherwise get the wrong errno value. */ if (stat (zdir, &s) == 0) { errno = EEXIST; return -1; } /* /bin/mkdir will create the directory with mode 777, so we set our umask to get the mode we want. */ (void) umask ((~ imode) & (S_IRWXU | S_IRWXG | S_IRWXO)); azargs[0] = UUDIR_PROGRAM; azargs[1] = zdir; azargs[2] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ipid = ixsspawn (azargs, aidescs, FALSE, FALSE, (const char *) NULL, TRUE, FALSE, (const char *) NULL, (const char *) NULL, (const char *) NULL); (void) umask (0); if (ipid < 0) return -1; if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) { /* Make up an errno value. */ errno = EACCES; return -1; } return 0; } ale 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 wuucp-1.04/unix/mkdirs.c1004440004150000170000000137505337263564012017 037777777777 1 0 /* mkdirs.c Create any directories needed for a file name. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include boolean fsysdep_make_dirs (zfile, fpublic) const char *zfile; boolean fpublic; { char *zcopy, *z; int imode; zcopy = zbufcpy (zfile); if (fpublic) imode = IPUBLIC_DIRECTORY_MODE; else imode = IDIRECTORY_MODE; for (z = zcopy; *z != '\0'; z++) { if (*z == '/' && z != zcopy) { *z = '\0'; if (! fsysdep_directory (zcopy)) { if (mkdir (zcopy, imode) != 0) { ulog (LOG_ERROR, "mkdir (%s): %s", zcopy, strerror (errno)); ubuffree (zcopy); return FALSE; } } *z = '/'; } } ubuffree (zcopy); return TRUE; } (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)uucp-1.04/unix/mode.c1004440004150000170000000107705337263565011452 037777777777 1 0 /* mode.c Get the Unix file mode of a file. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include unsigned int ixsysdep_file_mode (zfile) const char *zfile; { struct stat s; if (stat ((char *) zfile, &s) != 0) { ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); return 0; } #if S_IRWXU != 0700 #error Files modes need to be translated #endif /* We can't return 0, since that indicate an error. */ if ((s.st_mode & 0777) == 0) return 0400; return s.st_mode & 0777; } 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)uucp-1.04/unix/move.c1004440004150000170000001071405337263565011472 037777777777 1 0 /* move.c Move a file. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif /* Move (rename) a file from one name to another. This routine will optionally create necessary directories, and fpublic indicates whether the new directories should be publically accessible or not. If fcheck is true, it will try to determine whether the named user has write access to the new file. */ boolean fsysdep_move_file (zorig, zto, fmkdirs, fpublic, fcheck, zuser) const char *zorig; const char *zto; boolean fmkdirs; boolean fpublic; boolean fcheck; const char *zuser; { struct stat s; int o; DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, "fsysdep_move_file: Moving %s to %s", zorig, zto); /* Optionally make sure that zuser has write access on the directory. */ if (fcheck) { char *zcopy; char *zslash; zcopy = zbufcpy (zto); zslash = strrchr (zcopy, '/'); if (zslash == zcopy) zslash[1] = '\0'; else *zslash = '\0'; if (stat (zcopy, &s) != 0) { ulog (LOG_ERROR, "stat (%s): %s", zcopy, strerror (errno)); (void) remove (zorig); ubuffree (zcopy); return FALSE; } if (! fsuser_access (&s, W_OK, zuser)) { ulog (LOG_ERROR, "%s: %s", zcopy, strerror (EACCES)); (void) remove (zorig); ubuffree (zcopy); return FALSE; } ubuffree (zcopy); /* A malicious user now has a few milliseconds to change a symbolic link to a directory uucp has write permission on but the user does not (the obvious choice being /usr/lib/uucp). The only certain method I can come up with to close this race is to fork an suid process which takes on the users identity and does the actual copy. This is sufficiently high overhead that I'm not going to do it. */ } /* We try to use rename to move the file. */ if (rename (zorig, zto) == 0) return TRUE; if (fmkdirs && errno == ENOENT) { if (! fsysdep_make_dirs (zto, fpublic)) { (void) remove (zorig); return FALSE; } if (rename (zorig, zto) == 0) return TRUE; } #if HAVE_RENAME /* On some systems the system call rename seems to fail for arbitrary reasons. To get around this, we always try to copy the file by hand if the rename failed. */ errno = EXDEV; #endif /* If we can't link across devices, we must copy the file by hand. */ if (errno != EXDEV) { ulog (LOG_ERROR, "rename (%s, %s): %s", zorig, zto, strerror (errno)); (void) remove (zorig); return FALSE; } /* Copy the file. */ if (stat ((char *) zorig, &s) < 0) { ulog (LOG_ERROR, "stat (%s): %s", zorig, strerror (errno)); (void) remove (zorig); return FALSE; } /* Make sure the file gets the right mode by creating it before we call fcopy_file. */ (void) remove (zto); o = creat ((char *) zto, s.st_mode); if (o < 0) { if (fmkdirs && errno == ENOENT) { if (! fsysdep_make_dirs (zto, fpublic)) { (void) remove (zorig); return FALSE; } o = creat ((char *) zto, s.st_mode); } if (o < 0) { ulog (LOG_ERROR, "creat (%s): %s", zto, strerror (errno)); (void) remove (zorig); return FALSE; } } (void) close (o); if (! fcopy_file (zorig, zto, fpublic, fmkdirs)) { (void) remove (zorig); return FALSE; } if (remove (zorig) != 0) ulog (LOG_ERROR, "remove (%s): %s", zorig, strerror (errno)); return TRUE; } d, MAIL_PROGRAM) == 0; } ion was retried. In thisuucp-1.04/unix/opensr.c1004440004150000170000001333705337263565012036 037777777777 1 0 /* opensr.c Open files for sending and receiving. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "sysdep.h" #include #if HAVE_TIME_H #include #endif #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #ifndef time extern time_t time (); #endif /* Open a file to send to another system, and return the mode and the size. */ openfile_t esysdep_open_send (qsys, zfile, fcheck, zuser) const struct uuconf_system *qsys; const char *zfile; boolean fcheck; const char *zuser; { struct stat s; openfile_t e; int o; if (fsysdep_directory (zfile)) { ulog (LOG_ERROR, "%s: is a directory", zfile); return EFILECLOSED; } #if USE_STDIO e = fopen (zfile, BINREAD); if (e == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); return NULL; } o = fileno (e); #else e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0); if (e == -1) { ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno)); return -1; } o = e; #endif if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) ffileclose (e); return EFILECLOSED; } if (fstat (o, &s) == -1) { ulog (LOG_ERROR, "fstat: %s", strerror (errno)); s.st_mode = 0666; } /* We have to recheck the file permission, although we probably checked it already, because otherwise there would be a window in which somebody could change the contents of a symbolic link to point to some file which was only readable by uucp. */ if (fcheck) { if (! fsuser_access (&s, R_OK, zuser)) { ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES)); (void) ffileclose (e); return EFILECLOSED; } } return e; } /* Get a temporary file name to receive into. We use the ztemp argument to pick the file name, so that we relocate the file if the transmission is aborted. */ char * zsysdep_receive_temp (qsys, zto, ztemp) const struct uuconf_system *qsys; const char *zto; const char *ztemp; { if (ztemp != NULL && *ztemp == 'D' && strcmp (ztemp, "D.0") != 0) return zsappend3 (".Temp", qsys->uuconf_zname, ztemp); else return zstemp_file (qsys); } /* Open a temporary file to receive into. This should, perhaps, check that we have write permission on the receiving directory, but it doesn't. */ openfile_t esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart) const struct uuconf_system *qsys; const char *zto; const char *ztemp; const char *zreceive; long *pcrestart; { int o; openfile_t e; /* If we used the ztemp argument in zsysdep_receive_temp, above, then we will have a name consistent across conversations. In that case, we may have already received some portion of this file. */ o = -1; *pcrestart = -1; if (ztemp != NULL && *ztemp == 'D' && strcmp (ztemp, "D.0") != 0) { o = open ((char *) zreceive, O_WRONLY); if (o >= 0) { struct stat s; /* For safety, we insist on the file being less than 1 week old. This can still catch people, unfortunately. I don't know of any good solution to the problem of old files hanging around. If anybody has a file they want restarted, and they know about this issue, they can touch it to bring it up to date. */ if (fstat (o, &s) < 0 || s.st_mtime + 7 * 24 * 60 * 60 < time ((time_t *) NULL)) { (void) close (o); o = -1; } else { DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "esysdep_open_receive: Reusing %s", zreceive); *pcrestart = (long) s.st_size; } } } if (o < 0) o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); if (o < 0) { if (errno == ENOENT) { if (! fsysdep_make_dirs (zreceive, FALSE)) return EFILECLOSED; o = creat ((char *) zreceive, IPRIVATE_FILE_MODE); } if (o < 0) { ulog (LOG_ERROR, "creat (%s): %s", zreceive, strerror (errno)); return EFILECLOSED; } } if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) close (o); (void) remove (zreceive); return EFILECLOSED; } #if USE_STDIO e = fdopen (o, (char *) BINWRITE); if (e == NULL) { ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno)); (void) close (o); (void) remove (zreceive); return EFILECLOSED; } #else e = o; #endif return e; } o the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author 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" #incluuucp-1.04/unix/pause.c1004440004150000170000000366405337263566011650 037777777777 1 0 /* pause.c Pause for half a second. */ #include "uucp.h" #include "sysdep.h" #include "system.h" /* Pick a timing routine to use. I somewhat arbitrarily picked usleep above nap above napms above poll above select. */ #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL #undef HAVE_SELECT #define HAVE_SELECT 0 #endif #if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS #undef HAVE_POLL #define HAVE_POLL 0 #endif #if HAVE_USLEEP || HAVE_NAP #undef HAVE_NAPMS #define HAVE_NAPMS 0 #endif #if HAVE_USLEEP #undef HAVE_NAP #define HAVE_NAP 0 #endif #if HAVE_SELECT #include #if HAVE_SYS_SELECT_H #include #endif #endif #if HAVE_POLL #if HAVE_STROPTS_H #include #endif #if HAVE_POLL_H #include #endif #if ! HAVE_STROPTS_H && ! HAVE_POLL_H /* We need a definition for struct pollfd, although it doesn't matter what it contains. */ struct pollfd { int idummy; }; #endif /* ! HAVE_STROPTS_H && ! HAVE_POLL_H */ #endif /* HAVE_POLL */ #if HAVE_TIME_H #if HAVE_SYS_TIME_AND_TIME_H || ! USE_SELECT_TIMER #include #endif #endif void usysdep_pause () { #if HAVE_NAPMS napms (500); #endif /* HAVE_NAPMS */ #if HAVE_NAP #if HAVE_HUNDREDTHS_NAP nap (50L); #else nap (500L); #endif /* ! HAVE_HUNDREDTHS_NAP */ #endif /* HAVE_NAP */ #if HAVE_USLEEP usleep (500 * (long) 1000); #endif /* HAVE_USLEEP */ #if HAVE_POLL struct pollfd sdummy; /* We need to pass an unused pollfd structure because poll checks the address before checking the number of elements. */ poll (&sdummy, 0, 500); #endif /* HAVE_POLL */ #if HAVE_SELECT struct timeval s; s.tv_sec = 0; s.tv_usec = 500 * (long) 1000; select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s); #endif /* USE_SELECT_TIMER */ #if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP #if ! USE_SELECT_TIMER && ! HAVE_POLL sleep (1); #endif /* ! USE_SELECT_TIMER && ! HAVE_POLL */ #endif /* ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP */ } name (%s, %s): %s", zorig, zto, strerror (errno)); (void) remove uucp-1.04/unix/picksb.c1004440004150000170000001176305337263566012005 037777777777 1 0 /* 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.6 1992/12/17 05:32:09 ian Rel $"; #endif #include "uudefs.h" #include "system.h" #include "sysdep.h" #include #include #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ #if GETPWUID_DECLARATION_OK #ifndef getpwuid extern struct passwd *getpwuid (); #endif #endif /* Local variables. */ /* Directory of ~/receive/USER. */ static DIR *qStopdir; /* Name of ~/receive/USER. */ static char *zStopdir; /* Directory of ~/receive/USER/SYSTEM. */ static DIR *qSsysdir; /* Name of system. */ static char *zSsysdir; /* Prepare to get a list of all the file to uupick for this user. */ /*ARGSUSED*/ boolean fsysdep_uupick_init (zsystem, zpubdir) const char *zsystem; const char *zpubdir; { const char *zuser; zuser = zsysdep_login_name (); zStopdir = (char *) xmalloc (strlen (zpubdir) + sizeof "/receive/" + strlen (zuser)); sprintf (zStopdir, "%s/receive/%s", zpubdir, zuser); qStopdir = opendir (zStopdir); if (qStopdir == NULL && errno != ENOENT) { ulog (LOG_ERROR, "opendir (%s): %s", zStopdir, strerror (errno)); return FALSE; } qSsysdir = NULL; return TRUE; } /* Return the next file from the uupick directories. */ /*ARGSUSED*/ char * zsysdep_uupick (zsysarg, zpubdir, pzfrom, pzfull) const char *zsysarg; const char *zpubdir; char **pzfrom; char **pzfull; { struct dirent *qentry; while (TRUE) { while (qSsysdir == NULL) { const char *zsystem; char *zdir; if (qStopdir == NULL) return NULL; if (zsysarg != NULL) { closedir (qStopdir); qStopdir = NULL; zsystem = zsysarg; } else { do { qentry = readdir (qStopdir); if (qentry == NULL) { closedir (qStopdir); qStopdir = NULL; return NULL; } } while (strcmp (qentry->d_name, ".") == 0 || strcmp (qentry->d_name, "..") == 0); zsystem = qentry->d_name; } zdir = zbufalc (strlen (zStopdir) + strlen (zsystem) + sizeof "/"); sprintf (zdir, "%s/%s", zStopdir, zsystem); qSsysdir = opendir (zdir); if (qSsysdir == NULL) { if (errno != ENOENT && errno != ENOTDIR) ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno)); } else { ubuffree (zSsysdir); zSsysdir = zbufcpy (zsystem); } ubuffree (zdir); } qentry = readdir (qSsysdir); if (qentry == NULL) { closedir (qSsysdir); qSsysdir = NULL; continue; } if (strcmp (qentry->d_name, ".") == 0 || strcmp (qentry->d_name, "..") == 0) continue; *pzfrom = zbufcpy (zSsysdir); *pzfull = zsappend3 (zStopdir, zSsysdir, qentry->d_name); return zbufcpy (qentry->d_name); } } /*ARGSUSED*/ boolean fsysdep_uupick_free (zsystem, zpubdir) const char *zsystem; const char *zpubdir; { xfree ((pointer) zStopdir); if (qStopdir != NULL) { closedir (qStopdir); qStopdir = NULL; } ubuffree (zSsysdir); zSsysdir = NULL; if (qSsysdir != NULL) { closedir (qSsysdir); qSsysdir = NULL; } return TRUE; } /* Expand a local file name for uupick. */ char * zsysdep_uupick_local_file (zfile) const char *zfile; { struct passwd *q; /* If this does not start with a simple ~, pass it to zsysdep_local_file_cwd; as it happens, zsysdep_local_file_cwd only uses the zpubdir argument if the file starts with a simple ~, so it doesn't really matter what we pass for zpubdir. */ if (zfile[0] != '~' || (zfile[1] != '/' && zfile[1] != '\0')) return zsysdep_local_file_cwd (zfile, (const char *) NULL); q = getpwuid (getuid ()); if (q == NULL) { ulog (LOG_ERROR, "Can't get home directory"); return NULL; } if (zfile[1] == '\0') return zbufcpy (q->pw_dir); return zsysdep_in_dir (q->pw_dir, zfile + 2); } eived some pouucp-1.04/unix/portnm.c1004440004150000170000000167505337263566012052 037777777777 1 0 /* portnm.c Get the port name of stdin. */ #include "uucp.h" #include "sysdep.h" #include "system.h" #if HAVE_TCP #if HAVE_SYS_TYPES_TCP_H #include #endif #include #endif #ifndef ttyname extern char *ttyname (); #endif /* Get the port name of standard input. I assume that Unix systems generally support ttyname. If they don't, this function can just return NULL. It uses getsockname to see whether standard input is a TCP connection. */ const char * zsysdep_port_name (ftcp_port) boolean *ftcp_port; { const char *z; *ftcp_port = FALSE; #if HAVE_TCP { size_t clen; struct sockaddr s; clen = sizeof (struct sockaddr); if (getsockname (0, &s, &clen) == 0) *ftcp_port = TRUE; } #endif /* HAVE_TCP */ z = ttyname (0); if (z == NULL) return NULL; if (strncmp (z, "/dev/", sizeof "/dev/" - 1) == 0) return z + sizeof "/dev/" - 1; else return z; } FILECLOSED; } #if USE_STDIO e = fdopen (o, (char *) BINWRITEuucp-1.04/unix/proctm.c1004440004150000170000001133305337263566012027 037777777777 1 0 /* proctm.c Get the time spent in the process. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "sysdep.h" #include "system.h" #if HAVE_SYS_PARAM_H #include #endif #if HAVE_LIMITS_H #include #endif /* Prefer gettimeofday to ftime to times. */ #if HAVE_GETTIMEOFDAY || HAVE_FTIME #undef HAVE_TIMES #define HAVE_TIMES 0 #endif #if HAVE_GETTIMEOFDAY #undef HAVE_FTIME #define HAVE_FTIME 0 #endif #if HAVE_TIME_H && (HAVE_SYS_TIME_AND_TIME_H || ! HAVE_GETTIMEOFDAY) #include #endif #if HAVE_GETTIMEOFDAY #include #endif #if HAVE_FTIME #include #endif #if HAVE_TIMES #if HAVE_SYS_TIMES_H #include #endif #if TIMES_DECLARATION_OK /* We use a macro to protect this because times really returns clock_t and on some systems, such as Ultrix 4.0, clock_t is int. We don't leave it out entirely because on some systems, such as System III, the declaration is necessary for correct compilation. */ #ifndef times extern long times (); #endif #endif /* TIMES_DECLARATION_OK */ #ifdef _SC_CLK_TCK #define HAVE_SC_CLK_TCK 1 #else #define HAVE_SC_CLK_TCK 0 #endif /* TIMES_TICK may have been set in policy.h, or we may be able to get it using sysconf. If neither is the case, try to find a useful definition from the system header files. */ #if TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) #ifdef CLK_TCK #undef TIMES_TICK #define TIMES_TICK CLK_TCK #else /* ! defined (CLK_TCK) */ #ifdef HZ #undef TIMES_TICK #define TIMES_TICK HZ #endif /* defined (HZ) */ #endif /* ! defined (CLK_TCK) */ #endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */ #endif /* HAVE_TIMES */ #ifndef time extern time_t time (); #endif #if HAVE_SYSCONF #ifndef sysconf extern long sysconf (); #endif #endif /* Get the time in seconds and microseconds; this need only work within the process when called from the system independent code. It is also called by ixsysdep_time. */ long ixsysdep_process_time (pimicros) long *pimicros; { #if HAVE_GETTIMEOFDAY struct timeval stime; struct timezone stz; (void) gettimeofday (&stime, &stz); if (pimicros != NULL) *pimicros = (long) stime.tv_usec; return (long) stime.tv_sec; #endif /* HAVE_GETTIMEOFDAY */ #if HAVE_FTIME static boolean fbad; if (! fbad) { struct timeb stime; static struct timeb slast; (void) ftime (&stime); /* On some systems, such as SCO 3.2.2, ftime can go backwards in time. If we detect this, we switch to using time. */ if (slast.time != 0 && (stime.time < slast.time || (stime.time == slast.time && stime.millitm < slast.millitm))) fbad = TRUE; else { slast = stime; if (pimicros != NULL) *pimicros = (long) stime.millitm * (long) 1000; return (long) stime.time; } } if (pimicros != NULL) *pimicros = 0; return (long) time ((time_t *) NULL); #endif /* HAVE_FTIME */ #if HAVE_TIMES struct tms s; long i; static int itick; if (itick == 0) { #if TIMES_TICK == 0 #if HAVE_SYSCONF && HAVE_SC_CLK_TCK itick = (int) sysconf (_SC_CLK_TCK); #else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ const char *z; z = getenv ("HZ"); if (z != NULL) itick = (int) strtol (z, (char **) NULL, 10); /* If we really couldn't get anything, just use 60. */ if (itick == 0) itick = 60; #endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ #else /* TIMES_TICK != 0 */ itick = TIMES_TICK; #endif /* TIMES_TICK == 0 */ } i = (long) times (&s); if (pimicros != NULL) *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick); return i / (long) itick; #endif /* HAVE_TIMES */ #if ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES if (pimicros != NULL) *pimicros = 0; return (long) time ((time_t *) NULL); #endif /* ! HAVE_GETTIMEOFDAY && ! HAVE_FTIME && ! HAVE_TIMES */ } t 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 "/receivuucp-1.04/unix/recep.c1004440004150000170000001240205337263567011620 037777777777 1 0 /* recep.c See whether a file has already been received. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include #if HAVE_TIME_H #include #endif #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif static char *zsreceived_name P((const struct uuconf_system *qsys, const char *ztemp)); /* These routines are used to see whether we have already received a file in a previous UUCP connection. It is possible for the acknowledgement of a received file to be lost. The sending system will then now know that the file was correctly received, and will send it again. This can be a problem particularly with protocols which support channels, since they may send several small files in a single window, all of which may be received correctly although the sending system never sees the acknowledgement. If these files involve an execution, the execution will happen twice, which will be bad. We use a simple system. For each file we want to remember, we create an empty file names .Received/SYS/TEMP, where SYS is the name of the system and TEMP is the name of the temporary file used by the sender. If no temporary file is used by the sender, we don't remember that we received the file. This is not perfect, but execution files will always have a temporary file, so the most important case is handled. Also, any file received from Taylor UUCP 1.04 or greater will always have a temporary file. */ /* Return the name we are going use for the marker, or NULL if we have no name. */ static char * zsreceived_name (qsys, ztemp) const struct uuconf_system *qsys; const char *ztemp; { if (ztemp != NULL && *ztemp == 'D' && strcmp (ztemp, "D.0") != 0) return zsappend3 (".Received", qsys->uuconf_zname, ztemp); else return NULL; } /* Remember that we have already received a file. */ /*ARGSUSED*/ boolean fsysdep_remember_reception (qsys, zto, ztemp) const struct uuconf_system *qsys; const char *zto; const char *ztemp; { char *zfile; int o; zfile = zsreceived_name (qsys, ztemp); if (zfile == NULL) return TRUE; o = creat (zfile, IPUBLIC_FILE_MODE); if (o < 0) { if (errno == ENOENT) { if (fsysdep_make_dirs (zfile, TRUE)) { ubuffree (zfile); return FALSE; } o = creat (zfile, IPUBLIC_FILE_MODE); } if (o < 0) { ulog (LOG_ERROR, "creat (%s): %s", zfile, strerror (errno)); ubuffree (zfile); return FALSE; } } ubuffree (zfile); /* We don't have to actually put anything in the file; we just use the name. This is more convenient than keeping a file with a list of names. */ if (close (o) < 0) { ulog (LOG_ERROR, "fsysdep_remember_reception: close: %s", strerror (errno)); return FALSE; } return TRUE; } /* See if we have already received a file. Note that don't delete the marker file here, because we need to know that the sending system has received our denial first. This function returns TRUE if the file has already been received, FALSE if it has not. */ /*ARGSUSED*/ boolean fsysdep_already_received (qsys, zto, ztemp) const struct uuconf_system *qsys; const char *zto; const char *ztemp; { char *zfile; struct stat s; boolean fret; zfile = zsreceived_name (qsys, ztemp); if (zfile == NULL) return FALSE; if (stat (zfile, &s) < 0) { if (errno != ENOENT) ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); ubuffree (zfile); return FALSE; } /* Ignore the file (return FALSE) if it is over one week old. */ fret = s.st_mtime + 7 * 24 * 60 * 60 >= time ((time_t *) NULL); if (fret) DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_already_received: Found %s", zfile); ubuffree (zfile); return fret; } /* Forget that we have received a file. */ /*ARGSUSED*/ boolean fsysdep_forget_reception (qsys, zto, ztemp) const struct uuconf_system *qsys; const char *zto; const char *ztemp; { char *zfile; zfile = zsreceived_name (qsys, ztemp); if (zfile == NULL) return TRUE; if (remove (zfile) < 0 && errno != ENOENT) { ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); ubuffree (zfile); return FALSE; } return TRUE; } re Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author 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" #includeuucp-1.04/unix/remove.c1004440004150000170000000024605337263567012022 037777777777 1 0 /* remove.c Remove a file (Unix specific implementation). */ #include "uucp.h" #include "sysdep.h" int remove (z) const char *z; { return unlink (z); } ome 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 #uucp-1.04/unix/rename.c1004440004150000170000000076505337263567012002 037777777777 1 0 /* rename.c Rename a file to a new name (Unix specific implementation). */ #include "uucp.h" #include "sysdep.h" #include /* This implementation will not work on directories, but fortunately we never want to rename directories. */ int rename (zfrom, zto) const char *zfrom; const char *zto; { if (link (zfrom, zto) < 0) { if (errno != EEXIST) return -1; if (unlink (zto) < 0 || link (zfrom, zto) < 0) return -1; } return unlink (zfrom); } if (pimicrouucp-1.04/unix/rmdir.c1004440004150000170000000161405337263571011635 037777777777 1 0 /* rmdir.c Remove a directory on a system which doesn't have the rmdir system call. This is only called by uupick, which is not setuid, so we don't have to worry about the problems of invoking the setuid /bin/rmdir program. */ #include "uucp.h" #include "sysdep.h" #include int rmdir (zdir) const char *zdir; { const char *azargs[3]; int aidescs[3]; pid_t ipid; azargs[0] = RMDIR_PROGRAM; azargs[1] = zdir; azargs[2] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, TRUE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) return -1; if (ixswait ((unsigned long) ipid, (const char *) NULL) != 0) { /* Make up an errno value. */ errno = EBUSY; return -1; } return 0; } NULL) *pimicros = (i % (long) itick) * ((long) 1000000 / (long) itick); return i / (long) itick; #endif /* HAVuucp-1.04/unix/run.c1004440004150000170000000421405337263571011323 037777777777 1 0 /* run.c Run a program. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* Start up a new program and end the current one. We don't have to worry about SIGHUP because the current process is either not a process group leader (uucp, uux) or it does not have a controlling terminal (uucico). */ boolean fsysdep_run (zprogram, zarg1, zarg2) const char *zprogram; const char *zarg1; const char *zarg2; { char *zlib; const char *azargs[4]; int aidescs[3]; pid_t ipid; zlib = zbufalc (sizeof SBINDIR + sizeof "/" + strlen (zprogram)); sprintf (zlib, "%s/%s", SBINDIR, zprogram); azargs[0] = zlib; azargs[1] = zarg1; azargs[2] = zarg2; azargs[3] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; /* We pass fsetuid and fshell as TRUE, which permits uucico and uuxqt to be replaced by (non-setuid) shell scripts. */ ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); ubuffree (zlib); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); return FALSE; } return TRUE; } ocols 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 auucp-1.04/unix/seq.c1004440004150000170000000606305337263572011314 037777777777 1 0 /* seq.c Get and increment the conversation sequence number for a system. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include /* Get the current conversation sequence number for a remote system, and increment it for next time. The conversation sequence number is kept in a file named for the system in the directory .Sequence in the spool directory. This is not compatible with other versions of UUCP, but it makes more sense to me. The sequence file is only used if specified in the information for that system. */ long ixsysdep_get_sequence (qsys) const struct uuconf_system *qsys; { FILE *e; char *zname; struct stat s; long iseq; /* This will only be called when the system is locked anyhow, so there is no need to use a separate lock for the conversation sequence file. */ zname = zsysdep_in_dir (".Sequence", qsys->uuconf_zname); iseq = 0; if (stat (zname, &s) == 0) { boolean fok; char *zline; size_t cline; /* The file should only be readable and writable by uucp. */ if ((s.st_mode & (S_IRWXG | S_IRWXO)) != 0) { ulog (LOG_ERROR, "Bad file protection for conversation sequence file"); ubuffree (zname); return -1; } e = fopen (zname, "r+"); if (e == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); ubuffree (zname); return -1; } ubuffree (zname); fok = TRUE; zline = NULL; cline = 0; if (getline (&zline, &cline, e) <= 0) fok = FALSE; else { char *zend; iseq = strtol (zline, &zend, 10); if (zend == zline) fok = FALSE; } xfree ((pointer) zline); if (! fok) { ulog (LOG_ERROR, "Bad format for conversation sequence file"); (void) fclose (e); return -1; } rewind (e); } else { e = esysdep_fopen (zname, FALSE, FALSE, TRUE); ubuffree (zname); if (e == NULL) return -1; } ++iseq; fprintf (e, "%ld", iseq); if (fclose (e) != 0) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); return -1; } return iseq; } 1004440004150000170000000024605337263567012022 037777777777 1 0 uucp-1.04/unix/serial.c1004440004150000170000021220705337263572012002 037777777777 1 0 /* 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.26 1993/01/07 02:31:53 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "conn.h" #include "sysdep.h" #include #include #if HAVE_SYS_PARAM_H #include #endif #if HAVE_LIMITS_H #include #endif #if HAVE_TLI #if HAVE_TIUSER_H #include #else /* ! HAVE_TIUSER_H */ #if HAVE_XTI_H #include #endif /* HAVE_XTI_H */ #endif /* ! HAVE_TIUSER_H */ #endif /* HAVE_TLI */ #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_BSD_TTY #include #if HAVE_SYS_SELECT_H #include #endif #endif #if HAVE_TIME_H #if HAVE_SYS_TIME_AND_TIME_H || ! HAVE_BSD_TTY #include #endif #endif #if HAVE_STRIP_BUG && HAVE_BSD_TTY #include #endif #if HAVE_SVR4_LOCKFILES /* Get the right definitions for major and minor. */ #if MAJOR_IN_MKDEV #include #endif /* MAJOR_IN_MKDEV */ #if MAJOR_IN_SYSMACROS #include #endif /* MAJOR_IN_SYSMACROS */ #if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS #ifndef major #define major(i) (((i) >> 8) & 0xff) #endif #ifndef minor #define minor(i) ((i) & 0xff) #endif #endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */ #endif /* HAVE_SVR4_LOCKFILES */ /* Get definitions for both O_NONBLOCK and O_NDELAY. */ #ifndef O_NDELAY #ifdef FNDELAY #define O_NDELAY FNDELAY #else /* ! defined (FNDELAY) */ #define O_NDELAY 0 #endif /* ! defined (FNDELAY) */ #endif /* ! defined (O_NDELAY) */ #ifndef O_NONBLOCK #ifdef FNBLOCK #define O_NONBLOCK FNBLOCK #else /* ! defined (FNBLOCK) */ #define O_NONBLOCK 0 #endif /* ! defined (FNBLOCK) */ #endif /* ! defined (O_NONBLOCK) */ #if O_NDELAY == 0 && O_NONBLOCK == 0 #error No way to do nonblocking I/O #endif /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ #ifndef EAGAIN #ifndef EWOULDBLOCK #define EAGAIN (-1) #define EWOULDBLOCK (-1) #else /* defined (EWOULDBLOCK) */ #define EAGAIN EWOULDBLOCK #endif /* defined (EWOULDBLOCK) */ #else /* defined (EAGAIN) */ #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif /* ! defined (EWOULDBLOCK) */ #endif /* defined (EAGAIN) */ #ifndef ENODATA #define ENODATA EAGAIN #endif /* Make sure we have a definition for MAX_INPUT. */ #ifndef MAX_INPUT #define MAX_INPUT (256) #endif /* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal. Otherwise, if we have the TIOCEXCL ioctl call, we have to open the terminal before we know that it is unlocked. */ #ifdef TIOCSINUSE #define HAVE_TIOCSINUSE 1 #else #ifdef TIOCEXCL #define HAVE_TIOCEXCL 1 #endif #endif #if HAVE_TLI extern int t_errno; extern char *t_errlist[]; extern int t_nerr; #endif /* Determine bits to clear for the various terminal control fields for HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS. */ #if HAVE_SYSV_TERMIO #define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \ | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \ | IXON | IXANY | IXOFF) #define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \ | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \ | VTDLY | FFDLY) #define ICLEAR_CFLAG (CBAUD | CLOCAL | CSIZE | PARENB | PARODD) #define ISET_CFLAG (CS8 | CREAD | HUPCL) #define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \ | ECHONL | NOFLSH) #endif #if HAVE_POSIX_TERMIOS #define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \ | INLCR | INPCK | ISTRIP | IXOFF | IXON \ | PARMRK) #define ICLEAR_OFLAG (OPOST) #define ICLEAR_CFLAG (CLOCAL | CSIZE | PARENB | PARODD) #define ISET_CFLAG (CS8 | CREAD | HUPCL) #define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \ | ISIG | NOFLSH | TOSTOP) #endif /* Local functions. */ static RETSIGTYPE usalarm P((int isig)); static boolean fsserial_init P((struct sconnection *qconn, const struct sconncmds *qcmds, const char *zdevice)); static void usserial_free P((struct sconnection *qconn)); static boolean fsserial_lockfile P((boolean flok, const struct sconnection *)); static boolean fsserial_lock P((struct sconnection *qconn, boolean fin)); static boolean fsserial_unlock P((struct sconnection *qconn)); static boolean fsserial_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean fsstdin_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean fsmodem_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean fsdirect_open P((struct sconnection *qconn, long ibaud, boolean fwait)); static boolean fsblock P((struct ssysdep_conn *q, boolean fblock)); static boolean fsserial_close P((struct ssysdep_conn *q)); static boolean fsstdin_close P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, boolean fsuccess)); static boolean fsmodem_close P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, boolean fsuccess)); static boolean fsdirect_close P((struct sconnection *qconn, pointer puuconf, struct uuconf_dialer *qdialer, boolean fsuccess)); static boolean fsserial_reset P((struct sconnection *qconn)); static boolean fsstdin_reset P((struct sconnection *qconn)); static boolean fsstdin_read P((struct sconnection *qconn, char *zbuf, size_t *pclen, size_t cmin, int ctimeout, boolean freport)); static boolean fsstdin_write P((struct sconnection *qconn, const char *zwrite, size_t cwrite)); static boolean fsserial_break P((struct sconnection *qconn)); static boolean fsstdin_break P((struct sconnection *qconn)); static boolean fsserial_set P((struct sconnection *qconn, enum tparitysetting tparity, enum tstripsetting tstrip, enum txonxoffsetting txonxoff)); static boolean fsstdin_set P((struct sconnection *qconn, enum tparitysetting tparity, enum tstripsetting tstrip, enum txonxoffsetting txonxoff)); static boolean fsmodem_carrier P((struct sconnection *qconn, boolean fcarrier)); static boolean fsrun_chat P((int oread, int owrite, char **pzprog)); static boolean fsstdin_chat P((struct sconnection *qconn, char **pzprog)); static long isserial_baud P((struct sconnection *qconn)); /* The command table for standard input ports. */ static const struct sconncmds sstdincmds = { usserial_free, NULL, /* pflock */ NULL, /* pfunlock */ fsstdin_open, fsstdin_close, fsstdin_reset, NULL, /* pfdial */ fsstdin_read, fsstdin_write, fsysdep_conn_io, fsstdin_break, fsstdin_set, NULL, /* pfcarrier */ fsstdin_chat, isserial_baud }; /* The command table for modem ports. */ static const struct sconncmds smodemcmds = { usserial_free, fsserial_lock, fsserial_unlock, fsmodem_open, fsmodem_close, fsserial_reset, fmodem_dial, fsysdep_conn_read, fsysdep_conn_write, fsysdep_conn_io, fsserial_break, fsserial_set, fsmodem_carrier, fsysdep_conn_chat, isserial_baud }; /* The command table for direct ports. */ static const struct sconncmds sdirectcmds = { usserial_free, fsserial_lock, fsserial_unlock, fsdirect_open, fsdirect_close, fsserial_reset, NULL, /* pfdial */ fsysdep_conn_read, fsysdep_conn_write, fsysdep_conn_io, fsserial_break, fsserial_set, NULL, /* pfcarrier */ fsysdep_conn_chat, isserial_baud }; /* If the system will let us set both O_NDELAY and O_NONBLOCK, we do so. This is because some ancient drivers on some systems appear to look for one but not the other. Some other systems will give an EINVAL error if we attempt to set both, so we use a static global to hold the value we want to set. If we get EINVAL, we change the global and try again (if some system gives an error other than EINVAL, the code will have to be modified). */ static int iSunblock = O_NDELAY | O_NONBLOCK; /* This code handles SIGALRM. See the discussion above fsysdep_conn_read. Normally we ignore SIGALRM, but the handler will temporarily be set to this function, which should set fSalarm and then either longjmp or schedule another SIGALRM. fSalarm is never referred to outside of this file, but we don't make it static to try to fool compilers which don't understand volatile. */ volatile sig_atomic_t fSalarm; static RETSIGTYPE usalarm (isig) int isig; { #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET (void) signal (isig, usalarm); #endif fSalarm = TRUE; #if HAVE_RESTARTABLE_SYSCALLS longjmp (sSjmp_buf, 1); #else alarm (1); #endif } /* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and SIGPIPE and another to restore the original state. When these functions are called (in fsysdep_modem_close) SIGHUP is being ignored. The routines are isblocksigs, which returns a value of type HELD_SIG_MASK and usunblocksigs which takes a single argument of type HELD_SIG_MASK. */ #if HAVE_SIGPROCMASK /* Use the POSIX sigprocmask call. */ #define HELD_SIG_MASK sigset_t static sigset_t isblocksigs P((void)); static sigset_t isblocksigs () { sigset_t sblock, sold; /* These expressions need an extra set of parentheses to avoid a bug in SCO 3.2.2. */ (void) (sigemptyset (&sblock)); (void) (sigaddset (&sblock, SIGINT)); (void) (sigaddset (&sblock, SIGQUIT)); (void) (sigaddset (&sblock, SIGTERM)); (void) (sigaddset (&sblock, SIGPIPE)); (void) sigprocmask (SIG_BLOCK, &sblock, &sold); return sold; } #define usunblocksigs(s) \ ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL)) #else /* ! HAVE_SIGPROCMASK */ #if HAVE_SIGBLOCK /* Use the BSD sigblock and sigsetmask calls. */ #define HELD_SIG_MASK int #ifndef sigmask #define sigmask(i) (1 << ((i) - 1)) #endif #define isblocksigs() \ sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \ | sigmask (SIGTERM) | sigmask (SIGPIPE)) #define usunblocksigs(i) ((void) sigsetmask (i)) #else /* ! HAVE_SIGBLOCK */ #if HAVE_SIGHOLD /* Use the SVR3 sighold and sigrelse calls. */ #define HELD_SIG_MASK int static int isblocksigs P((void)); static int isblocksigs () { sighold (SIGINT); sighold (SIGQUIT); sighold (SIGTERM); sighold (SIGPIPE); return 0; } static void usunblocksigs P((int)); /*ARGSUSED*/ static void usunblocksigs (i) int i; { sigrelse (SIGINT); sigrelse (SIGQUIT); sigrelse (SIGTERM); sigrelse (SIGPIPE); } #else /* ! HAVE_SIGHOLD */ /* We have no way to block signals. This system will suffer from a race condition in fsysdep_modem_close. */ #define HELD_SIG_MASK int #define isblocksigs() 0 #define usunblocksigs(i) #endif /* ! HAVE_SIGHOLD */ #endif /* ! HAVE_SIGBLOCK */ #endif /* ! HAVE_SIGPROCMASK */ /* Initialize a connection for use on a serial port. */ static boolean fsserial_init (qconn, qcmds, zdevice) struct sconnection *qconn; const struct sconncmds *qcmds; const char *zdevice; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); if (zdevice == NULL && qconn->qport != NULL && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) zdevice = qconn->qport->uuconf_zname; if (zdevice == NULL) q->zdevice = NULL; else if (*zdevice == '/') q->zdevice = zbufcpy (zdevice); else { size_t clen; clen = strlen (zdevice); q->zdevice = zbufalc (sizeof "/dev/" + clen); memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1); memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen); q->zdevice[sizeof "/dev/" + clen - 1] = '\0'; } q->o = -1; q->ftli = FALSE; qconn->psysdep = (pointer) q; qconn->qcmds = qcmds; return TRUE; } /* Initialize a connection for use on standard input. */ boolean fsysdep_stdin_init (qconn) struct sconnection *qconn; { return fsserial_init (qconn, &sstdincmds, (const char *) NULL); } /* Initialize a connection for use on a modem port. */ boolean fsysdep_modem_init (qconn) struct sconnection *qconn; { return fsserial_init (qconn, &smodemcmds, qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice); } /* Initialize a connection for use on a direct port. */ boolean fsysdep_direct_init (qconn) struct sconnection *qconn; { return fsserial_init (qconn, &sdirectcmds, qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice); } /* Free up a serial port. */ static void usserial_free (qconn) struct sconnection *qconn; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; ubuffree (qsysdep->zdevice); xfree ((pointer) qsysdep); qconn->psysdep = NULL; } /* This routine is used for both locking and unlocking. It is the only routine which knows how to translate a device name into the name of a lock file. If it can't figure out a name, it does nothing and returns TRUE. */ static boolean fsserial_lockfile (flok, qconn) boolean flok; const struct sconnection *qconn; { struct ssysdep_conn *qsysdep; const char *z; char *zalc; boolean fret; qsysdep = (struct ssysdep_conn *) qconn->psysdep; if (qconn->qport == NULL) z = NULL; else z = qconn->qport->uuconf_zlockname; zalc = NULL; if (z == NULL) { #if ! HAVE_SVR4_LOCKFILES { const char *zbase; size_t clen; zbase = strrchr (qsysdep->zdevice, '/') + 1; clen = strlen (zbase); zalc = zbufalc (sizeof "LCK.." + clen); memcpy (zalc, "LCK..", sizeof "LCK.." - 1); memcpy (zalc + sizeof "LCK.." - 1, zbase, clen + 1); #if HAVE_SCO_LOCKFILES { char *zl; for (zl = zalc + sizeof "LCK.." - 1; *zl != '\0'; zl++) if (isupper (*zl)) *zl = tolower (*zl); } #endif z = zalc; } #else /* ! HAVE_SVR4_LOCKFILES */ #if HAVE_SVR4_LOCKFILES { struct stat s; if (stat (qsysdep->zdevice, &s) != 0) { ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice, strerror (errno)); return FALSE; } zalc = zbufalc (sizeof "LK.123.123.123"); sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev), major (s.st_rdev), minor (s.st_rdev)); z = zalc; } #else /* ! HAVE_SVR4_LOCKFILES */ z = strrchr (qsysdep->zdevice, '/') + 1; #endif /* ! HAVE_SVR4_LOCKFILES */ #endif /* ! HAVE_SVR4_LOCKFILES */ } if (flok) fret = fsdo_lock (z, FALSE, (boolean *) NULL); else fret = fsdo_unlock (z, FALSE); #if HAVE_COHERENT_LOCKFILES if (fret) { if (flok) { if (lockttyexist (z)) { ulog (LOG_NORMAL, "%s: port already locked"); fret = FALSE; } else fret = fscoherent_disable_tty (z, &qsysdep->zenable); } else { fret = TRUE; if (qsysdep->zenable != NULL) { const char *azargs[3]; int aidescs[3]; pid_t ipid; azargs[0] = "/etc/enable"; azargs[1] = qsysdep->zenable; azargs[2] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ipid = ixsspawn (azargs, aidescs, TRUE, FALSE, (const char *) NULL, TRUE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s", qsysdep->zenable, strerror (errno)); fret = FALSE; } else { if (ixswait ((unsigned long) ipid, (const char *) NULL) == 0) fret = TRUE; else fret = FALSE; } ubuffree (qsysdep->zenable); qsysdep->zenable = NULL; } } } #endif /* HAVE_COHERENT_LOCKFILES */ ubuffree (zalc); return fret; } /* If we can mark a modem line in use, then when we lock a port we must open it and mark it in use. We can't wait until the actual open because we can't fail out if it is locked then. */ static boolean fsserial_lock (qconn, fin) struct sconnection *qconn; boolean fin; { if (! fsserial_lockfile (TRUE, qconn)) return FALSE; #if HAVE_TIOCSINUSE || HAVE_TIOCEXCL /* Open the line and try to mark it in use. */ { struct ssysdep_conn *qsysdep; int iflag; qsysdep = (struct ssysdep_conn *) qconn->psysdep; if (fin) iflag = 0; else iflag = iSunblock; qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag); if (qsysdep->o < 0) { #if O_NONBLOCK != 0 if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL) { iSunblock = O_NONBLOCK; qsysdep->o = open (qsysdep->zdevice, O_RDWR | O_NONBLOCK); } #endif if (qsysdep->o < 0) { if (errno != EBUSY) ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice, strerror (errno)); (void) fsserial_lockfile (FALSE, qconn); return FALSE; } } #if HAVE_TIOCSINUSE /* If we can't mark it in use, return FALSE to indicate that the lock failed. */ if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0) { if (errno != EALREADY) ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno)); #ifdef TIOCNOTTY (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); #endif (void) close (qsysdep->o); qsysdep->o = -1; (void) fsserial_lockfile (FALSE, qconn); return FALSE; } #endif if (fcntl (qsysdep->o, F_SETFD, fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); #ifdef TIOCNOTTY (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); #endif (void) close (qsysdep->o); qsysdep->o = -1; (void) fsserial_lockfile (FALSE, qconn); return FALSE; } #ifdef TIOCSCTTY /* On BSD 4.4, make it our controlling terminal. */ (void) ioctl (qsysdep->o, TIOCSCTTY, 0); #endif } #endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */ return TRUE; } /* Unlock a modem or direct port. */ static boolean fsserial_unlock (qconn) struct sconnection *qconn; { boolean fret; struct ssysdep_conn *qsysdep; fret = TRUE; /* The file may have been opened by fsserial_lock, so close it here if necessary. */ qsysdep = (struct ssysdep_conn *) qconn->psysdep; if (qsysdep->o >= 0) { #ifdef TIOCNOTTY (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL); #endif if (close (qsysdep->o) < 0) { ulog (LOG_ERROR, "close: %s", strerror (errno)); fret = FALSE; } qsysdep->o = -1; } if (! fsserial_lockfile (FALSE, qconn)) fret = FALSE; return fret; } /* Open a serial line. This sets the terminal settings. We begin in seven bit mode and let the protocol change if necessary. */ #if HAVE_POSIX_TERMIOS typedef speed_t baud_code; #else typedef int baud_code; #endif static struct sbaud_table { baud_code icode; long ibaud; } asSbaud_table[] = { { B50, 50 }, { B75, 75 }, { B110, 110 }, { B134, 134 }, { B150, 150 }, { B200, 200 }, { B300, 300 }, { B600, 600 }, { B1200, 1200 }, { B1800, 1800 }, { B2400, 2400 }, { B4800, 4800 }, { B9600, 9600 }, #ifdef B19200 { B19200, 19200 }, #else /* ! defined (B19200) */ #ifdef EXTA { EXTA, 19200 }, #endif /* EXTA */ #endif /* ! defined (B19200) */ #ifdef B38400 { B38400, 38400 }, #else /* ! defined (B38400) */ #ifdef EXTB { EXTB, 38400 }, #endif /* EXTB */ #endif /* ! defined (B38400) */ #ifdef B57600 { B57600, 57600 }, #endif #ifdef B76800 { B76800, 76800 }, #endif #ifdef B115200 { B115200, 115200 }, #endif { B0, 0 } }; #define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0]) #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS /* Hold the MIN value for the terminal to avoid setting it unnecessarily. */ static int cSmin; #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ static boolean fsserial_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { struct ssysdep_conn *q; baud_code ib; q = (struct ssysdep_conn *) qconn->psysdep; if (q->zdevice != NULL) ulog_device (strrchr (q->zdevice, '/') + 1); else { const char *zport; boolean fdummy; #if DEBUG > 0 if (qconn->qport != NULL && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN) ulog (LOG_FATAL, "fsserial_open: Can't happen"); #endif zport = zsysdep_port_name (&fdummy); if (zport != NULL) ulog_device (zport); } ib = B0; if (ibaud != 0) { int i; for (i = 0; i < CBAUD_TABLE; i++) if (asSbaud_table[i].ibaud == ibaud) break; if (i >= CBAUD_TABLE) { ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud); return FALSE; } ib = asSbaud_table[i].icode; } /* The port may have already been opened by the locking routine. */ if (q->o < 0) { int iflag; if (fwait) iflag = 0; else iflag = iSunblock; q->o = open (q->zdevice, O_RDWR | iflag); if (q->o < 0) { #if O_NONBLOCK != 0 if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL) { iSunblock = O_NONBLOCK; q->o = open (q->zdevice, O_RDWR | O_NONBLOCK); } #endif if (q->o < 0) { ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno)); return FALSE; } } if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); return FALSE; } #ifdef TIOCSCTTY /* On BSD 4.4, make it our controlling terminal. */ (void) ioctl (q->o, TIOCSCTTY, 0); #endif } /* Get the port flags, and make sure the ports are blocking. */ q->iflags = fcntl (q->o, F_GETFL, 0); if (q->iflags < 0) { ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); return FALSE; } q->istdout_flags = -1; if (! fgetterminfo (q->o, &q->sorig)) { q->fterminal = FALSE; return TRUE; } q->fterminal = TRUE; q->snew = q->sorig; #if HAVE_BSD_TTY q->snew.stty.sg_flags = RAW | ANYP; if (ibaud == 0) ib = q->snew.stty.sg_ospeed; else { q->snew.stty.sg_ispeed = ib; q->snew.stty.sg_ospeed = ib; } /* We don't want to receive any interrupt characters. */ q->snew.stchars.t_intrc = -1; q->snew.stchars.t_quitc = -1; q->snew.stchars.t_eofc = -1; q->snew.stchars.t_brkc = -1; q->snew.sltchars.t_suspc = -1; q->snew.sltchars.t_rprntc = -1; q->snew.sltchars.t_dsuspc = -1; q->snew.sltchars.t_flushc = -1; q->snew.sltchars.t_werasc = -1; q->snew.sltchars.t_lnextc = -1; #ifdef NTTYDISC /* We want to use the ``new'' terminal driver so that we can use the local mode bits to control XON/XOFF. */ { int iparam; if (ioctl (q->o, TIOCGETD, &iparam) >= 0 && iparam != NTTYDISC) { iparam = NTTYDISC; (void) ioctl (q->o, TIOCSETD, &iparam); } } #endif #ifdef TIOCHPCL /* When the file is closed, hang up the line. This is a safety measure in case the program crashes. */ (void) ioctl (q->o, TIOCHPCL, 0); #endif #ifdef TIOCFLUSH { int iparam; /* Flush pending input. */ #ifdef FREAD iparam = FREAD; #else iparam = 0; #endif (void) ioctl (q->o, TIOCFLUSH, &iparam); } #endif /* TIOCFLUSH */ #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO if (ibaud == 0) ib = q->snew.c_cflag & CBAUD; q->snew.c_iflag &=~ ICLEAR_IFLAG; q->snew.c_oflag &=~ ICLEAR_OFLAG; q->snew.c_cflag &=~ ICLEAR_CFLAG; q->snew.c_cflag |= (ib | ISET_CFLAG); q->snew.c_lflag &=~ ICLEAR_LFLAG; cSmin = 1; q->snew.c_cc[VMIN] = cSmin; q->snew.c_cc[VTIME] = 0; #ifdef TCFLSH /* Flush pending input. */ (void) ioctl (q->o, TCFLSH, 0); #endif #endif /* HAVE_SYSV_TERMIO */ #if HAVE_POSIX_TERMIOS if (ibaud == 0) ib = cfgetospeed (&q->snew); q->snew.c_iflag &=~ ICLEAR_IFLAG; q->snew.c_oflag &=~ ICLEAR_OFLAG; q->snew.c_cflag &=~ ICLEAR_CFLAG; q->snew.c_cflag |= ISET_CFLAG; q->snew.c_lflag &=~ ICLEAR_LFLAG; cSmin = 1; q->snew.c_cc[VMIN] = cSmin; q->snew.c_cc[VTIME] = 0; (void) cfsetospeed (&q->snew, ib); (void) cfsetispeed (&q->snew, ib); /* Flush pending input. */ (void) tcflush (q->o, TCIFLUSH); #endif /* HAVE_POSIX_TERMIOS */ if (! fsetterminfo (q->o, &q->snew)) { ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno)); return FALSE; } if (ibaud != 0) q->ibaud = ibaud; else { int i; q->ibaud = (long) 1200; for (i = 0; i < CBAUD_TABLE; i++) { if (asSbaud_table[i].icode == ib) { q->ibaud = asSbaud_table[i].ibaud; break; } } DEBUG_MESSAGE1 (DEBUG_PORT, "fsserial_open: Baud rate is %ld", q->ibaud); } return TRUE; } /* Open a standard input port. The code alternates q->o between 0 and 1 as appropriate. It is always 0 before any call to fsblock. */ static boolean fsstdin_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) qconn->psysdep; q->o = 0; if (! fsserial_open (qconn, ibaud, fwait)) return FALSE; q->istdout_flags = fcntl (1, F_GETFL, 0); if (q->istdout_flags < 0) { ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); return FALSE; } return TRUE; } /* Open a modem port. */ static boolean fsmodem_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { if (ibaud == (long) 0) ibaud = qconn->qport->uuconf_u.uuconf_smodem.uuconf_ibaud; return fsserial_open (qconn, ibaud, fwait); } /* Open a direct port. */ static boolean fsdirect_open (qconn, ibaud, fwait) struct sconnection *qconn; long ibaud; boolean fwait; { if (ibaud == (long) 0) ibaud = qconn->qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; return fsserial_open (qconn, ibaud, fwait); } /* Change the blocking status of the port. We keep track of the current blocking status to avoid calling fcntl unnecessarily; fcntl turns out to be surprisingly expensive, at least on Ultrix. */ static boolean fsblock (qs, fblock) struct ssysdep_conn *qs; boolean fblock; { int iwant; int isys; if (fblock) iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK); else iwant = qs->iflags | iSunblock; if (iwant == qs->iflags) return TRUE; isys = fcntl (qs->o, F_SETFL, iwant); if (isys < 0) { #if O_NONBLOCK != 0 if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL) { iSunblock = O_NONBLOCK; iwant = qs->iflags | O_NONBLOCK; isys = fcntl (qs->o, F_SETFL, iwant); } #endif if (isys < 0) { ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); return FALSE; } } qs->iflags = iwant; if (qs->istdout_flags >= 0) { if (fblock) iwant = qs->istdout_flags &~ (O_NDELAY | O_NONBLOCK); else iwant = qs->istdout_flags | iSunblock; if (fcntl (1, F_SETFL, iwant) < 0) { /* We don't bother to fix up iSunblock here, since we succeeded above. */ ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); return FALSE; } qs->istdout_flags = iwant; } return TRUE; } /* Close a serial port. */ static boolean fsserial_close (q) struct ssysdep_conn *q; { if (q->o >= 0) { /* Use a 30 second timeout to avoid hanging while draining output. */ if (q->fterminal) { fSalarm = FALSE; if (fsysdep_catch ()) { usysdep_start_catch (); usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); (void) alarm (30); (void) fsetterminfodrain (q->o, &q->sorig); } usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); (void) alarm (0); usysdep_end_catch (); /* If we timed out, use the non draining call. Hopefully this can't hang. */ if (fSalarm) (void) fsetterminfo (q->o, &q->sorig); } #ifdef TIOCNOTTY /* We don't want this as our controlling terminal any more, so get rid of it. This is necessary because we don't want to open /dev/tty, since that can confuse the serial port locking on some computers. */ (void) ioctl (q->o, TIOCNOTTY, (char *) NULL); #endif (void) close (q->o); q->o = -1; /* Sleep to give the terminal a chance to settle, in case we are about to call out again. */ sleep (2); } return TRUE; } /* Close a stdin port. */ /*ARGSUSED*/ static boolean fsstdin_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; (void) close (1); (void) close (2); qsysdep->o = 0; return fsserial_close (qsysdep); } /* Close a modem port. */ static boolean fsmodem_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { struct ssysdep_conn *qsysdep; boolean fret; struct uuconf_dialer sdialer; const struct uuconf_chat *qchat; qsysdep = (struct ssysdep_conn *) qconn->psysdep; fret = TRUE; /* Figure out the dialer so that we can run the complete or abort chat scripts. */ if (qdialer == NULL) { if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL) { const char *zdialer; int iuuconf; zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0]; iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer); if (iuuconf == UUCONF_SUCCESS) qdialer = &sdialer; else { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; } } else qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer; } /* Get the complete or abort chat script to use. */ qchat = NULL; if (qdialer != NULL) { if (fsuccess) qchat = &qdialer->uuconf_scomplete; else qchat = &qdialer->uuconf_sabort; } if (qchat != NULL && (qchat->uuconf_pzprogram != NULL || qchat->uuconf_pzchat != NULL)) { boolean fsighup_ignored; HELD_SIG_MASK smask; int i; sig_atomic_t afhold[INDEXSIG_COUNT]; /* We're no longer interested in carrier. */ (void) fsmodem_carrier (qconn, FALSE); /* The port I/O routines check whether any signal has been received, and abort if one has. While we are closing down the modem, we don't care if we received a signal in the past, but we do care if we receive a new signal (otherwise it would be difficult to kill a uucico which was closing down a modem). We never care if we get SIGHUP at this point. So we turn off SIGHUP, remember what signals we've already seen, and clear our notion of what signals we've seen. We have to block the signals while we remember and clear the array, since we might otherwise miss a signal which occurred between the copy and the clear (old systems can't block signals; they will just have to suffer the race). */ usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored); smask = isblocksigs (); for (i = 0; i < INDEXSIG_COUNT; i++) { afhold[i] = afSignal[i]; afSignal[i] = FALSE; } usunblocksigs (smask); if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL, (const struct uuconf_dialer *) NULL, (const char *) NULL, FALSE, qconn->qport->uuconf_zname, qsysdep->ibaud)) fret = FALSE; /* Restore the old signal array and the SIGHUP handler. It is not necessary to block signals here, since all we are doing is exactly what the signal handler itself would do if the signal occurred. */ for (i = 0; i < INDEXSIG_COUNT; i++) if (afhold[i]) afSignal[i] = TRUE; if (! fsighup_ignored) usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL); } if (qdialer != NULL && qdialer == &sdialer) (void) uuconf_dialer_free (puuconf, &sdialer); #if ! HAVE_RESET_BUG /* Reset the terminal to make sure we drop DTR. It should be dropped when we close the descriptor, but that doesn't seem to happen on some systems. Use a 30 second timeout to avoid hanging while draining output. */ if (qsysdep->fterminal) { #if HAVE_BSD_TTY qsysdep->snew.stty.sg_ispeed = B0; qsysdep->snew.stty.sg_ospeed = B0; #endif #if HAVE_SYSV_TERMIO qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0; #endif #if HAVE_POSIX_TERMIOS (void) cfsetospeed (&qsysdep->snew, B0); #endif fSalarm = FALSE; if (fsysdep_catch ()) { usysdep_start_catch (); usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); (void) alarm (30); (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew); } usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); (void) alarm (0); usysdep_end_catch (); /* Let the port settle. */ sleep (2); } #endif /* ! HAVE_RESET_BUG */ if (! fsserial_close (qsysdep)) fret = FALSE; return fret; } /* Close a direct port. */ /*ARGSUSED*/ static boolean fsdirect_close (qconn, puuconf, qdialer, fsuccess) struct sconnection *qconn; pointer puuconf; struct uuconf_dialer *qdialer; boolean fsuccess; { return fsserial_close ((struct ssysdep_conn *) qconn->psysdep); } /* Reset a serial port by hanging up. */ static boolean fsserial_reset (qconn) struct sconnection *qconn; { struct ssysdep_conn *q; sterminal sbaud; q = (struct ssysdep_conn *) qconn->psysdep; if (! q->fterminal) return TRUE; sbaud = q->snew; #if HAVE_BSD_TTY sbaud.stty.sg_ispeed = B0; sbaud.stty.sg_ospeed = B0; #endif #if HAVE_SYSV_TERMIO sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0; #endif #if HAVE_POSIX_TERMIOS if (cfsetospeed (&sbaud, B0) < 0) { ulog (LOG_ERROR, "Can't set baud rate: %s", strerror (errno)); return FALSE; } #endif if (! fsetterminfodrain (q->o, &sbaud)) { ulog (LOG_ERROR, "Can't hangup terminal: %s", strerror (errno)); return FALSE; } /* Give the terminal a chance to settle. */ sleep (2); if (! fsetterminfo (q->o, &q->snew)) { ulog (LOG_ERROR, "Can't reopen terminal: %s", strerror (errno)); return FALSE; } return TRUE; } /* Reset a standard input port. */ static boolean fsstdin_reset (qconn) struct sconnection *qconn; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = 0; return fsserial_reset (qconn); } /* Begin dialing out on a modem port. This opens the dialer device if there is one. */ boolean fsysdep_modem_begin_dial (qconn, qdial) struct sconnection *qconn; struct uuconf_dialer *qdial; { struct ssysdep_conn *qsysdep; const char *z; qsysdep = (struct ssysdep_conn *) qconn->psysdep; #ifdef TIOCMODEM /* If we can tell the modem to obey modem control, do so. */ { int iperm; iperm = 0; (void) ioctl (qsysdep->o, TIOCMODEM, &iperm); } #endif /* TIOCMODEM */ /* If we supposed to toggle DTR, do so. */ if (qdial->uuconf_fdtr_toggle) { #ifdef TIOCCDTR (void) ioctl (qsysdep->o, TIOCCDTR, 0); sleep (2); (void) ioctl (qsysdep->o, TIOCSDTR, 0); #else /* ! defined (TIOCCDTR) */ (void) fconn_reset (qconn); #endif /* ! defined (TIOCCDTR) */ if (qdial->uuconf_fdtr_toggle_wait) sleep (2); } if (! fsmodem_carrier (qconn, FALSE)) return FALSE; /* Open the dial device if there is one. */ z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device; if (z != NULL) { char *zfree; int o; qsysdep->ohold = qsysdep->o; zfree = NULL; if (*z != '/') { zfree = zbufalc (sizeof "/dev/" + strlen (z)); sprintf (zfree, "/dev/%s", z); z = zfree; } o = open ((char *) z, O_RDWR | O_NOCTTY); if (o < 0) { ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno)); ubuffree (zfree); return FALSE; } ubuffree (zfree); if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) close (o); return FALSE; } qsysdep->o = o; } return TRUE; } /* Tell the port to require or not require carrier. On BSD this uses TIOCCAR and TIOCNCAR, which I assume are generally supported (it can also use the LNOMDM bit supported by IS68K Unix). On System V it resets or sets CLOCAL. We only require carrier if the port supports it. This will only be called with fcarrier TRUE if the dialer supports carrier. */ static boolean fsmodem_carrier (qconn, fcarrier) struct sconnection *qconn; boolean fcarrier; { register struct ssysdep_conn *q; q = (struct ssysdep_conn *) qconn->psysdep; if (! q->fterminal) return TRUE; if (fcarrier) { if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier) { #ifdef TIOCCAR /* Tell the modem to pay attention to carrier. */ if (ioctl (q->o, TIOCCAR, 0) < 0) { ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno)); return FALSE; } #endif /* TIOCCAR */ #if HAVE_BSD_TTY #ifdef LNOMDM /* IS68K Unix uses a local LNOMDM bit. */ { int iparam; iparam = LNOMDM; if (ioctl (q->o, TIOCLBIC, &iparam) < 0) { ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s", strerror (errno)); return FALSE; } } #endif /* LNOMDM */ #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS /* Put the modem into nonlocal mode. */ q->snew.c_cflag &=~ CLOCAL; if (! fsetterminfo (q->o, &q->snew)) { ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno)); return FALSE; } #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ } } else { #ifdef TIOCNCAR /* Tell the modem to ignore carrier. */ if (ioctl (q->o, TIOCNCAR, 0) < 0) { ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno)); return FALSE; } #endif /* TIOCNCAR */ #if HAVE_BSD_TTY #ifdef LNOMDM /* IS68K Unix uses a local LNOMDM bit. */ { int iparam; iparam = LNOMDM; if (ioctl (q->o, TIOCLBIS, &iparam) < 0) { ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s", strerror (errno)); return FALSE; } } #endif /* LNOMDM */ #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS /* Put the modem into local mode (ignore carrier) to start the chat script. */ q->snew.c_cflag |= CLOCAL; if (! fsetterminfo (q->o, &q->snew)) { ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno)); return FALSE; } #if HAVE_CLOCAL_BUG /* On SCO and AT&T UNIX PC you have to reopen the port. */ { int onew; onew = open (q->zdevice, O_RDWR); if (onew < 0) { ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno)); return FALSE; } if (fcntl (onew, F_SETFD, fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) close (onew); return FALSE; } (void) close (q->o); q->o = onew; } #endif /* HAVE_CLOCAL_BUG */ #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ } return TRUE; } /* Finish dialing out on a modem by closing any dialer device and waiting for carrier. */ boolean fsysdep_modem_end_dial (qconn, qdial) struct sconnection *qconn; struct uuconf_dialer *qdial; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) qconn->psysdep; if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL) { (void) close (q->o); q->o = q->ohold; } if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier && qdial->uuconf_fcarrier) { /* Tell the port that we need carrier. */ if (! fsmodem_carrier (qconn, TRUE)) return FALSE; #ifdef TIOCWONLINE /* We know how to wait for carrier, so do so. */ /* If we already got a signal, just quit now. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; /* This bit of code handles signals just like fsysdep_conn_read does. See that function for a longer explanation. */ /* Use fsysdep_catch to handle a longjmp from the signal handler. */ fSalarm = FALSE; if (fsysdep_catch ()) { /* Start catching SIGALRM; normally we ignore it. */ usysdep_start_catch (); usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); (void) alarm (qdial->uuconf_ccarrier_wait); /* We really don't care if we get an error, since that will probably just mean that TIOCWONLINE isn't supported in which case there's nothing we can do anyhow. If we get SIGINT we want to keep waiting for carrier, because SIGINT just means don't start any new sessions. We don't handle SIGINT correctly if we do a longjmp in the signal handler; too bad. */ while (ioctl (q->o, TIOCWONLINE, 0) < 0 && errno == EINTR) { /* Log the signal. */ ulog (LOG_ERROR, (const char *) NULL); if (FGOT_QUIT_SIGNAL () || fSalarm) break; } } /* Turn off the pending SIGALRM and ignore SIGALARM again. */ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); (void) alarm (0); usysdep_end_catch (); /* If we got a random signal, just return FALSE. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; /* If we timed out, give an error. */ if (fSalarm) { ulog (LOG_ERROR, "Timed out waiting for carrier"); return FALSE; } #endif /* TIOCWONLINE */ } return TRUE; } /* Read data from a connection, with a timeout. This routine handles all types of connections, including TLI. This function should return when we have read cmin characters or the timeout has occurred. We have to work a bit to get Unix to do this efficiently on a terminal. The simple implementation schedules a SIGALRM signal and then calls read; if there is a single character available, the call to read will return immediately, so there must be a loop which terminates when the SIGALRM is delivered or the correct number of characters has been read. This can be very inefficient with a fast CPU or a low baud rate (or both!), since each call to read may return only one or two characters. Under POSIX or System V, we can specify a minimum number of characters to read, so there is no serious trouble. Under BSD, we figure out how many characters we have left to read, how long it will take for them to arrive at the current baud rate, and sleep that long. Doing this with a timeout and avoiding all possible race conditions get very hairy, though. Basically, we're going to schedule a SIGALRM for when the timeout expires. I don't really want to do a longjmp in the SIGALRM handler, though, because that may lose data. Therefore, I have the signal handler set a variable. However, this means that there will be a span of time between the time the code checks the variable and the time it calls the read system call; if the SIGALRM occurs during that time, the read might hang forever. To avoid this, the SIGALRM handler not only sets a global variable, it also schedules another SIGALRM for one second in the future (POSIX specifies that a signal handler is permitted to safely call alarm). To avoid getting a continual sequence of SIGALRM interrupts, we change the signal handler to ignore SIGALRM when we're about to exit the function. This means that every time we execute fsysdep_conn_read we make at least five system calls. It's the best I've been able to come up with, though. When fsysdep_conn_read finishes, there will be no SIGALRM scheduled and SIGALRM will be ignored. */ boolean fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport) struct sconnection *qconn; char *zbuf; size_t *pclen; size_t cmin; int ctimeout; boolean freport; { CATCH_PROTECT size_t cwant; boolean fret; register struct ssysdep_conn * const q = (struct ssysdep_conn *) qconn->psysdep; cwant = *pclen; *pclen = 0; /* Guard against a bad timeout. We return TRUE when a timeout expires. It is possible to get a negative timeout here because the calling code does not check user supplied timeouts for plausibility. */ if (ctimeout <= 0) return TRUE; /* We want to do a blocking read. */ if (! fsblock (q, TRUE)) return FALSE; fSalarm = FALSE; /* We're going to set up an alarm signal to last for the entire read. If the read system call cannot be interrupted, the signal handler will do a longjmp causing fsysdep_catch (a macro) to return FALSE. We handle that here. If read can be interrupted, fsysdep_catch will be defined to TRUE. */ if (fsysdep_catch ()) { /* Prepare to catch SIGALRM and schedule the signal. */ usysdep_start_catch (); usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL); alarm (ctimeout); } else { /* We caught a signal. We don't actually have to do anything, as all the appropriate checks are made at the start of the following loop. */ } fret = FALSE; while (TRUE) { int cgot; #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS /* If we can tell the terminal not to return until we have a certain number of characters, do so. */ if (q->fterminal) { int csetmin; /* I'm not that confident about setting MIN to values larger than 127, although up to 255 would probably work. */ if (cmin < 127) csetmin = cmin; else csetmin = 127; if (csetmin != cSmin) { q->snew.c_cc[VMIN] = csetmin; while (! fsetterminfo (q->o, &q->snew)) { if (errno != EINTR || FGOT_QUIT_SIGNAL ()) { int ierr; /* We turn off the signal before reporting the error to minimize any problems with interrupted system calls. */ ierr = errno; usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); usysdep_end_catch (); ulog (LOG_ERROR, "Can't set MIN for terminal: %s", strerror (ierr)); return FALSE; } if (fSalarm) { ulog (LOG_ERROR, "Timed out when setting MIN to %d; retrying", csetmin); fSalarm = FALSE; alarm (ctimeout); } } cSmin = csetmin; } } #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */ /* If we've received a signal, get out now. */ if (FGOT_QUIT_SIGNAL ()) break; /* If we've already gotten a SIGALRM, get out with whatever we've accumulated. */ if (fSalarm) { fret = TRUE; break; } /* Right here is the race condition which we avoid by having the SIGALRM handler schedule another SIGALRM. */ #if HAVE_TLI if (q->ftli) { int iflags; cgot = t_rcv (q->o, zbuf, cwant, &iflags); if (cgot < 0 && t_errno != TSYSERR) { usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); usysdep_end_catch (); if (freport) ulog (LOG_ERROR, "t_rcv: %s", (t_errno >= 0 && t_errno < t_nerr ? t_errlist[t_errno] : "unknown TLI error")); return FALSE; } } else #endif cgot = read (q->o, zbuf, cwant); /* If the read returned an error, check for signals. */ if (cgot < 0) { if (errno == EINTR) { /* Log the signal. */ ulog (LOG_ERROR, (const char *) NULL); } if (fSalarm) { fret = TRUE; break; } if (FGOT_QUIT_SIGNAL ()) break; } /* If read returned an error, get out. We just ignore EINTR here, since it must be from some signal we don't care about. If the read returned 0 then the line must have been hung up (normally we would have received SIGHUP, but we can't count on that). We turn off the signals before calling ulog to reduce problems with interrupted system calls. */ if (cgot <= 0) { if (cgot < 0 && errno == EINTR) cgot = 0; else { int ierr; ierr = errno; usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); usysdep_end_catch (); if (freport) { if (cgot == 0) ulog (LOG_ERROR, "Line disconnected"); else ulog (LOG_ERROR, "read: %s", strerror (ierr)); } return FALSE; } } cwant -= cgot; if (cgot >= cmin) cmin = 0; else cmin -= cgot; zbuf += cgot; *pclen += cgot; /* If we have enough data, get out now. */ if (cmin == 0) { fret = TRUE; break; } #if HAVE_BSD_TTY /* We still want more data, so sleep long enough for the rest of it to arrive. We don't this for System V or POSIX because setting MIN is good enough (we can't sleep longer than it takes to get MAX_INPUT characters anyhow). The baud rate is approximately 10 times the number of characters which will arrive in one second, so the number of milliseconds to sleep == characters * (milliseconds / character) == characters * (1000 * (seconds / character)) == characters * (1000 * (1 / (baud / 10))) == characters * (10000 / baud) We arbitrarily reduce the sleep amount by 10 milliseconds to attempt to account for the amount of time it takes to set up the sleep. This is how long it takes to get half a character at 19200 baud. We then don't bother to sleep for less than 10 milliseconds. We don't sleep if the read was interrupted. We use select to sleep. It would be easy to use poll as well, but it's unlikely that any system with BSD ttys would have poll but not select. Using select avoids hassles with the pending SIGALRM; if it hits the select will be interrupted, and otherwise the select will not affect it. */ #if ! HAVE_SELECT #error This code requires select; feel free to extend it #endif if (q->fterminal && cmin > 1 && cgot > 0) { int csleepchars; int isleep; /* We don't try to read all the way up to MAX_INPUT, since that might drop a character. */ if (cmin <= MAX_INPUT - 10) csleepchars = cmin; else csleepchars = MAX_INPUT - 10; isleep = (int) (((long) csleepchars * 10000L) / q->ibaud); isleep -= 10; if (isleep > 10) { struct timeval s; s.tv_sec = isleep / 1000; s.tv_usec = (isleep % 1000) * 1000; /* Some versions of select take a pointer to an int, while some take a pointer to an fd_set. I just cast the arguments to a generic pointer, and assume that any machine which distinguishes int * from fd_set * (I would be amazed if there are any such machines) have an appropriate prototype somewhere or other. */ (void) select (0, (pointer) NULL, (pointer) NULL, (pointer) NULL, &s); /* Here either the select finished sleeping or we got a SIGALRM. If the latter occurred, fSalarm was set to TRUE; it will be checked at the top of the loop. */ } } #endif /* HAVE_BSD_TTY */ } /* Turn off the pending SIGALRM and return. */ usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); alarm (0); usysdep_end_catch (); return fret; } /* Read from a stdin port. */ static boolean fsstdin_read (qconn, zbuf, pclen, cmin, ctimeout, freport) struct sconnection *qconn; char *zbuf; size_t *pclen; size_t cmin; int ctimeout; boolean freport; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = 0; return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport); } /* Write data to a connection. This routine handles all types of connections, including TLI. */ boolean fsysdep_conn_write (qconn, zwrite, cwrite) struct sconnection *qconn; const char *zwrite; size_t cwrite; { struct ssysdep_conn *q; int czero; q = (struct ssysdep_conn *) qconn->psysdep; /* We want blocking writes here. */ if (! fsblock (q, TRUE)) return FALSE; czero = 0; while (cwrite > 0) { int cdid; /* Loop until we don't get an interrupt. */ while (TRUE) { /* If we've received a signal, don't continue. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; #if HAVE_TLI if (q->ftli) { cdid = t_snd (q->o, zwrite, cwrite, 0); if (cdid < 0 && t_errno != TSYSERR) { ulog (LOG_ERROR, "t_snd: %s", (t_errno >= 0 && t_errno < t_nerr ? t_errlist[t_errno] : "unknown TLI error")); return FALSE; } } else #endif cdid = write (q->o, zwrite, cwrite); if (cdid >= 0) break; if (errno != EINTR) break; /* We were interrupted by a signal. Log it. */ ulog (LOG_ERROR, (const char *) NULL); } if (cdid < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) { ulog (LOG_ERROR, "write: %s", strerror (errno)); return FALSE; } cdid = 0; } if (cdid == 0) { /* On some systems write will return 0 if carrier is lost. If we fail to write anything ten times in a row, we assume that this has happened. This is hacked in like this because there seems to be no reliable way to tell exactly why the write returned 0. */ ++czero; if (czero >= 10) { ulog (LOG_ERROR, "Line disconnected"); return FALSE; } } else { czero = 0; cwrite -= cdid; zwrite += cdid; } } return TRUE; } /* Write to a stdin port. */ static boolean fsstdin_write (qconn, zwrite, cwrite) struct sconnection *qconn; const char *zwrite; size_t cwrite; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = 0; if (! fsblock (qsysdep, TRUE)) return FALSE; qsysdep->o = 1; return fsysdep_conn_write (qconn, zwrite, cwrite); } /* The fsysdep_conn_io routine is supposed to both read and write data until it has either filled its read buffer or written out all the data it was given. This lets us write out large packets without losing incoming data. It handles all types of connections, including TLI. */ boolean fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread) struct sconnection *qconn; const char *zwrite; size_t *pcwrite; char *zread; size_t *pcread; { struct ssysdep_conn *q; size_t cwrite, cread; int czero; q = (struct ssysdep_conn *) qconn->psysdep; cwrite = *pcwrite; *pcwrite = 0; cread = *pcread; *pcread = 0; czero = 0; while (TRUE) { int cgot, cdid; size_t cdo; /* This used to always use nonblocking writes, but it turns out that some systems don't support them on terminals. The current algorithm is: loop: unblocked read if read buffer full, return if nothing to write, return if HAVE_UNBLOCKED_WRITES write all data else write up to SINGLE_WRITE bytes if all data written, return if no data written blocked write of up to SINGLE_WRITE bytes This algorithm should work whether the system supports unblocked writes on terminals or not. If the system supports unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will call write more often than it needs to. If the system does not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1, then the write may hang so long that incoming data is lost. This is actually possible at high baud rates on any system when a blocking write is done; there is no solution, except hardware handshaking. */ /* If we are running on standard input, we switch the file descriptors by hand. */ if (q->istdout_flags >= 0) q->o = 0; /* Do an unblocked read. */ if (! fsblock (q, FALSE)) return FALSE; /* Loop until we get something (error or data) other than an acceptable EINTR. */ while (TRUE) { /* If we've received a signal, don't continue. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; #if HAVE_TLI if (q->ftli) { int iflags; cgot = t_rcv (q->o, zread, cread, &iflags); if (cgot < 0) { if (t_errno == TNODATA) errno = EAGAIN; else if (t_errno != TSYSERR) { ulog (LOG_ERROR, "t_rcv: %s", (t_errno >= 0 && t_errno < t_nerr ? t_errlist[t_errno] : "unknown TLI error")); return FALSE; } } } else #endif cgot = read (q->o, zread, cread); if (cgot >= 0) break; if (errno != EINTR) break; /* We got interrupted by a signal. Log it. */ ulog (LOG_ERROR, (const char *) NULL); } if (cgot < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) { ulog (LOG_ERROR, "read: %s", strerror (errno)); return FALSE; } cgot = 0; } cread -= cgot; zread += cgot; *pcread += cgot; /* If we've filled the read buffer, or we have nothing left to write, return out. */ if (cread == 0 || cwrite == 0) return TRUE; /* The port is currently unblocked. Do a write. */ cdo = cwrite; #if ! HAVE_UNBLOCKED_WRITES if (q->fterminal && cdo > SINGLE_WRITE) cdo = SINGLE_WRITE; #endif if (q->istdout_flags >= 0) q->o = 1; /* Loop until we get something besides EINTR. */ while (TRUE) { /* If we've received a signal, don't continue. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; #if HAVE_TLI if (q->ftli) { cdid = t_snd (q->o, zwrite, cdo, 0); if (cdid < 0) { if (t_errno == TFLOW) errno = EAGAIN; else if (t_errno != TSYSERR) { ulog (LOG_ERROR, "t_snd: %s", (t_errno >= 0 && t_errno < t_nerr ? t_errlist[t_errno] : "unknown TLI error")); return FALSE; } } } else #endif cdid = write (q->o, zwrite, cdo); if (cdid >= 0) break; if (errno != EINTR) break; /* We got interrupted by a signal. Log it. */ ulog (LOG_ERROR, (const char *) NULL); } if (cdid < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA) { ulog (LOG_ERROR, "write: %s", strerror (errno)); return FALSE; } cdid = 0; } if (cdid > 0) { /* We wrote some data. If we wrote everything, return out. Otherwise loop around and do another read. */ cwrite -= cdid; zwrite += cdid; *pcwrite += cdid; if (cwrite == 0) return TRUE; czero = 0; } else { /* We didn't write any data. Do a blocking write. */ if (q->istdout_flags >= 0) q->o = 0; if (! fsblock (q, TRUE)) return FALSE; cdo = cwrite; if (cdo > SINGLE_WRITE) cdo = SINGLE_WRITE; DEBUG_MESSAGE1 (DEBUG_PORT, "fsysdep_conn_io: Blocking write of %lud", (unsigned long) cdo); if (q->istdout_flags >= 0) q->o = 1; /* Loop until we get something besides EINTR. */ while (TRUE) { /* If we've received a signal, don't continue. */ if (FGOT_QUIT_SIGNAL ()) return FALSE; #if HAVE_TLI if (q->ftli) { cdid = t_snd (q->o, zwrite, cdo, 0); if (cdid < 0 && t_errno != TSYSERR) { ulog (LOG_ERROR, "t_snd: %s", (t_errno >= 0 && t_errno < t_nerr ? t_errlist[t_errno] : "unknown TLI error")); return FALSE; } } else #endif cdid = write (q->o, zwrite, cdo); if (cdid >= 0) break; if (errno != EINTR) break; /* We got interrupted by a signal. Log it. */ ulog (LOG_ERROR, (const char *) NULL); } if (cdid < 0) { ulog (LOG_ERROR, "write: %s", strerror (errno)); return FALSE; } if (cdid == 0) { /* On some systems write will return 0 if carrier is lost. If we fail to write anything ten times in a row, we assume that this has happened. This is hacked in like this because there seems to be no reliable way to tell exactly why the write returned 0. */ ++czero; if (czero >= 10) { ulog (LOG_ERROR, "Line disconnected"); return FALSE; } } else { cwrite -= cdid; zwrite += cdid; *pcwrite += cdid; czero = 0; } } } } /* Send a break character to a serial port. */ static boolean fsserial_break (qconn) struct sconnection *qconn; { struct ssysdep_conn *q; q = (struct ssysdep_conn *) qconn->psysdep; #if HAVE_BSD_TTY (void) ioctl (q->o, TIOCSBRK, 0); sleep (2); (void) ioctl (q->o, TIOCCBRK, 0); return TRUE; #endif /* HAVE_BSD_TTY */ #if HAVE_SYSV_TERMIO (void) ioctl (q->o, TCSBRK, 0); return TRUE; #endif /* HAVE_SYSV_TERMIO */ #if HAVE_POSIX_TERMIOS return tcsendbreak (q->o, 0) == 0; #endif /* HAVE_POSIX_TERMIOS */ } /* Send a break character to a stdin port. */ static boolean fsstdin_break (qconn) struct sconnection *qconn; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = 1; return fsserial_break (qconn); } /* Change the setting of a serial port. */ /*ARGSUSED*/ static boolean fsserial_set (qconn, tparity, tstrip, txonxoff) struct sconnection *qconn; enum tparitysetting tparity; enum tstripsetting tstrip; enum txonxoffsetting txonxoff; { register struct ssysdep_conn *q; boolean fchanged, fdo; int iset = 0; int iclear = 0; q = (struct ssysdep_conn *) qconn->psysdep; if (! q->fterminal) return TRUE; fchanged = FALSE; /* Set the parity for output characters. */ #if HAVE_BSD_TTY /* This will also cause parity detection on input characters. */ fdo = FALSE; switch (tparity) { case PARITYSETTING_DEFAULT: break; case PARITYSETTING_NONE: #if HAVE_PARITY_BUG /* The Sony NEWS mishandles this for some reason. */ iset = 0; iclear = ANYP; #else iset = ANYP; iclear = 0; #endif fdo = TRUE; break; case PARITYSETTING_EVEN: iset = EVENP; iclear = ODDP; fdo = TRUE; break; case PARITYSETTING_ODD: iset = ODDP; iclear = EVENP; fdo = TRUE; break; case PARITYSETTING_MARK: case PARITYSETTING_SPACE: /* Not supported. */ break; } if (fdo) { if ((q->snew.stty.sg_flags & iset) != iset || (q->snew.stty.sg_flags & iclear) != 0) { q->snew.stty.sg_flags |= iset; q->snew.stty.sg_flags &=~ iclear; fchanged = TRUE; } } #else /* ! HAVE_BSD_TTY */ fdo = FALSE; switch (tparity) { case PARITYSETTING_DEFAULT: break; case PARITYSETTING_NONE: iset = CS8; iclear = PARENB | PARODD | (CSIZE &~ CS8); fdo = TRUE; break; case PARITYSETTING_EVEN: iset = PARENB | CS7; iclear = PARODD | (CSIZE &~ CS7); fdo = TRUE; break; case PARITYSETTING_ODD: iset = PARENB | PARODD | CS7; iclear = CSIZE &~ CS7; fdo = TRUE; break; case PARITYSETTING_MARK: case PARITYSETTING_SPACE: /* Not supported. */ break; } if (fdo) { if ((q->snew.c_cflag & iset) != iset || (q->snew.c_cflag & iclear) != 0) { q->snew.c_cflag |= iset; q->snew.c_cflag &=~ iclear; fchanged = TRUE; } } #endif /* ! HAVE_BSD_TTY */ /* Set whether input characters are stripped to seven bits. */ #if HAVE_BSD_TTY #ifdef LPASS8 { int i; i = LPASS8; if (tstrip == STRIPSETTING_EIGHTBITS) { i = LPASS8; (void) ioctl (q->o, TIOCLBIS, &i); } else if (tstrip == STRIPSETTING_SEVENBITS) { i = LPASS8; (void) ioctl (q->o, TIOCLBIC, &i); } } #endif #else /* ! HAVE_BSD_TTY */ fdo = FALSE; switch (tstrip) { case STRIPSETTING_DEFAULT: break; case STRIPSETTING_EIGHTBITS: iset = 0; iclear = ISTRIP; fdo = TRUE; break; case STRIPSETTING_SEVENBITS: iset = ISTRIP; iclear = 0; fdo = TRUE; break; } if (fdo) { if ((q->snew.c_iflag & iset) != iset || (q->snew.c_iflag & iclear) != 0) { q->snew.c_iflag |= iset; q->snew.c_iflag &=~ iclear; fchanged = TRUE; } } #endif /* ! HAVE_BSD_TTY */ /* Set XON/XOFF handshaking. */ #if HAVE_BSD_TTY fdo = FALSE; switch (txonxoff) { case XONXOFF_DEFAULT: break; case XONXOFF_OFF: iset = RAW; iclear = TANDEM | CBREAK; fdo = TRUE; break; case XONXOFF_ON: iset = CBREAK | TANDEM; iclear = RAW; fdo = TRUE; break; } if (fdo) { if ((q->snew.stty.sg_flags & iset) != iset || (q->snew.stty.sg_flags & iclear) != 0) { q->snew.stty.sg_flags |= iset; q->snew.stty.sg_flags &=~ iclear; fchanged = TRUE; } } #else /* ! HAVE_BSD_TTY */ fdo = FALSE; switch (txonxoff) { case XONXOFF_DEFAULT: break; case XONXOFF_OFF: iset = 0; iclear = IXON | IXOFF; fdo = TRUE; break; case XONXOFF_ON: #ifdef CRTSCTS #if HAVE_POSIX_TERMIOS /* This is system dependent, but I haven't figured out a good way around it yet. If we are doing hardware flow control, we don't send XON/XOFF characters but we do recognize them. */ if ((q->snew.c_cflag & CRTSCTS) != 0) { iset = IXON; iclear = IXOFF; fdo = TRUE; break; } #endif /* HAVE_POSIX_TERMIOS */ #endif /* defined (CRTSCTS) */ iset = IXON | IXOFF; iclear = 0; fdo = TRUE; break; } if (fdo) { if ((q->snew.c_iflag & iset) != iset || (q->snew.c_iflag & iclear) != 0) { q->snew.c_iflag |= iset; q->snew.c_iflag &=~ iclear; fchanged = TRUE; } } #endif /* ! HAVE_BSD_TTY */ if (fchanged) { if (! fsetterminfodrain (q->o, &q->snew)) { ulog (LOG_ERROR, "Can't change terminal settings: %s", strerror (errno)); return FALSE; } } #if HAVE_BSD_TTY if (txonxoff == XONXOFF_ON && (q->snew.stty.sg_flags & ANYP) == ANYP) { int i; /* At least on Ultrix, we seem to have to set LLITOUT and LPASS8. This shouldn't foul things up anywhere else. As far as I can tell, this has to be done after setting the terminal into cbreak mode, not before. */ #ifndef LLITOUT #define LLITOUT 0 #endif #ifndef LPASS8 #define LPASS8 0 #endif #ifndef LAUTOFLOW #define LAUTOFLOW 0 #endif i = LLITOUT | LPASS8 | LAUTOFLOW; (void) ioctl (q->o, TIOCLBIS, &i); #if HAVE_STRIP_BUG /* Ultrix 4.0 has a peculiar problem: setting CBREAK always causes input characters to be stripped. I hope this does not apply to other BSD systems. It is possible to work around this by using the termio call. I wish this sort of stuff was not necessary!!! */ { struct termio s; if (ioctl (q->o, TCGETA, &s) >= 0) { s.c_iflag &=~ ISTRIP; (void) ioctl (q->o, TCSETA, &s); } } #endif /* HAVE_STRIP_BUG */ } #endif /* HAVE_BSD_TTY */ return TRUE; } /* Change settings of a stdin port. */ static boolean fsstdin_set (qconn, tparity, tstrip, txonxoff) struct sconnection *qconn; enum tparitysetting tparity; enum tstripsetting tstrip; enum txonxoffsetting txonxoff; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; qsysdep->o = 0; return fsserial_set (qconn, tparity, tstrip, txonxoff); } /* Run a chat program. */ static boolean fsrun_chat (oread, owrite, pzprog) int oread; int owrite; char **pzprog; { int aidescs[3]; FILE *e; pid_t ipid; char *z; size_t c; aidescs[0] = oread; aidescs[1] = owrite; aidescs[2] = SPAWN_READ_PIPE; /* Pass fkeepuid, fkeepenv and fshell as TRUE. This puts the responsibility of maintaing security on the chat program. */ ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno)); return FALSE; } e = fdopen (aidescs[2], (char *) "r"); if (e == NULL) { ulog (LOG_ERROR, "fdopen: %s", strerror (errno)); (void) close (aidescs[2]); (void) kill (ipid, SIGKILL); (void) ixswait ((unsigned long) ipid, (const char *) NULL); return FALSE; } /* The FILE e now is attached to stderr of the program. Forward every line the program outputs to the log file. */ z = NULL; c = 0; while (getline (&z, &c, e) > 0) { size_t clen; clen = strlen (z); if (z[clen - 1] == '\n') z[clen - 1] = '\0'; if (*z != '\0') ulog (LOG_NORMAL, "chat: %s", z); } xfree ((pointer) z); (void) fclose (e); return ixswait ((unsigned long) ipid, "Chat program") == 0; } /* Run a chat program on a stdin port. */ /*ARGSUSED*/ static boolean fsstdin_chat (qconn, pzprog) struct sconnection *qconn; char **pzprog; { return fsrun_chat (0, 1, pzprog); } /* Run a chat program on any general type of connection. */ boolean fsysdep_conn_chat (qconn, pzprog) struct sconnection *qconn; char **pzprog; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; return fsrun_chat (qsysdep->o, qsysdep->o, pzprog); } /* Return baud rate of a serial port. */ static long isserial_baud (qconn) struct sconnection *qconn; { struct ssysdep_conn *qsysdep; qsysdep = (struct ssysdep_conn *) qconn->psysdep; return qsysdep->ibaud; } rlist[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"uucp-1.04/unix/signal.c1004440004150000170000001241305337263573011776 037777777777 1 0 /* signal.c Signal handling routines. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* Signal handling routines. When we catch a signal, we want to set the appropriate elements of afSignal and afLog_signal to TRUE. If we are on a system which restarts system calls, we may also want to longjmp out. On a system which does not restart system calls, these signal handling routines are well-defined by ANSI C. */ #if HAVE_RESTARTABLE_SYSCALLS volatile sig_atomic_t fSjmp; volatile jmp_buf sSjmp_buf; #endif /* HAVE_RESTARTABLE_SYSCALLS */ /* Some systems, such as SunOS, have a SA_INTERRUPT bit that must be set in the sigaction structure to force system calls to be interrupted. */ #ifndef SA_INTERRUPT #define SA_INTERRUPT 0 #endif /* The SVR3 sigset function can be called just like signal, unless system calls are restarted which is extremely unlikely; we prevent this case in sysh.unx. */ #if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC #define signal sigset #endif /* The sigvec structure changed from 4.2BSD to 4.3BSD. These macros make the 4.3 code backward compatible. */ #ifndef SV_INTERRUPT #define SV_INTERRUPT 0 #endif #if ! HAVE_SIGVEC_SV_FLAGS #define sv_flags sv_onstack #endif /* Catch a signal. Reinstall the signal handler if necessary, set the appropriate variables, and do a longjmp if necessary. */ RETSIGTYPE ussignal (isig) int isig; { int iindex; #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET (void) signal (isig, ussignal); #endif switch (isig) { default: iindex = INDEXSIG_SIGHUP; break; #ifdef SIGINT case SIGINT: iindex = INDEXSIG_SIGINT; break; #endif #ifdef SIGQUIT case SIGQUIT: iindex = INDEXSIG_SIGQUIT; break; #endif #ifdef SIGTERM case SIGTERM: iindex = INDEXSIG_SIGTERM; break; #endif #ifdef SIGPIPE case SIGPIPE: iindex = INDEXSIG_SIGPIPE; break; #endif } afSignal[iindex] = TRUE; afLog_signal[iindex] = TRUE; #if HAVE_RESTARTABLE_SYSCALLS if (fSjmp) longjmp (sSjmp_buf, 1); #endif /* HAVE_RESTARTABLE_SYSCALLS */ } /* Prepare to catch a signal. This is basically the ANSI C routine signal, but it uses sigaction or sigvec instead if they are available. If fforce is FALSE, we do not set the signal if it is currently being ignored. If pfignored is not NULL and fforce is FALSE, then *pfignored will be set to TRUE if the signal was previously being ignored (if fforce is TRUE the value returned in *pfignored is meaningless). If we can't change the signal handler we give a fatal error. */ void usset_signal (isig, pfn, fforce, pfignored) int isig; RETSIGTYPE (*pfn) P((int)); boolean fforce; boolean *pfignored; { #if HAVE_SIGACTION struct sigaction s; if (! fforce) { (void) (sigemptyset (&s.sa_mask)); if (sigaction (isig, (struct sigaction *) NULL, &s) != 0) ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno)); if (s.sa_handler == SIG_IGN) { if (pfignored != NULL) *pfignored = TRUE; return; } if (pfignored != NULL) *pfignored = FALSE; } s.sa_handler = pfn; (void) (sigemptyset (&s.sa_mask)); s.sa_flags = SA_INTERRUPT; if (sigaction (isig, &s, (struct sigaction *) NULL) != 0) ulog (LOG_FATAL, "sigaction (%d): %s", isig, strerror (errno)); #else /* ! HAVE_SIGACTION */ #if HAVE_SIGVEC struct sigvec s; if (! fforce) { if (sigvec (isig, (struct sigvec *) NULL, &s) != 0) ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno)); if (s.sv_handler == SIG_IGN) { if (pfignored != NULL) *pfignored = TRUE; return; } if (pfignored != NULL) *pfignored = FALSE; } s.sv_handler = pfn; s.sv_mask = 0; s.sv_flags = SV_INTERRUPT; if (sigvec (isig, &s, (struct sigvec *) NULL) != 0) ulog (LOG_FATAL, "sigvec (%d): %s", isig, strerror (errno)); #else /* ! HAVE_SIGVEC */ if (! fforce) { if (signal (isig, SIG_IGN) == SIG_IGN) { if (pfignored != NULL) *pfignored = TRUE; return; } if (pfignored != NULL) *pfignored = FALSE; } (void) signal (isig, pfn); #endif /* ! HAVE_SIGVEC */ #endif /* ! HAVE_SIGACTION */ } /* The routine called by the system independent code, which always uses the same signal handler. */ void usysdep_signal (isig) int isig; { usset_signal (isig, ussignal, FALSE, (boolean *) NULL); } 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, "Cuucp-1.04/unix/sindir.c1004440004150000170000000075405337263573012016 037777777777 1 0 /* 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; } s.c_iflag &=~ ISTRIPuucp-1.04/unix/size.c1004440004150000170000000063705337263573011500 037777777777 1 0 /* size.c Get the size in bytes of a file. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include long csysdep_size (zfile) const char *zfile; { struct stat s; if (stat ((char *) zfile, &s) < 0) { if (errno == ENOENT) return -1; ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); return -2; } return s.st_size; } chat program. */ ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE, (const chauucp-1.04/unix/sleep.c1004440004150000170000000025105337263573011626 037777777777 1 0 /* 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); } 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 booleanuucp-1.04/unix/splcmd.c1004440004150000170000000556505337263574012016 037777777777 1 0 /* splcmd.c Spool a command. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include #include /* Given a set of commands to execute for a remote system, create a command file holding them. This creates a single command file holding all the commands passed in. It returns a jobid. */ char * zsysdep_spool_commands (qsys, bgrade, ccmds, pascmds) const struct uuconf_system *qsys; int bgrade; int ccmds; const struct scmd *pascmds; { char *z; FILE *e; int i; const struct scmd *q; char *zjobid; #if DEBUG > 0 if (! UUCONF_GRADE_LEGAL (bgrade)) ulog (LOG_FATAL, "Bad grade %d", bgrade); #endif z = zscmd_file (qsys, bgrade); if (z == NULL) return NULL; e = esysdep_fopen (z, FALSE, FALSE, TRUE); if (e == NULL) { ubuffree (z); return NULL; } for (i = 0, q = pascmds; i < ccmds; i++, q++) { switch (q->bcmd) { case 'S': fprintf (e, "S %s %s %s -%s %s 0%o %s\n", q->zfrom, q->zto, q->zuser, q->zoptions, q->ztemp, q->imode, q->znotify == NULL ? (const char *) "" : q->znotify); break; case 'R': fprintf (e, "R %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, q->zoptions); break; case 'X': fprintf (e, "X %s %s %s -%s\n", q->zfrom, q->zto, q->zuser, q->zoptions); break; case 'E': fprintf (e, "E %s %s %s -%s %s 0%o %s 0 %s\n", q->zfrom, q->zto, q->zuser, q->zoptions, q->ztemp, q->imode, q->znotify, q->zcmd); break; default: ulog (LOG_ERROR, "zsysdep_spool_commands: Unrecognized type %d", q->bcmd); (void) fclose (e); (void) remove (z); ubuffree (z); return NULL; } } if (fclose (e) != 0) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); (void) remove (z); ubuffree (z); return NULL; } zjobid = zsfile_to_jobid (qsys, z, bgrade); if (zjobid == NULL) (void) remove (z); ubuffree (z); return zjobid; } #if HAVE_SIGSET && ! HAVE_SIGACTION && ! HAVE_SIGVEC #define signal sigset #endif /* The sigvec structure changed from 4.2BSD to 4.3BSD. uucp-1.04/unix/splnam.c1004440004150000170000000061605337263574012016 037777777777 1 0 /* 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)); } SYSCALLS if (fSjmp) longjmp (sSjmp_buf, 1); #endif /* HAVE_RESTARTABLE_SYSCALLS */ } /* Prepare to catch a uucp-1.04/unix/spool.c1004440004150000170000003326005337263575011662 037777777777 1 0 /* 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.5 1992/10/08 04:21:04 ian Rel $"; #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 */ } ame 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 puucp-1.04/unix/spawn.c1004440004150000170000002301305337263574011650 037777777777 1 0 /* spawn.c Spawn a program securely. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #ifndef environ extern char **environ; #endif /* Spawn a child in a fairly secure fashion. This returns the process ID of the child or -1 on error. It takes far too many arguments: pazargs -- arguments (element 0 is command) aidescs -- file descriptors for stdin, stdout and stderr fkeepuid -- TRUE if euid should be left unchanged fkeepenv -- TRUE if environment should be left unmodified zchdir -- directory to chdir to fnosigs -- TRUE if child should ignore SIGHUP, SIGINT and SIGQUIT fshell -- TRUE if should try /bin/sh if execve gets ENOEXEC zpath -- value for environment variable PATH zuu_machine -- value for environment variable UU_MACHINE zuu_user -- value for environment variable UU_USER The aidescs array is three elements long. 0 is stdin, 1 is stdout and 2 is stderr. The array may contain either file descriptor numbers to dup appropriately, or one of the following: SPAWN_NULL -- set descriptor to /dev/null SPAWN_READ_PIPE -- set aidescs element to pipe for parent to read SPAWN_WRITE_PIPE -- set aidescs element to pipe for parent to write If fkeepenv is FALSE, a standard environment is created. The environment arguments (zpath, zuu_machine and zuu_user) are only used if fkeepenv is FALSE; any of them may be NULL. This routine expects that all file descriptors have been set to close-on-exec, so it doesn't have to worry about closing them explicitly. It sets the close-on-exec flag for the new pipe descriptors it returns. */ pid_t ixsspawn (pazargs, aidescs, fkeepuid, fkeepenv, zchdir, fnosigs, fshell, zpath, zuu_machine, zuu_user) const char **pazargs; int aidescs[3]; boolean fkeepuid; boolean fkeepenv; const char *zchdir; boolean fnosigs; boolean fshell; const char *zpath; const char *zuu_machine; const char *zuu_user; { char *zshcmd; int i; char *azenv[9]; char **pazenv; boolean ferr; int ierr = 0; int onull; int aichild_descs[3]; int cpar_close; int aipar_close[4]; int cchild_close; int aichild_close[3]; pid_t iret = 0; const char *zcmd; /* If we might have to use the shell, allocate enough space for the quoted command before forking. Otherwise the allocation would modify the data segment and we could not safely use vfork. */ zshcmd = NULL; if (fshell) { size_t clen; clen = 0; for (i = 0; pazargs[i] != NULL; i++) clen += strlen (pazargs[i]); zshcmd = zbufalc (2 * clen + i); } /* Set up a standard environment. This is again done before forking because it will modify the data segment. */ if (fkeepenv) pazenv = environ; else { const char *zterm, *ztz; char *zspace; int ienv; if (zpath == NULL) zpath = CMDPATH; azenv[0] = zbufalc (sizeof "PATH=" + strlen (zpath)); sprintf (azenv[0], "PATH=%s", zpath); zspace = azenv[0] + sizeof "PATH=" - 1; while ((zspace = strchr (zspace, ' ')) != NULL) *zspace = ':'; azenv[1] = zbufalc (sizeof "HOME=" + strlen (zSspooldir)); sprintf (azenv[1], "HOME=%s", zSspooldir); zterm = getenv ("TERM"); if (zterm == NULL) zterm = "unknown"; azenv[2] = zbufalc (sizeof "TERM=" + strlen (zterm)); sprintf (azenv[2], "TERM=%s", zterm); azenv[3] = zbufcpy ("SHELL=/bin/sh"); azenv[4] = zbufalc (sizeof "USER=" + strlen (OWNER)); sprintf (azenv[4], "USER=%s", OWNER); ienv = 5; ztz = getenv ("TZ"); if (ztz != NULL) { azenv[ienv] = zbufalc (sizeof "TZ=" + strlen (ztz)); sprintf (azenv[ienv], "TZ=%s", ztz); ++ienv; } if (zuu_machine != NULL) { azenv[ienv] = zbufalc (sizeof "UU_MACHINE=" + strlen (zuu_machine)); sprintf (azenv[ienv], "UU_MACHINE=%s", zuu_machine); ++ienv; } if (zuu_user != NULL) { azenv[ienv] = zbufalc (sizeof "UU_USER=" + strlen (zuu_user)); sprintf (azenv[ienv], "UU_USER=%s", zuu_user); ++ienv; } azenv[ienv] = NULL; pazenv = azenv; } /* Set up any needed pipes. */ ferr = FALSE; onull = -1; cpar_close = 0; cchild_close = 0; for (i = 0; i < 3; i++) { if (aidescs[i] == SPAWN_NULL) { if (onull < 0) { onull = open ((char *) "/dev/null", O_RDWR); if (onull < 0 || fcntl (onull, F_SETFD, fcntl (onull, F_GETFD, 0) | FD_CLOEXEC) < 0) { ierr = errno; (void) close (onull); ferr = TRUE; break; } aipar_close[cpar_close] = onull; ++cpar_close; } aichild_descs[i] = onull; } else if (aidescs[i] != SPAWN_READ_PIPE && aidescs[i] != SPAWN_WRITE_PIPE) aichild_descs[i] = aidescs[i]; else { int aipipe[2]; if (pipe (aipipe) < 0) { ierr = errno; ferr = TRUE; break; } if (aidescs[i] == SPAWN_READ_PIPE) { aidescs[i] = aipipe[0]; aichild_close[cchild_close] = aipipe[0]; aichild_descs[i] = aipipe[1]; aipar_close[cpar_close] = aipipe[1]; } else { aidescs[i] = aipipe[1]; aichild_close[cchild_close] = aipipe[1]; aichild_descs[i] = aipipe[0]; aipar_close[cpar_close] = aipipe[0]; } ++cpar_close; ++cchild_close; if (fcntl (aidescs[i], F_SETFD, fcntl (aidescs[i], F_GETFD, 0) | FD_CLOEXEC) < 0) { ierr = errno; ferr = TRUE; break; } } } #if DEBUG > 1 if (! ferr && FDEBUGGING (DEBUG_EXECUTE)) { ulog (LOG_DEBUG_START, "Forking %s", pazargs[0]); for (i = 1; pazargs[i] != NULL; i++) ulog (LOG_DEBUG_CONTINUE, " %s", pazargs[i]); ulog (LOG_DEBUG_END, "%s", ""); } #endif if (! ferr) { /* This should really be vfork if available. */ iret = ixsfork (); if (iret < 0) { ferr = TRUE; ierr = errno; } } if (ferr) { for (i = 0; i < cchild_close; i++) (void) close (aichild_close[i]); iret = -1; } if (iret != 0) { /* The parent. Close the child's ends of the pipes and return the process ID, or an error. */ for (i = 0; i < cpar_close; i++) (void) close (aipar_close[i]); ubuffree (zshcmd); if (! fkeepenv) { char **pz; for (pz = azenv; *pz != NULL; pz++) ubuffree (*pz); } errno = ierr; return iret; } /* The child. */ #ifdef STDIN_FILENO #if STDIN_FILENO != 0 || STDOUT_FILENO != 1 || STDERR_FILENO != 2 #error The following code makes invalid assumptions #endif #endif for (i = 0; i < 3; i++) { if (aichild_descs[i] != i) (void) dup2 (aichild_descs[i], i); /* This should only be necessary if aichild_descs[i] == i, but some systems copy the close-on-exec flag for a dupped descriptor, which is wrong according to POSIX. */ (void) fcntl (i, F_SETFD, fcntl (i, F_GETFD, 0) &~ FD_CLOEXEC); } zcmd = pazargs[0]; pazargs[0] = strrchr (zcmd, '/'); if (pazargs[0] == NULL) pazargs[0] = zcmd; else ++pazargs[0]; if (! fkeepuid) { (void) setuid (getuid ()); (void) setgid (getgid ()); } if (zchdir != NULL) (void) chdir (zchdir); if (fnosigs) { #ifdef SIGHUP (void) signal (SIGHUP, SIG_IGN); #endif #ifdef SIGINT (void) signal (SIGINT, SIG_IGN); #endif #ifdef SIGQUIT (void) signal (SIGQUIT, SIG_IGN); #endif } (void) execve ((char *) zcmd, (char **) pazargs, pazenv); /* The exec failed. If permitted, try using /bin/sh to execute a shell script. */ if (errno == ENOEXEC && fshell) { char *zto; const char *azshargs[4]; pazargs[0] = zcmd; zto = zshcmd; for (i = 0; pazargs[i] != NULL; i++) { const char *zfrom; for (zfrom = pazargs[i]; *zfrom != '\0'; zfrom++) { /* Some versions of /bin/sh appear to have a bug such that quoting a '/' sometimes causes an error. I don't know exactly when this happens (I can recreate it on Ultrix 4.0), but in any case it is harmless to not quote a '/'. */ if (*zfrom != '/') *zto++ = '\\'; *zto++ = *zfrom; } *zto++ = ' '; } *(zto - 1) = '\0'; azshargs[0] = "sh"; azshargs[1] = "-c"; azshargs[2] = zshcmd; azshargs[3] = NULL; (void) execve ((char *) "/bin/sh", (char **) azshargs, pazenv); } _exit (EXIT_FAILURE); /* Avoid compiler warning. */ return -1; } nix/spawn.c1004440004150000170000002301305337263574011650 037777777777 1 0 uucp-1.04/unix/srmdir.c1004440004150000170000000470605337263575012031 037777777777 1 0 /* srmdir.c Remove a directory and all its contents. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FTW_H #include #endif static int isremove_dir P((const char *, const struct stat *, int)); /* Keep a list of directories to be removed. */ struct sdirlist { struct sdirlist *qnext; char *zdir; }; static struct sdirlist *qSdirlist; /* Remove a directory and all files in it. */ boolean fsysdep_rmdir (zdir) const char *zdir; { boolean fret; struct sdirlist *q; qSdirlist = NULL; fret = TRUE; if (ftw ((char *) zdir, isremove_dir, 5) != 0) { ulog (LOG_ERROR, "ftw: %s", strerror (errno)); fret = FALSE; } q = qSdirlist; while (q != NULL) { struct sdirlist *qnext; if (rmdir (q->zdir) != 0) { ulog (LOG_ERROR, "rmdir (%s): %s", q->zdir, strerror (errno)); fret = FALSE; } ubuffree (q->zdir); qnext = q->qnext; xfree ((pointer) q); q = qnext; } return fret; } /* Remove a file in a directory. */ /*ARGSUSED*/ static int isremove_dir (zfile, qstat, iflag) const char *zfile; const struct stat *qstat; int iflag; { if (iflag == FTW_D || iflag == FTW_DNR) { struct sdirlist *q; q = (struct sdirlist *) xmalloc (sizeof (struct sdirlist)); q->qnext = qSdirlist; q->zdir = zbufcpy (zfile); qSdirlist = q; } else { if (remove (zfile) != 0) ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); } return 0; } v; const char *zchdir; boolean fnosigs; boouucp-1.04/unix/statsb.c1004440004150000170000003001505337263575012021 037777777777 1 0 /* 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.10 1992/11/14 16:14:07 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ #if HAVE_TIME_H #include #endif #if HAVE_UTIME_H #include #endif /* Local functions. */ static int ussettime P((const char *z, time_t inow)); static boolean fskill_or_rejuv P((pointer puuconf, const char *zid, boolean fkill)); /* See whether the user is permitted to kill arbitrary jobs. This is true only for root and uucp. We check for uucp by seeing if the real user ID and the effective user ID are the same; this works because we should be suid to uucp, so our effective user ID will always be uucp while our real user ID will be whoever ran the program. */ boolean fsysdep_privileged () { uid_t iuid; iuid = getuid (); return iuid == 0 || iuid == geteuid (); } /* Set file access time to the present. On many systems this could be done by passing NULL to utime, but on some that doesn't work. This routine is not time critical, so we never rely on NULL. */ static int ussettime(z, inow) const char *z; time_t inow; { #if HAVE_UTIME_H struct utimbuf s; s.actime = inow; s.modtime = inow; return utime ((char *) z, &s); #else time_t ai[2]; ai[0] = inow; ai[1] = inow; return utime ((char *) z, ai); #endif } /* Kill a job, given the jobid. */ boolean fsysdep_kill_job (puuconf, zid) pointer puuconf; const char *zid; { return fskill_or_rejuv (puuconf, zid, TRUE); } /* Rejuvenate a job, given the jobid. */ boolean fsysdep_rejuvenate_job (puuconf, zid) pointer puuconf; const char *zid; { return fskill_or_rejuv (puuconf, zid, FALSE); } /* Kill or rejuvenate a job, given the jobid. */ static boolean fskill_or_rejuv (puuconf, zid, fkill) pointer puuconf; const char *zid; boolean fkill; { char *zfile; char *zsys; char bgrade; time_t inow = 0; int iuuconf; struct uuconf_system ssys; FILE *e; boolean fret; char *zline; size_t cline; int isys; zfile = zsjobid_to_file (zid, &zsys, &bgrade); if (zfile == NULL) return FALSE; if (! fkill) inow = time ((time_t *) NULL); iuuconf = uuconf_system_info (puuconf, zsys, &ssys); if (iuuconf == UUCONF_NOT_FOUND) { if (! funknown_system (puuconf, zsys, &ssys)) { ulog (LOG_ERROR, "%s: Bad job id", zid); ubuffree (zfile); ubuffree (zsys); return FALSE; } } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); ubuffree (zfile); ubuffree (zsys); return FALSE; } e = fopen (zfile, "r"); if (e == NULL) { if (errno == ENOENT) ulog (LOG_ERROR, "%s: Job not found", zid); else ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); (void) uuconf_system_free (puuconf, &ssys); ubuffree (zfile); ubuffree (zsys); return FALSE; } /* Now we have to read through the file to identify any temporary files. */ fret = TRUE; zline = NULL; cline = 0; while (getline (&zline, &cline, e) > 0) { struct scmd s; if (! fparse_cmd (zline, &s)) { ulog (LOG_ERROR, "Bad line in command file %s", zfile); fret = FALSE; continue; } /* You are only permitted to delete a job if you submitted it or if you are root or uucp. */ if (strcmp (s.zuser, zsysdep_login_name ()) != 0 && ! fsysdep_privileged ()) { ulog (LOG_ERROR, "%s: Not submitted by you", zid); xfree ((pointer) zline); (void) fclose (e); (void) uuconf_system_free (puuconf, &ssys); ubuffree (zfile); ubuffree (zsys); return FALSE; } if (s.bcmd == 'S' || s.bcmd == 'E') { char *ztemp; ztemp = zsfind_file (s.ztemp, ssys.uuconf_zname, bgrade); if (ztemp == NULL) fret = FALSE; else { if (fkill) isys = remove (ztemp); else isys = ussettime (ztemp, inow); if (isys != 0 && errno != ENOENT) { ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime", ztemp, strerror (errno)); fret = FALSE; } ubuffree (ztemp); } } } xfree ((pointer) zline); (void) fclose (e); (void) uuconf_system_free (puuconf, &ssys); ubuffree (zsys); if (fkill) isys = remove (zfile); else isys = ussettime (zfile, inow); if (isys != 0 && errno != ENOENT) { ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime", zfile, strerror (errno)); fret = FALSE; } ubuffree (zfile); return fret; } /* Get the time a work job was queued. */ long ixsysdep_work_time (qsys, pseq) const struct uuconf_system *qsys; pointer pseq; { char *zjobid, *zfile; long iret; zjobid = zsysdep_jobid (qsys, pseq); zfile = zsjobid_to_file (zjobid, (char **) NULL, (char *) NULL); if (zfile == NULL) return 0; ubuffree (zjobid); iret = ixsysdep_file_time (zfile); ubuffree (zfile); return iret; } /* Get the time a file was created (actually, the time it was last modified). */ long ixsysdep_file_time (zfile) const char *zfile; { struct stat s; if (stat ((char *) zfile, &s) < 0) { if (errno != ENOENT) ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); return ixsysdep_time ((long *) NULL); } return (long) s.st_mtime; } /* Start getting the status files. */ boolean fsysdep_all_status_init (phold) pointer *phold; { DIR *qdir; qdir = opendir ((char *) ".Status"); if (qdir == NULL) { ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno)); return FALSE; } *phold = (pointer) qdir; return TRUE; } /* Get the next status file. */ char * zsysdep_all_status (phold, pferr, qstat) pointer phold; boolean *pferr; struct sstatus *qstat; { DIR *qdir = (DIR *) phold; struct dirent *qentry; while (TRUE) { errno = 0; qentry = readdir (qdir); if (qentry == NULL) { if (errno == 0) *pferr = FALSE; else { ulog (LOG_ERROR, "readdir: %s", strerror (errno)); *pferr = TRUE; } return NULL; } if (qentry->d_name[0] != '.') { struct uuconf_system ssys; /* Hack seriously; fsysdep_get_status only looks at the zname element of the qsys argument, so if we fake that we can read the status file. This should really be done differently. */ ssys.uuconf_zname = qentry->d_name; if (fsysdep_get_status (&ssys, qstat, (boolean *) NULL)) return zbufcpy (qentry->d_name); /* If fsysdep_get_status fails, it will output an error message. We just continue with the next entry, so that most of the status files will be displayed. */ } } } /* Finish getting the status file. */ void usysdep_all_status_free (phold) pointer phold; { DIR *qdir = (DIR *) phold; (void) closedir (qdir); } /* Get the status of all processes holding lock files. We do this by invoking ps after we've figured out the process entries to use. */ boolean fsysdep_lock_status () { DIR *qdir; struct dirent *qentry; int calc; int *pai; int cgot; int aidescs[3]; char *zcopy, *ztok; int cargs, iarg; char **pazargs; qdir = opendir ((char *) zSlockdir); if (qdir == NULL) { ulog (LOG_ERROR, "opendir (%s): %s", zSlockdir, strerror (errno)); return FALSE; } /* We look for entries that start with "LCK.." and ignore everything else. This won't find all possible lock files, but it should find all the locks on terminals and systems. */ calc = 0; pai = NULL; cgot = 0; while ((qentry = readdir (qdir)) != NULL) { char *zname; int o; #if HAVE_V2_LOCKFILES int i; #else char ab[12]; #endif int cread; int ierr; int ipid; if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0) continue; zname = zsysdep_in_dir (zSlockdir, qentry->d_name); o = open ((char *) zname, O_RDONLY | O_NOCTTY, 0); if (o < 0) { if (errno != ENOENT) ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno)); ubuffree (zname); continue; } #if HAVE_V2_LOCKFILES cread = read (o, &i, sizeof i); #else cread = read (o, ab, sizeof ab - 1); #endif ierr = errno; (void) close (o); if (cread < 0) { ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr)); ubuffree (zname); continue; } ubuffree (zname); #if HAVE_V2_LOCKFILES ipid = i; #else ab[cread] = '\0'; ipid = strtol (ab, (char **) NULL, 10); #endif printf ("%s: %d\n", qentry->d_name, ipid); if (cgot >= calc) { calc += 10; pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int)); } pai[cgot] = ipid; ++cgot; } if (cgot == 0) return TRUE; aidescs[0] = SPAWN_NULL; aidescs[1] = 1; aidescs[2] = 2; /* Parse PS_PROGRAM into an array of arguments. */ zcopy = zbufcpy (PS_PROGRAM); cargs = 0; for (ztok = strtok (zcopy, " \t"); ztok != NULL; ztok = strtok ((char *) NULL, " \t")) ++cargs; pazargs = (char **) xmalloc ((cargs + 1) * sizeof (char *)); memcpy (zcopy, PS_PROGRAM, sizeof PS_PROGRAM); for (ztok = strtok (zcopy, " \t"), iarg = 0; ztok != NULL; ztok = strtok ((char *) NULL, " \t"), ++iarg) pazargs[iarg] = ztok; pazargs[iarg] = NULL; #if ! HAVE_PS_MULTIPLE /* We have to invoke ps multiple times. */ { int i; char *zlast, *zset; zlast = pazargs[cargs - 1]; zset = zbufalc (strlen (zlast) + 20); for (i = 0; i < cgot; i++) { pid_t ipid; sprintf (zset, "%s%d", zlast, pai[i]); pazargs[cargs - 1] = zset; ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); else (void) ixswait ((unsigned long) ipid, PS_PROGRAM); } ubuffree (zset); } #else { char *zlast; int i; pid_t ipid; zlast = zbufalc (strlen (pazargs[cargs - 1]) + cgot * 20 + 1); strcpy (zlast, pazargs[cargs - 1]); for (i = 0; i < cgot; i++) { char ab[20]; sprintf (ab, "%d", pai[i]); strcat (zlast, ab); if (i + 1 < cgot) strcat (zlast, ","); } pazargs[cargs - 1] = zlast; ipid = ixsspawn ((const char **) pazargs, aidescs, FALSE, FALSE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); else (void) ixswait ((unsigned long) ipid, PS_PROGRAM); ubuffree (zlast); } #endif ubuffree (zcopy); xfree ((pointer) pazargs); return TRUE; } ; 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 ussettuucp-1.04/unix/status.c1004440004150000170000001164205337263576012052 037777777777 1 0 /* status.c Routines to get and set the status for a system. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "uuconf.h" #include "sysdep.h" #include "system.h" #include #if SPOOLDIR_HDB || SPOOLDIR_SVR4 /* If we are using HDB spool layout, store status using HDB status values. SVR4 is a variant of HDB. */ #define MAP_STATUS 1 static const int aiMapstatus[] = { 0, 13, 7, 6, 4, 20, 3, 2 }; #define CMAPENTRIES (sizeof (aiMapstatus) / sizeof (aiMapstatus[0])) #else /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ #define MAP_STATUS 0 #endif /* ! SPOOLDIR_HDB && ! SPOOLDIR_SVR4 */ /* Get the status of a system. This assumes that we are in the spool directory. */ boolean fsysdep_get_status (qsys, qret, pfnone) const struct uuconf_system *qsys; struct sstatus *qret; boolean *pfnone; { char *zname; FILE *e; char *zline; char *zend, *znext; boolean fbad; int istat; if (pfnone != NULL) *pfnone = FALSE; zname = zsysdep_in_dir (".Status", qsys->uuconf_zname); e = fopen (zname, "r"); if (e == NULL) { if (errno != ENOENT) { ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); ubuffree (zname); return FALSE; } zline = NULL; } else { size_t cline; zline = NULL; cline = 0; if (getline (&zline, &cline, e) <= 0) { xfree ((pointer) zline); zline = NULL; } (void) fclose (e); } if (zline == NULL) { /* There is either no status file for this system, or it's been truncated, so fake a good status. */ qret->ttype = STATUS_COMPLETE; qret->cretries = 0; qret->ilast = 0; qret->cwait = 0; if (pfnone != NULL) *pfnone = TRUE; ubuffree (zname); return TRUE; } /* It turns out that scanf is not used much in this program, so for the benefit of small computers we avoid linking it in. This is basically sscanf (zline, "%d %d %ld %d", &qret->ttype, &qret->cretries, &qret->ilast, &qret->cwait); except that it's done with strtol. */ fbad = FALSE; istat = (int) strtol (zline, &zend, 10); if (zend == zline) fbad = TRUE; #if MAP_STATUS /* On some systems it may be appropriate to map system dependent status values on to our status values. */ { int i; for (i = 0; i < CMAPENTRIES; ++i) { if (aiMapstatus[i] == istat) { istat = i; break; } } } #endif /* MAP_STATUS */ if (istat < 0 || istat >= (int) STATUS_VALUES) istat = (int) STATUS_COMPLETE; qret->ttype = (enum tstatus_type) istat; znext = zend; qret->cretries = (int) strtol (znext, &zend, 10); if (zend == znext) fbad = TRUE; znext = zend; qret->ilast = strtol (znext, &zend, 10); if (zend == znext) fbad = TRUE; znext = zend; qret->cwait = (int) strtol (znext, &zend, 10); if (zend == znext) fbad = TRUE; xfree ((pointer) zline); if (fbad) { ulog (LOG_ERROR, "%s: Bad status file format", zname); ubuffree (zname); return FALSE; } ubuffree (zname); return TRUE; } /* Set the status of a remote system. This assumes the system is locked when this is called, and that the program is in the spool directory. */ boolean fsysdep_set_status (qsys, qset) const struct uuconf_system *qsys; const struct sstatus *qset; { char *zname; FILE *e; int istat; zname = zsysdep_in_dir (".Status", qsys->uuconf_zname); e = esysdep_fopen (zname, TRUE, FALSE, TRUE); ubuffree (zname); if (e == NULL) return FALSE; istat = (int) qset->ttype; #if MAP_STATUS /* On some systems it may be appropriate to map istat onto a system dependent number. */ if (istat >= 0 && istat < CMAPENTRIES) istat = aiMapstatus[istat]; #endif /* MAP_STATUS */ fprintf (e, "%d %d %ld %d %s %s\n", istat, qset->cretries, qset->ilast, qset->cwait, azStatus[(int) qset->ttype], qsys->uuconf_zname); if (fclose (e) != 0) { ulog (LOG_ERROR, "fclose: %s", strerror (errno)); return FALSE; } return TRUE; } We just continue with the next entry, so that most of the status files will be displayeduucp-1.04/unix/strerr.c1004440004150000170000000052705337263576012050 037777777777 1 0 /* strerr.c Return a string for a Unix errno value. */ #include "uucp.h" #include #ifndef sys_nerr extern int sys_nerr; #endif #ifndef sys_errlist extern char *sys_errlist[]; #endif char * strerror (ierr) int ierr; { if (ierr >= 0 && ierr < sys_nerr) return sys_errlist[ierr]; return (char *) "unknown error"; } . */ calc = 0; pai = NULL; cgot = 0; while ((qentry = readdir (qdir)) != NULL) { char *zname; int o; #if HAVE_V2_LOCKFILES int i; #else uucp-1.04/unix/time.c1004440004150000170000000117205337263576011462 037777777777 1 0 /* time.c Get the current time. */ #include "uucp.h" #if HAVE_TIME_H #include #endif #include "system.h" #ifndef time extern time_t time (); #endif /* Get the time in seconds since the epoch, with optional microseconds. We use ixsysdep_process_time to get the microseconds if it will work (it won't if it uses times, since that returns a time based only on the process). */ long ixsysdep_time (pimicros) long *pimicros; { #if HAVE_GETTIMEOFDAY || HAVE_FTIME return ixsysdep_process_time (pimicros); #else if (pimicros != NULL) *pimicros = 0; return (long) time ((time_t *) NULL); #endif } ] = 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; uucp-1.04/unix/tmpfil.c1004440004150000170000000372505337263576012025 037777777777 1 0 /* 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 } uucp-1.04/unix/trunc.c1004440004150000170000000631205337263577011661 037777777777 1 0 /* trunc.c Truncate a file to zero length. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif /* External functions. */ #ifndef lseek extern off_t lseek (); #endif /* Truncate a file to zero length. If this fails, it closes and removes the file. We support a number of different means of truncation, which is probably a waste of time since this function is currently only called when the 'f' protocol resends a file. */ #if HAVE_FTRUNCATE #undef HAVE_LTRUNC #define HAVE_LTRUNC 0 #endif #if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC #ifdef F_CHSIZE #define HAVE_F_CHSIZE 1 #else /* ! defined (F_CHSIZE) */ #ifdef F_FREESP #define HAVE_F_FREESP 1 #endif /* defined (F_FREESP) */ #endif /* ! defined (F_CHSIZE) */ #endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */ openfile_t esysdep_truncate (e, zname) openfile_t e; const char *zname; { int o; #if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP int itrunc; if (! ffilerewind (e)) { ulog (LOG_ERROR, "rewind: %s", strerror (errno)); (void) ffileclose (e); (void) remove (zname); return EFILECLOSED; } #if USE_STDIO o = fileno (e); #else o = e; #endif #if HAVE_FTRUNCATE itrunc = ftruncate (o, 0); #endif #if HAVE_LTRUNC itrunc = ltrunc (o, (long) 0, SEEK_SET); #endif #if HAVE_F_CHSIZE itrunc = fcntl (o, F_CHSIZE, (off_t) 0); #endif #if HAVE_F_FREESP /* This selection is based on an implementation of ftruncate by kucharsk@Solbourne.com (William Kucharski). */ { struct flock fl; fl.l_whence = 0; fl.l_len = 0; fl.l_start = 0; fl.l_type = F_WRLCK; itrunc = fcntl (o, F_FREESP, &fl); } #endif if (itrunc != 0) { #if HAVE_FTRUNCATE ulog (LOG_ERROR, "ftruncate: %s", strerror (errno)); #endif #ifdef HAVE_LTRUNC ulog (LOG_ERROR, "ltrunc: %s", strerror (errno)); #endif #ifdef HAVE_F_CHSIZE ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno)); #endif #ifdef HAVE_F_FREESP ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno)); #endif (void) ffileclose (e); (void) remove (zname); return EFILECLOSED; } return e; #else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */ (void) ffileclose (e); (void) remove (zname); o = creat ((char *) zname, IPRIVATE_FILE_MODE); if (o == -1) { ulog (LOG_ERROR, "creat (%s): %s", zname, strerror (errno)); return EFILECLOSED; } if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) close (o); return EFILECLOSED; } #if USE_STDIO e = fdopen (o, (char *) BINWRITE); if (e == NULL) { ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno)); (void) close (o); (void) remove (zname); return NULL; } #else /* ! USE_STDIO */ e = o; #endif /* ! USE_STDIO */ return e; #endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */ } (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 tuucp-1.04/unix/uacces.c1004440004150000170000001072405337263577011773 037777777777 1 0 /* uacces.c Check access to a file by user name. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include #include #if HAVE_GETGRENT #include #if GETGRENT_DECLARATION_OK #ifndef getgrent extern struct group *getgrent (); #endif #endif #endif /* HAVE_GETGRENT */ #if GETPWNAM_DECLARATION_OK #ifndef getpwnam extern struct passwd *getpwnam (); #endif #endif /* Do access(2) on a stat structure, except that the user name is provided. If the user name in zuser is NULL, require the file to be accessible to the world. Return TRUE if access is permitted, FALSE otherwise. This does not log an error message. */ boolean fsuser_access (q, imode, zuser) const struct stat *q; int imode; const char *zuser; { static char *zuser_hold; static uid_t iuid_hold; static gid_t igid_hold; static int cgroups_hold; static gid_t *paigroups_hold; int ir, iw, ix, iand; if (imode == F_OK) return TRUE; if (zuser != NULL) { /* We keep static variables around for the last user we did, to avoid looking up a user multiple times. */ if (zuser_hold == NULL || strcmp (zuser_hold, zuser) != 0) { struct passwd *qpwd; if (zuser_hold != NULL) { ubuffree (zuser_hold); zuser_hold = NULL; cgroups_hold = 0; xfree ((pointer) paigroups_hold); paigroups_hold = NULL; } qpwd = getpwnam ((char *) zuser); if (qpwd == NULL) { /* Check this as a remote request. */ zuser = NULL; } else { #if HAVE_GETGRENT struct group *qg; #endif zuser_hold = zbufcpy (zuser); iuid_hold = qpwd->pw_uid; igid_hold = qpwd->pw_gid; #if HAVE_GETGRENT /* Get the list of groups for this user. This is definitely more appropriate for BSD than for System V. It may just be a waste of time, and perhaps it should be configurable. */ setgrent (); while ((qg = getgrent ()) != NULL) { const char **pz; if (qg->gr_gid == igid_hold) continue; for (pz = (const char **) qg->gr_mem; *pz != NULL; pz++) { if ((*pz)[0] == *zuser && strcmp (*pz, zuser) == 0) { paigroups_hold = ((gid_t *) (xrealloc ((pointer) paigroups_hold, ((cgroups_hold + 1) * sizeof (gid_t))))); paigroups_hold[cgroups_hold] = qg->gr_gid; ++cgroups_hold; break; } } } endgrent (); #endif } } } /* Now do the actual access check. */ if (zuser != NULL) { /* The superuser can do anything. */ if (iuid_hold == 0) return TRUE; /* If this is the uid we're running under, there's no point to checking access further, because when we actually try the operation the system will do the checking for us. */ if (iuid_hold == geteuid ()) return TRUE; } ir = S_IROTH; iw = S_IWOTH; ix = S_IXOTH; if (zuser != NULL) { if (iuid_hold == q->st_uid) { ir = S_IRUSR; iw = S_IWUSR; ix = S_IXUSR; } else { boolean fgroup; fgroup = FALSE; if (igid_hold == q->st_gid) fgroup = TRUE; else { int i; for (i = 0; i < cgroups_hold; i++) { if (paigroups_hold[i] == q->st_gid) { fgroup = TRUE; break; } } } if (fgroup) { ir = S_IRGRP; iw = S_IWGRP; ix = S_IXGRP; } } } iand = 0; if ((imode & R_OK) != 0) iand |= ir; if ((imode & W_OK) != 0) iand |= iw; if ((imode & X_OK) != 0) iand |= ix; return (q->st_mode & iand) == iand; } ude "uucp.h" #include "uuconf.h" #include "uucp-1.04/unix/ufopen.c1004440004150000170000001227505337263577012027 037777777777 1 0 /* ufopen.c Open a file with the permissions of the invoking user. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif /* Local functions. */ static boolean fsuser_perms P((uid_t *pieuid)); static boolean fsuucp_perms P((long ieuid)); /* Switch to permissions of the invoking user. */ static boolean fsuser_perms (pieuid) uid_t *pieuid; { uid_t ieuid, iuid; ieuid = geteuid (); iuid = getuid (); if (pieuid != NULL) *pieuid = ieuid; #if HAVE_SETREUID /* Swap the effective user id and the real user id. We can then swap them back again when we want to return to the uucp user's permissions. */ if (setreuid (ieuid, iuid) < 0) { ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", (long) ieuid, (long) iuid, strerror (errno)); return FALSE; } #else /* ! HAVE_SETREUID */ #if HAVE_SAVED_SETUID /* Set the effective user id to the real user id. Since the effective user id is saved (it's the saved setuid) we will able to set back to it later. If the real user id is root we will not be able to switch back and forth, so don't even try. */ if (iuid != 0) { if (setuid (iuid) < 0) { ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno)); return FALSE; } } #else /* ! HAVE_SAVED_SETUID */ /* There's no way to switch between real permissions and effective permissions. Just try to open the file with the uucp permissions. */ #endif /* ! HAVE_SAVED_SETUID */ #endif /* ! HAVE_SETREUID */ return TRUE; } /* Restore the uucp permissions. */ /*ARGSUSED*/ static boolean fsuucp_perms (ieuid) long ieuid; { #if HAVE_SETREUID /* Swap effective and real user id's back to what they were. */ if (! fsuser_perms ((uid_t *) NULL)) return FALSE; #else /* ! HAVE_SETREUID */ #if HAVE_SAVED_SETUID /* Set ourselves back to our original effective user id. */ if (setuid ((uid_t) ieuid) < 0) { ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno)); /* Is this error message helpful or confusing? */ if (errno == EPERM) ulog (LOG_ERROR, "Probably HAVE_SAVED_SETUID in policy.h should be set to 0"); return FALSE; } #else /* ! HAVE_SAVED_SETUID */ /* We didn't switch, no need to switch back. */ #endif /* ! HAVE_SAVED_SETUID */ #endif /* ! HAVE_SETREUID */ return TRUE; } /* Open a file with the permissions of the invoking user. Ignore the fbinary argument since Unix has no distinction between text and binary files. */ /*ARGSUSED*/ openfile_t esysdep_user_fopen (zfile, frd, fbinary) const char *zfile; boolean frd; boolean fbinary; { uid_t ieuid; openfile_t e; const char *zerr; int o = 0; if (! fsuser_perms (&ieuid)) return EFILECLOSED; zerr = NULL; #if USE_STDIO e = fopen (zfile, frd ? "r" : "w"); if (e == NULL) zerr = "fopen"; else o = fileno (e); #else if (frd) { e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0); zerr = "open"; } else { e = creat ((char *) zfile, IPUBLIC_FILE_MODE); zerr = "creat"; } if (e >= 0) { o = e; zerr = NULL; } #endif if (! fsuucp_perms ((long) ieuid)) { if (ffileisopen (e)) (void) ffileclose (e); return EFILECLOSED; } if (zerr != NULL) { ulog (LOG_ERROR, "%s (%s): %s", zerr, zfile, strerror (errno)); #if ! HAVE_SETREUID /* Are these error messages helpful or confusing? */ #if HAVE_SAVED_SETUID if (errno == EACCES && getuid () == 0) ulog (LOG_ERROR, "The superuser may only transfer files that are readable by %s", OWNER); #else if (errno == EACCES) ulog (LOG_ERROR, "You may only transfer files that are readable by %s", OWNER); #endif #endif /* ! HAVE_SETREUID */ return EFILECLOSED; } if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); (void) ffileclose (e); return EFILECLOSED; } return e; } stribute 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 impuucp-1.04/unix/ultspl.c1004440004150000170000000054605337263577012054 037777777777 1 0 /* 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; } ser 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, FAuucp-1.04/unix/unknwn.c1004440004150000170000000173205337263600012032 037777777777 1 0 /* unknwn.c Check remote.unknown shell script. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include /* Run the remote.unknown shell script. If it succeeds, we return FALSE because that means that the system is not permitted to log in. If the execution fails, we return TRUE. */ boolean fsysdep_unknown_caller (zscript, zsystem) const char *zscript; const char *zsystem; { const char *azargs[3]; int aidescs[3]; pid_t ipid; azargs[0] = zscript; azargs[1] = zsystem; azargs[2] = NULL; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ipid = ixsspawn (azargs, aidescs, TRUE, TRUE, (const char *) NULL, FALSE, TRUE, (const char *) NULL, (const char *) NULL, (const char *) NULL); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn: %s", strerror (errno)); return FALSE; } return ixswait ((unsigned long) ipid, (const char *) NULL) != 0; } em; *pz != NULL; pz++) { uucp-1.04/unix/uuto.c1004440004150000170000000123005337263600011477 037777777777 1 0 /* 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; } 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; } ude "uucp.h" #include "uuconf.h" #include "uucp-1.04/unix/walk.c1004440004150000170000000207205337263600011446 037777777777 1 0 /* walk.c Walk a directory tree. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #if HAVE_FTW_H #include #endif static int iswalk_dir P((const char *zname, const struct stat *qstat, int iflag)); /* Walk a directory tree. */ static size_t cSlen; static void (*puSfn) P((const char *zfull, const char *zrelative, pointer pinfo)); static pointer pSinfo; boolean usysdep_walk_tree (zdir, pufn, pinfo) const char *zdir; void (*pufn) P((const char *zfull, const char *zrelative, pointer pinfo)); pointer pinfo; { cSlen = strlen (zdir) + 1; puSfn = pufn; pSinfo = pinfo; return ftw ((char *) zdir, iswalk_dir, 5) == 0; } /* Pass a file found in the directory tree to the system independent function. */ /*ARGSUSED*/ static int iswalk_dir (zname, qstat, iflag) const char *zname; const struct stat *qstat; int iflag; { char *zcopy; if (iflag != FTW_F) return 0; zcopy = zbufcpy (zname + cSlen); (*puSfn) (zname, zcopy, pSinfo); ubuffree (zcopy); return 0; } ude #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif /* Local functions. */ static boolean fsuser_perms P((uid_t *pieuid)); static boolean fsuucp_perms P((long ieuid)); /* Switch to permissions of the invoking user. uucp-1.04/unix/wldcrd.c1004440004150000170000001062105337263600011766 037777777777 1 0 /* wldcrd.c Expand wildcards. Copyright (C) 1991, 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #include #if HAVE_GLOB && ! HAVE_GLOB_H #undef HAVE_GLOB #define HAVE_GLOB 0 #endif #if HAVE_GLOB #include #endif /* Local variables to hold the wildcard in progress. */ #if HAVE_GLOB static glob_t sSglob; static int iSglob; #else static char *zSwildcard_alloc; static char *zSwildcard; #endif /* Start getting a wildcarded file spec. Use the glob function if it is available, and otherwise use the shell. */ boolean fsysdep_wildcard_start (zfile) const char *zfile; { #if HAVE_GLOB #if DEBUG > 0 if (*zfile != '/') ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile); #endif if (glob (zfile, 0, (int (*) ()) NULL, &sSglob) != 0) sSglob.gl_pathc = 0; iSglob = 0; return TRUE; #else /* ! HAVE_GLOB */ char *zcmd, *zto; const char *zfrom; size_t c; const char *azargs[4]; FILE *e; pid_t ipid; #if DEBUG > 0 if (*zfile != '/') ulog (LOG_FATAL, "fsysdep_wildcard: %s: Can't happen", zfile); #endif zSwildcard_alloc = NULL; zSwildcard = NULL; zcmd = zbufalc (sizeof ECHO_PROGRAM + sizeof " " + 2 * strlen (zfile)); memcpy (zcmd, ECHO_PROGRAM, sizeof ECHO_PROGRAM - 1); zto = zcmd + sizeof ECHO_PROGRAM - 1; *zto++ = ' '; zfrom = zfile; while (*zfrom != '\0') { /* To avoid shell trickery, we quote all characters except letters, digits, and wildcard specifiers. We don't quote '/' to avoid an Ultrix sh bug. */ if (! isalnum (*zfrom) && *zfrom != '*' && *zfrom != '?' && *zfrom != '[' && *zfrom != ']' && *zfrom != '/') *zto++ = '\\'; *zto++ = *zfrom++; } *zto = '\0'; azargs[0] = "/bin/sh"; azargs[1] = "-c"; azargs[2] = zcmd; azargs[3] = NULL; ubuffree (zcmd); e = espopen (azargs, TRUE, &ipid); if (e == NULL) { ulog (LOG_ERROR, "espopen: %s", strerror (errno)); return FALSE; } zSwildcard_alloc = NULL; c = 0; if (getline (&zSwildcard_alloc, &c, e) <= 0) { xfree ((pointer) zSwildcard_alloc); zSwildcard_alloc = NULL; } if (ixswait ((unsigned long) ipid, ECHO_PROGRAM) != 0) { xfree ((pointer) zSwildcard_alloc); return FALSE; } if (zSwildcard_alloc == NULL) return FALSE; DEBUG_MESSAGE1 (DEBUG_EXECUTE, "fsysdep_wildcard_start: got \"%s\"", zSwildcard_alloc); zSwildcard = zSwildcard_alloc; return TRUE; #endif /* ! HAVE_GLOB */ } /* Get the next wildcard spec. */ /*ARGSUSED*/ char * zsysdep_wildcard (zfile) const char *zfile; { #if HAVE_GLOB char *zret; if (iSglob >= sSglob.gl_pathc) return NULL; zret = zbufcpy (sSglob.gl_pathv[iSglob]); ++iSglob; return zret; #else /* ! HAVE_GLOB */ char *zret; if (zSwildcard_alloc == NULL || zSwildcard == NULL) return NULL; zret = zSwildcard; while (*zSwildcard != '\0' && ! isspace (BUCHAR (*zSwildcard))) ++zSwildcard; if (*zSwildcard != '\0') { *zSwildcard = '\0'; ++zSwildcard; while (*zSwildcard != '\0' && isspace (BUCHAR (*zSwildcard))) ++zSwildcard; } if (*zSwildcard == '\0') zSwildcard = NULL; return zbufcpy (zret); #endif /* ! HAVE_GLOB */ } /* Finish up getting wildcard specs. */ boolean fsysdep_wildcard_end () { #if HAVE_GLOB globfree (&sSglob); return TRUE; #else /* ! HAVE_GLOB */ xfree ((pointer) zSwildcard_alloc); zSwildcard_alloc = NULL; zSwildcard = NULL; return TRUE; #endif /* ! HAVE_GLOB */ } in zuser is NULL, require the file to be accessible to the world. Return TRUE if access is permitted, FAuucp-1.04/unix/work.c1004440004150000170000004634005337263601011501 037777777777 1 0 /* 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.10 1992/11/14 16:14:07 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "sysdep.h" #include #include #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ /* Local functions. */ static char *zswork_directory P((const char *zsystem)); static boolean fswork_file P((const char *zsystem, const char *zfile, char *pbgrade)); static int iswork_cmp P((constpointer pkey, constpointer pdatum)); /* These functions can support multiple actions going on at once. This allows the UUCP package to send and receive multiple files at the same time. This is a very flexible feature, but I'm not sure it will actually be used all that much. The ssfile structure holds a command file name and all the lines read in from that command file. The union within the ssline structure initially holds a line from the file and then holds a pointer back to the ssfile structure; a pointer to this union is used as a sequence pointer. The ztemp entry of the ssline structure holds the name of a temporary file to delete, if any. */ #define CFILELINES (10) struct ssline { char *zline; struct ssfile *qfile; char *ztemp; }; struct ssfile { char *zfile; int clines; int cdid; struct ssline aslines[CFILELINES]; }; /* Static variables for the work scan. */ static char **azSwork_files; static size_t cSwork_files; static size_t iSwork_file; static struct ssfile *qSwork_file; /* Given a system name, return a directory to search for work. */ static char * zswork_directory (zsystem) const char *zsystem; { #if SPOOLDIR_V2 return zbufcpy ("."); #endif /* SPOOLDIR_V2 */ #if SPOOLDIR_BSD42 || SPOOLDIR_BSD43 return zbufcpy ("C."); #endif /* SPOOLDIR_BSD42 || SPOOLDIR_BSD43 */ #if SPOOLDIR_HDB || SPOOLDIR_SVR4 return zbufcpy (zsystem); #endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */ #if SPOOLDIR_ULTRIX return zsappend3 ("sys", (fsultrix_has_spool (zsystem) ? zsystem : "DEFAULT"), "C."); #endif /* SPOOLDIR_ULTRIX */ #if SPOOLDIR_TAYLOR return zsysdep_in_dir (zsystem, "C."); #endif /* SPOOLDIR_TAYLOR */ } /* See whether a file name from the directory returned by zswork_directory is really a command for a particular system. Return the command grade. */ /*ARGSUSED*/ static boolean fswork_file (zsystem, zfile, pbgrade) const char *zsystem; const char *zfile; char *pbgrade; { #if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX int cfilesys, csys; /* The file name should be C.ssssssgqqqq, where g is exactly one letter and qqqq is exactly four numbers. The system name may be truncated to six or seven characters. The system name of the file must match the system name we're looking for, since there could be work files for several systems in one directory. */ if (zfile[0] != 'C' || zfile[1] != '.') return FALSE; csys = strlen (zsystem); cfilesys = strlen (zfile) - 7; if (csys != cfilesys && (csys < 6 || (cfilesys != 6 && cfilesys != 7))) return FALSE; *pbgrade = zfile[cfilesys + 2]; return strncmp (zfile + 2, zsystem, cfilesys) == 0; #endif /* V2 || BSD42 || BSD43 || ULTRIX */ #if SPOOLDIR_HDB || SPOOLDIR_SVR4 int clen; /* The HDB file name should be C.ssssssgqqqq where g is exactly one letter and qqqq is exactly four numbers or letters. We don't check the system name, because it is guaranteed by the directory we are looking in and some versions of uucp set it to the local system rather than the remote one. I'm not sure of the exact format of the SVR4 file name, but it does not include the grade at all. */ if (zfile[0] != 'C' || zfile[1] != '.') return FALSE; clen = strlen (zfile); if (clen < 7) return FALSE; #if ! SPOOLDIR_SVR4 *pbgrade = zfile[clen - 5]; #endif return TRUE; #endif /* SPOOLDIR_HDB || SPOOLDIR_SVR4 */ #if SPOOLDIR_TAYLOR /* We don't keep the system name in the file name, since that forces truncation. Our file names are always C.gqqqq. */ *pbgrade = zfile[2]; return (zfile[0] == 'C' && zfile[1] == '.' && strlen (zfile) == 7); #endif /* SPOOLDIR_TAYLOR */ } /* A comparison function to look through the list of file names. */ static int iswork_cmp (pkey, pdatum) constpointer pkey; constpointer pdatum; { const char * const *pzkey = (const char * const *) pkey; const char * const *pzdatum = (const char * const *) pdatum; return strcmp (*pzkey, *pzdatum); } /* See whether there is any work to do for a particular system. */ boolean fsysdep_has_work (qsys) const struct uuconf_system *qsys; { char *zdir; DIR *qdir; struct dirent *qentry; #if SPOOLDIR_SVR4 DIR *qgdir; struct dirent *qgentry; #endif zdir = zswork_directory (qsys->uuconf_zname); if (zdir == NULL) return FALSE; qdir = opendir ((char *) zdir); if (qdir == NULL) { ubuffree (zdir); return FALSE; } #if SPOOLDIR_SVR4 qgdir = qdir; while ((qgentry = readdir (qgdir)) != NULL) { char *zsub; if (qgentry->d_name[0] == '.' || qgentry->d_name[1] != '\0') continue; zsub = zsysdep_in_dir (zdir, qgentry->d_name); qdir = opendir (zsub); ubuffree (zsub); if (qdir == NULL) continue; #endif while ((qentry = readdir (qdir)) != NULL) { char bgrade; if (fswork_file (qsys->uuconf_zname, qentry->d_name, &bgrade)) { closedir (qdir); #if SPOOLDIR_SVR4 closedir (qgdir); #endif ubuffree (zdir); return TRUE; } } #if SPOOLDIR_SVR4 closedir (qdir); } qdir = qgdir; #endif closedir (qdir); ubuffree (zdir); return FALSE; } /* Initialize the work scan. We have to read all the files in the work directory, so that we can sort them by work grade. The bgrade argument is the minimum grade to consider. We don't want to return files that we have already considered; usysdep_get_work_free will clear the data out when we are done with the system. This returns FALSE on error. */ #define CWORKFILES (10) boolean fsysdep_get_work_init (qsys, bgrade) const struct uuconf_system *qsys; int bgrade; { char *zdir; DIR *qdir; struct dirent *qentry; size_t chad; size_t callocated; #if SPOOLDIR_SVR4 DIR *qgdir; struct dirent *qgentry; #endif zdir = zswork_directory (qsys->uuconf_zname); if (zdir == NULL) return FALSE; qdir = opendir (zdir); if (qdir == NULL) { boolean fret; if (errno == ENOENT) fret = TRUE; else { ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno)); fret = FALSE; } ubuffree (zdir); return fret; } chad = cSwork_files; callocated = cSwork_files; /* Sort the files we already know about so that we can check the new ones with bsearch. It would be faster to use a hash table, and the code should be probably be changed. The sort done at the end of this function does not suffice because it only includes the files added last time, and does not sort the entire array. Some (bad) qsort implementations are very slow when given a sorted array, which causes particularly bad effects here. */ if (chad > 0) qsort ((pointer) azSwork_files, chad, sizeof (char *), iswork_cmp); #if SPOOLDIR_SVR4 qgdir = qdir; while ((qgentry = readdir (qgdir)) != NULL) { char *zsub; if (qgentry->d_name[0] == '.' || qgentry->d_name[1] != '\0' || UUCONF_GRADE_CMP (bgrade, qgentry->d_name[0]) < 0) continue; zsub = zsysdep_in_dir (zdir, qgentry->d_name); qdir = opendir (zsub); if (qdir == NULL) { if (errno != ENOTDIR && errno != ENOENT) { ulog (LOG_ERROR, "opendir (%s): %s", zsub, strerror (errno)); ubuffree (zsub); return FALSE; } ubuffree (zsub); continue; } ubuffree (zsub); #endif while ((qentry = readdir (qdir)) != NULL) { char bfilegrade; char *zname; #if ! SPOOLDIR_SVR4 zname = zbufcpy (qentry->d_name); #else zname = zsysdep_in_dir (qgentry->d_name, qentry->d_name); bfilegrade = qgentry->d_name[0]; #endif if (! fswork_file (qsys->uuconf_zname, qentry->d_name, &bfilegrade) || UUCONF_GRADE_CMP (bgrade, bfilegrade) < 0 || (azSwork_files != NULL && bsearch ((pointer) &zname, (pointer) azSwork_files, chad, sizeof (char *), iswork_cmp) != NULL)) ubuffree (zname); else { DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "fsysdep_get_work_init: Found %s", zname); if (cSwork_files >= callocated) { callocated += CWORKFILES; azSwork_files = (char **) xrealloc ((pointer) azSwork_files, callocated * sizeof (char *)); } azSwork_files[cSwork_files] = zname; ++cSwork_files; } } #if SPOOLDIR_SVR4 closedir (qdir); } qdir = qgdir; #endif closedir (qdir); ubuffree (zdir); /* Sorting the files alphabetically will get the grades in the right order, since all the file prefixes are the same. */ if (cSwork_files > chad) qsort ((pointer) (azSwork_files + chad), cSwork_files - chad, sizeof (char *), iswork_cmp); return TRUE; } /* Get the next work entry for a system. This must parse the next line in the next work file. The type of command is set into qcmd->bcmd; if there are no more commands we call fsysdep_get_work_init to rescan, in case any came in since the last call. If there are still no commands, qcmd->bcmd is set to 'H'. Each field in the structure is set to point to a spot in an malloced string. The only time we use the grade here is when calling fsysdep_get_work_init to rescan. */ boolean fsysdep_get_work (qsys, bgrade, qcmd) const struct uuconf_system *qsys; int bgrade; struct scmd *qcmd; { char *zdir; if (qSwork_file != NULL && qSwork_file->cdid >= qSwork_file->clines) qSwork_file = NULL; if (azSwork_files == NULL) { qcmd->bcmd = 'H'; return TRUE; } zdir = NULL; /* This loop continues until a line is returned. */ while (TRUE) { /* This loop continues until a file is opened and read in. */ while (qSwork_file == NULL) { FILE *e; struct ssfile *qfile; int iline, callocated; char *zline; size_t cline; char *zname; /* Read all the lines of a command file into memory. */ do { if (iSwork_file >= cSwork_files) { /* Rescan the work directory. */ if (! fsysdep_get_work_init (qsys, bgrade)) { ubuffree (zdir); return FALSE; } if (iSwork_file >= cSwork_files) { qcmd->bcmd = 'H'; ubuffree (zdir); return TRUE; } } if (zdir == NULL) { zdir = zswork_directory (qsys->uuconf_zname); if (zdir == NULL) return FALSE; } zname = zsysdep_in_dir (zdir, azSwork_files[iSwork_file]); ++iSwork_file; e = fopen (zname, "r"); if (e == NULL) { ulog (LOG_ERROR, "fopen (%s): %s", zname, strerror (errno)); ubuffree (zname); } } while (e == NULL); qfile = (struct ssfile *) xmalloc (sizeof (struct ssfile)); callocated = CFILELINES; iline = 0; zline = NULL; cline = 0; while (getline (&zline, &cline, e) > 0) { if (iline >= callocated) { /* The sizeof (struct ssfile) includes CFILELINES entries already, so using callocated * sizeof (struct ssline) will give us callocated * CFILELINES entries. */ qfile = ((struct ssfile *) xrealloc ((pointer) qfile, (sizeof (struct ssfile) + (callocated * sizeof (struct ssline))))); callocated += CFILELINES; } qfile->aslines[iline].zline = zbufcpy (zline); qfile->aslines[iline].qfile = NULL; qfile->aslines[iline].ztemp = NULL; iline++; } xfree ((pointer) zline); if (fclose (e) != 0) ulog (LOG_ERROR, "fclose: %s", strerror (errno)); if (iline == 0) { /* There were no lines in the file; this is a poll file, for which we return a 'P' command. */ qfile->aslines[0].zline = zbufcpy ("P"); qfile->aslines[0].qfile = NULL; qfile->aslines[0].ztemp = NULL; iline = 1; } qfile->zfile = zname; qfile->clines = iline; qfile->cdid = 0; qSwork_file = qfile; } /* This loop continues until all the lines from the current file are used up, or a line is returned. */ while (TRUE) { int iline; if (qSwork_file->cdid >= qSwork_file->clines) { /* We don't want to free qSwork_file here, since it must remain until all the lines have been completed. It is freed in fsysdep_did_work. */ qSwork_file = NULL; /* Go back to the main loop which finds another file. */ break; } iline = qSwork_file->cdid; ++qSwork_file->cdid; /* Now parse the line into a command. */ if (! fparse_cmd (qSwork_file->aslines[iline].zline, qcmd)) { ulog (LOG_ERROR, "Bad line in command file %s", qSwork_file->zfile); ubuffree (qSwork_file->aslines[iline].zline); qSwork_file->aslines[iline].zline = NULL; continue; } qSwork_file->aslines[iline].qfile = qSwork_file; qcmd->pseq = (pointer) (&qSwork_file->aslines[iline]); if (qcmd->bcmd == 'S' || qcmd->bcmd == 'E') { char *zreal; zreal = zsysdep_spool_file_name (qsys, qcmd->ztemp, qcmd->pseq); if (zreal == NULL) { ubuffree (qSwork_file->aslines[iline].zline); qSwork_file->aslines[iline].zline = NULL; ubuffree (zdir); return FALSE; } qSwork_file->aslines[iline].ztemp = zreal; } ubuffree (zdir); return TRUE; } } } /* When a command has been complete, fsysdep_did_work is called. The sequence entry was set above to be the address of an aslines structure whose pfile entry points to the ssfile corresponding to this file. We can then check whether all the lines have been completed (they will have been if the pfile entry is NULL) and remove the file if they have been. This means that we only remove a command file if we manage to complete every transfer it specifies in a single UUCP session. I don't know if this is how regular UUCP works. */ boolean fsysdep_did_work (pseq) pointer pseq; { struct ssfile *qfile; struct ssline *qline; int i; qline = (struct ssline *) pseq; ubuffree (qline->zline); qline->zline = NULL; qfile = qline->qfile; qline->qfile = NULL; /* Remove the temporary file, if there is one. It really doesn't matter if this fails, and not checking the return value lets us attempt to remove D.0 or whatever an unused temporary file is called without complaining. */ if (qline->ztemp != NULL) { (void) remove (qline->ztemp); ubuffree (qline->ztemp); qline->ztemp = NULL; } /* If not all the lines have been returned from fsysdep_get_work, we can't remove the file yet. */ if (qfile->cdid < qfile->clines) return TRUE; /* See whether all the commands have been completed. */ for (i = 0; i < qfile->clines; i++) if (qfile->aslines[i].qfile != NULL) return TRUE; /* All commands have finished. */ if (remove (qfile->zfile) != 0) { ulog (LOG_ERROR, "remove (%s): %s", qfile->zfile, strerror (errno)); return FALSE; } ubuffree (qfile->zfile); xfree ((pointer) qfile); if (qfile == qSwork_file) qSwork_file = NULL; return TRUE; } /* Free up the results of a work scan, when we're done with this system. */ /*ARGSUSED*/ void usysdep_get_work_free (qsys) const struct uuconf_system *qsys; { if (azSwork_files != NULL) { size_t i; for (i = 0; i < cSwork_files; i++) ubuffree ((pointer) azSwork_files[i]); xfree ((pointer) azSwork_files); azSwork_files = NULL; cSwork_files = 0; iSwork_file = 0; } if (qSwork_file != NULL) { int i; ubuffree (qSwork_file->zfile); for (i = 0; i < qSwork_file->cdid; i++) { ubuffree (qSwork_file->aslines[i].zline); ubuffree (qSwork_file->aslines[i].ztemp); } for (i = qSwork_file->cdid; i < qSwork_file->clines; i++) ubuffree (qSwork_file->aslines[i].zline); xfree ((pointer) qSwork_file); qSwork_file = NULL; } } /* Save the temporary file used by a send command, and return an informative message to mail to the requestor. This is called when a file transfer failed, to make sure that the potentially valuable file is not completely lost. */ const char * zsysdep_save_temp_file (pseq) pointer pseq; { struct ssline *qline = (struct ssline *) pseq; char *zto, *zslash; size_t cwant; static char *zbuf; static int cbuf; if (! fsysdep_file_exists (qline->ztemp)) return NULL; zslash = strrchr (qline->ztemp, '/'); if (zslash == NULL) zslash = qline->ztemp; else ++zslash; zto = zbufalc (sizeof PRESERVEDIR + sizeof "/" + strlen (zslash)); sprintf (zto, "%s/%s", PRESERVEDIR, zslash); if (! fsysdep_move_file (qline->ztemp, zto, TRUE, FALSE, FALSE, (const char *) NULL)) { ubuffree (zto); return "Could not move file to preservation directory"; } cwant = sizeof "File saved as\n\t/" + strlen (zSspooldir) + strlen (zto); if (cwant > cbuf) { ubuffree (zbuf); zbuf = zbufalc (cwant); cbuf = cwant; } sprintf (zbuf, "File saved as\n\t%s/%s", zSspooldir, zto); ubuffree (zto); return zbuf; } /* Get the jobid of a work file. This is needed by uustat. */ char * zsysdep_jobid (qsys, pseq) const struct uuconf_system *qsys; pointer pseq; { return zsfile_to_jobid (qsys, ((struct ssline *) pseq)->qfile->zfile, bsgrade (pseq)); } /* Get the grade of a work file. The pseq argument can be NULL when this is called from zsysdep_spool_file_name, and simply means that this is a remote file; returning -1 will cause zsfind_file to do the right thing. */ char bsgrade (pseq) pointer pseq; { const char *zfile; char bgrade; if (pseq == NULL) return -1; zfile = ((struct ssline *) pseq)->qfile->zfile; #if ! SPOOLDIR_SVR4 bgrade = zfile[strlen (zfile) - CSEQLEN - 1]; #else bgrade = *(strchr (zfile, '/') + 1); #endif return bgrade; } &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_MESSAuucp-1.04/unix/xqtfil.c1004440004150000170000001456005337263601012025 037777777777 1 0 /* 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.4 1992/11/14 16:14:07 ian Rel $"; #endif #include "uudefs.h" #include "sysdep.h" #include "system.h" #include #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ /* Under the V2 or BSD42 spool directory scheme, all execute files are in the main spool directory. Under the BSD43 scheme, they are all in the directory X.. Under the HDB or SVR4 scheme, they are in directories named after systems. Under the ULTRIX scheme, they are in X. subdirectories of subdirectories of sys. Under the TAYLOR scheme, they are all in the subdirectory X. of a directory named after the system. This means that for HDB, ULTRIX, SVR4 or TAYLOR, we have to search directories of directories. */ #if SPOOLDIR_V2 || SPOOLDIR_BSD42 #define ZDIR "." #define SUBDIRS 0 #endif #if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR #define ZDIR "." #define SUBDIRS 1 #endif #if SPOOLDIR_ULTRIX #define ZDIR "sys" #define SUBDIRS 1 #endif #if SPOOLDIR_BSD43 #define ZDIR "X." #define SUBDIRS 0 #endif /* Static variables for the execute file scan. */ static DIR *qSxqt_topdir; #if ! SUBDIRS static const char *zSdir; #else /* SUBDIRS */ static char *zSdir; static DIR *qSxqt_dir; static char *zSsystem; #endif /* SUBDIRS */ /* Initialize the scan for execute files. The function usysdep_get_xqt_free will clear the data out when we are done with the system. This returns FALSE on error. */ /*ARGSUSED*/ boolean fsysdep_get_xqt_init () { usysdep_get_xqt_free (); qSxqt_topdir = opendir ((char *) ZDIR); if (qSxqt_topdir == NULL) { if (errno == ENOENT) return TRUE; ulog (LOG_ERROR, "opendir (%s): %s", ZDIR, strerror (errno)); return FALSE; } return TRUE; } /* Return the name of the next execute file to read and process. If this returns NULL, *pferr must be checked. If will be TRUE on error, FALSE if there are no more files. On a successful return *pzsystem will be set to the system for which the execute file was created. */ char * zsysdep_get_xqt (pzsystem, pferr) char **pzsystem; boolean *pferr; { *pferr = FALSE; if (qSxqt_topdir == NULL) return NULL; /* This loop continues until we find a file. */ while (TRUE) { DIR *qdir; struct dirent *q; #if ! SUBDIRS zSdir = ZDIR; qdir = qSxqt_topdir; #else /* SUBDIRS */ /* This loop continues until we find a subdirectory to read. */ while (qSxqt_dir == NULL) { struct dirent *qtop; qtop = readdir (qSxqt_topdir); if (qtop == NULL) { (void) closedir (qSxqt_topdir); qSxqt_topdir = NULL; return NULL; } /* No system name may start with a dot (this is enforced by tisystem in sysinf.c). This allows us to quickly skip impossible directories. */ if (qtop->d_name[0] == '.') continue; DEBUG_MESSAGE1 (DEBUG_SPOOLDIR, "zsysdep_get_xqt: Found %s in top directory", qtop->d_name); ubuffree (zSdir); #if SPOOLDIR_HDB || SPOOLDIR_SVR4 zSdir = zbufcpy (qtop->d_name); #endif #if SPOOLDIR_ULTRIX zSdir = zsappend3 ("sys", qtop->d_name, "X."); #endif #if SPOOLDIR_TAYLOR zSdir = zsysdep_in_dir (qtop->d_name, "X."); #endif ubuffree (zSsystem); zSsystem = zbufcpy (qtop->d_name); qSxqt_dir = opendir (zSdir); if (qSxqt_dir == NULL && errno != ENOTDIR && errno != ENOENT) ulog (LOG_ERROR, "opendir (%s): %s", zSdir, strerror (errno)); } qdir = qSxqt_dir; #endif /* SUBDIRS */ q = readdir (qdir); #if DEBUG > 1 if (q != NULL) DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, "zsysdep_get_xqt: Found %s in subdirectory %s", q->d_name, zSdir); #endif /* If we've found an execute file, return it. We have to get the system name, which is easy for HDB or TAYLOR. For other spool directory schemes, we have to pull it out of the X. file name; this would be insecure, except that zsfind_file clobbers the file name to include the real system name. */ if (q != NULL && q->d_name[0] == 'X' && q->d_name[1] == '.') { char *zret; #if SPOOLDIR_HDB || SPOOLDIR_SVR4 || SPOOLDIR_TAYLOR *pzsystem = zbufcpy (zSsystem); #else { size_t clen; clen = strlen (q->d_name) - 7; *pzsystem = zbufalc (clen + 1); memcpy (*pzsystem, q->d_name + 2, clen); (*pzsystem)[clen] = '\0'; } #endif zret = zsysdep_in_dir (zSdir, q->d_name); #if DEBUG > 1 DEBUG_MESSAGE2 (DEBUG_SPOOLDIR, "zsysdep_get_xqt: Returning %s (system %s)", zret, *pzsystem); #endif return zret; } /* If we've reached the end of the directory, then if we are using subdirectories loop around to read the next one, otherwise we are finished. */ if (q == NULL) { (void) closedir (qdir); #if SUBDIRS qSxqt_dir = NULL; continue; #else qSxqt_topdir = NULL; return NULL; #endif } } } /* Free up the results of an execute file scan, when we're done with this system. */ /*ARGSUSED*/ void usysdep_get_xqt_free () { if (qSxqt_topdir != NULL) { (void) closedir (qSxqt_topdir); qSxqt_topdir = NULL; } #if SUBDIRS if (qSxqt_dir != NULL) { (void) closedir (qSxqt_dir); qSxqt_dir = NULL; } ubuffree (zSdir); zSdir = NULL; ubuffree (zSsystem); zSsystem = NULL; #endif } zfile); xfree ((pointer) qfile); if (qfile == qSwork_file) qSwork_file = NULL; return TRUE; } /* Free up the results of a work scanuucp-1.04/unix/xqtsub.c1004440004150000170000003457705337263602012057 037777777777 1 0 /* 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.8 1993/01/17 04:16:13 ian Rel $"; #endif #include "uudefs.h" #include "uuconf.h" #include "system.h" #include "sysdep.h" #include #include #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef O_RDONLY #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #if HAVE_OPENDIR #if HAVE_DIRENT_H #include #else /* ! HAVE_DIRENT_H */ #include #define dirent direct #endif /* ! HAVE_DIRENT_H */ #endif /* HAVE_OPENDIR */ /* Get a value for EX_TEMPFAIL. */ #if HAVE_SYSEXITS_H #include #endif #ifndef EX_TEMPFAIL #define EX_TEMPFAIL 75 #endif /* Get the full pathname of the command to execute, given the list of permitted commands and the allowed path. */ char * zsysdep_find_command (zcmd, pzcmds, pzpath, pferr) const char *zcmd; char **pzcmds; char **pzpath; boolean *pferr; { char **pz; *pferr = FALSE; for (pz = pzcmds; *pz != NULL; pz++) { char *zslash; if (strcmp (*pz, "ALL") == 0) break; zslash = strrchr (*pz, '/'); if (zslash != NULL) ++zslash; else zslash = *pz; if (strcmp (zslash, zcmd) == 0 || strcmp (*pz, zcmd) == 0) { /* If we already have an absolute path, we can get out immediately. */ if (**pz == '/') return zbufcpy (*pz); break; } } /* If we didn't find this command, get out. */ if (*pz == NULL) return NULL; /* We didn't find an absolute pathname, so we must look through the path. */ for (pz = pzpath; *pz != NULL; pz++) { char *zname; struct stat s; zname = zsysdep_in_dir (*pz, zcmd); if (stat (zname, &s) == 0) return zname; } *pferr = FALSE; return NULL; } /* Expand a local filename for uuxqt. This is special because uuxqt only wants to expand filenames that start with ~ (it does not want to prepend the current directory to other names) and if the ~ is double, it is turned into a single ~. This returns NULL to indicate that no change was required; it has no way to return error. */ char * zsysdep_xqt_local_file (qsys, zfile) const struct uuconf_system *qsys; const char *zfile; { if (*zfile != '~') return NULL; if (zfile[1] == '~') { size_t clen; char *zret; clen = strlen (zfile); zret = zbufalc (clen); memcpy (zret, zfile + 1, clen); return zret; } return zsysdep_local_file (zfile, qsys->uuconf_zpubdir); } #if ! ALLOW_FILENAME_ARGUMENTS /* Check to see whether an argument specifies a file name; if it does, make sure that the file may legally be sent and/or received. For Unix, we do not permit any occurrence of "/../" in the name, nor may it start with "../". Otherwise, if it starts with "/" we check against the list of permitted files. */ boolean fsysdep_xqt_check_file (qsys, zfile) const struct uuconf_system *qsys; const char *zfile; { size_t clen; clen = strlen (zfile); if ((clen == sizeof "../" - 1 && strcmp (zfile, "../") == 0) || (clen >= sizeof "/.." - 1 && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0) || strstr (zfile, "/../") != NULL || (*zfile == '/' && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL) || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL)))) { ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile); return FALSE; } return TRUE; } #endif /* ! ALLOW_FILENAME_ARGUMENTS */ /* Invoke the command specified by an execute file. */ /*ARGSUSED*/ boolean fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput, fshell, iseq, pzerror, pftemp) const struct uuconf_system *qsys; const char *zuser; const char **pazargs; const char *zfullcmd; const char *zinput; const char *zoutput; boolean fshell; int iseq; char **pzerror; boolean *pftemp; { int aidescs[3]; boolean ferr; pid_t ipid; int ierr; char abxqtdir[sizeof XQTDIR + 4]; const char *zxqtdir; int istat; char *zpath; #if ALLOW_SH_EXECUTION const char *azshargs[4]; #endif *pzerror = NULL; *pftemp = FALSE; aidescs[0] = SPAWN_NULL; aidescs[1] = SPAWN_NULL; aidescs[2] = SPAWN_NULL; ferr = FALSE; if (zinput != NULL) { aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0); if (aidescs[0] < 0) { ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno)); ferr = TRUE; } else if (fcntl (aidescs[0], F_SETFD, fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); ferr = TRUE; } } if (! ferr && zoutput != NULL) { aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE); if (aidescs[1] < 0) { ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno)); *pftemp = TRUE; ferr = TRUE; } else if (fcntl (aidescs[1], F_SETFD, fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); ferr = TRUE; } } if (! ferr) { *pzerror = zstemp_file (qsys); aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE); if (aidescs[2] < 0) { if (errno == ENOENT) { if (! fsysdep_make_dirs (*pzerror, FALSE)) { *pftemp = TRUE; ferr = TRUE; } else aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE); } if (! ferr && aidescs[2] < 0) { ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno)); *pftemp = TRUE; ferr = TRUE; } } if (! ferr && fcntl (aidescs[2], F_SETFD, fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0) { ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); ferr = TRUE; } } if (iseq == 0) zxqtdir = XQTDIR; else { sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); zxqtdir = abxqtdir; } if (ferr) { if (aidescs[0] != SPAWN_NULL) (void) close (aidescs[0]); if (aidescs[1] != SPAWN_NULL) (void) close (aidescs[1]); if (aidescs[2] != SPAWN_NULL) (void) close (aidescs[2]); ubuffree (*pzerror); return FALSE; } #if ALLOW_SH_EXECUTION if (fshell) { azshargs[0] = "/bin/sh"; azshargs[1] = "-c"; azshargs[2] = zfullcmd; azshargs[3] = NULL; pazargs = azshargs; } #else fshell = FALSE; #endif if (qsys->uuconf_pzpath == NULL) zpath = NULL; else { size_t c; char **pz; c = 0; for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++) c += strlen (*pz) + 1; zpath = zbufalc (c); *zpath = '\0'; for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++) { strcat (zpath, *pz); if (pz[1] != NULL) strcat (zpath, ":"); } } /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we aren't already using the shell. */ ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE, ! fshell, zpath, qsys->uuconf_zname, zuser); ierr = errno; ubuffree (zpath); if (aidescs[0] != SPAWN_NULL) (void) close (aidescs[0]); if (aidescs[1] != SPAWN_NULL) (void) close (aidescs[1]); if (aidescs[2] != SPAWN_NULL) (void) close (aidescs[2]); if (ipid < 0) { ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr)); *pftemp = TRUE; return FALSE; } istat = ixswait ((unsigned long) ipid, "Execution"); if (istat == EX_TEMPFAIL) *pftemp = TRUE; return istat == 0; } /* Lock a uuxqt process. */ int ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts) const char *zcmd; int cmaxuuxqts; { char ab[sizeof "LCK.XQT.9999"]; int i; if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000) cmaxuuxqts = 9999; for (i = 0; i < cmaxuuxqts; i++) { sprintf (ab, "LCK.XQT.%d", i); if (fsdo_lock (ab, TRUE, (boolean *) NULL)) break; } if (i >= cmaxuuxqts) return -1; if (zcmd != NULL) { char abcmd[sizeof "LXQ.123456789"]; sprintf (abcmd, "LXQ.%.9s", zcmd); abcmd[strcspn (abcmd, " \t/")] = '\0'; if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL)) { (void) fsdo_unlock (ab, TRUE); return -1; } } return i; } /* Unlock a uuxqt process. */ boolean fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts) int iseq; const char *zcmd; int cmaxuuxqts; { char ab[sizeof "LCK.XQT.9999"]; boolean fret; fret = TRUE; sprintf (ab, "LCK.XQT.%d", iseq); if (! fsdo_unlock (ab, TRUE)) fret = FALSE; if (zcmd != NULL) { char abcmd[sizeof "LXQ.123456789"]; sprintf (abcmd, "LXQ.%.9s", zcmd); abcmd[strcspn (abcmd, " \t/")] = '\0'; if (! fsdo_unlock (abcmd, TRUE)) fret = FALSE; } return fret; } /* See whether a particular uuxqt command is locked (this depends on the implementation of fsdo_lock). */ boolean fsysdep_uuxqt_locked (zcmd) const char *zcmd; { char ab[sizeof "LXQ.123456789"]; struct stat s; sprintf (ab, "LXQ.%.9s", zcmd); return stat (ab, &s) == 0; } /* Lock a particular execute file. */ boolean fsysdep_lock_uuxqt_file (zfile) const char *zfile; { char *zcopy, *z; boolean fret; zcopy = zbufcpy (zfile); z = strrchr (zcopy, '/'); if (z == NULL) *zcopy = 'L'; else *(z + 1) = 'L'; fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL); ubuffree (zcopy); return fret; } /* Unlock a particular execute file. */ boolean fsysdep_unlock_uuxqt_file (zfile) const char *zfile; { char *zcopy, *z; boolean fret; zcopy = zbufcpy (zfile); z = strrchr (zcopy, '/'); if (z == NULL) *zcopy = 'L'; else *(z + 1) = 'L'; fret = fsdo_unlock (zcopy, TRUE); ubuffree (zcopy); return fret; } /* Lock the execute directory. Since we use a different directory depending on which LCK.XQT.dddd file we got, there is actually no need to create a lock file. We do make sure that the directory exists, though. */ boolean fsysdep_lock_uuxqt_dir (iseq) int iseq; { const char *zxqtdir; char abxqtdir[sizeof XQTDIR + 4]; if (iseq == 0) zxqtdir = XQTDIR; else { sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); zxqtdir = abxqtdir; } if (mkdir (zxqtdir, S_IRWXU) < 0 && errno != EEXIST) { ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno)); return FALSE; } return TRUE; } /* Unlock the execute directory and clear it out. The lock is actually the LCK.XQT.dddd file, so we don't unlock it, but we do remove all the files. */ boolean fsysdep_unlock_uuxqt_dir (iseq) int iseq; { const char *zxqtdir; char abxqtdir[sizeof XQTDIR + 4]; DIR *qdir; if (iseq == 0) zxqtdir = XQTDIR; else { sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); zxqtdir = abxqtdir; } qdir = opendir ((char *) zxqtdir); if (qdir != NULL) { struct dirent *qentry; while ((qentry = readdir (qdir)) != NULL) { char *z; if (strcmp (qentry->d_name, ".") == 0 || strcmp (qentry->d_name, "..") == 0) continue; z = zsysdep_in_dir (zxqtdir, qentry->d_name); if (remove (z) < 0) { int ierr; ierr = errno; if (! fsysdep_directory (z)) ulog (LOG_ERROR, "remove (%s): %s", z, strerror (ierr)); else (void) fsysdep_rmdir (z); } ubuffree (z); } closedir (qdir); } return TRUE; } /* Move files into the execution directory. */ boolean fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput) int cfiles; const char *const *pzfrom; const char *const *pzto; boolean fto; int iseq; char **pzinput; { char *zinput; const char *zxqtdir; char abxqtdir[sizeof XQTDIR + 4]; int i; if (pzinput == NULL) zinput = NULL; else zinput = *pzinput; if (iseq == 0) zxqtdir = XQTDIR; else { sprintf (abxqtdir, "%s%04d", XQTDIR, iseq); zxqtdir = abxqtdir; } for (i = 0; i < cfiles; i++) { const char *zfrom, *zto; char *zfree; if (pzto[i] == NULL) continue; zfree = zsysdep_in_dir (zxqtdir, pzto[i]); zfrom = pzfrom[i]; zto = zfree; if (zinput != NULL && strcmp (zinput, zfrom) == 0) { *pzinput = zbufcpy (zto); zinput = NULL; } if (! fto) { const char *ztemp; ztemp = zfrom; zfrom = zto; zto = ztemp; (void) chmod (zfrom, IPRIVATE_FILE_MODE); } if (rename (zfrom, zto) < 0) { #if HAVE_RENAME /* On some systems the system call rename seems to fail for arbitrary reasons. To get around this, we always try to copy the file by hand if the rename failed. */ errno = EXDEV; #endif if (errno != EXDEV) { ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto, strerror (errno)); ubuffree (zfree); break; } if (! fcopy_file (zfrom, zto, FALSE, FALSE)) { ubuffree (zfree); break; } if (remove (zfrom) < 0) ulog (LOG_ERROR, "remove (%s): %s", zfrom, strerror (errno)); } if (fto) (void) chmod (zto, IPUBLIC_FILE_MODE); ubuffree (zfree); } if (i < cfiles) { if (fto) (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq, (char **) NULL); return FALSE; } return TRUE; } f_pzremote_send, qsys->uuconf_zpubdir, TRUE, FALSE, (const char *) NULL) || ! fin_directory_list (zfile, quucp-1.04/uuconf/0407750004150000170000000000005337265114010057 5 0 1 0 uucp-1.04/uuconf/README1004440004150000170000001115305337263603011543 037777777777 1 0 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 9"]; 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); uuucp-1.04/uuconf/COPYING.LIB1004440004150000170000006126105337263602012327 037777777777 1 0 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ffer, 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 uucp-1.04/uuconf/MANIFEST1004440004150000170000000141505337263603012014 037777777777 1 0 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 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. uucp-1.04/uuconf/Makefile.in1004440004150000170000000434605337263603012736 037777777777 1 0 # This is the Makefile for the Taylor UUCP uuconf library # # The file Makefile.in should be processed by configure to generate # Makefile. If you want to generate Makefile by hand, you must find # all variables surrounded by @ and replace them with the correct # value (e.g. @CC@ must be replaced by something like cc or gcc). SHELL = /bin/sh # These values are overriden by the top level Makefile prefix = /usr/local newconfigdir = $(prefix)/conf/uucp oldconfigdir = /usr/lib/uucp # These values are overridden by the top level Makefile CC = @CC@ CFLAGS = @CFLAGS@ RANLIB = @RANLIB@ LN_S = @LN_S@ # Source directory and, if necessary, VPATH srcdir = @srcdir@ VPATH = @srcdir@ MORECFLAGS = -I$(srcdir) -I. -I$(srcdir)/.. -I.. -DNEWCONFIGLIB=\"$(newconfigdir)\" -DOLDCONFIGLIB=\"$(oldconfigdir)\" OBJS = addblk.o addstr.o allblk.o alloc.o base.o bool.o callin.o \ calout.o chatc.o cmdarg.o cmdfil.o cmdlin.o debfil.o deblev.o \ diacod.o dial.o diasub.o dnams.o errno.o errstr.o filnam.o \ freblk.o fredia.o free.o freprt.o fresys.o grdcmp.o hdial.o \ hdnams.o hinit.o hlocnm.o hport.o hrmunk.o hsinfo.o hsnams.o \ hsys.o hunk.o iniglb.o init.o int.o lckdir.o lineno.o llocnm.o \ local.o locnm.o logfil.o maxuxq.o mrgblk.o paramc.o port.o \ prtsub.o pubdir.o rdlocs.o rdperm.o reliab.o remunk.o sinfo.o \ snams.o split.o spool.o stafil.o syssub.o tcalou.o tdial.o \ tdialc.o tdnams.o tgcmp.o thread.o time.o tinit.o tlocnm.o \ tport.o tportc.o tsinfo.o tsnams.o tsys.o tval.o ugtlin.o \ unk.o val.o vinit.o vport.o vsinfo.o vsnams.o vsys.o all: libuuconf.a libuuconf.a: $(OBJS) rm -f libuuconf.a ar qc libuuconf.a $(OBJS) -$(RANLIB) libuuconf.a .c.o: $(CC) -c $(CFLAGS) $(MORECFLAGS) $< syshdr.h: syshdr.unx rm -f syshdr.h $(LN_S) $(srcdir)/syshdr.unx syshdr.h clean: rm -f $(OBJS) libuuconf.a syshdr.h distclean: clean rm -f Makefile mostlyclean: clean realclean: distclean dist: mkdir ../uucp-$(VERSION)/uuconf ln `cat MANIFEST` ../uucp-$(VERSION)/uuconf Makefile: Makefile.in (cd ..; sh config.status) # Header file dependencies $(OBJS): uucnfi.h syshdr.h $(srcdir)/../uucp.h ../conf.h $(srcdir)/../policy.h $(srcdir)/../uuconf.h addblk.o: alloc.h allblk.o: alloc.h alloc.o: alloc.h freblk.o: alloc.h free.o: alloc.h mrgblk.o: alloc.h laims; 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 onuucp-1.04/uuconf/alloc.h1004440004150000170000000501005337263604012122 037777777777 1 0 /* 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; }; 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, alteruucp-1.04/uuconf/syshdr.unx1004440004150000170000000642405337263622012741 037777777777 1 0 /* syshdr.unx -*- C -*- Unix system header for the uuconf library. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP uuconf library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ /* The root directory (used when setting local-send and local-receive values). */ #define ZROOTDIR "/" /* The current directory (used by uuconv as a prefix for the newly created file names). */ #define ZCURDIR "." /* The names of the Taylor UUCP configuration files. These are appended to NEWCONFIGLIB which is defined in Makefile. */ #define CONFIGFILE "/config" #define SYSFILE "/sys" #define PORTFILE "/port" #define DIALFILE "/dial" #define CALLFILE "/call" #define PASSWDFILE "/passwd" #define DIALCODEFILE "/dialcode" /* The names of the various V2 configuration files. These are appended to OLDCONFIGLIB which is defined in Makefile. */ #define V2_SYSTEMS "/L.sys" #define V2_DEVICES "/L-devices" #define V2_USERFILE "/USERFILE" #define V2_CMDS "/L.cmds" #define V2_DIALCODES "/L-dialcodes" /* The names of the HDB configuration files. These are appended to OLDCONFIGLIB which is defined in Makefile. */ #define HDB_SYSFILES "/Sysfiles" #define HDB_SYSTEMS "/Systems" #define HDB_PERMISSIONS "/Permissions" #define HDB_DEVICES "/Devices" #define HDB_DIALERS "/Dialers" #define HDB_DIALCODES "/Dialcodes" #define HDB_MAXUUXQTS "/Maxuuxqts" #define HDB_REMOTE_UNKNOWN "/remote.unknown" /* A string which is inserted between the value of OLDCONFIGLIB (defined in the Makefile) and any names specified in the HDB Sysfiles file. */ #define HDB_SEPARATOR "/" /* A macro to check whether fopen failed because the file did not exist. */ #define FNO_SUCH_FILE() (errno == ENOENT) #if ! HAVE_STRERROR /* We need a definition for strerror; normally the function in the unix directory is used, but we want to be independent of that library. This macro evaluates its argument multiple times. */ extern int sys_nerr; extern char *sys_errlist[]; #define strerror(ierr) \ ((ierr) >= 0 && (ierr) < sys_nerr ? sys_errlist[ierr] : "unknown error") #endif /* ! HAVE_STRERROR */ /* We want to be able to mark the Taylor UUCP system files as close on exec. */ #if HAVE_FCNTL_H #include #else #if HAVE_SYS_FILE_H #include #endif #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 1 #endif #define CLOSE_ON_EXEC(e) \ do \ { \ int cle_i = fileno (e); \ \ fcntl (cle_i, F_SETFD, fcntl (cle_i, F_GETFD, 0) | FD_CLOEXEC); \ } \ while (0) 1 0 uucp-1.04/uuconf/uucnfi.h1004440004150000170000003105205337263627012333 037777777777 1 0 /* 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)); st 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 puucp-1.04/uuconf/addblk.c1004440004150000170000000330105337263603012244 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } ed 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 restrictionuucp-1.04/uuconf/addstr.c1004440004150000170000000757305337263604012324 037777777777 1 0 /* 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.4 1992/11/14 16:16:24 ian Rel $"; #endif #include /* When setting system information, we need to be able to distinguish between a value that is not set and a value that has been set to NULL. We do this by initializing the value to point to the variable _uuconf_unset, and then correcting it in the function _uuconf_isystem_basic_default. This variable is declared in this file because some linkers will apparently not pull in an object file which merely declarates a variable. This functions happens to be pulled in by almost everything. */ char *_uuconf_unset; /* Add a string to a list of strings. The list is maintained as an array of elements ending in NULL. The total number of available slots is always a multiple of CSLOTS, so by counting the current number of elements we can tell whether a new slot is needed. If the fcopy argument is TRUE, the new string is duplicated into memory. If the fcheck argument is TRUE, this does not add a string that is already in the list. The pblock argument may be used to do the allocations within a memory block. This returns a standard uuconf error code. */ #define CSLOTS (8) int _uuconf_iadd_string (qglobal, zadd, fcopy, fcheck, ppzstrings, pblock) struct sglobal *qglobal; char *zadd; boolean fcopy; boolean fcheck; char ***ppzstrings; pointer pblock; { char **pz; size_t c; if (fcheck && *ppzstrings != NULL) { for (pz = *ppzstrings; *pz != NULL; pz++) if (strcmp (zadd, *pz) == 0) return UUCONF_SUCCESS; } if (fcopy) { size_t clen; char *znew; clen = strlen (zadd) + 1; znew = (char *) uuconf_malloc (pblock, clen); if (znew == NULL) { if (qglobal != NULL) qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) znew, (pointer) zadd, clen); zadd = znew; } pz = *ppzstrings; if (pz == NULL || pz == (char **) &_uuconf_unset) { pz = (char **) uuconf_malloc (pblock, CSLOTS * sizeof (char *)); if (pz == NULL) { if (qglobal != NULL) qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } *ppzstrings = pz; } else { c = 0; while (*pz != NULL) { ++pz; ++c; } if ((c + 1) % CSLOTS == 0) { char **pznew; pznew = (char **) uuconf_malloc (pblock, ((c + 1 + CSLOTS) * sizeof (char *))); if (pznew == NULL) { if (qglobal != NULL) qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) pznew, (pointer) *ppzstrings, c * sizeof (char *)); uuconf_free (pblock, *ppzstrings); *ppzstrings = pznew; pz = pznew + c; } } pz[0] = zadd; pz[1] = NULL; return UUCONF_SUCCESS; } struct uuconf_system *qsys)); /* Read the HDB Permissions file. */ extern int _uuconf_ihread_permissions P((struct sglobal *qglouucp-1.04/uuconf/allblk.c1004440004150000170000000305605337263604012274 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } *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 bsepuucp-1.04/uuconf/alloc.c1004440004150000170000000436005337263604012124 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } an 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 restrictionuucp-1.04/uuconf/base.c1004440004150000170000000336405337263605011750 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } } f 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 memoryuucp-1.04/uuconf/bool.c1004440004150000170000000354705337263605011774 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } uucp-1.04/uuconf/callin.c1004440004150000170000000751005337263605012275 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include static int iplogin P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* Check a login name and password against the UUCP password file. This looks at the Taylor UUCP password file, but will work even if uuconf_taylor_init was not called. */ int uuconf_callin (pglobal, zlogin, zpassword) pointer pglobal; const char *zlogin; const char *zpassword; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; char **pz; struct uuconf_cmdtab as[2]; char *zfilepass; /* If we have no password file names, fill in the default name. */ if (qglobal->qprocess->pzpwdfiles == NULL) { char ab[sizeof NEWCONFIGLIB + sizeof PASSWDFILE - 1]; memcpy ((pointer) ab, (pointer) NEWCONFIGLIB, sizeof NEWCONFIGLIB - 1); memcpy ((pointer) (ab + sizeof NEWCONFIGLIB - 1), (pointer) PASSWDFILE, sizeof PASSWDFILE); iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, &qglobal->qprocess->pzpwdfiles, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret; } as[0].uuconf_zcmd = zlogin; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; as[0].uuconf_pvar = (pointer) &zfilepass; as[0].uuconf_pifn = iplogin; as[1].uuconf_zcmd = NULL; zfilepass = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzpwdfiles; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_CASE, (pointer) NULL); (void) fclose (e); if (iret != UUCONF_SUCCESS || zfilepass != NULL) break; } if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME; } else if (zfilepass == NULL || strcmp (zfilepass, zpassword) != 0) iret = UUCONF_NOT_FOUND; if (zfilepass != NULL) free ((pointer) zfilepass); return iret; } /* This is called if it is the name we are looking for. The pvar argument points to zfilepass, and we set it to the password. */ static int iplogin (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pzpass = (char **) pvar; *pzpass = strdup (argv[1]); if (*pzpass == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } return UUCONF_CMDTABRET_EXIT; } else { if (c > CALLOC_SIZE) q->qnext = (struct sblock *) malloc (sizeof (struct sblock) + c - CALLOC_SIZE); else q->qnext = (struct sblock *) malloc (sizeofuucp-1.04/uuconf/calout.c1004440004150000170000000477505337263605012334 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Find callout login name and password for a system. */ /*ARGSUSED*/ int uuconf_callout (pglobal, qsys, pzlog, pzpass) pointer pglobal; const struct uuconf_system *qsys; char **pzlog; char **pzpass; { #if HAVE_TAYLOR_CONFIG return uuconf_taylor_callout (pglobal, qsys, pzlog, pzpass); #else /* ! HAVE_TAYLOR_CONFIG */ struct sglobal *qglobal = (struct sglobal *) pglobal; *pzlog = NULL; *pzpass = NULL; if (qsys->uuconf_zcall_login == NULL && qsys->uuconf_zcall_password == NULL) return UUCONF_NOT_FOUND; if ((qsys->uuconf_zcall_login != NULL && strcmp (qsys->uuconf_zcall_login, "*") == 0) || (qsys->uuconf_zcall_password != NULL && strcmp (qsys->uuconf_zcall_password, "*") == 0)) return UUCONF_NOT_FOUND; if (qsys->uuconf_zcall_login != NULL) { *pzlog = strdup (qsys->uuconf_zcall_login); if (*pzlog == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } } if (qsys->uuconf_zcall_password != NULL) { *pzpass = strdup (qsys->uuconf_zcall_password); if (*pzpass == NULL) { qglobal->ierrno = errno; if (*pzlog != NULL) { free ((pointer) *pzlog); *pzlog = NULL; } return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } } return UUCONF_SUCCESS; #endif /* ! HAVE_TAYLOR_CONFIG */ } oryuucp-1.04/uuconf/chatc.c1004440004150000170000001334105337263606012115 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #endif #include #include static int icchat P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int icchat_fail P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int icunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* The chat script commands. */ static const struct cmdtab_offset asChat_cmds[] = { { "chat", UUCONF_CMDTABTYPE_FN, offsetof (struct uuconf_chat, uuconf_pzchat), icchat }, { "chat-program", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_chat, uuconf_pzprogram), NULL }, { "chat-timeout", UUCONF_CMDTABTYPE_INT, offsetof (struct uuconf_chat, uuconf_ctimeout), NULL }, { "chat-fail", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct uuconf_chat, uuconf_pzfail), icchat_fail }, { "chat-seven-bit", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_chat, uuconf_fstrip), NULL }, { NULL, 0, 0, NULL } }; #define CCHAT_CMDS (sizeof asChat_cmds / sizeof asChat_cmds[0]) /* Handle a chat script command. The chat script commands are entered as UUCONF_CMDTABTYPE_PREFIX, and the commands are routed to this function. We copy the command table onto the stack and repoint it at qchat in order to make the function reentrant. The return value can include UUCONF_CMDTABRET_KEEP, but should not include UUCONF_CMDTABRET_EXIT. */ int _uuconf_ichat_cmd (qglobal, argc, argv, qchat, pblock) struct sglobal *qglobal; int argc; char **argv; struct uuconf_chat *qchat; pointer pblock; { char *zchat; struct uuconf_cmdtab as[CCHAT_CMDS]; int iret; /* This is only invoked when argv[0] will contain the string "chat"; the specific chat script command comes after that point. */ for (zchat = argv[0]; *zchat != '\0'; zchat++) if ((*zchat == 'c' || *zchat == 'C') && strncasecmp (zchat, "chat", sizeof "chat" - 1) == 0) break; if (*zchat == '\0') return UUCONF_SYNTAX_ERROR; argv[0] = zchat; _uuconf_ucmdtab_base (asChat_cmds, CCHAT_CMDS, (char *) qchat, as); iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, pblock, icunknown, 0, pblock); return iret &~ UUCONF_CMDTABRET_EXIT; } /* Handle the "chat" command. This breaks up substrings in expect strings, and sticks the arguments into a NULL terminated array. */ static int icchat (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char ***ppz = (char ***) pvar; pointer pblock = pinfo; int i; *ppz = NULL; for (i = 1; i < argc; i += 2) { char *z, *zdash; int iret; /* Break the expect string into substrings. */ z = argv[i]; zdash = strchr (z, '-'); while (zdash != NULL) { *zdash = '\0'; iret = _uuconf_iadd_string (qglobal, z, TRUE, FALSE, ppz, pblock); if (iret != UUCONF_SUCCESS) return iret; *zdash = '-'; z = zdash; zdash = strchr (z + 1, '-'); } iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz, pblock); if (iret != UUCONF_SUCCESS) return iret; /* Add the send string without breaking it up. If it starts with a dash we must replace it with an escape sequence, to prevent it from being interpreted as a subsend. */ if (i + 1 < argc) { if (argv[i + 1][0] != '-') iret = _uuconf_iadd_string (qglobal, argv[i + 1], FALSE, FALSE, ppz, pblock); else { size_t clen; clen = strlen (argv[i + 1]); z = uuconf_malloc (pblock, clen + 2); if (z == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } z[0] = '\\'; memcpy ((pointer) (z + 1), (pointer) argv[i + 1], clen + 1); iret = _uuconf_iadd_string (qglobal, z, FALSE, FALSE, ppz, pblock); } if (iret != UUCONF_SUCCESS) return iret; } } return UUCONF_CMDTABRET_KEEP; } /* Add a new chat failure string. */ /*ARGSUSED*/ static int icchat_fail (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char ***ppz = (char ***) pvar; pointer pblock = pinfo; return _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, ppz, pblock); } /* Return a syntax error for an unknown command. */ /*ARGSUSED*/ static int icunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { return UUCONF_SYNTAX_ERROR; } rn 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; pointeruucp-1.04/uuconf/cmdarg.c1004440004150000170000001142705337263606012273 037777777777 1 0 /* 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.3 1992/10/03 15:10:20 ian Rel $"; #endif #include #undef strcmp #if HAVE_STRCASECMP #undef strcasecmp #endif extern int strcmp (), strcasecmp (); /* Look up a command with arguments in a table and execute it. */ int uuconf_cmd_args (pglobal, cargs, pzargs, qtab, pinfo, pfiunknown, iflags, pblock) pointer pglobal; int cargs; char **pzargs; const struct uuconf_cmdtab *qtab; pointer pinfo; int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); int iflags; pointer pblock; { struct sglobal *qglobal = (struct sglobal *) pglobal; int bfirstu, bfirstl; int (*pficmp) P((const char *, const char *)); register const struct uuconf_cmdtab *q; int itype; int callowed; bfirstu = bfirstl = pzargs[0][0]; if ((iflags & UUCONF_CMDTABFLAG_CASE) != 0) pficmp = strcmp; else { if (islower (bfirstu)) bfirstu = toupper (bfirstu); if (isupper (bfirstl)) bfirstl = tolower (bfirstl); pficmp = strcasecmp; } itype = 0; for (q = qtab; q->uuconf_zcmd != NULL; q++) { int bfirst; bfirst = q->uuconf_zcmd[0]; if (bfirst != bfirstu && bfirst != bfirstl) continue; itype = UUCONF_TTYPE_CMDTABTYPE (q->uuconf_itype); if (itype != UUCONF_CMDTABTYPE_PREFIX) { if ((*pficmp) (q->uuconf_zcmd, pzargs[0]) == 0) break; } else { size_t clen; clen = strlen (q->uuconf_zcmd); if ((iflags & UUCONF_CMDTABFLAG_CASE) != 0) { if (strncmp (q->uuconf_zcmd, pzargs[0], clen) == 0) break; } else { if (strncasecmp (q->uuconf_zcmd, pzargs[0], clen) == 0) break; } } } if (q->uuconf_zcmd == NULL) { if (pfiunknown == NULL) return UUCONF_CMDTABRET_CONTINUE; return (*pfiunknown) (pglobal, cargs, pzargs, (pointer) NULL, pinfo); } callowed = UUCONF_CARGS_CMDTABTYPE (q->uuconf_itype); if (callowed != 0 && callowed != cargs) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; switch (itype) { case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_STRING): if (cargs == 1) *(char **) q->uuconf_pvar = (char *) ""; else if (cargs == 2) *(char **) q->uuconf_pvar = pzargs[1]; else return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; return UUCONF_CMDTABRET_KEEP; case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_INT): return _uuconf_iint (qglobal, pzargs[1], q->uuconf_pvar, TRUE); case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_LONG): return _uuconf_iint (qglobal, pzargs[1], q->uuconf_pvar, FALSE); case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_BOOLEAN): return _uuconf_iboolean (qglobal, pzargs[1], (int *) q->uuconf_pvar); case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FULLSTRING): if (cargs == 1) { char ***ppz = (char ***) q->uuconf_pvar; int iret; *ppz = NULL; iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppz, pblock); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; return UUCONF_CMDTABRET_CONTINUE; } else { char ***ppz = (char ***) q->uuconf_pvar; int i; *ppz = NULL; for (i = 1; i < cargs; i++) { int iret; iret = _uuconf_iadd_string (qglobal, pzargs[i], FALSE, FALSE, ppz, pblock); if (iret != UUCONF_SUCCESS) { *ppz = NULL; return iret | UUCONF_CMDTABRET_EXIT; } } return UUCONF_CMDTABRET_KEEP; } case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_FN): case UUCONF_TTYPE_CMDTABTYPE (UUCONF_CMDTABTYPE_PREFIX): return (*q->uuconf_pifn) (pglobal, cargs, pzargs, q->uuconf_pvar, pinfo); default: return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; } /*NOTREACHED*/ } _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 suucp-1.04/uuconf/cmdfil.c1004440004150000170000000502505337263606012271 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Read and parse commands from a file, updating uuconf_lineno as appropriate. */ int uuconf_cmd_file (pglobal, e, qtab, pinfo, pfiunknown, iflags, pblock) pointer pglobal; FILE *e; const struct uuconf_cmdtab *qtab; pointer pinfo; int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); int iflags; pointer pblock; { struct sglobal *qglobal = (struct sglobal *) pglobal; boolean fcont; char *zline; size_t cline; int iret; fcont = (iflags & UUCONF_CMDTABFLAG_BACKSLASH) != 0; zline = NULL; cline = 0; iret = UUCONF_SUCCESS; qglobal->ilineno = 0; while ((fcont ? _uuconf_getline (qglobal, &zline, &cline, e) : getline (&zline, &cline, e)) > 0) { ++qglobal->ilineno; iret = uuconf_cmd_line (pglobal, zline, qtab, pinfo, pfiunknown, iflags, pblock); if ((iret & UUCONF_CMDTABRET_KEEP) != 0) { iret &=~ UUCONF_CMDTABRET_KEEP; if (pblock != NULL) { if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; iret = (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_LINENO); break; } } zline = NULL; cline = 0; } if ((iret & UUCONF_CMDTABRET_EXIT) != 0) { iret &=~ UUCONF_CMDTABRET_EXIT; if (iret != UUCONF_SUCCESS) iret |= UUCONF_ERROR_LINENO; break; } iret = UUCONF_SUCCESS; } return iret; } _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 (iuucp-1.04/uuconf/cmdlin.c1004440004150000170000000666705337263606012316 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include #include /* Parse a command line into fields and process it via a command table. The command table functions may keep the memory allocated for the line, but they may not keep the memory allocated for the argv list. This function strips # comments. */ #define CSTACK (16) int uuconf_cmd_line (pglobal, zline, qtab, pinfo, pfiunknown, iflags, pblock) pointer pglobal; char *zline; const struct uuconf_cmdtab *qtab; pointer pinfo; int (*pfiunknown) P((pointer, int, char **, pointer, pointer)); int iflags; pointer pblock; { struct sglobal *qglobal = (struct sglobal *) pglobal; char *z; int cargs; char *azargs[CSTACK]; char **pzargs; int iret; /* Any # not preceeded by a backslash starts a comment. */ z = zline; while ((z = strchr (z, '#')) != NULL) { if (z == zline || *(z - 1) != '\\') { *z = '\0'; break; } /* Remove the backslash. */ while ((*(z - 1) = *z) != '\0') ++z; } /* Parse the first CSTACK arguments by hand to avoid malloc. */ z = zline; cargs = 0; pzargs = azargs; while (TRUE) { while (*z != '\0' && isspace (BUCHAR (*z))) ++z; if (*z == '\0') break; if (cargs >= CSTACK) { char **pzsplit; size_t csplit; int cmore; pzsplit = NULL; csplit = 0; cmore = _uuconf_istrsplit (z, '\0', &pzsplit, &csplit); if (cmore < 0) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } pzargs = (char **) malloc ((cmore + CSTACK) * sizeof (char *)); if (pzargs == NULL) { qglobal->ierrno = errno; free ((pointer) pzsplit); return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) pzargs, (pointer) azargs, CSTACK * sizeof (char *)); memcpy ((pointer) (pzargs + CSTACK), (pointer) pzsplit, cmore * sizeof (char *)); cargs = cmore + CSTACK; free ((pointer) pzsplit); break; } azargs[cargs] = z; ++cargs; while (*z != '\0' && ! isspace (BUCHAR (*z))) z++; if (*z == '\0') break; *z++ = '\0'; } if (cargs <= 0) return UUCONF_CMDTABRET_CONTINUE; iret = uuconf_cmd_args (pglobal, cargs, pzargs, qtab, pinfo, pfiunknown, iflags, pblock); if (pzargs != azargs) free ((pointer) pzargs); return iret; } else { size_t clen; clen = strlen (q->uuconf_zcmd); if ((iflauucp-1.04/uuconf/debfil.c1004440004150000170000000261005337263606012255 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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; } = NULL; return iret | UUCONF_CMDTABRET_EXIT; } } return UUCONF_CMDTABRET_KEEP; } case UUCONF_TTYPEuucp-1.04/uuconf/deblev.c1004440004150000170000000255705337263607012304 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } or of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucnuucp-1.04/uuconf/diacod.c1004440004150000170000000617005337263607012261 037777777777 1 0 /* 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.5 1993/01/01 16:49:10 ian Rel $"; #endif #include static int idcode P((pointer pglobal, int argc, char **argv, pointer pinfo, pointer pvar)); /* Get the name of the UUCP log file. */ int uuconf_dialcode (pglobal, zdial, pznum) pointer pglobal; const char *zdial; char **pznum; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_cmdtab as[2]; char **pz; int iret; as[0].uuconf_zcmd = zdial; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 0; as[0].uuconf_pvar = (pointer) pznum; as[0].uuconf_pifn = idcode; as[1].uuconf_zcmd = NULL; *pznum = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzdialcodefiles; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, (uuconf_cmdtabfn) NULL, 0, (pointer) NULL); (void) fclose (e); if (iret != UUCONF_SUCCESS || *pznum != NULL) break; } if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME; } else if (*pznum == NULL) iret = UUCONF_NOT_FOUND; return iret; } /* This is called if the dialcode is found. It copies the number into the heap and gets out of reading the file. */ /*ARGSUSED*/ static int idcode (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pznum = (char **) pvar; if (argc == 1) { *pznum = malloc (1); if (*pznum != NULL) **pznum = '\0'; } else if (argc == 2) *pznum = strdup (argv[1]); else return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; if (*pznum == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } return UUCONF_CMDTABRET_EXIT; } h> #include /* Parse a command line into fields and process it via a command table. The command table functions may keep the memory allocated for the line, but they may not keep the memory allocated for the argv list. This function strips # comments. */ #define CSTACK (16) int uuconf_cmd_line (pglobal, zline, qtab, pinfo, pfiunknown, iflags, pblock) pointer puucp-1.04/uuconf/dial.c1004440004150000170000000331305337263607011743 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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; } 37777777777 1 0 uucp-1.04/uuconf/diasub.c1004440004150000170000000421605337263607012304 037777777777 1 0 /* 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.3 1992/07/15 19:08:11 ian Rel $"; #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; } ls. 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" uucp-1.04/uuconf/dnams.c1004440004150000170000000506705337263610012136 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } LL, 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 (uucp-1.04/uuconf/errno.c1004440004150000170000000255005337263610012153 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Return the saved errno value. */ int uuconf_error_errno (pglobal) pointer pglobal; { struct sglobal *qglobal = (struct sglobal *) pglobal; if (qglobal == NULL) return errno; else return qglobal->ierrno; } ption) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warruucp-1.04/uuconf/errstr.c1004440004150000170000001256405337263610012355 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } am may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucnfi.h" #ifuucp-1.04/uuconf/filnam.c1004440004150000170000000253705337263610012301 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } et; } /* 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 (uucp-1.04/uuconf/freblk.c1004440004150000170000000337305337263611012300 037777777777 1 0 /* 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.4 1992/11/19 05:22:00 ian Rel $"; #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; } } 37777777777 1 0 uucp-1.04/uuconf/fredia.c1004440004150000170000000256305337263611012265 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } ere is no linenumber, the trailing colon is not output. If there is no filename, the linenumber is not output, and neither is the uucp-1.04/uuconf/free.c1004440004150000170000000364405337263611011755 037777777777 1 0 /* 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.3 1992/07/11 21:08:53 ian Rel $"; #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; } } } le > 0) { *zbuf++ = ' '; --cbuf; --cmsg; } ccopy = cmsg; if (cuucp-1.04/uuconf/freprt.c1004440004150000170000000254305337263611012333 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } cense, 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 tuucp-1.04/uuconf/fresys.c1004440004150000170000000255205337263611012344 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } se, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without evuucp-1.04/uuconf/grdcmp.c1004440004150000170000000374005337263612012306 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Compare two grades, returning < 0 if b1 should be executed before b2, == 0 if they are the same, or > 0 if b1 should be executed after b2. This can not fail, and does not return a standard uuconf error code. This implementation assumes that the upper case letters are in sequence, and that the lower case letters are in sequence. */ int uuconf_grade_cmp (barg1, barg2) int barg1; int barg2; { int b1, b2; /* Make sure the arguments are unsigned. */ b1 = (int) BUCHAR (barg1); b2 = (int) BUCHAR (barg2); if (isdigit (b1)) { if (isdigit (b2)) return b1 - b2; else return -1; } else if (isupper (b1)) { if (isdigit (b2)) return 1; else if (isupper (b2)) return b1 - b2; else return -1; } else { if (! islower (b2)) return 1; else return b1 - b2; } } ANY WARRANTY; without even the uucp-1.04/uuconf/hdial.c1004440004150000170000001042405337263612012110 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include #include /* Find a dialer in the HDB configuration files by name. */ int uuconf_hdb_dialer_info (pglobal, zname, qdialer) pointer pglobal; const char *zname; struct uuconf_dialer *qdialer; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pz; char *zline; size_t cline; char **pzsplit; size_t csplit; int iret; zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; iret = UUCONF_NOT_FOUND; for (pz = qglobal->qprocess->pzhdb_dialers; *pz != NULL; pz++) { FILE *e; int cchars; qglobal->ilineno = 0; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { int ctoks; pointer pblock; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; if (isspace (BUCHAR (zline[0])) || zline[0] == '#') continue; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } if (ctoks < 1) continue; if (strcmp (zname, pzsplit[0]) != 0) continue; /* We found the dialer. */ pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; _uuconf_uclear_dialer (qdialer); qdialer->uuconf_zname = pzsplit[0]; qdialer->uuconf_palloc = pblock; if (ctoks > 1) { /* The second field is characters to send instead of "=" and "-" in phone numbers. */ if (strcmp (pzsplit[1], "\"\"") == 0) { char *zsubs; char bnext; zsubs = pzsplit[1]; bnext = *zsubs; while (bnext != '\0') { if (bnext == '=') qdialer->uuconf_zdialtone = zsubs + 1; else if (bnext == '-') qdialer->uuconf_zpause = zsubs + 1; if (zsubs[1] == '\0') break; zsubs += 2; bnext = *zsubs; *zsubs = '\0'; } } /* Any remaining fields form a chat script. */ if (ctoks > 2) { pzsplit[1] = (char *) "chat"; iret = _uuconf_ichat_cmd (qglobal, ctoks - 1, pzsplit + 1, &qdialer->uuconf_schat, pblock); iret &=~ UUCONF_CMDTABRET_KEEP; if (iret != UUCONF_SUCCESS) { uuconf_free_block (pblock); break; } } } iret = UUCONF_SUCCESS; break; } (void) fclose (e); if (iret != UUCONF_NOT_FOUND) break; } if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } return iret; } are Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author 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 USEuucp-1.04/uuconf/hdnams.c1004440004150000170000000537505337263612012312 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include #include /* Get all the dialer names from the HDB Dialers file. */ int uuconf_hdb_dialer_names (pglobal, ppzdialers) pointer pglobal; char ***ppzdialers; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; char *zline; size_t cline; char **pz; *ppzdialers = NULL; iret = UUCONF_SUCCESS; zline = NULL; cline = 0; for (pz = qglobal->qprocess->pzhdb_dialers; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } qglobal->ilineno = 0; while (_uuconf_getline (qglobal, &zline, &cline, e) > 0) { ++qglobal->ilineno; /* Lines beginning with whitespace are treated as comments. No dialer name can contain a '#', which is another comment character, so eliminating the first '#' does no harm and catches comments. */ zline[strcspn (zline, " \t#\n")] = '\0'; if (*zline == '\0') continue; iret = _uuconf_iadd_string (qglobal, zline, TRUE, TRUE, ppzdialers, (pointer) NULL); if (iret != UUCONF_SUCCESS) { iret |= UUCONF_ERROR_LINENO; break; } } (void) fclose (e); } if (zline != NULL) free ((pointer) zline); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; return iret | UUCONF_ERROR_FILENAME; } if (*ppzdialers == NULL) iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppzdialers, (pointer) NULL); return UUCONF_SUCCESS; } 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 impliuucp-1.04/uuconf/hinit.c1004440004150000170000001767505337263612012161 037777777777 1 0 /* 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.4 1992/09/16 06:19:29 ian Rel $"; #endif #include #include /* Avoid replicating OLDCONFIGLIB several times if not necessary. */ static const char abHoldconfiglib[] = OLDCONFIGLIB; /* Initialize the routines which read HDB configuration files. */ int uuconf_hdb_init (ppglobal, zprogram) pointer *ppglobal; const char *zprogram; { struct sglobal **pqglobal = (struct sglobal **) ppglobal; int iret; struct sglobal *qglobal; pointer pblock; char abdialcodes[sizeof OLDCONFIGLIB + sizeof HDB_DIALCODES - 1]; char *zsys; FILE *e; if (*pqglobal == NULL) { iret = _uuconf_iinit_global (pqglobal); if (iret != UUCONF_SUCCESS) return iret; } qglobal = *pqglobal; pblock = qglobal->pblock; if (zprogram == NULL || strcmp (zprogram, "uucp") == 0) zprogram = "uucico"; /* Add the Dialcodes file to the global list. */ memcpy ((pointer) abdialcodes, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (abdialcodes + sizeof OLDCONFIGLIB - 1), (pointer) HDB_DIALCODES, sizeof HDB_DIALCODES); iret = _uuconf_iadd_string (qglobal, abdialcodes, TRUE, FALSE, &qglobal->qprocess->pzdialcodefiles, pblock); if (iret != UUCONF_SUCCESS) return iret; /* Read the Sysfiles file. We allocate the name on the heap rather than the stack so that we can return it in qerr->uuconf_zfilename. */ zsys = uuconf_malloc (pblock, sizeof OLDCONFIGLIB + sizeof HDB_SYSFILES - 1); if (zsys == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zsys, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (zsys + sizeof OLDCONFIGLIB - 1), (pointer) HDB_SYSFILES, sizeof HDB_SYSFILES); iret = UUCONF_SUCCESS; e = fopen (zsys, "r"); if (e == NULL) uuconf_free (pblock, zsys); else { char *zline; size_t cline; char **pzargs; size_t cargs; char **pzcolon; size_t ccolon; int cchars; zline = NULL; cline = 0; pzargs = NULL; cargs = 0; pzcolon = NULL; ccolon = 0; qglobal->ilineno = 0; while (iret == UUCONF_SUCCESS && (cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { int ctypes, cnames; int i; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; if (isspace (BUCHAR (zline[0])) || zline[0] == '#') continue; ctypes = _uuconf_istrsplit (zline, '\0', &pzargs, &cargs); if (ctypes < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } if (ctypes == 0) continue; if (strncmp (pzargs[0], "service=", sizeof "service=" - 1) != 0) { iret = UUCONF_SYNTAX_ERROR; break; } pzargs[0] += sizeof "service=" - 1; cnames = _uuconf_istrsplit (pzargs[0], ':', &pzcolon, &ccolon); if (cnames < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } for (i = 0; i < cnames; i++) if (strcmp (zprogram, pzcolon[i]) == 0) break; if (i >= cnames) continue; for (i = 1; i < ctypes && iret == UUCONF_SUCCESS; i++) { char ***ppz; int cfiles, ifile; if (strncmp (pzargs[i], "systems=", sizeof "systems=" - 1) == 0) { ppz = &qglobal->qprocess->pzhdb_systems; pzargs[i] += sizeof "systems=" - 1; } else if (strncmp (pzargs[i], "devices=", sizeof "devices=" - 1) == 0) { ppz = &qglobal->qprocess->pzhdb_devices; pzargs[i] += sizeof "devices=" - 1; } else if (strncmp (pzargs[i], "dialers=", sizeof "dialers=" - 1) == 0) { ppz = &qglobal->qprocess->pzhdb_dialers; pzargs[i] += sizeof "dialers=" - 1; } else { iret = UUCONF_SYNTAX_ERROR; break; } cfiles = _uuconf_istrsplit (pzargs[i], ':', &pzcolon, &ccolon); if (cfiles < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } for (ifile = 0; ifile < cfiles && iret == UUCONF_SUCCESS; ifile++) { /* Looking for a leading '/' is Unix dependent, and should probably be changed. */ if (pzcolon[ifile][0] == '/') iret = _uuconf_iadd_string (qglobal, pzcolon[ifile], TRUE, FALSE, ppz, pblock); else { char *zdir; size_t clen; clen = strlen (pzcolon[ifile]); zdir = (char *) uuconf_malloc (pblock, (sizeof OLDCONFIGLIB + sizeof HDB_SEPARATOR + clen - 1)); if (zdir == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) zdir, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (zdir + sizeof OLDCONFIGLIB - 1), HDB_SEPARATOR, sizeof HDB_SEPARATOR - 1); memcpy ((pointer) (zdir + sizeof OLDCONFIGLIB - 1 + sizeof HDB_SEPARATOR - 1), (pointer) pzcolon[ifile], clen + 1); iret = _uuconf_iadd_string (qglobal, zdir, FALSE, FALSE, ppz, pblock); } } } } (void) fclose (e); if (zline != NULL) free ((pointer) zline); if (pzargs != NULL) free ((pointer) pzargs); if (pzcolon != NULL) free ((pointer) pzcolon); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = zsys; return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } } if (qglobal->qprocess->pzhdb_systems == NULL) { char ab[sizeof OLDCONFIGLIB + sizeof HDB_SYSTEMS - 1]; memcpy ((pointer) ab, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), (pointer) HDB_SYSTEMS, sizeof HDB_SYSTEMS); iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, &qglobal->qprocess->pzhdb_systems, pblock); } if (qglobal->qprocess->pzhdb_devices == NULL && iret == UUCONF_SUCCESS) { char ab[sizeof OLDCONFIGLIB + sizeof HDB_DEVICES - 1]; memcpy ((pointer) ab, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), (pointer) HDB_DEVICES, sizeof HDB_DEVICES); iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, &qglobal->qprocess->pzhdb_devices, pblock); } if (qglobal->qprocess->pzhdb_dialers == NULL && iret == UUCONF_SUCCESS) { char ab[sizeof OLDCONFIGLIB + sizeof HDB_DIALERS - 1]; memcpy ((pointer) ab, (pointer) abHoldconfiglib, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (ab + sizeof OLDCONFIGLIB - 1), (pointer) HDB_DIALERS, sizeof HDB_DIALERS); iret = _uuconf_iadd_string (qglobal, ab, TRUE, FALSE, &qglobal->qprocess->pzhdb_dialers, pblock); } return iret; } ar **pz; *ppzdialers = NULL; iret = UUCONF_SUCCESS; zline uucp-1.04/uuconf/hlocnm.c1004440004150000170000000443505337263613012315 037777777777 1 0 /* 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.4 1992/11/14 23:13:40 ian Rel $"; #endif #include /* Get the local name to use, based on the login name, from the HDB configuration files. */ int uuconf_hdb_login_localname (pglobal, zlogin, pzname) pointer pglobal; const char *zlogin; char **pzname; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct shpermissions *qperm; if (! qglobal->qprocess->fhdb_read_permissions) { int iret; iret = _uuconf_ihread_permissions (qglobal); if (iret != UUCONF_SUCCESS) return iret; } for (qperm = qglobal->qprocess->qhdb_permissions; qperm != NULL; qperm = qperm->qnext) { if (qperm->zmyname != NULL && qperm->zmyname != (char *) &_uuconf_unset && qperm->pzlogname != NULL && qperm->pzlogname != (char **) &_uuconf_unset) { char **pz; for (pz = qperm->pzlogname; *pz != NULL; pz++) { if (strcmp (*pz, zlogin) == 0) { *pzname = strdup (qperm->zmyname); if (*pzname == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } return UUCONF_SUCCESS; } } } } *pzname = NULL; return UUCONF_NOT_FOUND; } the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #incuucp-1.04/uuconf/hport.c1004440004150000170000002337605337263613012176 037777777777 1 0 /* 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.6 1993/01/31 02:53:24 ian Rel $"; #endif #include #include /* Find a port in the HDB configuration files by name, baud rate, and special purpose function. */ int uuconf_hdb_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) pointer pglobal; const char *zname; long ibaud; long ihighbaud; int (*pifn) P((struct uuconf_port *, pointer)); pointer pinfo; struct uuconf_port *qport; { struct sglobal *qglobal = (struct sglobal *) pglobal; char *zline; size_t cline; char **pzsplit; size_t csplit; int iret; char **pz; zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; iret = UUCONF_NOT_FOUND; for (pz = qglobal->qprocess->pzhdb_devices; *pz != NULL; pz++) { FILE *e; int cchars; qglobal->ilineno = 0; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } iret = UUCONF_NOT_FOUND; while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { int ctoks; char *z, *zprotos, *zport; long ilow, ihigh; pointer pblock; ++qglobal->ilineno; iret = UUCONF_NOT_FOUND; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; if (isspace (BUCHAR (zline[0])) || zline[0] == '#') continue; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } /* An entry in Devices is type device dial-device baud dialer-token pairs The type (normally "ACU") is treated as the name. */ /* If there aren't enough entries, ignore the line; this should probably do something more useful. */ if (ctoks < 4) continue; /* There may be a comma separated list of protocols after the name. */ zprotos = strchr (pzsplit[0], ','); if (zprotos != NULL) { *zprotos = '\0'; ++zprotos; } zport = pzsplit[0]; /* Get any modem class, and pick up the baud rate while we're at it. The modem class will be appended to the name, so we need to get it before we see if we've found the port with the right name. */ z = pzsplit[3]; if (strcasecmp (z, "Any") == 0 || strcmp (z, "-") == 0) { ilow = 0L; ihigh = 0L; } else { char *zend; while (*z != '\0' && ! isdigit (BUCHAR (*z))) ++z; ilow = strtol (z, &zend, 10); if (*zend == '-') ihigh = strtol (zend + 1, (char **) NULL, 10); else ihigh = ilow; if (z != pzsplit[3]) { size_t cclass, cport; cclass = z - pzsplit[3]; cport = strlen (pzsplit[0]); zport = malloc (cport + cclass + 1); if (zport == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) zport, (pointer) pzsplit[0], cport); memcpy ((pointer) (zport + cport), (pointer) pzsplit[3], cclass); zport[cport + cclass] = '\0'; } } /* Make sure the name and baud rate match any argument. */ if ((zname != NULL && strcmp (zport, zname) != 0) || (ibaud != 0 && ilow != 0 && (ilow > ibaud || ihigh < ibaud))) { if (zport != pzsplit[0]) free ((pointer) zport); continue; } /* Some systems permit ,M after the device name. This means to open the port with O_NDELAY and then change it. We just ignore this flag, although perhaps we should record it somewhere. */ pzsplit[1][strcspn (pzsplit[1], ",")] = '\0'; /* Now we must construct the port information, so that we can pass it to pifn. The port type is determined by its name, unfortunately. The name "Direct" is used for a direct port, "TCP" for a TCP port, and anything else for a modem port. */ pblock = NULL; _uuconf_uclear_port (qport); qport->uuconf_zname = zport; qport->uuconf_zprotocols = zprotos; if (strcmp (pzsplit[0], "Direct") == 0) { qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT; qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1]; qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow; } else if (strcmp (pzsplit[0], "TCP") == 0) { /* For a TCP port, the device name is taken as the TCP port to use. */ qport->uuconf_ttype = UUCONF_PORTTYPE_TCP; qport->uuconf_ireliable = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[1]; } else if (ctoks >= 5 && (strcmp (pzsplit[4], "TLI") == 0 || strcmp (pzsplit[4], "TLIS") == 0)) { size_t c; char **pzd; qport->uuconf_ttype = UUCONF_PORTTYPE_TLI; qport->uuconf_u.uuconf_stli.uuconf_zdevice = pzsplit[1]; qport->uuconf_u.uuconf_stli.uuconf_fstream = strcmp (pzsplit[4], "TLIS") == 0; qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL; pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } c = (ctoks - 4) * sizeof (char *); pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); if (pzd == NULL) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); pzd[ctoks - 4] = NULL; qport->uuconf_u.uuconf_stli.uuconf_pzdialer = pzd; qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL; qport->uuconf_ireliable = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); } else { qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM; qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1]; if (strcmp (pzsplit[2], "-") != 0) qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = pzsplit[2]; else qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; if (ilow == ihigh) { qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow; qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; } else { qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow; qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh; } qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; if (ctoks < 5) qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; else { size_t c; char **pzd; pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } c = (ctoks - 4) * sizeof (char *); pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); if (pzd == NULL) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); pzd[ctoks - 4] = NULL; qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd; } qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; } if (pifn != NULL) { iret = (*pifn) (qport, pinfo); if (iret != UUCONF_SUCCESS) { if (zport != pzsplit[0]) free ((pointer) zport); if (pblock != NULL) uuconf_free_block (pblock); if (iret != UUCONF_NOT_FOUND) break; continue; } } /* This is the port we want. */ if (pblock == NULL) { pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } } if (uuconf_add_block (pblock, zline) != 0 || (zport != pzsplit[0] && uuconf_add_block (pblock, zport) != 0)) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; qport->uuconf_palloc = pblock; break; } (void) fclose (e); if (iret != UUCONF_NOT_FOUND) break; } if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } return iret; } 37777777777 1 0 uucp-1.04/uuconf/hrmunk.c1004440004150000170000000341105337263613012332 037777777777 1 0 /* 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 1992/09/14 22:07:51 ian Rel $"; #endif #include /* Get the name of the HDB remote.unknown shell script. */ int uuconf_hdb_remote_unknown (pglobal, pzname) pointer pglobal; char **pzname; { struct sglobal *qglobal = (struct sglobal *) pglobal; size_t csize; csize = sizeof OLDCONFIGLIB + sizeof HDB_REMOTE_UNKNOWN - 1; *pzname = malloc (csize); if (*pzname == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy (*pzname, OLDCONFIGLIB, sizeof OLDCONFIGLIB - 1); memcpy (*pzname + sizeof OLDCONFIGLIB - 1, HDB_REMOTE_UNKNOWN, sizeof HDB_REMOTE_UNKNOWN); return UUCONF_SUCCESS; } ++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,uucp-1.04/uuconf/hsinfo.c1004440004150000170000004064205337263613012323 037777777777 1 0 /* 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.6 1992/11/14 16:16:24 ian Rel $"; #endif #include #include static int ihadd_machine_perm P((struct sglobal *qglobal, struct uuconf_system *qsys, struct shpermissions *qperm)); static int ihadd_logname_perm P((struct sglobal *qglobal, struct uuconf_system *qsys, struct shpermissions *qperm)); /* Get the information for a particular system from the HDB configuration files. This does not make sure that all the default values are set. */ int _uuconf_ihdb_system_internal (qglobal, zsystem, qsys) struct sglobal *qglobal; const char *zsystem; struct uuconf_system *qsys; { int iret; struct shpermissions *qperm; char *zline; size_t cline; char **pzsplit; size_t csplit; char **pzcomma; size_t ccomma; pointer pblock; char **pz; boolean ffound_machine, ffound_login; struct shpermissions *qother_machine; struct uuconf_system *qalt; if (! qglobal->qprocess->fhdb_read_permissions) { iret = _uuconf_ihread_permissions (qglobal); if (iret != UUCONF_SUCCESS) return iret; } /* First look through the Permissions information to see if this is an alias for some system. I assume that an alias applies to the first name in the corresponding MACHINE entry. */ for (qperm = qglobal->qprocess->qhdb_permissions; qperm != NULL; qperm = qperm->qnext) { if (qperm->pzalias == NULL || qperm->pzmachine == NULL || qperm->pzalias == (char **) &_uuconf_unset || qperm->pzmachine == (char **) &_uuconf_unset) continue; for (pz = qperm->pzalias; *pz != NULL; pz++) { if (strcmp (*pz, zsystem) == 0) { zsystem = qperm->pzmachine[0]; break; } } if (*pz != NULL) break; } zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; pzcomma = NULL; ccomma = 0; pblock = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++) { FILE *e; int cchars; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } qglobal->ilineno = 0; while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { int ctoks, ctimes, i; struct uuconf_system *qset; char *z, *zretry; int cretry; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; if (isspace (BUCHAR (zline[0])) || zline[0] == '#') continue; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } /* If this isn't the system we're looking for, keep reading the file. */ if (ctoks < 1 || strcmp (zsystem, pzsplit[0]) != 0) continue; /* If this is the first time we've found the system, we want to set *qsys directly. Otherwise, we allocate a new alternate. */ if (pblock == NULL) { pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_system (qsys); qsys->uuconf_palloc = pblock; qset = qsys; } else { struct uuconf_system **pq; qset = ((struct uuconf_system *) uuconf_malloc (pblock, sizeof (struct uuconf_system))); if (qset == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_system (qset); for (pq = &qsys->uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qset; } /* Add this line to the memory block we are building for the system. */ if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; cline = 0; /* The format of a line in Systems is system time device speed phone chat For example, airs Any ACU 9600 5551212 ogin: foo pass: bar */ /* Get the system name. */ qset->uuconf_zname = pzsplit[0]; qset->uuconf_fcall = TRUE; qset->uuconf_fcalled = FALSE; if (ctoks < 2) continue; /* A time string is "time/grade,time/grade;retry". A missing grade is taken as BGRADE_LOW. */ zretry = strchr (pzsplit[1], ';'); if (zretry == NULL) cretry = 0; else { *zretry = '\0'; cretry = (int) strtol (zretry + 1, (char **) NULL, 10); } ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma); if (ctimes < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } for (i = 0; i < ctimes; i++) { char *zslash; char bgrade; z = pzcomma[i]; zslash = strchr (z, '/'); if (zslash == NULL) bgrade = UUCONF_GRADE_LOW; else { *zslash = '\0'; bgrade = zslash[1]; if (! UUCONF_GRADE_LEGAL (bgrade)) bgrade = UUCONF_GRADE_LOW; } iret = _uuconf_itime_parse (qglobal, z, (long) bgrade, cretry, _uuconf_itime_grade_cmp, &qset->uuconf_qtimegrade, pblock); if (iret != UUCONF_SUCCESS) break; } if (iret != UUCONF_SUCCESS) break; if (ctoks < 3) continue; /* Pick up the device name. It can be followed by a comma and a list of protocols. */ qset->uuconf_zport = pzsplit[2]; z = strchr (pzsplit[2], ','); if (z != NULL) { qset->uuconf_zprotocols = z + 1; *z = '\0'; } if (ctoks < 4) continue; /* The speed entry can be a numeric speed, or a range of speeds, or "Any", or "-". If it starts with a letter, the initial nonnumeric prefix is a modem class, which gets appended to the port name. */ z = pzsplit[3]; if (strcasecmp (z, "Any") != 0 && strcmp (z, "-") != 0) { char *zend; while (*z != '\0' && ! isdigit (BUCHAR (*z))) ++z; qset->uuconf_ibaud = strtol (z, &zend, 10); if (*zend == '-') qset->uuconf_ihighbaud = strtol (zend + 1, (char **) NULL, 10); if (z != pzsplit[3]) { size_t cport, cclass; cport = strlen (pzsplit[2]); cclass = z - pzsplit[3]; qset->uuconf_zport = uuconf_malloc (pblock, cport + cclass + 1); if (qset->uuconf_zport == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) qset->uuconf_zport, (pointer) pzsplit[2], cport); memcpy ((pointer) (qset->uuconf_zport + cport), (pointer) pzsplit[3], cclass); qset->uuconf_zport[cport + cclass] = '\0'; } } if (ctoks < 5) continue; /* Get the phone number. */ qset->uuconf_zphone = pzsplit[4]; if (ctoks < 6) continue; /* Get the chat script. We just hand this off to the chat script processor, so that it will parse subsend and subexpect strings correctly. */ pzsplit[4] = (char *) "chat"; iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4, &qset->uuconf_schat, pblock); iret &=~ UUCONF_CMDTABRET_KEEP; if (iret != UUCONF_SUCCESS) break; } (void) fclose (e); if (iret != UUCONF_SUCCESS) break; } if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); if (pzcomma != NULL) free ((pointer) pzcomma); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; return iret | UUCONF_ERROR_FILENAME; } if (pblock == NULL) return UUCONF_NOT_FOUND; /* Now we have to put in the Permissions information. The relevant Permissions entries are those with this system in the MACHINE list and (if this system does not have a VALIDATE entry) those with a LOGNAME list but no MACHINE list. If no entry is found with this system in the MACHINE list, then we must look for an entry with "OTHER" in the MACHINE list. */ ffound_machine = FALSE; ffound_login = FALSE; qother_machine = NULL; for (qperm = qglobal->qprocess->qhdb_permissions; qperm != NULL; qperm = qperm->qnext) { boolean fmachine; /* MACHINE=OTHER is recognized specially. It appears that OTHER need only be recognized by itself, not when combined with other machine names. */ if (qother_machine == NULL && qperm->pzmachine != NULL && qperm->pzmachine != (char **) &_uuconf_unset && qperm->pzmachine[0][0] == 'O' && strcmp (qperm->pzmachine[0], "OTHER") == 0) qother_machine = qperm; /* If this system is named in a MACHINE entry, we must add the appropriate information to every alternate that could be used for calling out. */ fmachine = FALSE; if (! ffound_machine && qperm->pzmachine != NULL && qperm->pzmachine != (char **) &_uuconf_unset) { for (pz = qperm->pzmachine; *pz != NULL; pz++) { if ((*pz)[0] == zsystem[0] && strcmp (*pz, zsystem) == 0) { for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) { if (qalt->uuconf_fcall) { iret = ihadd_machine_perm (qglobal, qalt, qperm); if (iret != UUCONF_SUCCESS) return iret; } } fmachine = TRUE; ffound_machine = TRUE; break; } } } /* A LOGNAME line applies to this machine if it is listed in the corresponding VALIDATE entry, or if it is not listed in any VALIDATE entry. On this pass through the Permissions entry we pick up the information if the system appears in a VALIDATE entry; if it does not, we make another pass to put in all the LOGNAME lines. */ if (qperm->pzlogname != NULL && qperm->pzlogname != (char **) &_uuconf_unset && qperm->pzvalidate != NULL && qperm->pzvalidate != (char **) &_uuconf_unset) { for (pz = qperm->pzvalidate; *pz != NULL; ++pz) if ((*pz)[0] == zsystem[0] && strcmp (*pz, zsystem) == 0) break; if (*pz != NULL) { for (pz = qperm->pzlogname; *pz != NULL; ++pz) { /* If this LOGNAME line is also a matching MACHINE line, we can add the LOGNAME permissions to the first alternate. Otherwise, we must create a new alternate. We cannot put a LOGNAME line in the first alternate if MACHINE does not match, because certain permissions (e.g. READ) may be specified by both types of lines, and we must use LOGNAME entries only when accepting calls and MACHINE entries only when placing calls. */ if (fmachine && (qsys->uuconf_zcalled_login == NULL || (qsys->uuconf_zcalled_login == (char *) &_uuconf_unset))) { qsys->uuconf_zcalled_login = *pz; iret = ihadd_logname_perm (qglobal, qsys, qperm); } else { struct uuconf_system *qnew; struct uuconf_system **pq; qnew = ((struct uuconf_system *) uuconf_malloc (pblock, sizeof (struct uuconf_system))); if (qnew == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } *qnew = *qsys; qnew->uuconf_qalternate = NULL; for (pq = &qsys->uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qnew; qnew->uuconf_zcalled_login = *pz; qnew->uuconf_fcall = FALSE; iret = ihadd_logname_perm (qglobal, qnew, qperm); } if (iret != UUCONF_SUCCESS) return iret; } ffound_login = TRUE; } } } /* If we didn't find an entry for the machine, we must use the MACHINE=OTHER entry, if any. */ if (! ffound_machine && qother_machine != NULL) { for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) { if (qalt->uuconf_fcall) { iret = ihadd_machine_perm (qglobal, qalt, qother_machine); if (iret != UUCONF_SUCCESS) return iret; } } } /* If this system was not listed in any VALIDATE entry, then we must add a called-login for each LOGNAME entry in Permissions. */ if (! ffound_login) { for (qperm = qglobal->qprocess->qhdb_permissions; qperm != NULL; qperm = qperm->qnext) { if (qperm->pzlogname == NULL || qperm->pzlogname == (char **) &_uuconf_unset) continue; for (pz = qperm->pzlogname; *pz != NULL; pz++) { struct uuconf_system *qnew; struct uuconf_system **pq; qnew = ((struct uuconf_system *) uuconf_malloc (pblock, sizeof (struct uuconf_system))); if (qnew == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } *qnew = *qsys; qnew->uuconf_qalternate = NULL; for (pq = &qsys->uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qnew; /* We recognize LOGNAME=OTHER specially, although this appears to be an SCO innovation. */ if (strcmp (*pz, "OTHER") == 0) qnew->uuconf_zcalled_login = (char *) "ANY"; else qnew->uuconf_zcalled_login = *pz; qnew->uuconf_fcall = FALSE; iret = ihadd_logname_perm (qglobal, qnew, qperm); if (iret != UUCONF_SUCCESS) return iret; } } } /* HDB permits local requests to receive to any directory, which is not the default put in by _uuconf_isystem_basic_default. We set it here instead. */ for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) { iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, FALSE, FALSE, &qalt->uuconf_pzlocal_receive, pblock); if (iret != UUCONF_SUCCESS) return iret; } /* HDB does not have a maximum number of retries if a retry time is given in the time field. */ if (qsys->uuconf_qtimegrade != NULL && qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset && qsys->uuconf_qtimegrade->uuconf_cretry > 0) qsys->uuconf_cmax_retries = 0; return UUCONF_SUCCESS; } /* Add the settings of a MACHINE line in Permissions to a system. */ /*ARGSIGNORED*/ static int ihadd_machine_perm (qglobal, qsys, qperm) struct sglobal *qglobal; struct uuconf_system *qsys; struct shpermissions *qperm; { if (qperm->frequest >= 0) qsys->uuconf_fsend_request = qperm->frequest; else qsys->uuconf_fsend_request = FALSE; qsys->uuconf_pzremote_send = qperm->pzread; qsys->uuconf_pzremote_receive = qperm->pzwrite; qsys->uuconf_pzcmds = qperm->pzcommands; qsys->uuconf_zlocalname = qperm->zmyname; qsys->uuconf_zpubdir = qperm->zpubdir; qsys->uuconf_pzalias = qperm->pzalias; return UUCONF_SUCCESS; } /* Add the settings of a LOGNAME line in Permissions to a system. */ /*ARGSIGNORED*/ static int ihadd_logname_perm (qglobal, qsys, qperm) struct sglobal *qglobal; struct uuconf_system *qsys; struct shpermissions *qperm; { qsys->uuconf_fcalled = TRUE; if (qperm->frequest >= 0) qsys->uuconf_fsend_request = qperm->frequest; else qsys->uuconf_fsend_request = FALSE; qsys->uuconf_fcalled_transfer = qperm->fsendfiles; qsys->uuconf_pzremote_send = qperm->pzread; qsys->uuconf_pzremote_receive = qperm->pzwrite; qsys->uuconf_fcallback = qperm->fcallback; qsys->uuconf_zlocalname = qperm->zmyname; qsys->uuconf_zpubdir = qperm->zpubdir; return UUCONF_SUCCESS; } break; } if (iret != UUCONF_SUCCESS) break; if (ctoks < 3) continue; uucp-1.04/uuconf/hsnams.c1004440004150000170000000676405337263614012336 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include #include /* Get all the system names from the HDB Systems file. We have to read the Permissions file in order to support aliases. */ int uuconf_hdb_system_names (pglobal, ppzsystems, falias) pointer pglobal; char ***ppzsystems; int falias; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; char *zline; size_t cline; char **pz; *ppzsystems = NULL; iret = UUCONF_SUCCESS; zline = NULL; cline = 0; for (pz = qglobal->qprocess->pzhdb_systems; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } qglobal->ilineno = 0; while (_uuconf_getline (qglobal, &zline, &cline, e) > 0) { ++qglobal->ilineno; /* Lines beginning with whitespace are treated as comments. No system name can contain a '#', which is another comment character, so eliminating the first '#' does no harm and catches comments. */ zline[strcspn (zline, " \t#\n")] = '\0'; if (*zline == '\0') continue; iret = _uuconf_iadd_string (qglobal, zline, TRUE, TRUE, ppzsystems, (pointer) NULL); if (iret != UUCONF_SUCCESS) { iret |= UUCONF_ERROR_LINENO; break; } } (void) fclose (e); } if (zline != NULL) free ((pointer) zline); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; return iret | UUCONF_ERROR_FILENAME; } /* If we are supposed to return aliases, we must read the Permissions file. */ if (falias) { struct shpermissions *q; if (! qglobal->qprocess->fhdb_read_permissions) { iret = _uuconf_ihread_permissions (qglobal); if (iret != UUCONF_SUCCESS) return iret; } for (q = qglobal->qprocess->qhdb_permissions; q != NULL; q = q->qnext) { pz = q->pzalias; if (pz == NULL || pz == (char **) &_uuconf_unset) continue; for (; *pz != NULL; pz++) { iret = _uuconf_iadd_string (qglobal, *pz, TRUE, TRUE, ppzsystems, (pointer) NULL); if (iret != UUCONF_SUCCESS) return iret; } } } if (*ppzsystems == NULL) iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppzsystems, (pointer) NULL); return iret; } OGNAME line uucp-1.04/uuconf/hsys.c1004440004150000170000000325605337263614012024 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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); } f 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 (iuucp-1.04/uuconf/hunk.c1004440004150000170000000776605337263614012015 037777777777 1 0 /* 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.3 1992/08/23 21:00:19 ian Rel $"; #endif #include /* Get information about an unknown system from the HDB Permissions file. This doesn't run the remote.unknown shell script, because that's too system dependent. */ int uuconf_hdb_system_unknown (pglobal, qsys) pointer pglobal; struct uuconf_system *qsys; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; boolean ffirst; struct shpermissions *qperm; struct uuconf_system *qalt; if (! qglobal->qprocess->fhdb_read_permissions) { iret = _uuconf_ihread_permissions (qglobal); if (iret != UUCONF_SUCCESS) return iret; } _uuconf_uclear_system (qsys); qsys->uuconf_palloc = uuconf_malloc_block (); if (qsys->uuconf_palloc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } ffirst = TRUE; for (qperm = qglobal->qprocess->qhdb_permissions; qperm != NULL; qperm = qperm->qnext) { char **pz; if (qperm->pzlogname == NULL || qperm->pzlogname == (char **) &_uuconf_unset) continue; for (pz = qperm->pzlogname; *pz != NULL; pz++) { if (ffirst) { qalt = qsys; ffirst = FALSE; } else { struct uuconf_system **pq; qalt = ((struct uuconf_system *) uuconf_malloc (qsys->uuconf_palloc, sizeof (struct uuconf_system))); if (qalt == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } _uuconf_uclear_system (qalt); for (pq = &qsys->uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qalt; } /* We recognize LOGNAME=OTHER specially, although this appears to be an SCO innovation. */ if (strcmp (*pz, "OTHER") == 0) qalt->uuconf_zcalled_login = (char *) "ANY"; else qalt->uuconf_zcalled_login = *pz; qalt->uuconf_fcall = FALSE; qsys->uuconf_fcalled = TRUE; if (qperm->frequest >= 0) qsys->uuconf_fsend_request = qperm->frequest; else qsys->uuconf_fsend_request = FALSE; qsys->uuconf_fcalled_transfer = qperm->fsendfiles; qsys->uuconf_pzremote_send = qperm->pzread; qsys->uuconf_pzremote_receive = qperm->pzwrite; qsys->uuconf_fcallback = qperm->fcallback; qsys->uuconf_zlocalname = qperm->zmyname; qsys->uuconf_zpubdir = qperm->zpubdir; } } if (ffirst) return UUCONF_NOT_FOUND; /* HDB permits local requests to receive to any directory, which is not the default put in by _uuconf_isystem_basic_default. We set it here instead. */ for (qalt = qsys; qalt != NULL; qalt = qalt->uuconf_qalternate) { iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, FALSE, FALSE, &qalt->uuconf_pzlocal_receive, qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } return _uuconf_isystem_basic_default (qglobal, qsys); } but WITuucp-1.04/uuconf/iniglb.c1004440004150000170000001224105337263614012274 037777777777 1 0 /* 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.6 1992/08/24 02:50:41 ian Rel $"; #endif #include /* Initialize the global information structure. */ int _uuconf_iinit_global (pqglobal) struct sglobal **pqglobal; { pointer pblock; register struct sprocess *qprocess; char *azargs[3]; int iret; pblock = uuconf_malloc_block (); if (pblock == NULL) return UUCONF_MALLOC_FAILED; *pqglobal = (struct sglobal *) uuconf_malloc (pblock, sizeof (struct sglobal)); if (*pqglobal == NULL) { uuconf_free_block (pblock); return UUCONF_MALLOC_FAILED; } (*pqglobal)->qprocess = ((struct sprocess *) uuconf_malloc (pblock, sizeof (struct sprocess))); if ((*pqglobal)->qprocess == NULL) { uuconf_free_block (pblock); *pqglobal = NULL; return UUCONF_MALLOC_FAILED; } (*pqglobal)->pblock = pblock; (*pqglobal)->ierrno = 0; (*pqglobal)->ilineno = 0; (*pqglobal)->zfilename = NULL; qprocess = (*pqglobal)->qprocess; qprocess->zlocalname = NULL; qprocess->zspooldir = SPOOLDIR; qprocess->zpubdir = PUBDIR; #ifdef LOCKDIR qprocess->zlockdir = LOCKDIR; #else qprocess->zlockdir = SPOOLDIR; #endif qprocess->zlogfile = LOGFILE; qprocess->zstatsfile = STATFILE; qprocess->zdebugfile = DEBUGFILE; qprocess->zdebug = ""; qprocess->cmaxuuxqts = 0; qprocess->fv2 = TRUE; qprocess->fhdb = TRUE; qprocess->pzdialcodefiles = NULL; qprocess->pztimetables = NULL; qprocess->zconfigfile = NULL; qprocess->pzsysfiles = NULL; qprocess->pzportfiles = NULL; qprocess->pzdialfiles = NULL; qprocess->pzpwdfiles = NULL; qprocess->pzcallfiles = NULL; qprocess->qunknown = NULL; qprocess->fread_syslocs = FALSE; qprocess->qsyslocs = NULL; qprocess->qvalidate = NULL; qprocess->fuses_myname = FALSE; qprocess->zv2systems = NULL; qprocess->zv2devices = NULL; qprocess->zv2userfile = NULL; qprocess->zv2cmds = NULL; qprocess->pzhdb_systems = NULL; qprocess->pzhdb_devices = NULL; qprocess->pzhdb_dialers = NULL; qprocess->fhdb_read_permissions = FALSE; qprocess->qhdb_permissions = NULL; azargs[0] = NULL; azargs[1] = (char *) "Evening"; azargs[2] = (char *) "Wk1705-0755,Sa,Su"; iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, (pointer) NULL, (pointer) NULL); if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) { azargs[1] = (char *) "Night"; azargs[2] = (char *) "Wk2305-0755,Sa,Su2305-1655"; iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, (pointer) NULL, (pointer) NULL); } if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) { azargs[1] = (char *) "NonPeak"; azargs[2] = (char *) "Wk1805-0655,Sa,Su"; iret = _uuconf_itimetable ((pointer) *pqglobal, 3, azargs, (pointer) NULL, (pointer) NULL); } if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) { uuconf_free_block (pblock); *pqglobal = NULL; /* Strip off any special bits, since there's no global structure. */ return UUCONF_ERROR_VALUE (iret); } return UUCONF_SUCCESS; } /* Add a timetable. This is also called by the Taylor UUCP initialization code, as well as by the Taylor UUCP sys file code (although the latter is obsolete). There's no point in putting this in a separate file, since everything must call _uuconf_init_global. There is a race condition here if this is called by two different threads on a sys file command, but the sys file command is obsolete anyhow. */ /*ARGSUSED*/ int _uuconf_itimetable (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; iret = _uuconf_iadd_string (qglobal, argv[1], FALSE, FALSE, &qglobal->qprocess->pztimetables, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; iret = _uuconf_iadd_string (qglobal, argv[2], FALSE, FALSE, &qglobal->qprocess->pztimetables, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; return UUCONF_CMDTABRET_KEEP; } 37777777777 1 0 uucp-1.04/uuconf/init.c1004440004150000170000000401705337263615011776 037777777777 1 0 /* 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.4 1992/09/24 02:00:32 ian Rel $"; #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; } global->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->uuconfuucp-1.04/uuconf/int.c1004440004150000170000000344505337263615011631 037777777777 1 0 /* 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.3 1992/10/15 02:12:23 ian Rel $"; #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; } Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #incluuucp-1.04/uuconf/lckdir.c1004440004150000170000000260105337263615012300 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } NULL; qprocess->zv2userfile = NULL; qprocess->zv2cmds = NULL; qprocess->pzhdb_systems = NULL; qprocess->pzhdb_devices uucp-1.04/uuconf/lineno.c1004440004150000170000000252505337263615012321 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; iret = _uuconf_iadd_string (qglobal, argv[2], FALSE, FALSE, &qglobuucp-1.04/uuconf/llocnm.c1004440004150000170000000374305337263615012324 037777777777 1 0 /* 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.4 1992/10/15 02:12:23 ian Rel $"; #endif #include /* Get the local name to use, given a login name. */ int uuconf_login_localname (pglobal, zlogin, pzname) pointer pglobal; const char *zlogin; char **pzname; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; #if HAVE_TAYLOR_CONFIG iret = uuconf_taylor_login_localname (pglobal, zlogin, pzname); if (iret != UUCONF_NOT_FOUND) return iret; #endif #if HAVE_HDB_CONFIG iret = uuconf_hdb_login_localname (pglobal, zlogin, pzname); if (iret != UUCONF_NOT_FOUND) return iret; #endif if (qglobal->qprocess->zlocalname != NULL) { *pzname = strdup ((char *) qglobal->qprocess->zlocalname); if (*pzname == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } return UUCONF_SUCCESS; } *pzname = NULL; return UUCONF_NOT_FOUND; } ONF_NOT_FOUND; *pqglob = Nuucp-1.04/uuconf/local.c1004440004150000170000000426005337263616012126 037777777777 1 0 /* 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.3 1992/08/04 04:12:22 ian Rel $"; #endif #include /* Get default information about the local system. */ int uuconf_system_local (pglobal, qsys) pointer pglobal; struct uuconf_system *qsys; { struct sglobal *qglobal = (struct sglobal *) pglobal; int iret; _uuconf_uclear_system (qsys); qsys->uuconf_palloc = uuconf_malloc_block (); if (qsys->uuconf_palloc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } qsys->uuconf_zname = (char *) qglobal->qprocess->zlocalname; /* By default, we permit the local system to forward to and from any system. */ iret = _uuconf_iadd_string (qglobal, (char *) "ANY", FALSE, FALSE, &qsys->uuconf_pzforward_from, qsys->uuconf_palloc); if (iret == UUCONF_SUCCESS) iret = _uuconf_iadd_string (qglobal, (char *) "ANY", FALSE, FALSE, &qsys->uuconf_pzforward_to, qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) { uuconf_free_block (qsys->uuconf_palloc); return iret; } return _uuconf_isystem_basic_default (qglobal, qsys); } _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 uucp-1.04/uuconf/locnm.c1004440004150000170000000263705337263616012152 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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; } rs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucp-1.04/uuconf/logfil.c1004440004150000170000000256205337263616012313 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } program may be contacted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucnfi.h" uucp-1.04/uuconf/maxuxq.c1004440004150000170000000455405337263616012365 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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 */ } LOC_FAILED | UUCONF_ERROR_ERRNO; } return UUCONF_SUCCESS; } *pzname = NULL; return UUCONF_NOT_FOUND; } ONF_NOT_FOUND; *pqglob = Nuucp-1.04/uuconf/mrgblk.c1004440004150000170000000277705337263617012326 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } =uucp-1.04/uuconf/paramc.c1004440004150000170000001113405337263617012276 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Handle protocol-parameter commands by inserting them into an array of structures. The return value may include UUCONF_CMDTABRET_KEEP and UUCONF_CMDTABRET_EXIT, if appropriate. */ int _uuconf_iadd_proto_param (qglobal, argc, argv, pqparam, pblock) struct sglobal *qglobal; int argc; char **argv; struct uuconf_proto_param **pqparam; pointer pblock; { struct uuconf_proto_param *q; size_t c; struct uuconf_proto_param_entry *qentry; if (argc < 2) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; /* The first argument is the protocol character. */ if (argv[0][1] != '\0') return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; if (*pqparam == NULL) { *pqparam = ((struct uuconf_proto_param *) uuconf_malloc (pblock, 2 * sizeof (struct uuconf_proto_param))); if (*pqparam == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } (*pqparam)[1].uuconf_bproto = '\0'; q = *pqparam; q->uuconf_bproto = argv[0][0]; q->uuconf_qentries = NULL; } else { c = 0; for (q = *pqparam; q->uuconf_bproto != '\0'; q++) { if (q->uuconf_bproto == argv[0][0]) break; ++c; } if (q->uuconf_bproto == '\0') { struct uuconf_proto_param *qnew; qnew = ((struct uuconf_proto_param *) uuconf_malloc (pblock, ((c + 2) * sizeof (struct uuconf_proto_param)))); if (qnew == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) qnew, (pointer) *pqparam, c * sizeof (struct uuconf_proto_param)); qnew[c + 1].uuconf_bproto = '\0'; uuconf_free (pblock, *pqparam); *pqparam = qnew; q = qnew + c; q->uuconf_bproto = argv[0][0]; q->uuconf_qentries = NULL; } } if (q->uuconf_qentries == NULL) { qentry = ((struct uuconf_proto_param_entry *) uuconf_malloc (pblock, 2 * sizeof (struct uuconf_proto_param_entry))); if (qentry == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } qentry[1].uuconf_cargs = 0; q->uuconf_qentries = qentry; } else { struct uuconf_proto_param_entry *qnewent; c = 0; for (qentry = q->uuconf_qentries; qentry->uuconf_cargs != 0; qentry++) ++c; qnewent = ((struct uuconf_proto_param_entry *) uuconf_malloc (pblock, ((c + 2) * sizeof (struct uuconf_proto_param_entry)))); if (qnewent == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) qnewent, (pointer) q->uuconf_qentries, c * sizeof (struct uuconf_proto_param_entry)); qnewent[c + 1].uuconf_cargs = 0; uuconf_free (pblock, q->uuconf_qentries); q->uuconf_qentries = qnewent; qentry = qnewent + c; } qentry->uuconf_cargs = argc - 1; qentry->uuconf_pzargs = (char **) uuconf_malloc (pblock, ((argc - 1) * sizeof (char *))); if (qentry->uuconf_pzargs == NULL) { qglobal->ierrno = errno; qentry->uuconf_cargs = 0; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) qentry->uuconf_pzargs, (pointer) (argv + 1), (argc - 1) * sizeof (char *)); return UUCONF_CMDTABRET_KEEP; } 1004440004150000170000000455405337263616012365 037777777777 1 0 uucp-1.04/uuconf/port.c1004440004150000170000000423105337263617012017 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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; } 6 037777777777 1 0 uucp-1.04/uuconf/pubdir.c1004440004150000170000000260005337263620012310 037777777777 1 0 /* 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.4 1992/06/15 18:40:43 ian Rel $"; #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; } uucp-1.04/uuconf/prtsub.c1004440004150000170000000353205337263617012355 037777777777 1 0 /* 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.4 1992/07/15 19:08:11 ian Rel $"; #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; } to == argv[0][0]) break; ++c; } if (q->uuconf_bproto == '\0') { struct uuconf_proto_param *qnew; qnew = ((struct uuconf_proto_param *) uucuucp-1.04/uuconf/rdlocs.c1004440004150000170000001766305337263620012330 037777777777 1 0 /* 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.4 1992/07/25 20:44:25 ian Rel $"; #endif #include static int itsystem P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int itcalled_login P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int itmyname P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* This code scans through the Taylor UUCP system files in order to locate each system and to gather the login restrictions (since this information is held in additional arguments to the "called-login" command, it can appear anywhere in the systems files). It also records whether any "myname" appears, as an optimization for uuconf_taylor_localname. This table is used to dispatch the appropriate commands. Most commands are simply ignored. Note that this is a uuconf_cmdtab, not a cmdtab_offset. */ static const struct uuconf_cmdtab asTcmds[] = { { "system", UUCONF_CMDTABTYPE_FN | 2, NULL, itsystem }, { "alias", UUCONF_CMDTABTYPE_FN | 2, (pointer) asTcmds, itsystem }, { "called-login", UUCONF_CMDTABTYPE_FN | 0, NULL, itcalled_login }, { "myname", UUCONF_CMDTABTYPE_FN | 2, NULL, itmyname }, { NULL, 0, NULL, NULL } }; /* This structure is used to pass information into the command table functions. */ struct sinfo { /* The sys file name. */ const char *zname; /* The open sys file. */ FILE *e; /* The list of locations we are building. */ struct stsysloc *qlocs; /* The list of validation restrictions we are building. */ struct svalidate *qvals; }; /* Look through the sys files to find the location and names of all the systems. Since we're scanning the sys files, we also record the validation information specified by the additional arguments to the called-login command. We don't use uuconf_cmd_file to avoid the overhead of breaking the line up into arguments if not necessary. */ int _uuconf_iread_locations (qglobal) struct sglobal *qglobal; { char *zline; size_t cline; struct sinfo si; int iret; char **pz; if (qglobal->qprocess->fread_syslocs) return UUCONF_SUCCESS; zline = NULL; cline = 0; si.qlocs = NULL; si.qvals = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzsysfiles; *pz != NULL; pz++) { FILE *e; int cchars; qglobal->ilineno = 0; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } #ifdef CLOSE_ON_EXEC CLOSE_ON_EXEC (e); #endif si.zname = *pz; si.e = e; while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { char *zcmd; ++qglobal->ilineno; zcmd = zline + strspn (zline, " \t"); if (strncasecmp (zcmd, "system", sizeof "system" - 1) == 0 || strncasecmp (zcmd, "alias", sizeof "alias" - 1) == 0 || strncasecmp (zcmd, "called-login", sizeof "called-login" - 1) == 0 || strncasecmp (zcmd, "myname", sizeof "myname" - 1) == 0) { iret = uuconf_cmd_line ((pointer) qglobal, zline, asTcmds, (pointer) &si, (uuconf_cmdtabfn) NULL, 0, qglobal->pblock); if ((iret & UUCONF_CMDTABRET_KEEP) != 0) { iret &=~ UUCONF_CMDTABRET_KEEP; zline = NULL; cline = 0; } if (iret != UUCONF_SUCCESS) { iret &=~ UUCONF_CMDTABRET_EXIT; break; } } } if (iret != UUCONF_SUCCESS) break; } if (zline != NULL) free ((pointer) zline); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; if (UUCONF_ERROR_VALUE (iret) != UUCONF_MALLOC_FAILED) qglobal->qprocess->fread_syslocs = TRUE; } else { qglobal->qprocess->qsyslocs = si.qlocs; qglobal->qprocess->qvalidate = si.qvals; qglobal->qprocess->fread_syslocs = TRUE; } return iret; } /* Handle a "system" or "alias" command by recording the file and location. If pvar is not NULL, this is an "alias" command. */ /*ARGSUSED*/ static int itsystem (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; struct stsysloc *q; size_t csize; q = (struct stsysloc *) uuconf_malloc (qglobal->pblock, sizeof (struct stsysloc)); if (q == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } csize = strlen (argv[1]) + 1; q->zname = uuconf_malloc (qglobal->pblock, csize); if (q->zname == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } q->qnext = qinfo->qlocs; memcpy ((pointer) q->zname, (pointer) argv[1], csize); q->falias = pvar != NULL; q->zfile = qinfo->zname; q->e = qinfo->e; q->iloc = ftell (qinfo->e); q->ilineno = qglobal->ilineno; qinfo->qlocs = q; return UUCONF_CMDTABRET_CONTINUE; } /* Handle the "called-login" command. This just records any extra arguments, so that uuconf_validate can check them later if necessary. */ /*ARGSUSED*/ static int itcalled_login (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; register struct svalidate *qval; int i; if (argc <= 2) return UUCONF_CMDTABRET_CONTINUE; for (qval = qinfo->qvals; qval != NULL; qval = qval->qnext) if (strcmp (argv[1], qval->zlogname) == 0) break; if (qval == NULL) { qval = (struct svalidate *) uuconf_malloc (qglobal->pblock, sizeof (struct svalidate)); if (qval == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } qval->qnext = qinfo->qvals; qval->zlogname = argv[1]; qval->pzmachines = NULL; qinfo->qvals = qval; } for (i = 2; i < argc; i++) { int iret; iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, TRUE, &qval->pzmachines, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; } return UUCONF_CMDTABRET_KEEP; } /* Handle the "myname" command by simply recording that it appears. This information is used by uuconf_taylor_localname. */ /*ARGSUSED*/ static int itmyname (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; qglobal->qprocess->fuses_myname = TRUE; return UUCONF_CMDTABRET_CONTINUE; } in the hope that it will be useful, but WITHOUT ANY WARRANTY; without evenuucp-1.04/uuconf/rdperm.c1004440004150000170000002661105337263620012324 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #endif #include #include static int ihcolon P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ihsendfiles P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ihunknownperm P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ihadd_norw P((struct sglobal *qglobal, char ***ppz, char **pzno)); /* These routines reads in the HDB Permissions file. We store the entries in a linked list of shpermissions structures, so we only have to actually read the file once. */ /* This command table and static structure are used to parse a line from Permissions. The entries are parsed as follows: Multiple strings separated by colons: LOGNAME, MACHINE, READ, WRITE, NOREAD, NOWRITE, COMMANDS, VALIDATE, ALIAS. Boolean values: REQUEST, CALLBACK. Simple strings: MYNAME, PUBDIR. "Yes" or "call": SENDFILES. The NOREAD and NOWRITE entries are merged into the READ and WRITE entries, rather than being permanently stored. They are handled specially in the uuconf_cmdtab table. */ static const struct cmdtab_offset asHperm_cmds[] = { { "NOREAD", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon }, { "NOWRITE", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, ihcolon }, { "LOGNAME", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzlogname), ihcolon }, { "MACHINE", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzmachine), ihcolon }, { "REQUEST", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct shpermissions, frequest), NULL }, { "SENDFILES", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, fsendfiles), ihsendfiles }, { "READ", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzread), ihcolon }, { "WRITE", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzwrite), ihcolon }, { "CALLBACK", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct shpermissions, fcallback), NULL }, { "COMMANDS", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzcommands), ihcolon }, { "VALIDATE", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzvalidate), ihcolon }, { "MYNAME", UUCONF_CMDTABTYPE_STRING, offsetof (struct shpermissions, zmyname), NULL }, { "PUBDIR", UUCONF_CMDTABTYPE_STRING, offsetof (struct shpermissions, zpubdir), NULL }, { "ALIAS", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct shpermissions, pzalias), ihcolon }, { NULL, 0, 0, NULL } }; #define CHPERM_CMDS (sizeof asHperm_cmds / sizeof asHperm_cmds[0]) /* Actually read the Permissions file into a linked list of structures. */ int _uuconf_ihread_permissions (qglobal) struct sglobal *qglobal; { char *zperm; FILE *e; int iret; struct uuconf_cmdtab as[CHPERM_CMDS]; char **pznoread, **pznowrite; struct shpermissions shperm; char *zline; size_t cline; char **pzsplit; size_t csplit; int cchars; struct shpermissions *qlist, **pq; if (qglobal->qprocess->fhdb_read_permissions) return UUCONF_SUCCESS; zperm = (char *) uuconf_malloc (qglobal->pblock, (sizeof OLDCONFIGLIB + sizeof HDB_PERMISSIONS - 1)); if (zperm == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zperm, (pointer) OLDCONFIGLIB, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (zperm + sizeof OLDCONFIGLIB - 1), (pointer) HDB_PERMISSIONS, sizeof HDB_PERMISSIONS); e = fopen (zperm, "r"); if (e == NULL) { uuconf_free (qglobal->pblock, zperm); qglobal->qprocess->fhdb_read_permissions = TRUE; return UUCONF_SUCCESS; } _uuconf_ucmdtab_base (asHperm_cmds, CHPERM_CMDS, (char *) &shperm, as); as[0].uuconf_pvar = (pointer) &pznoread; as[1].uuconf_pvar = (pointer) &pznowrite; zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; qlist = NULL; pq = &qlist; qglobal->ilineno = 0; iret = UUCONF_SUCCESS; while ((cchars = _uuconf_getline (qglobal, &zline, &cline, e)) > 0) { int centries; struct shpermissions *qnew; int i; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; if (isspace (BUCHAR (zline[0])) || zline[0] == '#') continue; centries = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (centries < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } if (centries == 0) continue; shperm.pzlogname = (char **) &_uuconf_unset; shperm.pzmachine = (char **) &_uuconf_unset; shperm.frequest = -1; shperm.fsendfiles = -1; shperm.pzread = (char **) &_uuconf_unset; shperm.pzwrite = (char **) &_uuconf_unset; shperm.fcallback = -1; shperm.pzcommands = (char **) &_uuconf_unset; shperm.pzvalidate = (char **) &_uuconf_unset; shperm.zmyname = (char *) &_uuconf_unset; shperm.zpubdir = (char *) &_uuconf_unset; shperm.pzalias = (char **) &_uuconf_unset; pznoread = (char **) &_uuconf_unset; pznowrite = (char **) &_uuconf_unset; for (i = 0; i < centries; i++) { char *zeq; char *azargs[2]; zeq = strchr (pzsplit[i], '='); if (zeq == NULL) { iret = UUCONF_SYNTAX_ERROR; qglobal->qprocess->fhdb_read_permissions = TRUE; break; } *zeq = '\0'; azargs[0] = pzsplit[i]; azargs[1] = zeq + 1; iret = uuconf_cmd_args (qglobal, 2, azargs, as, (pointer) NULL, ihunknownperm, 0, qglobal->pblock); if ((iret & UUCONF_CMDTABRET_KEEP) != 0) { iret &=~ UUCONF_CMDTABRET_KEEP; if (uuconf_add_block (qglobal->pblock, zline) != 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; cline = 0; } if ((iret & UUCONF_CMDTABRET_EXIT) != 0) { iret &=~ UUCONF_CMDTABRET_EXIT; break; } } if (iret != UUCONF_SUCCESS) break; if (shperm.pzmachine == (char **) &_uuconf_unset && shperm.pzlogname == (char **) &_uuconf_unset) { iret = UUCONF_SYNTAX_ERROR; qglobal->qprocess->fhdb_read_permissions = TRUE; break; } /* Attach any NOREAD or NOWRITE entries to the corresponding READ or WRITE entries in the format expected for the pzlocal_receive, etc., fields in uuconf_system. */ if (pznoread != NULL) { iret = ihadd_norw (qglobal, &shperm.pzread, pznoread); if (iret != UUCONF_SUCCESS) break; uuconf_free (qglobal->pblock, pznoread); } if (pznowrite != NULL) { iret = ihadd_norw (qglobal, &shperm.pzwrite, pznowrite); if (iret != UUCONF_SUCCESS) break; uuconf_free (qglobal->pblock, pznowrite); } qnew = ((struct shpermissions *) uuconf_malloc (qglobal->pblock, sizeof (struct shpermissions))); if (qnew == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } *qnew = shperm; *pq = qnew; pq = &qnew->qnext; *pq = NULL; } (void) fclose (e); if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); if (iret == UUCONF_SUCCESS) { qglobal->qprocess->qhdb_permissions = qlist; qglobal->qprocess->fhdb_read_permissions = TRUE; } else { qglobal->zfilename = zperm; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } return iret; } /* Split the argument into colon separated strings, and assign a NULL terminated array of strings to pvar. */ /*ARGSUSED*/ static int ihcolon (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char ***ppz = (char ***) pvar; char **pzsplit; size_t csplit; int centries; int i; int iret; *ppz = NULL; pzsplit = NULL; csplit = 0; centries = _uuconf_istrsplit (argv[1], ':', &pzsplit, &csplit); if (centries < 0) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } if (centries == 0) { if (pzsplit != NULL) free ((pointer) pzsplit); return UUCONF_CMDTABRET_CONTINUE; } iret = UUCONF_SUCCESS; for (i = 0; i < centries; i++) { iret = _uuconf_iadd_string (qglobal, pzsplit[i], FALSE, FALSE, ppz, qglobal->pblock); if (iret != UUCONF_SUCCESS) { iret |= UUCONF_CMDTABRET_EXIT; break; } } free ((pointer) pzsplit); return UUCONF_CMDTABRET_KEEP; } /* Handle the SENDFILES parameter, which can take "yes" or "call" or "no" as an argument. The string "call" is equivalent to "no". */ /*ARGSUSED*/ static int ihsendfiles (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { int *pi = (int *) pvar; switch (argv[1][0]) { case 'C': case 'c': case 'N': case 'n': *pi = FALSE; break; case 'Y': case 'y': *pi = TRUE; break; default: return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; } return UUCONF_CMDTABRET_CONTINUE; } /* If there is an unknown Permissions entry, return a syntax error. This should probably be more clever. */ /*ARGSUSED*/ static int ihunknownperm (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; } /* Add a NOREAD or NOWRITE entry to a READ or WRITE entry. */ static int ihadd_norw (qglobal, ppz, pzno) struct sglobal *qglobal; char ***ppz; char **pzno; { register char **pz; if (pzno == (char **) &_uuconf_unset) return UUCONF_SUCCESS; for (pz = pzno; *pz != NULL; pz++) { size_t csize; char *znew; int iret; csize = strlen (*pz) + 1; znew = (char *) uuconf_malloc (qglobal->pblock, csize + 1); if (znew == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } znew[0] = '!'; memcpy ((pointer) (znew + 1), (pointer) *pz, csize); iret = _uuconf_iadd_string (qglobal, znew, FALSE, FALSE, ppz, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret; } return UUCONF_SUCCESS; } global, int argc, char **argv, pointer pvar, pointer pinfo)); static int ihadd_norw P((struct sglobal *qglobal, uucp-1.04/uuconf/reliab.c1004440004150000170000000635605337263620012275 037777777777 1 0 /* 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.3 1992/07/15 19:08:11 ian Rel $"; #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; } ; 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_MALLOuucp-1.04/uuconf/remunk.c1004440004150000170000000265605337263621012340 037777777777 1 0 /* 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 1992/09/14 22:07:51 ian Rel $"; #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 } . */ if (pznoread != NULL) { iret = ihadd_norw (qglobal, &shperm.pzreaduucp-1.04/uuconf/sinfo.c1004440004150000170000000545705337263621012157 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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); } uconf_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 (quucp-1.04/uuconf/snams.c1004440004150000170000000637405337263621012161 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } , 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[1uucp-1.04/uuconf/split.c1004440004150000170000000507205337263621012165 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Split a string into tokens. The bsep argument is the separator to use. If it is the null byte, white space is used as the separator, and leading white space is discarded. Otherwise, each occurrence of the separator character delimits a field (and thus some fields may be empty). The array and size arguments may be used to reuse the same memory. This function is not tied to uuconf; the only way it can fail is if malloc or realloc fails. */ int _uuconf_istrsplit (zline, bsep, ppzsplit, pcsplit) register char *zline; int bsep; char ***ppzsplit; size_t *pcsplit; { size_t i; i = 0; while (TRUE) { if (bsep == '\0') { while (isspace (BUCHAR (*zline))) ++zline; if (*zline == '\0') break; } if (i >= *pcsplit) { char **pznew; size_t cnew; if (*pcsplit == 0) { cnew = 8; pznew = (char **) malloc (cnew * sizeof (char *)); } else { cnew = *pcsplit * 2; pznew = (char **) realloc ((pointer) *ppzsplit, cnew * sizeof (char *)); } if (pznew == NULL) return -1; *ppzsplit = pznew; *pcsplit = cnew; } (*ppzsplit)[i] = zline; ++i; if (bsep == '\0') { while (*zline != '\0' && ! isspace (BUCHAR (*zline))) ++zline; } else { while (*zline != '\0' && *zline != bsep) ++zline; } if (*zline == '\0') break; *zline++ = '\0'; } return i; } t (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 eveuucp-1.04/uuconf/spool.c1004440004150000170000000260505337263622012166 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #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; } = _uuconf_ihdb_system_internal (qglobal, zsystem, q); if (iret == UUCONF_SUCCESS) { if (fgot) { iret uucp-1.04/uuconf/stafil.c1004440004150000170000000261205337263622012312 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. */ #include "uucnfi.h" #ifuucp-1.04/uuconf/syssub.c1004440004150000170000003403105337263622012360 037777777777 1 0 /* 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.9 1992/11/14 16:16:24 ian Rel $"; #endif #include /* This macro operates on every string (char *) field in struct uuconf_system. */ #define SYSTEM_STRINGS(OP) \ do \ { \ OP (uuconf_zname); \ OP (uuconf_zalternate); \ OP (uuconf_zdebug); \ OP (uuconf_zmax_remote_debug); \ OP (uuconf_zphone); \ OP (uuconf_zcall_login); \ OP (uuconf_zcall_password); \ OP (uuconf_zcalled_login); \ OP (uuconf_zprotocols); \ OP (uuconf_zpubdir); \ OP (uuconf_zlocalname); \ } \ while (0) /* This macro operates on every string array (char **) field in struct uuconf_system. */ #define SYSTEM_STRING_ARRAYS(OP) \ do \ { \ OP (uuconf_pzalias); \ OP (uuconf_pzlocal_send); \ OP (uuconf_pzremote_send); \ OP (uuconf_pzlocal_receive); \ OP (uuconf_pzremote_receive); \ OP (uuconf_pzpath); \ OP (uuconf_pzcmds); \ OP (uuconf_pzforward_from); \ OP (uuconf_pzforward_to); \ OP (uuconf_schat.uuconf_pzchat); \ OP (uuconf_schat.uuconf_pzprogram); \ OP (uuconf_schat.uuconf_pzfail); \ OP (uuconf_scalled_chat.uuconf_pzchat); \ OP (uuconf_scalled_chat.uuconf_pzprogram); \ OP (uuconf_scalled_chat.uuconf_pzfail); \ } \ while (0) /* This macro operations on every timespan pointer (struct uuconf_timespan *) in struct uuconf_system. */ #define SYSTEM_TIMESPANS(OP) \ do \ { \ OP (uuconf_qtimegrade); \ OP (uuconf_qcalltimegrade); \ OP (uuconf_qcall_local_size); \ OP (uuconf_qcall_remote_size); \ OP (uuconf_qcalled_local_size); \ OP (uuconf_qcalled_remote_size); \ } \ while (0) /* This macro operates on every boolean value (of type int, although some type int are not boolean) field in uuconf_system. */ #define SYSTEM_BOOLEANS(OP) \ do \ { \ OP (uuconf_fcall); \ OP (uuconf_fcalled); \ OP (uuconf_fcallback); \ OP (uuconf_fsequence); \ OP (uuconf_fsend_request); \ OP (uuconf_frec_request); \ OP (uuconf_fcall_transfer); \ OP (uuconf_fcalled_transfer); \ OP (uuconf_schat.uuconf_fstrip); \ OP (uuconf_scalled_chat.uuconf_fstrip); \ } \ while (0) /* This macro operates on every generic integer (type int or long) in uuconf_system. */ #define SYSTEM_INTEGERS(OP) \ do \ { \ OP (uuconf_cmax_retries); \ OP (uuconf_csuccess_wait); \ OP (uuconf_ibaud); \ OP (uuconf_ihighbaud); \ OP (uuconf_cfree_space); \ OP (uuconf_schat.uuconf_ctimeout); \ OP (uuconf_scalled_chat.uuconf_ctimeout); \ } \ while (0) /* There is no macro for uuconf_qalternate, uuconf_zport, uuconf_qport, uuconf_qproto_params, or uuconf_palloc. */ /* Clear the contents of a struct uuconf_system. */ void _uuconf_uclear_system (q) struct uuconf_system *q; { #define CLEAR(x) q->x = (char *) &_uuconf_unset SYSTEM_STRINGS (CLEAR); #undef CLEAR #define CLEAR(x) q->x = (char **) &_uuconf_unset SYSTEM_STRING_ARRAYS (CLEAR); #undef CLEAR #define CLEAR(x) q->x = (struct uuconf_timespan *) &_uuconf_unset SYSTEM_TIMESPANS (CLEAR); #undef CLEAR #define CLEAR(x) q->x = -1 SYSTEM_BOOLEANS (CLEAR); SYSTEM_INTEGERS (CLEAR); #undef CLEAR q->uuconf_qalternate = NULL; q->uuconf_zport = (char *) &_uuconf_unset; q->uuconf_qport = (struct uuconf_port *) &_uuconf_unset; q->uuconf_qproto_params = (struct uuconf_proto_param *) &_uuconf_unset; q->uuconf_palloc = NULL; } /* Default the contents of one struct uuconf_system to the contents of another. This default alternate by alternate. Any additional alternates in q default to the last alternate of qdefault. If the faddalternates arguments is TRUE, additional alternates or qdefault are added to q; these alternates are copies of the first alternate of q, and defaults are set from the additional alternates of qdefault. */ int _uuconf_isystem_default (qglobal, qset, qdefault, faddalternates) struct sglobal *qglobal; struct uuconf_system *qset; struct uuconf_system *qdefault; boolean faddalternates; { struct uuconf_system *qalt; if (qset->uuconf_palloc != qdefault->uuconf_palloc) qset->uuconf_palloc = _uuconf_pmalloc_block_merge (qset->uuconf_palloc, qdefault->uuconf_palloc); /* If we are adding alternates from the default, make sure we have at least as many alternates in qset as we do in qdefault. Each new alternate we create gets initialized to the first alternate of the system. */ if (faddalternates) { struct uuconf_system **pq, *qdef; for (qdef = qdefault, pq = &qset; qdef != NULL; qdef = qdef->uuconf_qalternate, pq = &(*pq)->uuconf_qalternate) { if (*pq == NULL) { *pq = ((struct uuconf_system *) uuconf_malloc (qset->uuconf_palloc, sizeof (struct uuconf_system))); if (*pq == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } **pq = *qset; (*pq)->uuconf_qalternate = NULL; } } } for (qalt = qset; qalt != NULL; qalt = qalt->uuconf_qalternate) { #define DEFAULT(x) \ if (qalt->x == (char *) &_uuconf_unset) qalt->x = qdefault->x SYSTEM_STRINGS (DEFAULT); #undef DEFAULT #define DEFAULT(x) \ if (qalt->x == (char **) &_uuconf_unset) qalt->x = qdefault->x SYSTEM_STRING_ARRAYS (DEFAULT); #undef DEFAULT #define DEFAULT(x) \ if (qalt->x == (struct uuconf_timespan *) &_uuconf_unset) \ qalt->x = qdefault->x SYSTEM_TIMESPANS (DEFAULT); #undef DEFAULT #define DEFAULT(x) if (qalt->x < 0) qalt->x = qdefault->x SYSTEM_BOOLEANS (DEFAULT); SYSTEM_INTEGERS (DEFAULT); #undef DEFAULT /* We only copy over zport if both zport and qport are NULL, because otherwise a default zport would override a specific qport. */ if (qalt->uuconf_zport == (char *) &_uuconf_unset && qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) qalt->uuconf_zport = qdefault->uuconf_zport; if (qalt->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) qalt->uuconf_qport = qdefault->uuconf_qport; if (qalt->uuconf_qproto_params == (struct uuconf_proto_param *) &_uuconf_unset) qalt->uuconf_qproto_params = qdefault->uuconf_qproto_params; if (qdefault->uuconf_qalternate != NULL) qdefault = qdefault->uuconf_qalternate; } return UUCONF_SUCCESS; } /* Put in the basic defaults. This ensures that the fields are valid on every uuconf_system structure. */ int _uuconf_isystem_basic_default (qglobal, q) struct sglobal *qglobal; register struct uuconf_system *q; { int iret; iret = UUCONF_SUCCESS; for (; q != NULL && iret == UUCONF_SUCCESS; q = q->uuconf_qalternate) { /* The default of 26 allowable retries is traditional. */ if (q->uuconf_cmax_retries < 0) q->uuconf_cmax_retries = 26; if (q->uuconf_schat.uuconf_pzchat == (char **) &_uuconf_unset) { q->uuconf_schat.uuconf_pzchat = NULL; iret = _uuconf_iadd_string (qglobal, (char *) "\"\"", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "\\r\\c", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "ogin:", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "-BREAK", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "-ogin:", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "\\L", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "word:", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_iadd_string (qglobal, (char *) "\\P", FALSE, FALSE, &q->uuconf_schat.uuconf_pzchat, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } if (q->uuconf_schat.uuconf_ctimeout < 0) q->uuconf_schat.uuconf_ctimeout = 10; if (q->uuconf_schat.uuconf_fstrip < 0) q->uuconf_schat.uuconf_fstrip = TRUE; if (q->uuconf_scalled_chat.uuconf_ctimeout < 0) q->uuconf_scalled_chat.uuconf_ctimeout = 60; if (q->uuconf_scalled_chat.uuconf_fstrip < 0) q->uuconf_scalled_chat.uuconf_fstrip = TRUE; if (q->uuconf_fsend_request < 0) q->uuconf_fsend_request = TRUE; if (q->uuconf_frec_request < 0) q->uuconf_frec_request = TRUE; if (q->uuconf_fcall_transfer < 0) q->uuconf_fcall_transfer = TRUE; if (q->uuconf_fcalled_transfer < 0) q->uuconf_fcalled_transfer = TRUE; if (q->uuconf_pzlocal_send == (char **) &_uuconf_unset) { q->uuconf_pzlocal_send = NULL; iret = _uuconf_iadd_string (qglobal, (char *) ZROOTDIR, FALSE, FALSE, &q->uuconf_pzlocal_send, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } if (q->uuconf_pzremote_send == (char **) &_uuconf_unset) { q->uuconf_pzremote_send = NULL; iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, &q->uuconf_pzremote_send, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } if (q->uuconf_pzlocal_receive == (char **) &_uuconf_unset) { q->uuconf_pzlocal_receive = NULL; iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, &q->uuconf_pzlocal_receive, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } if (q->uuconf_pzremote_receive == (char **) &_uuconf_unset) { q->uuconf_pzremote_receive = NULL; iret = _uuconf_iadd_string (qglobal, (char *) "~", FALSE, FALSE, &q->uuconf_pzremote_receive, q->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret; } if (q->uuconf_pzpath == (char **) &_uuconf_unset) { char *zdup; char **pz; size_t csplit; int c; zdup = (char *) uuconf_malloc (q->uuconf_palloc, sizeof CMDPATH); if (zdup == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zdup, (pointer) CMDPATH, sizeof CMDPATH); pz = NULL; csplit = 0; if ((c = _uuconf_istrsplit (zdup, '\0', &pz, &csplit)) < 0) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } q->uuconf_pzpath = (char **) uuconf_malloc (q->uuconf_palloc, ((c + 1) * sizeof (char *))); if (q->uuconf_pzpath == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) q->uuconf_pzpath, (pointer) pz, c * sizeof (char *)); q->uuconf_pzpath[c] = NULL; free ((pointer) pz); } if (q->uuconf_pzcmds == (char **) &_uuconf_unset) { q->uuconf_pzcmds = ((char **) uuconf_malloc (q->uuconf_palloc, 3 * sizeof (const char *))); if (q->uuconf_pzcmds == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } q->uuconf_pzcmds[0] = (char *) "rnews"; q->uuconf_pzcmds[1] = (char *) "rmail"; q->uuconf_pzcmds[2] = NULL; } if (q->uuconf_cfree_space < 0) q->uuconf_cfree_space = DEFAULT_FREE_SPACE; if (q->uuconf_zpubdir == (const char *) &_uuconf_unset) q->uuconf_zpubdir = qglobal->qprocess->zpubdir; #define SET(x) if (q->x == (char *) &_uuconf_unset) q->x = NULL SYSTEM_STRINGS(SET); #undef SET #define SET(x) if (q->x == (char **) &_uuconf_unset) q->x = NULL SYSTEM_STRING_ARRAYS(SET); #undef SET #define SET(x) \ if (q->x == (struct uuconf_timespan *) &_uuconf_unset) q->x = NULL SYSTEM_TIMESPANS (SET); #undef SET #define SET(x) if (q->x < 0) q->x = 0 SYSTEM_BOOLEANS (SET); SYSTEM_INTEGERS (SET); #undef SET if (q->uuconf_zport == (char *) &_uuconf_unset) q->uuconf_zport = NULL; if (q->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) q->uuconf_qport = NULL; if (q->uuconf_qproto_params == (struct uuconf_proto_param *) &_uuconf_unset) q->uuconf_qproto_params = NULL; } return iret; } conf_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 = uucp-1.04/uuconf/tcalou.c1004440004150000170000001112305337263622012314 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include static int icsys P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* Find the callout login name and password for a system from the Taylor UUCP configuration files. */ int uuconf_taylor_callout (pglobal, qsys, pzlog, pzpass) pointer pglobal; const struct uuconf_system *qsys; char **pzlog; char **pzpass; { struct sglobal *qglobal = (struct sglobal *) pglobal; boolean flookup; struct uuconf_cmdtab as[2]; char **pz; int iret; pointer pinfo; *pzlog = NULL; *pzpass = NULL; flookup = FALSE; if (qsys->uuconf_zcall_login != NULL) { if (strcmp (qsys->uuconf_zcall_login, "*") == 0) flookup = TRUE; else { *pzlog = strdup (qsys->uuconf_zcall_login); if (*pzlog == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } } } if (qsys->uuconf_zcall_password != NULL) { if (strcmp (qsys->uuconf_zcall_password, "*") == 0) flookup = TRUE; else { *pzpass = strdup (qsys->uuconf_zcall_password); if (*pzpass == NULL) { qglobal->ierrno = errno; if (*pzlog != NULL) { free ((pointer) *pzlog); *pzlog = NULL; } return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } } } if (! flookup) { if (*pzlog == NULL && *pzpass == NULL) return UUCONF_NOT_FOUND; return UUCONF_SUCCESS; } as[0].uuconf_zcmd = qsys->uuconf_zname; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 3; if (*pzlog == NULL) as[0].uuconf_pvar = (pointer) pzlog; else as[0].uuconf_pvar = NULL; as[0].uuconf_pifn = icsys; as[1].uuconf_zcmd = NULL; if (*pzpass == NULL) pinfo = (pointer) pzpass; else pinfo = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzcallfiles; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } iret = uuconf_cmd_file (pglobal, e, as, pinfo, (uuconf_cmdtabfn) NULL, 0, qsys->uuconf_palloc); (void) fclose (e); if (iret != UUCONF_SUCCESS) break; if (*pzlog != NULL) break; } if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; return iret | UUCONF_ERROR_FILENAME; } if (*pzlog == NULL && *pzpass == NULL) return UUCONF_NOT_FOUND; return UUCONF_SUCCESS; } /* Copy the login name and password onto the heap and set the pointers. The pzlog argument is passed in pvar, and the pzpass argument is passed in pinfo. */ static int icsys (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pzlog = (char **) pvar; char **pzpass = (char **) pinfo; if (pzlog != NULL) { *pzlog = strdup (argv[1]); if (*pzlog == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } } if (pzpass != NULL) { *pzpass = strdup (argv[2]); if (*pzpass == NULL) { qglobal->ierrno = errno; if (pzlog != NULL) { free ((pointer) *pzlog); *pzlog = NULL; } return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } } return UUCONF_CMDTABRET_EXIT; } global, (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->uuconuucp-1.04/uuconf/tdial.c1004440004150000170000001375305337263623012136 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include static int iddialer P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int idunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* Find a dialer in the Taylor UUCP configuration files by name. */ int uuconf_taylor_dialer_info (pglobal, zname, qdialer) pointer pglobal; const char *zname; struct uuconf_dialer *qdialer; { struct sglobal *qglobal = (struct sglobal *) pglobal; FILE *e; pointer pblock; int iret; char **pz; e = NULL; pblock = NULL; iret = UUCONF_NOT_FOUND; for (pz = qglobal->qprocess->pzdialfiles; *pz != NULL; pz++) { struct uuconf_cmdtab as[2]; char *zdialer; struct uuconf_dialer sdefault; int ilineno; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } qglobal->ilineno = 0; /* Gather the default information from the top of the file. We do this by handling the "dialer" command ourselves and passing every other command to _uuconf_idialer_cmd via idunknown. The value of zdialer will be an malloc block. */ as[0].uuconf_zcmd = "dialer"; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; as[0].uuconf_pvar = (pointer) &zdialer; as[0].uuconf_pifn = iddialer; as[1].uuconf_zcmd = NULL; pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_dialer (&sdefault); sdefault.uuconf_palloc = pblock; zdialer = NULL; iret = uuconf_cmd_file (pglobal, e, as, (pointer) &sdefault, idunknown, UUCONF_CMDTABFLAG_BACKSLASH, pblock); /* Now skip until we find a dialer with a matching name. */ while (iret == UUCONF_SUCCESS && zdialer != NULL && strcmp (zname, zdialer) != 0) { free ((pointer) zdialer); zdialer = NULL; ilineno = qglobal->ilineno; iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_BACKSLASH, pblock); qglobal->ilineno += ilineno; } if (iret != UUCONF_SUCCESS) { if (zdialer != NULL) free ((pointer) zdialer); break; } if (zdialer != NULL) { size_t csize; /* We've found the dialer we're looking for. Read the rest of the commands for it. */ as[0].uuconf_pvar = NULL; *qdialer = sdefault; csize = strlen (zdialer) + 1; qdialer->uuconf_zname = uuconf_malloc (pblock, csize); if (qdialer->uuconf_zname == NULL) { qglobal->ierrno = errno; free ((pointer) zdialer); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) qdialer->uuconf_zname, (pointer) zdialer, csize); free ((pointer) zdialer); ilineno = qglobal->ilineno; iret = uuconf_cmd_file (pglobal, e, as, qdialer, idunknown, UUCONF_CMDTABFLAG_BACKSLASH, pblock); qglobal->ilineno += ilineno; break; } (void) fclose (e); e = NULL; uuconf_free_block (pblock); pblock = NULL; iret = UUCONF_NOT_FOUND; } if (e != NULL) (void) fclose (e); if (iret != UUCONF_SUCCESS && pblock != NULL) uuconf_free_block (pblock); if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME; } return iret; } /* Handle a "dialer" command. This copies the string onto the heap and returns the pointer in *pvar, unless pvar is NULL. It returns UUCONF_CMDTABRET_EXIT to force _uuconf_icmd_file_internal to stop reading and return to the code above, which will then check the dialer name just read to see if it matches. */ /*ARGSUSED*/ static int iddialer (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pz = (char **) pvar; if (pz != NULL) { size_t csize; csize = strlen (argv[1]) + 1; *pz = malloc (csize); if (*pz == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) *pz, (pointer) argv[1], csize); } return UUCONF_CMDTABRET_EXIT; } /* Handle an unknown command by passing it on to _uuconf_idialer_cmd, which will parse it into the dialer structure. */ /*ARGSUSED*/ static int idunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_dialer *qdialer = (struct uuconf_dialer *) pinfo; return _uuconf_idialer_cmd (qglobal, argc, argv, qdialer); } tem *qsys; char uucp-1.04/uuconf/tdialc.c1004440004150000170000001554505337263623012302 037777777777 1 0 /* 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.3 1992/07/15 19:08:11 ian Rel $"; #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; } } if (iret != UUCONF_SUCCESS) { if (zdialer != NULL) free ((pointer) zdialer); break; } if (zdialer != NULL) { size_t csize;uucp-1.04/uuconf/tdnams.c1004440004150000170000000605205337263623012321 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include static int indialer P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* Get the names of all the dialers from the Taylor UUCP configuration files. */ int uuconf_taylor_dialer_names (pglobal, ppzdialers) pointer pglobal; char ***ppzdialers; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_cmdtab as[2]; char **pz; int iret; *ppzdialers = NULL; as[0].uuconf_zcmd = "dialer"; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; as[0].uuconf_pvar = (pointer) ppzdialers; as[0].uuconf_pifn = indialer; as[1].uuconf_zcmd = NULL; iret = UUCONF_SUCCESS; for (pz = qglobal->qprocess->pzdialfiles; *pz != NULL; pz++) { FILE *e; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } iret = uuconf_cmd_file (pglobal, e, as, (pointer) NULL, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_BACKSLASH, (pointer) NULL); (void) fclose (e); if (iret != UUCONF_SUCCESS) break; } if (iret != UUCONF_SUCCESS) { qglobal->zfilename = *pz; return iret | UUCONF_ERROR_FILENAME; } if (*ppzdialers == NULL) iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppzdialers, (pointer) NULL); return UUCONF_SUCCESS; } /* Add a dialer name to the list. */ /*ARGSUSED*/ static int indialer (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char ***ppzdialers = (char ***) pvar; int iret; iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, TRUE, ppzdialers, (pointer) NULL); if (iret != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } TABILITY 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 "uucnuucp-1.04/uuconf/tgcmp.c1004440004150000170000000270405337263623012145 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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); } _FN | 2, offsetof (struct uuconf_dialer, uuconf_ireliauucp-1.04/uuconf/thread.c1004440004150000170000000374305337263624012307 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Initialize for a new thread, by allocating a new sglobal structure which points to the same sprocess structure. */ int uuconf_init_thread (ppglobal) pointer *ppglobal; { struct sglobal **pqglob = (struct sglobal **) ppglobal; pointer pblock; struct sglobal *qnew; pblock = uuconf_malloc_block (); if (pblock == NULL) { (*pqglob)->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } qnew = (struct sglobal *) uuconf_malloc (pblock, sizeof (struct sglobal)); if (qnew == NULL) { (*pqglob)->ierrno = errno; uuconf_free_block (pblock); return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } qnew->pblock = pblock; qnew->ierrno = 0; qnew->ilineno = 0; qnew->zfilename = NULL; qnew->qprocess = (*pqglob)->qprocess; *pqglob = qnew; return UUCONF_SUCCESS; } ese just turn a string intuucp-1.04/uuconf/time.c1004440004150000170000002533205337263624011774 037777777777 1 0 /* 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.7 1992/10/15 02:12:23 ian Rel $"; #endif #include #include static int itadd_span P((struct sglobal *qglobal, int istart, int iend, long ival, int cretry, int (*picmp) P((long, long)), struct uuconf_timespan **pqspan, pointer pblock)); static int itnew P((struct sglobal *qglobal, struct uuconf_timespan **pqset, struct uuconf_timespan *qnext, int istart, int iend, long ival, int cretry, pointer pblock)); /* An array of weekday abbreviations. The code below assumes that each one starts with a lower case letter. */ static const struct { const char *zname; int imin; int imax; } asTdays[] = { { "any", 0, 6 }, { "wk", 1, 5 }, { "su", 0, 0 }, { "mo", 1, 1 }, { "tu", 2, 2 }, { "we", 3, 3 }, { "th", 4, 4 }, { "fr", 5, 5 }, { "sa", 6, 6 }, { "never", -1, -2 }, { NULL, 0, 0 } }; /* Parse a time string and add it to a span list. This function is given the value, the retry time, and the comparison function to use. */ int _uuconf_itime_parse (qglobal, ztime, ival, cretry, picmp, pqspan, pblock) struct sglobal *qglobal; char *ztime; long ival; int cretry; int (*picmp) P((long, long)); struct uuconf_timespan **pqspan; pointer pblock; { struct uuconf_timespan *qlist; char bfirst; const char *z; qlist = *pqspan; if (qlist == (struct uuconf_timespan *) &_uuconf_unset) qlist = NULL; /* Expand the string using a timetable. Keep rechecking the string until it does not match. */ while (TRUE) { char **pz; char *zfound; bfirst = *ztime; if (isupper (BUCHAR (bfirst))) bfirst = tolower (BUCHAR (bfirst)); zfound = NULL; pz = qglobal->qprocess->pztimetables; /* We want the last timetable to have been defined with this name, so we always look through the entire table. */ while (*pz != NULL) { if ((bfirst == (*pz)[0] || (isupper (BUCHAR ((*pz)[0])) && bfirst == tolower (BUCHAR ((*pz)[0])))) && strcasecmp (ztime, *pz) == 0) zfound = pz[1]; pz += 2; } if (zfound == NULL) break; ztime = zfound; } /* Look through the time string. */ z = ztime; while (*z != '\0') { int iday; boolean afday[7]; int istart, iend; if (*z == ',' || *z == '|') ++z; if (*z == '\0' || *z == ';') break; for (iday = 0; iday < 7; iday++) afday[iday] = FALSE; /* Get the days. */ do { bfirst = *z; if (isupper (BUCHAR (bfirst))) bfirst = tolower (BUCHAR (bfirst)); for (iday = 0; asTdays[iday].zname != NULL; iday++) { size_t clen; if (bfirst != asTdays[iday].zname[0]) continue; clen = strlen (asTdays[iday].zname); if (strncasecmp (z, asTdays[iday].zname, clen) == 0) { int iset; for (iset = asTdays[iday].imin; iset <= asTdays[iday].imax; iset++) afday[iset] = TRUE; z += clen; break; } } if (asTdays[iday].zname == NULL) return UUCONF_SYNTAX_ERROR; } while (isalpha (BUCHAR (*z))); /* Get the hours. */ if (! isdigit (BUCHAR (*z))) { istart = 0; iend = 24 * 60; } else { char *zendnum; istart = (int) strtol ((char *) z, &zendnum, 10); if (*zendnum != '-' || ! isdigit (BUCHAR (zendnum[1]))) return UUCONF_SYNTAX_ERROR; z = zendnum + 1; iend = (int) strtol ((char *) z, &zendnum, 10); z = zendnum; istart = (istart / 100) * 60 + istart % 100; iend = (iend / 100) * 60 + iend % 100; } /* Add the times we've found onto the list. */ for (iday = 0; iday < 7; iday++) { if (afday[iday]) { int iminute, iret; iminute = iday * 24 * 60; if (istart < iend) iret = itadd_span (qglobal, iminute + istart, iminute + iend, ival, cretry, picmp, &qlist, pblock); else { /* Wrap around midnight. */ iret = itadd_span (qglobal, iminute, iminute + iend, ival, cretry, picmp, &qlist, pblock); if (iret == UUCONF_SUCCESS) iret = itadd_span (qglobal, iminute + istart, iminute + 24 * 60, ival, cretry, picmp, &qlist, pblock); } if (iret != UUCONF_SUCCESS) return iret; } } } *pqspan = qlist; return UUCONF_SUCCESS; } /* Add a time span to an existing list of time spans. We keep the list sorted by time to make this operation easier. This modifies the existing list, and returns the modified version. It takes a comparison function which should return < 0 if the first argument should take precedence over the second argument and == 0 if they are the same (for grades this is igradecmp; for sizes it is minus (the binary operator)). */ static int itadd_span (qglobal, istart, iend, ival, cretry, picmp, pqspan, pblock) struct sglobal *qglobal; int istart; int iend; long ival; int cretry; int (*picmp) P((long, long)); struct uuconf_timespan **pqspan; pointer pblock; { struct uuconf_timespan **pq; int iret; /* istart < iend */ for (pq = pqspan; *pq != NULL; pq = &(*pq)->uuconf_qnext) { int icmp; /* Invariant: PREV (*pq) == NULL || PREV (*pq)->iend <= istart */ /* istart < iend && (*pq)->istart < (*pq)->iend */ if (iend <= (*pq)->uuconf_istart) { /* istart < iend <= (*pq)->istart < (*pq)->iend */ /* No overlap, and we're at the right spot. See if we can combine these spans. */ if (iend == (*pq)->uuconf_istart && cretry == (*pq)->uuconf_cretry && (*picmp) (ival, (*pq)->uuconf_ival) == 0) { (*pq)->uuconf_istart = istart; return UUCONF_SUCCESS; } /* We couldn't combine them. */ break; } if ((*pq)->uuconf_iend <= istart) { /* (*pq)->istart < (*pq)->iend <= istart < iend */ /* No overlap. Try attaching this span. */ if ((*pq)->uuconf_iend == istart && (*pq)->uuconf_cretry == cretry && ((*pq)->uuconf_qnext == NULL || iend <= (*pq)->uuconf_qnext->uuconf_istart) && (*picmp) (ival, (*pq)->uuconf_ival) == 0) { (*pq)->uuconf_iend = iend; return UUCONF_SUCCESS; } /* Couldn't attach; keep looking for the right spot. We might be able to combine part of the new span onto an existing span, but it's probably not worth it. */ continue; } /* istart < iend && (*pq)->istart < (*pq)->iend && istart < (*pq)->iend && (*pq)->istart < iend */ /* Overlap. */ icmp = (*picmp) (ival, (*pq)->uuconf_ival); if (icmp == 0) { /* Just expand the old span to include the new span. */ if (istart < (*pq)->uuconf_istart) (*pq)->uuconf_istart = istart; if ((*pq)->uuconf_iend >= iend) return UUCONF_SUCCESS; if ((*pq)->uuconf_qnext == NULL || iend <= (*pq)->uuconf_qnext->uuconf_istart) { (*pq)->uuconf_iend = iend; return UUCONF_SUCCESS; } /* The span we are adding overlaps the next span as well. Expand the old span up to the next old span, and keep trying to add the new span. */ (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart; istart = (*pq)->uuconf_iend; } else if (icmp < 0) { /* Replace the old span with the new span. */ if ((*pq)->uuconf_istart < istart) { /* Save the initial portion of the old span. */ iret = itnew (qglobal, pq, *pq, (*pq)->uuconf_istart, istart, (*pq)->uuconf_ival, (*pq)->uuconf_cretry, pblock); if (iret != UUCONF_SUCCESS) return iret; pq = &(*pq)->uuconf_qnext; } if (iend < (*pq)->uuconf_iend) { /* Save the final portion of the old span. */ iret = itnew (qglobal, &(*pq)->uuconf_qnext, (*pq)->uuconf_qnext, iend, (*pq)->uuconf_iend, (*pq)->uuconf_ival, (*pq)->uuconf_cretry, pblock); if (iret != UUCONF_SUCCESS) return iret; } (*pq)->uuconf_ival = ival; (*pq)->uuconf_istart = istart; (*pq)->uuconf_cretry = cretry; if ((*pq)->uuconf_qnext == NULL || iend <= (*pq)->uuconf_qnext->uuconf_istart) { (*pq)->uuconf_iend = iend; return UUCONF_SUCCESS; } /* Move this span up to the next one, and keep trying to add the new span. */ (*pq)->uuconf_iend = (*pq)->uuconf_qnext->uuconf_istart; istart = (*pq)->uuconf_iend; } else { /* Leave the old span untouched. */ if (istart < (*pq)->uuconf_istart) { /* Put in the initial portion of the new span. */ iret = itnew (qglobal, pq, *pq, istart, (*pq)->uuconf_istart, ival, cretry, pblock); if (iret != UUCONF_SUCCESS) return iret; pq = &(*pq)->uuconf_qnext; } if (iend <= (*pq)->uuconf_iend) return UUCONF_SUCCESS; /* Keep trying to add the new span. */ istart = (*pq)->uuconf_iend; } } /* This is the spot for the new span, and there's no overlap. */ return itnew (qglobal, pq, *pq, istart, iend, ival, cretry, pblock); } /* A utility function to create a new uuconf_timespan structure. */ static int itnew (qglobal, pqset, qnext, istart, iend, ival, cretry, pblock) struct sglobal *qglobal; struct uuconf_timespan **pqset; struct uuconf_timespan *qnext; int istart; int iend; long ival; int cretry; pointer pblock; { register struct uuconf_timespan *qnew; qnew = ((struct uuconf_timespan *) uuconf_malloc (pblock, sizeof (struct uuconf_timespan))); if (qnew == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } qnew->uuconf_qnext = qnext; qnew->uuconf_istart = istart; qnew->uuconf_iend = iend; qnew->uuconf_ival = ival; qnew->uuconf_cretry = cretry; *pqset = qnew; return UUCONF_SUCCESS; } rary 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. */ uucp-1.04/uuconf/tinit.c1004440004150000170000002443405337263624012167 037777777777 1 0 /* 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.5 1992/10/10 05:19:29 ian Rel $"; #endif #include /* Local functions. */ static int itset_default P((struct sglobal *qglobal, char ***ppzvar, const char *zfile)); static int itadd P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int itunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int itprogram P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static const struct cmdtab_offset asCmds[] = { { "nodename", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zlocalname), NULL }, { "hostname", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zlocalname), NULL }, { "uuname", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zlocalname), NULL }, { "spool", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zspooldir), NULL }, { "pubdir", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zpubdir), NULL }, { "lockdir", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zlockdir), NULL }, { "logfile", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zlogfile), NULL }, { "statfile", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zstatsfile), NULL }, { "debugfile", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zdebugfile), NULL }, { "debug", UUCONF_CMDTABTYPE_STRING, offsetof (struct sprocess, zdebug), NULL }, { "max-uuxqts", UUCONF_CMDTABTYPE_INT, offsetof (struct sprocess, cmaxuuxqts), NULL }, { "sysfile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzsysfiles), itadd }, { "portfile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzportfiles), itadd }, { "dialfile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzdialfiles), itadd }, { "dialcodefile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzdialcodefiles), itadd }, { "callfile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzcallfiles), itadd }, { "passwdfile", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct sprocess, pzpwdfiles), itadd }, { "unknown", UUCONF_CMDTABTYPE_FN, offsetof (struct sprocess, qunknown), itunknown }, { "v2-files", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct sprocess, fv2), NULL }, { "hdb-files", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct sprocess, fhdb), NULL }, { "bnu-files", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct sprocess, fhdb), NULL }, { "timetable", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct sprocess, pztimetables), _uuconf_itimetable }, { NULL, 0, 0, NULL } }; #define CCMDS (sizeof asCmds / sizeof asCmds[0]) /* This structure is used to pass information into the command table functions. */ struct sinfo { /* The program name. */ const char *zname; /* A pointer to the command table being used, passed to isystem so it can call uuconf_cmd_args. */ struct uuconf_cmdtab *qcmds; }; /* Initialize the routines which read the Taylor UUCP configuration files. */ int uuconf_taylor_init (ppglobal, zprogram, zname) pointer *ppglobal; const char *zprogram; const char *zname; { struct sglobal **pqglobal = (struct sglobal **) ppglobal; int iret; char *zcopy; struct sglobal *qglobal; boolean fdefault; FILE *e; struct sinfo si; if (*pqglobal == NULL) { iret = _uuconf_iinit_global (pqglobal); if (iret != UUCONF_SUCCESS) return iret; } qglobal = *pqglobal; if (zname != NULL) { size_t csize; csize = strlen (zname) + 1; zcopy = uuconf_malloc (qglobal->pblock, csize); if (zcopy == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zcopy, (pointer) zname, csize); fdefault = FALSE; } else { zcopy = uuconf_malloc (qglobal->pblock, sizeof NEWCONFIGLIB + sizeof CONFIGFILE - 1); if (zcopy == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zcopy, (pointer) NEWCONFIGLIB, sizeof NEWCONFIGLIB - 1); memcpy ((pointer) (zcopy + sizeof NEWCONFIGLIB - 1), (pointer) CONFIGFILE, sizeof CONFIGFILE); fdefault = TRUE; } qglobal->qprocess->zconfigfile = zcopy; e = fopen (zcopy, "r"); if (e == NULL) { if (! fdefault) { qglobal->ierrno = errno; qglobal->zfilename = zcopy; return (UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_FILENAME); } /* There is no config file, so just use the default values. */ } else { struct uuconf_cmdtab as[CCMDS]; _uuconf_ucmdtab_base (asCmds, CCMDS, (char *) qglobal->qprocess, as); if (zprogram == NULL) zprogram = "uucp"; si.zname = zprogram; si.qcmds = as; iret = uuconf_cmd_file (qglobal, e, as, (pointer) &si, itprogram, UUCONF_CMDTABFLAG_BACKSLASH, qglobal->pblock); (void) fclose (e); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = zcopy; return iret | UUCONF_ERROR_FILENAME; } } /* Get the defaults for the file names. */ iret = itset_default (qglobal, &qglobal->qprocess->pzsysfiles, SYSFILE); if (iret != UUCONF_SUCCESS) return iret; iret = itset_default (qglobal, &qglobal->qprocess->pzportfiles, PORTFILE); if (iret != UUCONF_SUCCESS) return iret; iret = itset_default (qglobal, &qglobal->qprocess->pzdialfiles, DIALFILE); if (iret != UUCONF_SUCCESS) return iret; iret = itset_default (qglobal, &qglobal->qprocess->pzdialcodefiles, DIALCODEFILE); if (iret != UUCONF_SUCCESS) return iret; iret = itset_default (qglobal, &qglobal->qprocess->pzpwdfiles, PASSWDFILE); if (iret != UUCONF_SUCCESS) return iret; iret = itset_default (qglobal, &qglobal->qprocess->pzcallfiles, CALLFILE); if (iret != UUCONF_SUCCESS) return iret; return UUCONF_SUCCESS; } /* Add new strings to a variable. */ /*ARGSUSED*/ static int itadd (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char ***ppz = (char ***) pvar; int i; int iret; if (argc == 1) { iret = _uuconf_iadd_string (qglobal, NULL, FALSE, FALSE, ppz, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret; } else { for (i = 1; i < argc; i++) { iret = _uuconf_iadd_string (qglobal, argv[i], TRUE, FALSE, ppz, qglobal->pblock); if (iret != UUCONF_SUCCESS) return iret; } } return UUCONF_CMDTABRET_CONTINUE; } /* Handle an "unknown" command. We accumulate this into a linked list, and only parse them later in uuconf_unknown_system_info. */ /*ARGSUSED*/ static int itunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sunknown **pq = (struct sunknown **) pvar; struct sunknown *q; q = (struct sunknown *) uuconf_malloc (qglobal->pblock, sizeof (struct sunknown)); if (q == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } q->qnext = NULL; q->ilineno = qglobal->ilineno; q->cargs = argc - 1; q->pzargs = (char **) uuconf_malloc (qglobal->pblock, (argc - 1) * sizeof (char *)); if (q->pzargs == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) q->pzargs, (pointer) (argv + 1), (argc - 1) * sizeof (char *)); while (*pq != NULL) pq = &(*pq)->qnext; *pq = q; return UUCONF_CMDTABRET_KEEP; } /* If we encounter an unknown command, see if it is the program with which we were invoked. If it was, pass the remaining arguments back through the table. */ /*ARGSUSED*/ static int itprogram (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; if (argc <= 1 || strcasecmp (qinfo->zname, argv[0]) != 0) return UUCONF_CMDTABRET_CONTINUE; return uuconf_cmd_args (pglobal, argc - 1, argv + 1, qinfo->qcmds, (pointer) NULL, (uuconf_cmdtabfn) NULL, 0, qglobal->pblock); } /* If a filename was not set by the configuration file, add in the default value. */ static int itset_default (qglobal, ppzvar, zfile) struct sglobal *qglobal; char ***ppzvar; const char *zfile; { size_t clen; char *zadd; if (*ppzvar != NULL) return UUCONF_SUCCESS; clen = strlen (zfile); zadd = (char *) uuconf_malloc (qglobal->pblock, sizeof NEWCONFIGLIB + clen); if (zadd == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zadd, (pointer) NEWCONFIGLIB, sizeof NEWCONFIGLIB - 1); memcpy ((pointer) (zadd + sizeof NEWCONFIGLIB - 1), (pointer) zfile, clen + 1); return _uuconf_iadd_string (qglobal, zadd, FALSE, FALSE, ppzvar, qglobal->pblock); } eral 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 Auucp-1.04/uuconf/tlocnm.c1004440004150000170000000603605337263624012332 037777777777 1 0 /* 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.3 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Get the local name to use, based on the login name, from the Taylor UUCP configuration files. This could probably be done in a slightly more intelligent fashion, but no matter what it has to read the systems files. */ int uuconf_taylor_login_localname (pglobal, zlogin, pzname) pointer pglobal; const char *zlogin; char **pzname; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pznames, **pz; int iret; if (! qglobal->qprocess->fread_syslocs) { iret = _uuconf_iread_locations (qglobal); if (iret != UUCONF_SUCCESS) return iret; } /* As a simple optimization, if there is no "myname" command we can simply return immediately. */ if (! qglobal->qprocess->fuses_myname) { *pzname = NULL; return UUCONF_NOT_FOUND; } iret = uuconf_taylor_system_names (pglobal, &pznames, 0); if (iret != UUCONF_SUCCESS) return iret; *pzname = NULL; iret = UUCONF_NOT_FOUND; for (pz = pznames; *pz != NULL; pz++) { struct uuconf_system ssys; struct uuconf_system *qsys; iret = uuconf_system_info (pglobal, *pz, &ssys); if (iret != UUCONF_SUCCESS) break; for (qsys = &ssys; qsys != NULL; qsys = qsys->uuconf_qalternate) { if (qsys->uuconf_zlocalname != NULL && qsys->uuconf_fcalled && qsys->uuconf_zcalled_login != NULL && strcmp (qsys->uuconf_zcalled_login, zlogin) == 0) { *pzname = strdup (qsys->uuconf_zlocalname); if (*pzname != NULL) iret = UUCONF_SUCCESS; else { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } break; } } (void) uuconf_system_free (pglobal, &ssys); if (qsys != NULL) break; iret = UUCONF_NOT_FOUND; } for (pz = pznames; *pz != NULL; pz++) free ((pointer) *pz); free ((pointer) pznames); return iret; } 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_SUCCESuucp-1.04/uuconf/tport.c1004440004150000170000001637405337263625012215 037777777777 1 0 /* 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.5 1992/07/25 20:44:25 ian Rel $"; #endif #include static int ipport P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ipunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* Find a port in the Taylor UUCP configuration files by name, baud rate, and special purpose function. */ int uuconf_taylor_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) pointer pglobal; const char *zname; long ibaud; long ihighbaud; int (*pifn) P((struct uuconf_port *, pointer)); pointer pinfo; struct uuconf_port *qport; { struct sglobal *qglobal = (struct sglobal *) pglobal; FILE *e; pointer pblock; char *zfree; int iret; char **pz; if (ihighbaud == 0L) ihighbaud = ibaud; e = NULL; pblock = NULL; zfree = NULL; iret = UUCONF_NOT_FOUND; for (pz = qglobal->qprocess->pzportfiles; *pz != NULL; pz++) { struct uuconf_cmdtab as[2]; char *zport; struct uuconf_port sdefault; int ilineno; e = fopen (*pz, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) continue; qglobal->ierrno = errno; iret = UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO; break; } qglobal->ilineno = 0; /* Gather the default information from the top of the file. We do this by handling the "port" command ourselves and passing every other command to _uuconf_iport_cmd via ipunknown. The value of zport will be an malloc block. */ as[0].uuconf_zcmd = "port"; as[0].uuconf_itype = UUCONF_CMDTABTYPE_FN | 2; as[0].uuconf_pvar = (pointer) &zport; as[0].uuconf_pifn = ipport; as[1].uuconf_zcmd = NULL; pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_port (&sdefault); sdefault.uuconf_palloc = pblock; zport = NULL; iret = uuconf_cmd_file (pglobal, e, as, (pointer) &sdefault, ipunknown, UUCONF_CMDTABFLAG_BACKSLASH, pblock); if (iret != UUCONF_SUCCESS) { zfree = zport; break; } /* Now skip until we find a port with a matching name. If the zname argument is NULL, we will have to read every port. */ iret = UUCONF_NOT_FOUND; while (zport != NULL) { uuconf_cmdtabfn piunknown; boolean fmatch; if (zname == NULL || strcmp (zname, zport) == 0) { piunknown = ipunknown; *qport = sdefault; qport->uuconf_zname = zport; zfree = zport; fmatch = TRUE; } else { piunknown = NULL; free ((pointer) zport); fmatch = FALSE; } zport = NULL; ilineno = qglobal->ilineno; iret = uuconf_cmd_file (pglobal, e, as, (pointer) qport, piunknown, UUCONF_CMDTABFLAG_BACKSLASH, pblock); qglobal->ilineno += ilineno; if (iret != UUCONF_SUCCESS) break; iret = UUCONF_NOT_FOUND; /* We may have just gathered information about a port. See if it matches the name, the baud rate and the special function. */ if (fmatch) { if (ibaud != 0) { if (qport->uuconf_ttype == UUCONF_PORTTYPE_MODEM) { long imbaud, imhigh, imlow; imbaud = qport->uuconf_u.uuconf_smodem.uuconf_ibaud; imhigh = qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud; imlow = qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud; if (imbaud == 0 && imlow == 0) ; else if (ibaud <= imbaud && imbaud <= ihighbaud) ; else if (imlow != 0 && imlow <= ihighbaud && imhigh >= ibaud) ; else fmatch = FALSE; } else if (qport->uuconf_ttype == UUCONF_PORTTYPE_DIRECT) { long idbaud; idbaud = qport->uuconf_u.uuconf_sdirect.uuconf_ibaud; if (idbaud != 0 && idbaud != ibaud) fmatch = FALSE; } } } if (fmatch) { if (pifn != NULL) { iret = (*pifn) (qport, pinfo); if (iret == UUCONF_NOT_FOUND) fmatch = FALSE; else if (iret != UUCONF_SUCCESS) break; } } if (fmatch) { if (uuconf_add_block (pblock, zfree) == 0) { zfree = NULL; iret = UUCONF_SUCCESS; } else { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } break; } if (zfree != NULL) { free ((pointer) zfree); zfree = NULL; } } (void) fclose (e); e = NULL; if (iret != UUCONF_NOT_FOUND) break; uuconf_free_block (pblock); pblock = NULL; } if (e != NULL) (void) fclose (e); if (zfree != NULL) free ((pointer) zfree); if (iret != UUCONF_SUCCESS && pblock != NULL) uuconf_free_block (pblock); if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) { qglobal->zfilename = *pz; iret |= UUCONF_ERROR_FILENAME; } return iret; } /* Handle a "port" command. This copies the string onto the heap and returns the pointer in *pvar. It returns UUCONF_CMDTABRET_EXIT to force uuconf_cmd_file to stop reading and return to the code above, which will then check the port just read to see if it matches. */ /*ARGSUSED*/ static int ipport (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; char **pz = (char **) pvar; size_t csize; csize = strlen (argv[1]) + 1; *pz = malloc (csize); if (*pz == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) *pz, (pointer) argv[1], csize); return UUCONF_CMDTABRET_EXIT; } /* Handle an unknown command by passing it on to _uuconf_iport_cmd, which will parse it into the port structure. */ /*ARGSUSED*/ static int ipunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_port *qport = (struct uuconf_port *) pinfo; return _uuconf_iport_cmd (qglobal, argc, argv, qport); } nfiguration 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; uucp-1.04/uuconf/tportc.c1004440004150000170000003373205337263625012355 037777777777 1 0 /* 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.5 1992/07/25 18:44:34 ian Rel $"; #endif #include static int ipproto_param P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ipbaud_range P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ipdialer P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); static int ipcunknown P((pointer pglobal, int argc, char **argv, pointer pvar, pointer pinfo)); /* The string names of the port types. This array corresponds to the uuconf_porttype enumeration. */ static const char * const azPtype_names[] = { NULL, "stdin", "modem", "direct", "tcp", "tli" }; #define CPORT_TYPES (sizeof azPtype_names / sizeof azPtype_names[0]) /* The command table for generic port commands. The "port" and "type" commands are handled specially. */ static const struct cmdtab_offset asPort_cmds[] = { { "protocol", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_zprotocols), NULL }, { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_port, uuconf_qproto_params), ipproto_param }, { "seven-bit", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_iseven_bit }, { "reliable", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_ireliable }, { "half-duplex", UUCONF_CMDTABTYPE_FN | 2, offsetof (struct uuconf_port, uuconf_ireliable), _uuconf_ihalf_duplex }, { "lockname", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_zlockname), NULL }, { NULL, 0, 0, NULL } }; #define CPORT_CMDS (sizeof asPort_cmds / sizeof asPort_cmds[0]) /* The stdin port command table. */ static const struct cmdtab_offset asPstdin_cmds[] = { { NULL, 0, 0, NULL } }; #define CSTDIN_CMDS (sizeof asPstdin_cmds / sizeof asPstdin_cmds[0]) /* The modem port command table. */ static const struct cmdtab_offset asPmodem_cmds[] = { { "device", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_zdevice), NULL }, { "baud", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), NULL }, { "speed", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_ibaud), NULL }, { "baud-range", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, { "speed-range", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipbaud_range }, { "carrier", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_fcarrier), NULL }, { "dial-device", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_zdial_device), NULL }, { "dialer", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem), ipdialer }, { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_port, uuconf_u.uuconf_smodem.uuconf_pzdialer), NULL }, { NULL, 0, 0, NULL } }; #define CMODEM_CMDS (sizeof asPmodem_cmds / sizeof asPmodem_cmds[0]) /* The direct port command table. */ static const struct cmdtab_offset asPdirect_cmds[] = { { "device", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_zdevice), NULL }, { "baud", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), NULL }, { "speed", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_port, uuconf_u.uuconf_sdirect.uuconf_ibaud), NULL }, { NULL, 0, 0, NULL } }; #define CDIRECT_CMDS (sizeof asPdirect_cmds / sizeof asPdirect_cmds[0]) /* The TCP port command table. */ static const struct cmdtab_offset asPtcp_cmds[] = { { "service", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stcp.uuconf_zport), NULL }, { NULL, 0, 0, NULL } }; #define CTCP_CMDS (sizeof asPtcp_cmds / sizeof asPtcp_cmds[0]) /* The TLI port command table. */ static const struct cmdtab_offset asPtli_cmds[] = { { "device", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zdevice), NULL }, { "stream", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_fstream), NULL }, { "push", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzpush), NULL }, { "dialer-sequence", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_pzdialer), NULL }, { "server-address", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_port, uuconf_u.uuconf_stli.uuconf_zservaddr), NULL }, { NULL, 0, 0, NULL } }; #define CTLI_CMDS (sizeof asPtli_cmds / sizeof asPtli_cmds[0]) #undef max #define max(i1, i2) ((i1) > (i2) ? (i1) : (i2)) #define CCMDS \ max (max (max (CPORT_CMDS, CSTDIN_CMDS), CMODEM_CMDS), \ max (max (CDIRECT_CMDS, CTCP_CMDS), CTLI_CMDS)) /* Handle a command passed to a port from a Taylor UUCP configuration file. This can be called when reading either the port file or the sys file. The return value may have UUCONF_CMDTABRET_KEEP set, but not UUCONF_CMDTABRET_EXIT. It assigns values to the elements of qport. The first time this is called, qport->uuconf_zname and qport->uuconf_palloc should be set and qport->uuconf_ttype should be UUCONF_PORTTYPE_UNKNOWN. */ int _uuconf_iport_cmd (qglobal, argc, argv, qport) struct sglobal *qglobal; int argc; char **argv; struct uuconf_port *qport; { boolean fgottype; const struct cmdtab_offset *qcmds; size_t ccmds; struct uuconf_cmdtab as[CCMDS]; int i; int iret; fgottype = strcasecmp (argv[0], "type") == 0; if (fgottype || qport->uuconf_ttype == UUCONF_PORTTYPE_UNKNOWN) { enum uuconf_porttype ttype; /* We either just got a "type" command, or this is an uninitialized port. If the first command to a port is not "type", it is assumed to be a modem port. This implementation will actually permit "type" at any point, but will effectively discard any type specific information that appears before the "type" command. This supports defaults, in that the default may be of a specific type while future ports in the same file may be of other types. */ if (! fgottype) ttype = UUCONF_PORTTYPE_MODEM; else { if (argc != 2) return UUCONF_SYNTAX_ERROR; for (i = 0; i < CPORT_TYPES; i++) if (azPtype_names[i] != NULL && strcasecmp (argv[1], azPtype_names[i]) == 0) break; if (i >= CPORT_TYPES) return UUCONF_SYNTAX_ERROR; ttype = (enum uuconf_porttype) i; } qport->uuconf_ttype = ttype; switch (ttype) { default: case UUCONF_PORTTYPE_STDIN: break; case UUCONF_PORTTYPE_MODEM: qport->uuconf_u.uuconf_smodem.uuconf_zdevice = NULL; qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; break; case UUCONF_PORTTYPE_DIRECT: qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = NULL; qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = -1; break; case UUCONF_PORTTYPE_TCP: qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp"; qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED | UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX); break; case UUCONF_PORTTYPE_TLI: qport->uuconf_u.uuconf_stli.uuconf_zdevice = NULL; qport->uuconf_u.uuconf_stli.uuconf_fstream = FALSE; qport->uuconf_u.uuconf_stli.uuconf_pzpush = NULL; qport->uuconf_u.uuconf_stli.uuconf_pzdialer = NULL; qport->uuconf_u.uuconf_stli.uuconf_zservaddr = NULL; qport->uuconf_ireliable = (UUCONF_RELIABLE_SPECIFIED | UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX); break; } if (fgottype) return UUCONF_CMDTABRET_CONTINUE; } /* See if this command is one of the generic ones. */ qcmds = asPort_cmds; ccmds = CPORT_CMDS; for (i = 0; i < CPORT_CMDS - 1; i++) if (strcasecmp (argv[0], asPort_cmds[i].zcmd) == 0) break; if (i >= CPORT_CMDS - 1) { /* It's not a generic command, so we must check the type specific commands. */ switch (qport->uuconf_ttype) { case UUCONF_PORTTYPE_STDIN: qcmds = asPstdin_cmds; ccmds = CSTDIN_CMDS; break; case UUCONF_PORTTYPE_MODEM: qcmds = asPmodem_cmds; ccmds = CMODEM_CMDS; break; case UUCONF_PORTTYPE_DIRECT: qcmds = asPdirect_cmds; ccmds = CDIRECT_CMDS; break; case UUCONF_PORTTYPE_TCP: qcmds = asPtcp_cmds; ccmds = CTCP_CMDS; break; case UUCONF_PORTTYPE_TLI: qcmds = asPtli_cmds; ccmds = CTLI_CMDS; break; default: return UUCONF_SYNTAX_ERROR; } } /* Copy the command table onto the stack and modify it to point to qport. */ _uuconf_ucmdtab_base (qcmds, ccmds, (char *) qport, as); iret = uuconf_cmd_args ((pointer) qglobal, argc, argv, as, (pointer) qport, ipcunknown, 0, qport->uuconf_palloc); return iret &~ UUCONF_CMDTABRET_EXIT; } /* Handle the "protocol-parameter" command. */ static int ipproto_param (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; struct uuconf_port *qport = (struct uuconf_port *) pinfo; return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, qport->uuconf_palloc); } /* Handle the "baud-range" command. */ /*ARGSUSED*/ static int ipbaud_range (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; int iret; iret = _uuconf_iint (qglobal, argv[1], (pointer) &qmodem->uuconf_ilowbaud, FALSE); if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) return iret; iret |= _uuconf_iint (qglobal, argv[2], (pointer) &qmodem->uuconf_ihighbaud, FALSE); return iret; } /* Handle the "dialer" command. If there is one argument, this names a dialer. Otherwise, the remaining arguments form a command describing the dialer. */ static int ipdialer (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_modem_port *qmodem = (struct uuconf_modem_port *) pvar; struct uuconf_port *qport = (struct uuconf_port *) pinfo; int iret; if (argc < 2) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; if (argc > 2) { if (qmodem->uuconf_qdialer == NULL) { struct uuconf_dialer *qnew; size_t clen; qnew = ((struct uuconf_dialer *) uuconf_malloc (qport->uuconf_palloc, sizeof (struct uuconf_dialer))); if (qnew == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } _uuconf_uclear_dialer (qnew); clen = strlen (qport->uuconf_zname); qnew->uuconf_zname = (char *) uuconf_malloc (qport->uuconf_palloc, (clen + sizeof " dialer")); if (qnew->uuconf_zname == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) qnew->uuconf_zname, (pointer) qport->uuconf_zname, clen); memcpy ((pointer) (qnew->uuconf_zname + clen), (pointer) " dialer", sizeof " dialer"); qnew->uuconf_palloc = qport->uuconf_palloc; qmodem->uuconf_qdialer = qnew; } iret = _uuconf_idialer_cmd (qglobal, argc - 1, argv + 1, qmodem->uuconf_qdialer); if ((iret &~ UUCONF_CMDTABRET_KEEP) != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } else { qmodem->uuconf_pzdialer = NULL; iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, &qmodem->uuconf_pzdialer, qport->uuconf_palloc); if (iret != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } } /* Give an error for an unknown port command. */ /*ARGSUSED*/ static int ipcunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; } truct uuconf_port, uuconf_u.uuconf_smouucp-1.04/uuconf/tsinfo.c1004440004150000170000006631305337263625012345 037777777777 1 0 /* 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.9 1992/11/14 16:16:24 ian Rel $"; #endif #include #include #ifndef SEEK_SET #define SEEK_SET 0 #endif static void uiset_call P((struct uuconf_system *qsys)); static int iisizecmp P((long i1, long i2)); /* Local functions needed to parse the system information file. */ #define CMDTABFN(z) \ static int z P((pointer, int, char **, pointer, pointer)) CMDTABFN (iisystem); CMDTABFN (iialias); CMDTABFN (iialternate); CMDTABFN (iidefault_alternates); CMDTABFN (iitime); CMDTABFN (iitimegrade); CMDTABFN (iisize); CMDTABFN (iibaud_range); CMDTABFN (iiport); CMDTABFN (iichat); CMDTABFN (iicalled_login); CMDTABFN (iiproto_param); CMDTABFN (iirequest); CMDTABFN (iitransfer); CMDTABFN (iiforward); CMDTABFN (iiunknown); #undef CMDTABFN /* We have to pass a fair amount of information in and out of the various system commands. Using global variables would make the code non-reentrant, so we instead pass a pointer to single structure as the pinfo argument to the system commands. */ struct sinfo { /* The system information we're building up. */ struct uuconf_system *qsys; /* Whether any alternates have been used. */ boolean falternates; /* A list of the previous alternates. */ struct uuconf_system salternate; /* Whether to use extra alternates from the file wide defaults. */ int fdefault_alternates; }; /* The command table for system commands. */ static const struct cmdtab_offset asIcmds[] = { { "system", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iisystem }, { "alias", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iialias }, { "alternate", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iialternate }, { "default-alternates", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iidefault_alternates }, { "time", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_system, uuconf_qtimegrade), iitime }, { "timegrade", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_system, uuconf_qtimegrade), iitimegrade }, { "max-retries", UUCONF_CMDTABTYPE_INT, offsetof (struct uuconf_system, uuconf_cmax_retries), NULL }, { "success-wait", UUCONF_CMDTABTYPE_INT, offsetof (struct uuconf_system, uuconf_csuccess_wait), NULL }, { "call-timegrade", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_system, uuconf_qcalltimegrade), iitimegrade }, { "call-local-size", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_system, uuconf_qcall_local_size), iisize }, { "call-remote-size", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_system, uuconf_qcall_remote_size), iisize }, { "called-local-size", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_system, uuconf_qcalled_local_size), iisize }, { "called-remote-size", UUCONF_CMDTABTYPE_FN | 3, offsetof (struct uuconf_system, uuconf_qcalled_remote_size), iisize }, { "timetable", UUCONF_CMDTABTYPE_FN | 3, (size_t) -1, _uuconf_itimetable }, { "baud", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_system, uuconf_ibaud), NULL }, { "speed", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_system, uuconf_ibaud), NULL }, { "baud-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range }, { "speed-range", UUCONF_CMDTABTYPE_FN | 3, 0, iibaud_range }, { "port", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiport }, { "phone", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zphone), NULL }, { "address", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zphone), NULL }, { "chat", UUCONF_CMDTABTYPE_PREFIX | 0, offsetof (struct uuconf_system, uuconf_schat), iichat }, { "call-login", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zcall_login), NULL }, { "call-password", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zcall_password), NULL }, { "called-login", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_system, uuconf_zcalled_login), iicalled_login }, { "callback", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_fcallback), NULL }, { "sequence", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_fsequence), NULL }, { "protocol", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zprotocols), NULL }, { "protocol-parameter", UUCONF_CMDTABTYPE_FN | 0, offsetof (struct uuconf_system, uuconf_qproto_params), iiproto_param }, { "called-chat", UUCONF_CMDTABTYPE_PREFIX | 0, offsetof (struct uuconf_system, uuconf_scalled_chat), iichat }, { "debug", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zdebug), NULL }, { "max-remote-debug", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zmax_remote_debug), NULL }, { "send-request", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_fsend_request), NULL }, { "receive-request", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_frec_request), NULL }, { "request", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iirequest }, { "call-transfer", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_fcall_transfer), NULL }, { "called-transfer", UUCONF_CMDTABTYPE_BOOLEAN, offsetof (struct uuconf_system, uuconf_fcalled_transfer), NULL }, { "transfer", UUCONF_CMDTABTYPE_FN | 2, (size_t) -1, iitransfer }, { "local-send", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzlocal_send), NULL }, { "remote-send", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzremote_send), NULL }, { "local-receive", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzlocal_receive), NULL }, { "remote-receive", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzremote_receive), NULL }, { "command-path", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzpath), NULL }, { "commands", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzcmds), NULL }, { "free-space", UUCONF_CMDTABTYPE_LONG, offsetof (struct uuconf_system, uuconf_cfree_space), NULL }, { "forward-from", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzforward_from), NULL }, { "forward-to", UUCONF_CMDTABTYPE_FULLSTRING, offsetof (struct uuconf_system, uuconf_pzforward_to), NULL }, { "forward", UUCONF_CMDTABTYPE_FN | 0, (size_t) -1, iiforward }, { "pubdir", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zpubdir), NULL }, { "myname", UUCONF_CMDTABTYPE_STRING, offsetof (struct uuconf_system, uuconf_zlocalname), NULL }, { NULL, 0, 0, NULL } }; #define CSYSTEM_CMDS (sizeof asIcmds / sizeof asIcmds[0]) /* Get information about the system zsystem from the Taylor UUCP configuration files. Sets *qsys. This does not ensure that all default information is set. */ int _uuconf_itaylor_system_internal (qglobal, zsystem, qsys) struct sglobal *qglobal; const char *zsystem; struct uuconf_system *qsys; { int iret; struct stsysloc *qloc; struct uuconf_cmdtab as[CSYSTEM_CMDS]; struct sinfo si; struct uuconf_system sdefaults; if (! qglobal->qprocess->fread_syslocs) { iret = _uuconf_iread_locations (qglobal); if (iret != UUCONF_SUCCESS) return iret; } /* Find the system in the list of locations. */ for (qloc = qglobal->qprocess->qsyslocs; qloc != NULL; qloc = qloc->qnext) if (qloc->zname[0] == zsystem[0] && strcmp (qloc->zname, zsystem) == 0) break; if (qloc == NULL) return UUCONF_NOT_FOUND; /* If this is an alias, then the real system is the next non-alias in the list. */ while (qloc->falias) { qloc = qloc->qnext; if (qloc == NULL) return UUCONF_NOT_FOUND; } _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as); rewind (qloc->e); /* Read the file wide defaults from the start of the file. */ _uuconf_uclear_system (qsys); si.qsys = qsys; si.falternates = FALSE; si.fdefault_alternates = TRUE; qsys->uuconf_palloc = uuconf_malloc_block (); if (qsys->uuconf_palloc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } iret = uuconf_cmd_file ((pointer) qglobal, qloc->e, as, (pointer) &si, iiunknown, UUCONF_CMDTABFLAG_BACKSLASH, qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = qloc->zfile; return iret | UUCONF_ERROR_FILENAME; } if (! si.falternates) uiset_call (qsys); else { /* Attach the final alternate. */ iret = iialternate ((pointer) qglobal, 0, (char **) NULL, (pointer) NULL, (pointer) &si); if (iret != UUCONF_SUCCESS) return iret; } /* Save off the defaults. */ sdefaults = *qsys; /* Advance to the information for the system we want. */ if (fseek (qloc->e, qloc->iloc, SEEK_SET) != 0) { qglobal->ierrno = errno; qglobal->zfilename = qloc->zfile; return (UUCONF_FSEEK_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_FILENAME); } /* Read in the system we want. */ _uuconf_uclear_system (qsys); qsys->uuconf_zname = (char *) qloc->zname; qsys->uuconf_palloc = sdefaults.uuconf_palloc; si.falternates = FALSE; iret = uuconf_cmd_file (qglobal, qloc->e, as, (pointer) &si, iiunknown, UUCONF_CMDTABFLAG_BACKSLASH, qsys->uuconf_palloc); qglobal->ilineno += qloc->ilineno; if (iret == UUCONF_SUCCESS) { if (! si.falternates) uiset_call (qsys); else iret = iialternate ((pointer) qglobal, 0, (char **) NULL, (pointer) NULL, (pointer) &si); } /* Merge in the defaults. */ if (iret == UUCONF_SUCCESS) iret = _uuconf_isystem_default (qglobal, qsys, &sdefaults, si.fdefault_alternates); /* The first alternate is always available for calling in. */ if (iret == UUCONF_SUCCESS) qsys->uuconf_fcalled = TRUE; if (iret != UUCONF_SUCCESS) { qglobal->zfilename = qloc->zfile; iret |= UUCONF_ERROR_FILENAME; } return iret; } /* Set the fcall and fcalled field for the system. This marks a particular alternate for use when calling out or calling in. This is where we implement the semantics described in the documentation: a change to a relevant field implies that the alternate is used. If all the relevant fields are unchanged, the alternate is not used. */ static void uiset_call (qsys) struct uuconf_system *qsys; { qsys->uuconf_fcall = (qsys->uuconf_qtimegrade != (struct uuconf_timespan *) &_uuconf_unset || qsys->uuconf_zport != (char *) &_uuconf_unset || qsys->uuconf_qport != (struct uuconf_port *) &_uuconf_unset || qsys->uuconf_ibaud >= 0 || qsys->uuconf_zphone != (char *) &_uuconf_unset || qsys->uuconf_schat.uuconf_pzchat != (char **) &_uuconf_unset || qsys->uuconf_schat.uuconf_pzprogram != (char **) &_uuconf_unset); qsys->uuconf_fcalled = qsys->uuconf_zcalled_login != (char *) &_uuconf_unset; } /* Handle the "system" command. Because we skip directly to the system we want to read, a "system" command means we've reached the end of it. */ static int iisystem (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { return UUCONF_CMDTABRET_EXIT; } /* Handle the "alias" command. */ /*ARGSUSED*/ static int iialias (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; int iret; iret = _uuconf_iadd_string (qglobal, argv[1], TRUE, FALSE, &qinfo->qsys->uuconf_pzalias, qinfo->qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } /* Handle the "alternate" command. The information just read is in sIhold. If this is the first "alternate" command for this system, we save off the current information in sIalternate. Otherwise we default this information to sIalternate, and then add it to the end of the list of alternates in sIalternate. */ static int iialternate (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; uiset_call (qinfo->qsys); if (! qinfo->falternates) { qinfo->salternate = *qinfo->qsys; qinfo->falternates = TRUE; } else { int iret; struct uuconf_system *qnew, **pq; iret = _uuconf_isystem_default (qglobal, qinfo->qsys, &qinfo->salternate, FALSE); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_EXIT; qnew = ((struct uuconf_system *) uuconf_malloc (qinfo->qsys->uuconf_palloc, sizeof (struct uuconf_system))); if (qnew == NULL) { qglobal->ierrno = errno;; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } *qnew = *qinfo->qsys; for (pq = &qinfo->salternate.uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qnew; } /* If this is the last alternate command, move the information back to qinfo->qsys. */ if (argc == 0) *qinfo->qsys = qinfo->salternate; else { _uuconf_uclear_system (qinfo->qsys); qinfo->qsys->uuconf_zname = qinfo->salternate.uuconf_zname; qinfo->qsys->uuconf_palloc = qinfo->salternate.uuconf_palloc; if (argc > 1) { qinfo->qsys->uuconf_zalternate = argv[1]; return UUCONF_CMDTABRET_KEEP; } } return UUCONF_CMDTABRET_CONTINUE; } /* Handle the "default-alternates" command. This just takes a boolean argument which is used to set the fdefault_alternates field of the sinfo structure. */ /*ARGSUSED*/ static int iidefault_alternates (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; return _uuconf_iboolean (qglobal, argv[1], &qinfo->fdefault_alternates); } /* Handle the "time" command. We do this by turning it into a "timegrade" command with a grade of BGRADE_LOW. The first argument is a time string, and the optional second argument is the retry time. */ /*ARGSUSED*/ static int iitime (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { char *aznew[4]; char ab[2]; if (argc != 2 && argc != 3) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; aznew[0] = argv[0]; ab[0] = UUCONF_GRADE_LOW; ab[1] = '\0'; aznew[1] = ab; aznew[2] = argv[1]; if (argc > 2) aznew[3] = argv[2]; return iitimegrade (pglobal, argc + 1, aznew, pvar, pinfo); } /* Handle the "timegrade" command by calling _uuconf_itime_parse with appropriate ival (the work grade) and cretry (the retry time) arguments. */ static int iitimegrade (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar; struct sinfo *qinfo = (struct sinfo *) pinfo; int cretry; int iret; if (argc < 3 || argc > 4) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; if (argv[1][1] != '\0' || ! UUCONF_GRADE_LEGAL (argv[1][0])) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; if (argc == 3) cretry = 0; else { iret = _uuconf_iint (qglobal, argv[3], (pointer) &cretry, TRUE); if (iret != UUCONF_SUCCESS) return iret; } iret = _uuconf_itime_parse (qglobal, argv[2], (long) argv[1][0], cretry, _uuconf_itime_grade_cmp, pqspan, qinfo->qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } /* Handle the "baud-range" command, also known as "speed-range". */ static int iibaud_range (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_system *qsys = (struct uuconf_system *) pvar; int iret; iret = _uuconf_iint (qglobal, argv[1], (pointer) &qsys->uuconf_ibaud, FALSE); if (iret != UUCONF_SUCCESS) return iret; return _uuconf_iint (qglobal, argv[2], (pointer) &qsys->uuconf_ihighbaud, FALSE); } /* Handle one of the size commands ("call-local-size", etc.). The first argument is a number of bytes, and the second argument is a time string. The pvar argument points to the string array to which we add this new string. */ /*ARGSUSED*/ static int iisize (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_timespan **pqspan = (struct uuconf_timespan **) pvar; struct sinfo *qinfo = (struct sinfo *) pinfo; long ival; int iret; iret = _uuconf_iint (qglobal, argv[1], (pointer) &ival, FALSE); if (iret != UUCONF_SUCCESS) return iret; iret = _uuconf_itime_parse (qglobal, argv[2], ival, 0, iisizecmp, pqspan, qinfo->qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } /* A comparison function for sizes to pass to _uuconf_itime_parse. */ static int iisizecmp (i1, i2) long i1; long i2; { /* We can't just return i1 - i2 because that would be a long. */ if (i1 < i2) return -1; else if (i1 == i2) return 0; else return 1; } /* Handle the "port" command. If there is one argument, this names a port. Otherwise, the remaining arguments form a command describing the port. */ /*ARGSUSED*/ static int iiport (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; if (argc < 2) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; else if (argc == 2) { qinfo->qsys->uuconf_zport = argv[1]; return UUCONF_CMDTABRET_KEEP; } else { int iret; if (qinfo->qsys->uuconf_qport == (struct uuconf_port *) &_uuconf_unset) { struct uuconf_port *qnew; qnew = ((struct uuconf_port *) uuconf_malloc (qinfo->qsys->uuconf_palloc, sizeof (struct uuconf_port))); if (qnew == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } _uuconf_uclear_port (qnew); if (qinfo->qsys->uuconf_zname == NULL) qnew->uuconf_zname = (char *) "default system file port"; else { char *zname; size_t clen; clen = strlen (qinfo->qsys->uuconf_zname); zname = (char *) uuconf_malloc (qinfo->qsys->uuconf_palloc, clen + sizeof "system port"); if (zname == NULL) { qglobal->ierrno = errno; return (UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO | UUCONF_CMDTABRET_EXIT); } memcpy ((pointer) zname, (pointer) "system ", sizeof "system " - 1); memcpy ((pointer) (zname + sizeof "system " - 1), (pointer) qinfo->qsys->uuconf_zname, clen); memcpy ((pointer) (zname + sizeof "system " - 1 + clen), (pointer) " port", sizeof " port"); qnew->uuconf_zname = zname; } qnew->uuconf_palloc = qinfo->qsys->uuconf_palloc; qinfo->qsys->uuconf_qport = qnew; } iret = _uuconf_iport_cmd (qglobal, argc - 1, argv + 1, qinfo->qsys->uuconf_qport); if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } } /* Handle the "chat" and "called-chat" set of commands. These just hand off to the generic chat script function. */ static int iichat (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; struct uuconf_chat *qchat = (struct uuconf_chat *) pvar; int iret; iret = _uuconf_ichat_cmd (qglobal, argc, argv, qchat, qinfo->qsys->uuconf_palloc); if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) iret |= UUCONF_CMDTABRET_EXIT; return iret; } /* Handle the "called-login" command. This only needs to be in a function because there can be additional arguments listing the remote systems which are permitted to use this login name. The additional arguments are not actually handled here; they are handled by uuconf_taylor_system_names, which already has to go through all the system files. */ /*ARGSUSED*/ static int iicalled_login (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { char **pz = (char **) pvar; if (argc < 2) return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; *pz = argv[1]; return UUCONF_CMDTABRET_KEEP; } /* Handle the "protocol-parameter" command. This just hands off to the generic protocol parameter handler. */ static int iiproto_param (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_proto_param **pqparam = (struct uuconf_proto_param **) pvar; struct sinfo *qinfo = (struct sinfo *) pinfo; if (*pqparam == (struct uuconf_proto_param *) &_uuconf_unset) *pqparam = NULL; return _uuconf_iadd_proto_param (qglobal, argc - 1, argv + 1, pqparam, qinfo->qsys->uuconf_palloc); } /* Handle the "request" command. This is equivalent to specifying both "call-request" and "called-request". */ /*ARGSUSED*/ static int iirequest (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; int iret; iret = _uuconf_iboolean (qglobal, argv[1], &qinfo->qsys->uuconf_fsend_request); if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) qinfo->qsys->uuconf_frec_request = qinfo->qsys->uuconf_fsend_request; return iret; } /* Handle the "transfer" command. This is equivalent to specifying both "call-transfer" and "called-transfer". */ /*ARGSUSED*/ static int iitransfer (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; int iret; iret = _uuconf_iboolean (qglobal, argv[1], &qinfo->qsys->uuconf_fcall_transfer); if (UUCONF_ERROR_VALUE (iret) == UUCONF_SUCCESS) qinfo->qsys->uuconf_fcalled_transfer = qinfo->qsys->uuconf_fcall_transfer; return iret; } /* Handle the "forward" command. This is equivalent to specifying both "forward-from" and "forward-to". */ /*ARGSUSED*/ static int iiforward (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct sinfo *qinfo = (struct sinfo *) pinfo; struct uuconf_system *qsys; int i; int iret; qsys = qinfo->qsys; qsys->uuconf_pzforward_from = NULL; qsys->uuconf_pzforward_to = NULL; for (i = 1; i < argc; i++) { iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE, &qsys->uuconf_pzforward_to, qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT; iret = _uuconf_iadd_string (qglobal, argv[i], FALSE, FALSE, &qsys->uuconf_pzforward_from, qsys->uuconf_palloc); if (iret != UUCONF_SUCCESS) return iret | UUCONF_CMDTABRET_KEEP | UUCONF_CMDTABRET_EXIT; } return UUCONF_CMDTABRET_KEEP; } /* Handle an unknown command. This should probably be done more intelligently. */ /*ARGSUSED*/ static int iiunknown (pglobal, argc, argv, pvar, pinfo) pointer pglobal; int argc; char **argv; pointer pvar; pointer pinfo; { return UUCONF_SYNTAX_ERROR | UUCONF_CMDTABRET_EXIT; } /* Return information for an unknown system. It would be better to put this in a different file, but it would require breaking several functions out of this file. Perhaps I will do it sometime. */ int uuconf_taylor_system_unknown (pglobal, qsys) pointer pglobal; struct uuconf_system *qsys; { struct sglobal *qglobal = (struct sglobal *) pglobal; struct uuconf_cmdtab as[CSYSTEM_CMDS]; struct sinfo si; struct sunknown *q; int iret; if (qglobal->qprocess->qunknown == NULL) return UUCONF_NOT_FOUND; _uuconf_ucmdtab_base (asIcmds, CSYSTEM_CMDS, (char *) qsys, as); _uuconf_uclear_system (qsys); si.qsys = qsys; si.falternates = FALSE; si.fdefault_alternates = TRUE; qsys->uuconf_palloc = uuconf_malloc_block (); if (qsys->uuconf_palloc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } for (q = qglobal->qprocess->qunknown; q != NULL; q = q->qnext) { iret = uuconf_cmd_args (pglobal, q->cargs, q->pzargs, as, (pointer) &si, iiunknown, UUCONF_CMDTABFLAG_BACKSLASH, qsys->uuconf_palloc); iret &=~ UUCONF_CMDTABRET_KEEP; if (UUCONF_ERROR_VALUE (iret) != UUCONF_SUCCESS) { qglobal->zfilename = qglobal->qprocess->zconfigfile; qglobal->ilineno = q->ilineno; return ((iret &~ UUCONF_CMDTABRET_EXIT) | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO); } if ((iret & UUCONF_CMDTABRET_EXIT) != 0) break; } if (! si.falternates) uiset_call (qsys); else { iret = iialternate (pglobal, 0, (char **) NULL, (pointer) NULL, (pointer) &si); if (iret != UUCONF_SUCCESS) return iret; } /* The first alternate is always available for calling in. */ qsys->uuconf_fcalled = TRUE; return _uuconf_isystem_basic_default (qglobal, qsys); } 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)uucp-1.04/uuconf/tsnams.c1004440004150000170000000462305337263626012345 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } ys->uuconf_zname, clen); memcpy ((pointer) (zname + sizeof "system " - 1 + clen), (poiuucp-1.04/uuconf/tsys.c1004440004150000170000000330305337263626012034 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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); } aram = 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) uucp-1.04/uuconf/tval.c1004440004150000170000000416405337263626012006 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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; } 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_uclearuucp-1.04/uuconf/ugtlin.c1004440004150000170000000503505337263626012340 037777777777 1 0 /* 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.3 1992/07/26 03:57:39 ian Rel $"; #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'; } } ucnfi.h" #if USE_RCS_ID const char _uuconf_tsnams_rcsid[] = "$Id: tsnams.c,v 1.2 1992/06/15 18:40:43 ian Rel $"; #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; uucp-1.04/uuconf/unk.c1004440004150000170000000454605337263626011641 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include /* Get information about an unknown system. If we are using HAVE_TAYLOR_CONFIG, we just use it. Otherwise if we are using HAVE_HDB_CONFIG, we use it. Otherwise we return a default system. This isn't right for HAVE_V2_CONFIG, because it is possible to specify default directories to read and write in USERFILE. However, I'm not going to bother to write that code unless somebody actually wants it. */ /*ARGSUSED*/ int uuconf_system_unknown (pglobal, qsys) pointer pglobal; struct uuconf_system *qsys; { #if HAVE_TAYLOR_CONFIG return uuconf_taylor_system_unknown (pglobal, qsys); #else /* ! HAVE_TAYLOR_CONFIG */ #if HAVE_HDB_CONFIG return uuconf_hdb_system_unknown (pglobal, qsys); #else /* ! HAVE_HDB_CONFIG */ #if HAVE_V2_CONFIG struct sglobal *qglobal = (struct sglobal *) pglobal; _uuconf_uclear_system (qsys); qsys->uuconf_palloc = uuconf_malloc_block (); if (qsys->uuconf_palloc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } return _uuconf_isystem_basic_default (qglobal, qsys); #else /* ! HAVE_V2_CONFIG */ return UUCONF_NOT_FOUND; #endif /* ! HAVE_V2_CONFIG */ #endif /* ! HAVE_HDB_CONFIG */ #endif /* ! HAVE_TAYLOR_CONFIG */ } (pglobal, zsystem, qsys) pointer pglobal; const char *zsystem; struct uuconf_system *qsys; { struct sglobal *qglobal = (struct sglobal *)uucp-1.04/uuconf/val.c1004440004150000170000000264305337263632011617 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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 } ted at ian@airs.com or c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. uucp-1.04/uuconf/vinit.c1004440004150000170000000633105337263632012164 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #endif #include static int ivinlib P((struct sglobal *qglobal, const char *z, size_t csize, char **pz)); /* Return an allocated buffer holding a file name in OLDCONFIGLIB. The c argument is the size of z including the trailing null byte, since this is convenient for both the caller and this function. */ static int ivinlib (qglobal, z, c, pz) struct sglobal *qglobal; const char *z; size_t c; char **pz; { char *zalc; zalc = uuconf_malloc (qglobal->pblock, sizeof OLDCONFIGLIB - 1 + c); if (zalc == NULL) { qglobal->ierrno = errno; return UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } memcpy ((pointer) zalc, (pointer) OLDCONFIGLIB, sizeof OLDCONFIGLIB - 1); memcpy ((pointer) (zalc + sizeof OLDCONFIGLIB - 1), (pointer) z, c); *pz = zalc; return UUCONF_SUCCESS; } /* Initialize the routines which read V2 configuration files. The only thing we do here is allocate the file names. */ int uuconf_v2_init (ppglobal) pointer *ppglobal; { struct sglobal **pqglobal = (struct sglobal **) ppglobal; int iret; struct sglobal *qglobal; char *zdialcodes; if (*pqglobal == NULL) { iret = _uuconf_iinit_global (pqglobal); if (iret != UUCONF_SUCCESS) return iret; } qglobal = *pqglobal; iret = ivinlib (qglobal, V2_SYSTEMS, sizeof V2_SYSTEMS, &qglobal->qprocess->zv2systems); if (iret != UUCONF_SUCCESS) return iret; iret = ivinlib (qglobal, V2_DEVICES, sizeof V2_DEVICES, &qglobal->qprocess->zv2devices); if (iret != UUCONF_SUCCESS) return iret; iret = ivinlib (qglobal, V2_USERFILE, sizeof V2_USERFILE, &qglobal->qprocess->zv2userfile); if (iret != UUCONF_SUCCESS) return iret; iret = ivinlib (qglobal, V2_CMDS, sizeof V2_CMDS, &qglobal->qprocess->zv2cmds); if (iret != UUCONF_SUCCESS) return iret; iret = ivinlib (qglobal, V2_DIALCODES, sizeof V2_DIALCODES, &zdialcodes); if (iret != UUCONF_SUCCESS) return iret; return _uuconf_iadd_string (qglobal, zdialcodes, FALSE, FALSE, &qglobal->qprocess->pzdialcodefiles, qglobal->pblock); } 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 = (chuucp-1.04/uuconf/vport.c1004440004150000170000001474005337263632012210 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include #include /* Find a port in the V2 configuration files by name, baud rate, and special purpose function. */ int uuconf_v2_find_port (pglobal, zname, ibaud, ihighbaud, pifn, pinfo, qport) pointer pglobal; const char *zname; long ibaud; long ihighbaud; int (*pifn) P((struct uuconf_port *, pointer)); pointer pinfo; struct uuconf_port *qport; { struct sglobal *qglobal = (struct sglobal *) pglobal; FILE *e; char *zline; size_t cline; char **pzsplit; size_t csplit; int iret; int cchars; e = fopen (qglobal->qprocess->zv2devices, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) return UUCONF_NOT_FOUND; qglobal->ierrno = errno; qglobal->zfilename = qglobal->qprocess->zv2devices; return (UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_FILENAME); } zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; iret = UUCONF_NOT_FOUND; qglobal->ilineno = 0; while ((cchars = getline (&zline, &cline, e)) > 0) { int ctoks; char *zend; long ilow, ihigh; pointer pblock; ++qglobal->ilineno; iret = UUCONF_NOT_FOUND; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; zline[strcspn (zline, "#")] = '\0'; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } /* An entry in L-devices is type device dial-device baud dialer The type (normally "ACU") is treated as the name. */ /* If there aren't enough entries, ignore the line; this should probably do something more useful. */ if (ctoks < 4) continue; /* Make sure the name matches any argument. */ if (zname != NULL && strcmp (pzsplit[0], zname) != 0) continue; /* Get the baud rate. */ ilow = strtol (pzsplit[3], &zend, 10); if (*zend == '-') ihigh = strtol (zend + 1, (char **) NULL, 10); else ihigh = ilow; /* Make sure the baud rate matches any argument. */ if (ibaud != 0 && ilow != 0 && (ilow > ibaud || ihigh < ibaud)) continue; /* Now we must construct the port information, so that we can pass it to pifn. The port type is determined by it's name, unfortunately. The name "DIR" is used for a direct port, and anything else for a modem port. */ pblock = NULL; _uuconf_uclear_port (qport); qport->uuconf_zname = pzsplit[0]; if (strcmp (pzsplit[0], "DIR") == 0) { qport->uuconf_ttype = UUCONF_PORTTYPE_DIRECT; qport->uuconf_u.uuconf_sdirect.uuconf_zdevice = pzsplit[1]; qport->uuconf_u.uuconf_sdirect.uuconf_ibaud = ilow; } else { qport->uuconf_ttype = UUCONF_PORTTYPE_MODEM; qport->uuconf_u.uuconf_smodem.uuconf_zdevice = pzsplit[1]; if (strcmp (pzsplit[2], "-") != 0) qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = pzsplit[2]; else qport->uuconf_u.uuconf_smodem.uuconf_zdial_device = NULL; if (ilow == ihigh) { qport->uuconf_u.uuconf_smodem.uuconf_ibaud = ilow; qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = 0L; } else { qport->uuconf_u.uuconf_smodem.uuconf_ibaud = 0L; qport->uuconf_u.uuconf_smodem.uuconf_ilowbaud = ilow; qport->uuconf_u.uuconf_smodem.uuconf_ihighbaud = ihigh; } qport->uuconf_u.uuconf_smodem.uuconf_fcarrier = TRUE; if (ctoks < 5) qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = NULL; else { size_t c; char **pzd; /* We support dialer/token pairs, although normal V2 doesn't. */ pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } c = (ctoks - 4) * sizeof (char *); pzd = (char **) uuconf_malloc (pblock, c + sizeof (char *)); if (pzd == NULL) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) pzd, (pointer) (pzsplit + 4), c); pzd[ctoks - 4] = NULL; qport->uuconf_u.uuconf_smodem.uuconf_pzdialer = pzd; } qport->uuconf_u.uuconf_smodem.uuconf_qdialer = NULL; } if (pifn != NULL) { iret = (*pifn) (qport, pinfo); if (iret != UUCONF_SUCCESS) { if (pblock != NULL) uuconf_free_block (pblock); if (iret != UUCONF_NOT_FOUND) break; continue; } } /* This is the port we want. */ if (pblock == NULL) { pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } } if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; uuconf_free_block (pblock); iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; qport->uuconf_palloc = pblock; break; } (void) fclose (e); if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); if (iret != UUCONF_SUCCESS && iret != UUCONF_NOT_FOUND) { qglobal->zfilename = qglobal->qprocess->zv2devices; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } return iret; } seful, but WITHOUT ANY WARRANuucp-1.04/uuconf/vsinfo.c1004440004150000170000003436305337263632012345 037777777777 1 0 /* 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.4 1992/07/25 20:44:25 ian Rel $"; #endif #include #include /* Get the information for a particular system from the V2 configuration files. This does not make sure that all the default values are set. */ int _uuconf_iv2_system_internal (qglobal, zsystem, qsys) struct sglobal *qglobal; const char *zsystem; struct uuconf_system *qsys; { char *zline; size_t cline; char **pzsplit; size_t csplit; char **pzcomma; size_t ccomma; FILE *e; int cchars; pointer pblock; int iret; e = fopen (qglobal->qprocess->zv2systems, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) return UUCONF_NOT_FOUND; qglobal->ierrno = errno; qglobal->zfilename = qglobal->qprocess->zv2systems; return (UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_FILENAME); } zline = NULL; cline = 0; pzsplit = NULL; csplit = 0; pzcomma = NULL; ccomma = 0; pblock = NULL; iret = UUCONF_SUCCESS; qglobal->ilineno = 0; while ((cchars = getline (&zline, &cline, e)) > 0) { int ctoks, ctimes, i; struct uuconf_system *qset; char *z, *zretry; int cretry; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; zline[strcspn (zline, "#")] = '\0'; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } /* If this isn't the system we're looking for, keep reading the file. */ if (ctoks < 1 || strcmp (zsystem, pzsplit[0]) != 0) continue; /* If this is the first time we've found the system, we want to set *qsys directly. Otherwise, we allocate a new alternate. */ if (pblock == NULL) { pblock = uuconf_malloc_block (); if (pblock == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_system (qsys); qsys->uuconf_palloc = pblock; qset = qsys; } else { struct uuconf_system **pq; qset = ((struct uuconf_system *) uuconf_malloc (pblock, sizeof (struct uuconf_system))); if (qset == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_system (qset); for (pq = &qsys->uuconf_qalternate; *pq != NULL; pq = &(*pq)->uuconf_qalternate) ; *pq = qset; } /* Add this line to the memory block we are building for the system. */ if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; cline = 0; /* The format of a line in Systems is system time device speed phone chat For example, airs Any ACU 9600 5551212 ogin: foo pass: bar */ /* Get the system name. */ qset->uuconf_zname = pzsplit[0]; qset->uuconf_fcall = TRUE; qset->uuconf_fcalled = TRUE; if (ctoks < 2) continue; /* A time string is "time/grade,time/grade;retry". A missing grade is taken as BGRADE_LOW. On some versions the retry time is actually separated by a comma, which won't work right here. */ zretry = strchr (pzsplit[1], ';'); if (zretry == NULL) cretry = 0; else { *zretry = '\0'; cretry = (int) strtol (zretry + 1, (char **) NULL, 10); } ctimes = _uuconf_istrsplit (pzsplit[1], ',', &pzcomma, &ccomma); if (ctimes < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } for (i = 0; i < ctimes; i++) { char *zslash; char bgrade; z = pzcomma[i]; zslash = strchr (z, '/'); if (zslash == NULL) bgrade = UUCONF_GRADE_LOW; else { *zslash = '\0'; bgrade = zslash[1]; if (! UUCONF_GRADE_LEGAL (bgrade)) bgrade = UUCONF_GRADE_LOW; } iret = _uuconf_itime_parse (qglobal, z, (long) bgrade, cretry, _uuconf_itime_grade_cmp, &qset->uuconf_qtimegrade, pblock); if (iret != UUCONF_SUCCESS) break; } if (iret != UUCONF_SUCCESS) break; if (ctoks < 3) continue; /* Pick up the device name. It can be followed by a comma and a list of protocols (this is not actually supported by most V2 systems, but it should be compatible). */ qset->uuconf_zport = pzsplit[2]; z = strchr (pzsplit[2], ','); if (z != NULL) { qset->uuconf_zprotocols = z + 1; *z = '\0'; } /* If the port is "TCP", we set up a system specific port. The baud rate becomes the service number and the phone number becomes the address (still stored in qsys->zphone). */ if (strcmp (qset->uuconf_zport, "TCP") == 0) { qset->uuconf_zport = NULL; qset->uuconf_qport = ((struct uuconf_port *) uuconf_malloc (pblock, sizeof (struct uuconf_port))); if (qset->uuconf_qport == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } _uuconf_uclear_port (qset->uuconf_qport); qset->uuconf_qport->uuconf_zname = (char *) "TCP"; qset->uuconf_qport->uuconf_ttype = UUCONF_PORTTYPE_TCP; qset->uuconf_qport->uuconf_ireliable = (UUCONF_RELIABLE_ENDTOEND | UUCONF_RELIABLE_RELIABLE | UUCONF_RELIABLE_EIGHT | UUCONF_RELIABLE_FULLDUPLEX | UUCONF_RELIABLE_SPECIFIED); if (ctoks < 4) qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport = (char *) "uucp"; else qset->uuconf_qport->uuconf_u.uuconf_stcp.uuconf_zport = pzsplit[3]; } if (ctoks < 4) continue; qset->uuconf_ibaud = strtol (pzsplit[3], (char **) NULL, 10); if (ctoks < 5) continue; /* Get the phone number. */ qset->uuconf_zphone = pzsplit[4]; if (ctoks < 6) continue; /* Get the chat script. We just hand this off to the chat script processor, so that it will parse subsend and subexpect strings correctly. */ pzsplit[4] = (char *) "chat"; iret = _uuconf_ichat_cmd (qglobal, ctoks - 4, pzsplit + 4, &qset->uuconf_schat, pblock); iret &=~ UUCONF_CMDTABRET_KEEP; if (iret != UUCONF_SUCCESS) break; } (void) fclose (e); if (pzcomma != NULL) free ((pointer) pzcomma); if (iret != UUCONF_SUCCESS) { if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); qglobal->zfilename = qglobal->qprocess->zv2systems; return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } if (pblock == NULL) { if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); return UUCONF_NOT_FOUND; } /* Now read USERFILE and L.cmds to get permissions. We can't fully handle USERFILE since that specifies permissions based on local users which we do not support. */ { e = fopen (qglobal->qprocess->zv2userfile, "r"); if (e != NULL) { char **pzlocal, **pzremote; boolean fdefault_callback; char *zdefault_login; struct uuconf_system *q; pzlocal = NULL; pzremote = NULL; fdefault_callback = FALSE; zdefault_login = NULL; qglobal->ilineno = 0; while ((cchars = getline (&zline, &cline, e)) > 0) { int ctoks; char *zcomma; boolean fcallback; char **pzlist, **pznew; ++qglobal->ilineno; --cchars; if (zline[cchars] == '\n') zline[cchars] = '\0'; zline[strcspn (zline, "#")] = '\0'; ctoks = _uuconf_istrsplit (zline, '\0', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } if (ctoks == 0) continue; /* The first field is username,machinename */ zcomma = strchr (pzsplit[0], ','); if (zcomma == NULL) continue; *zcomma++ = '\0'; /* The rest of the line is the list of directories, except that if the first directory is "c" we must call the system back. */ fcallback = FALSE; pzlist = pzsplit + 1; --ctoks; if (ctoks > 0 && pzsplit[1][0] == 'c' && pzsplit[1][1] == '\0') { fcallback = TRUE; pzlist = pzsplit + 2; --ctoks; } /* Now pzsplit[0] is the user name, zcomma is the system name, fcallback indicates whether a call back is required, ctoks is the number of directories and pzlist points to the directories. If the system name matches, then the user name is the name that the system must use to log in, and the list of directories is what may be transferred in by either local or remote request. Otherwise, if no system name matches, then the first line with no user name gives the list of directories that may be transferred by local request, and the first line with no system name gives the list of directories that may be transferred by remote request. */ if ((pzsplit[0][0] != '\0' || pzlocal != NULL) && (zcomma[0] != '\0' || pzremote != NULL) && strcmp (zcomma, zsystem) != 0) continue; /* NULL terminate the list of directories. */ pznew = (char **) uuconf_malloc (pblock, (ctoks + 1) * sizeof (char *)); if (pznew == NULL) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } memcpy ((pointer) pznew, (pointer) pzlist, ctoks * sizeof (char *)); pznew[ctoks] = NULL; if (uuconf_add_block (pblock, zline) != 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; break; } zline = NULL; cline = 0; if (pzsplit[0][0] == '\0') { pzlocal = pznew; fdefault_callback = fcallback; } else if (zcomma[0] == '\0') { pzremote = pznew; zdefault_login = pzsplit[0]; } else { /* Both the login name and the machine name were listed; require the machine to be logged in under this name. This is not fully backward compatible, and perhaps should be changed. On the other hand, it is more useful. */ for (q = qsys; q != NULL; q = q->uuconf_qalternate) { q->uuconf_zcalled_login = pzsplit[0]; q->uuconf_fcallback = fcallback; q->uuconf_pzlocal_send = pznew; q->uuconf_pzlocal_receive = pznew; q->uuconf_pzremote_send = pznew; q->uuconf_pzremote_receive = pznew; } break; } } (void) fclose (e); if (iret != UUCONF_SUCCESS) { if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); qglobal->zfilename = qglobal->qprocess->zv2userfile; return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } if (qsys->uuconf_pzlocal_send == (char **) &_uuconf_unset && pzlocal != NULL) { for (q = qsys; q != NULL; q = q->uuconf_qalternate) { q->uuconf_fcallback = fdefault_callback; q->uuconf_pzlocal_send = pzlocal; q->uuconf_pzlocal_receive = pzlocal; } } if (qsys->uuconf_pzremote_send == (char **) &_uuconf_unset && pzremote != NULL) { for (q = qsys; q != NULL; q = q->uuconf_qalternate) { q->uuconf_zcalled_login = zdefault_login; q->uuconf_pzremote_send = pzremote; q->uuconf_pzremote_receive = pzremote; } } } } /* Now we must read L.cmds to determine which commands may be executed. */ { e = fopen (qglobal->qprocess->zv2cmds, "r"); if (e != NULL) { qglobal->ilineno = 0; if (getline (&zline, &cline, e) > 0) { ++qglobal->ilineno; zline[strcspn (zline, "#\n")] = '\0'; if (strncmp (zline, "PATH=", sizeof "PATH=" - 1) == 0) { int ctoks; char **pznew; zline += sizeof "PATH=" - 1; ctoks = _uuconf_istrsplit (zline, ':', &pzsplit, &csplit); if (ctoks < 0) { qglobal->ierrno = errno; iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } pznew = NULL; if (iret == UUCONF_SUCCESS) { pznew = ((char **) uuconf_malloc (pblock, (ctoks + 1) * sizeof (char *))); if (pznew == NULL) iret = UUCONF_MALLOC_FAILED | UUCONF_ERROR_ERRNO; } if (iret == UUCONF_SUCCESS) { memcpy ((pointer) pznew, (pointer) pzsplit, ctoks * sizeof (char *)); pznew[ctoks] = NULL; qsys->uuconf_pzpath = pznew; zline = NULL; cline = 0; } if (getline (&zline, &cline, e) < 0) { if (zline != NULL) { free ((pointer) zline); zline = NULL; } } else ++qglobal->ilineno; } } if (iret == UUCONF_SUCCESS && zline != NULL) { while (TRUE) { zline[strcspn (zline, "#\n")] = '\0'; iret = _uuconf_iadd_string (qglobal, zline, TRUE, FALSE, &qsys->uuconf_pzcmds, pblock); if (iret != UUCONF_SUCCESS) break; if (getline (&zline, &cline, e) < 0) break; ++qglobal->ilineno; } } (void) fclose (e); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = qglobal->qprocess->zv2cmds; iret |= UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } } } if (zline != NULL) free ((pointer) zline); if (pzsplit != NULL) free ((pointer) pzsplit); return iret; } 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,uucp-1.04/uuconf/vsnams.c1004440004150000170000000565105337263633012347 037777777777 1 0 /* 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.3 1992/07/25 20:44:25 ian Rel $"; #endif #include /* Get all the system names from the V2 L.sys file. This code does not support aliases, although some V2 versions do have an L-aliases file. */ /*ARGSUSED*/ int uuconf_v2_system_names (pglobal, ppzsystems, falias) pointer pglobal; char ***ppzsystems; int falias; { struct sglobal *qglobal = (struct sglobal *) pglobal; FILE *e; int iret; char *zline; size_t cline; *ppzsystems = NULL; e = fopen (qglobal->qprocess->zv2systems, "r"); if (e == NULL) { if (FNO_SUCH_FILE ()) return _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppzsystems, (pointer) NULL); qglobal->ierrno = errno; qglobal->zfilename = qglobal->qprocess->zv2systems; return (UUCONF_FOPEN_FAILED | UUCONF_ERROR_ERRNO | UUCONF_ERROR_FILENAME); } qglobal->ilineno = 0; iret = UUCONF_SUCCESS; zline = NULL; cline = 0; while (getline (&zline, &cline, e) > 0) { char *zname; ++qglobal->ilineno; /* Skip leading whitespace to get to the system name. Then cut the system name off at the first whitespace, comment, or newline. */ zname = zline + strspn (zline, " \t"); zname[strcspn (zname, " \t#\n")] = '\0'; if (*zname == '\0') continue; iret = _uuconf_iadd_string (qglobal, zname, TRUE, TRUE, ppzsystems, (pointer) NULL); if (iret != UUCONF_SUCCESS) break; } (void) fclose (e); if (zline != NULL) free ((pointer) zline); if (iret != UUCONF_SUCCESS) { qglobal->zfilename = qglobal->qprocess->zv2systems; return iret | UUCONF_ERROR_FILENAME | UUCONF_ERROR_LINENO; } if (*ppzsystems == NULL) iret = _uuconf_iadd_string (qglobal, (char *) NULL, FALSE, FALSE, ppzsystems, (pointer) NULL); return iret; } ons based on local users which we do not support. */ { e = fopen (qglobal->uucp-1.04/uuconf/vsys.c1004440004150000170000000325205337263633012037 037777777777 1 0 /* 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.2 1992/06/15 18:40:43 ian Rel $"; #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); } inate 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 *)); pznlocal; 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)