mgetty-1.1.36/README.1st0100644000031200001470000000730110215076526013000 0ustar gertfaxHi, this is the mgetty+sendfax distribution. It contains programs to send and receive faxes in a unix environment using a class 2 faxmodem. For detailed informations how everything works and how to build and use it, see the file "mgetty.texi" (in doc/, see below) If you can access the WWW, you might try looking at http://alpha.greenie.net/mgetty/index.html, or http://www.leo.org/~doering/mgetty/index.html. You'll find all the documentation and the FAQ nicely formatted there. For voice stuff, look into voice/doc/readme.Beginners. Brief installation instructions can be found below. My license policy boils down to this: -------------------------------------------------------------------------- Mgetty+Sendfax was written by Gert Doering, with many contributions from the Internet. Vgetty was written by Klaus Weidner, Marc Eberhard, Marc Schaefer and also many contributions from the Internet community. The whole package, starting with version 1.1.22, is distributed under the GNU GPL license, found in the accompanying file 'COPYING'. If you want to redistribute mgetty under a different license (like in "selling it to your customers"), contact me, and we will work something out. -------------------------------------------------------------------------- To make the programs, copy "policy.h-dist" to "policy.h", edit it according to your needs. The defaults are reasonable, though. Then edit "Makefile" to set CC=, CCFLAGS=, INSTALL= and the various xxxDIR= (LIB/MAN/BIN/SBINDIR/CONFDIR) to fit your system. After that, running "make" should do. "Make" will also create the "mgetty.texi"-File in "doc/" if you have the "texinfo" package installed. If the user name that you have specified as FAX_OUT_USER=... in the Makefile ("fax" or similar) does not exist in your system, you have to create it now. Don't forget to set a good password. If you want to run faxrun or faxrunqd under this user ID (which is recommended), it must have access to your modem devices (/dev/tty...). Most of the options set in "policy.h" can be changed at run-time from the "mgetty.config" configuration file. CONFDIR= (in Makefile) plus the file name specified in policy.h controls where that will be. With C-Compilers that do not understand the "#ident" directive, give the "make noident" command before using the "make" command for the first time. Run "make testdisk" to see if the disk statistics grabber works (it should report the correct block free count for the partitions containing "/" and ".". If not, consult getdisk.c, taking special note of the "v*" defines for hints as to which settings you use. If your system is one of the "v*", try defining that "v*" macro in the Makefile CCFLAGS. Please let us know what works, and what your C compiler uses to identify your computer. Run "make test" to run some test scripts - this will mainly check the G3 tools and some shell functions. It can't test "all" of the package yet. Finally, "make install". If you have any problems, suggestions or bug reports, please contact gert@greenie.muc.de or gert@space.net (greenie preferred!) - but make sure you have read the documentation first! I get quite annoyed when I have to answer the same questions for the 99th time! Read "BUGS"! Generic questions ("it doesn't work") should go to the mgetty mailing list (mgetty@muc.de), because I just don't have time to explain it all again and again. (Un-)Subscription is done via mgetty-request@muc.de. And... please do not forget that I'm doing this kind of support entirely in my spare time - sometimes my answers will be very short, or it may take a long time for me to answer - since sometimes I need my time to make a living... Now... have fun & fax! gert mgetty-1.1.36/THANKS0100644000031200000620000000272306426156651012711 0ustar gertgroupMany thanks to: Peter Bechtold, peter@fns.greenie.muc.de, for sending me dozens of faxes to test mgetty, for calling me back numerous times after failed attempts to send him a fax with sendfax, ... Klaus Weidner, klaus@greenie.muc.de, for the original linux port, and for testing dozens of pre-releases Lawrence 'dreamer' Chen, lawrence@combdyn.com, for the initial ISC port, and for testing the package with a SupraFAX-Modem. Kay, kschulz@gold.t-informatik.ba-stuttgart.de, for testing on ISC - and telling me that it's possible to ask dozens of questions without having ever read the README file... Georg Edelmann, georg@alpha.saar.de, for testing on Linux, and finding some stupid bugs Uwe S. Obst, sysop@ganymed.phiger.com, for testing on SCO 3.2.4 and finding the only working way to set the hardware flow control flags (Other combinations seem to always prevent parallel dial-outs) Bodo Bauer, bodo@hal.nbg.sub.org, for porting mgetty to SVR4 (though he did quite confuse me by insisting that the fax receiver does not work...) Christoph Adomeit, for bugging me long enough to implement XON / XOFF flow control in fax sending / receiving, and buffered reads in fax receiving; and for borrowing me one of his GVC modems long enough to make faxing work with it. Christopher M. Ward, for testing on SCO with another GVC modem. ... and to all others who tested release after release. (The list here is incomplete, a more complete list can be found in mgetty.texi) mgetty-1.1.36/TODO0100644000031200001470000004116010531065176012103 0ustar gertfax1) make sendfax recognize "-h " option to set page headers started 20.3.93, GD new idea: send "AT+FDT", then (optional) page header, then page data. (does not work) new idea: customized pbmtog3, without EOP. "first cut" done, 21.9.93, use "g3cat" Suggestion: use "-h ", g3cat output of that program with the data page (-> headers with real send time) see 119 2) make external configuration possible mostly done (1.1.95) 3) #include bad idea, not really useful 6) faxmail - gatway program for mail -> fax (started) 7) when (before) receiving a fax, check if there's enough space left (amount configurably) -> clewis generic "get spool file name", check multiple directories (multiple dirs done, code is ugly, clean up) 8) function for creating spool file names (->dir, prefix; <- name, fd) with (optional) sequence numbers 14) make mgetty (and g3cat) add an digifax header to incoming faxes (optionally). 16) tiffg3 -> raw g3 / digifax converter 17) library functions for opening / reading g3 files 18) Makefile. / AutoConf? 20) tio - increase abstraction layer even more, make TIO an opaque pointer, so that the upper layers do not have to know *anything* about the data structure used by tio.c/.h (with old/new settings, to avoid surplus system calls) 21) additional flag: skip modem initialization and all, go directly to reading of login name (for callback) (would also help Hylafax) 24) fax_notify_mail: include "realname" (from fax phone book) in Subject: 31) VSI*FAX 34) ungetty mechanism 35) utmp writing / process arguments on SunOS 45) make fax poll server more flexible 51) faxspool.c (sgid fax) -> $LIBDIR/faxspool.sh -> on TODO since at least June 1994 -> 18.11.2002: *done* via "faxq-helper" 51a) have it start faxrunq immediately (configurably) 55) vhangup()? (->Linux) (security issues) 57) SIGUSR1 *after* answering -> hangup 59) mgetty/faxrec(): valiate incoming fax data, request retransmission partially done, if +FP(T)S:... returns valid values. 60) faxspool - multiple targets in one fax call: faxspool tgt file(s) faxspool -m tgt1 tgt2 tgt3 -- file(s) faxspool -M tgt-file file(s) 62) session parameter mismatch (width / length / resolution) -> correct "on-the-fly" (integrate "smart" g3cat into sendfax.c). If the page is too long, cut after 2050 (letter) or 2156 (A4) lines. 63) ZyXEL callback (description, "hack" in mgetty.c - ZYXEL_CALLBACK) (integrate in state machine) 63b) real callback 66) faxcleanup 73) locks.c: only "guess" that it's a binary lock if it doesn't consist entirely of " 0-9\n". 75) dialcode translations in faxspool 90) support ct 91) g3split 96) number of RINGs changeable without /etc/inittab change (done). Changeable without restart? 97) BREAK -> mgetty exits (does it?) 98) fax_wait_for: accept " +FHNG:..." 107) create own fax file header, with sender ID (if known), resolution, and *magic byte*! 108) faxreq (re-queue, remove Status junk from JOB) done with "faxq -r" - really delete "Status" lines? 112) sendfax: return +FHNG in exit() code 114) callback: other lines (if available), random delay 116) use more detailed access privileges in faxspool (long distance, local) 118) modem auto-detect not only for voice but for modem type (e.g. MultiTech, ZyXEL, ...) in general 12.12.97: basic work done 119) dynamically generate page headers in faxrunq 12.12.97: integrate with class 1 work - we have to "g3cat" the page data anyway (for padding) 120) with 119, multicasting is easy 121) check disk space before spooling faxes 123) -DNO_MODEM? 124) if write/read in fax_send_page() fails, exit loop (kkeyte) 125) cleanup script that will rollover logs 126) if sendfax is killed, faxrunq assumes "ok" for some strange reason. (caused by the way exec() / wait() handle return code / signals) 10.12.97: resolved for faxrunqd. Still open for faxrunq??? 127) step-by-step installation guide 128) g3topbm: use same decoder as g3view (speed/space tradeoff?) 129) g3topbm: speed up decoding by reading the file as a whole 135) for modems where AT+FAA=1 doesn't work: use SIGUSR2 to toggle fax/data (for people knowing what type of call comes in) 136) keep modem in data mode, switch to fax mode (+FAA=1 or 0, depending on -D/-F) if desired before sending ATA. Reason: dialout processes can safely assume "+FCLASS=0" with this setup. 136a) add signal to switch reception mode for dumb no-adaptive-answering modems, see 135) 137) call "new_fax" program for each page during reception (for those people that have a fast machine and a slow printer and want to see the results immediately. Hi Harald!) 139) RING during initialization -> wait for it to stop, init modem again 141) make lock/log/spool paths configurable 144) if first line in logfile is written *after* setuid() in login.c, no opening of LOG_PATH is possible. open log sooner? mode 666? 145) include Device/Hostname in "notify mail" [Device done. Do we really want the hostname?] 79) g3cat: fix line width (that is, "repair" broken T.4 files on-the-fly) 147) make "g3cat" fix line width! (done, but doesn't seem to work for all receivers) 151) SCHED option? 152) get bit order for class 2 / class 2 ok / 2.0 for receiving and polling right 153) testing: add some signal that will cause a fax reception to "fail" (RTN) 154) add some way to change runtime configuration 155) fax receiver: ignore signals (USR1, USR2) more completely, only barf about "interrupted system call" if SIGARLM 156) if login name contains spaces, split into several arguments (*optionally*). Use : "login username ENV1=foo ENV2=bar". 157) add a "what to try if modem init fails" routine (try 19200 bps, try sending to get modem back from voice mode, ...) (Julian Assange, proff@suburbia.net; ard@cstmel.hobby.nl) 09.07.96: done, +++ATH moved to that part as well. Baud rate switching still open. 160) make "dialin.config" path configurable (and all other paths except "login.config" as well). [not sure whether I want this] 161) make path to "mgetty.config" configurable via command line switch 163) SIGUSR2: harden all "byte-receive" functions against EINTR 168) accept error messages while sending a page 169) "faxspool -t" must be smarter: "send at 2:00 tonight" isn't possible now 170) make "waiting for lock file to disappear" smarter: wait for *PID* to disappear *or* mtime change [->no need to read() the file every time if mtime didn't change and PID still exists] (-f =remco) 171) callback: password! 174) on Dr.Neuhaus: stay in +fclass=2 mode, don't go to +fclass=0 same for the Hayes Optima (+FAA=1 doesn't work in +fclass=0 mode) 175) man page documentation for "login.config" 177) AIX, native SCO: DTR toggle needs re-open() on device 178) Linux: #ifdef PARANOID -> lock HUPCL (and CLOCAL?) flag in termios and do vhangup() stuff 180) switch from policy.h-dist to policy.h with "reasonable defaults" 240) do away with policy.h, make everything run-time configurable 184) make sendfax choose fax device in a "random" fashion (avoid problems when the first modem in a "hunt group" dies (NO DIALTONE)) (if faxrunqd is used, it will take care of this) 186) make "distinguished ring" run-time-option: dist-ring "RING 1" fax dist-ring "RING B" fax/data dist-ring "RING 3" voice (dynamically growing list, appended to "action" list) 187) clean up tio handling / gettydefs stuff in mgetty.c 188) init / DCD drop / I/O error: can we catch it with CLOCAL? 189) sendfax: log "hint" if "ignore-carrier" is not set but "should be" 191) watchit.pl: make "remail" smarter 193) makelock: check for existance of lock file *directory*, complain (loudly, L_FATAL!) if it doesn't exist. 194) faxspool: add switch to suppress e-mail 195) make "logging *only* to syslog" conditional compile 197) +FAP (Sub-Adressing frames) support? 199) selectively reject fax reception (on sender ID)? http://www.vix.com/hylafax/setup-advanced.html#QualifyTSI 200) build kind of "libiberty" with auxiliary functions [split up goodies.c] 201) make "open() on TCP/IP" socket possible in sendfax (for things like portmasters, that have special IP ports to access their modem cards) 203) fix ATD/ERROR problem with USR vs. ERROR response in fax_send_ppm 205) vgetty on AIX: make sure VTIME is not set != 0 while waiting with select() or poll() -- drivers are dumb and use VTIME for timeout, not the value passed to select()... *sigh* 206) if "Dr.Neuhaus SMARTY" is detected, set some flag to prevent switching back to +fclass=0 ("modem_quirks |= NEED_2"?) 207) if "Telejet SaferFAX" set "cls2ok" ("modem_quirks |= PROPER_BOR"); 209) faxrm - fix "call with no arguments" 210) fix cnd.c / mgetty.c: clearing of CallerID if call was rejected (Frank Piwarski, fpiwarsk@MyMy.com) 211) fix CLOCAL handling in mgetty (->Ted T'so) 212) faxrm: generic "removeit" subroutine, not multiple "rmdir $jobid" 213) add support for Mark Himsley (mark@mdsh.com)'s weird 2400/fax modem, requiring multiple baud rate switches 215) implement e-mail to fax gateway using fax addressing as in IETF draft "draft-ietf-fax-addressing-02.txt" (or similar) 218) check whether "ATI1" always returns version number info on the *first* line on ZyXEL 2864I models, instead of "checksum first" (like all other models) --> faxlib.c, "case 28642:" 222) fix "g3cat"'s line width correction algorithm - include black dot. 224) faxspool: permit "*" as part of the phone number --> faxrunq(d): make sure that "*" in $phone is never expanded as wildcard! 225) use a non-root user-id (nobody?) for "cnd-program" 226) call cnd-program after "min-rings" RINGs, and before waiting for the remaining number of RINGs. (Also, that way vgetty can control the number of RINGs depending on the distinctive RING number / ISDN MSN) 226a) have the cnd-program decide whether to "answer NOW", or "ask me again later". 227) mgetty: add config option to call external program in the case of "L_AUDIT / failed" exit's? Might be helpful for an external management system... (Robert Canary) 227a) external scoreboard (shared memory, etc) too keep track of things? 228) find a way to limit the number of "faxrunq"'s that can run in parallel (on systems with a very large fax queue, it might happen that faxrunq is ran often enough to overflow file/process tables, causing everything to break) - Graham Leggett WORKAROUND: use faxrunqd if you have many modems and high fax througput. 229) weird idea: use NSFs to communicate version number "proceeding", mgetty's own NSF vendor code assigned 2006/06/07 230) add "frontends" section to the documentation (mgetty.texi) 231) pass dist_ring and called_id as env variables to login/new_fax 232) have cndfind() signal back to ring.c if the string found was a "caller ID" (for speedups, Caller ID is counted as "RING", to avoid waiting for the next real RING which might delay answering by a number of seconds) 233) have different login: prompts for callback/non-callback logins 234) make new_fax path configurable 235) build "faxspool-d" daemon that listens to network requests, plus "r-faxspool" client. 236) make Windows client use faxspool-d, not lpd 237) use r-faxspool/faxspool-d locally as well, to avoid world-writeable /var/spool/fax directory 238) show vgetty version in "vgetty -V", not only mgetty version 239) make utmp entry (CallerId/Connect) configurable from mgetty.config 241) cnd-program rework (more return codes, call after first RING) 242) document callback and login.conf v2 243) fix page lengths while sending (integrate in "send G3 file with byte padding" that's necessary for class 1 anyway) 244) faxrunqd / write combining: if some pages of a "combined" job (everything but the first) have already been renamed to f.g3.done, sendfax will refuse cooperation ("command line error"). BUG. 245) open anon CVS for mgetty 248) include script to rotate/move log files on a regular basis (base on contrib/mvlog, move to tools/, run through sedscript for location and naming for the log files) 250) move prototype for time() to mgetty.h, remove everywhere else 252) implement backend code for mgetty/sendfax.config "*-flow" directives 253) rewrite modem ID code (base on ATI9, fall back to ATI if ATI9 doesn't work) 254) in vgetty, "voice_log_level" overrides "-x" - cli args should have precedence! Tricky problem (voice/libutil/config.c). 255) if faxrunq(d) can't read config file due to permission problems, don't ignore error but print some informative message 256) add easy way to create/remove $FAX_SPOOL_OUT/stop (fax-helper?) done: faxq stop / faxq start 257) generalize calling $(MAKE) in subdirs - put all $(MAKE) arguments in one common variable 261) faxrunqd: don't count "modem locked" as "failure" for a given job (but *do* delay by a certain time) (hmmm - maybe not. If all modems are locked for a long period of time, it might be useful to flag the fax as "failed" to get people to notice. Combine with 259 - should resolve problem) 262) faxrunqd: smarter algorithm for "modem is broken" (locked = doesn't count, can't init = +1, NO CARRIER = +0.2) 263) faxspool.rules: add sample mappings for PDF (via acroread, xpdf, recent ghostscript versions) 264) faxrunqd: timeout on "hanging" sendfax processes (timeout > 15 min + 5 minutes * number of pages, or something like that) 265) faxrunqd: write tty to acct.log (format change / WEB gui) 260) faxrunqd: bump up priority of "exit 12" jobs 266) faxunrqd: if a job fails half-way through (12), increase priority to re-send missing parts quickly 267) faxrunqd: sort per-modem statistics numerically (watchout: "total") 268) faxrunq+faxrunqd: have configurable counters for "send-a-warning after tries, fail after " have separate counter for "modem-locked" costing-failures tries-except-modem-locked total-tries warning - 10 10 failure 5 30 100 269) faxrunqd: have configurable threshold for "everything is broken" -> if that threshold is reached, generate STOP file, warning e-mail, and suspend itself (like "the local in-house PABX is broken") 270) Makefile: have all paths depend on $(root)/ (->Debian) use $(root)/ for "make bindist" 271) rethink whole concept of "blocking yes" - when is this supposed to be used ("getty" replacement) - how is it supposed to work and then fix logging in mgetty.c ("waiting..." is not appropriate) 272) have a configurable delay after each "sendfax" call in faxrunq(d) (reason: long but not timing-critical out queue, don't starve incoming calls. Wouter van Marle, wouter@squirrel-systems.com) 273) update "ZyXEL" modem section in mgetty.texi-in - it's mainly specific to the 1496s. More recent ZyXELs need mentioning. ksadil@bigpond.com reports that the U90e works well with vgetty. 274) g32sff (based on g3cat routines) 275) sff2g3: duplicate previous line on 0xff/0x00 tag 276) fix "make beta" process (no gcc on target machine anymore) [26.11.05: moved to new target machine] 276a) add freshmeat net reminder 277) mg_m_init.c/mg_get_ctty() - if setsid() fails, and getppid() != 1, mgetty might be run from the command line. Should we try fork()ing, then setsid()'ing, and then getting a new controlling tty? (Things are likely to fail anyway due to missing utmp slots...) 280a) implement BREAK and dual-tilde sending in tools/microcom.c 282) add test code for ring.c, faxlib.c, and other low-level modules (overload mdm_read_byte() -> feed various RING strings to ring.c etc) t_ring.c: test "action" strings (CONNECT, ERROR, etc.) 283) mvlog: gzip 284) test function for faxq-helper? 286) faxrunqd: add hard (long) timeout to "wait for child processes" so that faxrunqd can recover in case something seriously gets stuck 287) run "cvs tag" automatically after "make beta" 288) change all #idents to contain @(#) prefix 289) re-do all the bitmap conversion stuff in faxspool (with recent netpbm versions, pgmtopbm doesn't properly work anymore, instead you need to use pamditherbw | pamtopnm) 290) (re-)organize fax class 1 "state" - e.g. always use fax_param_d 291) implement T.37 on-ramp and off-ramp gateways 292) implement T.38 on-ramp and off-ramp gateways 293) implement -o 'myoption arguments' flags to mgetty and sendfax, get rid of all these flag letters mgetty-1.1.36/BUGS0100644000031200001470000000433107566001176012101 0ustar gertfaxHi, as you may imagine, I get about 10 - 30 mails a day, with questions, suggestions, bug reports about mgetty. Since very many of those mails are answered in the manual, or your modem's manual, please make sure that you have read all those manuals before mailing me (I can get very unfriendly if the question is clearly answered somewhere in there!). There's a very detailed section on "Problems common to many modem types" in the mgetty manual, and still those questions are asked so very frequently :-( The second type of mails that usually evoke very short and unfriendly results are bug reports "it does not work" without any informations about the used hardware, modem, what exactly went wrong, ... So, here's what I need - your modem type (if you know it, include the ROM version number) - the operating system (with version number) - operating system specials (custom serial driver, unusual serial hardware) - a mgetty log file (VERY IMPORTANT). Where the log file is stored is controlled by the LOG_PATH definition in policy.h, and please start mgetty/sendfax with a log level high enough (-x5 or more) to capture all modem commands and responses. Please trim the log file to just contain one (or few) invocations of mgetty/sendfax, I really hate it if people think they are doing me some good and mail me a logfile containing four weeks mgetty activity, totalling 5000 lines... - if you're experience problems when *sending* faxes, try to find out what (if anything) came out at the receiving end. This can be quite important for finding flow control related bugs. - if you want to send a question about some message, don't transcribe it - copy it (cut and paste) exactly as it was printed. If you have read the manual, and provide all those informations, your chances that I take enough time to closely read your mail and answer it in a friendly manner are quite high. If some/most informations are missing, I sometimes get very unfriendly... (Naturally there are some exceptions of this, e.g., if I have already exchanged a couple of mails with you, and your name does ring a bell in my head, there is no need to include all the stuff in every mail...) gert mgetty-1.1.36/FTP0100644000031200000620000000206306426156706012350 0ustar gertgroupmgetty+sendfax can usually be found at: sunsite.unc.edu:/pub/Linux/system/Serial/mgetty+sendfax* tsx-11.mit.edu:/pub/linux/sources/sbin/mgetty+sendfax ftp.leo.org:/pub/comp/networking/communication/modem/mgetty/mgetty* some other nice persons have also offered to put up mgetty+sendfax for ftp: ------------------------------ From: garyf@wiis.wang.com (Gary Field) I put your software on das.wang.com: garyf/mgetty+sendfax. I also extracted the README file and put that there too. Feel free to post an announcement on the net. Gary ------------------------------ From: I put the files up for anonymous ftp at ftp.pdc.kth.se in home/erikw/Public/sco. If you want to you can tell people to get it from there. My home directory is in AFS so it can also be reached in /afs/nada.kth.se/home/ass/erikw/Public. /Erik ------------------------------ From: Francois Vrana if you are still looking for a site to store your fax s/w i would be willing to do this. the site would be rcorco.rco.qc.ca (/pub) ------------------------------ mgetty-1.1.36/Recommend0100644000031200001470000000157506673027145013263 0ustar gertfaxMODEM Recommendations for use with mgetty/vgetty ------------------------------------------------ What modem to recommend depends on your needs. There are very few modems that handle fax + data + voice perfectly, but quite a number that are well suited for two of the categories, and less good (or sometimes not at all) for the third. For Fax+Data: * USR Courier V.34/X.2 (no voice) For FAX+Voice: * ZyXEL 1496 (data only up to 19200, but best fax implementation) For Data+Voice: * USR Sportster VI series (fax implementation is VERY bad) For FAX+DATA+Voice * ZyXEL 2864 * MultiTech MT2834ZDXv [watch out - recent firmware versions are weird, I have been told that 0316D firmware is OK, but make sure that you can return the modem if it doesn't work] * ELSA MicroLink TQV/Office series (fax is not perfect, but works ok) Last updated: March 1999 mgetty-1.1.36/inittab.aix0100644000031200000620000000463506426157007014133 0ustar gertgroup#!/bin/ksh #From: michael@hal6000.thp.uni-duisburg.de (Michael Staats) #Subject: AIX inittab installation #To: gert@greenie.muc.de (Gert Doering) #Date: Mon, 29 Nov 1993 11:10:20 +0100 #> Ummm. That would force the user to specify the ttys in the Makefile - #> doesn't sound too good. What about a small "inittab.aix" shell script that #> sets up only /etc/inittab? With a tty line as an argument? # #of course, why not? So here it is: # #====================================================================== #!/bin/ksh # mgetty installscript for AIX # (C) 1993 Michael Staats # free according to GNU Public License # # extensive Changes by Chris Lewis, clewis@ferret.ocunix.on.ca TTY=tty0 DEBUGLEV=3 while getopts pm:t:x:n: name; do case $name in m) MGETTY="$OPTARG";; n) NRINGS="-n $OPTARG";; x) DEBUGLEV="$OPTARG";; t) TTY=${OPTARG#/dev/*};; *) echo "unknown option." >&2 echo "Usage: $0 [-m full_mgetty_path] [-x debuglevel] [-t tty]" >&2 exit 1;; esac done # Try to find MGETTY if not specified if [ -z "$MGETTY" ]; then eval "$(grep '^BINDIR=' Makefile)" eval "$(grep '^SBINDIR=' Makefile)" MGETTY="$SBINDIR/mgetty" [ ! -x "$MGETTY" ] && MGETTY="$BINDIR/mgetty" [ ! -x "$MGETTY" ] && { MGETTY="$(which mgetty)" case "$MGETTY" in ./*) MGETTY=$PWD/${MGETTY#./*};; esac } [ ! -x "$MGETTY" ] && { echo "Can't find mgetty. Please specify with -m mgettypath." >&2 } fi echo echo " Ok, I'll install $MGETTY for use with $TTY." echo " I will change /etc/inittab and update the ODM so that" echo " /etc/getty will not run for this tty." echo echo -n " Is this ok (y/n)? " YN= while [ -z "$YN" ]; do read YN done if [ "$YN" = y ]; then echo "Installing." if [ -n "`lsitab $TTY`" ] then chdev -l $TTY -a ttyprog_action=off chitab "$TTY:2:off:/etc/getty -u /dev/$TTY" fi if [ -n "`lsitab m$TTY`" ] then chitab "m$TTY:2:respawn:$MGETTY -x $DEBUGLEV $NRINGS $TTY" echo "Changed m$TTY entry in /etc/inittab" else mkitab "m$TTY:2:respawn:$MGETTY -x $DEBUGLEV $NRINGS $TTY" echo "Added m$TTY entry to /etc/inittab" fi # This doesn't appear necessary on AIX, but what the hey: telinit q else echo "Try again with \"$0 [ -m full_mgetty_path ] [ -t tty ]\"" fi exit 0 ====================================================================== Enjoy, Michael -- Michael Staats, Theoretical Physics, Uni-GH Duisburg email: michael@hal6000.thp.Uni-Duisburg.DE mgetty-1.1.36/inst.sh0100755000031200000620000000421506426157040013301 0ustar gertgroup#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog -f" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 mgetty-1.1.36/version.h0100444000031200001470000000007010634472373013247 0ustar gertfaxchar * mgetty_version = "interim release 1.1.36-Jun15"; mgetty-1.1.36/Makefile0100644000031200001470000005736010634472354013070 0ustar gertfax# Makefile for the mgetty fax package # # SCCS-ID: $Id: Makefile,v 4.71 2007/06/15 11:15:56 gert Exp $ (c) Gert Doering # # this is the C compiler to use (on SunOS, the standard "cc" does not # grok my code, so please use gcc there. On ISC 4.0, use "icc".). CC=gcc #CC=cc # #### C Compiler Flags #### # # For SCO Unix 3.2v4, it may be necessary to define -D__STDC__=0 # If you have problems with dial-in / dial-out on the same line (e.g. # 'cu' telling you "CAN'T ACCESS DEVICE"), you should try -DBROKEN_SCO_324 # If the compiler barfs about my getopt() prototype, change it (mgetty.h) # If the linker cannot find "syslog()" (compiled with SYSLOG defined), # link "-lsocket". # # On SCO Unix 3.2.2, select(S) refuses to sleep less than a second, # so use poll(S) instead. Define -DUSE_POLL # # For Systems with a "login uid" (man setluid()), define -DSECUREWARE # (All SCO Systems have this). Maybe you've to link some special library # for it, on SCO it's "-lprot_s". # # # Add "-DSVR4" to compile on System V Release 4 unix # For SVR4.2, add "-DSVR4 -DSVR42" to the CFLAGS line. # # For Linux, you don't have to define anything # # For SunOS 4.x, please define -Dsunos4. # (We can't use "#ifdef sun" because that's defined on solaris as well) # If you use gcc, add -Wno-missing-prototypes, our code is OK, but # the Sun4 header files lack a lot standard definitions... # Be warned, Hardware handshake (and serial operations in general) # work a lot more reliably with patch 100513-05 (jumbo tty patch)! # # For Solaris 2.x, please define -Dsolaris2, which will automatically # #define SVR4. # # Add "-DISC" to compile on Interactive Unix. For posixized ISC 4.0 you # may have to add -D_POSIX_SOURCE # # For IBM AIX 4.x, no changes should be necessary. For AIX 3.x, it might # be necessary to add -D_ALL_SOURCE and -DUSE_POLL to the CFLAGS line. # [If you experience "strange" problems with AIX, report to me...!] # # Add "-D_3B1_ -DUSE_READ -D_NOSTDLIB_H -DSHORT_FILENAMES" to compile # on the AT&T 3b1 machine -g.t. # # Add "-DMEIBE" to compile on the Panasonic (Matsushita Electric # industry) BE workstation # # When compiling on HP/UX, make sure that the compiler defines _HPUX_SOURCE, # if it doesn't, add "-D_HPUX_SOURCE" to the CFLAGS line. # # On NeXTStep, add "-DNEXTSGTTY -DBSD". To compile vgetty or if you are # brave, you have to use "-posix -DBSD". # # On the MIPS RiscOS, add "-DMIPS -DSVR4 -systype svr4" (the other # subsystems are too broken. Watch out that *all* programs honour # the SVR4 locking convention, "standard" UUCP and CU do not!) # # For (otherwise not mentioned) systems with BSD utmp handling, define -DBSD # # Add "-D_NOSTDLIB_H" if you don't have # # Add "-DPOSIX_TERMIOS" to use POSIX termios.h, "-DSYSV_TERMIO" to use # the System 5 termio.h style. (Default set in tio.h) # # For machines without the select() call: # Add "-DUSE_POLL" if you don't have select, but do have poll # Add "-DUSE_READ" if you don't have select or poll (ugly) # # For older SVR systems (with a filename length restriction to 14 # characters), define -DSHORT_FILENAMES # # For Systems that default to non-interruptible system calls (symptom: # timeouts in do_chat() don't work reliably) but do have siginterrupt(), # define -DHAVE_SIGINTERRUPT. This is the default if BSD is defined. # # For Systems with broken termios / VMIN/VTIME mechanism (symptom: mgetty # hangs in "waiting for line to clear"), define -DBROKEN_VTIME. Notably # this hits FreeBSD 0.9 and some SVR4.2 users... # # If you don't have *both* GNU CC and GNU AS, remove "-pipe" # # Disk statistics: # # The following macros select one of 5 different variants of partition # information grabbing. AIX, Linux, 3b1 and SVR4 systems will figure # this out themselves. You can test whether you got this right by # running "make testdisk". If it fails, consult getdisk.c for # further instructions. # # BSDSTATFS - BSD/hp-ux/SunOS/Dynix/vrios # 2-parameter statfs() # ULTRIXSTATFS - Ultrix wacko statfs # SVR4 - SVR4 statvfs() # SVR3 - SVR3/88k/Apollo/SCO 4-parameter statfs() # USTAT - ustat(), no statfs etc. # #CFLAGS=-Wall -O2 -pipe -DSECUREWARE -DUSE_POLL CFLAGS=-O2 -Wall -pipe #CFLAGS=-O -DSVR4 #CFLAGS=-O -DSVR4 -DSVR42 #CFLAGS=-O -DUSE_POLL #CFLAGS=-Wall -g -O2 -pipe # 3B1: You can remove _NOSTDLIB_H and USE_READ if you have the # networking library and gcc. #CFLAGS=-D_3B1_ -D_NOSTDLIB_H -DUSE_READ -DSHORT_FILENAMES #CFLAGS=-std -DPOSIX_TERMIOS -O2 -D_BSD -DBSD # for OSF/1 (w/ /bin/cc) #CFLAGS=-DNEXTSGTTY -DBSD -O2 # for NeXT with sgtty (better!) #CFLAGS=-posix -DUSE_VARARGS -DBSD -O2 # for NeXT with POSIX #CFLAGS=-D_HPUX_SOURCE -Aa -DBSDSTATFS # for HP-UX 9.x #CFLAGS=-cckr -D__STDC__ -O -DUSE_READ # for IRIX 5.2 and up # # LDFLAGS specify flags to pass to the linker. You could specify # special link modes, binary formats, whatever... # # For the 3B1, add "-s -shlib". For other systems, nothing is needed. # # LIBS specify extra libraries to link to the programs # (do not specify the libraries in the LDFLAGS statement) # # To use the "setluid()" function on SCO, link "-lprot", and to use # the "syslog()" function, link "-lsocket". # # For SVR4(.2) and Solaris 2, you may need "-lsocket -lnsl" for syslog(). # # For ISC, add "-linet -lpt" (and -lcposix, if necessary) # # For Sequent Dynix/ptx, you have to add "-lsocket" # # For OSF/1, add "-lbsd". # # On SCO Xenix, add -ldir -lx # # For FreeBSD and NetBSD, add "-lutil" if the linker complains about # "utmp.o: unresolved symbol _login" # For Linux, add "-lutil" if the linker complains about "updwtmp". # LDFLAGS= LIBS= #LIBS=-lprot -lsocket # SCO Unix #LIBS=-lsocket #LIBS=-lbsd # OSF/1 #LIBS=-lutil # FreeBSD or Linux/GNU libc2 #LDFLAGS=-posix # NeXT with POSIX #LDFLAGS=-s -shlib # 3B1 # # # the following things are mainly used for ``make install'' # # # program to use for installing files # # "-o " sets the username that will own the binaries after installing. # "-g " sets the group # "-c" means "copy" (as opposed to "move") # # if your systems doesn't have one, use the shell script that I provide # in "inst.sh" (taken from X11R5). Needed on IRIX5.2 INSTALL=install -c -o bin -g bin #INSTALL=install -c -o root -g wheel # NeXT/BSD #INSTALL=/usr/ucb/install -c -o bin -g bin # AIX, Solaris 2.x #INSTALL=installbsd -c -o bin -g bin # OSF/1, AIX 4.1, 4.2 #INSTALL=/usr/bin/X11/bsdinst -c -o bin # IRIX # # prefix, where most (all?) of the stuff lives, usually /usr/local or /usr # prefix=/usr/local # # prefix for all the spool directories (usually /usr/spool or /var/spool) # spool=/var/spool # # where the mgetty + sendfax binaries live (used for "make install") # SBINDIR=$(prefix)/sbin # # where the user executable binaries live # BINDIR=$(prefix)/bin # # where the font+coverpage files go # LIBDIR=$(prefix)/lib/mgetty+sendfax # # where the configuration files (*.config, aliases, fax.allow/deny) go to # CONFDIR=$(prefix)/etc/mgetty+sendfax #CONFDIR=/etc/default/ # # # where mgetty PID files (mgetty.pid) go to # (the faxrunqd PID file lives in FAX_SPOOL_OUT/ due to permission reasons) # VARRUNDIR=/var/run # # the fax spool directory # FAX_SPOOL=$(spool)/fax FAX_SPOOL_IN=$(FAX_SPOOL)/incoming FAX_SPOOL_OUT=$(FAX_SPOOL)/outgoing # # the user that owns the "outgoing fax queue" (FAX_SPOOL_OUT) # this user must exist in the system, otherwise faxspool will not work! # # faxrunq and faxrunqd should run under this user ID, and nothing else. # This user needs access to the modems of course. # # (it's possible to run faxrunq(d) as root, but the FAX_OUT_USER # MUST NOT BE root or any other privileged account). # FAX_OUT_USER=fax # # # Where section 1 manual pages should be placed MAN1DIR=$(prefix)/man/man1 # # Where section 4 manual pages (mgettydefs.4) should be placed MAN4DIR=$(prefix)/man/man4 # # Section 5 man pages (faxqueue.5) MAN5DIR=$(prefix)/man/man5 # # Section 8 man pages (sendfax.8) MAN8DIR=$(prefix)/man/man8 # # Where the GNU Info-Files are located # INFODIR=$(prefix)/info # # # A shell that understands bourne-shell syntax # Usually this will be /bin/sh or /usr/bin/sh, but bash or ksh are fine. # (on some ultrix systems, you may need /bin/sh5 here) # SHELL=/bin/sh # # If your shell requires pre-posix syntax to disable traps ('trap 0' # instead of 'trap - 0'), set this to "0" (very rarely needed) # SHELL_TRAP_POSIX=1 # # If you have problems with the awk-programs in the fax/ shell scripts, # try using "nawk" or "gawk" (or whatever works...) here # needed on most SunOS/Solaris/ISC/NeXTStep versions. # AWK=awk # # A few (very few) programs want Perl, preferably Perl5. This define # tells them where to find it. You can use everything except "faxrunqd" # and the "tkperl" frontends without PERL, so don't worry if you don't # have it. # If you specify command line arguments (-w), don't forget the quotes! PERL="/usr/bin/perl -w" # # If you have Perl with TK extentions, define it here. This may be the # same as PERL=... above, or different, if you have TkPerl statically # linked. TKPERL=/usr/bin/tkperl # # # An echo program that understands escapes like "\n" for newline or # "\c" for "no-newline-at-end". On SunOS, this is /usr/5bin/echo, in the # bash, it's "echo -e" # (don't forget the quotes, otherwise compiling mksed will break!!) # # If you do not have *any* echo program at all that will understand "\c", # please use the "mg.echo" program provided in the compat/ subdirectory. # Set ECHO="mg.echo" and INSTALL_MECHO to mg.echo # ECHO="echo" # # INSTALL_MECHO=mg.echo # # for mgetty, that's it. If you want to use the voice # extentions, go ahead (don't forget to read the manual!) # To maintain security, I recommend creating a new group for # users who are allowed to manipulate the recorded voice messages. PHONE_GROUP=phone PHONE_PERMS=770 # Add -DNO_STRSTR to CFLAGS if you don't have strstr(). # create hard/soft links (-s will be added by vgetty Makefile) LN=ln #LN=/usr/5bin/ln RM=rm MV=mv # # Nothing to change below this line ---------------------------------! # MR=1.1 SR=36 DIFFR=1.1.35 # # OBJS=mgetty.o logfile.o do_chat.o locks.o utmp.o logname.o login.o \ mg_m_init.o modem.o faxrec.o ring.o \ faxlib.o faxsend.o faxrecp.o class1.o class1lib.o faxhng.o hyla_nsf.o \ g3file.o io.o gettydefs.o tio.o cnd.o getdisk.o goodies.o \ config.o conf_mg.o do_stat.o SFAXOBJ=sendfax.o logfile.o locks.o modem.o \ faxlib.o faxsend.o faxrecp.o class1.o class1lib.o faxhng.o hyla_nsf.o \ g3file.o io.o tio.o getdisk.o config.o conf_sf.o goodies.o all: bin-all doc-all bin-all: mgetty sendfax newslock sedscript subdirs call-back # a few C files need extra compiler arguments mgetty.o : mgetty.c syslibs.h mgetty.h ugly.h policy.h tio.h fax_lib.h \ config.h mg_utmp.h Makefile $(CC) $(CFLAGS) -DVARRUNDIR=\"$(VARRUNDIR)\" -c mgetty.c conf_mg.o : conf_mg.c mgetty.h ugly.h policy.h syslibs.h \ config.h conf_mg.h Makefile $(CC) $(CFLAGS) -DFAX_SPOOL_IN=\"$(FAX_SPOOL_IN)\" \ -DCONFDIR=\"$(CONFDIR)\" -c conf_mg.c conf_sf.o : conf_sf.c mgetty.h ugly.h policy.h syslibs.h \ config.h conf_sf.h Makefile $(CC) $(CFLAGS) -DCONFDIR=\"$(CONFDIR)\" -c conf_sf.c login.o : login.c mgetty.h ugly.h config.h policy.h mg_utmp.h Makefile $(CC) $(CFLAGS) -DCONFDIR=\"$(CONFDIR)\" -c login.c cnd.o : cnd.c syslibs.h policy.h mgetty.h ugly.h config.h Makefile $(CC) $(CFLAGS) -DCONFDIR=\"$(CONFDIR)\" -c cnd.c logname.o : logname.c syslibs.h mgetty.h policy.h tio.h mg_utmp.h Makefile # here are the binaries... mgetty: $(OBJS) $(CC) -o mgetty $(OBJS) $(LDFLAGS) $(LIBS) sendfax: $(SFAXOBJ) $(CC) -o sendfax $(SFAXOBJ) $(LDFLAGS) $(LIBS) # sentinelized binaries for runtime testing... sentinel: mgetty.sen sendfax.sen mgetty.sen: $(OBJS) sentinel -v $(CC) -o mgetty.sen $(OBJS) $(LDFLAGS) $(LIBS) sendfax.sen: $(SFAXOBJ) sentinel -v $(CC) -o sendfax.sen $(SFAXOBJ) $(LDFLAGS) $(LIBS) # subdirectories... subdirs: cd g3 ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "LIBS=$(LIBS)" all cd tools ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "LIBS=$(LIBS)" all cd fax ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "LIBS=$(LIBS)" "FAX_SPOOL_OUT=$(FAX_SPOOL_OUT)" "FAX_OUT_USER=$(FAX_OUT_USER)" "CONFDIR=$(CONFDIR)" all call-back: @$(MAKE) mgetty cd callback ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "CONFDIR=$(CONFDIR)" "VARRUNDIR=$(VARRUNDIR)" "LIBS=$(LIBS)" all contrib-all: cd contrib ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "LIBS=$(LIBS)" all doc-all: cd doc ; $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS) -I.." "LDFLAGS=$(LDFLAGS)" "LIBS=$(LIBS)" doc-all # things... getdisk: getdisk.c $(CC) $(CFLAGS) -DTESTDISK getdisk.c -o getdisk testdisk: getdisk ./getdisk / . # README PROBLEMS DISTRIB=README.1st THANKS TODO BUGS FTP Recommend \ inittab.aix inst.sh version.h \ Makefile ChangeLog policy.h-dist ftp.sh mkidirs \ login.cfg.in mgetty.cfg.in sendfax.cfg.in \ dialin.config faxrunq.config \ mgetty.c mgetty.h ugly.h do_chat.c logfile.c logname.c locks.c \ mg_m_init.c modem.c ring.c \ class1.h class1.c class1lib.c hyla_nsf.c \ faxrec.c faxrecp.c faxsend.c faxlib.c fax_lib.h sendfax.c \ g3file.c \ io.c tio.c tio.h gettydefs.c login.c do_stat.c faxhng.c \ config.h config.c conf_sf.h conf_sf.c conf_mg.h conf_mg.c \ cnd.c getdisk.c mksed.c utmp.c mg_utmp.h syslibs.h goodies.c noident: policy.h for file in `find . -type f -name "*.[ch]" -print` ; do \ echo "$$file..."; \ case $$file in \ *.c) \ mv -f $$file tmp-noident; \ sed -e "s/^#ident\(.*\)$$/static char sccsid[] =\1;/" $$file; \ ;; \ *.h) \ mv -f $$file tmp-noident; \ f=`basename $$file .h`; \ sed -e "s/^#ident\(.*\)$$/static char sccs_$$f[] =\1;/" $$file; \ ;; \ esac; \ done $(MAKE) "CC=$(CC)" "CFLAGS=$(CFLAGS)" all sedscript: mksed ./mksed >sedscript chmod +x sedscript mksed: mksed.c policy.h Makefile $(CC) $(CFLAGS) -DBINDIR=\"$(BINDIR)\" -DSBINDIR=\"$(SBINDIR)\" \ -DLIBDIR=\"$(LIBDIR)\" \ -DCONFDIR=\"$(CONFDIR)\" \ -DFAX_SPOOL=\"$(FAX_SPOOL)\" \ -DFAX_SPOOL_IN=\"$(FAX_SPOOL_IN)\" \ -DFAX_SPOOL_OUT=\"$(FAX_SPOOL_OUT)\" \ -DFAX_OUT_USER=\"$(FAX_OUT_USER)\" \ -DVARRUNDIR=\"$(VARRUNDIR)\" \ -DAWK=\"$(AWK)\" \ -DPERL=\"$(PERL)\" -DTKPERL=\"$(TKPERL)\" \ -DECHO=\"$(ECHO)\" \ -DSHELL=\"$(SHELL)\" \ -DSHELL_TRAP_POSIX=$(SHELL_TRAP_POSIX) \ -o mksed mksed.c policy.h-dist: policy.h @rm -f policy.h-dist cp policy.h policy.h-dist @chmod u+w policy.h-dist version.h: $(DISTRIB) rm -f version.h if expr "$(MR)" : "[0-9].[13579]" >/dev/null ; then \ date=`date "+%b%d"` ;\ echo "char * mgetty_version = \"interim release $(MR).$(SR)-$$date\";" >version.h ;\ else \ echo "char * mgetty_version = \"stable release $(MR).$(SR)\";" >version.h ;\ fi chmod 444 version.h mgetty$(MR).$(SR).tar.gz: $(DISTRIB) rm -f mgetty-$(MR).$(SR) ln -sf . mgetty-$(MR).$(SR) find . -name core -print | xargs rm -f cd voice ; $(MAKE) clean && cvs update -d . ( echo "$(DISTRIB)" | tr " " "\\012" ; \ for i in `find . -name .files -print | sed -e 's;^./;;` ; do \ cat $$i | sed -e '/^\.files/d' -e 's;^;'`dirname $$i`'/;' ; \ done ; \ find voice -type f -print | grep -v CVS ; \ ) \ | sed -e 's;^;mgetty-$(MR).$(SR)/;g' \ | gtar cvvfT mgetty$(MR).$(SR).tar - gzip -f -9 -v mgetty$(MR).$(SR).tar tar: mgetty$(MR).$(SR).tar.gz diff: mgetty$(DIFFR)-$(MR).$(SR).diff.gz sign: tar pgp -sab mgetty$(MR).$(SR).tar.gz chmod +r mgetty$(MR).$(SR).tar.gz.asc mgetty$(DIFFR)-$(MR).$(SR).diff.gz: \ mgetty$(DIFFR).tar.gz mgetty$(MR).$(SR).tar.gz -rm -rf /tmp/mgd mkdir /tmp/mgd gtar xvCfz /tmp/mgd mgetty$(DIFFR).tar.gz gtar xvCfz /tmp/mgd mgetty$(MR).$(SR).tar.gz ( cd /tmp/mgd ; \ gdiff -u3 --ignore-space-change --recursive --new-file -I "^#ident" \ mgetty-$(DIFFR) mgetty-$(MR).$(SR) ; \ exit 0 ) >mgetty$(DIFFR)-$(MR).$(SR).diff rm -rf /tmp/mgd gzip -f -9 -v mgetty$(DIFFR)-$(MR).$(SR).diff mg.uue: mgetty$(MR).$(SR).tar.gz uuencode mgetty$(MR).$(SR)-`date +%b%d`.tar.gz mg.uue uu: mg.uue uu2: mg.uue split -3600 mg.uue mg.uu. # this is for automatic uploading to the beta site. # DO NOT USE IT if you're not ME! Please! # beta: tar diff sign test `hostname` = greenie.muc.de || exit 1 # local cp mgetty$(MR).$(SR).tar.gz /pub/mgetty-archive/ cp mgetty$(DIFFR)-$(MR).$(SR).diff.gz /pub/mgetty-archive/ -cvs commit -m 'new version released' version.h # master ftp/www site ./ftp.sh $(MR).$(SR) delta.greenie.net \ '~ftp/pub/mgetty/source/$(MR)' ./beta $(MR) $(SR) $(DIFFR) delta.greenie.net \ '/home/httpd/mgetty.greenie.net/doc' #shar1: $(DISTRIB) # shar -M -c -l 40 -n mgetty+sendfax-$(MR).$(SR) -a -o mgetty.sh $(DISTRIB) # #shar: $(DISTRIB) # shar -M $(DISTRIB) >mgetty$(MR).$(SR).sh doc-tar: cd doc ; $(MAKE) "VS=$(MR).$(SR)" doc-tar policy.h: @echo @echo "You have to create your local policy.h first." @echo "Copy policy.h-dist and edit it." @echo @exit 1 clean: rm -f *.o compat/*.o mgetty sendfax rm -f testgetty getdisk mksed sedscript newslock *~ rm -f sendfax.config mgetty.config login.config cd g3 && $(MAKE) clean cd fax && $(MAKE) clean cd tools && $(MAKE) clean cd callback && $(MAKE) clean cd contrib && $(MAKE) clean cd doc && $(MAKE) clean cd voice && $(MAKE) clean cd t && $(MAKE) clean fullclean: clean distclean: clean login.config: login.cfg.in sedscript ./sedscript login.config mgetty.config: mgetty.cfg.in sedscript ./sedscript mgetty.config sendfax.config: sendfax.cfg.in sedscript ./sedscript sendfax.config newslock: compat/newslock.c $(CC) $(CFLAGS) -o newslock compat/newslock.c # internal: use this to create a "clean" mgetty+sendfax tree bindist: all doc-all sedscript -rm -rf bindist ./mkidirs bindist$(prefix) bindist$(spool) bd=`pwd`/bindist; PATH=`pwd`:"$$PATH" $(MAKE) prefix=$$bd$(prefix) \ BINDIR=$$bd$(BINDIR) SBINDIR=$$bd$(SBINDIR) \ LIBDIR=$$bd$(LIBDIR) CONFDIR=$$bd$(CONFDIR) \ spool=$$bd$(spool) FAX_SPOOL=$$bd$(FAX_SPOOL) \ FAX_SPOOL_IN=$$bd$(FAX_SPOOL_IN) \ FAX_SPOOL_OUT=$$bd$(FAX_SPOOL_OUT) \ MAN1DIR=$$bd$(MAN1DIR) MAN4DIR=$$bd$(MAN4DIR) \ MAN5DIR=$$bd$(MAN5DIR) MAN8DIR=$$bd$(MAN8DIR) \ INFODIR=$$bd$(INFODIR) install cd bindist; gtar cvvfz mgetty$(MR).$(SR)-bin.tgz * install: install.bin install.doc install.bin: mgetty sendfax newslock \ login.config mgetty.config sendfax.config # # binaries # -test -d $(BINDIR) || ( ./mkidirs $(BINDIR) ; chmod 755 $(BINDIR) ) $(INSTALL) -m 755 newslock $(BINDIR) -test -d $(SBINDIR) || ( ./mkidirs $(SBINDIR) ; chmod 755 $(SBINDIR) ) -mv -f $(SBINDIR)/mgetty $(SBINDIR)/mgetty.old -mv -f $(SBINDIR)/sendfax $(SBINDIR)/sendfax.old $(INSTALL) -s -m 700 mgetty $(SBINDIR) $(INSTALL) -s -m 755 sendfax $(SBINDIR) # # data files + directories # test -d $(LIBDIR) || \ ( ./mkidirs $(LIBDIR) && chmod 755 $(LIBDIR) ) test -d $(CONFDIR) || \ ( ./mkidirs $(CONFDIR) && chmod 755 $(CONFDIR)) test -f $(CONFDIR)/login.config || \ $(INSTALL) -o root -m 600 login.config $(CONFDIR)/ test -f $(CONFDIR)/mgetty.config || \ $(INSTALL) -o root -m 600 mgetty.config $(CONFDIR)/ test -f $(CONFDIR)/sendfax.config || \ $(INSTALL) -o root -m 644 sendfax.config $(CONFDIR)/ test -f $(CONFDIR)/dialin.config || \ $(INSTALL) -o root -m 600 dialin.config $(CONFDIR)/ test -f $(CONFDIR)/faxrunq.config || \ $(INSTALL) -o root -m 644 faxrunq.config $(CONFDIR)/ # # test for outdated stuff # -@if test -f $(LIBDIR)/mgetty.login ; \ then \ echo "WARNING: the format of $(LIBDIR)/mgetty.login has " ;\ echo "been changed. Because of this, to avoid confusions, it's called " ;\ echo "$(CONFDIR)/login.config now." ;\ echo "" ;\ fi # # fax spool directories # test -d $(spool) || \ ( mkdir $(spool) && chmod 755 $(spool) ) test -d $(FAX_SPOOL) || \ ( mkdir $(FAX_SPOOL) && \ chown $(FAX_OUT_USER) $(FAX_SPOOL) && \ chmod 755 $(FAX_SPOOL) ) test -d $(FAX_SPOOL_IN) || \ ( mkdir $(FAX_SPOOL_IN) && chmod 755 $(FAX_SPOOL_IN) ) test -d $(FAX_SPOOL_OUT) || \ mkdir $(FAX_SPOOL_OUT) chown $(FAX_OUT_USER) $(FAX_SPOOL_OUT) chmod 755 $(FAX_SPOOL_OUT) # # g3 tool programs # cd g3 ; $(MAKE) install INSTALL="$(INSTALL)" \ BINDIR=$(BINDIR) \ LIBDIR=$(LIBDIR) CONFDIR=$(CONFDIR) # # fax programs / scripts / font file # cd fax ; $(MAKE) install INSTALL="$(INSTALL)" \ FAX_OUT_USER=$(FAX_OUT_USER) \ BINDIR=$(BINDIR) SBINDIR=$(SBINDIR) \ LIBDIR=$(LIBDIR) CONFDIR=$(CONFDIR) # # compatibility # if [ ! -z "$(INSTALL_MECHO)" ] ; then \ cd compat ; \ $(CC) $(CFLAGS) -o mg.echo mg.echo.c && \ $(INSTALL) -s -m 755 mg.echo $(BINDIR) ; \ fi # # documentation # install.doc: cd doc ; $(MAKE) install INSTALL="$(INSTALL)" \ MAN1DIR=$(MAN1DIR) \ MAN4DIR=$(MAN4DIR) \ MAN5DIR=$(MAN5DIR) \ MAN8DIR=$(MAN8DIR) \ INFODIR=$(INFODIR) # # WWW frontend stuff # install.www: cd frontends/www ; $(MAKE) install.www INSTALL="$(INSTALL)" \ BINDIR=$(BINDIR) \ LIBDIR=$(LIBDIR) CONFDIR=$(CONFDIR) # # voice extensions, consult the `voice' chapter in the documentation # vgetty: @$(MAKE) mgetty cd voice; $(MAKE) CFLAGS="$(CFLAGS)" CC="$(CC)" LDFLAGS="$(LDFLAGS)" \ LN="$(LN)" MV="$(MV)" RM="$(RM)" \ LIBS="$(LIBS)" \ FAX_SPOOL_IN="$(FAX_SPOOL_IN)" CONFDIR="$(CONFDIR)" \ VARRUNDIR="$(VARRUNDIR)" \ SHELL="$(SHELL)" vgetty-all vgetty-install: sedscript cd voice; $(MAKE) CFLAGS="$(CFLAGS)" CC="$(CC)" LDFLAGS="$(LDFLAGS)" \ BINDIR="$(BINDIR)" SBINDIR="$(SBINDIR)" LIBDIR="$(LIBDIR)" \ CONFDIR="$(CONFDIR)" MAN1DIR="$(MAN1DIR)" MAN8DIR="$(MAN8DIR)" INSTALL="$(INSTALL)" \ PHONE_GROUP="$(PHONE_GROUP)" PHONE_PERMS="$(PHONE_PERMS)" \ LN="$(LN)" MV="$(MV)" RM="$(RM)" \ LIBS="$(LIBS)" vgetty-install install-vgetty: vgetty-install ## test suite test: bin-all for D in g3 t ; do \ ( cd $$D ; $(MAKE) CFLAGS="$(CFLAGS) -I.." test ); \ done check: test ## misc dump: logfile.o config.o conf_mg.o goodies.o getdisk.o tio.o gettydefs.o io.o $(CC) -o dump -g dump.c logfile.o config.o conf_mg.o goodies.o getdisk.o tio.o gettydefs.o io.o $(LDFLAGS) ######## anything below this line was generated by gcc -MM *.c cnd.o : cnd.c syslibs.h policy.h mgetty.h ugly.h config.h conf_mg.o : conf_mg.c mgetty.h ugly.h policy.h syslibs.h tio.h config.h conf_mg.h conf_sf.o : conf_sf.c mgetty.h ugly.h policy.h syslibs.h config.h conf_sf.h config.o : config.c syslibs.h mgetty.h ugly.h config.h do_chat.o : do_chat.c syslibs.h mgetty.h ugly.h policy.h tio.h ring.o: ring.c syslibs.h mgetty.h ugly.h policy.h tio.h do_stat.o : do_stat.c syslibs.h mgetty.h ugly.h policy.h tio.h dump.o : dump.c syslibs.h mgetty.h ugly.h policy.h tio.h fax_lib.h mg_utmp.h \ config.h conf_mg.h faxhng.o : faxhng.c mgetty.h ugly.h faxlib.o : faxlib.c mgetty.h ugly.h policy.h fax_lib.h faxrec.o : faxrec.c syslibs.h mgetty.h ugly.h tio.h policy.h fax_lib.h faxsend.o : faxsend.c syslibs.h mgetty.h ugly.h tio.h policy.h fax_lib.h files.o : files.c mgetty.h ugly.h policy.h getdisk.o : getdisk.c policy.h mgetty.h ugly.h gettydefs.o : gettydefs.c syslibs.h mgetty.h ugly.h policy.h goodies.o : goodies.c syslibs.h mgetty.h ugly.h config.h io.o : io.c syslibs.h mgetty.h ugly.h locks.o : locks.c mgetty.h ugly.h policy.h logfile.o : logfile.c mgetty.h ugly.h policy.h login.o : login.c mgetty.h ugly.h config.h policy.h mg_utmp.h logname.o : logname.c syslibs.h mgetty.h ugly.h policy.h tio.h mg_utmp.h mg_m_init.o : mg_m_init.c syslibs.h mgetty.h ugly.h tio.h policy.h fax_lib.h mgetty.o : mgetty.c syslibs.h mgetty.h ugly.h policy.h tio.h fax_lib.h mg_utmp.h \ config.h conf_mg.h sendfax.o : sendfax.c syslibs.h mgetty.h ugly.h tio.h policy.h fax_lib.h config.h \ conf_sf.h tio.o : tio.c mgetty.h ugly.h tio.h utmp.o : utmp.c mgetty.h ugly.h mg_utmp.h class1.o: class1.c mgetty.h ugly.h fax_lib.h tio.h class1.h class1lib.o: class1lib.c mgetty.h ugly.h fax_lib.h tio.h class1.h hyla_nsf.o: hyla_nsf.c mgetty.h ugly.h policy.h mgetty-1.1.36/ChangeLog0100644000031200001470000014577610634471753013215 0ustar gertfaxFri Jun 15 13:11:24 MEST 2007 Gert Doering * add missing files (g3file.c), re-release 1.1.36 Fri Jun 15 09:13:20 MEST 2007 Gert Doering * release 1.1.36 Wed May 16 17:46:39 MEST 2007 Gert Doering * faxsend.c: (optionally) insert 100 0-bytes at start of page, to help modems that have problems with the before-EOL timing (new USRs) * fax_lib.c: add new MQ_ bit for 0-padding Sat May 5 14:03:16 MEST 2007 Gert Doering * fax/faxrunqd.in: make wait() interruptible, avoid queue stalls if only one modem active and this modem has a very long job. Additionally, detect hung sendfax processes, and kill()' em. * faxlib.c: recognize modem ID for Blatzheim ISDN/hybrid modems Fri Jan 19 08:36:49 MET 2007 Gert Doering * fax/faxrunqd.in: add functionality to run external scripts if the fax queue reaches a "high water mark" length, and if a given modem has more than consecutive errors * doc/faxrunqd.8in: document new options Thu Dec 7 16:44:55 MET 2006 Gert Doering * fax/faxspool.in: add @S@ for faxheader (replace with job id) Wed Nov 22 16:41:47 MET 2006 Gert Doering * sendfax.c: for "failed transmitting", log #of pages successfully sent + #of retries (important for judging significance of errors) * conf_sf.c: add new sendfax option "-R " to set "max_tries" value * doc/sendfax.8in: document -R Wed Oct 25 13:50:17 MEST 2006 Gert Doering * tools/README: update documentation, add "microcom" * class1lib.c: in fax1_send_frame(): make logging more uniform and easier to read. Handle case of "NO CARRIER" after frame has been sent, and check for internal consistency regarding "we have carrier" vs. "use existing carrier" (ugly) * class1.c: on reception, don't try to send DIS when CSI frame couldn't be sent. Log # of current re-try. Thu Oct 19 10:01:02 MEST 2006 Jan-Peter Koopmann * add exim4 documentation to frontends/mail2fax06/README Fri Sep 29 13:05:40 MEST 2006 Gert Doering * class1lib.c: check all fax_send() return values (in case flow control gets stuck, we might have a timeout in there) * class1.c: properly implement scan line time handling / byte padding * class1.c: implement re-training on TCF/FTT, including stepdown * class1lib.c: implement fax1_st_table[] for scan line time handling (bit ordering in DCS/DIS frames is just weird). Add scan time parameter to fax1_send_dcs() * fax/faxspool.rules: add conversion rules for .jpg and .doc Wed Sep 27 11:49:45 MEST 2006 Gert Doering * fax/faxrunqd.in: fix write combining bug with partially-sent jobs Tue Sep 26 11:05:36 MEST 2006 Gert Doering * voice/libvoice/*: sparc64 compatibility fixes (*int vs. *p_int) * voice/Makefile: pull in new object files (hyla_nsf.o, g3file.o) * g3file.c: implement first draft of generic G3 I/O module, including EOL padding * t/t_g3f_c.c, t/t_g3file.in: test routines for g3file.c * class1.c: change fax1_send_page() to use g3_send_file() * fax/faxspool.in: netpbm calls "giftoppm" now "giftopnm" -> adapt Fri Sep 22 23:43:51 MEST 2006 Gert Doering * frontends/mail2fax06/: implement new mail to fax conversion tool, in perl, using MIME::Parser, which will properly handle attachments Wed Jun 14 11:38:54 MEST 2006 Gert Doering * tools/microcom.c: add to fix missing prototype warnings * config.c: insert {} to silence over-eager compiler warnings * tio.c: change "static char[] tio_compilation_type" into "#ident" (get rid of "unused variable" warning, save a few bytes .data) * locks.c: get rid of "unused variable tries" compiler warning * hyla_nsf.c: add mgetty T.35 vendor code to table Sat Jun 10 13:45:04 MEST 2006 Gert Doering * mgetty has its own ITU T.35 vendor code now! [0x04 0x81 0x0e] Fri May 26 22:04:20 MEST 2006 Gert Doering * tools/mid.c: implement "-Q" (quick query) Thu Apr 13 12:07:16 MEST 2006 Gert Doering * faxlib.c: handle USR reporting format for NSF frames Sun Apr 9 18:39:51 MEST 2006 Gert Doering * fax/faxrunqd.in: fix quoting bug in `date` call (Klaus Weglehner) * hyla_nsf.c: import new set of tables from Hylafax NSF.c++ Wed Mar 29 14:26:48 MEST 2006 Gert Doering * hyla_nsf.c, class1.c, class1.h: silence compiler complaints * config.h: cast return value of c_bool() to (boolean) Wed Mar 22 15:10:18 MET 2006 Gert Doering * class1.c: hand off incoming NSF frames to decoder * faxlib.c: convert incoming NSF frames to binary, hand off to decoder * hyla_nsf.c: import NSF vendor tables + decoder from Hylafax Tue Mar 7 15:10:13 MET 2006 Gert Doering * class1.c: fax1_send_page(): fix end-of-page handling, reorder sending of TSI and DCS to correctly handle RTP/RTN * class1.c: fax1_send_page(): properly use fax_send_swaptable[] (page sending works now, if receiver doesn't need padding) * class1.c: fax1_send_page(): fix first and last chunk of page data (digifax header wasn't skipped, and last chunk was lost) * class1.c: handle DCN in fax1_dial_and_phase_AB() * class1.c: add receive torture test (to sender), more logging * fax_lib.h: define CAN character (cancel, ctrl-x) * class1lib.c: fax1_receive_frame(): if waiting for start-of-frame already runs into timeout, don't even try to read end-of-frame modem response (robustness) * class1lib.c: tell modem (send CAN character) when we timeout after AT+FRH=n, to make sure recovering works Mon Mar 6 17:27:04 MET 2006 Gert Doering * class1lib.c: don't query AT+FRH=?/+FTH=? carriers Wed Feb 22 18:10:50 MET 2006 Gert Doering * */Makefile: move all "fullclean" extras into "clean" target, remove "make fullclean" * Makefile: for "make fullclean" or "distclean", just do "clean" Wed Feb 22 14:36:16 MET 2006 Gert Doering * release 1.1.35 Sat Feb 18 13:42:59 MET 2006 Gert Doering * tio.c: tio_check_speed(): set errno to EINVAL for invalid speeds * doc/faxq-helper.8in: add man page Thu Feb 9 18:44:06 MET 2006 Gert Doering * fax_lib.h, class1lib.c: implement MQ_C1_NO_V17 Thu Jan 19 14:41:33 MET 2006 Gert Doering * fax/faxrunq.in: implement same acct.log format as in faxrunqd 1.71 * www/faxhist.in: adapt to new acct.log, cleanup sorted output * www/faxhists.in: adapt to new acct.log, show total number of lines Fri Jan 13 15:06:26 MET 2006 Gert Doering * fax/faxrunqd.in: change output format for acct.log to something that is more consistant and easier to parse Tue Jan 3 11:17:07 MET 2006 Gert Doering * use +FAA=x for adaptive answer in class 1.0 mode, +FAE=x in class 1 (this is very ill-standardized. Some modems accept both, some only one or the other) Sun Jan 1 17:19:08 MET 2006 Gert Doering * class1.c, class1lib.c: make (receive) code robust against all sort of unexpected behaviours (modem responses not coming back in time, sudden hangups from the remote end, need for re-tries, etc.) still not the full T.30 flow chart, but important parts of it. Sat Dec 31 17:01:19 MET 2005 Gert Doering * class 1 fax reception now "mostly works" * class1lib.c: correctly construct DIS frame from modem capabilities + user settings * faxrecp.c: use fax_recv_swaptable[] for bit swapping (if needed) * faxlib.c: initialize fax_recv_swaptable[] to swap bits in class 1/1.0 mode, add lots of comments to explain background * mgetty.c: get non-adaptive answering in class 1/1.0 right * various: handle "class 1" and "class 1.0" the same way (for now) Fri Dec 30 22:35:00 MET 2005 Gert Doering * class1.c, class1lib.c: rework frame sending, handle DCS * faxrec.c: split faxrec() into fax class-independent part and class 2/2.0 handler (fax2_highlevel_receive()) * faxrec.c, policy.h: drop FAX_USRobotics cruft * conf_mg.c: drop FAX_USRobotics -> SWITCHBAUD 19200 logic Wed Dec 28 22:56:57 MET 2005 Gert Doering * faxrec.c, mg_m_init.c: preparations for fax class 1 receive * class1.c, class1lib.c: very preliminary fax class 1 receiver * class1.h: fix wrong value for T30_DCN Tue Dec 20 22:01:48 MET 2005 Warren Burstein * conf_mg.c: fix typo if MAIL_TO is undefined Wed Nov 30 09:46:52 MET 2005 Gert Doering * release 1.1.34 Sat Nov 26 14:28:09 MET 2005 Gert Doering * mg_m_init.c: write to log file if blocking open() is used * logfile.c, tio.c, tio.h, mgetty.h: portability changes to GNU/kFreeBSD (by Robin Elfrink) * Makefile: new master FTP site is mgetty.greenie.net Thu Nov 24 17:38:44 MET 2005 Gert Doering * faxlib.c, voice/libvoice/detect.c: understand ATI response 1507 for another ZyXEL Omni 56K variant (56k Pro) * doc/mgetty.texi-in: document login-env-ttyprompt-hack * policy.h: drop description of ENV_TTYPROMPT, point to mgetty.texi * logname.c: replace #ifdef ENV_TTYPROMPT with run-time check of the new config option, login-env-ttyprompt-hack * mgetty.c: pass c_bool(env_ttyprompt) to getlogname() * conf_mg.h, conf_mg.c: add option login-env-ttyprompt-hack * mgetty.c: cleanup, use set_env_var() to set TERM=... Wed Nov 9 10:12:36 MET 2005 Gert Doering / D.Binderman * locks.c: a lprintf() call was missing a file name argument Fri Jun 17 19:05:27 MEST 2005 Gert Doering * faxlib.c: remove #ifdef FAX_USRobotics -> MQ_USR_FMINSP (if someone still has such an old modem, setting "modem_quirks 0x20" will do the same thing at run-time) Wed Jun 15 11:43:12 MEST 2005 Marcus Meissner * voice/libvoice/record.c: fix (non-exploitable) 1-byte buffer overflow in construction of RMD file header Wed May 25 16:04:11 MEST 2005 Gert Doering * sendfax.c: alarm() out of fcntl() if it hangs > 10s. (AIX problem) Mon Apr 25 16:27:14 MEST 2005 Gert Doering * logname.c: drain tty output before changing CR/LF settings * mgetty.h, callback/callback.c: SIG_HDLR_ARGS cleanup * mgetty.h, locks.c: prototype for rmlocks() cleaned up * faxlib.c: decode & log receiver capabilities (+FDIS/+FIS) Sat Apr 16 11:51:25 MEST 2005 Gert Doering * cnd.c: add destination number format (NDID=...) for Digi DataFire * fax/faxq.in: add "faxq stop" and "faxq start" functionality * doc/faxq.1in: document start/stop Sun Apr 10 23:02:00 MEST 2005 Gert Doering * release 1.1.33 * fax/faxq-helper.c: repair creation of multi-page fax JOB files Wed Mar 23 10:57:05 MET 2005 Gert Doering * ring.c: repair detection of V.253 RING signalling (R) Wed Mar 16 12:08:44 MET 2005 Gert Doering * t/t_ring.c: add test module for "ring.c" and "cnd.c" functions Sun Mar 13 12:43:08 MET 2005 Gert Doering * release 1.1.32 * voice/: import vgetty jumbo patch from Juergen Kosel, adding full duplex voice (experimental) and V.253 fixes * voice/libpvf/wav.c, voice/pvftools/pvfcut.c, pvfecho.c, pvfreverse.c: fix realloc(NULL) induced core dumps on older OSes Sun Feb 27 12:58:29 MET 2005 Gert Doering * g3/Makefile: add tests for g3cat -L/-w * g3/g3cat.c: add -L switch (cap lines in output file) * doc/g3cat.1in: document all command line switches * Makefile, mksed.c: new setting: SHELL_TRAP_POSIX * t/t_trap.in: test for correct shell/trap behaviour * fax/faxrunq.in: get correct "trap 0" syntax from sedscript Thu Feb 24 17:24:18 MET 2005 Gert Doering * fax/faxq-helper.c: fix scrubbing of JOB file lines, create "user" line if not present * fax/faxspool.in: don't pass logname/id information to faxq-helper anymore (unless "-u" is set) - caused weird problems, gains nothing Thu Feb 17 12:08:13 MET 2005 Gert Doering * fax/faxrunqd.in: speed up detection of new jobs in queue (<10s) * fax/faxrunqd.in: change over to 'use strict' perl Mon Feb 14 13:41:49 MET 2005 Karsten Keil * doc/mgetty.texi-in: dirindex node * mgetty.h: on __powerpc64__ platforms, define PTR_IS_LONG Wed Feb 9 10:46:08 MET 2005 Gert Doering * config.h: portability fixes ((int) cast) for 64bit platforms Mon Jan 3 17:46:36 MET 2005 Matthias Andree * fax/faxrunq.in: workaround for bash 3.x "trap" incompatibility Wed Nov 24 14:33:43 MET 2004 Gert Doering * tools/microcom.c: add utra-light terminal program * fax/faxrunqd.in: Implement 'sendfax-tty-map' (run tty-specific sendfax binary) * fax/faxrunqd.in, faxrunq.in: implement update-call-program Sun Nov 14 21:28:07 MET 2004 fdc@cliwe.ping.de (Frank D. Cringle) * frontends/X11/viewfax: import viewfax-2.6 Sat Nov 13 23:12:53 MET 2004 Gert Doering * doc/faxrunqd.8in: document sendfax-tty-map & update-call-program * fax/faxspool.in: fix wrong test for "$HOME/.make.coverpg" * fax/faxspool.in: fix spooling from stdin ("faxspool 123 -") * faxlib.c: recognize "Eicon ISDN Modem" as DIVA card with class 2 Thu Nov 11 21:54:11 MET 2004 Gert Doering * t/Makefile, t/t_echo.sh: add tests for $ECHO setting Mon Nov 8 21:07:35 MET 2004 Gert Doering * incorporate portability patches from NetBSD pkgsrc tree Tue Nov 2 09:17:37 MET 2004 Gert Doering * add t/ subdirectory and t/t_conf.c struct/int size test program * Makefile: call t/Makefile for "make test" Sat Jul 24 16:54:52 MEST 2004 Gert Doering * release 1.1.31 * doc/mgetty.texi-in: add section on isdn4linux and CAPI Sat Jul 17 17:21:38 MEST 2004 Gert Doering * doc/sff2g3.1in: add man page for sff2g3 Sat Jul 17 12:18:28 MEST 2004 Andreas Barth * cnd.c: add "+CLIP:" string for caller ID * voice/libvoice/detect.c: ATI codes for Zoom and Multitech modems * voice/libvoice/V253modem.c: more flexible sample/s. handling (old stuff was fixed at 7200 hz) * voice/pvftools/pvftormd.c: accept 7200, 8000, 11025 Hz for "Lucent" * fax/faxspool.in: use per-user .faxheader/.make.coverpg files instead of global defaults (if per-user files exists) Fri Jul 16 19:03:48 MEST 2004 Gert Doering * g3/Makefile: add "make test" test suite (for G3 tools) * g3/sff2g3.c: NEW: converter from CAPI SFF fax format to raw G3 * Makefile: pack g3/sff2g3.c Thu Feb 5 18:40:29 MET 2004 Gert Doering * fax/faxspool: rework umask saving/restoring (use subshell trick) Sat Jan 10 00:01:25 MET 2004 Gert Doering * faxlib.c: add 1503 ID code (ZyXEL U-90E) Tue Dec 16 12:46:52 MET 2003 Andreas Barth * Makefile: remove -DAUTO_PPP * policy.h: include FIDO and AUTO_PPP here Fri Dec 5 22:46:47 MET 2003 Ken Findlay * login.c: empty lines should never match, not even empty user names Mon Nov 17 20:08:59 MET 2003 Gert Doering * mgetty.c: log warning if parent PID is not "1" (init) * mgetty.cfg.in: add clarification about "direct yes" to sample cfg Fri Nov 7 21:47:27 MET 2003 Andreas Barth * fax/faxspool.in: add per-user faxheader and coverpg files * doc/faxspool.1in, mgetty.texi: document new feature Thu Oct 9 12:44:47 MEST 2003 Gert Doering * fax/faxspool.in: reject empty (0 bytes) input files Sun Oct 5 13:59:51 MEST 2003 Gert Doering * do_chat.c: make clean_line() logging show the timeout value Mon Sep 29 23:36:34 MEST 2003 Andreas Barth * contrib/g3tolj.c, g3toxwd.c: clean up protoypes and return types * various .c files: integrate Debian cleanup fixes (usually adding and/or where missing) Wed Aug 20 12:39:53 MEST 2003 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: change signal handling - use HUP for graceful exit, and dump statistics to logfile upon receipt of USR2 Sat Jun 28 22:14:35 MEST 2003 Gert Doering (gert@greenie.muc.de) * fax/faxq-helper.c: honour user umask when spooling G3 files (user decides whether group/other can read faxes) * fax/faxspoool.in: reset umask after creating tmpdir (with umask 077) * fax/faxq-helper.c: file name validation was overly strict - accept anything that's printable, not a space, '/' or '\' Thu Jun 12 16:56:44 MEST 2003 Gert Doering (gert@greenie.muc.de) * faxlib.c: Multitech and USR return class 2.0/2.1 +FPS:, values in decimal, not hex -> change +FPS: parser to do decimal for those modems (via modem_quirks |= MQ_FPS_NOT_HEX) * fax_lib.h: add MQ_FPS_NOT_HEX modem quirk bit * faxrec.c, faxrecp.c: understand VR=8 for "normal mode" (200x100 dpi) Mon Apr 28 19:41:14 MEST 2003 Gert Doering (gert@greenie.muc.de) * logname: make "buffer overrun" error message more precise Wed Apr 23 10:49:25 MEST 2003 John R. Jackson * voice/libutil/access.c: more verbose error reporting Wed Apr 9 23:05:23 MEST 2003 Gert Doering (gert@greenie.muc.de) * fax/faxspool.in: fix spooling without header line (-h -) Sun Apr 6 16:09:14 MEST 2003 Andreas Barth * mgetty.8in, mgetty.texi-in: document escape sequences for /etc/issue and login prompt. Wed Mar 5 21:37:38 MET 2003 Gert Doering (gert@greenie.muc.de) * Makefile: abort "make install" before installing faxspool if fax user does not exist * Makefile: unconditionally chown $FAX_SPOOL_OUT to fax user Tue Feb 4 17:46:45 MET 2003 Gert Doering (gert@greenie.muc.de) * fax/faxq-helper.c: uid=0 overrides access permission checks * fax/faxrm.in: bugfix: get faxq-helper path from sedscript Tue Jan 21 14:27:39 MET 2003 Gert Doering (gert@greenie.muc.de) * fax/faxspool.in: abort with a proper error message on input file names containing white space or quote characters Tue Jan 14 14:30:42 MET 2003 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: include "success" counter in per_phone_statistics * ugly.h: #define USE_VARARGS for non-Ansi C compilers * logfile.c: change #include<> sequence to catch USE_VARARGS def. Wed Jan 8 23:03:26 MET 2003 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: if a fax job fails, reschedule on different modem (if possible) * voice/libvoice/V253modem.c: fix ELSA_RMD_NAME (used for V.253 modem <-> other modem RMD equivalency checks) Mon Dec 16 14:08:06 MET 2002 Gert Doering (gert@greenie.muc.de) * release 1.1.30 Sun Dec 15 20:45:48 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/vgetty/answer.c, voice/include/default.c: integrate Paul Fox' pre_message and beep_sound patches Thu Dec 12 07:33:12 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/libvoice/detect.c: recognize MultiTech MT3334ZDXV * faxhng.c: add some result codes for the i4l DIVA driver * voice/libvoice/IS_101.c: fix DTMF events for the unshielded case Thu Dec 5 17:40:05 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/vgetty/answer.c: accept arbitrary ring types, not only 0..6 Wed Dec 4 09:15:47 MET 2002 Gert Doering (gert@greenie.muc.de) * ring.c: map DRON/DROF return codes to binary word, use result as distinctive RING number Tue Dec 3 23:10:05 MET 2002 Gert Doering (gert@greenie.muc.de) * frontends/www/README: add user authentication example Mon Nov 25 22:16:41 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/libvoice/V253modem.c: repair messed-up 16 bit PCM patch Mon Nov 25 14:05:20 MET 2002 Gert Doering (gert@greenie.muc.de) * release 1.1.29 * voice/libvoice/detect.c: insert delay before sending ATE0 to modem (timing issue - modem might not have sent the full \r\n sequence from the last "OK" yet when the new AT comes in) Sat Nov 23 12:55:39 MET 2002 Gert Doering (gert@greenie.muc.de) * doc/*.[158]in: bring man pages up to date * tools/ltest.c, tools/mid.c: adapt to new lprintf() prototype * mgetty.h, logfile.c: adapt to use and "..." function declaration (unless USE_VARARGS is set, which is needed for NeXT platforms). Karsten Keil . * Makefile: relax permissions on sendfax and faxrunq.config install - must be readable/executeable by user "fax" now * doc/faxrunqd.8in: document "-u", minor updates * fax/faxrunqd.in, fax/faxspool.in, fax/faxrunq.in: revert Aug 6, 200 change - put faxqueue_done back into $FAX_SPOOL_OUT/ (faxrunq/faxrunqd have no access rights to $VARRUNDIR/ anymore, and $FAX_SPOOL_OUT is no longer world writeable anyway) * fax/faxq.in: change from .last_run to faxqueue_done * fax/faxrunqd.in: add "-u " switch (set uid to ) * fax/faxq-helper.c: finalize new fax queue handling using helper process (suid fax) and a fax queue that is no longer world-readable (open issue since 1994 :) ) * faxrecp.c: implement experimental teergrubing mode (signal "page bad, please retransmit" at the end of each page - or just hang up hard on caller). Activared with "modem-quirks 0x100" or "0x200", respectively. Tue Nov 19 12:13:46 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/libvoice/V253Modem.c: add 16 bit linear PCM support (patch coming from Peter Bruley) * voice/pvftools/pvftormd.c, rmdtopvf.c: add 16 bit linear PCM * rework faxq-helper concept (suid root -> suid fax) * fax/faxq.in: adap "-r" to use faxq-helper Sun Nov 17 22:19:56 MET 2002 Gert Doering (gert@greenie.muc.de) * fax/faxspool.in: adapt to use faxq-helper * fax/faxrm.in: adapt to use faxq-helper * Makefile: create FAX_SPOOL_OUT with mode 755 and owner FAX_OUT_USER * Makefile: add FAX_OUT_USER definition, pass lots of variables to fax/Makefile (for faxq-helper) * README.1st: add instructions about FAX_OUT_USER setup * doc/mgetty.texi-in add instructions about FAX_OUT_USER setup Wed Nov 13 23:12:30 MET 2002 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: fix symlink / file overwrite race in JOB files. Pointed out by Jablonovsky Alexander * doc/faxrunq.8in: point out insecurity in symlink handling Tue Nov 12 22:42:33 MET 2002 Nalin Dahyabhai * mgetty.h: Intel 64bit platforms (__x86_64__) needs PTR_IS_LONG Wed Nov 6 23:56:05 MET 2002 Gert Doering (gert@greenie.muc.de) * voice/libvoice/IS_101.c: implement DLE shielding for long DTMF tones for V.253 (initially by Lee Howard ) * mgetty.c: throw out DIST_RING #define - not used anymore Tue Nov 5 22:41:29 MET 2002 Gert Doering (gert@greenie.muc.de) * ring.c: make sure action strings (CONNECT) are only recognized at the beginning if a line, not in the middle (Paul Fox, pgf@foxharp.boston.ma.us, CALLER NAME = CONNECTICUT). * cnd.c: replace non-printable characters and quotes in caller ID or caller name strings with ' ' - safeguard for passing them to shell later on. Mon Nov 4 23:43:28 MET 2002 Gert Doering (gert@greenie.muc.de) * doc/mgetty.texi-in: add stuff about recent multitech modems, superfine+v.34 fax, and rework chapter about common problems * faxlib.c: fix ugliness with USR modems reporting remote fax ID as " 12345" -> skip leading '"' and all whitespace Sun Oct 20 14:32:05 MEST 2002 Gert Doering (gert@greenie.muc.de) * cnd.c: possible buffer overrun via CallName (found by "A. Guru" ) Mon Apr 8 22:28:11 MEST 2002 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd: fix priority vs. write combining bug Mon Mar 11 19:26:29 MET 2002 Gert Doering (gert@greenie.muc.de) * login.c: check for close-on-exec bit on FD 0 (FreeBSD 4.1 bug) Sat Mar 2 19:23:35 MET 2002 Gert Doering (gert@greenie.muc.de) * login.c: export Caller Name as environment variable $CALLER_NAME Wed Feb 20 18:28:40 MET 2002 Gert Doering (gert@greenie.muc.de) * login.c: make message about bad permissions even more clear Thu Jan 10 21:11:20 MET 2002 Gert Doering (gert@greenie.muc.de) * release 1.1.28 * faxrec.c: replace "0"'s by "STDIN" (readability) Fri Jan 4 18:50:31 MET 2002 Gert Doering (gert@greenie.muc.de) * doc/mgetty.texi-in: some updates * doc/faxrunq.1in, doc/faxrunqd.8in: document calling convention changes (as below) * fax/faxrunq(d).in: pass (last) sendfax return code as 2nd argument to success/failure program Mon Dec 17 22:55:56 MET 2001 Gert Doering (gert@greenie.muc.de) * policy.h, utmp.c: incorporate some NetBSD changes * various: change time() prototype to "time_t time(time_t *tloc)" * mgetty.h, syslibs.h, logfile.c: some #ifdef fiddling for Darwin Sun Dec 16 14:56:18 MET 2001 Gert Doering (gert@greenie.muc.de) * doc/faxrunq.1in, doc/faxrunqd.8in: document more stuff * fax/faxrunq, fax/faxrunqd: don't run queue if a file $FAX_SPOOL_OUT/stop exists. Sun Dec 2 14:23:34 CET 2001 Gert Doering (gert@greenie.muc.de) * login.c: MAX_LOGIN_ARGS handling reworked (claimed N, but allowed only N-1), plus warning message improved. Sun Oct 21 16:40:51 MEST 2001 Gert Doering (gert@greenie.muc.de) * release 1.1.27 * doc/mgetty.texi-in: work on isdn4linux notes * cnd.c (cndtable): add swedish ZyXEL caller ID format (T. Lundgren) * cnd.c (cndtable): add "CALLED NUMBER:" (Jan Oberlaender/i4l) Fri Sep 28 23:06:24 MEST 2001 Gert Doering (gert@greenie.muc.de) * various: adaptions to OpenBSD (similar to NetBSD) Mon Jun 18 22:26:08 MEST 2001 Gert Doering (gert@greenie.muc.de) * mgetty.h: patch to adapt to Linux/S390 (PTR_IS_LONG) * frontends/www/: integrate new version from Neko Mon Apr 16 10:56:21 MEST 2001 Gert Doering (gert@greenie.muc.de) * release 1.1.26 * frontends/windows/lprfax.txt: add description of "fax port monitor" Tue Mar 13 21:32:47 MET 2001 Gert Doering (gert@greenie.muc.de) * login.c: export current tty as $DEVICE to shell Sat Feb 24 11:48:11 MET 2001 Gert Doering (gert@greenie.muc.de) * updates to frontends/www/ (minor bug fixes) * updates to voice/ (see voice/ChangeLog) Sat Feb 24 12:47:19 2001 Marc SCHAEFER * dialin.config: added V253 codes for OUT_OF_AREA and PRIVATE. Thu Feb 1 22:20:10 MET 2001 Gert Doering (gert@greenie.muc.de) * release 1.1.25 Sat Jan 27 19:14:15 MET 2001 Gert Doering (gert@greenie.muc.de) * mksed.c: fix @KVG_PID_FILE@ * getdisk.c: fix overflow on file systems with > 2G (2^31 bytes) free * getdisk.c: default MINFREESPACE from policy.h was interpreted as *bytes*, not as *kbytes*. Which kind of defeats the purpose of checking for "enough disk space". Fixed, work with kbytes now. Fri Jan 19 20:51:31 MET 2001 Gert Doering (gert@greenie.muc.de) * ring.c: add isdn4linux form "RING/" (*sigh*) Mon Jan 8 11:19:16 MET 2001 Gert Doering (gert@greenie.muc.de) * goodies.c: fix include files (Linux/FreeBSD/SVR4 dependent) Sun Jan 7 21:10:28 MET 2001 Gert Doering (gert@greenie.muc.de) * release 1.1.24 Sun Jan 7 00:28:09 MET 2001 Gert Doering (gert@greenie.muc.de) * faxrecp.c: check access rights first, space second (this will give clearer log messages for non-existing directories) * getdisk.c: fix #ifdef mess (this code did never work!) Fri Jan 5 19:30:39 CET 2001 Gert Doering (gert@mobile.greenie.muc.de) * faxrecp.c: accept multiple directories for fax storage, separated by ':'. Use the first one that is writeable and has enough disk space. * mgetty.c, conf_mg.c, conf_mg.c: add "fax-spool-in" config file option to set the incoming fax dir(s). * doc/mgetty.texi-in: document fax-spool-in Thu Jan 4 18:32:24 CET 2001 Gert Doering (gert@mobile.greenie.muc.de) * faxrecp.c: change fax page writing to open( O_EXCL|O_CREAT ) * locks.c: use mkstemp() to create tmp file, if available, open( O_EXCL|O_CREAT ) otherwise. * goodies.c: FreeBSD 3.3 already has /proc//cmdline Thu Dec 21 23:04:25 MET 2000 Gert Doering (gert@greenie.muc.de) * release 1.1.23 * goodies.c: on FreeBSD 4, use /proc//cmdline * mgetty.c: understand VMA_FAX vgetty return codes (unexpected +FCO) Sat Sep 23 16:50:14 MEST 2000 Gert Doering (gert@greenie.muc.de) * mgetty.h: Intel ia64 adaptions (PTR_IS_LONG) (coming from RedHat patches) Sat Aug 26 13:10:00 MEST 2000 Gert Doering (gert@greenie.muc.de) * frontends/X11/: new viewfax version (2.5) Thu Aug 17 19:58:20 MEST 2000 Gert Doering (gert@greenie.muc.de) * release 1.1.22 Mon Aug 14 21:20:26 MEST 2000 Gert Doering (gert@greenie.muc.de) * callback/callback.c: use VARRUNDIR instead of MGETTY_PID_FILE * mgetty.c: use VARRUNDIR to get name of PID file, non-conditional * policy.h: MGETTY_PID_FILE is gone, VARRUNDIR used instead * mgetty.c: write CallerId to UTMP, if available, Connect otherwise Sun Aug 6 16:13:43 MEST 2000 Gert Doering (gert@greenie.muc.de) * fax/faxspool: convert .pdf files via Acroread (contributed by Michael Fischer v. Mollard, mfvm@gmx.de). * Makefile, mksed: introduce $VARRUNDIR * fax/faxrunqd.in, fax/faxrunq.in, fax/faxspool.in: change location of ".last_run" to $VARRUNDIR/faxqueue_done (previously, $fax_spool_out/.last_run creation was vulnerable to symlink attacks) Tue Jul 4 20:56:30 MEST 2000 Gert Doering (gert@greenie.muc.de) * cnd.c: add NMBR= format for Digi DataFire RAS Tue Nov 02 15:23:52 1999 Gert Doering (gert@greenie.muc.de) * login.c: add \Y hack (simplar to \I) to get CallerID in ut_host field Sat Jul 31 22:10:09 1999 Gert Doering (gert@greenie.muc.de) * faxlib.c: distinguish Elink 310 and Elink 343 Sat Jul 22 11:23:29 2000 Marc SCHAEFER * SGML FAQ update. Sat Jul 24 23:25:17 1999 Gert Doering (gert@greenie.muc.de) * release 1.1.21 * ring.c: accept a few additional caller/called ID formats Mon Jun 07 22:42:29 1999 Gert Doering (gert@greenie.muc.de) * ring.c: fix bug with CalledNr saving if msn_list is empty Thu May 27 15:49:11 1999 Gert Doering (gd@medat.de) * frontends/www/: check in latest version (view both queues) * fax/faxspool.in: implement calling of external programs to do the G3 conversion (fall back to internal functions) Sat May 22 13:37:28 1999 Gert Doering (gd@medat.de) * fax/faxrunqd.in: phase II of "write combining" done (send multiple faxes to one number in one sendfax call) Sun May 09 13:05:50 1999 Gert Doering (gert@greenie.muc.de) * ring.c: count "NMBR =" line as "RING", so answering is quicker even when waiting for the Caller ID line to come in. Sat May 01 22:20:15 1999 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: restructure code to handle multiple jobs to same phone number (preparations for "write combining") Sun Feb 28 14:26:08 1999 Gert Doering (gert@greenie.muc.de) * mg_m_init.c: add need-dsr / DSR+CTS test loop (modem off) * conf_mg.h, conf_mg.c: add need-dsr flag * fax/faxrunqd.in: fix "pid file" handling bug (recognize own PID) Wed Feb 24 14:05:58 1999 Gert Doering (gd@medat.de) * conf_mg.h, conf_mg.c: add data-flow/fax-send-flow/fax-rec-flow * conf_sf.h, conf_sf.c: add fax-send-flow/fax-rec-flow * config.c: implement CT_FLOWL (flow control definition) * mgetty.h, tio.h: move FLOW_* definitions to mgetty.h * config.h, login.c: fix non-ANSI-C bugs Tue Feb 16 21:10:31 1999 Gert Doering (gert@greenie.muc.de) * frontends/www/faxsend.in: finish first cut * conf_mg.c, login.c, mgetty.c: make login.config run-time configurable Sat Feb 13 13:19:18 1999 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: implement -V * fax/faxrunqd.in, faxrunq.in: write program name to .last_run Sun Jan 17 18:22:48 1999 Gert Doering (gert@greenie.muc.de) * implement automatic PGP signing of created tarballs * release 1.1.20 * login.c: log warning if too many command line arguments given Sat Jan 16 18:19:36 1999 Gert Doering (gert@greenie.muc.de) * frontends/www: detail fixes, some new features * contrib/ptylogin/: add Marc Schaefer's ptylogin program, for securing modem/shell access to really untrustworthy people. Tue Jan 12 14:39:15 1999 Gert Doering (gert@greenie.muc.de) * cnd.c: accept ELSA (V25bis?) multi-line responses +MCR/+MRR * faxrec.c: log number of sent pages (for polling) * policy.h: change comments for EXEC_FUSER * mgetty.c: remove #ifndef linux (et al) around EXEC_FUSER Sun Dec 06 20:06:35 1998 Igor Sysoev (gert@greenie.muc.de) * locks.c: fix internal race condition (that could lead to deleteding "foreign" lock files) Tue Nov 24 21:09:05 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.19 * frontends/www/faxhists.cgi: new search function (for acct.log) Sun Nov 22 11:05:58 1998 Gert Doering (gert@greenie.muc.de) * faxlib.c: add Zoom/NX autodetection * frontends/www: fine tuning, better error messages, modularity Thu Nov 19 22:30:43 1998 Gert Doering (gert@greenie.muc.de) * ring.c: merge ISDN MSN/CallerID for Zoom/NX (Thomas Schuett) Thu Nov 12 16:26:59 1998 Gert Doering (gert@greenie.muc.de) * merge Debian documentation/faxrunq.config updates * frontends/www: 'make install' works now Tue Oct 13 17:24:20 1998 Gert Doering (gert@greenie.muc.de) * frontends/www: more work on the WWW GUI * faxlib.c: ignore quote characters in the remote fax id completely (USR modems always send them) Fri Sep 11 11:29:17 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.18 Wed Sep 09 23:22:27 1998 Gert Doering (gert@greenie.muc.de) * merge Marc's latest voice/ tree * some work on frontends/www/ Mon Sep 07 08:57:16 1998 Gert Doering (gert@greenie.muc.de) * mg_m_init: if TIOCSCTTY fails and getppid() != 1, log a warning "must run mgetty from /etc/inittab" (Russell King). Tue Sep 01 12:09:16 1998 Gert Doering (gert@greenie.muc.de) * mgetty.c: after "waiting...", call log_close() to make sure that the log file is properly reopened (could have been moved away by "savelog" etc. in the meantime) (Phil Hands/Debian) * logfile.c: add log_close() function * ring.c: fix 'forgetting of dist_ring number' bug (Joerg Friedrich) * logname.c(ln_escape_prompt): add some more escape sequences to get same features as 'agetty' (Phil Hands/Debian) Fri Aug 28 16:23:49 1998 Gert Doering / Simone Demmel * frontends/www/: work on WWW GUI Tue Aug 11 16:34:19 1998 Gert Doering (gd@medat.de) * fax/faxrunq.in: implement $max_fail_total, restructure code Fri Aug 07 19:41:39 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.17 Mon Aug 03 22:02:16 1998 Gert Doering (gert@greenie.muc.de) * policy.h: remove FAXSEND_NO_XON * doc/mgetty.texi-in: document "modem-quirks" * mgetty.c(main): implement "post-init-chat" for modems that forget some part of their setup during fax/voice initialization * conf_mg.c, conf_mg.h: add "post-init-chat" command Sun Aug 02 22:50:53 1998 Gert Doering (gert@greenie.muc.de) * mgetty.c: remove all "RING A" / "RING 1" etc. action items -- they will break the new distinctive RING code in ring.c (found by Gord Lamb) Tue Jul 21 00:03:18 1998 Frank D. Cringle (fdc@cliwe.ping.de) * fax/faxrunqd.in: get rid of "not reached" warning after exec() Thu Jul 16 11:24:30 1998 Gert Doering (gert@greenie.muc.de) * README.1st: point to the mailing list Sun Jul 05 22:28:05 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.16 (this bug is just too embarassing) * doc/mgetty.texi-in: rewrite US Robotics chapter * policy.h, doc/mgetty.texi-in, doc/modems.db: remove all references to FAX_SEND_IGNORE_CARRIER, this is really better done using sendfax.config. * conf_sf.c: make "ignore-carrier yes" the default value * ring.c: fix bug with standalone CallerID/RING (Florian La Roche) Thu Jul 02 11:42:54 1998 Gert Doering (gd@medat.de) * release 1.1.15 (on time for the C't magazine article) * sendfax.c: better logging for command line errors * conf_sf.c, conf_sf.h: add fax_max_speed/fax_min_speed/-M * sendfax.c: use fax_max_speed settings * conf_mg.c, conf_mg.h: add fax_max_speed/fax_min_speed * mgetty.c, mgetty.c, mg_m_init.c: use fax_max_speed settings Fri Jun 19 22:30:02 1998 Gert Doering (gert@greenie.muc.de) * cnd.c: add 'CallName' to call to 'cnd-program' Wed Jun 17 11:37:52 1998 Gert Doering (gert@greenie.muc.de) * Makefile, tio.h: throw away AIX3_FLOW, use '!_AIX41' instead * login.cfg.in: clarify comments, remove 'kdebug 7' * mgetty.c: change call to vgetty_answer to use new dist_ring flag Mon Jun 01 14:08:56 1998 Gert Doering (gert@greenie.muc.de) * cnd.c: implement cnd_call() [using system(), so beware...] * mgetty.c: call "cnd_call" (in cnd.c) to decide upon call acception * conf_mg.c, conf_mg.h: add "cnd-program" option * doc/mgetty.texi-in: document "cnd-program" (CallerID/mgetty.config) * callback/callback.c: fix stupid bug with "+" and "?" precendence, implement "-d" option (thanks to Gabor J. Toth) Mon May 25 13:49:19 1998 Gert Doering (gd@medat.de) * fax/faxrunq.in, faxrunqd.in: put job number (F...) into acct.log Sat May 09 16:36:52 1998 Gert Doering (gert@greenie.muc.de) * mgetty.h, logname.c: fix from Olaf Kirch to accept PPP frames with escaped "ALL STATIONS" byte (0xFF). Sat May 02 20:51:32 1998 Gert Doering (gert@greenie.muc.de) * ring.c: save ISDN MSN to CalledNr * cnd.c: new global variable, "CalledNr" for called number (MSN) * mgetty.c: pass information about "callback?" to login_dispatch() Thu Apr 23 20:18:06 1998 Gert Doering (gd@medat.de) * fax/faxrunqd.in: make faxrunqd more robust in case of modem outages, and make it load-balance jobs better. Sat Apr 18 23:32:19 1998 Gert Doering (gert@greenie.muc.de) * cnd.c: add support for "Kortex Adaptix" CallerID format * conf_mg.c, conf_mg.h: add "msn-list" option * ring.c: implement MSN -> distinctive RING mapping Fri Apr 17 09:35:49 1998 Gert Doering (gert@greenie.muc.de) * ring.c: implement ELSA and ZyXEL-I CallerID/MSN display * ring.c: adapt to USR type B CallerID: "RING 12345" * fax/faxspool.in: use "wc -w", not "wc -l" (Joseph Kwok). Wed Apr 15 21:49:56 1998 Gert Doering (gert@greenie.muc.de) * mgetty.c, mgetty.h: use wait_for_ring() instead of do_chat() now [no support for distinctive RING yet]. Mon Apr 13 20:00:44 1998 Gert Doering (gert@greenie.muc.de) * ring.c: start work on RING handler rewrite Sun Apr 05 15:11:49 1998 Gert Doering (gert@greenie.muc.de) * logname.c: replace \Y in /etc/issue with the Caller ID Thu Apr 02 18:45:13 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.14 * mgetty.c: recognize "RING U" as A_RING5 (Nick Holloway) * logname.c, g3/g32pbm.c: fix some warnings (Florian La Roche) Wed Apr 01 20:05:28 1998 Gert Doering (gert@greenie.muc.de) * Makefile, ftp.sh: gzip diffs before uploading * Makefile, doc/mgetty.texi: new master FTP site: alpha.greenie.net Sat Mar 28 22:29:08 1998 Gert Doering (gert@greenie.muc.de) * release 1.1.13 Thu Mar 26 10:04:20 1998 Gert Doering (gert@greenie.muc.de) * cnd.c: repair ELSA CID support * frontends/dialog/: remove listen.in, doesn't work anymore * Makefile: remove all references to VOICE_DIR Sat Mar 14 19:25:31 1998 Gert Doering (gert@greenie.muc.de) * cnd.c: add [preliminary] support for ELSA ISDN Caller-ID * fax/faxrunqd: new scheduler with all bells and whistles done Fri Feb 06 17:19:23 1998 Gert Doering (gd@medat.de) * fax/faxrunqd: first cut of new scheduler / queue manager Tue Jan 27 12:34:36 1998 Gert Doering (gd@medat.de) * release 1.1.12 * new voice tree from Marc * fax/faxrunqd: preparations for new per-modem queues Tue Jan 20 11:40:40 1998 Gert Doering (gd@medat.de) * fax/faxrunqd: change format of "faxrunqd.policy" file * tools/ltest.c: add -d, -k options (RTSL) * tio.c: implement tio_set_rs232_lines() (for systems with the TIOCMBI[CS] ioctl() calls) Sun Jan 18 18:08:35 1998 Gert Doering (gert@greenie.muc.de) * mg_m_init.c: add detection for "setserial spd_hi/spd_vhi" and warn user if this is active (use of setserial is deprecated) Fri Dec 19 17:06:55 1997 Gert Doering (gd@medat.de) * sendfax.c: add better logging (L_AUDIT) for "failed startups" Tue Dec 16 12:35:47 1997 Gert Doering (gert@greenie.muc.de) * release 1.1.11 * voice/: revert to 1.1.9 * div: put single quotes around all occurences of "caller=" in L_AUDIT messages - may contain whitespace. * logfile: do not convert trailing \n for L_AUDIT lines to "_" Mon Dec 15 00:22:04 1997 Gert Doering (gert@greenie.muc.de) * class1.c, class1lib.c, class1.h: preliminary work for class 1 support Fri Dec 12 15:12:49 1997 Gert Doering (gert@greenie.muc.de) * fax/faxrunq.in: change format of 'acct.log' into a more machine- readable form (same as faxrunqd uses) * sendfax.c, faxlib.c: add necessary "hooks" for first class 1 implementation * class1lib.c: start low-level class 1 work Wed Dec 10 12:52:13 1997 Gert Doering (gd@medat.de) * fax/faxrunqd.in: use age of job in sorting queue (to prevent starving very long jobs on very busy machines) * fax/faxrunqd.in: correctly handle case if sendfax is killed by an unexpected/uncaught signal. * fax/faxq.in: add "-P" option, create .queue-changed if -r/-P used * fax/faxrunqd.in: if $FAX_SPOO_OUT/.queue-changed exists, flush in-memory queue and re-read fax queue from disk Tue Dec 09 13:31:19 1997 Gert Doering (gert@greenie.muc.de) * frontends/voice: add am_tools.tar (answering machine) * faxlib.c: add 56k Rockwell modems (ATI -> 56000) * faxsend.c, policy.h: FAXSEND_NO_XON is obsolete, use "modem-quirks 0x08" in sendfax.config instead. Sun Dec 07 13:50:01 1997 Gert Doering (gert@greenie.muc.de) * release 1.1.10 * voice/: fix minor build problems on SCO. Sat Dec 06 00:45:17 1997 Gert Doering (gert@greenie.muc.de) * conf_mg.c, conf_mg.h, conf_sf.c, conf_sf.h: add "modem-quirks" * conf_mg.c: fix accident "fallthrough" for "-b" * modem.c (mdm_get_idstring): never return NULL, use "" * faxlib.c,sendfax.c: add new modem type (auto1), start playing with modem capability identification via AT+FCLASS=? Thu Dec 04 12:48:22 1997 Gert Doering (gert@greenie.muc.de) * faxlib.c: add auto-detection for USR V.32terbo/fax bugs * fax/faxrunqd.in: add "policy routing" feature Tue Dec 02 17:21:48 1997 Gert Doering (gert@greenie.muc.de) * sendfax.c, mgetty.c: be more paranoid about queue flushing when exit()ing after modem initialization failure Fri Nov 28 11:31:10 1997 Gert Doering (gd@medat.de) * faxlib.c: prepare for class 2.1/V.34 speeds * mgetty.c: write user ID and parent PID to log file (diagnosis) Wed Nov 26 18:05:20 1997 Gert Doering (gert@greenie.muc.de) * conf_sf.c: implement '-D' as command-line option to set 'dial-prefix' Tue Nov 18 11:57:46 1997 Gert Doering (gd@medat.de) * fax_lib.h, faxlib.c: make FAX_USRobotics a "modem quirks" flag * mgetty.h: on GLIBC 2.x systems, use HAVE_SIGINTERRUPT, otherwise timeout handling breaks (glibc restarts system functions) Sat Nov 15 21:15:36 1997 Gert Doering (gert@greenie.muc.de) * fax/faxrunqd.in: scheduler tweaks, SIGUSR2, logging, config Tue Nov 11 21:24:46 1997 Gert Doering (gd@medat.de) * fax/faxrunqd.in: smarter scheduling for many jobs on many modems Mon Nov 03 10:01:24 1997 Gert Doering (gert@greenie.muc.de) * voice/: switch over to remote-CVS Sat Nov 1 17:31:37 MET 1997 Gert Doering (gert@greenie.muc.de) * policy.h: make /var/log/sendfax.log the default for FAX_LOG Fri Oct 31 13:54:39 1997 Gert Doering (gert@greenie.muc.de) * doc/mgetty.texi-in: add warning about recent Rockwelloid junk. * faxlib.c, faxrecp.c: if modem autodetect finds a Rockwell modem (ATI returns 28800 or 33600), disable line quality check, because Rockwell modems usually don't understand AT+FPS=2. Junk. * sendfax.c, conf_sf.h, conf_sf.c: add "open-delay " option * fax/faxrunqd.in: start external processes with " 28800 and ATI3 -> "": assume Dr.Neuhaus Cybermod * config.c: accept negative numbers for CT_INT as well Thu Jun 05 23:20:37 1997 Frank Bartels (knarf@camelot.de) * policy.h: default for the log files is now /var/log/mgetty.ttyX Tue May 27 23:35:36 1997 Andreas Jaeger (aj@arthur.rhein-neckar.de) * tools/ltest.c: fix compiler warnings and "return 0" * Makefile: add comment to link "-lutil" on Linux / GNU Libc 2.0 * utmp.c: use updwtmp() on GNU Libc 2.0 systems Mon May 26 23:41:33 1997 Roeland Th. Jansen (bengel@xs4all.nl) * magic.o: prevent cats from logging into the computer Sat May 24 20:29:39 1997 Gert Doering (gert@greenie) * mgetty.c (St_go_to_jail): fix wrong resetting of CallerId * fax/faxrm.in: remove .source-files subdirectory, if existant Mon May 19 21:23:39 1997 Gert Doering (gert@greenie) * faxlib.c: add ATI code for USR 56K modems (5601) * cnd.c: fix typo in CallerID variable name Fri May 09 11:35:17 1997 Gert Doering (gert@greenie) * faxlib.c: chop off leading whitespace of fax_station_id Mon May 05 19:13:14 1997 Gert Doering (gert@greenie) * release 1.1.6 * Makefile: generate version diffs now (finally) Sat May 03 19:06:17 1997 Gert Doering (gert@greenie) * faxlib.c: rewrite modem identify function to use mdm_get_idstring for ATI, and maybe ATI1, ATI3, ..., for more detailed information about *this* modem type (firmware etc.) [see log files] * modem.c: new function: mdm_get_idstring() * modem.c: change mdm_command timeout to 10 seconds * cnd.c: add better logging * faxlib.c: add recognition of ZyXEL Omni.NET (ATI: 1281/1292) Thu Apr 17 17:33:40 1997 Gert Doering (gert@greenie) * fax/faxq: print "priority" field, if set in the JOB file * fax/faxspool: implement -P option (for faxrunqd) Wed Apr 16 11:06:03 1997 Gert Doering (gert@greenie) * release 1.1.5 * voice/: new voice code beta Sat Apr 12 16:47:42 1997 Gert Doering (gert@greenie) * tools/ltest.c: fix fcntl() call * faxlib.c: add all modem "ATI" codes that I know of (so far) * faxlib.c: preliminary support for modem type auto-detection with ATI (*very* preliminary) * callback/callback.c: drain output queue before signalling mgetty Thu Apr 10 10:13:34 1997 Gert Doering (gert@greenie) * voice/vgetty/Makefile: link ../../faxrecp.o * Makefile: call mkidir with "./mkidir" (if "." is not in $PATH) Sun Apr 6 17:26:41 1997 Gert Doering (gert@greenie) * logfile.c (sprintf): convert non-printable characters to '_' * release version 1.1.4 * mgetty.c (main): undo the "modem-check-time" change. If you use mgetty on direct serial lines, set "modem-check-time -1" in policy.h. Wed Apr 02 19:40:46 1997 Gert Doering (gert@greenie) * Makefile, tools/Makefile: fix bugs with move of "kvg" * revoke 1.1.3, because of stupid bugs that will cause many questions Mon Mar 31 15:06:42 1997 Gert Doering (gert@greenie) * release version 1.1.3 * sendfax.c: print meaningful message on non-class2/2.0 modems. * faxlib.c: remove special handling of "ERROR" response in class 2.0 (it can only happen after end-of-page is sent, and this is already handled in fax_send_ppm), because sometimes the USR Courier sends ERROR after ATD, and this confuses sendfax (*ugly*). * faxlib.c: add faxlib_init() to re-initialize everything * mgetty.c, faxrec.c: do the ATH0 command in "mgetty.c" (don't interfere with reception of multiple faxes from voice apps) * faxlib.c: accept "NO DIALTONE" and "NO DIAL TONE" (USR special) Fri Mar 28 13:55:18 1997 Kim-Minh Kaplan (gert@greenie) * mgetty.c: don't use "modem-check-time" on direct lines (-r) Wed Mar 26 12:45:57 1997 Gert Doering (gert@greenie) * tools/ltest.c: new line tester, to show RS232 status * contrib/g3hack.c: is now in frontends/X11/viewfax*/g3hack.c * Makefile: clean up some comments * mgetty.c: protect printing of issue file with alarm() [Knarf] Mon Mar 24 21:06:58 1997 Steffen Reith (gert@greenie) * conf_sf.c: make FAX_SEND_IGNORE_CARRIER the default value for "ignore-carrier y/n" in sendfax.config Thu Mar 20 12:52:25 1997 Bjarne Kvamme (gert@greenie) * faxsend.c: remove locks on panic_exit, use exit(15) not (11) Sun Mar 09 10:57:19 1997 Gert Doering (gert@greenie) * Makefile: use "mkidirs" for directory creation - "make bindist" works now even with "unsual" path settings Sun Mar 02 12:15:24 1997 Gert Doering (gert@greenie) * tools/, g3/: move "tools" directory to "g3", create new "tools" directory for auxiliary utilities like "kvg" or "ltest". Mon Feb 24 22:18:03 1997 Gert Doering (gert@greenie) * faxrec.c, faxrecp.c: split "protocol" and "high level" functions * Makefile: sendfax links faxrecp.o only, mgetty links both * faxrec.c: add creation of UTMP record for incoming faxes ("last") Thu Feb 20 11:17:11 1997 Gert Doering (gert@greenie) * release 1.1.2 * voice/: add new voice tree from Marc Mon Feb 17 21:36:04 1997 Gert Doering (gert@greenie) * mksed.c: add @NOLOGIN@ * doc/mgetty.8in: add description of /etc/nologin.ttyxx Sun Feb 02 23:44:00 1997 Gert Doering (gert@greenie) * Makefile: split $LDFLAGS into $(LDFLAGS) (in front of the linker command line) and $(LIBS) (after all the object files) Wed Jan 22 20:58:40 1997 Gert Doering (gert@greenie) * config.c (get_config): log name of config file being read Mon Jan 20 11:37:30 1997 Gert Doering (gert@greenie.muc.de) * release 1.1.0 mgetty-1.1.36/policy.h-dist0100644000031200001470000005164410634431301014023 0ustar gertfax#ident "$Id: policy.h,v 4.24 2006/03/22 14:05:32 gert Exp $ Copyright (c) Gert Doering" /* this is the file where all configuration defaults for mgetty / sendfax * are specified. * * defaults are used if no values are given in the config file(s). * config file values can be overridden by command line options. * * see mgetty.texi/mgetty.info for a description of the configuration files. */ /* main mgetty configuration file */ #define MGETTY_CONFIG "mgetty.config" /* sendfax configuration file * * if path doesn't start with "/", it's relative to CONFDIR (Makefile) * if not defined, no configuration file is read (saves a few kbytes) */ #define SENDFAX_CONFIG "sendfax.config" /* login dispatcher config file (for mgetty) * * In this file, you can configure which "login" program (default /bin/login) * to call for what user name. * * You could use it to call "uucico" for all users starting with "U*" * (works only with Taylor UUCP 1.04 with my patch), for AutoPPP calls * being properly dispatched to pppd, or to call a fido mailer for fido * calls (only if AutoPPP and/or FIDO support are compiled in, see below)... * * If you want to call /bin/login for all data calls, do not define this * * See the samples in the example login.config file (built from login.cfg.in). * * WARNING: make sure that this file isn't world-accessable (SECURITY!) * * If this doesn't start with "/", it's relative to CONFDIR. */ #define LOGIN_CFG_FILE "login.config" /* default login program * * If LOGIN_CFG_FILE is not defined, or does not exist, or doesn't * have a default entry, this program is called for user logins. * Normally, this is "/bin/login", just a few systems put "login" * elsewhere (e.g. Free/NetBSD in "/usr/bin/login"). */ #define DEFAULT_LOGIN_PROGRAM "/bin/login" /* FidoNet mailer support * * If you want to support incoming FidoNet calls, define FIDO. * * (If you don't know what this is, you don't want it) */ /* #define FIDO */ /* AutoPPP-Support * * If you want to auto-detect incoming PPP calls (with authorization done * by the pppd, i.e. via CHAP or PAP), define AUTO_PPP. * Not needed if PPP callers want to get a real "login:" * prompt first. Don't forget to activate the /AutoPPP/ line in login.config! */ /* #define AUTO_PPP */ /* callback config file * * this file controls the operation of the optional "callback" program. * how callback works, is explained in detail in mgetty.texi. You need * to set LOGIN_CFG_FILE (see above) to use callback from mgetty. * * If this path does not start with "/", it's relative to CONFDIR. */ #define CALLBACK_CONFIG "callback.config" /* if this file exists, it can be used to control what callers * are allowed in. If undefined, the functionality is omitted. * It will work only if your modem supports it. Check the modem manual. * For Rockwell-Based modems, add #CID=1 to MODEM_INIT_STRING, for * ZyXELs use S40.2=1. * If the path doesn't start with "/", it's relative to CONFDIR. */ /* #define CNDFILE "dialin.config" */ /* If you want to use /etc/gettydefs to set tty flags, define this * I recommend against it, I suspect some bugs lingering in that code * (and one doesn't really need it in a normal setup anyway). */ /* #define USE_GETTYDEFS */ /* Name of the "gettydefs" file (used only if USE_GETTYDEFS is set) */ #define GETTYDEFS "/etc/gettydefs" /* If no gettydefs "tag" is specified on the command line, use * this setting (from GETTYDEFS) as default (only if compiled with * USE_GETTYDEFS set) */ #define GETTYDEFS_DEFAULT_TAG "n" /* access modes */ /* user id of the "uucp" user. The tty device will be owned by this user, * so parallel dial-out of uucico will be possible */ #define DEVICE_OWNER "uucp" /* group id that the device is chown()ed to. If not defined, the * primary group of "DEVICE_OWNER" is used. */ #define DEVICE_GROUP "modem" /* access mode for the line while getty has it - it should be accessible * by uucp / uucp, but not by others (imagine someone dialing into your * system and using another modem to dial to another country...) */ #define FILE_MODE 0660 /* security: optionally, mgetty can system() this, to kill any dangling * processes on the current tty. A %s is replaced with the tty device. * * Under most circumstances, this is not needed. You might want * to use it if you offer dial-in services with shell accounts to people * that you don't trust (they might try to abuse your modems, and this * will stop a number of attacks). */ /* #define EXEC_FUSER "exec fuser -k -f %s >/dev/null 2>&1" */ /* logging */ /* system console - if a severe error happens at startup, mgetty writes * a message to this file and aborts * On SCO, this may be /dev/syscon! */ #define CONSOLE "/dev/console" /* Name of the mgetty log file * e.g. "/usr/spool/log/mgetty.log.%s" or "/tmp/log_mg.%s" * a "%s" will be replaced by the device name, e.g. "tty2a" * * if the directory does not exist, the log file goes to CONSOLE (!) */ #define LOG_PATH "/var/log/mgetty.%s" /* Default log error level threshold. Possible error levels are * L_FATAL, L_ERROR, L_AUDIT, L_WARN, L_MESG, L_NOISE, L_JUNK (see mgetty.h) */ #define LOG_LEVEL L_MESG /* Whether "\n"s in the modem response should start a new line * in the logfile */ /* #define LOG_CR_NEWLINE */ /* System administrator - if a severe error happens (lprintf called * with log_level L_FATAL) and writing to CONSOLE is not possible, * the logfile will be mailed to him */ #define ADMIN "root" /* Syslog * * If you want logging messages of type L_AUDIT, L_ERROR and L_FATAL * to go to the "syslog", define this. * mgetty will use the facility "LOG_AUTH", and the priorities * LOG_NOTICE, LOG_ERR and LOG_ALERT, respectively. */ /* #define SYSLOG */ /* Syslog facility * * This is the facility mgetty uses for logging. Ususally, this will be * LOG_AUTH, but on some systems, this may not exist, try LOG_DAEMON * instead (or look into the syslog manpage for available options) */ #define SYSLOG_FC LOG_AUTH /* login stuff */ /* System name - printed at login prompt * If you do not define this, the uname() call will be used */ /* #define SYSTEM "greenie" */ /* Login prompt * The "@", "\\D" and "\\T" escapes will be replaced by SYSTEM, the * current date and time, respectively. * override with "-p " switch */ #define LOGIN_PROMPT "@!login: " /* The old '#define ENV_TTYPROMPT' option has been superseded by setting * "login-env-ttyprompt-hack yes" in mgetty.config. See mgetty.texi for * details. */ /* Some very old terminals can only generate UPPERCASE letters. * Traditional getty variants detect this, and then set the * corresponding termio(s) flags to convert upper/lower case letters * "on the fly". Mgetty can do it, but since this is hardly * needed nowadays, the default is off. */ /* #define DO_LCUC_MAP */ /* Maximum time before login name has to be entered (in seconds) * (after that time a warning will be issued, after that, the call is * dropped). To disable that feature, do not define it. */ #define MAX_LOGIN_TIME 240 /* nologin file * * If that file exists, a ringing phone won't be answered (see manual). * "%s" will be replaced by the device name. */ #define NOLOGIN_FILE "/etc/nologin.%s" /* misc */ /* Path for the lock files. A %s will be replaced with the device name, * e.g. tty2a -> /usr/spool/uucp/LCK..tty2a * Make sure that this is the same file that your uucico uses for * locking! */ /* for a few systems, you can just take those defaults and be happy */ #if defined (SVR4) || defined(sunos4) # define LOCK_PATH "/var/spool/locks" # define LOCK "/var/spool/locks/LCK..%s" #else # ifdef sgi # define LOCK "/usr/spool/locks/LCK..%s" # endif # ifdef _AIX # define LOCK "/etc/locks/LCK..%s" # endif # ifdef NeXT # define LOCK "/usr/spool/uucp/LCK/LCK..%s" # endif # ifdef linux # define LOCK "/var/lock/LCK..%s" # endif # if defined(__FreeBSD__) || defined(__NetBSD__) # define LOCK "/var/spool/lock/LCK..%s" # endif #endif /* if your system isn't listed above, change that line here */ #ifndef LOCK #define LOCK "/usr/spool/uucp/LCK..%s" #endif /* Set this to "1" if your system uses binary lock files (i.e., the pid * as four byte integer in host byte order written to the lock file) * If it is "0", HDB locking will be used - the PID will be written as * 10 byte ascii, with a trailing newline * (Just check "LOCK" while uucico or pcomm or ... are running to find * out what lock files are used on your system) * On NeXT systems, you must set this to "1". */ #define LOCKS_BINARY 0 /* Lower case locks - change the last character of the device name * to lowercase for locking purposes. * * If you're using a SCO Unix system with those "tty1a/tty1A" device * pairs, you'll have to define this. */ /* #define LOCKS_LOWERCASE */ /* Change _all_ characters to lowercase (currently no system uses this) */ /* #define LOCKS_ALL_LOWERCASE */ /* the default speed used by mgetty - override it with "-s " * * WARNING: this is a bit tricky, since some modems insist on going to * 19200 bps when in fax mode. So, if fax receiving with a port speed of * something else doesn't work, try experimenting with FAX_RECV_SWITCHBD, * and if that doesn't help, try DEFAULT_PORTSPEED 19200 * * WARNING2: Speeds higher than 38400 aren't supported on all platforms, * and sometimes you have to use "50" to get 57600 or so! */ #define DEFAULT_PORTSPEED 38400 /* the modem initialization string * * the default string should set up most hayes compatible modems into a * fairly sane state (echo on, verbose reports on, quiet off, reset on * DTR toggle on), but it doesn't set any flow control options (because * that's done differently on each modem, look into your manual for commands * like &H3, &K4, \Q6 or similar things) or protocols. * * You can change the initialization sequence with the "init-chat" keyword * in "mgetty.config". * * If you need delays, specify them as "\\d", if you want to send a * backslash ('\'), give it as "\\\\". * * Very IMPORTANT: make sure that the modem assigns the DCD line properly, * usually this is done with the AT&C1 command! * * The modem must answer with "OK" (!!!) - otherwise, use "init-chat". */ #define MODEM_INIT_STRING "ATS0=0Q0&D3&C1" /* command termination string * * for most modems, terminating the AT... command with "\r" is * sufficient and "\r\n" also works without doing harm. * Unfortunately, for the Courier HST, you've to use *only* \r, * otherwise ATA won't work (immediate NO CARRIER), and for some * (old) ZyXELs, you have to use \r\n (no OK otherwise). * So, try one, and if it doesn't work, try the other. */ #define MODEM_CMD_SUFFIX "\r" /* "keep alive" * * mgetty can periodically check whether the modem is still alive * by issueing an "AT\r" command and checking for the "OK" * Define here, in seconds, how often mgetty should check. For normal * reliable modems, once an hour should be sufficient... * If you use "-1", or don't define this at all, mgetty won't check. */ #define MODEM_CHECK_TIME 3600 /* modem mode * * DEFAULT_MODEMTYPE specifies the default way mgetty+sendfax handle a * faxmodem. You have four choices: * "data" - data only, no faxing available (for sendfax, equal to "auto") * "cls2" - use AT+FCLASS=2 * "c2.0" - use AT+FCLASS=2.0 * "auto" - try "2.0", then "2", then fall to "data". * * Normally, you can leave this to "auto", but if you have a modem that * can do class 2.0 and class 2, and 2.0 doesn't work, then you could try * setting it to "cls2". * You can override this define with the "-C " switch. */ #define DEFAULT_MODEMTYPE "auto" /* some modems are a little bit slow - after sending a response (OK) * to the host, it will take some time before they can accept the next * command - specify the amount needed in data mode here (in * milliseconds). Normally, 50 ms should be sufficient. (On a slow * machine it may even work without any delay at all) * * Be warned: if your machine isn't able to sleep for less than one * second, this may cause problems. */ #define DO_CHAT_SEND_DELAY 50 /* and this is the delay before sending each command while in fax mode */ #define FAX_COMMAND_DELAY 50 /* incoming faxes will be chown()ed to this uid and gid. * if FAX_IN_GROUP is undefined, the group of ...OWNER is used. */ #define FAX_IN_OWNER "uucp" /* #define FAX_IN_GROUP "root" */ /* incoming faxes will be chmod()ed to this mode * (if you do not define this, the file mode will be controlled by * mgetty's umask) */ #define FAX_FILE_MODE 0660 /* FLOW CONTROL * * There are basically two types of flow control: * - hardware flow control: pull the RTS/CTS lines low to stop the other * side from spilling out data too fast * - sofware flow control: send an Xoff-Character to tell the other * side to stop sending, send an Xon to restart * obviously, use of Xon/Xoff has the disadvantage that you cannot send * those characters in your data anymore, but additionally, hardware flow * control is normally faster and more reliable * * mgetty can use multiple flow control variants: * FLOW_NONE - no flow control at all (absolutely not recommended) * FLOW_HARD - use RTS/CTS flow control (if available on your machine) * FLOW_SOFT - use Xon/Xoff flow control, leave HW lines alone * FLOW_BOTH - use both types simultaneously, if possible * * Note that few operating systems allow both types to be used together. * * mgetty won't (cannot!) notice if your settings don't work, but you'll * see it yourself: you'll experience character losses, garbled faxes, * low data throughput,..., if the flow control settings are wrong * * If in doubt what to use, try both and compare results. * (if you use FAS or SAS with the recommended settings, FLOW_HARD is a * "don't care" since the driver will use RTS/CTS anyway) * * If you use an atypical system, check whether tio_set_flow_control in * tio.c does the right thing for your system. */ /* This is the flow control used for normal data (login) connections * Set it to FLOW_HARD except in very special cases. */ #define DATA_FLOW FLOW_HARD /* This is the flow control used for incoming fax connections * Wrong settings will result in missing lines or erroneous lines * in most of the received faxes. * Most faxmodems expect Xon/Xoff, few honour the RTS line. */ #define FAXREC_FLOW FLOW_HARD | FLOW_SOFT /* And this is for sending faxes * * Wrong settings here will typically result in that the first few * centimeters of a transmitted fax look perfect, and then (the buffer * has filled up), the rest is more or less illegible junk. * For most faxes, this has to be FLOW_SOFT, though the Supra and ZyXEL * modems will (sometimes) do hardware flow control, too. Try it. * * If you see a large number of [11] and [13] characters in the sendfax * log file, your modem is propably doing software flow control - and * you've definitely set FAXSEND_FLOW to FLOW_HARD... * * Some versions of SCO Unix have a "weird" serial driver that will only * do half duplex hardware flow control. You will then run into the problem * that fax sending will time out after the first page sent (no ACK received) * and fail if FLOW_HARD is used. Use FLOW_SOFT instead. */ #define FAXSEND_FLOW FLOW_HARD | FLOW_SOFT /* if your faxmodem switches port bit rate just after sending the "+FCON" * message to the host, define this to contain the baudrate used. (Not * important if you have the portspeed set to this value anyway). * * Most Rockwell-based modems need FAX_RECV_SWITCHBD 19200. * ZyXELs do *not* need this, except if explicitely told to do so. * * You can see if this is set wrong if mgetty gets the "+FCON" response, * starts the fax receiver, and times out waiting for OK, receiving * nothing or just junk. */ /* #define FAX_RECV_SWITCHBD 19200 */ /* name of the logfile for outgoing faxes (e.g. /var/log/sendfax.log) * * watch out: if you run 'sendfax' as non-privileged user (user 'fax' etc.) * you might need to create this file manually and chown it to 'fax' */ #define FAX_LOG "/var/log/sendfax.log" /* local station ID (your fax number) * 20 character string, most faxmodem allow all ascii characters 32..127, * but some do only allow digits and blank * AT+FLID=? should tell you what's allowed and what not. */ #define FAX_STATION_ID "49 115 xxxxxxxx" /* ------ sendfax-specific stuff follows here -------- */ /* the baudrate used for *sending* faxes. ZyXELs can handle 38400, * SUPRAs (and many other rockwell-based faxmodems) can not. * I recommend 38400, since 19200 may be to slow for 14400 bps faxmodems! */ #define FAX_SEND_BAUD 38400 /* switch baud rate after +FCLASS=2 * * some weird modems require that you initialize the modem with one * baud rate (e.g. 2400 or 9600 for cheap 2400+fax modems, or `smart' * modems that insist on staying locked to 38400 (ELSA!)), but switch * to another baud rate, typically 19200, immediately after receiving * the "AT+FCLASS=2" command. * * If the following is defined, sendfax will switch to the speed given * here after sending AT+FCLASS=2. * * Only try fiddling with this if sendfax times out during modem * initialization, receiving junk instead of "OK" or "ERROR" (logfile!) */ /* #define FAX_SEND_SWITCHBD 19200 */ /* this is the command to set the modem to use the desired flow control. * For hardware handshake, this could be AT&H3 for the ZyXEL, &K3 for * Rockwell-Based modems or AT\\Q3&S0 for Exar-Based Modems (i.e. some GVC's) * If you don't want extra initalization, do not define it. * Don't forget the "AT"! */ /* #define FAX_MODEM_HANDSHAKE "AT&H3" */ /* This is the modem command used for dialing. The phone number will * get appended right after the string. Normally, "ATD" or "ATDP" should * suffice, but in some situations (company telephone systems) you might * need something like "ATx0DT0wP" (switch of dial-tone recognition, tone- * dial a "0", wait for dial-tone, pulse dial the rest) */ #define FAX_DIAL_PREFIX "ATD" /* When sending a fax, if the other side says "page bad, retrain * requested", sendfax will retry the page. Specifiy here the maximum * number of retries (I recommend 3) before hanging up. * * If you set it to "0", sendfax will *never* retransmit a page (only * do this if you know that your modem returns +FPTS:2 even if the * page arrived properly, but be warned - you wont' be able to react * properly to transmission errors!) * * See also the description of the "max-tries" and "max-tries-continue" * settings in the sendfax config file. */ #define FAX_SEND_MAX_TRIES 3 /* the device(s) used for faxing * multiple devices can be separated by ":", e.g. "tty1a:tty2a" * (with or without leading /dev/) * If you don't adapt this for your needs, sendfax won't run (you can * set it from the sendfax.config file, though)! */ #define FAX_MODEM_TTYS "tty4c:tty4d" /* Xon or not? * * the first issues of the class 2 drafts required that the program waits * for an Xon character before sending the page data. Later versions * removed that. Sendfax can do both, default is to wait for it. * * If you get an error message "... waiting for XON" when trying to * send a fax, try this one. Some ELSA modems are know to need it. * * ** THIS OPTION IS OBSOLETE ** * ** use "modem-quirks 0x08" in sendfax.config instead ** */ /* define mailer that accepts destination on command line and mail text * on stdin. For mailers with user friendly interfaces, (such as mail, * mailx, elm), include an appropriate subject line in the command * definition. If using a mail agent (such as sendmail), that reads * mail headers, define NEED_MAIL_HEADERS. */ #ifdef SVR4 # define MAILER "/usr/bin/mailx -s 'Incoming facsimile message'" #else # ifdef _AIX # define MAILER "/usr/sbin/sendmail" # define NEED_MAIL_HEADERS # endif # ifdef M_UNIX /* SCO */ # define MAILER "/usr/lib/mail/execmail" # define NEED_MAIL_HEADERS # endif #endif #ifndef MAILER # define MAILER "/usr/lib/sendmail" # define NEED_MAIL_HEADERS #endif /* where to send notify mail about incoming faxes to * (remember to create an mail alias if no such user exists!) */ #define MAIL_TO "faxadmin" /* after a fax has arrived, mgetty can call a program for further * processing of this fax. * * (e.g.: printing of the fax, sending as MIME mail, displaying in an X * window (the latter one could be tricky) ...) * * It will be called as: * "" <#pgs> ... * * Define the name of this program here * If you don't want this type of service, do not define it at all * Absolute path name has to be used here! */ #define FAX_NOTIFY_PROGRAM "/usr/local/lib/mgetty+sendfax/new_fax" /* default minimum space required on spooling partition for receiving a FAX * (in KILObytes) */ #define MINFREESPACE 1024 /* fax machines exchange so-called "non-standard-frames" that can be * used to identify what vendor and model is on the other end. * mgetty parses and prints this by default, because it can help * troubleshooting - but the tables use up memory. * If you're very tight on RAM, disable this (saves about 10 Kbyte). */ #define FAX_NSF_PARSER mgetty-1.1.36/ftp.sh0100755000031200001470000000133510100530677012536 0ustar gertfax#!/bin/sh # VS="$1" ; HOST=$2 ; DIR=$3 if [ -z "$VS" -o -z "$HOST" -o -z "$DIR" ] ; then echo "Syntax error: $0 " >&2 ; exit 1 fi SRC=mgetty$VS.tar.gz if [ ! -f "$SRC" ] ; then echo "$0: can't find $SRC!" >&2 ; exit 2 fi if expr "$VS" : '[0-9].[13579]' >/dev/null ; then DST=mgetty$VS-`date +%b%d`.tar.gz else DST=mgetty+sendfax-$VS.tar.gz fi scp $SRC $HOST:$DIR/$DST scp $SRC.asc $HOST:$DIR/$DST.asc # find diff's, if any... DIFF=`ls -rt mgetty*-$VS.diff.gz 2>/dev/null |tail -1` #test -n "$DIFF" && DIFF="put $DIFF" test -n "$DIFF" && \ scp $DIFF $HOST:$DIR/$DIFF # normal FTP upload #ftp -v $HOST < # Created: 1993-05-16 # Public domain # $Id: mkidirs,v 1.1 1997/10/30 18:57:15 gert Exp $ umask 022 errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here mgetty-1.1.36/login.cfg.in0100644000031200001470000000522006736077556013627 0ustar gertfax# login.config # # This is a sample "login dispatcher" configuration file for mgetty # # Format: # username userid utmp_entry login_program [arguments] # # Meaning: # for a "username" entered at mgettys login: prompt, call # "login_program" with [arguments], with the uid set to "userid", # and a USER_PROCESS utmp entry with ut_user = "utmp_entry" # # username may be prefixed / suffixed by "*" (wildcard) # # userid is a valid user name from /etc/passwd, or "-" to not set # a login user id and keep the uid/euid root (needed for /bin/login) # # utmp_entry is what will appear in the "who" listing. Use "-" to not # set an utmp entry (a must for /bin/login), use "@" to set it to the # username entered. Maximum length is 8 characters. # # login_program is the program that will be exec()ed, with the arguments # passed in [arguments]. A "@" in the arguments will be replaced with the # username entered. Warning: if no "@" is given, the login_program has # no way to know what user name the user entered. # # # SAMPLES: # Use this one with my Taylor-UUCP and Taylor-UUCP passwd files. # (Big advantage: tuucp can use the same passwd file for serial dial-in # and tcp dial-in [uucico running as in.uucpd]). Works from 1.05 up. # #U* uucp @ /usr/lib/uucp/uucico -l -u @ # # Use this one for fido calls (login name /FIDO/ is handled specially) # # You need Eugene Crosser's "ifmail" package for this to work. # mgetty has to be compiled with "-DFIDO", otherwise a fido call won't # be detected. # #/FIDO/ uucp fido /usr/local/lib/fnet/ifcico @ # # Automatic PPP startup on receipt of LCP configure request (AutoPPP). # mgetty has to be compiled with "-DAUTO_PPP" for this to work. # Warning: Case is significant, AUTOPPP or autoppp won't work! # Consult the "pppd" man page to find pppd options that work for you. # # NOTE: for *some* users, the "-detach" option has been necessary, for # others, not at all. If your pppd doesn't die after hangup, try it. # # NOTE2: "debug" creates lots of debugging info. LOOK AT IT if things # do not work out of the box, most likely it's a ppp problem! # # NOTE3: "man pppd" is your friend! # # NOTE4: max. 9 arguments allowed. # #/AutoPPP/ - a_ppp /usr/sbin/pppd auth -chap +pap login debug # # # An example where no login name in the argument list is desired: # automatically telnetting to machine "smarty" for a given login name # #telnet-smarty gast telnet /usr/bin/telnet -8 smarty # # This is the "standard" behaviour - *dont* set a userid or utmp # entry here, otherwise /bin/login will fail! # This entry isn't really necessary: if it's missing, the built-in # default will do exactly this. # * - - @LOGIN@ @ mgetty-1.1.36/mgetty.cfg.in0100644000031200001470000000320607756216365014026 0ustar gertfax# # mgetty configuration file # # this is a sample configuration file, see mgetty.info for details # # comment lines start with a "#", empty lines are ignored # ----- global section ----- # # In this section, you put the global defaults, per-port stuff is below # set the global debug level to "@LOG_LEVEL@" (default from policy.h) debug @LOG_LEVEL@ # set the local fax station id fax-id @FAX_STATION_ID@ # access the modem(s) with @SPEED@ bps speed @SPEED@ # use these options to make the /dev/tty-device owned by "uucp.uucp" # and mode "rw-rw-r--" (0664). *LEADING ZERO NEEDED!* #port-owner uucp #port-group uucp #port-mode 0664 # use these options to make incoming faxes owned by "root.uucp" # and mode "rw-r-----" (0640). *LEADING ZERO NEEDED!* #fax-owner root #fax-group uucp #fax-mode 0640 # ----- port specific section ----- # # Here you can put things that are valid only for one line, not the others # # Zoom V.FX 28.8, connected to ttyS0: don't do fax, less logging # #port ttyS0 # debug 3 # data-only y # some other Rockwell modem, needs "switchbd 19200" to receive faxes # properly (otherwise it will fail with "timeout"). # #port ttyS1 # speed 38400 # switchbd 19200 # ZyXEL 2864, connected to ttyS2: maximum debugging, grab statistics # #port ttyS2 # debug 8 # init-chat "" \d\d\d+++\d\d\dAT&FS2=255 OK ATN3S0=0S13.2=1 OK # statistics-chat "" AT OK ATI2 OK # statistics-file /var/log/statistics.ttyS2 # modem-type cls2 # direct connection of a VT100 terminal which doesn't like DTR drops # ("direct" meaning "*no* *modem*". NEVER enable "direct yes" on modem lines!) # #port ttyS3 # direct y # speed 19200 # toggle-dtr n mgetty-1.1.36/sendfax.cfg.in0100644000031200000620000000204206426144731014502 0ustar gertgroup# # sendfax configuration file # # this is a sample configuration file, see mgetty.info for details # # comment lines start with a "#", empty lines are ignored # ----- global section ----- # # In this section, you put the global defaults, per-port stuff is below # tell everybody what's going on verbose y # ... and send everything to the log file (quite detailed) debug 5 # which devices to use for outgoing faxes fax-devices @FAX_MODEM_TTYS@ # which fax number to transmit to the receiving station fax-id @FAX_STATION_ID@ # which command is used to dial out? (Could be ATD, ATDP, ATX3D0W...) #dial-prefix ATD # try transmitting every page three times, continue if 3rd try fails as well max-tries 3 max-tries-continue y # ----- port specific section ----- # # Here you can put things that are valid only for one line, not the others # # Modem on ttyS0 needs special initialization to do h/w handshaking #port ttyS0 # modem-handshake AT&K4 # Modem on ttyS1 doesn't work reliably in class 2.0, use class 2 instead #port ttyS1 # modem-type cls2 mgetty-1.1.36/dialin.config0100644000031200001470000000275307265556161014060 0ustar gertfax# dialin.config (CNDFILE in policy.h) # # cndfile contains a series of tokens separated by newlines, commas, tabs # and spaces. The callerid number is compared with each token in turn, # until a match occurs. A match occurs when the token compares equally to # the callerid information up to the length of the token. If the token is # prefixed with a "!", a match means "do not answer the phone". The token # "all" matches any telephone number, and will terminate scanning of the # cndfile. If no callerid number is present, it is assumed to have the # value "none". A line starting with "#" is a comment. There is an # implicit "all" at the end of the file. # # For example: # list of my friends' data lines #3433535, 7445343, 5551212 # # dad's fax #4164646777 # # disallow [other] calls from numbers matching the following prefix: #!416 # # disallow that speed dialer that keeps hitting my machine #!3444444 # # allow all calls with the following prefixes #832, 555 # # don't allow calls when there's no callerid: #!none # # It's okay to accept calls from out of area # ("OUT_OF_AREA" token seems ZyXEL specific) #OUT_OF_AREA # For V.253 compatibles modems "OUT OF AREA" is represented by the # single letter 'O' #O # # The caller has denied the transmission of his number # (private service) (For German Telecom dialprefix *31#). # This is for V.253 compatible modems represented by the single # letter 'P'. # don't allow access to my machine for those callers #!P # # # disallow all other calls #!all mgetty-1.1.36/faxrunq.config0100600000031200001470000000557210554073075014267 0ustar gertfax# faxrunq.config # # Sample configuration file for "faxrunq" and "faxrunqd" # # valid options: success-send-mail [y/n], failure-send-mail [y/n], # success-call-program , failure-call-program , # maxfail-costly , maxfail-total , # delete-sent-jobs [y/n], acct-log # # additional options specific to faxrunqd: fax-devices , # faxrunqd-log , faxrunqd-keep-logs , # acct-log , policy-config # say "y" here if you want a mail to be sent to the sender of the fax # when a fax has been successfully sent, "n" otherwise... (default "y") #success-send-mail n # this states whether a mail should be sent when a fax could not be # transmitted at all... (default "y") #failure-send-mail n # here you can specify a program that will be called for each fax that # has successfully been sent... (default: no program) #success-call-program /usr/local/lib/mgetty+sendfax/fax-success # and this program is run for each failed fax... (default: no program) #failure-call-program /usr/local/lib/mgetty+sendfax/fax-fail # how often should faxrunq retry "costly" errors (NO CARRIER, aborted # transmission, whatever - something that did cost telephone bill)? # (default: 3) #maxfail-costly 5 # this is the absolute maximum number of tries for a given fax # (default: 10) #maxfail-total 20 # if you want faxrunq to delete sent faxes completely, set this to "y". # If it is set to "n", faxes will be removed from the queue, but the # files won't be deleted, that is, you can see those faxes with # "faxq -o" (default: "n") #delete-sent-jobs y # accounting log file (default: see beginning of faxrunq/faxrunqd script) #acct-log /var/log/acct.log # The following options are for faxrunqd only: # which devices to use for outgoing faxes, seperated by ":" (default: no tty) # this may be overridden by the -l command line switch #fax-devices ttyS0:ttyS1 # log file for faxrunqd (default: see beginning of faxrunqd script) #faxrunqd-log /var/log/faxrunqd.log # number of logfiles to keep around when rolling (default: 3) #faxrunqd-keep-logs 5 # configuration file for policy routing, see faxrunqd man page for # details (default: none, i.e. don't use policy routing) #policy-config /usr/local/lib/mgetty+sendfax/policy.config # call an external script if the fax queue length goes over threshold # (default: off) #queue-length-high 250 /path/to/script.sh # call an external script if the fax queue falls under a low water mark again # (default: low water mark at 60% of high water mark, no script) #queue-length-low 100 /path/to/script.sh # call an external script if a modem goes bad # "bad" is defined as "more than X consecutive (!) failures" # the script will be passed the tty name, and the error codes (full list) # (default: off) #modem-error-threshold X /path/to/script.sh mgetty-1.1.36/mgetty.c0100644000031200001470000007744310356006656013110 0ustar gertfax#ident "$Id: mgetty.c,v 4.40 2005/12/31 15:54:01 gert Exp $ Copyright (c) Gert Doering" /* mgetty.c * * mgetty main module - initialize modem, lock, get log name, call login * * some parts of the code (lock handling, writing of the utmp entry) * are based on the "getty kit 2.0" by Paul Sutcliffe, Jr., * paul@devon.lns.pa.us, and are used with permission here. * * $Log: mgetty.c,v $ * Revision 4.40 2005/12/31 15:54:01 gert * correctly handle non-adaptive fax answer in class 1/1.0 mode (modem will * send "CONNECT", meaning "I'm in fax mode, please send DIS frame"...) * * Revision 4.39 2005/11/24 17:00:30 gert * add CVS Log keyword * */ #include #include "syslibs.h" #include #include #include #include #include #include #include "version.h" #include "mgetty.h" #include "policy.h" #include "tio.h" #include "fax_lib.h" #include "mg_utmp.h" #include "config.h" #include "conf_mg.h" #ifdef VOICE #include "voice/include/voice.h" #endif /* how much time may pass between two RINGs until mgetty goes into */ /* "waiting" state again */ int ring_chat_timeout = 10; /* what kind of "surprising" things are recognized */ chat_action_t ring_chat_actions[] = { { "CONNECT", A_CONN }, { "NO CARRIER", A_FAIL }, { "BUSY", A_FAIL }, { "ERROR", A_FAIL }, { "+FCON", A_FAX }, { "+FCO\r", A_FAX }, { "FAX", A_FAX }, { "+FHS:", A_FAIL }, { "+FHNG:", A_FAIL }, #ifdef VOICE { "VCON", A_VCON }, #endif { NULL, A_FAIL } }; /* the same actions are recognized while answering as are */ /* when waiting for RING, except for "CONNECT" */ chat_action_t * answer_chat_actions = &ring_chat_actions[1]; /* prototypes for system functions (that are missing in some * system header files) */ #if !defined(__NetBSD__) && !defined(__OpenBSD__) time_t time _PROTO(( time_t * tloc )); #endif /* logname.c */ int getlogname _PROTO(( char * prompt, TIO * termio, char * buf, int maxsize, int max_login_time, boolean do_fido, boolean env_ttyprompt )); /* conf_mg.c */ void exit_usage _PROTO((int num)); char * Device; /* device to use */ char * DevID; /* device name withouth '/'s */ extern time_t call_start; /* time when we sent ATA */ /* defined in faxrec.c */ void gettermio _PROTO((char * tag, boolean first, TIO * tio)); /* "simulated RING" handler */ boolean virtual_ring = FALSE; static RETSIGTYPE sig_pick_phone(SIG_HDLR_ARGS) { signal( SIGUSR1, sig_pick_phone ); virtual_ring = TRUE; } /* handle other signals: log them, and say goodbye... */ static RETSIGTYPE sig_goodbye _P1 ( (signo), int signo ) { lprintf( L_AUDIT, "failed dev=%s, pid=%d, got signal %d, exiting", Device, getpid(), signo ); rmlocks(); exit(10); } /* create a file with the process ID of the mgetty currently * active on a given device in it. */ static char pid_file_name[ MAXPATH ]; static void make_pid_file _P0( void ) { FILE * fp; sprintf( pid_file_name, "%s/mgetty.pid.%s", VARRUNDIR, DevID ); fp = fopen( pid_file_name, "w" ); if ( fp == NULL ) lprintf( L_ERROR, "can't create pid file %s", pid_file_name ); else { fprintf( fp, "%d\n", (int) getpid() ); fclose( fp ); } if ( chmod( pid_file_name, 0644 ) != 0 ) lprintf( L_ERROR, "can't chmod() pid file" ); } enum mgetty_States { St_unknown, St_go_to_jail, /* reset after unwanted call */ St_waiting, /* wait for activity on tty */ St_check_modem, /* check if modem is alive */ St_wait_for_RINGs, /* wait for RINGs before ATA */ St_answer_phone, /* ATA, wait for CONNECT/+FCO(N) */ St_nologin, /* no login allowed, wait for RINGing to stop */ St_dialout, /* parallel dialout, wait for lockfile to disappear */ St_get_login, /* prompt "login:", call login() */ St_callback_login, /* ditto, but after callback */ St_incoming_fax /* +FCON detected */ } mgetty_state = St_unknown; /* called on SIGUSR2. Exit, if no user online, ignore otherwise */ static RETSIGTYPE sig_new_config(SIG_HDLR_ARGS) { signal( SIGUSR2, sig_new_config ); if ( mgetty_state != St_answer_phone && mgetty_state != St_get_login && mgetty_state != St_callback_login && mgetty_state != St_incoming_fax ) { lprintf( L_AUDIT, "exit dev=%s, pid=%d, got signal USR2, exiting", Device, getpid() ); rmlocks(); exit(0); } lprintf( L_MESG, "Got SIGUSR2, modem is off-hook --> ignored" ); } enum mgetty_States st_sig_callback _P2( (pid, devname), int pid, char * devname ) { TIO tio; lprintf( L_MESG, "Got callback signal from pid=%d!", pid ); /* reopen device */ if ( mg_open_device( devname, FALSE ) == ERROR ) { lprintf( L_FATAL, "stsc: can't reopen device" ); exit(0); } /* setup device (but do *NOT*!! set speed) */ if ( tio_get( STDIN, &tio ) == ERROR ) { lprintf( L_FATAL, "stsc: can't get TIO" ); exit(0); } tio_mode_sane( &tio, c_bool( ignore_carrier ) ); tio_default_cc( &tio ); tio_mode_raw( &tio ); tio_set_flow_control( STDIN, &tio, DATA_FLOW ); if ( tio_set( STDIN, &tio ) == ERROR ) { lprintf( L_FATAL, "stsc: can't set TIO" ); exit(0); } /* make line controlling tty */ mg_get_ctty( STDIN, devname ); /* steal lock file from callback process */ lprintf( L_MESG, "stealing lock file from pid=%d", pid ); if ( steal_lock( Device, pid ) == ERROR ) return St_dialout; /* signal user */ printf( "...ok\r\n" ); /* signal callback process (but give it some time to enter pause()! */ delay(500); if ( kill( pid, SIGUSR1 ) < 0 ) { lprintf( L_ERROR, "can't signal callback process" ); } /* now give user a login prompt! */ return St_callback_login; } /* line locked, parallel dialout in process. * * Two things can happen now: * - lock file disappears --> dialout terminated, exit(), restart * - get signal SIGUSR1 --> dialout was callback, mgetty takes over */ enum mgetty_States st_dialout _P1( (devname), char * devname ) { int pid; /* the line is locked, a parallel dialout is in process */ virtual_ring = FALSE; /* used to signal callback */ /* write a note to utmp/wtmp about dialout, including process args * (don't do this on two-user-license systems!) */ #ifndef USER_LIMIT pid = checklock( Device ); /* !! FIXME, ugly */ make_utmp_wtmp( Device, UT_USER, "dialout", get_ps_args(pid) ); #endif /* close all file descriptors -> other processes can read port */ close(0); close(1); close(2); /* this is kind of tricky: sometimes uucico dial-outs do still collide with mgetty. So, when my uucico times out, I do *immediately* restart it. The double check makes sure that mgetty gives me at least 5 seconds to restart uucico */ do { /* wait for lock to disappear */ while ( ( pid = checklock(Device) ) != NO_LOCK ) { sleep(10); /* virtual ring? this would mean an active callback! */ if ( virtual_ring ) { return st_sig_callback( pid, devname ); } } /* wait a moment, then check for reappearing locks */ sleep(5); } while ( checklock(Device) != NO_LOCK ); /* OK, leave & get restarted by init */ exit(0); } /* end st_dialout() */ void get_ugid _PROTO(( conf_data * user, conf_data * group, uid_t * uid, gid_t * gid )); int main _P2((argc, argv), int argc, char ** argv) { char devname[MAXLINE+1]; /* full device name (with /dev/) */ char buf[MAXLINE+1]; TIO tio; FILE *fp; int i; action_t what_action; int rings_wanted; int rings = 0; int dist_ring = 0; /* type of RING detected */ #if defined(_3B1_) || defined(MEIBE) || defined(sysV68) extern struct passwd *getpwuid(), *getpwnam(); #endif uid_t uid; /* typical uid for UUCP */ gid_t gid; #ifdef VOICE boolean use_voice_mode = TRUE; #endif /* startup: initialize all signal handlers *NOW* */ (void) signal(SIGHUP, SIG_IGN); /* set to remove lockfile(s) and print "got signal..." message */ (void) signal(SIGINT, sig_goodbye); (void) signal(SIGQUIT, sig_goodbye); (void) signal(SIGTERM, sig_goodbye); /* sometimes it may be desired to have mgetty pick up the phone even if it didn't RING often enough (because you accidently picked it up manually...) or if it didn't RING at all (because you have a fax machine directly attached to the modem...), so send mgetty a signal SIGUSR1 and it will behave as if a RING was seen In addition, this is used by the "callback" module. */ signal( SIGUSR1, sig_pick_phone ); /* for reloading the configuration file, we need a way to tell mgetty "restart, but only if no user is online". Use SIGUSR2 for that */ signal( SIGUSR2, sig_new_config ); #ifdef HAVE_SIGINTERRUPT /* some systems, notable BSD 4.3, have to be told that system * calls are not to be automatically restarted after those signals. */ siginterrupt( SIGINT, TRUE ); siginterrupt( SIGALRM, TRUE ); siginterrupt( SIGHUP, TRUE ); siginterrupt( SIGUSR1, TRUE ); siginterrupt( SIGUSR2, TRUE ); #endif Device = "unknown"; /* process the command line */ mgetty_parse_args( argc, argv ); /* normal System V getty argument handling */ if (optind < argc) Device = argv[optind++]; else { lprintf(L_FATAL,"no line given"); exit_usage(2); } /* remove leading /dev/ prefix */ if ( strncmp( Device, "/dev/", 5 ) == 0 ) Device += 5; /* need full name of the device */ sprintf( devname, "/dev/%s", Device); /* Device ID = Device name without "/dev/", all '/' converted to '-' */ DevID = mydup( Device ); for ( i=0; DevID[i] != 0; i++ ) if ( DevID[i] == '/' ) DevID[i] = '-'; /* name of the logfile is device-dependant */ sprintf( buf, LOG_PATH, DevID ); log_init_paths( argv[0], buf, &Device[strlen(Device)-3] ); #ifdef VOICE lprintf( L_MESG, "vgetty: %s", vgetty_version); #endif lprintf( L_MESG, "mgetty: %s", mgetty_version); lprintf( L_NOISE, "%s compiled at %s, %s", __FILE__, __DATE__, __TIME__ ); i=getppid(); lprintf( L_NOISE, "user id: %d, pid: %d, parent pid: %d", getuid(), getpid(), i); if ( i != 1 ) { char *n = get_ps_args(i); lprintf( L_WARN, "WARNING: parent process not init(pid=1), but pid=%d (%s)", i, n != NULL? n: "unknown" ); } /* read configuration file */ mgetty_get_config( Device ); #ifdef VOICE check_system(); voice_config("vgetty", DevID); voice_register_event_handler(vgetty_handle_event); #endif #ifdef USE_GETTYDEFS if (optind < argc) conf_set_string( &c.gettydefs_tag, argv[optind++] ); lprintf( L_MESG, "gettydefs tag used: %s", c_string(gettydefs_tag) ); #endif make_pid_file(); lprintf(L_MESG, "check for lockfiles"); /* deal with the lockfiles; we don't want to charge * ahead if uucp, kermit or whatever else is already * using the line. * (Well... if we reach this point, most propably init has * hung up anyway :-( ) */ /* check for existing lock file(s) */ if (checklock(Device) != NO_LOCK) { st_dialout(NULL); } /* try to lock the line */ lprintf(L_MESG, "locking the line"); if ( makelock(Device) == FAIL ) { st_dialout(NULL); } /* the line is mine now ... */ /* set proper port ownership and permissions */ get_ugid( &c.port_owner, &c.port_group, &uid, &gid ); chown( devname, uid, gid ); if ( c_isset(port_mode) ) chmod( devname, c_int(port_mode) ); /* if necessary, kill any processes that still has the serial device * open (Marc Boucher, Marc Schaefer). */ #if defined( EXEC_FUSER ) sprintf( buf, EXEC_FUSER, devname ); if ( ( i = system( buf ) ) != 0 ) lprintf( L_WARN, "%s: return code %d", buf, i ); #endif /* setup terminal */ /* Currently, the tio set here is ignored. The invocation is only for the sideeffects of: - loading the gettydefs file if enabled. - setting port speed appropriately, if not set yet. */ gettermio(c_string(gettydefs_tag), TRUE, (TIO *) NULL); /* open + initialize device (mg_m_init.c) */ if ( mg_get_device( devname, c_bool(blocking), c_bool(toggle_dtr), c_int(toggle_dtr_waittime), c_int(speed) ) == ERROR ) { lprintf( L_FATAL, "cannot get terminal line dev=%s, exiting", Device); exit(30); } /* drain input - make sure there are no leftover "NO CARRIER"s * or "ERROR"s lying around from some previous dial-out */ clean_line( STDIN, 1); /* do modem initialization, normal stuff first, then fax */ if ( c_bool(direct_line) ) Connect = "DIRECT"; /* for "\I" in issue/prompt */ else { /* initialize data part */ if ( mg_init_data( STDIN, c_chat(init_chat), c_bool(need_dsr), c_chat(force_init_chat) ) == FAIL ) { lprintf( L_AUDIT, "failed in mg_init_data, dev=%s, pid=%d", Device, getpid() ); tio_flush_queue( STDIN, TIO_Q_BOTH ); /* unblock flow ctrl */ rmlocks(); exit(1); } /* if desired, get some "last call statistics" info */ if ( c_isset(statistics_chat) ) { get_statistics( STDIN, c_chat(statistics_chat), c_isset(statistics_file)? c_string(statistics_file): NULL ); } /* initialize ``normal'' fax functions */ if ( ( ! c_bool(data_only) ) && strcmp( c_string(modem_type), "data" ) != 0 && mg_init_fax( STDIN, c_string(modem_type), c_string(station_id), c_bool(fax_only), c_int(fax_max_speed) ) == SUCCESS ) { /* initialize fax polling server (only if faxmodem) */ if ( c_isset(fax_server_file) ) { faxpoll_server_init( STDIN, c_string(fax_server_file) ); } } #ifdef VOICE voice_fd = STDIN; voice_init(); if ( use_voice_mode ) { /* With external modems, the auto-answer LED can be used * to show a status flag. vgetty uses this to indicate * that new messages have arrived. */ vgetty_message_light(); } #endif /* VOICE */ /* some modems forget some of their settings during fax/voice * initialization -- use this as 'last chance' to set those things * [don't care for errors here] */ if ( c_isset( post_init_chat ) ) { lprintf( L_NOISE, "running post_init_chat" ); do_chat( STDIN, c_chat(post_init_chat), NULL, NULL, 10, TRUE ); } } /* wait .3s for line to clear (some modems send a \n after "OK", this may confuse the "call-chat"-routines) */ clean_line( STDIN, 3); /* remove locks, so any other process can dial-out. When waiting for "RING" we check for foreign lockfiles, if there are any, we give up the line - otherwise we lock it again */ rmlocks(); #if ( defined(linux) && defined(NO_SYSVINIT) ) || defined(sysV68) /* on linux, "simple init" does not make a wtmp entry when you * log so we have to do it here (otherwise, "who" won't work) */ make_utmp_wtmp( Device, UT_INIT, "uugetty", NULL ); #endif /* sleep... waiting for activity */ mgetty_state = St_waiting; while ( mgetty_state != St_get_login && mgetty_state != St_callback_login ) { switch (mgetty_state) /* state machine */ { case St_go_to_jail: /* after a rejected call (caller ID, not enough RINGs, * /etc/nologin file), do some cleanups, and go back to * field one: St_waiting */ CallTime = CallName = CalledNr = ""; /* dirty */ CallerId = "none"; clean_line( STDIN, 3); /* let line settle */ rmlocks(); mgetty_state = St_waiting; break; case St_waiting: /* wait for incoming characters (using select() or poll() to * prevent eating away from processes dialing out) */ lprintf( L_MESG, "waiting..." ); /* ignore accidential sighup, caused by dialout or such */ signal( SIGHUP, SIG_IGN ); /* here's mgetty's magic. Wait with select() or something * similar non-destructive for activity on the line. * If called with "-b" or as "getty", the blocking has * already happened in the open() call. */ if ( ! c_bool(blocking) ) { int wait_time = c_int(modem_check_time)*1000; if ( ! wait_for_input( STDIN, wait_time ) && ! c_bool(direct_line) && ! virtual_ring ) { /* no activity - is the modem alive or dead? */ log_close(); mgetty_state = St_check_modem; break; } } /* close (and reopen) log file, to make sure it hasn't been * moved away while sleeping and waiting for 'activity' */ log_close(); /* check for LOCK files, if there are none, grab line and lock it */ lprintf( L_NOISE, "checking lockfiles, locking the line" ); if ( makelock(Device) == FAIL) { lprintf( L_NOISE, "lock file exists (dialout)!" ); mgetty_state = St_dialout; break; } /* now: honour SIGHUP */ signal(SIGHUP, sig_goodbye ); rings = 0; /* check, whether /etc/nologin. exists. If yes, do not answer the phone. Instead, wait for ringing to stop. */ #ifdef NOLOGIN_FILE sprintf( buf, NOLOGIN_FILE, DevID ); if ( access( buf, F_OK ) == 0 ) { lprintf( L_MESG, "%s exists - do not accept call!", buf ); mgetty_state = St_nologin; break; } #endif mgetty_state = St_wait_for_RINGs; break; case St_check_modem: /* some modems have the nasty habit of just dying after some time... so, mgetty regularily checks with AT...OK whether the modem is still alive */ lprintf( L_MESG, "checking if modem is still alive" ); if ( makelock( Device ) == FAIL ) { mgetty_state = St_dialout; break; } /* try twice */ if ( mdm_command( "AT", STDIN ) == SUCCESS || mdm_command( "AT", STDIN ) == SUCCESS ) { mgetty_state = St_go_to_jail; break; } lprintf( L_FATAL, "modem on dev=%s doesn't react!", Device ); /* give up */ exit(30); break; case St_nologin: #ifdef NOLOGIN_FILE /* if a "/etc/nologin." file exists, wait for RINGing to stop, but count RINGs (in case the user removes the nologin file while the phone is RINGing), and if the modem auto-answers, handle it properly */ sprintf( buf, NOLOGIN_FILE, DevID ); /* while phone is ringing... */ while( wait_for_ring( STDIN, NULL, 10, ring_chat_actions, &what_action, &dist_ring ) == SUCCESS ) { rings++; if ( access( buf, F_OK ) != 0 || /* removed? */ virtual_ring == TRUE ) /* SIGUSR1? */ { mgetty_state = St_wait_for_RINGs; /* -> accept */ break; } } /* did nologin file disappear? */ if ( mgetty_state != St_nologin ) break; /* phone stopped ringing (do_chat() != SUCCESS) */ switch( what_action ) { case A_TIMOUT: /* stopped ringing */ lprintf( L_AUDIT, "rejected, rings=%d", rings ); mgetty_state = St_go_to_jail; break; case A_CONN: /* CONNECT */ clean_line( STDIN, 5 ); printf( "\r\n\r\nSorry, no login allowed\r\n" ); printf( "\r\nGoodbye...\r\n\r\n" ); sleep(5); exit(20); break; case A_FAX: /* +FCON */ mgetty_state = St_incoming_fax; break; default: lprintf( L_MESG, "unexpected action: %d", what_action ); exit(20); } #endif break; case St_dialout: /* wait for lock file to disappear *OR* for callback in progress */ mgetty_state = st_dialout(devname); break; case St_wait_for_RINGs: /* Wait until the proper number of RING strings have been seen. In case the modem auto-answers (yuck!) or someone hits DATA/VOICE, we'll accept CONNECT, +FCON, ... also. */ if ( c_bool(direct_line) ) /* no RING needed */ { mg_get_ctty( STDIN, devname ); /* get controll.tty */ mgetty_state = St_get_login; break; } dist_ring=0; /* yet unspecified RING type */ if ( c_bool(ringback) ) /* don't pick up on first call */ { int n = 0; while( wait_for_ring( STDIN, NULL, 17, ring_chat_actions, &what_action, &dist_ring ) == SUCCESS && ! virtual_ring ) { n++; } if ( what_action != A_TIMOUT ) goto Ring_got_action; lprintf( L_MESG, "ringback: phone stopped after %d RINGs, waiting for re-ring", n ); } /* how many rings to wait for (normally) */ rings_wanted = c_int(rings_wanted); #ifdef VOICE if ( use_voice_mode ) { /* modify, if toll saver, or in vgetty answer-file */ vgetty_rings(&rings_wanted); } #endif /* VOICE */ while ( rings < rings_wanted ) { if ( wait_for_ring( STDIN, c_chat(msn_list), ( c_bool(ringback) && rings == 0 ) ? c_int(ringback_time) : ring_chat_timeout, ring_chat_actions, &what_action, &dist_ring ) == FAIL) { break; /* ringing stopped, or "action" */ } rings++; } /* enough rings? */ if ( rings >= rings_wanted ) { mgetty_state = St_answer_phone; break; } Ring_got_action: /* not enough rings, timeout or action? */ switch( what_action ) { case A_TIMOUT: /* stopped ringing */ if ( rings == 0 && /* no ring *AT ALL* */ ! c_bool(ringback))/* and not "missed" ringback */ { lprintf( L_WARN, "huh? Junk on the line?" ); lprintf( L_WARN, " >>> could be a dial-out program without proper locking - check this!" ); rmlocks(); /* line is free again */ exit(0); /* let init restart mgetty */ } if ( c_bool(ringback) ) lprintf( L_AUDIT, "missed ringback!" ); else lprintf( L_AUDIT, "phone stopped ringing (rings=%d, dev=%s, pid=%d, caller='%s')", rings, Device, getpid(), CallerId ); mgetty_state = St_go_to_jail; break; case A_CONN: /* CONNECT */ mg_get_ctty( STDIN, devname ); mgetty_state = St_get_login; break; case A_FAX: /* +FCON */ mgetty_state = St_incoming_fax; break; #ifdef VOICE case A_VCON: vgetty_button(rings); use_voice_mode = FALSE; mgetty_state = St_answer_phone; break; #endif case A_FAIL: lprintf( L_AUDIT, "failed A_FAIL dev=%s, pid=%d, caller='%s'", Device, getpid(), CallerId ); exit(20); default: lprintf( L_MESG, "unexpected action: %d", what_action ); exit(20); } break; case St_answer_phone: /* Answer an incoming call, after the desired number of RINGs. If we have caller ID information, and checking it is desired, do it now, and possibly reject call if not allowed in. If we have to do some chat with the modem to get the Caller ID, do it now. */ if ( c_isset(getcnd_chat) ) { do_chat( STDIN, c_chat(getcnd_chat), NULL, NULL, 10, TRUE ); } /* Check Caller ID. Static table first, then cnd-program. */ if ( !cndlookup() || ( c_isset(cnd_program) && cnd_call( c_string(cnd_program), Device, dist_ring ) == 1)) { lprintf( L_AUDIT, "denied caller dev=%s, pid=%d, caller='%s'", Device, getpid(), CallerId); clean_line( STDIN, 80 ); /* wait for ringing to stop */ mgetty_state = St_go_to_jail; break; } /* from here, there's no way back. Either the call will succeed and mgetty will exec() something else, or it will fail and mgetty will exit(). */ /* get line as ctty: hangup will come through */ mg_get_ctty( STDIN, devname ); /* remember time of phone pickup */ call_start = time( NULL ); #ifdef VOICE if ( use_voice_mode ) { int rc; /* Answer in voice mode. The function will return only if it detects a data call, otherwise it will call exit(). */ rc = vgetty_answer(rings, rings_wanted, dist_ring); /* The modem will be in voice mode when voice_answer is * called. If the function returns, the modem is ready * to be connected in DATA mode with ATA. * * Exception: a CONNECT has been seen (-> go to "login:") * or a fax connection is established (go to fax receive) */ if ( rc == VMA_CONNECT ) { mgetty_state = St_get_login; break; } if ( rc == VMA_FCO || rc == VMA_FCON || rc == VMA_FAX ) { mgetty_state = St_incoming_fax; break; } } #endif /* VOICE */ if ( do_chat( STDIN, c_chat(answer_chat), answer_chat_actions, &what_action, c_int(answer_chat_timeout), TRUE) == FAIL ) { if ( what_action == A_FAX ) { mgetty_state = St_incoming_fax; break; } lprintf( L_AUDIT, "failed %s dev=%s, pid=%d, caller='%s', conn='%s', name='%s'", what_action == A_TIMOUT? "timeout": "A_FAIL", Device, getpid(), CallerId, Connect, CallName ); rmlocks(); exit(1); } #ifdef CLASS1 /* in fax class 1, without adaptive answer, the sequence * "ATA...CONNECT" means "we're in fax mode" - and it means * that the fax1 receiver must not wait for CONNECT, because * it's already there. Boy, is this ugly... */ if ( c_bool(fax_only) && ( modem_type == Mt_class1 || modem_type == Mt_class1_0 )) { fax1_receive_have_connect = TRUE; mgetty_state = St_incoming_fax; break; } #endif /* some (old) modems require the host to change port speed * to the speed returned in the CONNECT string, usually * CONNECT 2400 / 1200 / "" (meaning 300) */ if ( c_bool(autobauding) ) { int cspeed; if ( strlen( Connect ) == 0 ) /* "CONNECT\r" */ cspeed = 300; else cspeed = atoi(Connect); lprintf( L_MESG, "autobauding: switch to %d bps", cspeed ); if ( tio_check_speed( cspeed ) >= 0 ) { /* valid speed */ conf_set_int( &c.speed, cspeed ); tio_get( STDIN, &tio ); tio_set_speed( &tio, cspeed ); tio_set( STDIN, &tio ); } else { lprintf( L_ERROR, "autobauding: cannot parse 'CONNECT %s'", Connect ); } } mgetty_state = St_get_login; break; case St_incoming_fax: /* incoming fax, receive it (->faxrec.c) */ lprintf( L_MESG, "start fax receiver..." ); get_ugid( &c.fax_owner, &c.fax_group, &uid, &gid ); faxrec( c_string(fax_spool_in), c_int(switchbd), uid, gid, c_int(fax_mode), c_isset(notify_mail)? c_string(notify_mail): NULL ); /* some modems require a manual hangup, with a pause before it. Notably this is the creatix fax/voice modem, which is quite widespread, unfortunately... */ delay(1500); mdm_command( "ATH0", STDIN ); rmlocks(); exit( 0 ); break; default: /* unknown machine state */ lprintf( L_WARN, "unknown state: %s", mgetty_state ); exit( 33 ); } /* end switch( mgetty_state ) */ } /* end while( state != St_get_login ) */ /* this is "state St_get_login". Not included in switch/case, because it doesn't branch to other states. It may loop for a while, but it will never return */ /* wait for line to clear (after "CONNECT" a baud rate may be sent by the modem, on a non-MNP-Modem the MNP-request string sent by a calling MNP-Modem is discarded here, too) */ clean_line( STDIN, 3); tio_get( STDIN, &tio ); /* honor carrier now: terminate if modem hangs up prematurely * (can be bypassed if modem / serial port broken) */ if ( !c_bool( ignore_carrier ) ) { tio_carrier( &tio, TRUE ); tio_set( STDIN, &tio ); } else lprintf( L_MESG, "warning: carrier signal is ignored" ); /* make utmp and wtmp entry (otherwise login won't work) */ make_utmp_wtmp( Device, UT_LOGIN, "LOGIN", strcmp( CallerId, "none" ) != 0 ? CallerId: Connect ); /* wait a little bit befor printing login: prompt (to give * the other side time to get ready) */ delay( c_int(prompt_waittime) ); /* loop until a successful login is made */ for (;;) { /* protect against blocked output (for whatever reason) */ signal( SIGALRM, sig_goodbye ); alarm( 60 ); /* set ttystate for /etc/issue ("before" setting) */ gettermio(c_string(gettydefs_tag), TRUE, &tio); /* we have carrier, assert flow control (including HARD and IXANY!) */ tio_set_flow_control( STDIN, &tio, DATA_FLOW | FLOW_XON_IXANY ); tio_set( STDIN, &tio ); #ifdef NeXT /* work around NeXT's weird problems with POSIX termios vs. sgtty */ NeXT_repair_line(STDIN); #endif fputc('\r', stdout); /* just in case */ if (c_isset(issue_file)) { /* display ISSUE, if desired */ lprintf( L_NOISE, "print welcome banner (%s)", c_string(issue_file)); if (c_string(issue_file)[0] == '!') /* exec */ { system( c_string(issue_file)+1 ); } else if (c_string(issue_file)[0] != '/') { printf( "%s\r\n", ln_escape_prompt( c_string(issue_file) ) ); } else if ( (fp = fopen(c_string(issue_file), "r")) != (FILE *) NULL) { while ( fgets(buf, sizeof(buf), fp) != (char *) NULL ) { char * p = ln_escape_prompt( buf ); if ( p != NULL ) fputs( p, stdout ); fputc('\r', stdout ); } fclose(fp); } } /* set permissions to "rw-------" for login */ (void) chmod(devname, 0600); /* set ttystate for login ("after"), * cr-nl mapping flags are set by getlogname()! */ #ifdef USE_GETTYDEFS gettermio(c_string(gettydefs_tag), FALSE, &tio); tio_set( STDIN, &tio ); lprintf(L_NOISE, "i: %06o, o: %06o, c: %06o, l: %06o, p: %s", tio.c_iflag, tio.c_oflag, tio.c_cflag, tio.c_lflag, c_string(login_prompt)); #endif /* turn off alarm (getlogname has its own timeout) */ alarm(0); /* read a login name from tty (if just is pressed, re-print issue file) also adjust ICRNL / IGNCR to characters recv'd at end of line: cr+nl -> IGNCR, cr -> ICRNL, NL -> 0/ and: cr -> ONLCR, nl -> 0 for c_oflag */ if ( getlogname( c_string(login_prompt), &tio, buf, sizeof(buf), c_bool(blocking)? 0: c_int(login_time), c_bool(do_send_emsi), c_bool(env_ttyprompt) ) == -1 ) { continue; } /* remove PID file (mgetty is due to exec() login) */ (void) unlink( pid_file_name ); /* dreadful hack for Linux, set TERM if desired */ if ( c_isset(termtype) ) { set_env_var( "TERM", c_string(termtype) ); } /* catch "standard question #29" (DCD low -> /bin/login gets stuck) */ i = tio_get_rs232_lines(STDIN); if ( i != -1 && (( i & TIO_F_DCD ) == 0 ) ) { lprintf( L_WARN, "WARNING: starting login while DCD is low!" ); } /* hand off to login dispatcher (which will call /bin/login) */ login_dispatch( buf, mgetty_state == St_callback_login? TRUE: FALSE, c_string(login_config) ); /* doesn't return, if it does, something broke */ exit(FAIL); } } void gettermio _P3 ((id, first, tio), char *id, boolean first, TIO *tio ) { char *rp; #ifdef USE_GETTYDEFS static loaded = 0; GDE *gdp; #endif /* default setting */ if ( tio != NULL ) tio_mode_sane( tio, c_bool( ignore_carrier ) ); rp = NULL; #ifdef USE_GETTYDEFS /* if gettydefs used, override "tio_mode_sane" settings */ if (!loaded) { if (!loadgettydefs(GETTYDEFS)) { lprintf(L_WARN, "Couldn't load gettydefs - using defaults"); } loaded = 1; } if ( (gdp = getgettydef(id)) != NULL ) { lprintf(L_NOISE, "Using %s gettydefs entry, \"%s\"", gdp->tag, first? "before" : "after" ); if (first) /* "before" -> set port speed */ { if ( c.speed.flags == C_EMPTY || /* still default value */ c.speed.flags == C_PRESET ) /* -> use gettydefs */ conf_set_int( &c.speed, tio_get_speed( &(gdp->before)) ); } else /* "after" -> set termio flags *BUT NOT* speed */ if ( tio != NULL ) { *tio = gdp->after; tio_set_speed( tio, c_int(speed) ); } rp = gdp->prompt; } #endif if ( rp ) /* set login prompt only if still default */ { if ( c.login_prompt.flags == C_EMPTY || c.login_prompt.flags == C_PRESET ) { c.login_prompt.d.p = (void *) rp; c.login_prompt.flags = C_CONF; } } } mgetty-1.1.36/mgetty.h0100644000031200001470000002453510356006656013107 0ustar gertfax#ifndef ___MGETTY_H #define ___MGETTY_H #ident "$Id: mgetty.h,v 4.29 2005/12/31 15:52:45 gert Exp $ Copyright (c) Gert Doering" /* mgetty.h * * contains most of the constants and prototypes necessary for * mgetty+sendfax (except some fax constants, they are in fax_lib.h) * * $Log: mgetty.h,v $ * Revision 4.29 2005/12/31 15:52:45 gert * move typedef...uch from class1.h to mgetty.h * * Revision 4.28 2005/11/26 13:48:16 gert * GNU/kFreeBSD portability changes * * Revision 4.27 2005/04/25 15:29:20 gert * proper prototype for rmlocks() * set SIG_HDLR_ARGS correctly on AIX5 (needs -DAIX5 in CFLAGS) * */ #include "ugly.h" /* some generic, useful defines */ #ifndef ERROR #define ERROR -1 #define NOERROR 0 #endif #ifndef TRUE #define TRUE (1==1) #define FALSE (1==0) #endif #define FAIL -1 #define SUCCESS 0 /* defines for FIDO mailers */ #define TSYNC 0xae #define YOOHOO 0xf1 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ #define PPP_FRAME 0x7e /* PPP Framing character */ #define PPP_STATION 0xff /* "All Station" character */ #define PPP_ESCAPE 0x7d /* Escape Character */ #define PPP_CONTROL 0x03 /* PPP Control Field */ #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ #define PPP_UNESCAPE(c) ((c) ^ 0x20) /* un-escape character */ /* stuff in logfile.c */ #define L_FATAL 0 #define L_ERROR 1 #define L_AUDIT 2 #define L_WARN 3 #define L_MESG 4 #define L_NOISE 5 #define L_JUNK 6 void log_init_paths _PROTO(( char * program, char * path, char * infix )); void log_set_llevel _PROTO(( int level )); void log_close _PROTO((void)); int lputc _PROTO(( int level, char ch )); int lputs _PROTO(( int level, char * s )); #ifdef USE_VARARGS int lprintf _PROTO(()); #else int lprintf _PROTO((int level, const char *format, ...)); #endif /* various defines */ /* bsd stuff */ #if defined(__BSD_NET2__) || defined(__386BSD__) || \ defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__MACH__) # include /* defines BSD, BSD4_3 and BSD4_4 */ # ifndef BSD # define BSD /* just in case... */ # endif # if defined(__FreeBSD__) && !defined(__FreeBSD_version) # include /* FreeBSD version */ # endif #endif /* some versions of BSD have their own variant of fgetline that * behaves differently. Just change the name for now... * FIXME. */ #ifdef BSD # define fgetline mgetty_fgetline #endif /* define here what function to use for polling for characters * Chose one of the following: USE_SELECT, USE_POLL, USE_READ * I recommend USE_SELECT on all machines that have it, except SCO Unix, * since the tv_usec timer is not exact at all on SCO. * If your System has the "nap(S)" call, you can use this instead of * select(S) or poll(S) for sleeping less than one second. * Ditto for usleep(S), for systems having it. */ #if defined(linux) || defined(_AIX) # define USE_USLEEP #endif #if !defined(USE_POLL) && !defined(USE_READ) #define USE_SELECT #endif /* SunOS4 does not have memmove, but bcopy handles overlapping copies * as well. Watch out for src/dst argument order! */ #if defined(sunos4) || defined(NEED_MEMMOVE) # define memmove(dst, src, len) bcopy(src, dst, len) #endif /* these definitions specify the return value type and the arguments * for signal handler functions - if your compiler barfs, change them */ typedef void RETSIGTYPE; #if defined(_SCO_DS) || defined(AIX5) /* SCO OSR 5.0 */ # define SIG_HDLR_ARGS int signo #else # define SIG_HDLR_ARGS #endif typedef char boolean; typedef unsigned char uch; /* the cpp directive "sun" isn't useful at all, since is defined on * SunOS 4, Solaris 2, and even Solaris x86... * So, you have to define -Dsunos4, -Dsolaris2, or -Dsolaris86. * Otherwise: barf! */ #ifdef sun # if !defined( sunos4 ) && !defined( solaris2 ) && !defined( solaris86 ) # error "Please define -Dsunos4 or -Dsolaris2 or -Dsolaris86" # endif #endif #ifdef solaris2 # define SVR4 # define SVR42 # ifndef sun # define sun # endif #endif /* SGI's are SVR4... (jwz@netscape.com) */ #ifdef __sgi # define SVR4 # define SVR42 #endif /* assume that all BSD systems have the siginterrupt() function * for GNU libc 2.x, we need it as well (default behaviour is now "restart") */ #if defined(BSD) || defined(sunos4) ||\ ( defined(__GLIBC__) && __GLIBC__ >= 2 ) # ifndef NO_SIGINTERRUPT # define HAVE_SIGINTERRUPT # endif #endif /* assume that some systems do not have long filenames... */ #if ( defined(m88k) && !defined(SVR4) ) # ifndef SHORT_FILENAMES # define SHORT_FILENAMES # endif #endif /* On systems we know mmap() works, it will be used for reading G3 * files in the tools (g3topbm.c, g3cat.c), because it is a lot faster */ #if defined(linux) || defined(BSD) # define HAVE_MMAP #endif /* recent systems have mkstemp(), and it's more secure than mktemp() * SCO does not have it, though :-( */ #if !defined(M_UNIX) && !defined(_3B1_) # define HAVE_MKSTEMP #endif /* On a ALPHA, the config routines won't work, unless we change the * union to use "void *" and "long", instead of "int" (see config.h). * Same for Sparc Ultra machines [at least with SparcLinux] */ #if defined(__alpha__) || defined(__sparc64__) || \ defined(__ia64__) || defined(__s390x__) || defined(__x86_64__) || \ defined(__powerpc64__) # define PTR_IS_LONG #endif #define MAXLINE 1024 /* max. # chars in a line */ #define MAXPATH MAXLINE #define STDIN 0 typedef enum { A_TIMOUT, A_FAIL, A_FAX, A_VCON, A_CONN, A_RING1, A_RING2, A_RING3, A_RING4, A_RING5 } action_t; typedef struct chat_actions { char * expect; action_t action; } chat_action_t ; /* do_chat.c */ int do_chat _PROTO(( int filedesc, char * expect_send[], chat_action_t actions[], action_t * action, int chat_timeout_time, boolean timeout_first )); int do_chat_send _PROTO(( int filedesc, char * send_str_with_esc )); int clean_line _PROTO(( int filedesc, int tenths )); /* ring.c */ int wait_for_ring _PROTO(( int filedesc, char ** msn_list, int timeout, chat_action_t actions[], action_t * action, int * dist_ring_number )); /* do_stat.c */ void get_statistics _PROTO(( int filedesc, char ** chat, char * file )); /* goodies.c */ char * get_basename _PROTO(( char * )); char * mydup _PROTO(( char *s )); char * get_ps_args _PROTO(( int pid )); /* io.c */ boolean check_for_input _PROTO (( int fd )); boolean wait_for_input _PROTO (( int fd, int seconds )); void delay _PROTO(( int waittime )); /* locks.c */ #define NO_LOCK 0 /* returned by checklock() if no lock found */ int makelock _PROTO((char * device)); int makelock_file _PROTO(( char * lockname )); int checklock _PROTO((char * device)); void rmlocks _PROTO ((void)); int steal_lock _PROTO((char * device, int pid )); /* fax stuff */ void faxrec _PROTO(( char * spool_dir, unsigned int switchbd, int uid, int gid, int mode, char * mail_to )); char * fax_strerror _PROTO(( int fax_hangup_code )); void faxlib_init _PROTO((void)); extern int modem_quirks; /* initialization stuff: mg_m_init.c */ int mg_init_data _PROTO(( int fd, char * chat_seq[], boolean need_dsr, char * force_seq[])); int mg_init_fax _PROTO(( int fd, char * mclass, char * fax_id, boolean fax_only, int fax_max_speed )); int mg_init_voice _PROTO(( int fd )); void faxpoll_server_init _PROTO(( int fd, char * fax_server_file )); int mg_open_device _PROTO(( char * devname, boolean blocking )); int mg_init_device _PROTO(( int fd, boolean toggle_dtr, int toggle_dtr_waittime, unsigned int portspeed )); int mg_get_device _PROTO(( char * devname, boolean blocking, boolean toggle_dtr, int toggle_dtr_waittime, unsigned int portspeed )); int mg_get_ctty _PROTO(( int fd, char * devname )); int mg_drop_ctty _PROTO(( int fd )); /* modem.c */ int mdm_send _PROTO(( char * send, int fd )); int mdm_read_byte _PROTO(( int fd, char * c )); char * mdm_get_line _PROTO(( int fd )); int mdm_command _PROTO(( char * send, int fd )); char * mdm_get_idstring _PROTO(( char * send, int n, int fd )); /* logname.c */ char * ln_escape_prompt _PROTO(( char * prompt )); void set_env_var _PROTO(( char * var, char * string )); /* login stuff */ void login_dispatch _PROTO(( char * user, boolean is_callback, char * cf)); void setup_environment _PROTO(( void )); /* how long should I wait for a string from modem */ #define FAX_RESPONSE_TIMEOUT 120 /* how much time may pass while receiving a fax without getting data */ #define FAX_PAGE_TIMEOUT 60 /* cnd.c */ extern char *Connect; extern char *CallerId; extern char *CallTime; extern char *CallName; extern char *CalledNr; void cndfind _PROTO((char *str)); int cndlookup _PROTO((void)); int cnd_call _PROTO((char *name, char *tty, int dist_ring )); /* disk statistics retrieval in getdisk.c */ struct mountinfo { long mi_bsize; /* fundamental block size */ long mi_blocks; /* number of blocks in file system */ long mi_bfree; /* number of free blocks in file system */ long mi_bavail; /* blocks available to non-super user */ long mi_files; /* number of file nodes in file system */ long mi_ffree; /* number of free nodes in fs */ }; typedef struct mountinfo mntinf; extern long minfreespace; int checkspace _PROTO((char *path)); int getdiskstats _PROTO ((char *path, mntinf *mi)); /********* system prototypes **************/ extern char * mktemp _PROTO(( char * template )); #if !defined(linux) && !defined(SVR4) && !defined(__hpux) && \ !defined(BSD) && !defined(M_UNIX) && !defined(_AIX) && !defined(__GLIBC__) extern int getopt _PROTO(( int, char **, char * )); #endif extern int optind; extern char * optarg; /* system specific stuff */ #ifdef ISC #define fileno(p) (p)->_file # ifndef O_NDELAY # define O_NDELAY O_NONBLOCK # endif #endif #if defined(_3B1_) || defined(MEIBE) typedef ushort uid_t; typedef ushort gid_t; #endif #if defined(NeXT) # define NEED_PUTENV # define NEED_STRDUP char * strdup _PROTO(( char *src )); #endif /* hardware handshake flags for tio.c/tio.h * we have to define them here, because otherwise config.c would break */ #define FLOW_NONE 0x00 #define FLOW_HARD 0x01 /* rts/cts */ #define FLOW_XON_IN 0x02 /* incoming data, send xon/xoff */ #define FLOW_XON_OUT 0x04 /* send data, honor xon/xoff */ #define FLOW_SOFT (FLOW_XON_IN | FLOW_XON_OUT) #define FLOW_BOTH (FLOW_HARD | FLOW_SOFT ) #define FLOW_XON_IXANY 0x08 /* set IXANY flag together with IXON */ #endif /* ___MGETTY_H */ mgetty-1.1.36/ugly.h0100644000031200001470000000277107611100555012545 0ustar gertfax#ident "$Id: ugly.h,v 4.2 2003/01/14 14:03:19 gert Exp $ Copyright (c) Gert Doering" /* this module contains various macros that help you write function * prototypes that work both with ANSI-C and K&R C * macros written by Chris Lewis */ #ifdef __STDC__ #define _PROTO(x) x #define _P0(x) (x) #define _P1(x,a1) (a1) #define _P2(x,a1,a2) (a1,a2) #define _P3(x,a1,a2,a3) (a1,a2,a3) #define _P4(x,a1,a2,a3,a4) (a1,a2,a3,a4) #define _P5(x,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5) #define _P6(x,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6) #define _P7(x,a1,a2,a3,a4,a5,a6,a7) (a1,a2,a3,a4,a5,a6,a7) #define _P8(x,a1,a2,a3,a4,a5,a6,a7,a8) (a1,a2,a3,a4,a5,a6,a7,a8) #define _P9(x,a1,a2,a3,a4,a5,a6,a7,a8,a9) (a1,a2,a3,a4,a5,a6,a7,a8,a9) #define _P10(x,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) (a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) #else #define _PROTO(x) () #define _P0(x) () #define _P1(x,a1) x a1; #define _P2(x,a1,a2) x a1;a2; #define _P3(x,a1,a2,a3) x a1;a2;a3; #define _P4(x,a1,a2,a3,a4) x a1;a2;a3;a4; #define _P5(x,a1,a2,a3,a4,a5) x a1;a2;a3;a4;a5; #define _P6(x,a1,a2,a3,a4,a5,a6) x a1;a2;a3;a4;a5;a6; #define _P7(x,a1,a2,a3,a4,a5,a6,a7) x a1;a2;a3;a4;a5;a6;a7; #define _P8(x,a1,a2,a3,a4,a5,a6,a7,a8) x a1;a2;a3;a4;a5;a6;a7;a8; #define _P9(x,a1,a2,a3,a4,a5,a6,a7,a8,a9) x a1;a2;a3;a4;a5;a6;a7;a8;a9; #define _P10(x,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) x a1;a2;a3;a4;a5;a6;a7;a8;a9;a10; #define const #define volatile /* and function(fmt,...) is incompatible with K&R protoypes */ #ifndef USE_VARARGS # define USE_VARARGS #endif #endif mgetty-1.1.36/do_chat.c0100644000031200001470000001504607740003601013155 0ustar gertfax#ident "$Id: do_chat.c,v 4.2 2003/10/05 11:58:57 gert Exp $ Copyright (c) Gert Doering" /* do_chat.c * * This module handles all the non-fax talk with the modem */ #include #include "syslibs.h" #include #include #include #ifndef sunos4 #include #endif #ifndef EINTR #include #endif #include "mgetty.h" #include "policy.h" #include "tio.h" boolean chat_has_timeout; static RETSIGTYPE chat_timeout(SIG_HDLR_ARGS) { chat_has_timeout = TRUE; } extern boolean virtual_ring; /* send one string to "fd", honouring \c, \d and \\ */ int do_chat_send _P2( (fd, p), int fd, char * p ) { boolean nocr = FALSE; /* do not set CR/LF (\c) */ /* before sending, maybe we have to pause a little */ #ifdef DO_CHAT_SEND_DELAY delay(DO_CHAT_SEND_DELAY); #endif lprintf( L_MESG, "send: " ); while ( *p != 0 ) { if ( *p == '\\' ) /* special stuff */ { switch ( *(++p) ) { case 'd': lputs( L_MESG, "\\d"); delay(500); break; case 'c': nocr = TRUE; break; default: write( fd, p, 1 ); lputc( L_MESG, *p ); } } else { if ( write( fd, p, 1 ) != 1 ) { lprintf( L_ERROR, "do_chat: can't write to modem!" ); return ERROR; } lputc( L_MESG, *p ); } p++; } if ( ! nocr ) { write( fd, MODEM_CMD_SUFFIX, sizeof(MODEM_CMD_SUFFIX)-1 ); p = MODEM_CMD_SUFFIX; while ( *p ) lputc( L_MESG, *(p++) ); } return NOERROR; } int do_chat _P6((fd, expect_send, actions, action, chat_timeout_time, timeout_first ), int fd, char * expect_send[], chat_action_t actions[], action_t * action, int chat_timeout_time, boolean timeout_first ) { #define BUFFERSIZE 500 char buffer[BUFFERSIZE]; int i,cnt; int retcode = SUCCESS; int str; int h; TIO tio, save_tio; #define LSIZE 100 static char lbuf[LSIZE]; static char *lptr = lbuf; tio_get( fd, &tio ); save_tio = tio; tio_mode_raw( &tio ); tio_set( fd, &tio ); signal( SIGALRM, chat_timeout ); /* default "action" is timeout */ if ( actions != NULL && action != NULL ) *action = A_TIMOUT; str=0; while ( expect_send[str] != NULL ) { /* expect a string (expect_send[str] or abort[]) */ i = 0; if ( strlen( expect_send[str] ) != 0 ) { lprintf( L_MESG, "waiting for ``%s''", expect_send[str] ); lprintf( L_NOISE, "got: " ); chat_has_timeout = FALSE; /* set alarm timer. for the first string, the timer is only set if the flag "timeout_first" is true */ if ( str != 0 || timeout_first ) alarm( chat_timeout_time ); else alarm( 0 ); do { if ( virtual_ring && strncmp( expect_send[str], "RING", 4 ) == 0 ) { lputs( L_MESG, " ``found''" ); break; } cnt = read( fd, &buffer[i], 1 ); if ( cnt < 0 ) { if ( errno == EINTR ) cnt = 0; /* signal */ else { /* unsp. error */ lprintf( L_ERROR, "do_chat: error in read()"); retcode = FAIL; break; /* -> abort */ } } if ( chat_has_timeout ) /* timeout */ { lprintf( L_WARN, "timeout in chat script, waiting for `%s'", expect_send[str] ); retcode = FAIL; break; } if ( cnt > 0 ) { lputc( L_NOISE, buffer[i] ); /* build full lines, feed them to caller-id / connect * string parsing routine in cnd.c */ if ( buffer[i] == '\r' || buffer[i] == '\n' || (lptr >= lbuf+LSIZE-3) ) { *lptr = '\0'; if (lbuf[0]) cndfind(lbuf); lptr = lbuf; } else *lptr++ = buffer[i]; } i += cnt; if ( i>BUFFERSIZE-5 ) /* buffer full -> junk oldest stuff*/ { memcpy( &buffer[0], &buffer[BUFFERSIZE/2], i-BUFFERSIZE/2+1 ); i-=BUFFERSIZE/2; } /* look for the "expect"-string */ cnt = strlen( expect_send[str] ); if ( i >= cnt && memcmp( &buffer[i-cnt], expect_send[str], cnt ) == 0 ) { lputs( L_MESG, " ** found **" ); break; } /* look for one of the "abort"-strings */ if ( actions != NULL ) for ( h=0; actions[h].expect != NULL; h ++ ) { cnt = strlen( actions[h].expect ); if ( i>=cnt && memcmp( &buffer[i-cnt], actions[h].expect, cnt ) == 0 ) { lprintf( L_MESG,"found action string: ``%s''", actions[h].expect ); *action = actions[h].action; retcode = FAIL; break; } } } while ( i 0 && bytes < 10000 ) { if ( ++bytes < 500 ) lputc( L_NOISE, buffer[0] ); } #else TIO tio, save_tio; lprintf( L_NOISE, "waiting for line to clear (VTIME=%d), read: ", waittime); /* set terminal timeout to "waittime" tenth of a second */ tio_get( fd, &tio ); save_tio = tio; /*!! FIXME - sgtty?! */ tio.c_lflag &= ~ICANON; tio.c_cc[VMIN] = 0; tio.c_cc[VTIME] = waittime; tio_set( fd, &tio ); /* read everything that comes from modem until a timeout occurs */ while ( read( fd, buffer, 1 ) > 0 && bytes < 10000 ) { if ( ++bytes < 500 ) lputc( L_NOISE, buffer[0] ); } /* reset terminal settings */ tio_set( fd, &save_tio ); #endif if ( bytes > 500 ) lprintf( L_WARN, "clean_line: only 500 of %d bytes logged", bytes ); if ( bytes >= 10000 ) { extern char * Device; lprintf( L_FATAL, "clean_line: got too much junk (dev=%s).", Device ); } return 0; } mgetty-1.1.36/logfile.c0100644000031200001470000002123310342063640013171 0ustar gertfax#ident "$Id: logfile.c,v 4.11 2005/11/26 13:48:16 gert Exp $ Copyright (c) Gert Doering" #include #include #include #include #include #include #include #include #include "mgetty.h" #include "policy.h" /* this must be included after ugly.h (sets USE_VARARGS on non-ANSI cc's) */ #ifdef USE_VARARGS # if !defined(NeXT) || defined(NEXTSGTTY) # include # endif #else # include #endif #ifdef SYSLOG #include #if !defined(linux) && !defined(BSD) && !defined(_SCO_DS) && \ !defined(SVR42) && !defined(solaris2) && !defined(_AIX) && !defined(__GLIBC__) int openlog _PROTO(( char *, int, int )); int syslog _PROTO(( int, char *, ... )); #endif #endif /* on NeXTstep(POSIX), we have to use this *UGLY* way to cheat varargs/stdarg */ #if defined(NeXT) && !defined(NEXTSGTTY) # define va_alist a1,a2,a3,a4,a5,a6,a7,a8,a9 # define va_dcl long a1,a2,a3,a4,a5,a6,a7,a8,a9; # define vsprintf(buf,fmt,v) sprintf((buf),(fmt),a1,a2,a3,a4,a5,a6,a7,a8,a9) # define va_list int # define va_start(v) # define va_end(v) #endif static int log_level = LOG_LEVEL; /* set default log level threshold (jcp) */ static FILE * log_fp; static boolean mail_logfile = FALSE; static char log_path[ MAXPATH ]; static char log_infix[10]; /* printed between time stamp and text */ static char * log_program = "mgetty"; extern int atexit _PROTO(( void (*)(void) )); /* Most systems have these variables but do not declare them. On many of those systems that _do_ declare them, it won't hurt */ #if !defined(__NetBSD__) && !defined( __FreeBSD__ ) && !defined(__OpenBSD__) && !defined(__GLIBC__) && !defined(__MACH__) extern int sys_nerr; extern char *sys_errlist[]; #endif /* Interactive Unix is a little bit braindead - does not have atexit(), */ #if defined(ISC) || defined(SVR4) || defined(_3B1_) || \ defined(MEIBE) || defined(_SEQUENT_) || defined(_AIX) || \ defined(sysV68) || ( defined(M_XENIX) && !defined(M_UNIX) ) # define atexit(dummy) #endif /* on SunOS, we can do it with on_exit() */ #ifdef sunos4 # define atexit(func) on_exit(func, NULL) #endif void log_init_paths _P3 ( (l_program, l_path, l_infix), char * l_program, char * l_path, char * l_infix ) { if ( l_program != NULL ) /* set program name */ { char * p = strrchr( l_program, '/' ); log_program = ( p == NULL ) ? l_program : p+1; } if ( l_path != NULL ) /* set log file name+path */ { if ( log_fp != NULL && /* logfile already open */ strcmp( l_path, log_path ) != 0 ) /* and path changed */ { lprintf( L_MESG, "logging continues in file %s", l_path ); log_close(); /* -> reopen */ } strncpy( log_path, l_path, sizeof(log_path)-1 ); log_path[sizeof(log_path)-1] = 0; if ( strlen(l_path) >= sizeof(log_path) ) { lprintf( L_FATAL, "internal error: log file path too long!" ); } } if ( l_infix != NULL ) /* usually tty id */ { sprintf( log_infix, "%.*s ", (int) sizeof(log_infix)-2, l_infix ); } } void log_set_llevel _P1( (level), int level ) { log_level = level; } /* close log file, to give programs like 'savelog' a chance to move it away */ void log_close _P0(void) { if ( log_fp != NULL ) fclose( log_fp ); log_fp = NULL; } void logmail _P0( void ) { char ws[MAXPATH+100]; char buf[512]; int l; FILE * pipe_fp; int log_fd; if ( mail_logfile ) { lprintf( L_MESG, "mailing logfile to %s...", ADMIN ); sprintf( ws, "%s %s", MAILER, ADMIN ); pipe_fp = popen( ws, "w" ); if ( pipe_fp == NULL ) { lprintf( L_ERROR, "cannot open pipe to %s", MAILER ); /* FIXME: write to console - last resort */ fprintf( stderr, "cannot open pipe to %s", MAILER ); return; } fprintf( pipe_fp, "Subject: fatal error in logfile\n" ); fprintf( pipe_fp, "To: %s\n", ADMIN ); fprintf( pipe_fp, "From: root (Fax Getty)\n" ); fprintf( pipe_fp, "\nA fatal error has occured! The logfile follows\n" ); log_fd = open( log_path, O_RDONLY ); if ( log_fd == -1 ) { fprintf( pipe_fp, "The logfile '%s' cannot be opened (errno=%d)\n", log_path, errno ); } else { do { l = read( log_fd, buf, sizeof( buf ) ); fwrite( buf, l, 1, pipe_fp ); } while( l == sizeof( buf ) ); fprintf( pipe_fp, "\n------ logfile ends here -----\n" ); } close( log_fd ); pclose( pipe_fp ); } mail_logfile = FALSE; } int lputc _P2((level, ch), int level, char ch ) { if ( log_fp != NULL && level <= log_level ) { if ( isprint(ch) ) fputc( ch, log_fp ); else fprintf( log_fp, "[%02x]", (unsigned char) ch ); fflush( log_fp ); #ifdef LOG_CR_NEWLINE if ( ch == '\n' ) fputc( ch, log_fp ); #endif } return 0; } int lputs _P2((level, s), int level, char * s ) { int retcode = 0; if ( log_fp != NULL && level <= log_level ) { retcode = fputs( s!=NULL? s : "(NULL)", log_fp ); fflush( log_fp ); } return retcode; } #ifdef USE_VARARGS int lprintf( level, format, va_alist ) int level; const char * format; va_dcl #else int lprintf(int level, const char *format, ...) #endif { char ws[2000]; time_t ti; struct tm *tm; va_list pvar; int errnr; char * p; static int first_open = TRUE; if ( level > log_level ) /* log level high enough? */ { return 0; /* no -> return immediately */ } #ifdef USE_VARARGS va_start( pvar ); #else va_start( pvar, format ); #endif errnr = errno; if ( log_fp == NULL ) /* open log file, if necessary */ { if ( log_path[0] == 0 ) sprintf( log_path, LOG_PATH, "unknown" ); log_fp = fopen( log_path, "a" ); if ( log_fp == NULL ) /* opening log file failed */ { sprintf(ws, "cannot open logfile %s", log_path); perror(ws); /* use /dev/console for logging, if possible */ if ( ( log_fp = fopen( CONSOLE, "w" ) ) != NULL ) { fprintf( log_fp, "\n%s: resorting to logging to %s\n", log_program, CONSOLE ); } else /* give up, disable logging */ { sprintf( ws, "cannot log to %s, disable logging", CONSOLE ); perror( ws ); log_level = -1; return 0; } } /* make sure that the logfile is not accidently stdin, -out or -err */ if ( fileno( log_fp ) < 3 ) { int fd; if ( ( fd = fcntl( fileno( log_fp ), F_DUPFD, 3 ) ) > 2 ) { fclose( log_fp ); log_fp = fdopen( fd, "a" ); } } /* the first time we open the logfile, write a separator line * and initialize syslog logging (if desired) */ if ( first_open ) { first_open = FALSE; fprintf( log_fp, "\n--" ); #ifdef SYSLOG openlog( log_program, LOG_PID, SYSLOG_FC ); #endif } /* set close-on-exec bit (prevent user programs writing to logfile */ if ( fcntl( fileno( log_fp ), F_SETFD, 1 ) < 0 ) { lprintf( L_ERROR, "open_log: can't set close-on-exec bit" ); } } /* Marc's hack to get different verbosity levels on different * intendation levels *!!!! ugly. Rewrite some day. */ ws[0] = ' '; ws[1] = ' '; if (level == L_NOISE) vsprintf( &ws[1], format, pvar ); else if (level == L_JUNK) vsprintf( &ws[2], format, pvar ); else vsprintf( &ws[0], format, pvar ); va_end( pvar ); /* convert non-printable characters "in-place" to "_" */ if ( level != L_AUDIT ) for( p=ws; *p!='\0'; p++ ) { if ( ! isprint(*p) ) *p='_'; } ti = time(NULL); tm = localtime(&ti); if ( level == L_AUDIT ) /* some little auditing */ { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d ##### %s\n", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, ws ); #ifdef SYSLOG syslog( LOG_NOTICE, "%s", ws ); #endif } else if ( level != L_ERROR && level != L_FATAL ) { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d %s %s", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, log_infix, ws ); } else /* ERROR or FATAL */ { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d %s %s: %s", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, log_infix, ws, ( errnr <= sys_nerr ) ? sys_errlist[errnr]: "" ); #ifdef SYSLOG syslog( level == L_FATAL? LOG_ALERT: LOG_ERR, "%s: %m", ws ); #endif #ifndef SYSLOG if ( level == L_FATAL ) /* write to console */ { FILE * cons_fp; if ( ( cons_fp = fopen( CONSOLE, "w" ) ) != NULL ) { fprintf( cons_fp, "\n%s FATAL: %s %s\n", log_program, log_infix, ws ); fclose( cons_fp ); } else /* last resort */ if ( !mail_logfile ) { atexit( logmail ); mail_logfile = TRUE; } } #endif } /* end if ( L_ERROR or L_FATAL ) */ fflush(log_fp); return 0; } mgetty-1.1.36/logname.c0100644000031200001470000003527510341370470013206 0ustar gertfax#ident "$Id: logname.c,v 4.11 2005/11/24 16:58:32 gert Exp $ Copyright (c) Gert Doering" /* logname.c * * print 'login:' prompt, handling eventual escape sequence substitutions * * read login name, detect incoming PPP frames and FIDO startup sequences * * $Log: logname.c,v $ * Revision 4.11 2005/11/24 16:58:32 gert * add extra flag, env_ttyprompt, that replaces #ifdef ENV_TTYPROMPT * * Revision 4.10 2005/04/25 21:09:13 gert * drain tty output before changing CR/LF settings after reading login name * (this was a race condition on very fast machines that lead to confused * tty drivers - and there is no good reason NOT to let the output drain) * */ #include #include "syslibs.h" #include #include #include #include #include #include #ifndef sunos4 #include #endif #ifndef ENOENT #include #endif #include "mgetty.h" #include "policy.h" #include "tio.h" #include "mg_utmp.h" #include extern char * Device; /* mgetty.c */ /* ln_escape_prompt() * * substitute all "known" escapes, e.g. "\n" and "\t", plus some * private extentions (@, \D and \T for system name, date, and time) * * The caller has to free() the string returned * * If the resulting string would be too long, it's silently truncated. */ int strappnd _P2((s1,s2), char * s1, char * s2 ) { strcpy( s1, s2 ); return strlen( s1 ); } char * ln_escape_prompt _P1( (ep), char * ep ) { #define MAX_PROMPT_LENGTH 300 static char * p = NULL; int i; static struct utsname un; static boolean un_cached = FALSE; if ( p == NULL ) p = malloc( MAX_PROMPT_LENGTH ); if ( p == NULL ) return ep; if ( ! un_cached ) { uname( &un ); un_cached = TRUE; } i = 0; while ( *ep != 0 && i < MAX_PROMPT_LENGTH-4 ) { if ( *ep == '@' ) /* system name */ { #ifdef SYSTEM if ( sizeof( SYSTEM ) + i > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], SYSTEM ); #else if ( strlen( un.nodename ) +1 +i > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], un.nodename ); #endif /* !SYSTEM */ } else if ( *ep != '\\' ) p[i++] = *ep; else /* *ep == '\\' */ { ep++; switch ( *ep ) { case 'n': p[i++] = '\n'; break; case 'r': p[i++] = '\r'; break; case 'g': p[i++] = '\007'; break; case 'b': p[i++] = '\010'; break; case 'v': p[i++] = '\013'; break; case 'f': p[i++] = '\f'; break; case 't': p[i++] = '\t'; break; case 's': /* Operating System */ if ( i + strlen(un.sysname) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], un.sysname ); break; case 'm': /* machine arch. */ if ( i + strlen(un.machine) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], un.machine ); break; case 'R': /* OS release */ if ( i + strlen(un.release) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], un.release ); break; case 'V': /* OS version */ if ( i + strlen(un.version) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], un.version ); break; case 'Y': /* Caller ID */ { extern char * CallerId; if ( i + strlen(CallerId) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], CallerId ); break; } case 'P': /* port name */ case 'L': /* tty line */ { if ( i + strlen(Device) +1 > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], Device ); break; } case 'C': /* ctime */ { time_t ti = time(NULL); char * h = ctime( &ti ); if ( strlen(h) +1 +i > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], h ) -1; break; } case 'I': { if ( strlen(Connect) +1 +i > MAX_PROMPT_LENGTH ) break; i += strappnd( &p[i], Connect); break; } case 'N': /* numer of */ case 'U': /* users */ { sprintf( &p[i], "%d", get_current_users() ); i = strlen(p); break; } case 'S': /* port speed */ { /* ugly, I know. */ TIO temp_t; tio_get( 0, &temp_t ); sprintf( &p[i], "%d", tio_get_speed( &temp_t ) ); i = strlen(p); } break; case 'D': /* fallthrough */ case 'T': if ( i + 30 > MAX_PROMPT_LENGTH ) { i += strappnd( &p[i], "(x)" ); break; } else { time_t ti = time( NULL ); struct tm * tm = localtime( &ti ); if ( tm == NULL ) break; if ( *ep == 'D' ) sprintf( &p[i], "%d/%d/%d", tm->tm_mon+1, tm->tm_mday, tm->tm_year + 1900 ); else sprintf( &p[i], "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec ); i = strlen(p); } break; default: /* not a recognized string */ if ( isdigit( *ep ) ) /* "\01234" */ { char * help; p[i++] = strtol( ep, &help, 0 ); ep = help-1; } else p[i++] = *ep; } /* end switch( char after '\\' ) */ } /* end if ( char is '\\' ) */ ep++; } /* end while ( char to copy, p not full ) */ p[i] = 0; /* terminate string */ if ( *ep != 0 ) { lprintf( L_WARN, "ln_escape_prompt: input line too long - data truncated" ); } return p; } /* return TRUE if all letters found in the string are uppercase */ #ifdef DO_LCUC_MAP boolean ln_all_upper _P1( (string), char * string ) { int i; boolean uc = FALSE; for ( i=0; string[i] != 0; i++ ) { if ( string[i] == '\377' ) return FALSE; /* **EMSI_INQ */ if ( islower( string[i] ) ) return FALSE; if ( isupper( string[i] ) ) uc = TRUE; } if ( ! uc ) /* no letters at all */ return FALSE; /* -> counted as lowercase */ return TRUE; } #endif /* set_env_var( var, string ) * * create an environment entry "VAR=string" */ void set_env_var _P2( (var,string), char * var, char * string ) { char * v; v = malloc( strlen(var) + strlen(string) + 2 ); if ( v == NULL ) lprintf( L_ERROR, "set_env_var: cannot malloc" ); else { sprintf( v, "%s=%s", var, string ); lprintf( L_NOISE, "setenv: '%s'", v ); if ( putenv( v ) != 0 ) lprintf( L_ERROR, "putenv failed" ); } } static int timeouts = 0; static RETSIGTYPE getlog_timeout(SIG_HDLR_ARGS) { signal( SIGALRM, getlog_timeout ); lprintf( L_WARN, "getlogname: timeout" ); timeouts++; } /* getlogname() * * read the login name into "char buf[]", maximum length "maxsize". * depending on the key that the input was finished (\r vs. \n), mapping * of cr->nl is set in "TIO * tio" (with tio_set_cr()) * * If ENV_TTYPROMPT is set, do not read anything */ int getlogname _P7( (prompt, tio, buf, maxsize, max_login_time, do_fido, env_ttyprompt), char * prompt, TIO * tio, char * buf, int maxsize, int max_login_time, boolean do_fido, boolean env_ttyprompt ) { int i, r; char ch; TIO tio_save; char * final_prompt; #ifdef AUTO_PPP static int ppp_level = 0, ppp_escaped = 0; char ppp_ch; #endif /* read character by character! */ tio_save = *tio; tio_mode_raw( tio ); tio_set( STDIN, tio ); final_prompt = ln_escape_prompt( prompt ); if ( env_ttyprompt ) { printf( "\r\n%s", final_prompt ); tio_mode_sane( tio, FALSE ); tio_map_cr( tio, TRUE ); tio_set( STDIN, tio ); buf[0] = 0; set_env_var( "TTYPROMPT", final_prompt ); return 0; } if ( max_login_time > 0 ) { signal( SIGALRM, getlog_timeout ); alarm( max_login_time ); } newlogin: #ifdef FIDO /* send EMSI Request for FIDO (if desired) */ if ( do_fido ) printf( "**EMSI_REQA77E\r\021 \r" ); newlogin_noemsi: #endif printf( "\r\n%s", final_prompt ); if ( ferror( stdin ) ) { lprintf( L_ERROR, "getlogname: error writing prompt" ); } /* print logfile msg, showing all compiled-in options */ #ifdef FIDO # ifdef AUTO_PPP lprintf( L_NOISE, "getlogname (FIDO AUTO_PPP), read:" ); # else lprintf( L_NOISE, "getlogname (FIDO), read:" ); # endif #else /* !FIDO */ # ifdef AUTO_PPP lprintf( L_NOISE, "getlogname (AUTO_PPP), read:" ); # else lprintf( L_NOISE, "getlogname (no opts), read:" ); # endif #endif i = 0; do { if ( ( r = read( STDIN, &ch, 1 ) ) != 1 ) { if ( r == 0 ) /* EOF/HUP/^D */ { lprintf( L_MESG, "getlogname: got EOF, exiting" ); exit(0); } if ( errno != EINTR ) exit(0); /* HUP/^D/timeout */ if ( timeouts <= 1 ) /* first timeout */ { printf( "\r\n\07\r\nHey! Please login now. You have one minute left\r\n" ); alarm(60); } else /* second */ { printf( "\r\n\07\r\nYour login time (%d minutes) ran out. Goodbye.\r\n", (max_login_time / 60)+1 ); sleep(3); /* give message time to xmit */ lprintf( L_AUDIT, "failed dev=%s, pid=%d, login time out", Device, getpid() ); exit(0); /* bye bye... */ } ch = CKILL; /* timeout #1 -> clear input */ } lputc( L_NOISE, ch ); /* logging */ #ifdef FIDO if ( ch == (char) TSYNC ) { strcpy( buf, "\377tsync" ); i=6; ch='\r'; } else if ( ch == (char) YOOHOO ) { strcpy( buf, "\377yoohoo" ); i=7; ch='\r'; } #endif #ifdef AUTO_PPP /* Accept the following sequences as start of PPP packet: PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED (normal) PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) Odds are pretty low of hitting this by accident. See RFC1662 for more information. Contributed by Erik 'PPP' Olson, . Fix by okir@caldera.de: Recognize any escape sequence (some pppd's also escape the 'all stations' byte (0xFF)). */ ppp_ch = ch; if (ppp_escaped) { ppp_ch = PPP_UNESCAPE(ch); ppp_escaped = 0; } if (ppp_ch == (char) PPP_ESCAPE) { ppp_escaped = 1; } else if (ppp_ch == (char) PPP_FRAME) { ppp_level = 1; } else if (ppp_ch == (char) PPP_STATION && ppp_level == 1) { ppp_level = 2; } else if (ppp_ch == (char) PPP_CONTROL && ppp_level == 2) { ppp_level = 3; } else if (ppp_ch == (char) PPP_LCP_HI && ppp_level == 3) { ppp_level = 4; } else if (ppp_ch == (char) PPP_LCP_LOW && ppp_level == 4) { strcpy (buf, "/AutoPPP/"); i=9; ch = '\r'; /* the following is a hack... - if pppd startup is slow, and the * caller sends its PPP frames fast, they get echoed, and will * confuse the "loop detection" of some clients. So we switch * the saved tio to raw mode, which will be "restored" soon. */ tio_mode_raw( &tio_save ); } else { ppp_level = 0; ppp_escaped = 0; } #endif #ifdef JANUS /* ignore ^X as first character, some JANUS programs send it first to skip the usual bbs banner oli@rhein-main.de, 941217 */ if ( i == 0 && ch == 0x18 ) continue; #endif /* ignore [00] and [01] bytes - seem to be spuriously generated * when dialing into a ZyXEL 2864DI with X.75 (sometimes) */ if ( ch == 0 || ch == 1 ) continue; ch = ch & 0x7f; /* strip to 7 bit */ if ( ch == CQUIT ) exit(0); if ( ch == CEOF ) { if ( i == 0 ) exit(0); else continue; } if ( ch == CKILL || ch == 03 /*^C*/ ) goto newlogin; /* ignore XON/XOFF characters */ if ( ch == CSTART || ch == CSTOP ) continue; /* since some OSes use backspace and others DEL -> accept both */ if ( ch == 0x7f /*DEL*/ || ch == 0x08 /*BS*/ || ch == CERASE ) { if ( i > 0 ) { fputs( "\b \b", stdout ); i--; } } else if ( ch != 27 ) /* not */ { putc( ch, stdout ); if ( i >= maxsize || /* buffer full, */ ( ch == ' ' && i == 0 ) || /* leading ' ' */ ( ch == '-' && i == 0 ) ) /* or '-' */ fputs( "\b \b", stdout ); /* -> ignore */ else buf[i++] = ch; if ( i >= 7 && strncmp( &buf[i-7], "**EMSI_", 7 ) == 0 ) { #ifdef FIDO lprintf( L_NOISE, "got EMSI signature" ); strcpy( buf, "\377**EMSI_" ); i=8; break; #else lprintf( L_MESG, "incoming fido call, but no FIDO support" ); #endif } } } while ( ch != '\n' && ch != '\r' ); #ifdef FIDO if ( strncmp( buf, "\377**EMSI_", 8 ) == 0 ) { /* read up to final \r */ while ( ch != '\r' ) { if ( read( STDIN, &ch, 1 ) != 1 ) { lprintf( L_ERROR, "logname/FIDO: read error" ); exit(0); } if ( i < maxsize) buf[i++] = ch; if ( i >= 15 && strncmp( buf, "\377**EMSI_INQC816", 15 ) == 0 ) { ch = buf[i++] = '\r'; } } /* log EMSI packets that are not EMSI_INQ (e.g. EMSI_DAT) */ if ( strncmp( buf, "\377**EMSI_INQ", 11 ) != 0 ) { buf[i-1] = 0; lprintf( L_MESG, "non-INQ EMSI packet: '%.15s...', length %d", buf+1, i-1 ); if ( strncmp( buf, "\377**EMSI_CLI", 11 ) == 0 ) { lprintf( L_MESG, "got EMSI_CLI packet, re-read login name" ); goto newlogin_noemsi; } } } #endif alarm(0); buf[--i] = 0; *tio = tio_save; #ifdef JANUS /* change JANUS to janus */ if( strcmp(buf,"JANUS") == 0 ) strcpy(buf,"janus"); #endif /* for modems that are misconfigured and do not raise/lower DCD properly, check for some standard modem error codes now */ if( strcmp(buf,"NO CARRIER") == 0 || strcmp(buf,"ERROR") == 0 ) { lprintf( L_AUDIT, "failed dev=%s, pid=%d, got modem error '%s'", Device, getpid(), buf ); exit(0); } /* check whether all letters entered were uppercase, if yes, tell user to try again with l/c, if it's all uppercase again on the second try, enable UC<->LC mapping (this is mainly for full historic compatibility - off by default) */ #ifdef DO_LCUC_MAP if ( ln_all_upper( buf ) ) { static boolean was_all_uc = FALSE; if ( !was_all_uc ) /* first time */ { printf("\r\n\nIf your terminal supports lower case letter, please\r\n"); printf("use them. Login again, using lower case if possible\r\n\n"); was_all_uc = TRUE; return -1; } else /* second time */ { for ( i=0; buf[i] != 0; i++ ) if ( isupper( buf[i] ) ) buf[i] = tolower(buf[i]); tio_map_uclc( tio, TRUE ); lprintf( L_MESG, "login name all uppercase, set IUCLC OLCUC" ); } } #endif /* set CR/LF mapping according to the character the input was ended with */ if ( ch == '\n' ) { tio_map_cr( tio, FALSE ); fputc( '\r', stdout ); } else { tio_map_cr( tio, TRUE ); fputc( '\n', stdout ); lprintf( L_NOISE, "input finished with '\\r', setting ICRNL ONLCR" ); } tio_drain_output( STDIN ); /* make sure CR+LF has been sent */ tio_set( STDIN, tio ); if ( i == 0 ) return -1; else return 0; } mgetty-1.1.36/locks.c0100600000031200001470000002322610506054350012657 0ustar gertfax#ident "$Id: locks.c,v 4.7 2006/06/14 09:38:23 gert Exp $ Copyright (c) Gert Doering / Paul Sutcliffe Jr." /* large parts of the code in this module are taken from the * "getty kit 2.0" by Paul Sutcliffe, Jr., paul@devon.lns.pa.us, * and are used with permission here. * SVR4 style locking by Bodo Bauer, bodo@hal.nbg.sub.org. * * $Log: locks.c,v $ * Revision 4.7 2006/06/14 09:38:23 gert * get rid of compiler warning about "usused variable tries" * * Revision 4.6 2005/11/09 09:12:29 gert * error message was missing an argument (filename) to lprintf() * * Revision 4.5 2005/04/25 15:28:21 gert * rmlocks() is no signal handler -> use proper prototype * */ #include #include #include #include #include #include #include #include #include /* some OSes do include this in stdio.h, others don't... */ #ifndef EEXIST #include #endif #include "mgetty.h" #include "policy.h" /* SVR4 uses a different locking mechanism. This is why we need this... */ #ifdef SVR4 #include #define LCK_NODEV -1 #define LCK_OPNFAIL -2 #endif char lock[MAXLINE+1]; /* name of the lockfile */ static int readlock _PROTO(( char * name )); static char * get_lock_name _PROTO(( char * lock_name, char * device )); static int lock_write_pid _PROTO(( int fd )); static int we_have_lock = FALSE; /* * do_makelock() - attempt to create a lockfile * * Returns FAIL if lock could not be made (line in use). */ int do_makelock _P0( void ) { int fd, pid; char *temp, buf[MAXLINE+1]; #ifndef HAVE_MKSTEMP int tries = 0; #endif we_have_lock = FALSE; lprintf( L_NOISE, "do_makelock: lock='%s'", lock ); /* first make a temp file */ #ifdef HAVE_MKSTEMP /* secure, but not as portable */ temp=buf; sprintf(buf, LOCK, "TM.XXXXXX"); if ((fd = mkstemp(temp)) == FAIL ) { lprintf(L_ERROR, "cannot create tempfile (%s)", temp); return(FAIL); } #else /* portable, but subject to some problems on some platforms */ again: sprintf(buf, LOCK, "TM.XXXXXX"); temp = mktemp(buf); unlink(temp); if ((fd = open(temp, O_CREAT|O_WRONLY|O_EXCL, 0644)) == FAIL) { lprintf(L_ERROR, "cannot create tempfile (%s)", temp); if ( errno == EEXIST && ++tries < 20 ) goto again; return(FAIL); } #endif /* just in case some "umask" is set (errors are ignored) */ chmod( temp, 0644 ); /* put my pid in it */ if ( lock_write_pid( fd ) == FAIL) { unlink(temp); return FAIL; } /* link it to the lock file */ while (link(temp, lock) == FAIL) { if (errno != EEXIST ) { lprintf(L_ERROR, "lock not made: link(temp,lock) failed" ); } if (errno == EEXIST) /* lock file already there */ { if ((pid = readlock(lock)) == FAIL) { if ( errno == ENOENT ) /* disappeared */ continue; else { lprintf( L_NOISE, "cannot read lockfile" ); unlink(temp); return FAIL; } } if (pid == getpid()) /* huh? WE locked the line!*/ { lprintf( L_WARN, "we *have* the line!" ); break; } if ((kill(pid, 0) == FAIL) && errno == ESRCH) { /* pid that created lockfile is gone */ lprintf( L_NOISE, "stale lockfile, created by process %d, ignoring", pid ); if ( unlink(lock) < 0 && errno != EINTR && errno != ENOENT ) { lprintf( L_ERROR, "unlink() failed, giving up" ); unlink(temp); return FAIL; } continue; } lprintf(L_MESG, "lock not made: lock file exists (pid=%d)", pid); } /* if (errno == EEXIST) */ (void) unlink(temp); return(FAIL); } lprintf(L_NOISE, "lock made"); (void) unlink(temp); we_have_lock = TRUE; return(SUCCESS); } /* makelock( Device ) * * lock a device, * using the LOCK directory from mgetty.c resp. get_lock_name() */ int makelock _P1( (device), char *device) { lprintf(L_NOISE, "makelock(%s) called", device); if ( get_lock_name( lock, device ) == NULL ) { lprintf( L_ERROR, "cannot get lock name" ); return FAIL; } return do_makelock(); } /* steal_lock( device, process id ) * * steal a lock file from process "id", used for callback handover */ int steal_lock _P2((device, pid), char * device, int pid ) { int retcode, is_pid, fd; lprintf(L_NOISE, "steal_lock(%s) called", device); if ( get_lock_name( lock, device ) == NULL ) { lprintf( L_ERROR, "cannot get lock name" ); return FAIL; } is_pid = readlock(lock); if ( is_pid != pid ) { lprintf( L_ERROR, "PIDs do not match, lock process is %d, should be %d", is_pid, pid ); return FAIL; } /*!!! FIXME: there is a race condition here (is it?) */ fd = open( lock, O_RDWR ); if ( fd < 0 ) { lprintf( L_ERROR, "can't open %s for read/write", lock ); return FAIL; } retcode = lock_write_pid( fd ); if ( retcode == SUCCESS ) we_have_lock = TRUE; return retcode; } /* makelock_file( lock file ) * * make a lock file with a given name (used for locking of other files * than device nodes) */ int makelock_file _P1( (file), char * file ) { lprintf(L_NOISE, "makelock_file(%s) called", file); strcpy( lock, file ); return do_makelock(); } /* * checklock() - test for presence of valid lock file * * if lockfile found, return PID of process holding it, 0 otherwise */ int checklock _P1( (device), char * device) { int pid; struct stat st; char name[MAXLINE+1]; if ( get_lock_name( name, device ) == NULL ) { lprintf( L_ERROR, "cannot get lock name" ); return NO_LOCK; } if ((stat(name, &st) == FAIL) && errno == ENOENT) { lprintf(L_NOISE, "checklock: stat failed, no file"); return NO_LOCK; } if ((pid = readlock(name)) == FAIL) { lprintf(L_MESG, "checklock: couldn't read lockfile"); return NO_LOCK; } if (pid == getpid()) { lprintf(L_WARN, "huh? It's *our* lock file!" ); return NO_LOCK; } if ((kill(pid, 0) == FAIL) && errno == ESRCH) { lprintf(L_NOISE, "checklock: no active process has lock, will remove"); (void) unlink(name); return NO_LOCK; } lprintf(L_NOISE, "lockfile found, pid=%d", pid ); return pid; } /* * readlock() - read contents of lockfile * * Returns pid read or FAIL on error. * * private function */ static int readlock _P1( (name), char * name ) { int fd, pid; char apid[20]; int length; if ((fd = open(name, O_RDONLY)) == FAIL) return(FAIL); length = read(fd, apid, sizeof(apid)-1); apid[length]=0; /* make sscanf() happy */ pid = 0; if ( length == sizeof( pid ) || sscanf(apid, "%d", &pid) != 1 || pid == 0 ) { pid = * ( (int *) apid ); #if LOCKS_BINARY == 0 lprintf( L_WARN, "compiled with ascii locks, found binary lock file (length=%d, pid=%d)!", length, pid ); #endif } #if LOCKS_BINARY == 1 else { lprintf( L_WARN, "compiled with binary locks, found ascii lock file (length=%d, pid=%d)!", length, pid ); } #endif (void) close(fd); return(pid); } /* lock_write_pid() * * write contents of lock file: my process ID in specified format * * private function */ static int lock_write_pid _P1((fd), int fd) { #if LOCKS_BINARY int bpid; /* must be 4 bytes wide! */ bpid = getpid(); if ( write(fd, &bpid, sizeof(bpid) ) != sizeof(bpid) ) #else char apid[16]; sprintf( apid, "%10d\n", (int) getpid() ); if ( write(fd, apid, strlen(apid)) != strlen(apid) ) #endif { lprintf( L_FATAL, "cannot write PID to (temp) lock file" ); close(fd); return(FAIL); } close(fd); return SUCCESS; } /* * rmlocks() - remove lockfile */ void rmlocks _P0(void) { if ( we_have_lock ) { lprintf( L_NOISE, "removing lock file" ); if ( unlink(lock) == -1 ) lprintf( L_ERROR, "error removing lock file (huh?!)" ); } /* mark lock file as 'not set' */ we_have_lock = FALSE; } /* get_lock_name() * * determine full path + name of the lock file for a given device */ #ifdef SVR4 /* * get_lock_name() - create SVR4 lock file name (Bodo Bauer) */ static char *get_lock_name _P2( (lock, fax_tty), char* lock, char* fax_tty ) { struct stat tbuf; char ttyname[FILENAME_MAX]; lprintf(L_NOISE, "get_lock_name(%s) called", fax_tty); if ( strncmp( fax_tty, "/dev/", 5 ) == 0 ) strcpy( ttyname, fax_tty ); else sprintf(ttyname, "/dev/%s", fax_tty); lprintf(L_NOISE, "-> ttyname %s", ttyname); if (stat(ttyname, &tbuf) < 0) { if(errno == ENOENT) { lprintf(L_NOISE, "device does not exist: %s", ttyname); return(NULL); } else { lprintf(L_NOISE, "could not access line: %s", ttyname); return(NULL); } } sprintf(lock,"%s/LK.%03u.%03u.%03u", LOCK_PATH, major(tbuf.st_dev), tbuf.st_rdev >> 18, minor(tbuf.st_rdev)); lprintf(L_NOISE, "lock file: %s", lock); return(lock); } #else /* not SVR4 */ static char * get_lock_name _P2( (lock_name, device), char * lock_name, char * device ) { #ifdef LOCKS_LOWERCASE /* sco locking convention -> change all device names to lowercase */ char p[MAXLINE+1]; int i; if ( ( i = strlen( device ) ) > sizeof(p) ) { lprintf( L_FATAL, "get_lock_name: device name too long" ); exit(5); } #ifdef LOCKS_ALL_LOWERCASE /* convert the full name */ while ( i >= 0 ) { p[i] = tolower( device[i] ); i--; } #else /* convert only the last character */ strcpy( p, device ); i--; p[i] = tolower( p[i] ); #endif device = p; #endif /* LOCKS_LOWERCASE */ /* throw out all directory prefixes */ if ( strchr( device, '/' ) != NULL ) device = strrchr( device, '/' ) +1; sprintf( lock_name, LOCK, device); return lock_name; } #endif /* !SVR4 */ mgetty-1.1.36/mg_m_init.c0100644000031200001470000003011010356447311013512 0ustar gertfax#ident "$Id: mg_m_init.c,v 4.12 2006/01/03 10:15:37 gert Exp $ Copyright (c) Gert Doering" /* mg_m_init.c - part of mgetty+sendfax * * Initialize (fax-) modem for use with mgetty */ #include #include "syslibs.h" #include #include #include #include #include #ifndef sunos4 #include #endif #ifdef linux # include typedef u_int32_t __u32; # include #endif #include "mgetty.h" #include "tio.h" #include "policy.h" #include "fax_lib.h" #if (defined(M_XENIX) && !defined(M_UNIX)) || defined(NEXTSGTTY) #define O_NOCTTY 0 #endif chat_action_t init_chat_actions[] = { { "ERROR", A_FAIL }, { "BUSY", A_FAIL }, { "NO CARRIER", A_FAIL }, { NULL, A_FAIL } }; static int init_chat_timeout = 20; /* initialize data section */ int mg_init_data _P4( (fd, chat_seq, need_dsr, force_chat_seq), int fd, char * chat_seq[], boolean need_dsr, char * force_chat_seq[] ) { action_t what_action; if ( do_chat( fd, chat_seq, init_chat_actions, &what_action, init_chat_timeout, TRUE ) == SUCCESS ) { return SUCCESS; } /* maybe the modem init failed, because the modem was switched * off. So, we check now that there is a DSR or a CTS signal * coming from the modem - and if not, we sleep until it comes back. * WARNING: this can fail on systems not allowing to read out the * RS232 status lines, thus it is optional, and off by default! */ if ( need_dsr ) { int rs_lines = tio_get_rs232_lines(fd); if ( rs_lines != -1 && (rs_lines & (TIO_F_DSR|TIO_F_CTS) ) == 0 ) { lprintf( L_WARN, "No DSR/CTS signals, assuming modem is switched off, waiting..." ); while( (tio_get_rs232_lines(fd) & (TIO_F_DSR|TIO_F_CTS) ) == 0) { sleep(60); } } } /* if init_chat failed because the modem didn't respond, and we have * a "force_chat" sequence, try this. * (force_chat might contain DLE ETX for voice modems, or just plain * simple +++ATH0 for data modems (mis-)configured with AT&D0) */ if ( what_action == A_TIMOUT && force_chat_seq != NULL ) { lprintf( L_WARN, "init chat timed out, trying force-init-chat" ); if ( do_chat( fd, force_chat_seq, init_chat_actions, &what_action, init_chat_timeout, TRUE ) == SUCCESS || what_action != A_TIMOUT ) { lprintf( L_NOISE, "force-init succeeded, retrying init-chat"); clean_line(fd, 3); if ( do_chat( fd, chat_seq, init_chat_actions, &what_action, init_chat_timeout, TRUE ) == SUCCESS ) { return SUCCESS; } } } /* either no force_chat available, or that didn't help either: BARF! */ errno = ( what_action == A_TIMOUT )? EINTR: EINVAL; lprintf( L_ERROR, "init chat failed, exiting..." ); return FAIL; } /* initialization stuff for fax */ /* initialize fax section */ int mg_init_fax _P5( (fd, mclass, fax_id, fax_only, fax_max_speed), int fd, char * mclass, char * fax_id, boolean fax_only, int fax_max_speed ) { /* find out whether this beast is a fax modem... */ modem_type = fax_get_modem_type( fd, mclass ); if ( modem_type == Mt_data ) { lprintf( L_NOISE, "no class 2/2.0 faxmodem, no faxing available" ); return FAIL; } if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) { /* set adaptive answering */ char aabuf[20]; sprintf( aabuf, "AT+FA%s=%d", modem_type == Mt_class1? "E": "A", fax_only? 0:1 ); if ( mdm_command( aabuf, fd ) == FAIL ) { lprintf( L_MESG, "cannot set answer/reception flags" ); } fax_set_bor( fd, 1 ); /* can't fail */ } if ( modem_type == Mt_class2_0 ) { /* set adaptive answering, bit order, receiver on */ if ( mdm_command( fax_only? "AT+FAA=0;+FCR=1": "AT+FAA=1;+FCR=1", fd ) == FAIL ) { lprintf( L_MESG, "cannot set answer/reception flags" ); } if ( fax_set_bor( fd, 1 ) == FAIL ) { lprintf( L_MESG, "cannot set bit order, trying +BOR=0" ); fax_set_bor( fd, 0 ); } /* report everything except NSF (unless asked for it) */ mdm_command( (modem_quirks & MQ_SHOW_NSF)? "AT+FNR=1,1,1,1" : "AT+FNR=1,1,1,0", fd ); } if ( modem_type == Mt_class2 ) { /* even if we know that it's a class 2 modem, set it to * +FCLASS=0: there are some weird modems out there that won't * properly auto-detect fax/data when in +FCLASS=2 mode... * * Exception: Dr.Neuhaus modems do adaptive answering *only* if in * +FCLASS=2 mode -> check flag set by auto-detection */ if ( !fax_only && ! ( modem_quirks & MQ_NEED2 ) ) { if ( mdm_command( "AT+FCLASS=0", fd ) == FAIL ) { lprintf( L_MESG, "weird: cannot set class 0" ); } } /* now, set various flags and modem settings. Failures are logged, but ignored - after all, either the modem works or not, we'll see it when answering the phone ... */ /* set adaptive answering, bit order, receiver on */ if ( mdm_command( fax_only? "AT+FAA=0;+FCR=1": "AT+FAA=1;+FCR=1", fd ) == FAIL ) { lprintf( L_MESG, "cannot set answer/reception flags" ); } if ( fax_set_bor( fd, 0 ) == FAIL ) { lprintf( L_MESG, "cannot set bit order. Huh?" ); } } /* common part for class 2 and class 2.0 */ /* local fax station id */ fax_set_l_id( fd, fax_id ); /* capabilities */ if ( fax_set_fdcc( fd, 1, fax_max_speed, 0 ) == FAIL ) { lprintf( L_MESG, "huh? Cannot set +FDCC parameters" ); } return SUCCESS; } /* initialize fax poll server functions (if possible) */ extern char * faxpoll_server_file; /* in faxrec.c */ void faxpoll_server_init _P2( (fd,f), int fd, char * f ) { faxpoll_server_file = NULL; if ( access( f, R_OK ) != 0 ) { lprintf( L_ERROR, "cannot access/read '%s'", f ); } else if ( mdm_command( modem_type == Mt_class2_0? "AT+FLP=1":"AT+FLPL=1", fd ) == FAIL) { lprintf( L_WARN, "faxpoll_server_init: no polling available" ); } else { faxpoll_server_file = f; lprintf( L_NOISE, "faxpoll_server_init: OK, waiting for poll" ); } } /* open device (non-blocking / blocking) * * open with O_NOCTTY, to avoid preventing dial-out processes from * getting the line as controlling tty */ int mg_open_device _P2 ( (devname, blocking), char * devname, boolean blocking ) { int fd; if ( ! blocking ) { fd = open(devname, O_RDWR | O_NDELAY | O_NOCTTY ); if ( fd < 0 ) { lprintf( L_FATAL, "mod: cannot open line %s", devname ); return ERROR; } /* unset O_NDELAY (otherwise waiting for characters */ /* would be "busy waiting", eating up all cpu) */ fcntl( fd, F_SETFL, O_RDWR); } else /* blocking open */ { again: lprintf( L_MESG, "mod: blocking-open(%s)", devname ); fd = open( devname, O_RDWR | O_NOCTTY ); if ( fd < 0) { if ( errno == EAGAIN ) goto again; lprintf( L_FATAL, "mod: cannot open line %s", devname ); return ERROR; } } #ifdef NEXTSGTTY /* get rid of controlling tty: on NeXT, there is no O_NOCTTY */ ioctl( fd, TIOCNOTTY, 0 ); #endif /* make new fd == stdin if it isn't already */ if (fd > 0) { (void) close(0); if (dup(fd) != 0) { lprintf( L_FATAL, "mod: cannot make %s stdin", devname ); return ERROR; } } /* make stdout and stderr, too */ (void) close(1); (void) close(2); if (dup(0) != 1) { lprintf( L_FATAL, "mod: cannot dup to stdout"); return ERROR; } if (dup(0) != 2) { lprintf( L_FATAL, "mod: cannot dup to stderr"); return ERROR; } if ( fd > 2 ) (void) close(fd); /* switch off stdio buffering */ setbuf(stdin, (char *) NULL); setbuf(stdout, (char *) NULL); setbuf(stderr, (char *) NULL); return NOERROR; } /* init device: toggle DTR (if requested), set TIO values */ int mg_init_device _P4( (fd, toggle_dtr, toggle_dtr_waittime, portspeed ), int fd, boolean toggle_dtr, int toggle_dtr_waittime, unsigned int portspeed ) { TIO tio; if (toggle_dtr) { lprintf( L_MESG, "lowering DTR to reset Modem" ); tio_toggle_dtr( fd, toggle_dtr_waittime ); } #ifdef TIOCSSOFTCAR /* turn off SunOS soft carrier "feature" */ { int off = 0; if ( ioctl( fd, TIOCSSOFTCAR, &off ) < 0 ) lprintf( L_ERROR, "cannot turn off soft carrier" ); } #endif /* initialize port */ if ( tio_get( fd, &tio ) == ERROR ) { lprintf( L_FATAL, "cannot get TIO" ); return ERROR; } tio_mode_sane( &tio, TRUE ); /* initialize all flags */ tio_set_speed( &tio, portspeed ); /* set bit rate */ tio_default_cc( &tio ); /* init c_cc[] array */ tio_mode_raw( &tio ); #ifdef sun /* SunOS does not rx with RTSCTS unless carrier present */ tio_set_flow_control( STDIN, &tio, (DATA_FLOW) & (FLOW_SOFT) ); #else tio_set_flow_control( STDIN, &tio, DATA_FLOW ); #endif if ( tio_set( STDIN, &tio ) == ERROR ) { lprintf( L_FATAL, "cannot set TIO" ); return ERROR; } #ifdef linux /* if port speed is set to 38400, kernel flag might turn it into * 57600 or 115200. Make sure the user knows about it! */ if ( portspeed == 38400 ) { struct serial_struct serinfo; if ( ioctl( STDIN, TIOCGSERIAL, &serinfo ) == 0 && ( serinfo.flags & ASYNC_SPD_MASK ) != 0 ) { lprintf( L_WARN, "WARNING: obsolete setserial spd_hi/spd_vhi used, 38400 is not real port speed" ); } } #endif return NOERROR; } /* open + initialize device * * if first init fails, try again: on Linux and SunOS, the port isn't * able anymore after carrier drop, but after reopening it, it is. */ int mg_get_device _P5( (devname, blocking_open, toggle_dtr, toggle_dtr_waittime, portspeed ), char * devname, boolean blocking_open, boolean toggle_dtr, int toggle_dtr_waittime, unsigned int portspeed) { boolean first_try = TRUE; int rs_lines; /* most likely, HUPCL was set and so DTR is low right now. Give * modem some time to settle down. */ delay(500); /* open device, make it stdin/out/err */ try_again: if ( mg_open_device( devname, blocking_open ) == ERROR ) { lprintf( L_FATAL, "open device %s failed", devname ); return ERROR; } /* catch "standard question #17" (DCD drop -> fd invalid -> I/O error) */ rs_lines = tio_get_rs232_lines(STDIN); if ( rs_lines != -1 ) { #ifdef linux if ( rs_lines & TIO_F_DCD ) lprintf( L_MESG, "WARNING: DCD line still active, check modem settings (AT&Dx)" ); #endif if ( ! (rs_lines & TIO_F_DSR) ) lprintf( L_WARN, "WARNING: DSR is off - modem turned off or bad cable?" ); } /* initialize device (hangup, raw, speed). May fail! */ if ( mg_init_device( STDIN, toggle_dtr, toggle_dtr_waittime, portspeed ) == ERROR ) { if ( first_try ) { lprintf( L_WARN, "mg_init_device failed, trying again" ); first_try = FALSE; goto try_again; } lprintf( L_FATAL, "mg_init_device failed, exiting" ); return ERROR; } return NOERROR; } /* get a given tty as controlling tty * * on many systems, this works with ioctl( TIOCSCTTY ), on some * others, you have to reopen the device */ int mg_get_ctty _P2( (fd, devname), int fd, char * devname ) { /* BSD systems, Linux, *NOT* HP-UX */ #if defined( TIOCSCTTY ) && !defined( _HPUX_SOURCE) if ( setsid() == -1 && errno != EPERM ) { lprintf( L_ERROR, "cannot make myself session leader (setsid)" ); } if ( ioctl( fd, TIOCSCTTY, NULL ) != 0 ) { lprintf( L_ERROR, "cannot set controlling tty (ioctl)" ); if ( getppid() != 1 ) { lprintf( L_WARN, ">>> this might be caused because you have run mgetty/vgetty" ); lprintf( L_WARN, ">>> from the command line. Don't do that, use /etc/inittab!" ); } return ERROR; } #else /* SVR3 and earlier */ fd = open( devname, O_RDWR | O_NDELAY ); if ( fd == -1 ) { lprintf( L_ERROR, "cannot set controlling tty (open)" ); return ERROR; } fcntl( fd, F_SETFL, O_RDWR); /* unset O_NDELAY */ close( fd ); #endif /* !def TIOCSCTTY */ return NOERROR; } mgetty-1.1.36/modem.c0100644000031200001470000001114006442112172012646 0ustar gertfax#ident "$Id: modem.c,v 4.4 1997/12/05 23:48:08 gert Exp $ Copyright (c) Gert Doering" /* modem.c * * Module containing *very* basic modem functions * - send a command * - get a response back from the modem * - send a command, wait for OK/ERROR response */ #include #include #include #include #include #include #include "mgetty.h" #include "policy.h" /* get one line from the modem, only printable characters, terminated * by \r or \n. The termination character is *not* included */ char * mdm_get_line _P1( (fd), int fd ) { static char buffer[200]; int bufferp; char c; bufferp = 0; lprintf( L_JUNK, "got:" ); do { if( mdm_read_byte( fd, &c ) != 1 ) { lprintf( L_ERROR, "mdm_get_line: cannot read byte, return" ); return NULL; } lputc( L_JUNK, c ); if ( isprint( c ) && bufferp < sizeof(buffer) ) { buffer[ bufferp++ ] = c; } } while ( bufferp == 0 || ( c != 0x0a && c != 0x0d ) ); buffer[bufferp] = 0; return buffer; } /* wait for a given modem response string, * handle all the various class 2 / class 2.0 status responses */ static boolean fwf_timeout = FALSE; static RETSIGTYPE fwf_sig_alarm(SIG_HDLR_ARGS) /* SIGALRM handler */ { signal( SIGALRM, fwf_sig_alarm ); lprintf( L_WARN, "Warning: got alarm signal!" ); fwf_timeout = TRUE; } /* send a command string to the modem, terminated with the * MODEM_CMD_SUFFIX character / string from policy.h */ int mdm_send _P2( (send, fd), char * send, int fd ) { #ifdef DO_CHAT_SEND_DELAY delay(DO_CHAT_SEND_DELAY); #endif lprintf( L_MESG, "mdm_send: '%s'", send ); if ( write( fd, send, strlen( send ) ) != strlen( send ) || write( fd, MODEM_CMD_SUFFIX, sizeof(MODEM_CMD_SUFFIX)-1 ) != ( sizeof(MODEM_CMD_SUFFIX)-1 ) ) { lprintf( L_ERROR, "mdm_send: cannot write" ); return ERROR; } return NOERROR; } /* simple send / expect sequence, for things that do not require * parsing of the modem responses, or where the side-effects are * unwanted. */ int mdm_command _P2( (send, fd), char * send, int fd ) { char * l; if ( mdm_send( send, fd ) == ERROR ) return ERROR; /* wait for OK or ERROR, *without* side effects (as fax_wait_for * would have) */ signal( SIGALRM, fwf_sig_alarm ); alarm(10); fwf_timeout = FALSE; do { l = mdm_get_line( fd ); if ( l == NULL ) break; lprintf( L_NOISE, "mdm_command: string '%s'", l ); } while ( strcmp( l, "OK" ) != 0 && strcmp( l, "ERROR" ) != 0 ); alarm(0); signal( SIGALRM, SIG_DFL ); if ( l == NULL || strcmp( l, "ERROR" ) == 0 ) { lputs( L_MESG, " -> ERROR" ); return ERROR; } lputs( L_MESG, " -> OK" ); return NOERROR; } /* mdm_read_byte * read one byte from "fd", with buffering * caveat: only one fd allowed (only one buffer), no way to flush buffers */ int mdm_read_byte _P2( (fd, c), int fd, char * c ) { static char frb_buf[512]; static int frb_rp = 0; static int frb_len = 0; if ( frb_rp >= frb_len ) { frb_len = read( fd, frb_buf, sizeof( frb_buf ) ); if ( frb_len <= 0 ) { if ( frb_len == 0 ) errno = 0; /* undefined otherwise */ lprintf( L_ERROR, "mdm_read_byte: read returned %d", frb_len ); return frb_len; } frb_rp = 0; } *c = frb_buf[ frb_rp++ ]; return 1; } /* for modem identify (and maybe other nice purposes, who knows) * this function is handy: * - send some AT command, wait for OK/ERROR or 10 seconds timeout * - return a pointer to a static buffer holding the "nth" non-empty * answer line from the modem (for multi-line responses), or the * last line if n==-1 */ char * mdm_get_idstring _P3( (send, n, fd), char * send, int n, int fd ) { char * l; int i; static char rbuf[80]; if ( mdm_send( send, fd ) == ERROR ) return ""; /* wait for OK or ERROR, *without* side effects (as fax_wait_for * would have) */ signal( SIGALRM, fwf_sig_alarm ); alarm(10); fwf_timeout = FALSE; i=0; rbuf[0] = '\0'; while(1) { l = mdm_get_line( fd ); if ( l == NULL ) break; /* error */ if ( strcmp( l, send ) == 0 ) continue; /* command echo */ if ( strcmp( l, "OK" ) == 0 || /* final string */ strcmp( l, "ERROR" ) == 0 ) break; i++; lprintf( L_NOISE, "mdm_gis: string %d: '%s'", i, l ); if ( i==-1 || i==n ) /* copy string */ { strncpy( rbuf, l, sizeof(rbuf)-1); rbuf[sizeof(rbuf)-1]='\0'; } } alarm(0); signal( SIGALRM, SIG_DFL ); if ( l == NULL ) return ""; /* error */ return rbuf; } mgetty-1.1.36/ring.c0100644000031200001470000002232010220236551012503 0ustar gertfax#ident "$Id: ring.c,v 4.20 2005/03/23 09:56:57 gert Exp $ Copyright (c) Gert Doering" /* ring.c * * This module handles incoming RINGs, distinctive RINGs (RING 1, RING 2, * etc.), and out-of-band messages (v, "CONNECT", ...). * * Also, on ISDN "modems", multiple subscriber numbers (MSN) are mapped * to distinctive RING types. At least, if the ISDN device returns this * data. It's known to work for ZyXEL and ELSA products. * * Works closely with "cnd.c" to grab CallerID for analog modems. */ #include #include "syslibs.h" #include #include #include #include #ifndef EINTR #include #endif #include "mgetty.h" #include "policy.h" #include "tio.h" #include "fax_lib.h" /* strdup variant that returns "" in case of out-of-memory */ static char * safedup( char * in ) { char * p = strdup( in ); return ( p == NULL ) ? "" : p; } /* find number given in msn_list, return index */ static int find_msn _P2((string, msn_list), char * string, char ** msn_list ) { int i, len, len2; char * p; lprintf( L_NOISE, "MSN: '%s'", string ); CalledNr = safedup(string); /* save away */ if ( msn_list == NULL ) return 0; /* nothing to match against */ len=strlen(string); /* hack off sub-addresses ("/") * (future versions could do comparisons with and without subaddr...) */ p = strchr( string, '/' ); if ( p != NULL ) { len = (p - string); } for( i=0; msn_list[i] != NULL; i++ ) { lprintf( L_JUNK, "match: '%s'", msn_list[i] ); len2=strlen( msn_list[i] ); if ( len2 <= len && strncmp( msn_list[i], &string[len-len2], len2 ) == 0 ) { return i+1; } } return 0; /* not found -> unspecified */ } /* ELSA CallerID data comes in as "RING;[;]" * * this function is also used for others that report the number in * the format [non-digit(s)][non-digit(s)] */ static int ring_handle_ELSA _P2((string, msn_list), char * string, char ** msn_list ) { char * p; char ch; lprintf( L_MESG, "ELSA: '%s'", string ); /* remember first character, for differenciation between * ELSA-style ("RING;from") and ISDN4Linux ("RING/to") [grrr] */ ch = *string; /* skip over leading "garbage" */ while( *string != '\0' && !isdigit(*string) ) string++; /* grab caller number (all up to the first non-digit) */ p=string; while( isdigit(*p) ) p++; if ( *p == '\0' ) /* only one number listed */ { if ( ch == '/' ) /* isdn4linux -> number is MSN */ return find_msn( string, msn_list ); /* not -> it's caller ID, and no MSN */ CallerId = safedup( string ); return 0; } else /* MSN listed -> terminate string, get MSN */ { *p = '\0'; CallerId = safedup( string ); p++; while( *p != '\0' && !isdigit(*p) ) p++; return find_msn( p, msn_list ); } } /* Zoom MX/S CallerID data comes in as "RING: DN " * contributed by Thomas Schuett */ static int ring_handle_ZoomMX _P1((string), char * string) { char * p; lprintf( L_MESG, "Zoom MX/S: '%s'", string ); p=&string[8]; while( isdigit(*p) ) p++; *p = '\0'; CallerId = safedup( &string[8] ); return ( string[6]-'0'); } /* ZyXEL CallerID data comes in as "FM: [TO:]" or "TO:" * * unless Subadressing is used, in which case this looks like * [FM:[CallingPN] [/Subaddress/]][TO:[CalledPN] [/Subaddress/]] * for now, subaddresses are completely ignored (here and in find_msn) */ static int ring_handle_ZyXEL _P2((string, msn_list), char * string, char ** msn_list ) { char * p, ch; lprintf( L_MESG, "ZyXEL: '%s'", string ); if ( strncmp( string, "FM:", 3 ) == 0 ) /* caller ID */ { string+=3; p=string; while( isdigit(*p) ) p++; ch = *p; *p = '\0'; CallerId = safedup(string); *p = ch; while( isspace(*p) ) p++; /* skip potential sub-addresses ("//") */ if ( *p == '/' ) { p++; while ( *p != '\0' && *p != '/' ) { p++; } if ( *p != '\0' ) p++; } string = p; } if ( strncmp( string, "TO:", 3 ) == 0 ) /* target msn */ { return find_msn( string+3, msn_list ); } return 0; /* unspecified */ } /* handle V.253 DRON/DROF result codes * (signalling "Ring ON" / "Ring OFf" time) * * basically we build a binary word from the RINGs, and use that as * distinctive RING number. "Long" = 1, "Short" = 0 * * the very first code (always DROF) is always "long". * * example cadence (standard verizon "one long RING" call): * DROF=0 * DRON=11 * RING * DROF=40 * DRON=20 * RING */ static int drox_bitstring; static int drox_count; static void ring_handle_DROx( char * p ) { int len, bit; /* skip whitespace and '=' (covers "DRON=nnn" and "DRON = nnn") */ while( isspace(*p) || *p == '=' ) { p++; } len = atoi( p ); bit = ( drox_count == 0 || len > 9 ) ? 1 : 0; lputs( L_NOISE, bit? "": "" ); drox_bitstring = (drox_bitstring << 1 ) | bit; drox_count++; } static boolean chat_has_timeout; static RETSIGTYPE chat_timeout(SIG_HDLR_ARGS) { chat_has_timeout = TRUE; } extern boolean virtual_ring; int wait_for_ring _P6((fd, msn_list, timeout, actions, action, dist_ring_number), int fd, char ** msn_list, int timeout, chat_action_t actions[], action_t * action, int * dist_ring_number ) { #define BUFSIZE 500 char buf[BUFSIZE], ch, *p; int i, w, r; int rc = SUCCESS; boolean got_dle; /* for events (voice mode) */ lprintf( L_MESG, "wfr: waiting for ``RING''" ); lprintf( L_NOISE, "got: "); w=0; got_dle = FALSE; signal( SIGALRM, chat_timeout ); alarm( timeout ); chat_has_timeout = FALSE; while(TRUE) { if ( virtual_ring ) { lputs( L_NOISE, "``found''" ); break; } r = mdm_read_byte( fd, &ch ); if ( r <= 0 ) /* unsuccessful */ { if ( chat_has_timeout ) /* timeout */ lprintf( L_WARN, "wfr: timeout waiting for RING" ); else lprintf( L_ERROR, "wfr: error in read()" ); if ( action != NULL ) *action = A_TIMOUT; rc = FAIL; break; } lputc( L_NOISE, ch ); /* In voice mode, modems send sequences to signal * certain events, among them (IS-101) "RING". */ if ( got_dle ) /* last char was */ { switch( ch ) { case 'h': case 'p': /* handset on hook */ case 'H': case 'P': /* handset off hook */ case 'r': /* ringback detected */ *dist_ring_number = - (int)ch; goto have_ring; break; case 'R': /* RING detected */ *dist_ring_number = 0; goto have_ring; break; default: got_dle = FALSE; } } else if ( ch == DLE ) got_dle = TRUE; /* line termination character? no -> add to buffer and go on */ if ( ch != '\r' && ch != '\n' ) { /* skip whitespace at start of buffer */ if ( w == 0 && isspace(ch) ) continue; /* add character to buffer */ if( w < BUFSIZ-2 ) buf[w++] = ch; /* check for "actions" */ if ( actions != NULL ) for( i=0; actions[i].expect != NULL; i++ ) { int len = strlen( actions[i].expect ); if ( w == len && memcmp( buf, actions[i].expect, len ) == 0 ) { lprintf( L_MESG, "wfr: found action string: ``%s''", actions[i].expect ); *action = actions[i].action; rc = FAIL; break; } } if ( rc == FAIL ) break; /* break out of while() */ /* go on */ continue; } /* got a full line */ if ( w == 0 ) { continue; } /* ignore empty lines */ buf[w] = '\0'; cndfind( buf ); /* grab caller ID */ /* ZyXEL CallerID/MSN display? */ if ( strncmp( buf, "FM:", 3 ) == 0 || strncmp( buf, "TO:", 3 ) == 0 ) { *dist_ring_number = ring_handle_ZyXEL( buf, msn_list ); break; } /* Rockwell (et al) caller ID - handled by cndfind(), but * we count it as "RING" to be able to pick up immediately * instead of waiting for the next "real" RING * (but don't do this for V253 DRON/DROF modems!) */ if ( strncmp( buf, "NMBR", 4 ) == 0 && drox_count == 0 ) { break; } /* V.253 ring cadences */ if ( strncmp( buf, "DRON", 4 ) == 0 || strncmp( buf, "DROF", 4 ) == 0 ) { ring_handle_DROx( buf+4 ); w=0; continue; } /* now check the different RING types * if not "RING", clear buffer and get next line */ if ( strncmp( buf, "RING", 4 ) != 0 ) { w = 0; lprintf( L_NOISE, "got: " ); continue; } p=&buf[4]; while( isspace(*p) ) p++; if ( *p == '\0' ) /* "classic RING" */ { break; } if ( *p == ';' ) /* ELSA type */ { *dist_ring_number = ring_handle_ELSA( p, msn_list ); break; } if ( *p== ':' ) /* Zoom MX type */ { *dist_ring_number = ring_handle_ZoomMX( p ); break; } if ( strlen(p) > 1 ) /* USR type B: "RING 1234" */ { *dist_ring_number = ring_handle_ELSA( p, msn_list ); break; } if ( isdigit( *p ) ) /* RING 1 */ { *dist_ring_number = *p-'0'; break; } if ( isalpha( *p ) ) /* RING A */ { *dist_ring_number = tolower(*p)-'a' +1; break; } } have_ring: alarm(0); if ( drox_count > 0 ) { lprintf( L_NOISE, "wfr: DRON/DROF cadence: %x", drox_bitstring ); *dist_ring_number = drox_bitstring; drox_count=0; drox_bitstring=0; } lprintf( L_NOISE, "wfr: rc=%d, drn=%d", rc, *dist_ring_number ); return rc; } mgetty-1.1.36/class1.h0100600000031200001470000001107010520345474012737 0ustar gertfax#ident "$Id: class1.h,v 4.11 2006/09/29 19:31:50 gert Exp $ Copyright (c) Gert Doering" /* class1.h * * common definitions for class 1 fax modules * * $Log: class1.h,v $ * Revision 4.11 2006/09/29 19:31:50 gert * add "scan time" parameter to fax1_send_dcs() * add function fax1_reduce_max() (baud rate stepdown) * add extern declaration for "remote_cap" (in class1lib.c) * * Revision 4.10 2006/06/14 09:54:03 gert * dcs_btp needs to be declared 'extern' * * Revision 4.9 2006/03/29 12:25:02 gert * change type of fax1_dis to uch (unsigned char) * change type of "fcf" in fax1_send_idframe() to uch * * Revision 4.8 2006/01/04 21:06:25 gert * remove "speed" argument from fax1_send_dcs() (use fax1_max global) * * Revision 4.7 2006/01/01 16:02:25 gert * introduce extra argument to fax1_send_dcn to set fax_hangup_code * * Revision 4.6 2005/12/31 17:46:43 gert * add fax1_send_dis() * * Revision 4.5 2005/12/31 15:52:46 gert * move typedef...uch from class1.h to mgetty.h * * Revision 4.4 2005/12/30 23:05:34 gert * update & add various prototypes * * Revision 4.3 2005/12/28 21:46:11 gert * T30_DCN had wrong hex value (should be 0xfa, was 0xfc) * add symbolic values for T30 carrier values (+FRH=3/+FTH=3) * add prototypes for most functions in class1lib.c * add CVS + file description header * */ #define FRAMESIZE 300 extern uch fax1_dis; /* "X"-Bit (received DIS) */ /* class1lib.c */ RETSIGTYPE fax1_sig_alarm(SIG_HDLR_ARGS); void fax1_dump_frame _PROTO(( char io, uch * frame, int len )); int fax1_send_frame _PROTO(( int fd, int carrier, uch * frame, int len )); int fax1_send_simf_final _PROTO(( int fd, int carrier, uch fcf)); int fax1_send_simf_nonfinal _PROTO(( int fd, int carrier, uch fcf)); int fax1_send_dcn _PROTO(( int fd, int code )); void fax1_copy_id _PROTO(( uch * frame )); int fax1_send_idframe _PROTO(( int fd, uch fcf, int carrier)); void fax1_parse_dis _PROTO(( uch * frame )); void fax1_parse_dcs _PROTO(( uch * frame )); int fax1_send_dis _PROTO(( int fd )); int fax1_send_dcs _PROTO(( int fd, int s_time )); int fax1_receive_frame _PROTO (( int fd, int carrier, int timeout, uch * framebuf )); int fax1_init_FRM _PROTO(( int fd, int carrier )); void fax1_reduce_max _PROTO(( void )); /* class1.c */ int fax1_send_page _PROTO(( char * g3_file, int * bytes_sent, TIO * tio, Post_page_messages ppm, int fd )); struct fax1_btable { int speed; /* bit rate */ int flag; /* flag (for capabilities) */ int c_long, c_short; /* carrier numbers */ int dcs_bits; /* bits to be set in DCS */ }; extern struct fax1_btable * dcs_btp; /* current modulation */ extern fax_param_t remote_cap; /* receiver capabilities */ /* --- Definitions from ITU T.30, 07/96 --- */ /* control field - bit set on final frame, T.30 5.3.5 */ #define T30_FINAL 0x10 /* frame types (FCF), T.30 5.3.6, bits reversed! */ #define T30_DIS 0x80 /* Digital Information Signal */ #define T30_CSI 0x40 /* Called Subscriber Information */ #define T30_NSF 0x20 /* Non-Standard Facilities */ #define T30_DTC 0x81 /* Digital Transmit Command */ #define T30_CIG 0x41 /* Calling Subscriber Information */ #define T30_NSC 0x21 /* Non-Standard facilities Command */ #define T30_PWD 0xc1 /* Password (for polling) */ #define T30_SEP 0xa1 /* Selective Polling (subaddress) */ #define T30_DCS 0x82 /* Digital Command Signal */ #define T30_TSI 0x42 /* Transmit Subscriber Information */ #define T30_NSS 0x22 /* Non-Standard facilities Setup */ #define T30_SUB 0xc2 /* Subaddress */ #define T30_PWDT 0xa2 /* Password for Transmission */ #define T30_CFR 0x84 /* Confirmation To Receive */ #define T30_FTT 0x44 /* Failure To Train */ #define T30_EOM 0x8e /* End Of Message (end of page -> phase B) */ #define T30_MPS 0x4e /* MultiPage Signal (end of page -> phase C) */ #define T30_EOP 0x2e /* End Of Procedures (over and out) */ #define T30_PRI_EOM 0x9e /* EOM + PRI */ #define T30_PRI_MPS 0x5e /* MPS + PRI */ #define T30_PRI_EOP 0x3e /* EOP + PRI */ #define T30_PRI 0x10 /* bit 4 in FCF -> Procedure Interrupt */ #define T30_MCF 0x8c /* Message Confirmation (page good) */ #define T30_RTP 0xcc /* Retrain Positive */ #define T30_RTN 0x4c /* Retrain Negative */ #define T30_PIP 0xac /* Procedure Interrupt Positive */ #define T30_PIN 0x2c /* Procedure Interrupt Negative */ #define T30_DCN 0xfa /* Disconnect Now (phase E) */ #define T30_CRP 0x1c /* Command Repeat (optional) */ /* carrier values */ #define T30_CAR_SAME 0 /* pseudo-header, don't send AT+FTH/AT+FRH */ #define T30_CAR_V21 3 /* 300 bps for negotiation */ mgetty-1.1.36/class1.c0100644000031200001470000005423510520346100012737 0ustar gertfax#ident "$Id: class1.c,v 4.18 2006/10/27 09:07:12 gert Exp $ Copyright (c) Gert Doering" /* class1.c * * High-level functions to handle class 1 fax -- * state machines for fax phase A, B, C, D. Error recovery. * * Uses library functions in class1lib.c, faxlib.c and modem.c * * $Log: class1.c,v $ * Revision 4.18 2006/10/27 09:07:12 gert * add file name of page currently sent to log message * * Revision 4.17 2006/10/25 10:55:01 gert * class 1 receive: log current try #, send DIS only if CSI went without error * * Revision 4.16 2006/09/29 19:30:26 gert * properly calculate scan line time -> padding bytes * implement FTT -> retraining, with baud rate reduction * * Revision 4.15 2006/09/26 15:36:07 gert * - handle modems that don't get AT+FTS=8;+FTM=nn right * (re-do AT+FTM if the first command yields "OK") * - switch on and off Xon/Xoff flow control before/after sending page data * * Revision 4.14 2006/09/25 22:26:54 gert * fax1_send_page(): move all the G3 file handling to g3file.c functions * (-> cleanup code, build common infrastructure for class 1 + class 2) * * Revision 4.13 2006/03/22 14:13:12 gert * when sending, hand over received NSF to NSF decoder (faxlib.c/hyla_nsf.c) * * Revision 4.12 2006/03/07 21:31:50 gert * class 1 sending implementation: * - handle end-of-page (return to phase B or phase C, or send DCN/hangup) * - move sending of TSI and DCS inside fax1_send_page(), to be able to * handle RTN/RTP transparently - somewhat sloppy "phase B" definition, * but much cleaner this way * - fix reading of G3 files - skip digifax header, also send last chunk * - fix bit swapping (fax_send_swaptable) * -> class 1 sending now works, if the receiver doesn't need EOL padding * * Revision 4.11 2006/03/07 14:16:56 gert * fax1_dial_and_phase_AB(): add torture test code, refusing incoming CSI/DIS * 2 times before going on (mainly for testing receiver robustness) * fax1_send_page(): add log message to point out unimplemented stuff * * Revision 4.10 2006/01/04 21:07:12 gert * remove "speed" argument from fax1_send_dcs() (use fax1_max global) * * Revision 4.9 2006/01/03 09:12:20 gert * initialize "tries" in fax1_receive_page() * * Revision 4.8 2006/01/01 17:07:43 gert * change all fax1_send_dcn() to already set appropriate hangup code * add prototypes for local functions * add timeout handling and re-try logic to fax1_highlevel_receive(), * fax1_receive_tcf() and fax1_receive_page() * add handling of incoming DCNs (give up) * add calculation of "how long should TCF be?" + checking to fax1_receive_tcf() * * Revision 4.7 2005/12/31 17:47:10 gert * use fax1_send_dis() instead of doing it here * * Revision 4.6 2005/12/31 15:52:08 gert * more comments * fax 1 receiver: * * use global variable fax1_receive_have_connect to * communicate answering status ("have we seen CONNECT?") from mgetty.c * * prepare full T.30 receive state machine, including EOM->phase B * and RTP/RTN->TCF (not complete) * * set fax_hangup/fax_hangup_code correctly upon some error situations * * Revision 4.5 2005/12/30 23:05:05 gert * rework fax1_send_frame(): leading 0xff is now implicit * (symmetric to fax1_receive_frame()) * change all callers to use new "frame" layout without 0xff * change lots of occurences of "3" to use "T30_CAR_V21" * rename fax1_receive() to fax1_highlevel_receive() * use "fd" and not "STDIN" everywhere * hand DCS frame to class1lib/fax1_parse_dcs() * -> use proper carrier values for TCF and page reception (partially untested) * change "simple" frame sending to use fax1_send_simf_final() * add more comments about individual fax phases * * Revision 4.4 2005/12/28 21:53:08 gert * fix some compiler warnings and typos * adapt to changed fax1_send_idframe() * add CVS header * add (very rough and incomplete) fax class 1 implementation, consisting * - fax1_receive() (to be called from faxrec.c) * - fax1_receive_tcf() (handle TCF training frame + responses) * - fax1_receive_page() (setup page reception, hand to fax_get_page_data()) * */ #ifdef CLASS1 #include #include #include #include #include #include #include "mgetty.h" #include "fax_lib.h" #include "tio.h" #include "class1.h" #include "policy.h" enum T30_phases { Phase_A, Phase_B, Phase_C, Phase_D, Phase_E } fax1_phase; /* maping of "st" codes to actual time (for normal res.) */ static int fax_scan_times[8] = { 0, 5, 10, 10, 20, 20, 40, 40 }; int fax1_dial_and_phase_AB _P2( (dial_cmd,fd), char * dial_cmd, int fd ) { char * p; /* modem response */ uch framebuf[FRAMESIZE]; int first; int len; #ifdef TORTURE_TEST int t_tries=0; #endif /* send dial command */ if ( fax_send( dial_cmd, fd ) == ERROR ) { fax_hangup = TRUE; fax_hangup_code = FHUP_ERROR; return ERROR; } /* wait for ERROR/NO CARRIER/CONNECT */ signal( SIGALRM, fax1_sig_alarm ); alarm(FAX_RESPONSE_TIMEOUT); while( !fax_hangup ) { p = mdm_get_line ( fd ); if ( p == NULL ) { lprintf( L_ERROR, "fax1_dial: hard error dialing out" ); fax_hangup = TRUE; fax_hangup_code = FHUP_ERROR; break; } lprintf( L_NOISE, "fax1_dial: string '%s'", p ); if ( strcmp( p, "ERROR" ) == 0 || strcmp( p, "NO CARRIER" ) == 0 ) { fax_hangup = TRUE; fax_hangup_code = FHUP_ERROR; break; } if ( strcmp( p, "NO DIALTONE" ) == 0 || strcmp( p, "NO DIAL TONE" ) == 0 ) { fax_hangup = TRUE; fax_hangup_code = FHUP_NODIAL; break; } if ( strcmp( p, "BUSY" ) == 0 ) { fax_hangup = TRUE; fax_hangup_code = FHUP_BUSY; break; } if ( strcmp( p, "CONNECT" ) == 0 ) /* gotcha! */ { break; } } alarm(0); if ( fax_hangup ) return ERROR; /* now start fax negotiation (receive CSI, DIS, send DCS) * read all incoming frames until FINAL bit is set */ first=TRUE; again: do { if ( (len = fax1_receive_frame( fd, first? 0:3, 30, framebuf ) ) == ERROR ) { /*!!!! try 3 times! (flow diagram from T.30 / T30_T1 timeout) */ fax_hangup = TRUE; fax_hangup_code = 11; return ERROR; } switch ( framebuf[1] ) /* FCF */ { case T30_CSI: fax1_copy_id( framebuf ); break; case T30_NSF: fax1_incoming_nsf( framebuf+2, len-2 ); break; case T30_DIS: fax1_parse_dis( framebuf ); break; case T30_DCN: fax1_send_dcn( fd, 20 ); return ERROR; default: lprintf( L_WARN, "unexpected frame type 0x%02x", framebuf[1] ); } first=FALSE; } while( ( framebuf[0] & T30_FINAL ) == 0 ); #ifdef TORTURE_TEST while( ++t_tries < 3 ) { mdm_command( "AT+FRS=200", fd ); goto again; } #endif fax1_phase = Phase_B; /* Phase A done */ return NOERROR; } /* fax1_send_page * * send a page of G3 data * - if phase is "B", include sending of DCS, TCF and possibly * baud rate stepdown and repeated transmission of DCS. * - if phase is "C", directly send page data */ int fax1_send_page _P5( (g3_file, bytes_sent, tio, ppm, fd), char * g3_file, int * bytes_sent, TIO * tio, Post_page_messages ppm, int fd ) { uch framebuf[FRAMESIZE]; char * line; char cmd[40]; char dleetx[] = { DLE, ETX }; char rtc[] = { 0x00, 0x08, 0x80, 0x00, 0x08, 0x80, 0x00, 0x08 }; int pad_bytes, s_time; /* if we're in T.30 phase B, send DCS + training frame (TCF) now... * don't forget delay (75ms +/- 20ms)! * * NOTE: this is not strictly "phase B" - in T.30, phase B begins * after sending the DCS, and before sending TCF. But since RTN/RTP * return to sending DCS (bullet "D" in T.30 chart 5-2a), grouping it * this way is much more logical to implement */ /* calculate scan line time * in fine mode, some of the values get divided by 2 */ s_time = fax_scan_times[ remote_cap.st & 0x7 ]; if ( remote_cap.vr == 1 && (remote_cap.st & 0x1) == 0 ) s_time /= 2; if ( fax1_phase == Phase_B ) { char train[150]; int i, num; int tries=0; retrain: /* "(D)" in T.30/Figure 5-2a */ /* send local id frame (TSI) */ fax1_send_idframe( fd, T30_TSI|0x01, T30_CAR_V21 ); /* send DCS */ if ( fax1_send_dcs( fd, s_time ) == ERROR ) { fax_hangup = TRUE; fax_hangup_code = 10; return ERROR; } sprintf( cmd, "AT+FTS=8;+FTM=%d", dcs_btp->c_long ); fax_send( cmd, fd ); line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) line = mdm_get_line( fd ); if ( strcmp( line, "OK" ) == 0 ) { lprintf( L_MESG, "fax1_send_page: unexpected OK, re-do AT+FTM" ); sprintf( cmd, "AT+FTM=%d", dcs_btp->c_long ); fax_send( cmd, fd ); line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) line = mdm_get_line( fd ); } if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { lprintf( L_ERROR, "fax1_send_page: unexpected response 1: '%s'", line ); fax_hangup = TRUE; fax_hangup_code = 20; return ERROR; } /* send data for training (1.5s worth) */ num = (dcs_btp->speed/8)*1.5; lprintf( L_NOISE, "fax1_send_page: send %d bytes training (TCF)", num ); memset( train, 0, sizeof(train)); for( i=0; i 1 ) fax1_reduce_max(); if ( tries < 3 ) goto retrain; /* give up */ fax1_send_dcn( fd, 27 ); return ERROR; } /* phase B done, go to phase C */ fax1_phase = Phase_C; } if ( fax1_phase != Phase_C ) { lprintf( L_ERROR, "fax1_send_page: internal error: not Phase C" ); fax_hangup = TRUE; fax_hangup_code = FHUP_ERROR; return ERROR; } /* open G3 file, read first chunk, potentially skipping digifax header */ if ( g3_open_read( g3_file ) < 0 ) { /*!!! do something smart here...? */ fax1_send_dcn( fd, FHUP_ERROR ); return ERROR; } /* number of bytes to pad depend on scan time */ pad_bytes = ((dcs_btp->speed/8) * s_time + 999) / 1000; lprintf( L_MESG, "scan line time: %d ms -> %d bytes/line at %d bps", s_time, pad_bytes, dcs_btp->speed ); /* Phase C: send page data with high-speed carrier */ sprintf( cmd, "AT+FTM=%d", dcs_btp->c_short ); fax_send( cmd, fd ); line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) line = mdm_get_line( fd ); if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { lprintf( L_ERROR, "fax1_send_page: unexpected response 3: '%s'", line ); fax_hangup = TRUE; fax_hangup_code = 40; return ERROR; } lprintf( L_NOISE, "send page data (\"%s\")...", g3_file ); /* turn on xon/xoff flow control now, for page data sending */ if ( (FAXSEND_FLOW) & FLOW_SOFT ) { tio_set_flow_control( fd, tio, (FAXSEND_FLOW) & (FLOW_HARD|FLOW_XON_OUT)); tio_set( fd, tio ); } /* read page data from file, invert byte order, * insert padding bits (if scan line time > 0), * at end-of-file, add RTC */ if ( g3_send_file( g3_rf_chunk, fd, TRUE, TRUE, pad_bytes, 0 /*TODO!*/) < 0 ) { lprintf( L_ERROR, "error in g3_send_file()" ); return ERROR; } /*!!! ERROR HANDLING!! */ /*!!! PARANOIA: alarm()!! */ /* end of page: RTC */ write( fd, rtc, sizeof(rtc) ); /* end of data: DLE ETX */ write( fd, dleetx, 2 ); line = mdm_get_line( fd ); if ( line == NULL || strcmp( line, "OK" ) != 0 ) { lprintf( L_ERROR, "fax1_send_page: unexpected response 3a: '%s'", line ); fax_hangup = TRUE; fax_hangup_code = 40; return ERROR; } /* turn off xon/xoff flow control (will interfere with received frames) */ if ( (FAXSEND_FLOW) & FLOW_SOFT ) { tio_set_flow_control( fd, tio, (FAXSEND_FLOW) & FLOW_HARD ); tio_set( fd, tio ); } /* now send end-of-page frame (MPS/EOM/EOP) and get pps */ fax1_phase = Phase_D; lprintf( L_MESG, "page data sent, sending end-of-page frame (C->D)" ); sprintf( cmd, "AT+FTS=8;+FTH=3" ); fax_send( cmd, fd ); line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) line = mdm_get_line( fd ); if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { if ( strcmp( line, "OK" ) == 0 ) goto tryanyway; lprintf( L_ERROR, "fax1_send_page: unexpected response 4: '%s'", line ); fax_hangup = TRUE; fax_hangup_code = 50; return ERROR; } /* some modems seemingly can't handle AT+FTS=8;+FTH=3 (returning * "OK" instead of "CONNECT"), so send AT+FTH=3 again for those. */ tryanyway: framebuf[0] = 0x03 | T30_FINAL; switch( ppm ) { case pp_eom: framebuf[1] = T30_EOM | fax1_dis; break; case pp_eop: framebuf[1] = T30_EOP | fax1_dis; break; case pp_mps: framebuf[1] = T30_MPS | fax1_dis; break; default: lprintf( L_WARN, "fax1_send_page: canthappen(1) - PRI not supported" ); } fax1_send_frame( fd, strcmp(line, "OK")==0? 3:0 , framebuf, 2 ); /* get MPS/RTP/RTN code */ fax1_receive_frame( fd, T30_CAR_V21, 30, framebuf ); /*!!! T.30 flow chart... */ switch( framebuf[1] ) { case T30_MCF: /* page good */ fax_page_tx_status = 1; fax1_phase = Phase_C; break; case T30_RTN: /* retrain / negative */ fax_page_tx_status = 2; fax1_phase = Phase_B; break; case T30_RTP: /* retrain / positive */ fax_page_tx_status = 3; fax1_phase = Phase_B; break; case T30_PIN: /* procedure interrupt */ fax_page_tx_status = 4; fax1_phase = Phase_B; break; case T30_PIP: fax_page_tx_status = 5; fax1_phase = Phase_C; break; default: lprintf( L_ERROR, "fax1_transmit_page: unexpected frame" ); fax1_send_dcn(fd, 53); break; } /* if this was the last page, and the receiver is happy * (MCF or RTP), send DCN, and call it quits */ if ( ppm == pp_eop && ( fax_page_tx_status == 1 || fax_page_tx_status == 3 || fax_page_tx_status == 5 ) ) { fax1_send_dcn( fd, 0 ); fax1_phase = Phase_E; } /* otherwise, nothing to do - caller will re-enter fax1_send_page(), * for next page / re-send of same page (we won't know) */ return NOERROR; } boolean fax1_receive_have_connect = FALSE; int fax1_receive_tcf _PROTO((int fd, int carrier, int wantbytes)); int fax1_receive_page _PROTO((int fd, int carrier, int * pagenum, char * dirlist, int uid, int gid, int mode )); int fax1_highlevel_receive _P6( (fd, pagenum, dirlist, uid, gid, mode ), int fd, int * pagenum, char * dirlist, int uid, int gid, int mode) { int rc; uch frame[FRAMESIZE]; char * p; Post_page_messages ppm = pp_mps; boolean first = TRUE; int tries; boolean have_dcs; /* after ATA/CONNECT, first AT+FTH=3 is implicit -> send frames right away (first=TRUE) - when coming back to phase B after EOM, AT+FTH=3 must be sent */ /* with +FAE=1, the sequence seems to be * RING * ATA * FAX * CONNECT */ if ( !fax1_receive_have_connect ) { alarm(10); p = mdm_get_line( fd ); alarm(0); if ( p == NULL || strcmp( p, "CONNECT" ) != 0 ) { lprintf( L_WARN, "fax1_receive: initial CONNECT not seen" ); fax_hangup = TRUE; fax_hangup_code = FHUP_TIMEOUT; return ERROR; } } *pagenum = 0; /* phase B: Fax negotiations */ tries=0; have_dcs=FALSE; receive_phase_b: lprintf( L_MESG, "fax1 T.30 receive phase B (try %d)", tries+1 ); /* send local ID frame (CSI) - non-final */ rc = fax1_send_idframe( fd, T30_CSI, first?T30_CAR_SAME: T30_CAR_V21 ); first = FALSE; /* send DIS (but only if we haven't seen an error sending CSI) */ if ( rc == NOERROR ) rc = fax1_send_dis( fd ); /* now see what the other side has to say... */ wait_for_dcs: do { if ( fax1_receive_frame( fd, T30_CAR_V21, 30, frame ) == ERROR ) { if ( ++tries < 3 ) goto receive_phase_b; fax1_send_dcn( fd, 70 ); return ERROR; } switch( frame[1] & 0xfe ) /* FCF, ignoring X-bit */ { case T30_TSI: fax1_copy_id( frame ); break; case T30_NSF: break; case T30_DCS: fax1_parse_dcs( frame ); have_dcs=TRUE; break; case T30_DCN: fax1_send_dcn( fd, 70 ); return ERROR; break; default: lprintf( L_WARN, "unexpected frame type 0x%02x", frame[1] ); } } while( ( frame[0] & T30_FINAL ) == 0 ); if ( !have_dcs ) { lprintf( L_WARN, "T.30 B: final frame, but no DCS seen, re-send DIS" ); if ( ++tries < 3 ) goto receive_phase_b; fax1_send_dcn( fd, 70 ); return ERROR; } /* fax1_parse_dcs() has setup dcs_btp and fax_par_d for us */ /* receive 1.5s training sequence */ rc = fax1_receive_tcf( fd, dcs_btp->c_long, (dcs_btp->speed/8)*1.5 ); /* error receiving TCF ("no carrier seen") -> redo DIS/DCS */ if ( rc < 0 ) goto receive_phase_b; /* TCF bad? send FTT (failure to train), wait for next DCS */ if ( rc == 0 ) { rc = fax1_send_simf_final( fd, T30_CAR_V21, T30_FTT ); if ( ++tries < 10 ) goto wait_for_dcs; fax1_send_dcn( fd, 73 ); return ERROR; } /* TCF good, send CFR frame (confirmation to receive) */ rc = fax1_send_simf_final( fd, T30_CAR_V21, T30_CFR ); receive_next_page: /* phase C: start page reception & get page data */ lprintf( L_MESG, "fax1 T.30 receive phase C" ); rc = fax1_receive_page( fd, dcs_btp->c_short, pagenum, dirlist, uid, gid, mode ); /* if we have already hung up, not worth doing any retries etc. */ if ( rc == ERROR && fax_hangup ) return ERROR; /* phase D: post-message status * switch back to low-speed carrier, get (PRI-)EOM/MPS/EOP code */ tries=0; receive_phase_d: lprintf( L_MESG, "fax1 T.30 receive phase D" ); /* TODO: T.30 flow chart: will we ever hit non-final frames here? * what to do on error? */ do { if ( fax1_receive_frame( fd, T30_CAR_V21, 30, frame ) == ERROR ) { /* retry post-page handshake 3 times, then give up */ if ( ++tries < 3 ) goto receive_phase_d; fax1_send_dcn( fd, 100 ); return ERROR; } switch( frame[1] & 0xfe & ~T30_PRI ) /* FCF, ignoring X-bit */ { case T30_MPS: lprintf( L_MESG, "MPS: end of page, more to come" ); ppm = pp_mps; break; case T30_EOM: lprintf( L_MESG, "EOM: back to phase B" ); ppm = pp_eom; break; case T30_EOP: lprintf( L_MESG, "EOP: end of transmission" ); ppm = pp_eop; break; case T30_DCN: fax1_send_dcn( fd, 101 ); return ERROR; break; default: lprintf( L_WARN, "unexpected frame type 0x%02x", frame[1] ); } } while( ( frame[0] & T30_FINAL ) == 0 ); /* send back page good/bad return code (TODO: RTN/RTP codes) */ /* TODO: for RTN/RTP, restart training sequence (TCF) (??) */ rc = fax1_send_simf_final( fd, T30_CAR_V21, T30_MCF ); /* go back to phase B (EOM), go to next page (MPS), done (EOP) */ if ( ppm == pp_eom ) { goto receive_phase_b; } if ( ppm == pp_mps ) { goto receive_next_page; } /* EOP - get goodbye frame (DCN) from remote end, hang up */ fax1_receive_frame( fd, T30_CAR_V21, 30, frame ); if ( (frame[1] & 0xfe) != T30_DCN ) { lprintf( L_WARN, "fax1_receive: unexpected frame 0x%02x 0x%02x after EOP", frame[0], frame[1] ); } fax_hangup = TRUE; fax_hangup_code = 0; return NOERROR; } int fax1_receive_tcf _P3((fd,carrier,wantbytes), int fd, int carrier, int wantbytes) { int rc, count, notnull; char c, *p; boolean wasDLE=FALSE; int tries; tries=0; lprintf( L_NOISE, "fax1_r_tcf: carrier=%d", carrier ); get_carrier: rc = fax1_init_FRM( fd, carrier ); if ( rc == ERROR ) { while( ++tries<3 ) goto get_carrier; return ERROR; } /* TODO: proper timeout settings as per T.30 (?) */ alarm(5); count = notnull = 0; lprintf( L_JUNK, "fax1_r_tcf: got: " ); while(1) { if ( mdm_read_byte( fd, &c ) != 1 ) { /* timeout? corrupted DLE/ETX? let caller send FTT and retry */ lprintf( L_ERROR, "fax1_r_tcf: cannot read byte, return" ); return 0; } if ( c != 0 ) lputc( L_JUNK, c ); if ( wasDLE ) { if ( c == ETX ) break; wasDLE = 0; } if ( c == DLE ) { wasDLE = 1; continue; } count++; if ( c != 0 ) notnull++; } /* read post-frame "NO CARRIER" message */ p = mdm_get_line( fd ); alarm(0); if ( p == NULL || strcmp( p, "NO CARRIER" ) != 0 ) lprintf( L_WARN, "unexpected post-TCF modem response: '%s'", p ); if ( count < (wantbytes*3)/4 || /* not enough bytes */ notnull > count/10 ) /* or too many errors */ { lprintf( L_NOISE, "TCF: want %d, got %d, %d non-null -> retry", wantbytes, count, notnull ); return 0; /* try again */ } lprintf( L_NOISE, "TCF: want %d, got %d, %d non-null -> OK", wantbytes, count, notnull ); return 1; /* acceptable, go ahead */ } int fax1_receive_page _P7( (fd,carrier,pagenum,dirlist,uid,gid,mode), int fd, int carrier, int * pagenum, char * dirlist, int uid, int gid, int mode ) { int rc; char *p; int tries; char directory[MAXPATH]; fax_find_directory( dirlist, directory, sizeof(directory) ); tries=0; lprintf( L_NOISE, "fax1_rp: carrier=%d", carrier ); get_carrier: /* TODO: proper timeout settings as per T.30 */ alarm(10); rc = fax1_init_FRM( fd, carrier ); alarm(0); if ( rc == ERROR ) { if ( ++tries < 3 ) goto get_carrier; fax1_send_dcn( fd, 90 ); return ERROR; } /* now get page data (common function for class 1 and class 2) * note: fax_get_page_data() has its own alarm/timeout handling */ rc = fax_get_page_data( fd, ++(*pagenum), directory, uid, gid, mode ); /* read post-page "NO CARRIER" message */ alarm(10); p = mdm_get_line( fd ); alarm(0); if ( p == NULL || strcmp( p, "NO CARRIER" ) != 0 ) lprintf( L_WARN, "unexpected post-page modem response: '%s'", p ); if ( rc == ERROR ) { fax1_send_dcn( fd, 90 ); return ERROR; } /* TODO: copy quality checking */ return NOERROR; } #endif /* CLASS 1 */ mgetty-1.1.36/class1lib.c0100600000031200001470000006236410520345474013435 0ustar gertfax#ident "$Id: class1lib.c,v 4.20 2006/10/25 10:56:41 gert Exp $ Copyright (c) Gert Doering" /* class1lib.c * * Low-level functions to handle class 1 fax -- * send a frame, receive a frame, dump frame to log file, ... */ #ifdef CLASS1 #include #include #include #include #include #include #include #include "mgetty.h" #include "fax_lib.h" #include "tio.h" #include "class1.h" /* static variables * * only set by functions in this module and used by other functions, * but have to be module-global */ #define F1LID 20 static char fax1_local_id[F1LID]; /* local system ID */ static int fax1_min = 2400, /* min/max speed */ fax1_max = 14400; static int fax1_res; /* flag for normal resolution */ uch fax1_dis = 0x00; /* "X"-bit (last received DIS) */ static int fax1_fth, fax1_ftm, /* modem carrier capabilities */ fax1_frh, fax1_frm; /* symbolic constants for capability check */ #define V17 0xF00 #define V17_14400 0x800 #define V17_12000 0x400 #define V17_9600 0x200 #define V17_7200 0x100 #define V29 0x0F0 #define V29_9600 0x080 #define V29_7200 0x040 #define V27ter 0x00e #define V27t_4800 0x008 #define V27t_2400 0x004 #define V21 0x001 /* table of baud rate / carrier number / DCS bits */ struct fax1_btable fax1_btable[] = { { 14400, V17_14400, 145, 146, 0x20 /* 0001 */ }, { 12000, V17_12000, 121, 122, 0x28 /* 0101 */ }, { 9600, V17_9600, 97, 98, 0x24 /* 1001 */ }, { 9600, V29_9600, 96, 96, 0x04 /* 1000 */ }, { 7200, V17_7200, 73, 74, 0x2c /* 1101 */ }, { 7200, V29_7200, 72, 72, 0x0c /* 1100 */ }, { 4800, V27t_4800, 48, 48, 0x08 /* 0100 */ }, { 2400, V27t_2400, 24, 24, 0x00 /* 0000 */ }, { 300, V21, 3, 3, 0 }, { -1, -1,0,0,0 }}; /* pointer to current modulation in fax1_btable * (increment == fallback after FTT!) */ struct fax1_btable * dcs_btp = fax1_btable; /* table of bits-to-scan line time mappings, index = bits */ struct fax1_st_table { int st; int ms_n; int ms_f; char * txt; }; struct fax1_st_table fax1_st_table[8] = { /* ST, ms normal, ms fine bits */ { 5, 20, 20, " 20ms" }, /* 0 = 000 */ { 1, 5, 5, " 5ms" }, /* 1 = 100 */ { 3, 10, 10, " 10ms" }, /* 2 = 010 */ { 4, 20, 10, " 20/10ms" }, /* 3 = 110 */ { 7, 40, 40, " 40ms" }, /* 4 = 001 */ { 6, 40, 20, " 40/20ms" }, /* 5 = 101 */ { 2, 10, 5, " 10/5ms" }, /* 6 = 011 */ { 0, 0, 0, " 0ms" }}; /* 7 = 111 */ int fax1_set_l_id _P2( (fd, fax_id), int fd, char * fax_id ) { int i,l; char *p; l = strlen( fax_id ); if ( l > F1LID ) { l = F1LID; } /* bytes are transmitted in REVERSE order! */ p = &fax1_local_id[F1LID-1]; for ( i=0; ispeed > 0 ) { if ( cnr == btp->c_short || cnr == btp->c_long ) { cbits |= btp->flag; break; } btp++; } } return cbits; } /* step down max speed (at retrain time) */ void fax1_reduce_max _P0(void) { if ( dcs_btp->speed > 2400 ) { fax1_max = dcs_btp->speed - 2400; lprintf( L_NOISE, "reduce max speed to %d", fax1_max ); } } /* set fine/normal resolution flags and min/max transmission speed * including finding out maximum speed modem can do! */ int fax1_set_fdcc _P4( (fd, fine, max, min), int fd, int fine, int max, int min ) { char * p; lprintf( L_MESG, "fax1_set_fdcc: fine=%d, max=%d, min=%d", fine, max, min ); fax1_max = max; fax1_min = min; fax1_res = fine; if ( fax1_min == 0 ) fax1_min=2400; if ( fax1_max < fax1_min || fax1_max < 2400 || fax1_max > 14400 || fax1_min < 2400 || fax1_min > 14400 ) { lprintf( L_WARN, "min/max values (%d/%d) out of range, use 2400/14400", min, max ); fax1_min = 2400; fax1_max = 14400; } if ( fax1_res < 0 || fax1_res > 1 ) { lprintf( L_WARN, "fax1_res (%d) out of range, use fine (1)", fax1_res ); fax1_res = 1; } #if 0 /* we don't support anything but AT+FTH=3 yet */ p = mdm_get_idstring( "AT+FTH=?", 1, fd ); fax1_fth = fax1_carriers( p ); lprintf( L_MESG, "modem can send HDLC headers: %03x", fax1_fth ); #else fax1_fth = 001; #endif p = mdm_get_idstring( "AT+FTM=?", 1, fd ); fax1_ftm = fax1_carriers( p ); lprintf( L_MESG, "modem can send page data: %03x", fax1_ftm ); #if 0 /* we don't support anything but AT+FRH=3 yet */ p = mdm_get_idstring( "AT+FRH=?", 1, fd ); fax1_frh = fax1_carriers( p ); lprintf( L_MESG, "modem can recv HDLC headers: %03x", fax1_fth ); #else fax1_frh = 001; #endif p = mdm_get_idstring( "AT+FRM=?", 1, fd ); fax1_frm = fax1_carriers( p ); lprintf( L_MESG, "modem can recv page data: %03x", fax1_ftm ); return NOERROR; } /* timeout handler */ static boolean fax1_got_timeout = FALSE; RETSIGTYPE fax1_sig_alarm(SIG_HDLR_ARGS) { signal( SIGALRM, fax1_sig_alarm ); lprintf( L_WARN, "Warning: fax1: got alarm signal!" ); fax1_got_timeout = TRUE; } /* receive ONE frame, put it into *framebuf * * timeout set to "timout * 1/10 seconds" */ int fax1_receive_frame _P4 ( (fd, carrier, timeout, framebuf), int fd, int carrier, int timeout, uch * framebuf) { int count=0; /* bytes in frame */ int rc = NOERROR; /* return code */ char gotsync = FALSE; /* got 0xff frame sync */ char WasDLE = FALSE; /* got character */ char * line, c; if ( timeout > 0 ) { signal( SIGALRM, fax1_sig_alarm ); alarm( (timeout/10)+1 ); } if ( carrier > 0 ) { char cmd[20]; sprintf( cmd, "AT+FRH=%d", carrier ); /*!!! TOOD: DO NOT USE fax_send (FAX_COMMAND_DELAY) */ /* normally, fax_send() can only fail if something is really * messed up with the serial port, e.g. "stuck flow control" */ if ( fax_send( cmd, fd ) == ERROR ) { alarm(0); return ERROR; } /* wait for CONNECT/NO CARRIER */ line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) { line = mdm_get_line( fd ); } /* skip echo */ if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { alarm(0); if ( line == NULL ) { char cancel_str[] = { CAN }; lprintf( L_WARN, "fax1_receive_frame: no carrier (timeout), send CAN" ); write( fd, cancel_str, 1 ); alarm(2); line = mdm_get_line( fd ); alarm(0); } else lprintf( L_WARN, "fax1_receive_frame: no carrier (%s)", line ); return ERROR; } } lprintf( L_NOISE, "fax1_receive_frame: got:" ); /* we have a CONNECT now - now find the first byte of the frame * (0xFF), and read in shielded data up to the */ while(1) { if ( mdm_read_byte( fd, &c ) != 1 ) { lprintf( L_ERROR, "fax1_receive_frame: cannot read byte, return" ); rc = ERROR; break; } /*!!!! TODO: CONNECT/ERROR statt Frame-Daten erkennen */ lputc( L_NOISE, c ); if ( !gotsync ) /* wait for preamble */ { if ( c == (char) 0xFF ) gotsync = TRUE; continue; } /* got preamble, all further bytes are put into buffer */ /* enough room? */ if ( count >= FRAMESIZE-5 ) { lprintf( L_ERROR, "fax1_receive_frame: too many octets in frame" ); rc = ERROR; break; } if ( WasDLE ) /* previous character was DLE */ { if ( c == DLE ) /* DLE DLE -> DLE */ { framebuf[count++] = DLE; } else if ( c == SUB ) /* DLE SUB -> DLE DLE */ { framebuf[count++] = DLE; framebuf[count++] = DLE; } else if ( c == ETX ) /* end of frame detected */ { rc = count; break; } WasDLE = 0; continue; } /* previous character was not DLE, check for DLE now... */ if ( c == DLE ) { WasDLE = 1; continue; } /* all other characters are stored in buffer */ framebuf[count++] = c; } /* now read OK / ERROR response codes (only if we're still happy) */ if ( rc != ERROR ) { line = mdm_get_line( fd ); if ( line == NULL || /* timeout ... */ strcmp( line, "ERROR" ) == 0 ) /* or FCS error */ { lprintf( L_MESG, "fax1_receive_frame: dropping frame" ); rc = ERROR; } } /* turn off alarm */ alarm(0); if ( rc > 0 ) { fax1_dump_frame( '<', framebuf, count ); } return rc; } void fax1_dump_frame _P3((io, frame, len), char io, unsigned char * frame, int len) { int fcf = frame[1]; lprintf( L_MESG, "%c frame type: 0x%02x len: %d %s%s", io, fcf, len, frame[0]&0x10? "final": "non-final", (fcf & 0x0e) && ( fcf & 0x01 ) ? " X": ""); if ( fcf & 0x0e ) fcf &= ~0x01; /* clear "X" bit */ switch( fcf ) { /* simple frames */ case T30_CSI: lprintf( L_NOISE, "CSI: '%20.20s'", &frame[2] ); break; case T30_CIG: lprintf( L_NOISE, "CIG: '%20.20s'", &frame[2] ); break; case T30_TSI: lprintf( L_NOISE, "TSI: '%20.20s'", &frame[2] ); break; case T30_NSF: lprintf( L_NOISE, "NSF" ); break; case T30_CFR: lprintf( L_NOISE, "CFR" ); break; case T30_FTT: lprintf( L_NOISE, "FTT" ); break; case T30_MCF: lprintf( L_NOISE, "MCF" ); break; case T30_RTP: lprintf( L_NOISE, "RTP" ); break; case T30_RTN: lprintf( L_NOISE, "RTN" ); break; case T30_EOM: lprintf( L_NOISE, "EOM" ); break; case T30_MPS: lprintf( L_NOISE, "MPS" ); break; case T30_EOP: lprintf( L_NOISE, "EOP" ); break; case T30_DCN: lprintf( L_NOISE, "DCN" ); break; /* complicated ones... */ case T30_DIS: lprintf( L_NOISE, "DIS:" ); if ( frame[2] & 0x40 ) lputs( L_NOISE, " V8" ); lputs( L_NOISE, frame[2] & 0x80 ? " 64": " 256" ); if ( frame[3] & 0x01 ) lputs( L_NOISE, " +FPO" ); if ( frame[3] & 0x02 ) lputs( L_NOISE, " RCV" ); switch( (frame[3] >> 2) &0x0f ) { case 0x00: lputs( L_NOISE, " V27ter_fb" ); break; case 0x02: lputs( L_NOISE, " V27ter" ); break; case 0x01: lputs( L_NOISE, " V29" ); break; case 0x03: lputs( L_NOISE, " V27ter+V29" ); break; case 0x0b: lputs( L_NOISE, " V27ter+V29+V17" ); break; default: lputs( L_NOISE, " V.???" ); break; } if ( frame[3] & 0x40 ) lputs( L_NOISE, " 200" ); if ( frame[3] & 0x80 ) lputs( L_NOISE, " 2D" ); switch( frame[4] & 0x03 ) { case 0x00: lputs( L_NOISE, " 215mm" ); break; case 0x02: lputs( L_NOISE, " 215+255+303" ); break; case 0x01: lputs( L_NOISE, " 215+255" ); break; } switch( (frame[4]>>2) & 0x03 ) { case 0x00: lputs( L_NOISE, " A4" ); break; case 0x02: lputs( L_NOISE, " unlim" ); break; case 0x01: lputs( L_NOISE, " A4+B4" ); break; } lputs( L_NOISE, fax1_st_table[ (frame[4]>>4) & 0x07 ].txt ); if ( ( frame[4] & 0x80 ) == 0 ) break; /* extent bit */ if ( frame[5] & 0x04 ) lputs( L_NOISE, " ECM" ); if ( frame[5] & 0x40 ) lputs( L_NOISE, " T.6" ); if ( ( frame[5] & 0x80 ) == 0 ) break; /* extent bit */ if ( ( frame[6] & 0x80 ) == 0 ) break; /* extent bit */ /* the next bytes specify 300/400 dpi, color fax, ... */ break; case T30_DCS: lprintf( L_NOISE, "DCS:" ); if ( frame[2] & 0x40 ) lputs( L_NOISE, " V8" ); lputs( L_NOISE, frame[2] & 0x80 ? " 64": " 256" ); if ( frame[3] & 0x02 ) lputs( L_NOISE, " RCV!" ); switch( (frame[3] >> 2) &0x0f ) { case 0x00: lputs( L_NOISE, " V27ter_2400" ); break; case 0x02: lputs( L_NOISE, " V27ter_4800" ); break; case 0x01: lputs( L_NOISE, " V29_9600" ); break; case 0x03: lputs( L_NOISE, " V29_7200" ); break; case 0x04: lputs( L_NOISE, " V33_14400" ); break; case 0x06: lputs( L_NOISE, " V33_12000" ); break; case 0x08: lputs( L_NOISE, " V17_14400" ); break; case 0x0a: lputs( L_NOISE, " V17_12000" ); break; case 0x09: lputs( L_NOISE, " V17_9600" ); break; case 0x0b: lputs( L_NOISE, " V17_7200" ); break; default: lputs( L_NOISE, " V.???" ); break; } if ( frame[3] & 0x40 ) lputs( L_NOISE, " 200!" ); if ( frame[3] & 0x80 ) lputs( L_NOISE, " 2D!" ); switch( frame[4] & 0x03 ) { case 0x00: lputs( L_NOISE, " 1728/215mm" ); break; case 0x02: lputs( L_NOISE, " 2432/303mm" ); break; case 0x01: lputs( L_NOISE, " 2048/255mm" ); break; } switch( (frame[4]>>2) & 0x03 ) { case 0x00: lputs( L_NOISE, " A4" ); break; case 0x02: lputs( L_NOISE, " unlim" ); break; case 0x01: lputs( L_NOISE, " B4" ); break; } lputs( L_NOISE, fax1_st_table[ (frame[4]>>4) & 0x07 ].txt ); if ( ( frame[4] & 0x80 ) == 0 ) break; /* extent bit */ if ( frame[5] & 0x04 ) lputs( L_NOISE, " ECM" ); if ( frame[5] & 0x40 ) lputs( L_NOISE, " T.6" ); if ( ( frame[5] & 0x80 ) == 0 ) break; /* extent bit */ if ( ( frame[6] & 0x80 ) == 0 ) break; /* extent bit */ /* the next bytes specify 300/400 dpi, color fax, ... */ break; default: lprintf( L_NOISE, "frame FCF 0x%02x not yet decoded", fcf ); } } /* send arbitrary frame */ int fax1_send_frame _P4( (fd, carrier, frame, len), int fd, int carrier, uch * frame, int len ) { char * line; static int carrier_active = -2; /* inter-frame marker */ uch dle_buf[FRAMESIZE*2+2]; /* for DLE-coded frame */ int r,w; fax1_dump_frame( '>', frame, len ); /* this should never take more than a few msec, so the 10s timeout * is more a safeguard for modem lockups, implementation mistakes, etc. * - make sure we're not getting stuck in protocol loops */ alarm(10); /* send AT+FTH=3, wait for CONNECT * (but only if we've not sent an non-final frame before!) */ /* catch internal out-of-sync condition ('canthappen') * (this is OK for the very first frame sent in receive mode - ugly, yes) */ if ( carrier == T30_CAR_SAME && carrier_active == -1 ) { errno = EINVAL; lprintf( L_ERROR, "fax1_send_frame: internal error - no carrier, but T30_CAR_SAME requested" ); return ERROR; } if ( carrier > 0 && carrier_active != carrier ) { char cmd[20]; sprintf( cmd, "AT+FTH=%d", carrier ); if ( fax_send( cmd, fd ) == ERROR ) { alarm(0); carrier_active=-1; return ERROR; } /* wait for CONNECT/NO CARRIER */ line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) { line = mdm_get_line( fd ); } /* skip echo */ if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { alarm(0); lprintf( L_WARN, "fax1_send_frame: no carrier (%s)", line ); carrier_active=-1; return ERROR; } carrier_active=carrier; } /* first 0xff is mandatory, but not passed by caller */ dle_buf[0] = 0xff; w=1; /* send encoded frame data */ for( r=0; r */ dle_buf[w++] = DLE; dle_buf[w++] = ETX; lprintf( L_JUNK, "fax1_send_frame: %d/%d", len+1, w ); if ( write( fd, dle_buf, w ) != w ) { lprintf( L_ERROR, "fax1_send_frame: can't write all %d bytes", w ); alarm(0); fax_hangup=TRUE; return ERROR; } /*!!! alarm */ /*!!! LASAT schickt "CONNECT\r\nOK" bzw. nur "OK" (final/non-final) * --> ist das normal und richtig so??!? * * Nein... - es kommt immer entweder-oder, aber nach CONNECT muss * man OHNE neues AT+FTH *SOFORT* weitersenden! */ line = mdm_get_line( fd ); lprintf( L_NOISE, "fax1_send_frame: frame sent, got '%s'", line ); if ( frame[0] & T30_FINAL ) { carrier_active = -1; /* carrier is off */ lprintf( L_NOISE, "carrier is off - OK='%s'", line ); } /* as we're sending, we shouldn't see NO CARRIER response - but this * can happen, e.g. when the modem notices a remote hangup (ISDN etc.) */ if ( line == NULL || strcmp( line, "NO CARRIER" ) == 0 ) { lprintf( L_WARN, "fax1_send_frame: unexpected post-frame string '%s', assuming carrier off", line? line: "(null)" ); carrier_active = -1; return ERROR; } #if 0 if ( line != NULL && strcmp( line, "CONNECT" ) == 0 ) { line = mdm_get_line( fd ); lprintf( L_NOISE, "fax1_send_frame(2): got '%s'", line ); } #endif return NOERROR; } /* send simple frame, consisting only of FCF and no arguments * (non-final frame) */ int fax1_send_simf_nonfinal _P3( (fd, carrier, fcf), int fd, int carrier, uch fcf ) { uch frame[2]; frame[0] = 0x03; frame[1] = fcf; return fax1_send_frame( fd, carrier, frame, 2 ); } /* send simple frame, consisting only of FCF and no arguments * (final frame) */ int fax1_send_simf_final _P3( (fd, carrier, fcf), int fd, int carrier, uch fcf ) { uch frame[2]; frame[0] = 0x03 | T30_FINAL; frame[1] = fcf; return fax1_send_frame( fd, carrier, frame, 2 ); } /* send "disconnect now" frame (DCN), and move internal state to "game over" * Note: this is always a "final" frame */ int fax1_send_dcn _P2((fd, code), int fd, int code ) { if ( code != -1 ) { fax_hangup_code = code; fax_hangup = TRUE; } return fax1_send_simf_final( fd, T30_CAR_V21, T30_DCN|fax1_dis ); } /* send local identification (CSI, CIG or TSI) * Note: "final" bit is never set, as these frames are always optional. */ int fax1_send_idframe _P3((fd,fcf,carrier), int fd, uch fcf, int carrier) { unsigned char frame[F1LID+2]; frame[0] = 0x03; frame[1] = fcf; memcpy( &frame[2], fax1_local_id, F1LID ); return fax1_send_frame( fd, carrier, frame, sizeof(frame) ); } void fax1_copy_id _P1((frame), uch * frame ) { int w, r; char c; frame += 2; /* go to start of ID */ r = F1LID-1; w = 0; while ( r>= 0 && isspace(frame[r]) ) r--; /* skip leading whitespace */ while ( r>=0 ) /* copy backwards! */ { c = frame[r--]; if ( c == '"' || c == '\'' ) fax_remote_id[w++] = '_'; else fax_remote_id[w++] = c; } while( w>0 && isspace(fax_remote_id[w-1]) ) w--; fax_remote_id[w]=0; lprintf( L_MESG, "fax_id: '%s'", fax_remote_id ); } /* set local capabilities in DIS frame, announce to remote sender */ int fax1_send_dis _P1( (fd), int fd ) { uch frame[FRAMESIZE]; int speedbits = 0; int r_flags; struct fax1_btable * dis_btp = fax1_btable; /* start with modem capabilities, restrain by FDCC values */ r_flags = fax1_frm; while( dis_btp->speed > 2400 ) { if ( dis_btp->speed < fax1_min || dis_btp->speed > fax1_max ) { r_flags &= ~(dis_btp->flag); lprintf( L_NOISE, "fax1_dis: %d out of range -> r_flags=%03x", dis_btp->speed, r_flags ); } dis_btp++; } /* some devices advertise V.17, but it doesn't work - so provide override * switch via modem_quirks that unconditionally turns off V.17 */ if ( modem_quirks & MQ_C1_NO_V17 ) r_flags &= ~V17; /* this is a bit messy, but I don't know a really elegant way to * use the fax1_btable structure for that (see T.30, Table 2, p.46) */ if ( (r_flags & V17) && (r_flags & V29) && (r_flags & V27ter) ) { speedbits = 0x2c; /* 1101 */ } else { if ( r_flags & V27t_4800 ) { speedbits |= 0x08; /* 0100 */ } if ( r_flags & V29 ) { speedbits |= 0x04; /* 1000 */ } } lprintf( L_NOISE, "fax1_dis: r_flags=%03x -> speedbits=0x%02x", r_flags, speedbits ); /* DIS is always final frame */ frame[0] = 0x03 | T30_FINAL; frame[1] = T30_DIS; frame[2] = 0x00; /* bits 1..8: group 1/2 - unwanted */ frame[3] = 0x00 | /* bit 9: can transmit - TODO: polling! */ 0x02 | /* bit 10: can receive */ speedbits | /* bit 11..14: receive rates - TODO!! */ ((fax1_res&1) <<6) | /* bit 15: can fine */ 0x00; /* bit 16: can 2D */ frame[4] = 0x08 | /* bits 17..20 = 215mm width, unlim. length */ 0x70 | /* bits 21..23 = 0ms scan time */ 0x00; /* bit 24: extend bit - final */ return fax1_send_frame( fd, T30_CAR_SAME, frame, 5 ); } /* parse incoming DIS frame, set remote capability flags */ fax_param_t remote_cap; void fax1_parse_dis _P1((frame), uch * frame ) { remote_cap.vr = remote_cap.br = remote_cap.wd = remote_cap.ln = remote_cap.df = remote_cap.ec = remote_cap.bf = remote_cap.st = 0; frame += 2; /* go to start of FIF */ /* bit 9: ready to transmit fax (polling) */ if ( frame[1] & 0x01 ) fax_to_poll = TRUE; /* bit 10: receiving capabilities */ if ( ( frame[1] & 0x02 ) == 0 ) { /*!!!! HANDLE THIS */ lprintf( L_WARN, "remote station can't receive!" ); fax_hangup = TRUE; fax_hangup_code = 21; return; } switch( frame[1] & 0x3c ) /* bits 11..14 - data signalling rate */ { case 0x00: remote_cap.br = V27t_2400; break; case 0x08: remote_cap.br = V27ter; break; case 0x04: remote_cap.br = V29; break; case 0x0c: remote_cap.br = V29 | V27ter; break; case 0x1c: remote_cap.br = V29 | V27ter; break; /* V.33 */ case 0x2c: remote_cap.br = V17 | V29 | V27ter; break; default: lprintf( L_WARN, "unknown signalling rate: 0x%02x, use V27ter", frame[1] & 0x3c ); remote_cap.br = V27ter; } if ( frame[1] & 0x40 ) /* bit 15: fine res. */ { remote_cap.vr = 1; /*!! check bits 42 + 43 for "super-fine" (300/400 dpi) */ } if ( frame[1] & 0x80 ) /* bit 16: 2D */ remote_cap.df = 1; /* df??? */ /* bit 17+18: recording width, valid: 0/1/2 = 215/255/303 mm */ remote_cap.wd = frame[2] & 0x03; /* bit 19+20: recording length, valid: 0/1/2 = A4/B4/unlimited */ remote_cap.ln = ( frame[2] >> 2 ) & 0x03; /* bit 21-23: minimum scan line time */ remote_cap.st = fax1_st_table[ (frame[2] >> 4) & 0x07 ].st; if ( frame[2] & 0x80 ) /* extend bit */ { /* bit 27: ECM */ if ( frame[3] & 0x04 ) remote_cap.ec = 1; } fax1_dis = 0x01; /* set "X" bit (= received DIS OK) */ lprintf( L_MESG, "+FIS: %d,%03x,%d,%d,%d,%d,%d,%d", remote_cap.vr, remote_cap.br, remote_cap.wd, remote_cap.ln, remote_cap.df, remote_cap.ec, remote_cap.bf, remote_cap.st ); } int fax1_send_dcs _P2((fd, s_time), int fd, int s_time ) { uch framebuf[FRAMESIZE]; int i; /* find baud/carrier table entry that has a speed not over * "speed", and that uses a modulation scheme supported by both * the local and remote modem */ dcs_btp = fax1_btable; while( dcs_btp->speed > 2400 && ( dcs_btp->speed > fax1_max || ( dcs_btp->flag & fax1_ftm & remote_cap.br ) == 0 ) ) dcs_btp++; lprintf( L_NOISE, "+DCS: 1,%03x", dcs_btp->flag ); /*!!! calculate ALL values from DIS and to-be-sent page */ framebuf[0] = 0x03 | T30_FINAL; /* DCS is always final frame */ framebuf[1] = fax1_dis | T30_DCS; /* FCF */ framebuf[2] = 0; /* bits 1..8 */ framebuf[3] = 0x02 | /* bit 10: receiver operation */ dcs_btp->dcs_bits | /* bits 11..14: signalling rate */ ((fax1_res&remote_cap.vr)<<6) | /* bit 15: fine mode */ 0x00; /* bit 16: 2D */ framebuf[4] = 0x00 | /* bit 17+18: 215 mm width */ 0x04 | /* bit 19+20: B4 length */ 0x00 | /* bits 21-23: scan line time */ 0x00; /* bit 24: extend bit - final */ /* calculate correct bit settings for scan line time (bits 21-23) */ for( i=0;i<=7;i++ ) { if ( fax1_st_table[i].ms_n == s_time ) { framebuf[4] |= i<<4; break; } } return fax1_send_frame( fd, T30_CAR_V21, framebuf, 5 ); } /* parse incoming DCS frame * put communication parameters into global variables (dcs_btp, fax_par_d) */ /* TODO: error handling? "I don't understand this -> DCN" */ void fax1_parse_dcs _P1((frame), uch *frame) { /* bit rate + modulation requested (bits 11..14) */ dcs_btp = fax1_btable; while( dcs_btp->speed > 2400 && dcs_btp->dcs_bits != (frame[3] & 0x3c) ) dcs_btp++; fax_par_d.br = dcs_btp->speed/2400 - 1; /* fine resolution: bit 15 (98/196 lpi) */ fax_par_d.vr = ( frame[3] & 0x40 )? 1: 0; /* 2D: bit 16 (1D/2D mod read) */ fax_par_d.df = ( frame[3] & 0x80 )? 1: 0; /* page width: bits 17+18 (byte 4, bits 0+1) */ fax_par_d.wd = frame[4] & 0x03; /* page length: bits 19+20 */ fax_par_d.ln = (frame[4] >> 2 ) & 0x03; /* scan line time: bits 21-23 */ fax_par_d.st = fax1_st_table[ (frame[4] >> 4) & 0x07 ].st; /* extend bit? */ if ( ( frame[4] && 0x80 ) == 0 ) goto done; /* ECM - TODO */ done: lprintf( L_NOISE, "DCS: speed=%d, flag=%03x", dcs_btp->speed, dcs_btp->flag ); } int fax1_init_FRM _P2((fd,carrier), int fd, int carrier ) { char cmd[20]; char *line; int timeout = 30; /* TODO: is this sufficient timeout handling? */ if ( timeout > 0 ) { signal( SIGALRM, fax1_sig_alarm ); alarm( (timeout/10)+1 ); } sprintf( cmd, "AT+FRM=%d", carrier ); if ( fax_send( cmd, fd ) ) { alarm(0); return ERROR; } /* wait for CONNECT/NO CARRIER */ line = mdm_get_line( fd ); if ( line != NULL && strcmp( line, cmd ) == 0 ) { line = mdm_get_line( fd ); } /* skip echo */ alarm(0); if ( line == NULL || strcmp( line, "CONNECT" ) != 0 ) { lprintf( L_WARN, "fax1_init_FRM: no carrier (%s)", line ); return ERROR; } return NOERROR; } #endif /* CLASS1 */ mgetty-1.1.36/hyla_nsf.c0100644000031200001470000004724210443771527013377 0ustar gertfax/* $Id: hyla_nsf.c,v 4.6 2006/06/14 11:30:31 gert Exp $ */ /* * The tables in this file are taken from the HylaFAX distribution. Thus, * the Hylafax copyright (below) applies, not the mgetty copyright (GPL). * * This file does not exist in the original HylaFAX distribution. * Created by Dmitry Bely, April 2000 */ /* * Copyright (c) 1994-1996 Sam Leffler * Copyright (c) 1994-1996 Silicon Graphics, Inc. * HylaFAX is a trademark of Silicon Graphics * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include #include #include "mgetty.h" #include "policy.h" #ifdef FAX_NSF_PARSER typedef char bool; #define true 1 #define false 0 struct ModelData { const char* modelId; const char* modelName; }; typedef struct ModelData ModelData; struct NSFData { const char* vendorId; unsigned int vendorIdSize; /* Country & provider code (T.35) */ const char* vendorName; bool inverseStationIdOrder; unsigned int modelIdPos; unsigned int modelIdSize; const ModelData* knownModels; }; typedef struct NSFData NSFData; /* * Unless a manufacturer is able to provide detailed specifics * of the construction of their NSF signals the only guaranteed * accurate information that we get from NSF is the manufacturer * (once the bitorder and construction of the first few bytes is * confirmed). At that point we would ideally be able to identify * the model type, but doing that is often more guesswork than * anything and is more likely to prove wrong than right, depending * on how specific our ModelData typing is. Any matches as to the * model identification really should be taken with some degree * of scepticism. * * As manufacturers often encode (in plain text) a station identification * in the NSF string it is often useful to look for that. */ static const ModelData Canon[] = {{"\x80\x00\x80\x48\x00", "Faxphone B640"}, {"\x80\x00\x80\x49\x10", "Fax B100"}, {"\x80\x00\x8A\x49\x10", "Laser Class 9000 Series"}, {"\x80\x00\x8A\x48\x00", "Laser Class 2060"}, {NULL}}; static const ModelData Brother[] = {{"\x55\x55\x00\x88\x90\x80\x5F\x00\x15\x51", "Fax-560/770"}, {"\x55\x55\x00\x80\xB0\x80\x00\x00\x59\xD4", "Personal fax 190"}, {"\x55\x55\x00\x8C\x90\x80", "MFC-3100C/MFC-8600"}, {NULL}}; static const ModelData Panasonic0E[] = {{"\x00\x00\x00\x96\x0F\x01\x02\x00\x10\x05\x02\x95\xC8\x08\x01\x49\x02\x41\x53\x54\x47", "KX-F90" }, {"\x00\x00\x00\x96\x0F\x01\x03\x00\x10\x05\x02\x95\xC8\x08\x01\x49\x02\x03", "KX-F230/KX-FT21" }, {"\x00\x00\x00\x16\x0F\x01\x03\x00\x10\x05\x02\x95\xC8\x08", "KX-F780" }, {"\x00\x00\x00\x16\x0F\x01\x03\x00\x10\x00\x02\x95\x80\x08\x75\xB5", "KX-M260" }, {"\x00\x00\x00\x16\x0F\x01\x02\x00\x10\x05\x02\x85\xC8\x08\xAD", "KX-F2050BS" }, {NULL}}; static const ModelData Panasonic79[] = {{"\x00\x00\x00\x02\x0F\x09\x12\x00\x10\x05\x02\x95\xC8\x88\x80\x80\x01", "UF-S10" }, {"\x00\x00\x00\x16\x7F\x09\x13\x00\x10\x05\x16\x8D\xC0\xD0\xF8\x80\x01", "/Siemens Fax 940" }, {"\x00\x00\x00\x16\x0F\x09\x13\x00\x10\x05\x06\x8D\xC0\x50\xCB", "Panafax UF-321" }, {NULL}}; static const ModelData Ricoh[] = {{"\x00\x00\x00\x12\x10\x0D\x02\x00\x50\x00\x2A\xB8\x2C", "/Nashuatec P394" }, {NULL}}; static const ModelData Samsung16[] = {{"\x00\x00\xA4\x01", "M545 6800" }, {NULL}}; static const ModelData Samsung8C[] = {{"\x00\x00\x01\x00", "SF-2010" }, {NULL}}; static const ModelData SamsungA2[] = {{"\x00\x00\x80\x00", "FX-4000" }, {NULL}}; static const ModelData Sanyo[] = {{"\x00\x00\x10\xB1\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x41\x26\xFF\xFF\x00\x00\x85\xA1", "SFX-107" }, {"\x00\x00\x00\xB1\x12\xF2\x62\xB4\x82\x0A\xF2\x2A\x12\xD2\xA2\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x41\x4E\xFF\xFF\x00\x00", "MFP-510" }, {NULL}}; static const ModelData HP[] = {{"\x20\x00\x45\x00\x0C\x04\x70\xCD\x4F\x00\x7F\x49", "LaserJet 3150" }, {"\x04\x00\x00\x00\x00", "LaserJet 3030" }, /* gert */ {"\x40\x80\x84\x01\xF0\x6A", "OfficeJet" }, {"\xC0\x00\x00\x00\x00", "OfficeJet 500" }, {"\xC0\x00\x00\x00\x00\x8B", "Fax-920" }, {NULL}}; static const ModelData Sharp[] = {{"\x00\xCE\xB8\x80\x80\x11\x85\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\x00\x00\x00\x00\x00\x00\x00\x00\xED\x22\xB0\x00\x00\x90\x00\x8C", "Sharp UX-460" }, {"\x00\x4E\xB8\x80\x80\x11\x84\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\x00\x00\x00\x00\x00\x00\x00\x00\xED\x22\xB0\x00\x00\x90\x00\xAD", "Sharp UX-177" }, {"\x00\xCE\xB8\x00\x84\x0D\xDD\x00\x00\xDD\xDD\x00\x00\xDD\xDD\xDD\xDD\xDD\x02\x05\x28\x02\x22\x43\x29\xED\x23\x90\x00\x00\x90\x01\x00", "Sharp FO-4810" }, {NULL}}; static const ModelData Xerox[] = {{"\x00\x08\x2D\x43\x57\x50\x61\x75\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01\x1A\x02\x02\x10\x01\x82\x01\x30\x34", "635 Workcenter" }, {"\x00\x08\x0D\x49\xFF\xFF\xFF\xFF\xFF\xFF", "DP85F" }, /* gert */ {NULL}}; static const ModelData XeroxDA[] = {{"\x00\x00\xC0\x00", "Workcentre Pro 580" }, {NULL}}; static const ModelData Lexmark[] = {{"\x00\x80\xA0\x00", "X4270" }, {NULL}}; static const ModelData JetFax[] = {{"\x01\x00\x45\x00\x0D\x7F", "M910e" }, {NULL}}; static const ModelData PitneyBowes[] = {{"\x79\x91\xB1\xB8\x7A\xD8", "9550" }, {NULL}}; static const ModelData Muratec45[] = {{"\xF4\x91\xFF\xFF\xFF\x42\x2A\xBC\x01\x57", "M4700" }, {NULL}}; static const ModelData Muratec48[] = {{"\x53\x53\x61", "M620" }, {NULL}}; /* * Country code first byte, then manufacturer is last two bytes. See T.35. * Apparently Germany issued some manufacturer codes before the two-byte * standard was accepted, and so some few German manufacturers are * identified by a single manufacturer byte. * * T.30 5.3.6.2.7 (2003) states that the NSF FIF is transmitted * in MSB2LSB order. Revisions of T.30 prior to 2003 did not * contain explicit specification as to the transmit bit order. * (Although it did otherwise state that all HDLC frame data should * be in MSB order except as noted.) Because CSI, TSI, and other * prologue frames were in LSB order by way of an exception to the * general rule (T.30 5.3.6.2.4-11) many manufacturers assumed that * NSF should also be in LSB order. Consequently there will be * some country-code "masquerading" as a terminal may use the * proper country-code, but with an inverted bit order. * * Thus, country code x61 (Korea) turns into x86 (Papua New Guinea), * code xB5 (USA) turns into xAD (Tunisia), code x26 (China) turns * into x64 (Lebanon), code x04 (Germany) turns into x20 (Canada), * and code x3D (France) turns into xBC (Vietnam). * * For the most part it should be safe to identify a manufacturer * both with the MSB and LSB ordered bits, as the "masqueraded" country * is likely to not be actively assigning T.38 manufacturer codes. * However, some manufacturers (e.g. Microsoft) may use MSB for the * country code and LSB for the rest of the NSF, and so basically this * table must be verified and corrected against actual real-world * results. */ static const NSFData KnownNSF[] = { /* Japan */ {"\x00\x00\x00", 3, "unknown - indeterminate", true }, {"\x00\x00\x01", 3, "Anjitsu", false }, {"\x00\x00\x02", 3, "Nippon Telephone", false }, {"\x00\x00\x05", 3, "Mitsuba Electric", false }, {"\x00\x00\x06", 3, "Master Net", false }, {"\x00\x00\x09", 3, "Xerox/Toshiba", true, 3, 10, Xerox }, {"\x00\x00\x0A", 3, "Kokusai", false }, {"\x00\x00\x0D", 3, "Logic System International", false }, {"\x00\x00\x0E", 3, "Panasonic", false, 3,10, Panasonic0E }, {"\x00\x00\x11", 3, "Canon", false, 3, 5, Canon }, {"\x00\x00\x15", 3, "Toyotsushen Machinery", false }, {"\x00\x00\x16", 3, "System House Mind", false }, {"\x00\x00\x19", 3, "Xerox", true }, {"\x00\x00\x1D", 3, "Hitachi Software", false }, {"\x00\x00\x21", 3, "Oki Electric/Lanier", true }, {"\x00\x00\x25", 3, "Ricoh", true, 3,10, Ricoh }, {"\x00\x00\x26", 3, "Konica", false }, {"\x00\x00\x29", 3, "Japan Wireless", false }, {"\x00\x00\x2D", 3, "Sony", false }, {"\x00\x00\x31", 3, "Sharp/Olivetti", false, 3, 10, Sharp }, {"\x00\x00\x35", 3, "Kogyu", false }, {"\x00\x00\x36", 3, "Japan Telecom", false }, {"\x00\x00\x3D", 3, "IBM Japan", false }, {"\x00\x00\x39", 3, "Panasonic", false }, {"\x00\x00\x41", 3, "Swasaki Communication", false }, {"\x00\x00\x45", 3, "Muratec", false, 3,10, Muratec45 }, {"\x00\x00\x46", 3, "Pheonix", false }, {"\x00\x00\x48", 3, "Muratec", false, 3,3, Muratec48 }, /* not registered */ {"\x00\x00\x49", 3, "Japan Electric", false }, {"\x00\x00\x4D", 3, "Okura Electric", false }, {"\x00\x00\x51", 3, "Sanyo", false, 3,10, Sanyo }, {"\x00\x00\x55", 3, "unknown - Japan 55", false }, {"\x00\x00\x56", 3, "Brother", false, 3, 6, Brother }, {"\x00\x00\x59", 3, "Fujitsu", false }, {"\x00\x00\x5D", 3, "Kuoni", false }, {"\x00\x00\x61", 3, "Casio", false }, {"\x00\x00\x65", 3, "Tateishi Electric", false }, {"\x00\x00\x66", 3, "Utax/Mita", true }, {"\x00\x00\x69", 3, "Hitachi Production", false }, {"\x00\x00\x6D", 3, "Hitachi Telecom", false }, {"\x00\x00\x71", 3, "Tamura Electric Works", false }, {"\x00\x00\x75", 3, "Tokyo Electric Corp.", false }, {"\x00\x00\x76", 3, "Advance", false }, {"\x00\x00\x79", 3, "Panasonic", false, 3,10, Panasonic79 }, {"\x00\x00\x7D", 3, "Seiko", false }, {"\x00\x08\x00", 3, "Daiko", false }, {"\x00\x10\x00", 3, "Funai Electric", false }, {"\x00\x20\x00", 3, "Eagle System", false }, {"\x00\x30\x00", 3, "Nippon Business Systems", false }, {"\x00\x40\x00", 3, "Comtron", false }, {"\x00\x48\x00", 3, "Cosmo Consulting", false }, {"\x00\x50\x00", 3, "Orion Electric", false }, {"\x00\x60\x00", 3, "Nagano Nippon", false }, {"\x00\x70\x00", 3, "Kyocera", false }, {"\x00\x80\x00", 3, "Kanda Networks", false }, {"\x00\x88\x00", 3, "Soft Front", false }, {"\x00\x90\x00", 3, "Arctic", false }, {"\x00\xA0\x00", 3, "Nakushima", false }, {"\x00\xB0\x00", 3, "Minolta", false }, {"\x00\xC0\x00", 3, "Tohoku Pioneer", false }, {"\x00\xD0\x00", 3, "USC", false }, {"\x00\xE0\x00", 3, "Hiboshi", false }, {"\x00\xF0\x00", 3, "Sumitomo Electric", false }, /* Germany */ {"\x20\x09", 2, "ITK Institut für Telekommunikation GmbH & Co KG", false }, {"\x20\x11", 2, "Dr. Neuhaus Mikroelektronik", false }, {"\x20\x21", 2, "ITO Communication", false }, {"\x20\x31", 2, "mbp Kommunikationssysteme GmbH", false }, {"\x20\x41", 2, "Siemens", false }, {"\x20\x42", 2, "Deutsche Telekom AG", false }, {"\x20\x51", 2, "mps Software", false }, {"\x20\x61", 2, "Hauni Elektronik", false }, {"\x20\x71", 2, "Digitronic computersysteme gmbh", false }, {"\x20\x81\x00", 3, "Innovaphone GmbH", false }, {"\x20\x81\x40", 3, "TEDAS Gesellschaft für Telekommunikations-, Daten- und Audiosysteme mbH", false }, {"\x20\x81\x80", 3, "AVM Audiovisuelles Marketing und Computersysteme GmbH", false }, {"\x20\x81\xC0", 3, "EICON Technology Research GmbH", false }, {"\x20\x81\x70", 3, "mgetty+sendfax", false }, {"\x20\xB1", 2, "Schneider Rundfunkwerke AG", false }, {"\x20\xC2", 2, "Deutsche Telekom AG", false }, {"\x20\xD1", 2, "Ferrari electronik GmbH", false }, {"\x20\xF1", 2, "DeTeWe - Deutsche Telephonwerke AG & Co", false }, {"\x20\xFF", 2, "Germany Regional Code", false }, /* China */ {"\x64\x00\x00", 3, "unknown - China 00 00", false }, {"\x64\x01\x00", 3, "unknown - China 01 00", false }, {"\x64\x01\x01", 3, "unknown - China 01 01", false }, {"\x64\x01\x02", 3, "unknown - China 01 02", false }, /* France */ {"\xBC\x53\x01", 3, "Minolta", false }, /* Korea */ {"\x86\x00\x02", 3, "unknown - Korea 02", false }, {"\x86\x00\x06", 3, "unknown - Korea 06", false }, {"\x86\x00\x08", 3, "unknown - Korea 08", false }, {"\x86\x00\x0A", 3, "unknown - Korea 0A", false }, {"\x86\x00\x0E", 3, "unknown - Korea 0E", false }, {"\x86\x00\x10", 3, "Samsung", false }, {"\x86\x00\x11", 3, "unknown - Korea 11" }, {"\x86\x00\x16", 3, "Samsung", false, 3, 4, Samsung16 }, {"\x86\x00\x1A", 3, "unknown - Korea 1A", false }, {"\x86\x00\x40", 3, "unknown - Korea 40", false }, {"\x86\x00\x48", 3, "unknown - Korea 48", false }, {"\x86\x00\x52", 3, "unknown - Korea 52", false }, {"\x86\x00\x5A", 3, "unknown - Korea 5A", false }, {"\x86\x00\x5E", 3, "unknown - Korea 5E", false }, {"\x86\x00\x66", 3, "unknown - Korea 66", false }, {"\x86\x00\x6E", 3, "unknown - Korea 6E", false }, {"\x86\x00\x82", 3, "unknown - Korea 82", false }, {"\x86\x00\x88", 3, "unknown - Korea 88", false }, {"\x86\x00\x8A", 3, "unknown - Korea 8A", false }, {"\x86\x00\x8C", 3, "Samsung", false, 3, 4, Samsung8C }, {"\x86\x00\x92", 3, "unknown - Korea 92", false }, {"\x86\x00\x98", 3, "Samsung", false }, {"\x86\x00\xA2", 3, "Samsung", false, 3, 4, SamsungA2 }, {"\x86\x00\xA4", 3, "unknown - Korea A4", false }, {"\x86\x00\xC9", 3, "unknown - Korea C9", false }, {"\x86\x00\xCC", 3, "unknown - Korea CC", false }, {"\x86\x00\xD2", 3, "unknown - Korea D2", false }, {"\x86\x00\xDA", 3, "Xerox", false, 3, 4, XeroxDA }, {"\x86\x00\xE2", 3, "unknown - Korea E2", false }, {"\x86\x00\xEC", 3, "unknown - Korea EC", false }, {"\x86\x00\xEE", 3, "unknown - Korea EE", false }, /* United Kingdom */ {"\xB4\x00\xB0", 3, "DCE", false }, {"\xB4\x00\xB1", 3, "Hasler", false }, {"\xB4\x00\xB2", 3, "Interquad", false }, {"\xB4\x00\xB3", 3, "Comwave", false }, {"\xB4\x00\xB4", 3, "Iconographic", false }, {"\xB4\x00\xB5", 3, "Wordcraft", false }, {"\xB4\x00\xB6", 3, "Acorn", false }, /* United States */ {"\xAD\x00\x00", 3, "Pitney Bowes", false, 3, 6, PitneyBowes }, {"\xAD\x00\x0C", 3, "Dialogic", false }, {"\xAD\x00\x15", 3, "Lexmark", false, 3, 4, Lexmark }, {"\xAD\x00\x16", 3, "JetFax", false, 3, 6, JetFax }, {"\xAD\x00\x24", 3, "Octel", false }, {"\xAD\x00\x36", 3, "HP", false, 3, 5, HP }, {"\xAD\x00\x42", 3, "FaxTalk", false }, {"\xAD\x00\x44", 3, NULL, true }, {"\xAD\x00\x46", 3, "BrookTrout", false }, {"\xAD\x00\x51", 3, "Telogy Networks", false }, {"\xAD\x00\x55", 3, "HylaFAX", false }, {"\xAD\x00\x5C", 3, "IBM", false }, {"\xAD\x00\x98", 3, "unknown - USA 98", true }, {"\xB5\x00\x01", 3, "Picturetel", false }, {"\xB5\x00\x20", 3, "Conexant", false }, {"\xB5\x00\x22", 3, "Comsat", false }, {"\xB5\x00\x24", 3, "Octel", false }, {"\xB5\x00\x26", 3, "ROLM", false }, {"\xB5\x00\x28", 3, "SOFNET", false }, {"\xB5\x00\x29", 3, "TIA TR-29 Committee", false }, {"\xB5\x00\x2A", 3, "STF Tech", false }, {"\xB5\x00\x2C", 3, "HKB", false }, {"\xB5\x00\x2E", 3, "Delrina", false }, {"\xB5\x00\x30", 3, "Dialogic", false }, {"\xB5\x00\x32", 3, "Applied Synergy", false }, {"\xB5\x00\x34", 3, "Syncro Development", false }, {"\xB5\x00\x36", 3, "Genoa", false }, {"\xB5\x00\x38", 3, "Texas Instruments", false }, {"\xB5\x00\x3A", 3, "IBM", false }, {"\xB5\x00\x3C", 3, "ViaSat", false }, {"\xB5\x00\x3E", 3, "Ericsson", false }, {"\xB5\x00\x42", 3, "Bogosian", false }, {"\xB5\x00\x44", 3, "Adobe", false }, {"\xB5\x00\x46", 3, "Fremont Communications", false }, {"\xB5\x00\x48", 3, "Hayes", false }, {"\xB5\x00\x4A", 3, "Lucent", false }, {"\xB5\x00\x4C", 3, "Data Race", false }, {"\xB5\x00\x4E", 3, "TRW", false }, {"\xB5\x00\x52", 3, "Audiofax", false }, {"\xB5\x00\x54", 3, "Computer Automation", false }, {"\xB5\x00\x56", 3, "Serca", false }, {"\xB5\x00\x58", 3, "Octocom", false }, {"\xB5\x00\x5C", 3, "Power Solutions", false }, {"\xB5\x00\x5A", 3, "Digital Sound", false }, {"\xB5\x00\x5E", 3, "Pacific Data", false }, {"\xB5\x00\x60", 3, "Commetrex", false }, {"\xB5\x00\x62", 3, "BrookTrout", false }, {"\xB5\x00\x64", 3, "Gammalink", false }, {"\xB5\x00\x66", 3, "Castelle", false }, {"\xB5\x00\x68", 3, "Hybrid Fax", false }, {"\xB5\x00\x6A", 3, "Omnifax", false }, {"\xB5\x00\x6C", 3, "HP", false }, {"\xB5\x00\x6E", 3, "Microsoft", false }, {"\xB5\x00\x72", 3, "Speaking Devices", false }, {"\xB5\x00\x74", 3, "Compaq", false }, /* {"\xB5\x00\x76", 3, "Trust - Cryptek", false }, // collision with Microsoft */ {"\xB5\x00\x76", 3, "Microsoft", false }, /* uses LSB for country but MSB for manufacturer */ {"\xB5\x00\x78", 3, "Cylink", false }, {"\xB5\x00\x7A", 3, "Pitney Bowes", false }, {"\xB5\x00\x7C", 3, "Digiboard", false }, {"\xB5\x00\x7E", 3, "Codex", false }, {"\xB5\x00\x82", 3, "Wang Labs", false }, {"\xB5\x00\x84", 3, "Netexpress Communications", false }, {"\xB5\x00\x86", 3, "Cable-Sat", false }, {"\xB5\x00\x88", 3, "MFPA", false }, {"\xB5\x00\x8A", 3, "Telogy Networks", false }, {"\xB5\x00\x8E", 3, "Telecom Multimedia Systems", false }, {"\xB5\x00\x8C", 3, "AT&T", false }, {"\xB5\x00\x92", 3, "Nuera", false }, {"\xB5\x00\x94", 3, "K56flex", false }, {"\xB5\x00\x96", 3, "MiBridge", false }, {"\xB5\x00\x98", 3, "Xerox", false }, {"\xB5\x00\x9A", 3, "Fujitsu", false }, {"\xB5\x00\x9B", 3, "Fujitsu", false }, {"\xB5\x00\x9C", 3, "Natural Microsystems", false }, {"\xB5\x00\x9E", 3, "CopyTele", false }, {"\xB5\x00\xA2", 3, "Murata", false }, {"\xB5\x00\xA4", 3, "Lanier", false }, {"\xB5\x00\xA6", 3, "Qualcomm", false }, {"\xB5\x00\xAA", 3, "HylaFAX", false }, /* they did it backwards for a while */ {NULL} }; void hylafax_nsf_decode _P2(( nsf, nsfSize ), unsigned char * nsf, int nsfSize ) { const char * vendor = NULL; const char * model = NULL; const NSFData * p; const ModelData * pp; for( p = KnownNSF; p->vendorId; p++ ){ if( nsfSize >= p->vendorIdSize && memcmp( p->vendorId, &nsf[0], p->vendorIdSize )==0 ){ if( p->vendorName ) vendor = p->vendorName; if( p->knownModels ){ for( pp = p->knownModels; pp->modelId; pp++ ) if( nsfSize >= p->modelIdPos + p->modelIdSize && memcmp( pp->modelId, &nsf[p->modelIdPos], p->modelIdSize )==0 ) model = pp->modelName; } break; } } if ( vendor != NULL || model != NULL ) lprintf( L_MESG, "NSF: vendor=%s, model=%s", vendor != NULL? vendor: "", model != NULL? model : "" ); } #endif mgetty-1.1.36/faxrec.c0100644000031200001470000003037710356006656013042 0ustar gertfax#ident "$Id: faxrec.c,v 4.16 2005/12/31 15:55:48 gert Exp $ Copyright (c) Gert Doering" /* faxrec.c - part of mgetty+sendfax * * this module is used when the modem sends a string that triggers the * action "A_FAX" - typically this should be "+FCON". * * The incoming fax is received, and stored to $FAX_SPOOL_IN (one file per * page). After completition, the result is mailed to $MAIL_TO. * If FAX_NOTIFY_PROGRAM is defined, this program is called with all * data about the fax as arguments (see policy.h for a description) */ #include #include "syslibs.h" #include #include #include #include #include #include #include #include #ifndef sunos4 #include #endif #include "mgetty.h" #include "tio.h" #include "policy.h" #include "fax_lib.h" #include "mg_utmp.h" extern time_t call_start; /* in faxrecp.c, set in mgetty.c */ static time_t call_done; #if !defined(__NetBSD__) && !defined(__OpenBSD__) time_t time _PROTO(( time_t * tloc )); #endif /* all stuff in here was programmed according to a description of the * class 2 standard as implemented in the SupraFAX Faxmodem */ void fax_notify_mail _PROTO(( int number_of_pages, int p_number_of_pages, char * mail_to )); #ifdef FAX_NOTIFY_PROGRAM void fax_notify_program _PROTO(( int number_of_pages )); #endif void faxpoll_send_pages _PROTO(( int fd, int *ppagenum, TIO * tio, char * pollfile)); char * faxpoll_server_file = NULL; extern char * Device; extern char * fax_file_names; extern int fax_fn_size; void fax2_highlevel_receive _P8(( fd, pn, ppn, spool_in, switchbd, uid, gid, mode ), int fd, int * pn, int * ppn, char * spool_in, unsigned int switchbd, int uid, int gid, int mode ) { TIO tio; /* Setup tty interface * Do not set c_cflag, assume that caller has set bit rate, * hardware handshake, ... properly * For some modems, it's necessary to switch to 19200 bps. * (primarily old rockwell compatible thingies) */ tio_get( fd, &tio ); /* switch bit rates, if necessary */ if ( switchbd != 0 ) tio_set_speed( &tio, switchbd ); tio_mode_raw( &tio ); /* no input or output post-*/ /* processing, no signals */ tio_set( STDIN, &tio ); /* read: +FTSI:, +FDCS, OK (receive phase B negotiation) */ fax_wait_for( "OK", STDIN ); /* NOTE: in former times, we had some #ifdef FAX_USRobotics here, to * move baud rate switching behind the "wait for OK" - seems some * seriously broken firmware did a baud rate lock-in to 19200 (?) * *after* the first OK, not understanding AT commands at the current * port speed anymore. This has been dropped - ugly code. * If you need it back, tell me (will come back as modem_quirk) */ /* if the "switchbd" flag is set wrongly, the fax_wait_for() command * will time out -> write a warning to the log file and give up */ if ( fax_hangup_code == FHUP_TIMEOUT ) { lprintf( L_WARN, ">> The problem seen above might be caused by a wrong value of the" ); lprintf( L_WARN, ">> 'switchbd' option in 'mgetty.config' (currently set to '%d')", switchbd ); if ( switchbd > 0 && switchbd != 19200 ) lprintf( L_WARN, ">> try using 'switchbd 19200' or 'switchbd 0'"); else if ( switchbd > 0 ) lprintf( L_WARN, ">> try using 'switchbd 0'" ); else lprintf( L_WARN, ">> try using 'switchbd 19200'" ); fax_hangup = 1; } /* write a note to utmp/wtmp about incoming fax, including remote id * (don't do this on two-user-license systems!) */ #ifndef USER_LIMIT make_utmp_wtmp( Device, UT_USER, "fax_inc", fax_remote_id ); #endif /* *now* set flow control (we could have set it earlier, but on SunOS, * enabling CRTSCTS while DCD is low will make the port hang) */ tio_set_flow_control( fd, &tio, (FAXREC_FLOW) & (FLOW_HARD|FLOW_XON_IN) ); tio_set( fd, &tio ); /* tell modem about the flow control used (+FLO=...) */ fax_set_flowcontrol( fd, (FAXREC_FLOW) & FLOW_HARD ); fax_get_pages( fd, pn, spool_in, uid, gid, mode ); /* send polled documents (very simple yet) */ if ( faxpoll_server_file != NULL && fax_poll_req ) { lprintf( L_MESG, "starting fax poll send..." ); faxpoll_send_pages( fd, ppn, &tio, faxpoll_server_file ); } } void faxrec _P6((spool_in, switchbd, uid, gid, mode, mail_to), char * spool_in, unsigned int switchbd, int uid, int gid, int mode, char * mail_to) { int pagenum = 0, ppagenum = 0; /* pages received / sent */ lprintf( L_NOISE, "fax receiver: entry" ); /* allocate memory for fax page file names */ fax_file_names = malloc( fax_fn_size = MAXPATH * 4 ); if ( fax_file_names != NULL ) fax_file_names[0] = 0; /* call protocol-specific fax receiver * (class 2/2.0/2.1 are nearly identical, class 1 is very different) */ if ( modem_type == Mt_class2 || modem_type == Mt_class2_0 ) fax2_highlevel_receive( STDIN, &pagenum, &ppagenum, spool_in, switchbd, uid, gid, mode ); #ifdef CLASS1 else if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) fax1_highlevel_receive( STDIN, &pagenum, spool_in, uid, gid, mode ); #endif else { lprintf( L_ERROR, "faxrec: required modem driver (%d) not compiled in, abort", (int) modem_type ); return ; } call_done = time(NULL); lprintf( L_NOISE, "fax receiver: hangup & end" ); /* send mail to MAIL_TO */ if ( mail_to != NULL && strlen(mail_to) != 0 ) fax_notify_mail( pagenum, ppagenum, mail_to ); #ifdef FAX_NOTIFY_PROGRAM /* notify program */ fax_notify_program( pagenum ); #endif call_done = call_done - call_start; /* write audit information and return (caller will exit() then) */ lprintf( L_AUDIT, "fax dev=%s, pid=%d, caller='%s', name='%s', id='%s', +FHNG=%03d, pages=%d/%d, time=%02d:%02d:%02d\n", Device, getpid(), CallerId, CallName, fax_remote_id, fax_hangup_code, pagenum, ppagenum, call_done / 3600, (call_done / 60) % 60, call_done % 60); } void fax_notify_mail _P3( (pagenum, ppagenum, mail_to), int pagenum, int ppagenum, char * mail_to ) { FILE * pipe_fp; char * file_name, * p; char buf[256]; int r; time_t ti; lprintf( L_NOISE, "fax_notify_mail: sending mail to: %s", mail_to ); sprintf( buf, "%s %s >/dev/null 2>&1", MAILER, mail_to ); pipe_fp = popen( buf, "w" ); if ( pipe_fp == NULL ) { lprintf( L_ERROR, "fax_notify_mail: cannot open pipe to %s", MAILER ); return; } #ifdef NEED_MAIL_HEADERS fprintf( pipe_fp, "Subject: fax from %s\n", fax_remote_id[0] ? fax_remote_id: "(anonymous sender)" ); fprintf( pipe_fp, "To: %s\n", mail_to ); fprintf( pipe_fp, "From: root (Fax Getty)\n" ); fprintf( pipe_fp, "\n" ); #endif if ( fax_hangup_code == 0 ) { if ( pagenum != 0 || !fax_poll_req ) fprintf( pipe_fp, "A fax was successfully received:\n" ); else fprintf( pipe_fp, "A to-be-polled fax was successfully sent:\n" ); } else fprintf( pipe_fp, "An incoming fax transmission failed (+FHNG:%3d):\n", fax_hangup_code ); fprintf( pipe_fp, "Sender ID: %s\n", fax_remote_id ); fprintf( pipe_fp, "Pages received: %d\n", pagenum ); if ( fax_poll_req ) { fprintf( pipe_fp, "Pages sent : %d\n", ppagenum ); fprintf( pipe_fp, "Fax poll specs: %s\n", faxpoll_server_file ); } fprintf( pipe_fp, "\nModem device: %s\n", Device ); fprintf( pipe_fp, "\nCommunication parameters: %s\n", fax_param ); fprintf( pipe_fp, " Resolution : %s\n", (fax_par_d.vr == 0 || fax_par_d.vr == 8) ? "normal" :"fine"); fprintf( pipe_fp, " Bit Rate : %d\n", ( fax_par_d.br+1 ) * 2400 ); fprintf( pipe_fp, " Page Width : %d pixels\n", fax_par_d.wd == 0? 1728: ( fax_par_d.wd == 1 ? 2048: 2432 ) ); fprintf( pipe_fp, " Page Length: %s\n", fax_par_d.ln == 2? "unlimited": fax_par_d.ln == 1? "B4 (364 mm)" : "A4 (297 mm)" ); fprintf( pipe_fp, " Compression: %d (%s)\n", fax_par_d.df, fax_par_d.df == 0 ? "1d mod Huffman": (fax_par_d.df == 1 ? "2d mod READ": "2d uncompressed") ); fprintf( pipe_fp, " Error Corr.: %s\n", fax_par_d.ec? "ECM":"none" ); fprintf( pipe_fp, " Scan Time : %d\n\n", fax_par_d.st ); ti = call_done - call_start; /* time spent */ fprintf( pipe_fp, "Reception Time : %02d:%02d\n\n", (int) ti/60, (int) ti%60 ); if ( fax_hangup_code != 0 ) { fprintf( pipe_fp, "\nThe fax receive was *not* fully successful\n" ); fprintf( pipe_fp, "The Modem returned +FHNG:%3d\n", fax_hangup_code ); fprintf( pipe_fp, "\t\t (%s)\n", fax_strerror( fax_hangup_code ) ); } /* list the spooled fax files (jcp/gd) */ if ( pagenum != 0 ) { fprintf( pipe_fp, "\nSpooled G3 fax files:\n\n" ); p = file_name = fax_file_names; while ( p != NULL ) { p = strchr( file_name, ' ' ); if ( p != NULL ) *p = 0; fprintf( pipe_fp, " %s\n", file_name ); if ( p != NULL ) *p = ' '; file_name = p+1; } } fprintf( pipe_fp, "\n\nregards, your modem subsystem.\n" ); if ( ( r = pclose( pipe_fp ) ) != 0 ) { lprintf( L_WARN, "fax_notify_mail: mailer exit status: %d (%d)", r, r>>8 ); } } #ifdef FAX_NOTIFY_PROGRAM void fax_notify_program _P1( (pagenum), int pagenum ) { int r; char * line; if ( fax_file_names == NULL ) fax_file_names=""; line = malloc( fax_fn_size + sizeof( FAX_NOTIFY_PROGRAM) + 100 ); if ( line == NULL ) { lprintf( L_ERROR, "fax_notify_program: cannot malloc" ); return; } /* build command line * note: stdout / stderr redirected to console, we don't * want the program talking to the modem */ sprintf( line, "%s %d '%s' %d %s >%s 2>&1 no SIGHUP */ close( 0 ); close( 1 ); close( 2 ); #if defined(BSD) || defined(sunos4) setpgrp( 0, getpid() ); if ( ( r = open( "/dev/tty", O_RDWR ) ) >= 0 ) { ioctl( r, TIOCNOTTY, NULL ); close( r ); } #else setpgrp(); #endif setup_environment(); r = system( line ); if ( r != 0 ) lprintf( L_ERROR, "system() failed" ); exit(0); case -1: lprintf( L_ERROR, "fork() failed" ); break; } free( line ); } #endif void faxpoll_send_pages _P4( (fd, ppagenum, tio, pollfile), int fd, int *ppagenum, TIO *tio, char *pollfile ) { FILE * fp; char buf[MAXPATH]; char * file; char * fgetline _PROTO(( FILE * fp )); int tries; fp = fopen( pollfile, "r" ); if ( fp == NULL ) { lprintf( L_ERROR, "can't open %s", pollfile ); return; } /* for historical reasons: if the file starts with "0x00", assume it's not a text file but a G3 file */ if ( fread( buf, 1, 1, fp ) != 1 || buf[0] == 0 ) { fclose( fp ); lprintf( L_MESG, "fax poll: %s is (likely) G3 file", pollfile ); /* send page, no more pages to follow */ fax_send_page( faxpoll_server_file, NULL, tio, pp_eop, fd ); (*ppagenum)++; return; } /* read line by line, send as separate pages. * comments and continuation lines allowed */ rewind( fp ); file = fgetline( fp ); while ( file != NULL && !fax_hangup ) { /* copy filename (we need to know *before* sending the file whether it's the last one, and fgetline() uses a static buffer) */ strncpy( buf, file, sizeof(buf)-1 ); buf[sizeof(buf)-1] = 0; file = fgetline( fp ); lprintf( L_MESG, "fax poll: send %s...", buf ); fax_page_tx_status = -1; tries = 0; /* send file, retransmit (once) if RTN received */ do { if ( file == NULL ) /* last page */ fax_send_page( buf, NULL, tio, pp_eop, fd ); else /* not the very last */ fax_send_page( buf, NULL, tio, pp_mps, fd ); tries++; if ( fax_hangup ) { lprintf( L_WARN, "fax poll failed: +FHNG:%d (%s)", fax_hangup_code, fax_strerror(fax_hangup_code)); break; } if ( fax_page_tx_status != 1 ) lprintf( L_WARN, "fax poll: +FPS: %d", fax_page_tx_status ); } while( fax_page_tx_status == 2 && tries < 2 ); (*ppagenum)++; } fclose( fp ); } mgetty-1.1.36/faxrecp.c0100644000031200001470000002305410356006656013214 0ustar gertfax#ident "$Id: faxrecp.c,v 1.11 2005/12/31 15:55:36 gert Exp $ Copyright (c) Gert Doering" /* faxrecp.c - part of mgetty+sendfax * * this module does the "low level" work of receiving fax pages and * storing to disk (similar to "faxsend.c" for "low level sending") */ #include #include "syslibs.h" #include #include #include #include #include #include #include #include #include #ifndef sunos4 #include #endif #include "mgetty.h" #include "tio.h" #include "policy.h" #include "fax_lib.h" time_t call_start; /* initialized in mgetty.c */ RETSIGTYPE fax_sig_hangup(SIG_HDLR_ARGS) { signal( SIGHUP, fax_sig_hangup ); /* exit if we have not read "+FHNG:xxx" yet (unexpected hangup) */ if ( ! fax_hangup ) { lprintf( L_WARN, "how rude, got hangup! exiting..." ); exit(5); } } static boolean fax_timeout = FALSE; RETSIGTYPE fax_sig_alarm(SIG_HDLR_ARGS) { signal( SIGALRM, fax_sig_alarm ); lprintf( L_MESG, "timeout..." ); fax_timeout = TRUE; } char * fax_file_names = NULL; int fax_fn_size = 0; int fax_get_page_data _P6((fd, pagenum, directory, uid, gid, file_mode), int fd, int pagenum, char * directory, int uid, int gid, int file_mode ) { char temp[MAXPATH]; int fax_fd; FILE * fax_fp; char c; char WasDLE; int ErrorCount = 0; int ByteCount = 0; int i,j; extern char * Device; char DevId[3]; /* call_start is only initialized if we're called from mgetty, not * when fax polling (sendfax) or from another getty (contrib/faxin). * So, eventually set it here */ if ( call_start == 0L ) call_start = time( NULL ); /* generate spool file name * * the format depends on the length of filenames allowed. If only * short filenames are allowed, it is f[nf]iiiiiii.jj, iii being * kind of a sequence number and jj the page number. * if long filenames are allowed, the filename will include the * fax id of the sending fax * the "iiiiii" part will start repeating after approx. 8 years */ /* on some systems -- solaris2 -- the device name may look like * "/dev/cub/a", so use "ba" instead of "/a" for the device id */ strcpy( DevId, &Device[strlen(Device)-2] ); if ( DevId[0] == '/' ) DevId[0] = Device[strlen(Device)-3]; if ( DevId[0] == '/' ) DevId[0] = '-'; #ifdef SHORT_FILENAMES sprintf(temp, "%s/f%c%07x%s.%02d", directory, (fax_par_d.vr == 0 || fax_par_d.vr == 8) ? 'n': 'f', (int) call_start & 0xfffffff, DevId, pagenum ); #else /* include sender's fax id - if present - into filename */ sprintf(temp, "%s/f%c%07x%s-", directory, (fax_par_d.vr == 0 || fax_par_d.vr == 8) ? 'n': 'f', (int) call_start & 0xfffffff, DevId ); i = strlen(temp); /* filter out all characters but a-z, 0-9 */ for ( j=0; fax_remote_id[j] != 0; j++ ) { char c = fax_remote_id[j]; if ( isalnum(c) ) temp[i++] = c; else { if ( temp[i-1] != '-' ) temp[i++] = '-' ; } } if ( temp[i-1] == '-' ) i--; sprintf( &temp[i], ".%02d", pagenum ); #endif if ( checkspace(directory) < 1 ) { lprintf( L_ERROR, "Not enough space on %s for fax reception - dropping line", directory); return ERROR; } fax_fd = open( temp, O_WRONLY|O_EXCL|O_CREAT, 0440 ); if ( fax_fd < 0 ) { lprintf( L_ERROR, "opening %s failed, giving up", temp ); return ERROR; } fax_fp = fdopen( fax_fd, "w" ); /* do permission and owner changes as soon as possible -- security */ /* change file mode */ if ( file_mode != -1 && chmod( temp, file_mode ) != 0 ) { lprintf( L_ERROR, "fax_get_page_data: cannot change file mode" ); } /* change file owner and group (jcp) */ if ( uid != -1 && chown( temp, (uid_t) uid, (gid_t) gid ) != 0 ) { lprintf( L_ERROR, "fax_get_page_data: cannot change owner, group" ); } /* store file name in fax_file_names */ if ( fax_file_names != NULL ) if ( strlen( temp ) + strlen( fax_file_names ) + 2 > fax_fn_size ) { fax_fn_size += MAXPATH * 2; fax_file_names = realloc( fax_file_names, fax_fn_size ); } if ( fax_file_names != NULL ) { strcat( fax_file_names, " " ); strcat( fax_file_names, temp ); } /* install signal handlers */ signal( SIGALRM, fax_sig_alarm ); signal( SIGHUP, fax_sig_hangup ); fax_timeout = FALSE; WasDLE = 0; /* skip any leading garbage * it's reasonable to assume that a fax will start with a zero * byte (actually, T.4 requires it). * This has the additional benefit that we'll see error messages */ lprintf( L_NOISE, "fax_get_page_data: wait for EOL, got: " ); alarm( FAX_PAGE_TIMEOUT ); while ( !fax_timeout ) { if ( mdm_read_byte( fd, &c ) != 1 ) { lprintf( L_ERROR, "error waiting for page start" ); return ERROR; } lputc( L_NOISE, c ); if ( c == 0 ) { fputc( c, fax_fp ); break; } if ( c == DLE ) { WasDLE = 1; break; } } lprintf( L_MESG, "fax_get_page_data: receiving %s...", temp ); while ( !fax_timeout ) { /* refresh alarm timer every 1024 bytes * (to refresh it for every byte is far too expensive) */ if ( ( ByteCount & 0x3ff ) == 0 ) { alarm(FAX_PAGE_TIMEOUT); } if ( mdm_read_byte( fd, &c ) != 1 ) { ErrorCount++; lprintf( L_ERROR, "fax_get_page_data: cannot read from port (%d)!", ErrorCount ); if (ErrorCount > 10) return ERROR; } ByteCount++; if ( !WasDLE ) { if ( c == DLE ) WasDLE = 1; else fputc( fax_recv_swaptable[(uch)c], fax_fp ); } else /* WasDLE */ { if ( c == DLE ) /* DLE DLE -> DLE */ fputc( fax_recv_swaptable[(uch)c], fax_fp ); else if ( c == SUB ) /* DLE SUB -> 2x DLE */ { /* (class 2.0) */ fputc( fax_recv_swaptable[DLE], fax_fp ); fputc( fax_recv_swaptable[DLE], fax_fp ); } else if ( c == ETX ) break; /* DLE ETX -> end */ WasDLE = 0; } } alarm(0); fclose( fax_fp ); lprintf( L_MESG, "fax_get_page_data: page end, bytes received: %d", ByteCount); if ( fax_timeout ) { lprintf( L_MESG, "fax_get_page_data: aborting receive, timeout!" ); return ERROR; } return NOERROR; } /* helper function: find a directory in dirlist that has enough free * disk space (2x minfree). If none has "plenty", use the last one, * until space in there is less than 1x minfree, then give up. * (if no directory is writeable, we'll fail later on) */ void fax_find_directory _P3((dirlist,directory,size), char * dirlist, char * directory, int size ) { char *p, *p_help; p = dirlist; do { int l = strlen(p)+1; if ( l > size-1 ) l=size-1; p_help = memccpy( directory, p, ':', l ); if ( p_help != NULL ) { *(p_help-1) = '\0'; p++; } directory[l] = '\0'; p += strlen(directory); if ( access( directory, W_OK ) < 0 ) { lprintf( L_ERROR, "fax_find_dir: can't write to '%s'", directory); continue; } if ( checkspace(directory) > 1 ) { break; } lprintf( L_WARN, "fax_find_dir: not enough disk space in '%s'", directory); } while( *p != '\0' ); } /* receive fax pages * will return the number of received pages in *pagenum */ int fax_get_pages _P6( (fd, pagenum, dirlist, uid, gid, mode ), int fd, int * pagenum, char * dirlist, int uid, int gid, int mode ) { static const char start_rcv = DC2; char directory[MAXPATH]; fax_find_directory( dirlist, directory, sizeof(directory) ); *pagenum = 0; if ( fax_poll_req || fax_hangup ) { lprintf( L_MESG, "fax_get_pages: no pages to receive" ); return NOERROR; } /* send command for start page receive * read: +FCFR:, [+FTSI, +FDCS:], CONNECT */ if ( fax_command( "AT+FDR", "CONNECT", fd ) == ERROR ) { lprintf( L_WARN, "fax_get_pages: cannot start page receive" ); return ERROR; } while ( !fax_hangup && !fax_poll_req ) /* page receive loop */ { /* send command for start receive page data */ lprintf( L_NOISE, "sending DC2" ); write( fd, &start_rcv, 1); /* read page data (into temp file), change to , wait for for end of data */ if ( fax_get_page_data( fd, ++(*pagenum), directory, uid, gid, mode ) == ERROR ) { fax_hangup_code = -1; return ERROR; } /* read +FPTS:1 +FET 0 / 2 */ if ( fax_wait_for( "OK", fd ) == ERROR ) return ERROR; /* check line count and bad line count. If page too short (less * than 50 lines) or bad line count too high (> lc/5), reject * page (+FPS=2, MPS, page bad - retrain requested) * * Don't do this on generic Rockwell modems. It won't work. */ if ( ( modem_quirks & MQ_NO_LQC ) == 0 && fhs_details && ( fhs_lc < 50 || fhs_blc > (fhs_lc/10)+30 || fhs_blc > 500 ) ) { lprintf( L_WARN, "Page doesn't look good, request retrain (MPS)" ); fax_command( "AT+FPS=2", "OK", fd ); } /* teergrubing mode (s) */ if ( modem_quirks & 0x100 ) { lprintf( L_WARN, "teergrubing -> signalling 'page bad'" ); fax_command( "AT+FPS=2", "OK", fd ); } if ( modem_quirks & 0x200 ) { lprintf( L_WARN, "teergrubing -> hanging up hard" ); fax_command( "ATH0", "OK", fd ); return ERROR; } /* send command to receive next page * and to release post page response (+FP[T]S) to remote fax */ fax_send( "AT+FDR", fd ); /* read: +FCFR, [+FDCS:], CONNECT */ /* if it was the *last* page, modem will send +FHNG:0 -> * fax_hangup will be set to TRUE */ if ( fax_wait_for( "CONNECT", fd ) == ERROR ) return ERROR; } return NOERROR; } mgetty-1.1.36/faxsend.c0100644000031200001470000003016210634432552013207 0ustar gertfax#ident "$Id: faxsend.c,v 4.9 2007/06/15 06:44:58 gert Exp $ Copyright (c) 1994 Gert Doering" /* faxsend.c * * Send single fax pages using a class 2 or class 2.0 faxmodem. * Called by faxrec.c (poll server) and sendfax.c (sending faxes). * * Depends on "modem_type" being set to Mt_class2_0 for 2.0 support. * * Eventually add headers to each page. * * The code is still quite rough, but it works. * * $Log: faxsend.c,v $ * Revision 4.9 2007/06/15 06:44:58 gert * add CVS Log tag * */ #include #include #include #include #include "syslibs.h" #ifndef sunos4 #include #endif #include #include "mgetty.h" #include "tio.h" #include "policy.h" #include "fax_lib.h" static boolean fax_sendpg_timeout = FALSE; static RETSIGTYPE fax_send_timeout(SIG_HDLR_ARGS) { signal( SIGALRM, fax_send_timeout ); /* reactivate handler */ lprintf( L_WARN, "fax_send: timeout" ); fax_sendpg_timeout = TRUE; } /* DLE ETX: send at end of all fax data to terminate page */ static char fax_end_of_page[] = { DLE, ETX }; static void fax_send_panic_exit _P1( (fd), int fd ) { lprintf( L_FATAL, "PANIC: timeout sending fax page data, trying force modem reset\n" ); /* by all means, reset modem */ /* heavily use alarm(), to make sure nothing blocks */ /* flush output queue */ alarm( 5 ); tio_flush_queue( fd, TIO_Q_OUT ); /* restart possibly suspended output */ alarm( 5 ); tio_flow( fd, TRUE ); /* tell modem that the page is finished. Try twice */ alarm( 5 ); write( fd, fax_end_of_page, sizeof( fax_end_of_page ) ); alarm( 5 ); write( fd, fax_end_of_page, sizeof( fax_end_of_page ) ); /* Hang up. Various methods */ alarm( 5 ); write( fd, "AT+FK\r\n", 7 ); alarm( 5 ); write( fd, "ATH0\r\n", 6 ); /* Now, try to reset it by lowering DTR */ alarm( 10 ); tio_toggle_dtr( fd, 500 ); delay(500); tio_toggle_dtr( fd, 500 ); delay(500); /* try again to hang up + reset it */ alarm( 5 ); write( fd, "ATH0Z\r\n", 7 ); delay(500); /* if the modem is *still* off-hook, there's nothing we can do. */ /* Hope that mgetty will be able to reinitialize it */ alarm( 0 ); rmlocks(); exit(15); } /* fax_send_page - send one complete fax-G3-file to the modem * * modem has to be in sync, waiting for at+fdt * page punctuation is transmitted according to "ppm" * number of bytes transmitted is added to "*bytes_sent" (for statistics) */ int fax_send_page _P5( (g3_file, bytes_sent, tio, ppm, fd), char * g3_file, int * bytes_sent, TIO * tio, Post_page_messages ppm, int fd ) { int g3fd; char ch; char buf[256]; /* read chunk */ char wbuf[ sizeof(buf) * 2 ]; /* worst case: size doubles */ int w_total = 0; /* total bytes written */ int rc; /* return code */ #ifdef CLASS1 if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) return fax1_send_page( g3_file, bytes_sent, tio, ppm, fd ); #endif lprintf( L_NOISE, "fax_send_page(\"%s\") started...", g3_file ); /* disable software output flow control! It would eat the XON otherwise! */ tio_set_flow_control( fd, tio, (FAXSEND_FLOW) & FLOW_HARD ); tio_set( fd, tio ); /* tell modem that we're ready to send - modem will answer * with a couple of "+F..." messages and finally CONNECT and XON */ if ( fax_command( "AT+FDT", "CONNECT", fd ) == ERROR || fax_hangup != 0 ) { lprintf( L_WARN, "AT+FDT -> some error (%d), abort fax send!", fax_hangup_code ); return ERROR; } /* alarm handler */ signal( SIGALRM, fax_send_timeout ); /* when modem is ready to receive data, it will send us an XON * (20 seconds timeout) * * Not all issues of the class 2 draft require this Xon, and, further, * the class 2.0 and 2.1 standard do *not* have it, so it's optional. */ if ( modem_type == Mt_class2 && ( modem_quirks & MQ_NO_XON ) == 0 ) { lprintf( L_NOISE, "waiting for XON, got:" ); alarm( 20 ); do { if ( mdm_read_byte( fd, &ch ) != 1 ) { lprintf( L_ERROR, "timeout waiting for XON" ); fprintf( stderr, "error waiting for XON!\n" ); close( fd ); exit(11); /*! FIXME! should be done farther up */ } lputc( L_NOISE, ch ); } while ( ch != XON ); alarm(0); } /* end if ( mt == class 2 ) */ /* Now enable software flow control, if desired, we've got the Xon */ tio_set_flow_control( fd, tio, (FAXSEND_FLOW) & (FLOW_HARD|FLOW_XON_OUT)); tio_set( fd, tio ); /* send one page */ lprintf( L_MESG, "sending %s...", g3_file ); g3fd = open( g3_file, O_RDONLY ); if ( g3fd == -1 ) { lprintf( L_ERROR, "cannot open %s", g3_file ); lprintf( L_WARN, "have to send empty page instead" ); } else { int r, i, w; int w_refresh = 0; boolean first = TRUE; /* timing at start of page is a bit critical - some modems can't * get this reliably right, so we have the option to send a few ms * of 0-bytes, before the 001 EOL, thus relaxing the timing a bit */ if ( modem_quirks & MQ_NEED_SP_PAD ) { char nbuf[100]; lprintf( L_MESG, "send %d 0-bytes (pad before first EOL)...", sizeof(nbuf) ); bzero( nbuf, sizeof(nbuf) ); write( fd, nbuf, sizeof(nbuf) ); } alarm( 40 ); /* timeout if we get stuck in flow control */ while ( ( r = read( g3fd, buf, 64 ) ) > 0 ) { /* refresh alarm counter every 1000 bytes */ if ( w_refresh > 1000 ) { w_refresh -= 1000; alarm( 30 ); } i = 0; /* skip over GhostScript / digifaxhigh header */ if ( first ) { first = FALSE; if ( r >= 64 && strcmp( buf+1, "PC Research, Inc" ) == 0 ) { lprintf( L_MESG, "skipping over GhostScript header" ); i = 64; /* for dfax files, we can check if the resolutions match */ if ( ( fax_par_d.vr != 0 ) != ( buf[29] != 0 ) ) { fprintf( stderr, "WARNING: sending in %s mode, fax data is %s mode\n", fax_par_d.vr? "fine" : "normal", buf[29] ? "fine" : "normal" ); lprintf( L_WARN, "resolution mismatch" ); } } else /* it's incredible how stupid users are - check for */ /* "tiffg3" files and issue a warning if the file is */ /* suspect */ if ( r >= 2 && ( ( buf[0] == 0x49 && buf[1] == 0x49 ) || ( buf[0] == 0x4d && buf[1] == 0x4d ) ) ) { lprintf( L_WARN, "file may be 'tiffg3' - TIFF is *not* a valid input format" ); fprintf( stderr, "WARNING: file may be 'tiffg3' - TIFF file format is *not* supported!\n" ); fprintf( stderr, " Thus, fax transmission will most propably fail\n" ); } else if ( r < 10 || buf[0] != 0 ) { lprintf( L_WARN, "file looks 'suspicious', buf=%02x %02x %02x %02x...", buf[0] &0xff, buf[1] &0xff, buf[2] &0xff, buf[3] &0xff ); fprintf( stderr, "WARNING: are you sure that this is a G3 fax file? Doesn't seem to be...\n" ); } } /* escape DLE characters. If necessary (+FBO=0), swap bits */ for ( w = 0; i < r; i++ ) { wbuf[ w ] = fax_send_swaptable[ (unsigned char) buf[i] ]; if ( wbuf[ w++ ] == DLE ) wbuf[ w++ ] = DLE; } lprintf( L_JUNK, "read %d, write %d", r, w ); if ( write( fd, wbuf, w ) != w ) { lprintf( L_ERROR, "could not write all %d bytes", w ); } /* check for timeout */ if ( fax_sendpg_timeout ) { fax_send_panic_exit( fd ); } w_total += w; w_refresh += w; /* look if there's something to read * * normally there shouldn't be anything, but I have * seen very old ZyXEL releases sending junk and then * failing completely... so this may help when debugging * * Also, if you don't use FLOW_SOFT for sendfax, and * your modem insists on xon/xoff flow control, you'll * see these characters [0x11/0x13] here. */ if ( check_for_input( fd ) ) { lprintf( L_NOISE, "input: got " ); do { /* intentionally don't use mdm_read_byte here */ if ( read( fd, &ch, 1 ) != 1 ) { lprintf( L_ERROR, "read failed" ); break; } else lputc( L_NOISE, ch ); } while ( check_for_input( fd ) ); } } /* end while (more g3 data to read) */ close(g3fd); } /* end if (open file succeeded) */ lprintf( L_MESG, "page complete, %d bytes sent", w_total ); if ( bytes_sent != NULL ) *bytes_sent += w_total; /* send end-of-page characters and post-page-message */ rc = fax_send_ppm( fd, tio, ppm ); alarm(0); return rc; } /* send end-of-page code, set fax_page_transmit_status * * class 2 : send , then send AT+FET=... according to "type" * class 2.0: send {||}, then send AT+FPS? */ int fax_send_ppm _P3( (fd, tio, ppm), int fd, TIO * tio, Post_page_messages ppm ) { int rc; /* set alarm clock to a time long enough to handle *very* slow links * on modems with *very* large buffers (2400 / ZyXEL...) */ alarm( FAX_RESPONSE_TIMEOUT ); if ( modem_type == Mt_class2_0 ) { /* in class 2.0, end-of-page *and* page punctuation are * transmitted in one. The modem will return OK or ERROR, * depending on the remote page transmit status */ /* EIA 592, 8.3.3.7 */ char ppm_char, ppm_buf[2], *ppm_r; switch( ppm ) { case pp_mps: /* another page next */ ppm_char = 0x2c; break; case pp_eom: /* last page, another document next */ ppm_char = 0x3b; break; case pp_eop: /* no more pages or documents */ /* stop being sensitive to DCD drops */ #ifdef sun /* On SUNs, HW handshake has to be off while carrier is low */ /* -> to avoid underruns, drain buffers first (Nils Jonsson) */ tio_drain_output( fd ); tio_set_flow_control(fd, tio, (FAXSEND_FLOW) & FLOW_XON_OUT); #endif tio_carrier( tio, FALSE ); tio_set( fd, tio ); ppm_char = 0x2e; break; default: lprintf( L_WARN, "ppm type %d not implemented", ppm ); return ERROR; } lprintf( L_MESG, "sending DLE '" ); lputc( L_MESG, ppm_char ); lputc( L_MESG, '\'' ); ppm_buf[0] = DLE; ppm_buf[1] = ppm_char; if ( write( fd, ppm_buf, 2 ) != 2 ) { lprintf( L_ERROR, "cannot write PPM" ); return ERROR; } /* FIXME: I think this should be done with fax_wait_for()! */ do { ppm_r = mdm_get_line( fd ); if ( ppm_r == NULL ) return ERROR; /* hangup code. See fax_wait_for() for comments */ if ( strncmp( ppm_r, "+FHS:", 5 ) == 0 ) { fax_hangup = 1; signal( SIGHUP, SIG_IGN ); sscanf( &ppm_r[5], "%d", &fax_hangup_code ); lprintf( L_MESG, "connection hangup: '%s'", ppm_r ); lprintf( L_NOISE,"(%s)", fax_strerror( fax_hangup_code )); } } while ( strcmp( ppm_r, "OK" ) != 0 && strcmp( ppm_r, "ERROR" ) != 0 ); lprintf( L_MESG, "got response: '%s'", ppm_r ); /* fax page status is encoded here! */ /* FIXME: query page tx status from modem */ fax_page_tx_status = ( strcmp( ppm_r, "OK" ) == 0 ) ? 1: 2; /* FIXME: this way? */ /* fax_command( "AT+FPS?", "OK", fd ); */ return NOERROR; } else { /* transmit end of page ( -> OK) */ lprintf( L_MESG, "sending DLE ETX..." ); write( fd, fax_end_of_page, sizeof( fax_end_of_page )); if ( fax_wait_for( "OK", fd ) == ERROR ) return ERROR; /* transmit page punctuation */ switch ( ppm ) { case pp_mps: /* another page next */ rc = fax_command( "AT+FET=0", "OK", fd ); break; case pp_eom: /* last page, another document next */ rc = fax_command( "AT+FET=1", "OK", fd ); break; case pp_eop: /* no more pages or documents, over & out */ /* take care of modems pulling DCD low before the final * result code has reached the host */ tio_carrier( tio, FALSE ); #ifdef sun /* HW handshake has to be off while carrier is low */ tio_set_flow_control(fd, tio, (FAXSEND_FLOW) & FLOW_XON_OUT); #endif tio_set( fd, tio ); rc = fax_command( "AT+FET=2", "OK", fd ); break; default: /* pri-xxx codes */ lprintf( L_WARN, "ppm type %d not implemented", ppm ); rc = ERROR; } return rc; } /* end if ( ! modem == 2.0 ) */ } mgetty-1.1.36/faxlib.c0100600000031200001470000006760210617071162013022 0ustar gertfax#ident "$Id: faxlib.c,v 4.74 2007/02/06 17:04:13 gert Exp $ Copyright (c) Gert Doering" /* faxlib.c * * Module containing generic faxmodem functions (as: send a command, wait * for modem responses, parse modem responses) * * Only class 2 and class 2.0 stuff is here. Class 1 stuff is so * different that it goes to a separate library. * * $Log: faxlib.c,v $ * Revision 4.74 2007/02/06 17:04:13 gert * fix modem ID stuff for Blatzheim * * Revision 4.73 2007/02/06 16:26:07 gert * grab FW version number for Blatzheim modems * * Revision 4.72 2006/11/03 13:08:50 gert * add CVS tag * */ #include #include #include #include #include #include #include #include "mgetty.h" #include "policy.h" #include "fax_lib.h" Modem_type modem_type = Mt_unknown; /* uninitialized */ char fax_remote_id[40]; /* remote FAX id +FTSI */ char fax_param[1000]; /* transm. parameters +FDCS */ fax_param_t fax_par_d; /* fax params detailed */ char fax_hangup = 0; int fax_hangup_code = FHUP_UNKNOWN; /* hangup cause +FHNG: */ int fax_page_tx_status = 0; /* +FPTS: */ boolean fax_to_poll = FALSE; /* there's something to poll */ boolean fax_poll_req = FALSE; /* poll requested */ boolean fhs_details = FALSE; /* +FHS:xxx with detail info */ int fhs_lc, fhs_blc, fhs_cblc, fhs_lbc; int modem_quirks = 0; /* modem specials */ /* wait for a given modem response string, * handle all the various class 2 / class 2.0 status responses */ /* copy fax station id, removing quote characters (dangerous for shell!) * and leading/trailing whitespace */ static void fwf_copy_remote_id _P1( (id), char * id ) { int w = 0; while ( isspace(*id) || *id == '"' ) id++; /* skip leading whitespace */ while ( *id && w < sizeof(fax_remote_id)-1 ) { if ( *id != '"' && *id != '\'' ) fax_remote_id[w++] = *id; id++; } /* remove trailing whitespace */ while ( w>0 && isspace(fax_remote_id[w-1]) ) w--; fax_remote_id[w]=0; } static boolean fwf_timeout = FALSE; static RETSIGTYPE fwf_sig_alarm(SIG_HDLR_ARGS) /* SIGALRM handler */ { signal( SIGALRM, fwf_sig_alarm ); lprintf( L_WARN, "Warning: got alarm signal!" ); fwf_timeout = TRUE; } int fax_wait_for _P2( (s, fd), char * s, int fd ) { char * line; int ix; lprintf( L_MESG, "fax_wait_for(%s)", s ); if ( fax_hangup ) { lputs( L_MESG, ": already hangup!" ); return ERROR; } fwf_timeout = FALSE; signal( SIGALRM, fwf_sig_alarm ); alarm( FAX_RESPONSE_TIMEOUT ); do { line = mdm_get_line( fd ); if ( line == NULL ) { alarm( 0 ); signal( SIGALRM, SIG_DFL ); if ( fwf_timeout ) fax_hangup_code = FHUP_TIMEOUT; return ERROR; } lprintf( L_NOISE, "fax_wait_for: string '%s'", line ); /* find ":" character (or end-of-string) */ for ( ix=0; line[ix] != 0; ix++ ) if ( line[ix] == ':' ) { ix++; break; } if ( line[ix] == ' ' ) ix++; if ( strncmp( line, "+FTSI:", 6 ) == 0 || strncmp( line, "+FCSI:", 6 ) == 0 || strncmp( line, "+FCIG:", 6 ) == 0 || strncmp( line, "+FTI:", 5 ) == 0 || strncmp( line, "+FCI:", 5 ) == 0 || strncmp( line, "+FPI:", 5 ) == 0 ) { lprintf( L_MESG, "fax_id: '%s'", line ); fwf_copy_remote_id( &line[ix] ); } else if ( strncmp( line, "+FNSF:", 6 ) == 0 || /* class 2 */ strncmp( line, "+FNF:", 5 ) == 0 || /* class 2.0 */ strncmp( line, "FNF:", 4 ) == 0 ) /* USR bug */ { fax2_incoming_nsf( &line[ix] ); } else if ( strncmp( line, "+FDCS:", 6 ) == 0 || strncmp( line, "+FCS:", 5 ) == 0 ) { lprintf( L_MESG, "transmission par.: '%s'", line ); strcpy( fax_param, line ); if ( sscanf( &fax_param[ix], "%hd,%hx,%hd,%hd,%hd,%hd,%hd,%hd", &fax_par_d.vr, &fax_par_d.br, &fax_par_d.wd, &fax_par_d.ln, &fax_par_d.df, &fax_par_d.ec, &fax_par_d.bf, &fax_par_d.st ) != 8 ) { lprintf( L_WARN, "cannot evaluate +FCS-Code!" ); fax_par_d.vr = 0; } } else if ( strncmp( line, "+FDIS:", 6 ) == 0 || strncmp( line, "+FIS:", 5 ) == 0 ) { short vr, br, wd, ln, df, ec, bf, st, jp=0; char msg[200]; if ( sscanf( &line[ix], "%hd,%hx,%hd,%hd,%hd,%hd,%hd,%hd,%hd", &vr, &br, &wd, &ln, &df, &ec, &bf, &st, &jp ) < 8 ) { lprintf( L_WARN, "cannot evaluate +FIS-Code!" ); } /* prettyprint "non-basic" receiver capabilities */ msg[0] = '\0'; if ( vr & 1 ) strcat( msg, " fine" ); if ( vr & 2 ) strcat( msg, " sfine/R8" ); if ( vr & 4 ) strcat( msg, " sfine/R16" ); if ( vr & 0x20 ) strcat( msg, " 400dpi" ); if ( vr & 0x40 ) strcat( msg, " 300dpi" ); if ( br > 3 ) strcat( msg, br <= 5? " 144": " V34" ); if ( ln < 2 ) strcat( msg, ln == 0? " A4": " B4" ); if ( df > 0 ) strcat( msg, df == 1? " 2D/MR": df == 2? " 2D/uncomp": " 2D/MMR" ); if ( ec > 0 ) strcat( msg, " ECM" ); if ( bf > 0 ) strcat( msg, " BFT" ); if ( jp > 0 ) strcat( msg, " JPEG" ); lprintf( L_MESG, "receiver cap.: '%s' ->%s", line, msg ); } else if ( strncmp( line, "+FHNG:", 6 ) == 0 || strncmp( line, "+FHS:", 5 ) == 0 ) { /* hangup. First, set flag to indicate +FHNG: was read. * The SIGHUP signal catcher will check this, and not exit. * Next, reset the action for SIGHUP, to be ignore, so we * (and child processes) are not interrupted while we cleanup. * If the wait_for string is not "OK", return immediately, * since that is all that the modem can send after +FHNG */ fax_hangup = 1; /* set this as soon as possible */ /* change action for SIGHUP signals to be ignore */ #ifdef SIG_ERR if ( signal( SIGHUP, SIG_IGN ) == SIG_ERR ) { lprintf( L_WARN, "fax_wait_for: cannot reset SIGHUP handler." ); } #else signal( SIGHUP, SIG_IGN ); #endif lprintf( L_MESG, "connection hangup: '%s'", line ); sscanf( &line[ix], "%d", &fax_hangup_code ); lprintf( L_NOISE,"(%s)", fax_strerror( fax_hangup_code )); if ( strcmp( s, "OK" ) != 0 ) break; } else if ( strncmp( line, "+FPTS:", 6 ) == 0 || strncmp( line, "+FPS:", 5 ) == 0 ) { /* page transmit status * store into global variable (read by sendfax.c) */ lprintf( L_MESG, "page status: %s", line ); sscanf( &line[ix], "%d", &fax_page_tx_status ); /* evaluate line count, bad line count, ... for reception */ fhs_lc = 9999; fhs_blc = fhs_cblc = fhs_lbc = 0; fhs_details = FALSE; if ( line[ix+1] == ',' && /* +FPS:s,lc,blc */ sscanf( &line[ix+2], ( modem_type == Mt_class2 || (modem_quirks & MQ_FPS_NOT_HEX) ) ?"%d,%d,%d,%d" :"%x,%x,%x,%x", &fhs_lc, &fhs_blc, &fhs_cblc, &fhs_lbc ) >= 2 ) { lprintf( L_NOISE, "%d lines received, %d lines bad, %d bytes lost", fhs_lc, fhs_blc, fhs_lbc ); fhs_details = TRUE; } } else if ( strcmp( line, "+FPOLL" ) == 0 || strcmp( line, "+FPO" ) == 0 ) { /* the other side is telling us that it has a document that * we can poll (with AT+FDR) */ lprintf( L_MESG, "got +FPO -> will do polling" ); fax_to_poll = TRUE; } else if ( strncmp( line, "+FDTC:", 6 ) == 0 || strncmp( line, "+FTC:", 5 ) == 0 ) { /* we sent a +FLPL=1, and the other side wants to poll * that document now (send it with AT+FDT) */ lprintf( L_MESG, "got +FTC -> will send polled document" ); fax_poll_req = TRUE; /* we're waiting for a CONNECT here, in response to a * AT+FDR command, but only an OK will come. So, change * expect string to "OK" */ lprintf( L_MESG, "fax_wait_for('OK')" ); s = "OK"; } else if ( strcmp( line, "ERROR" ) == 0 || strcmp( line, "NO CARRIER" ) == 0 || strcmp( line, "BUSY" ) == 0 || strcmp( line, "NO DIALTONE" ) == 0 || strcmp( line, "NO DIAL TONE" ) == 0 ) { #if 0 /* not needed right now (fax_send_ppm), problem with USR!! */ if ( modem_type == Mt_class2_0 ) /* valid response */ { /* in class 2.0! */ if ( strcmp( line, "ERROR" ) == 0 ) { lprintf( L_MESG, "ERROR response" ); alarm(0); return NOERROR; /* !C2 */ } } #endif /* in class 2, one of the above codes means total failure */ lprintf( L_MESG, "ABORTING: line='%s'", line ); fax_hangup = 1; if ( strcmp(line, "BUSY") == 0 ) fax_hangup_code = FHUP_BUSY; else if (strcmp(line, "NO DIALTONE") == 0 || strcmp(line, "NO DIAL TONE") == 0) fax_hangup_code = FHUP_NODIAL; else fax_hangup_code = FHUP_ERROR; alarm( 0 ); signal( SIGALRM, SIG_DFL ); return ERROR; } } while ( strncmp( s, line, strlen(s) ) != 0 ); lputs( L_MESG, "** found **" ); alarm( 0 ); signal( SIGALRM, SIG_DFL ); if ( fax_hangup && fax_hangup_code != 0 ) return ERROR; return NOERROR; } /* (re-) initialize all global/static variables set by faxlib.c * necessary if fax state machine runs multiple times, e.g. in vgetty */ void faxlib_init _P0( void ) { fax_hangup = 0; fax_hangup_code = FHUP_UNKNOWN; fax_page_tx_status = 0; fax_to_poll = fax_poll_req = FALSE; fhs_details = FALSE; fax_remote_id[0] = '\0'; } /* send a command string to the modem, terminated with the * MODEM_CMD_SUFFIX character / string from policy.h */ int fax_send _P2( (send, fd), char * send, int fd ) { #ifndef CLASS1 # ifdef FAX_COMMAND_DELAY delay(FAX_COMMAND_DELAY); # endif #endif lprintf( L_MESG, "fax_send: '%s'", send ); if ( write( fd, send, strlen( send ) ) != strlen( send ) || write( fd, MODEM_CMD_SUFFIX, sizeof(MODEM_CMD_SUFFIX)-1 ) != ( sizeof(MODEM_CMD_SUFFIX)-1 ) ) { lprintf( L_ERROR, "fax_send: cannot write" ); return ERROR; } return NOERROR; } /* simple send / expect sequence, but pass "expect"ing through * fax_wait_for() to handle all the class 2 fax responses */ int fax_command _P3( (send, expect, fd), char * send, char * expect, int fd ) { if ( fax_send( send, fd ) == ERROR ) return ERROR; return fax_wait_for( expect, fd ); } /* Couple of routines to set this and that fax parameter, using class 2 * or 2.0 commands, according to the setting of "modem_type" */ /* set local fax id */ int fax_set_l_id _P2( (fd, fax_id), int fd, char * fax_id ) { char flid[60]; #ifdef CLASS1 if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) return fax1_set_l_id( fd, fax_id ); #endif if ( modem_type == Mt_class2_0 ) sprintf( flid, "AT+FLI=\"%.40s\"", fax_id ); else sprintf( flid, "AT+FLID=\"%.40s\"", fax_id ); if ( mdm_command( flid, fd ) == FAIL ) { lprintf( L_MESG, "cannot set local fax id. Huh?" ); return ERROR; } return NOERROR; } /* set resolution, minimum and maximum bit rate */ int fax_set_fdcc _P4( (fd, fine, max, min), int fd, int fine, int max, int min ) { char buf[50]; #ifdef CLASS1 if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) return fax1_set_fdcc( fd, fine, max, min ); #endif if ( modem_quirks & MQ_USR_FMINSP ) { /* some early versions of the USR fax firmware got this wrong, (put * "max" speed into register for "min" speed!!) so don't set speed */ sprintf( buf, "AT+FCC=%d", fine ); } else /* standard case, working modem */ { sprintf( buf, "AT%s=%d,%d,0,2,0,0,0,0", (modem_type == Mt_class2_0) ? "+FCC" : "+FDCC", fine, (max/2400) -1 ); } if ( mdm_command( buf, fd ) == ERROR ) { if ( max > 9600 ) return fax_set_fdcc( fd, fine, 9600, min ); else return ERROR; } if ( min >= 2400 ) { if ( modem_type == Mt_class2_0 ) sprintf( buf, "AT+FMS=%d", (min/2400) -1 ); else sprintf( buf, "AT+FMINSP=%d", (min/2400) -1 ); if ( mdm_command( buf, fd ) == ERROR ) { lprintf( L_WARN, "+FMINSP command failed, ignoring" ); } } return NOERROR; } /* set modem flow control (for fax mode only) * * right now, this works only for class 2.0 faxing. Class 2 has * no idea of a common flow control command. * If hw_flow is set, use RTS/CTS, otherwise, use Xon/Xoff. */ int fax_set_flowcontrol _P2( (fd, hw_flow), int fd, int hw_flow ) { if ( modem_type == Mt_class2_0 ) { if ( hw_flow ) { if ( mdm_command( "AT+FLO=2", fd ) == NOERROR ) return NOERROR; lprintf( L_WARN, "modem doesn't like +FLO=2; using Xon/Xoff" ); } return mdm_command( "AT+FLO=1", fd ); } return NOERROR; } /* byte swap table used for sending (yeah. Because Rockwell screwed * up *that* completely in class 2, we have to have different tables * for sending and receiving. Bah.) */ unsigned char fax_send_swaptable[256]; unsigned char fax_recv_swaptable[256]; /* set up bit swap table */ void fax_init_swaptable _P2( (direct, byte_tab), int direct, unsigned char byte_tab[] ) { int i; if ( direct ) for ( i=0; i<256; i++ ) byte_tab[i] = i; else for ( i=0; i<256; i++ ) byte_tab[i] = ( ((i & 0x01) << 7) | ((i & 0x02) << 5) | ((i & 0x04) << 3) | ((i & 0x08) << 1) | ((i & 0x10) >> 1) | ((i & 0x20) >> 3) | ((i & 0x40) >> 5) | ((i & 0x80) >> 7) ); } /* set modem bit order, and initialize bit swap table accordingly */ int faxmodem_bit_order = 0; int fax_set_bor _P2( (fd, bor), int fd, int bor ) { char buf[20]; faxmodem_bit_order = bor; fax_init_swaptable( faxmodem_bit_order & 1, fax_send_swaptable ); /* the whole bit swap table business is very ugly. It comes from * the way the old Rockwell class 2 code got it wrong (for reception * only!), and the way mgetty and all tools have been adapted to that. * So, class 2.x uses "1:1" (but uses different AT+FBO=x settings, * depending on whether the modem will do it right), and class 1(.x) * has to use "reverse" tables for reception. Bah. */ if ( modem_type == Mt_class1 || modem_type == Mt_class1_0 ) { fax_init_swaptable( FALSE, fax_recv_swaptable ); /* swap bits */ return NOERROR; } fax_init_swaptable( TRUE, fax_recv_swaptable ); /* no swap */ if ( modem_type == Mt_class2_0 ) sprintf( buf, "AT+FBO=%d", bor ); else sprintf( buf, "AT+FBOR=%d", bor ); return mdm_command( buf, fd ); } /* parse NSF (non-standard frames) - like "remote vendor ID", etc. * * class 2/2.0 deliver NSFs like this: "+FNF:86 40 40 FF 06 42 86 40 40", * while class 1 just delivers a binary frame. * -> convert to binary, pass on to class 1 handler * * (some modems deliver "+FNF:0000090008...", so we accept about anything * that looks like "pairs of hex digits with or without separators") */ #define char_to_hex(ch) ( ( (ch)>='0' && (ch)<='9')? (ch)-'0' : \ tolower((ch))-'a'+10 ) void fax2_incoming_nsf _P1((nsf_hex), char * nsf_hex ) { #ifdef FAX_NSF_PARSER uch nsf_bin[200]; int len; char *p; len = 0; p = nsf_hex; /* some modems insert extra quotes at the start... (ZyXEL) */ while( *p != '\0' && ! isxdigit(*p) ) p++; while( len try "old way" */ /* first of all, check for 2.0 */ if ( strcmp( mclass, "auto" ) == 0 || strcmp( mclass, "c2.0" ) == 0 ) { if ( mdm_command( "AT+FCLASS=2.0", fd ) == SUCCESS ) { return Mt_class2_0; } } #ifdef CLASS1 /* if explicitely requested, do class 1 (EXPERIMENTAL) */ if ( strcmp( mclass, "cls1" ) == 0 ) { if ( mdm_command( "AT+FCLASS=1", fd ) == SUCCESS ) { return Mt_class1; } } if ( strcmp( mclass, "c1.0" ) == 0 ) { if ( mdm_command( "AT+FCLASS=1.0", fd ) == SUCCESS ) { return Mt_class1_0; } } #endif /* not a 2.0 modem (or not allowed to check), simply *try* class 2, nothing to loose */ if ( mdm_command( "AT+FCLASS=2", fd ) == SUCCESS ) { return Mt_class2; } /* failed. Assume data modem */ return Mt_data; } /* end fax_get_modem_type() */ /* identify unknown modem via ATI code * * *very* preliminary - I'm experimenting... */ int mdm_identify _P1( (fd), int fd ) { char * l, *p; char * mis = NULL; /* more verbose modem ID string */ modem_type=Mt_unknown; /* try ATI first, ATI later to sub-divide results */ l = mdm_get_idstring( "ATI", 1, fd ); lprintf( L_NOISE, "mdm_identify: string '%s'", l ); if ( strcmp( l, "" ) == 0 ) { lprintf( L_WARN, "mdm_identify: can't get modem ID" ); return ERROR; } /* all-numerical? */ p = l; while( isdigit(*p) || isspace(*p) ) p++; if ( *p == '\0' ) /* all-numeric */ { int mid = atoi(l); /* numerical modem ID... */ switch(mid) { case 0: /* empty string */ lprintf( L_MESG, "got no modem ID. Hagenuk Speed Dragon?" ); mis = mdm_get_idstring( "ATI0", 1, fd ); break; case 1496: lprintf( L_MESG, "ZyXEL 1496 detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 2864: lprintf( L_MESG, "ZyXEL 2864(D) detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 28641: case 28642: lprintf( L_MESG, "ZyXEL 2864I(D) detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 33604: lprintf( L_MESG, "ZyXEL U-336E detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 1281: case 1291: case 1293: lprintf( L_MESG, "ZyXEL Omni.NET detected" ); modem_type=Mt_data; /* has no fax mode */ mis = mdm_get_idstring( "ATI1", 1, fd ); break; case 1292: lprintf( L_MESG, "ZyXEL Omni.NET LCD+M detected" ); modem_type=Mt_class2; /* rockwell based */ mis = mdm_get_idstring( "ATI1", 1, fd ); break; case 1500: case 1501: case 1507: lprintf( L_MESG, "ZyXEL Omni 56K (Plus/Pro) detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 1503: lprintf( L_MESG, "ZyXEL U-90E (?) detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI1", 2, fd ); break; case 1444: lprintf( L_MESG, "USR Courier/Sportster v32bis detected (assuming non-fax capable)" ); modem_type=Mt_data; break; case 1445: lprintf( L_MESG, "USR Courier/Sportster v32bis detected (buggy fax implementation)" ); modem_type=Mt_class2_0; modem_quirks |= MQ_USR_FMINSP | MQ_FPS_NOT_HEX; break; case 2886: case 3361: case 3362: case 3366: case 3367: lprintf( L_MESG, "USR Courier/Sportster V.34(+) detected" ); modem_type=Mt_class2_0; modem_quirks |= MQ_FPS_NOT_HEX; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 5601: case 5607: lprintf( L_MESG, "USR Courier/Sportster 56k detected" ); modem_type=Mt_class2_0; modem_quirks |= MQ_FPS_NOT_HEX; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 6401: lprintf( L_MESG, "USR I-Modem detected" ); modem_type=Mt_class2_0; modem_quirks |= MQ_FPS_NOT_HEX; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 62: /* sure? */ case 962: lprintf( L_MESG, "Dr. Neuhaus Smarty detected (?)" ); modem_type=Mt_class2; /* now do ATI9! */ modem_quirks |= MQ_NEED2; mis = mdm_get_idstring( "ATI9", 1, fd ); break; case 932: /* Thomas Schuett, info@thomas-schuett.de */ lprintf( L_MESG, "Zoom MX/S detected" ); modem_type=Mt_class2; modem_quirks |= MQ_NEED2; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 961: lprintf( L_MESG, "Zoltrix 14400 faxmodem detected (?)" ); modem_type=Mt_class2; mis = mdm_get_idstring( "ATI4", 1, fd ); break; case 144: /* UMC 1440 baud modem (not sure) */ lprintf( L_MESG, "UMC92144EF modem detected(?)" ); modem_type=Mt_class2; mis = mdm_get_idstring( "ATI4", 1, fd ); modem_quirks |= MQ_NEED2; break; case 184: /* sure? */ lprintf( L_MESG, "Telebit FastBlazer detected" ); modem_type=Mt_data; break; case 149: /* sure? */ lprintf( L_MESG, "Intel 14.4E/400e detected (?)" ); modem_type=Mt_unknown; break; case 247: /* use ATI2 for further distinction */ lprintf( L_MESG, "Multitech MT1432BA/MT1932ZDX/MT2834ZDX detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI2", 1, fd ); modem_quirks |= MQ_FBOR_OK; break; case 251: /* sure? */ lprintf( L_MESG, "Discovery 2400 AM detected" ); modem_type=Mt_data; break; case 288: /* Fred Wendorf */ lprintf( L_MESG, "Trust Communicator 28 K8 detected" ); modem_type=Mt_class2; modem_quirks |= MQ_NEED2; break; case 641: /* sure? */ lprintf( L_MESG, "ELSA MicroLink ISDN/TLpro detected" ); modem_type=Mt_data; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 643: /* ATI6/ATI3 for model/firmware info */ lprintf( L_MESG, "ELSA MicroLink ISDN/TLV.34 detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 645: /* ATI6/ATI3 for model/firmware info */ lprintf( L_MESG, "ELSA MicroLink Internet II detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 282: /* ATI6/ATI3 for model/firmware info */ lprintf( L_MESG, "ELSA MicroLink 28.8/56K series detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 140: /* ATI6/ATI3 for model/firmware info */ lprintf( L_MESG, "ELSA MicroLink 14.4TQ series detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 249: case 14400: /* further distinction necessary (ATI3,4,6)! */ case 28800: case 33600: case 56000: lprintf( L_MESG, "Generic Rockwell modem (%d)", mid ); modem_type=Mt_class2; modem_quirks |= MQ_NO_LQC; mis = mdm_get_idstring( "ATI3", 1, fd ); if ( mid == 28800 && mis[0] == '\0' ) /* no ATI3 code */ { lprintf( L_MESG, "Sounds more like Dr.Neuhaus Cybermod" ); modem_quirks |= MQ_NEED2; } else /* "Version 6.00" */ if ( mid == 28800 && strncmp( mis, "Version", 7 ) == 0 ) { lprintf( L_MESG, "Could be a Hayes Optima/Accura modem" ); mis = mdm_get_idstring( "ATI7", 2, fd ); modem_quirks |= MQ_NEED2; break; } mis = mdm_get_idstring( "ATI4", 1, fd ); break; case 2884: lprintf( L_MESG, "sounds like a Microcom DeskPorte Fast+" ); modem_type=Mt_class2_0; modem_quirks |= MQ_NO_LQC; /* +FPS: broken */ mis = mdm_get_idstring( "ATI3", 1, fd ); break; case 336: /* one report only */ lprintf( L_MESG, "could be a CompuTime RalleyCom 336" ); break; case 242: /* one report only */ lprintf( L_MESG, "could be a Tornado III FM-144VBIS" ); modem_type=Mt_class2; modem_quirks |= MQ_NO_XON; break; default: lprintf( L_MESG, "unknown numerical modem id %d", mid ); break; } } else /* non-numeric modem id string */ { lprintf( L_MESG, "non-numeric ID string: '%s'", l ); /* "Elink 310 Version 1.25" */ /* "Elink 34-3 P1 Version 1.64" */ if ( strncmp( l, "Elink", 5 ) == 0 ) { lprintf( L_MESG, "Elink detected" ); if ( strncmp( l+6, "34-3" , 4 ) == 0 ) modem_type=Mt_class2; else modem_type=Mt_data; } else if ( strncmp( l, "Eicon ISDN Modem", 16 ) == 0 ) { lprintf( L_MESG, "Diehl/Eicon ISDN (assuming DIVA card with class 2 fax)" ); modem_type=Mt_class2; } else if ( strncmp( l, "Linux ISDN", 10 ) == 0 ) { lprintf( L_MESG, "ISDN4Linux detected" ); modem_type=Mt_data; } /* got this from bruce@hn.pl.net */ else if ( strncmp( l, "1.03", 4 ) == 0 ) { lprintf( L_MESG, "Ellcon 14.4+Voice detected" ); modem_type=Mt_data; } /* got this from Matt Atkins, matta@cl-sys.com */ else if ( strncmp( l, "1.0", 3 ) == 0 ) { lprintf( L_MESG, "Cirrus Logic Communicator 56 detected" ); modem_type=Mt_unknown; mis = mdm_get_idstring( "ATI3", 1, fd ); } /* got this from Andreas Muck, * and Frank Damgaard */ else if ( strncmp( l, "5607A", 5 ) == 0 || strncmp( l, "5607B", 5 ) == 0 ) { lprintf( L_MESG, "USR Courier/Sportster V90 (national variant?) detected" ); modem_type=Mt_class2_0; modem_quirks |= MQ_FPS_NOT_HEX; mis = mdm_get_idstring( "ATI3", 1, fd ); } /* grrr, another one of those - Bill Nugent */ else if ( strncmp( l, "MT5600ZDXV", 10 ) == 0 ) { lprintf( L_MESG, "Multitech MT5600ZDXV detected" ); modem_type=Mt_class2; } /* and yet another one :-( - Nokia, sigh */ else if ( strncmp( l, "Nokia ", 6 ) == 0 ) { lprintf( L_MESG, "Nokia GSM telephone detected" ); modem_type=Mt_class2_0; mis = mdm_get_idstring( "ATI3", 1, fd ); } /* and yet another one - will they never end? Xavier Roche */ else if ( strncmp( l, "LT V.90", 7 ) == 0 ) { lprintf( L_MESG, "Multitech MT5634Z internal detected" ); modem_type=Mt_class2; modem_quirks |= MQ_NEED2; } else if ( strncmp( l, "LT V.92", 7 ) == 0 ) /* gert */ { lprintf( L_MESG, "Multitech MT5634ZBA-V92 detected" ); modem_type=Mt_class2_0; modem_quirks |= MQ_FPS_NOT_HEX; } else if ( strncmp( l, "SIEMENS", 7 ) == 0 ) /* gert */ { lprintf( L_MESG, "possibly Siemens GSM modem? assuming class 2" ); modem_type=Mt_class2; } else if ( strncmp( l, "BM-33k6/ISDN pro", 16 ) == 0 ) /* gert */ { lprintf( L_MESG, "Blatzheim ISDN modem, buggy class 2.0, force class 2" ); modem_type=Mt_class2; mis = mdm_get_idstring( "ATI3", 1, fd ); } } if ( mis != NULL ) lprintf( L_MESG, "additional info: '%s'", mis ); if ( modem_quirks ) lprintf( L_MESG, "modem quirks: %04x", modem_quirks ); return NOERROR; } mgetty-1.1.36/fax_lib.h0100600000031200001470000001131310634432524013154 0ustar gertfax#ident "$Id: fax_lib.h,v 4.19 2007/05/16 15:24:46 gert Exp $ Copyright (c) Gert Doering" /* fax_lib.h * * declare protopes for all the fax functions in faxrec.c and faxlib.c * declare global variables set by functions in faxlib.c * declare all the constants required for Class 2 faxing */ /* data types + variables */ typedef enum { Mt_unknown, Mt_data, Mt_class1, /* TIA/EIA 578 standard */ Mt_class1_0, /* ITU T.31 standard */ Mt_class2, /* SP-2388 / EIA 592 drafts */ Mt_class2_0, /* TIA/EIA 592 standard */ Mt_class2_1 /* ITU T.32 standard */ } Modem_type; extern Modem_type modem_type; typedef enum { pp_mps, pp_eom, pp_eop, pp_pri_mps, pp_pri_eom, pp_pri_eop } Post_page_messages; extern unsigned char fax_send_swaptable[], fax_recv_swaptable[]; /* function prototypes */ int fax_send _PROTO(( char * s, int fd )); /* write to fd, with logging */ /* expect string, handle fax msgs */ int fax_wait_for _PROTO(( char * s, int fd )); int fax_command _PROTO(( char * send, char * expect, int fd )); void fax_find_directory _PROTO(( char * dirlist, char * directory, int size )); int fax_get_pages _PROTO(( int fd, int * pagenum, char * directory, int uid, int gid, int mode )); int fax_get_page_data _PROTO(( int modem_fd, int pagenum, char * directory, int uid, int gid, int file_mode )); int fax_set_l_id _PROTO(( int fd, char * fax_id )); int fax_set_fdcc _PROTO(( int fd, int fine, int maxsp, int minsp )); int fax_set_bor _PROTO(( int fd, int bit_order )); int fax_set_flowcontrol _PROTO(( int fd, int hw_flow )); int mdm_identify _PROTO(( int fd )); void fax2_incoming_nsf _PROTO(( char * nsf_hex )); void fax1_incoming_nsf _PROTO(( uch * nsf_bin, int len )); void hylafax_nsf_decode _PROTO(( uch * nsf, int nsfSize )); #ifdef __TIO_H__ int fax_send_page _PROTO(( char * g3_file, int * bytes_sent, TIO * tio, Post_page_messages ppm, int fd )); int fax_send_ppm _PROTO(( int fd, TIO *tio, Post_page_messages ppm )); #endif Modem_type fax_get_modem_type _PROTO(( int fd, char * mclass )); typedef struct { short vr, br, wd, ln, df, ec, bf, st; } fax_param_t; #ifdef CLASS1 /* prototypes for class 1 functions */ int fax1_dial_and_phase_AB _PROTO(( char * dial_cmd, int fd )); int fax1_highlevel_receive _PROTO(( int fd, int * pagenum, char * dirlist, int uid, int gid, int mode)); int fax1_set_l_id _PROTO(( int fd, char * fax_id )); int fax1_set_fdcc _PROTO(( int fd, int fine, int max, int min )); extern boolean fax1_receive_have_connect; #endif /* g3file.c */ typedef int (in_func_t)(char *, int); in_func_t g3_rf_chunk; int g3_open_read _PROTO(( char * filename )); void g3_close _PROTO((void)); int g3_send_file _PROTO((in_func_t * in_func, int out_fd, int is_device, int escape_dle, int pad_bytes, int fax_res )); extern char fax_remote_id[]; /* remote FAX id +FTSI */ extern char fax_param[]; /* transm. parameters +FDCS */ extern char fax_hangup; extern int fax_hangup_code; extern int fax_page_tx_status; extern fax_param_t fax_par_d; extern boolean fax_to_poll; /* there's something */ /* to poll */ extern boolean fax_poll_req; /* caller wants to poll */ extern boolean fhs_details; /* +FHS:x,lc info avail.*/ extern int fhs_lc, fhs_blc, fhs_cblc, fhs_lbc; /* details */ extern int modem_quirks; /* modem specials */ /* fax_hangup_code gives the reason for failure, normally it's a positive * number returned by the faxmodem in the "+FHNG:iii" response. If the * modem returned BUSY or NO_CARRIER or ERROR, we use negative numbers to * signal what has happened. "-5" means something toally unexpeced. */ #define FHUP_BUSY -2 #define FHUP_NODIAL -3 #define FHUP_ERROR -4 #define FHUP_UNKNOWN -5 #define FHUP_TIMEOUT -6 #define ETX 003 #define DLE 020 #define SUB 032 #define DC2 022 #define XON 021 #define XOFF 023 #define CAN 030 /* ctrl-x, abort */ #ifndef ERROR #define ERROR -1 #define NOERROR 0 #endif /* modem_quirks specifies some details in this modem's implementation * that are just *different* from the usual... */ #define MQ_NEED2 0x01 /* must be in +FCLASS=2 for +FAA=1 to work */ #define MQ_FBOR_OK 0x02 /* +FBOR implemented correctly (Multitech) */ #define MQ_NO_LQC 0x04 /* +FPS:x,lc,blc can't be trusted */ #define MQ_NO_XON 0x08 /* do not wait for XON char when sending */ #define MQ_NEED_SP_PAD 0x10 /* modem needs 0-padding before start of page */ #define MQ_USR_FMINSP 0x20 /* USR: +FCC=1, sets MIN speed instead */ #define MQ_SHOW_NSF 0x40 /* set AT+FNR=1,1,1,1 (with NSFs) */ #define MQ_FPS_NOT_HEX 0x80 /* +FPS:, reported as decimal */ /* note: 0x100 and 0x200 currently used for teergrubing - faxrecp.c */ #define MQ_C1_NO_V17 0x400 /* class1: don't use V.17, even if adv. */ mgetty-1.1.36/sendfax.c0100600000031200001470000005302610554072555013207 0ustar gertfax#ident "$Id: sendfax.c,v 4.25 2006/11/22 17:04:21 gert Exp $ Copyright (c) Gert Doering" /* sendfax.c * * Send a Fax using a class 2 faxmodem. * Calls routines in faxrec.c and faxlib.c * * The code is still quite rough, but it works. * * $Log: sendfax.c,v $ * Revision 4.25 2006/11/22 17:04:21 gert * fix logging of #of pages (for exit 12) * * Revision 4.24 2006/11/22 16:24:57 gert * for the "transmission failed" (exit 12) case, log #of pages successfully * sent and #of of retransmissions - important stats to track down problems * * Revision 4.23 2006/09/27 09:12:25 gert * add L_AUDIT log message to non-accessible file error (exit 1) * * Revision 4.22 2006/09/26 15:10:23 gert * extend xon-xoff flow control comment a bit, for class 1 * * Revision 4.21 2005/12/31 16:01:11 gert * identically handle class 1 and 1.0 * * Revision 4.20 2005/05/25 14:03:55 gert * add CVS LOG * */ #include #include #include #include #include "syslibs.h" #ifndef sunos4 #include #endif #include #include #ifndef ENOENT # include #endif #include "version.h" #include "mgetty.h" #include "tio.h" #include "policy.h" #include "fax_lib.h" /* configuration */ #include "config.h" #include "conf_sf.h" /* use direct bit order in modem, that means, we have to reverse */ #define REVERSE 1 char * fac_tel_no; boolean verbose = FALSE; extern time_t call_start; /* for accounting */ /* seems to missing nearly everywhere */ #if !defined(__NetBSD__) && !defined(__OpenBSD__) time_t time _PROTO(( time_t * tloc )); #endif TIO fax_tio; char *Device = "unset"; void exit_usage _P2( (program, msg ), char * program, char * msg ) { if ( msg != NULL ) { lprintf( L_ERROR, "exit_usage: %s", msg ); fprintf( stderr, "%s: %s\n", program, msg ); } fprintf( stderr, "usage: %s [options] \n", program); fprintf( stderr, "\tvalid options: -p, -v, -l , -x , -n, -S, -r, -D \n"); lprintf( L_AUDIT, "failed: command line error" ); exit(1); } RETSIGTYPE fax_sig_goodbye _P1( (signo), int signo ) { if ( call_start == 0 ) call_start = time(NULL); lprintf( L_AUDIT, "failed: got signal %d, pid=%d, dev=%s, time=%ds, acct=\"%s\"", signo, getpid(), Device, ( time(NULL)-call_start ), c_string(acct_handle)); rmlocks(); exit(15); /* will close the fax device */ } int fax_open_device _P2( (fax_tty, use_stdin), char * fax_tty, boolean use_stdin ) { char device[MAXPATH]; int fd; if ( use_stdin ) /* fax modem on stdin */ { fd = 0; Device = ttyname(fd); /* for faxrec() */ if ( Device == NULL || *Device == '\0' ) Device = "unknown"; } else { int tries; /* ignore leading "/dev/" prefix */ if ( strncmp( fax_tty, "/dev/", 5 ) == 0 ) fax_tty += 5; if ( verbose ) printf( "Trying fax device '/dev/%s'... ", fax_tty ); tries = 0; while ( makelock( fax_tty ) != SUCCESS ) { if ( ++ tries < 3 ) { if ( verbose ) { printf( "locked... " ); fflush( stdout ); } sleep(5); } else { if ( verbose ) { printf( "locked, give up!\n" ); fflush( stdout ); } lprintf( L_MESG, "cannot lock %s", fax_tty ); return -1; } } sprintf( device, "/dev/%s", fax_tty ); if ( ( fd = open( device, O_RDWR | O_NDELAY ) ) == -1 ) { lprintf( L_ERROR, "error opening %s", device ); if ( verbose ) printf( "cannot open!\n" ); rmlocks(); return fd; } /* make device name externally visible (faxrec()) * we have to dup() it, because caller will change fax_tty */ Device = malloc( strlen(fax_tty)+1 ); if ( Device == NULL ) { perror( "sendfax: can't malloc" ); exit(2); } strcpy(Device, fax_tty); } /* unset O_NDELAY (otherwise waiting for characters */ /* would be "busy waiting", eating up all cpu) */ /* AIX has a special surprise for us: if a tcp/ip serial port is broken, * open() will succeed, but fcntl() will hang, and the fcntl() sysctl is * always restarted - so we MUST crash out from a signal handler :-( */ signal( SIGALRM, fax_sig_goodbye ); alarm(10); if ( fcntl( fd, F_SETFL, O_RDWR ) == -1 ) { lprintf( L_ERROR, "error in fcntl" ); close( fd ); if ( verbose ) printf( "cannot fcntl!\n" ); rmlocks(); return -1; } alarm(0); /* initialize baud rate, hardware handshake, ... */ tio_get( fd, &fax_tio ); /* even if we use a modem that requires Xon/Xoff flow control, * do *not* enable it here - it would interfere with the Xon * received at the top of a page. Worse, it would interfere with * received class 1 frames containing 0x11/0x13 characters... * --> individual page sending functions will turn on Xon/Xoff later */ tio_mode_sane( &fax_tio, TRUE ); tio_set_speed( &fax_tio, c_int(speed) ); tio_mode_raw( &fax_tio ); #ifdef sun /* sunos does not rx with RTSCTS unless carrier present */ tio_set_flow_control( fd, &fax_tio, FLOW_NONE ); #else tio_set_flow_control( fd, &fax_tio, (FAXSEND_FLOW) & FLOW_HARD ); #endif if ( tio_set( fd, &fax_tio ) == ERROR ) { lprintf( L_ERROR, "error in tio_set" ); close( fd ); if ( verbose ) printf( "cannot set termio values!\n" ); rmlocks(); return -1; } /* reset parameters */ fax_to_poll = FALSE; fax_remote_id[0] = 0; fax_param[0] = 0; if ( use_stdin ) { lprintf( L_NOISE, "fax_open_device, fax on stdin" ); } else { log_init_paths( NULL, NULL, &fax_tty[ strlen(fax_tty)-3 ] ); lprintf( L_NOISE, "fax_open_device succeeded, %s -> %d", fax_tty, fd ); } if ( verbose ) printf( "OK.\n" ); return fd; } /* fax_open: loop through all devices in fax_ttys until fax_open_device() * succeeds on one of them; then return file descriptor * return "-1" of no open succeeded (all locked, permission denied, ...) */ int fax_open _P2( (fax_ttys, use_stdin), char * fax_ttys, boolean use_stdin ) { char * p, * fax_tty; int fd; p = fax_tty = fax_ttys; do { p = strchr( fax_tty, ':' ); if ( p != NULL ) *p = 0; fd = fax_open_device( fax_tty, use_stdin ); if ( p != NULL ) *p = ':'; fax_tty = p+1; } while ( p != NULL && fd == -1 ); return fd; } /* finish off - close modem device, rm lockfile */ void fax_close _P1( (fd), int fd ) { tio_flush_queue( fd, TIO_Q_BOTH ); /* unlock flow ctl. */ fax_send( "AT+FCLASS=0", fd ); delay(500); tio_flush_queue( fd, TIO_Q_BOTH ); /* unlock flow ctl. */ close( fd ); rmlocks(); } /* sendfax-specific fax initializations */ /* polling: set calling station ID, receiver on, local poll on */ static int faxpoll_client_init _P2( (fd, cid), int fd, char * cid ) { char buf[60]; if ( modem_type == Mt_class2_0 ) { sprintf( buf, "AT+FPI=\"%.40s\"", cid ); if ( mdm_command( buf, fd ) == ERROR ) return ERROR; if ( mdm_command( "AT+FSP=1", fd ) == ERROR ) return ERROR; } else { sprintf( buf, "AT+FCIG=\"%.40s\"", cid ); if ( mdm_command( buf, fd ) == ERROR ) return ERROR; if ( mdm_command( "AT+FSPL=1", fd ) == ERROR ) return ERROR; } if ( mdm_command( "AT+FCR=1", fd ) == ERROR ) return ERROR; return NOERROR; } int main _P2( (argc, argv), int argc, char ** argv ) { int argidx; int fd; char buf[1000]; int i; int tries; /* number of unsuccessful tries */ int total_bytes = 0; /* number of bytes sent */ int total_pages = 0; /* number of pages (files) sent */ int total_resent= 0; /* number of pages resent */ /* initialize logging */ log_init_paths( argv[0], FAX_LOG, NULL ); /* parse switches (-> conf_sf.c) and read global config file */ if ( sendfax_parse_args( argc, argv ) == ERROR ) { exit_usage( argv[0], NULL ); } /* read config file (defaults) */ sendfax_get_config( NULL ); lprintf( L_MESG, "sendfax: %s", mgetty_version ); lprintf( L_NOISE, "%s compiled at %s, %s", __FILE__, __DATE__, __TIME__ ); /* for simplicity, put a few config things into global variables */ verbose = c_bool( verbose ); argidx = optind; /* fax number given? */ if ( argidx == argc ) { exit_usage( argv[0], "no fax number specified" ); } fac_tel_no = argv[ argidx++ ]; lprintf( L_MESG, "sending fax to %s", fac_tel_no ); /* check, if all the arguments passed are normal files and * readable */ for ( i=argidx; iphase B) */ else ppm = pp_eop; /* over & out (->hangup) */ } else /* not last page -> */ ppm = pp_mps; /* another page next */ fax_page_tx_status = -1; /* set by fax_send_page() */ if ( fax_send_page( argv[ argidx ], &total_bytes, &fax_tio, ppm, fd ) == ERROR ) { break; } /* after the page punctuation command, the modem * will send us a +FPTS: page transmit status. * The ppm value is written to fax_page_tx_status by * fax_send_page() / fax_send_ppm() * If the other side requests retransmission, do so. */ switch ( fax_page_tx_status ) { case 1: break; /* page good */ /* page bad - r. req. */ case 2: if ( c_int(max_tries) <= 0 ) /* ignore */ { fprintf( stderr, "WARNING: page bad (RTN), ignoring\n" ); lprintf( L_WARN, "WARNING: RTN ignored\n" ); } else /* try again */ { fprintf( stderr, "ERROR: RTN: page bad - retrain requested\n" ); tries ++; if ( tries >= c_int(max_tries) ) /* max tries reached */ { if ( c_bool(max_tries_ctd) ) /* go on */ { fprintf( stderr, "WARNING: maximum number of retries reached, going on\n" ); lprintf( L_WARN, "max. tries (%d) reached, going on", tries ); } else /* abort */ { fprintf( stderr, "ERROR: too many retries - aborting send\n" ); fax_hangup_code = -1; fax_hangup = 1; } } else { if ( verbose ) printf( "sending page again (retry %d)\n", tries ); total_resent++; continue; /* don't go to next page */ } } break; case 3: fprintf( stderr, "WARNING: RTP: page good, but retrain requested\n" ); break; case 4: case 5: fprintf( stderr, "WARNING: procedure interrupt requested - don't know how to handle it\n" ); break; case -1: /* something broke */ lprintf( L_WARN, "fpts:-1" ); break; default:fprintf( stderr, "WARNING: invalid code: +FPTS:%d\n", fax_page_tx_status ); break; } if ( fax_hangup && fax_hangup_code != 0 ) break; /* page transmitted successfully, rename file to ".done" */ if ( c_bool( rename_files ) ) { char done[MAXPATH+6]; if ( strlen( argv[argidx] ) > sizeof(done)-6 ) fprintf( stderr, "file name %s too long\n", argv[argidx] ); else { sprintf( done, "%s.done", argv[argidx] ); if ( rename( argv[argidx], done ) == -1 ) lprintf( L_ERROR, "can't rename work file to %s", done ); } } argidx++; /* next page */ tries=0; /* no tries yet */ } /* end main page loop */ if ( argidx < argc || ( fax_hangup && fax_hangup_code != 0 ) ) { lprintf( L_AUDIT, "failed transmitting %s: phone=\"%s\", +FHS:%02d, dev=%s, time=%ds, pages=%d/%d(+%d), bytes=%d, acct=\"%s\"", argv[argidx], fac_tel_no, fax_hangup_code, Device, ( time(NULL)-call_start ), total_pages-(argc-argidx)+1, total_pages, total_resent, total_bytes, c_string(acct_handle) ); fprintf( stderr, "\n%s: FAILED to transmit '%s'.\n", argv[0], argv[argidx] ); if ( fax_hangup_code == -1 ) fprintf( stderr, "(number of tries exhausted)\n" ); else fprintf( stderr, "Transmission error: +FHNG:%2d (%s)\n", fax_hangup_code, fax_strerror( fax_hangup_code ) ); fax_close( fd ); exit(12); } /* OK, handle (optional) fax polling now. * Fax polling will only be tried if user specified "-p" and the * faxmodem sent us a "+FPOLL" response */ if ( c_bool(fax_poll_wanted) ) { int pagenum = 0; if ( verbose ) printf( "starting fax poll\n" ); if ( ! fax_to_poll ) { printf( "remote does not have document to poll!\n" ); } else { /* class 2.0 modems use the correct byte order, Rockwell- * compatible class 2 modems get it wrong. */ if ( modem_type == Mt_class2_0 ) fax_set_bor( fd, 1 ); /* switch to fax receiver flow control */ tio_set_flow_control( fd, &fax_tio, (FAXREC_FLOW) & (FLOW_HARD|FLOW_XON_IN) ); tio_set( fd, &fax_tio ); if ( fax_get_pages( fd, &pagenum, c_string(poll_dir), -1, -1, -1 ) == ERROR ) { fprintf( stderr, "warning: polling failed\n" ); lprintf( L_AUDIT, "failed: polling failed, phone=\"%s\", +FHS:%02d, dev=%s, time=%ds, acct=\"%s\"", fac_tel_no, fax_hangup_code, Device, ( time(NULL)-call_start ), c_string(acct_handle) ); fax_close( fd ); exit(12); } } if ( verbose ) printf( "%d pages successfully polled!\n", pagenum ); } fax_close( fd ); lprintf( L_AUDIT, "success, phone=\"%s\", dev=%s, time=%ds, pages=%d(+%d), bytes=%d, acct=\"%s\"", fac_tel_no, Device, ( time(NULL)-call_start ), total_pages, total_resent, total_bytes, c_string(acct_handle) ); return 0; } mgetty-1.1.36/g3file.c0100600000031200001470000001737610506244546012736 0ustar gertfax#ident "$Id: g3file.c,v 1.2 2006/09/26 15:37:55 gert Exp $" /* g3file.c * * High-level functions to handle fax G3 I/O * - open disk file for reading (skipping digifax header) * - open disk file for writing (create "magic" header) * - transport G3 data from file to "out file descriptor" (file/device) * + optionally adding EOL padding (sending) * + optionally doing transcoding (1D/2D/...) (sending) [unimp] * - transport G3 data from "in file descriptor" to file * + optionally removing EOL padding (receiving) [unimp] * + checking receive copy quality [unimp] * * $Log: g3file.c,v $ * Revision 1.2 2006/09/26 15:37:55 gert * - on "device" file descriptors, check after each write() block whether there * is any sort of input data available - Xon/Xoff, modem errors, ... * - use sizeof(wbuf) to validate pad_bytes, not CHUNK * * Revision 1.1 2006/09/25 22:21:02 gert * G3 file handling functions, first draft (file->fd, bit padding) * * */ #include #include #include #include #include #include #include "mgetty.h" #include "fax_lib.h" #include "tio.h" #include "class1.h" static int g3_read_fd = -1; static uch g3_rf_buf[64]; static int g3_rf_idx = 0; /* read position in buffer */ static int g3_rf_num = 0; /* number of bytes in buffer */ static int g3_rf_fine = -1; /* resolution, -1 = unknown */ static uch bits_left[256]; /* 0-bits at left side of byte */ static uch bits_right[256]; /* 0-bits at right side of byte */ static int bits_lr_init = 0; /* build left/right bits table * (how many consecutive zero-bits on the left/right side of a byte?) */ void g3_init_lr_bittable _P0(void) { signed int i,j; if ( bits_lr_init ) return; bits_left[0] = bits_right[0] = 8; for( i=0; i<=7; i++ ) { for( j=(1<<(7-i))-1;j>=0; j--) { /* 0000 1 (jjj), 1-bit is at 1<<(7-i) */ bits_left[ (1<<(7-i)) + j ] = i; /* (jjj) 1 0000, 1-bit is at 1< skip */ if ( g3_rf_num >= 64 && strcmp( g3_rf_buf+1, "PC Research, Inc" ) == 0 ) { lprintf( L_MESG, "skipping over DigiFax header" ); g3_rf_idx = 64; /* for dfax files, remember resolution */ g3_rf_fine = ( g3_rf_buf[29] != 0 ); } return g3_read_fd; } /* close G3 file (if one is open), reset all static variables * called by g3_send_file(), g3_receive_file() at EOF or ERROR */ void g3_close _P0(void) { if (g3_read_fd < 0 ) return; close(g3_read_fd); g3_read_fd = -1; g3_rf_idx = 0; g3_rf_num = 0; g3_rf_fine = -1; } /* fill "buf" with new data from file, max size = max */ int g3_rf_chunk _P2((buf, max), char * buf, int max ) { int r, rp; rp = 0; /* stuff still left in buffer from open? */ if ( g3_rf_idx < g3_rf_num ) { r = g3_rf_num - g3_rf_idx; if ( r > max ) { r=max; } memcpy( buf, g3_rf_buf, g3_rf_num-g3_rf_idx ); g3_rf_idx += r; if ( r == max ) return r; rp = r; } /* all the arithmetics with "rp" is there to be able to * "look ahead" into the file in g3_open_read(), make sure the * system has the first bytes read (-> timing), but still read * CHUNK aligned reads on all further reads... * (we could do it with a larger static buffer, but that costs * memory all the time, not only when actively faxing) */ r = read( g3_read_fd, buf+rp, max-rp ); if ( r < 0 ) { lprintf( L_ERROR, "g3_read" ); } lprintf( L_JUNK, "rp=%d, r=%d", rp, r ); return r+rp; } /* send G3 file data to output file descriptor * in_func = function that will re-fill buffer * out_fd = output file descriptor, file or device * is_device = boolean, if true, check "out_fd" for modem responses * pad_bytes = pad each scan line to the given (min.) number of bytes * fax_res = normal/fine resolution (for warnings/format conversion) * [fax_comp = compression mode, for transcoding] */ int g3_send_file _P6(( in_func, out_fd, is_device, escape_dle, pad_bytes, fax_res ), in_func_t * in_func, int out_fd, int is_device, int escape_dle, int pad_bytes, int fax_res ) { #define CHUNK 1024 uch rbuf[CHUNK], wbuf[CHUNK+2]; int r, w, r_num; uch r_ch; int bytes_cur; /* bytes in current line (->padding) */ int have_0bits; /* 0-bits seen so far */ int lines_seen=-1; /* scan lines in file */ if ( g3_rf_fine != -1 && fax_res != g3_rf_fine ) { fprintf( stderr, "WARNING: sending in %s mode, fax data is %s mode\n", fax_res? "fine" : "normal", g3_rf_fine? "fine" : "normal" ); lprintf( L_WARN, "resolution mismatch" ); } /* we're going to be lazy further down, and always assume * "there is more space left in the buffer than we need padding", * so better make sure CHUNK is large enough */ if ( pad_bytes > sizeof(wbuf)/2 ) { errno=EINVAL; lprintf( L_ERROR, "g3_send_file: too much padding requested, pad_bytes=%d, CHUNK=%d", pad_bytes, CHUNK ); fprintf( stderr, "g3_send_file: internal error (pad_bytes)\n" ); return FAIL; } if ( pad_bytes < 0 ) pad_bytes = 0; /* be foolproof */ r_num = in_func( rbuf, sizeof(rbuf) ); r=0; w=0; bytes_cur=pad_bytes; /* never! pad first EOL */ have_0bits=0; do { r_ch = (uch)rbuf[r++]; bytes_cur++; /* do we have EOL? (11 consecutive 0-bits) */ #ifdef DEBUG_G3FILE fprintf( stderr, "h0b=%2d, r_ch=%03o -> l=%d, r=%d\n", have_0bits, r_ch, bits_left[r_ch], bits_right[r_ch] ); #endif if ( r_ch == 0 ) { have_0bits += 8; } else { if ( have_0bits + bits_left[r_ch] >= 11 ) { int need = (bytes_cur0 ) { wbuf[w++] = 0; need--; } bytes_cur=0; lines_seen++; } have_0bits = bits_right[r_ch]; } wbuf[w] = fax_send_swaptable[ r_ch ]; if ( escape_dle && wbuf[w] == DLE ) wbuf[++w] = DLE; w++; if ( r >= r_num ) /* buffer empty, read more */ { r_num = in_func( rbuf, sizeof(rbuf) ); if ( r_num < 0 ) { break; } r = 0; } if ( ( w >= (sizeof(wbuf)-2 - pad_bytes ) ) || /* write buffer full */ (r_num == 0) ) /* or end of input */ { if ( w != write( out_fd, wbuf, w ) ) { lprintf( L_ERROR, "fax1_send_page: can't write %d bytes", w ); break; } lprintf( L_JUNK, "write %d", w ); w=0; /* if this is going to a serial device, check for pending input * (stray Xon/Xoff from flow control, modem errors, ...) */ if ( is_device && check_for_input( out_fd ) ) { lprintf( L_NOISE, "input: got " ); do { /* intentionally don't use mdm_read_byte here */ if ( read( out_fd, &r_ch, 1 ) != 1 ) { lprintf( L_ERROR, "read failed" ); break; } else lputc( L_NOISE, r_ch ); } while ( check_for_input( out_fd ) ); } } /* end if (need to write buffer) */ } while(r_num>0); g3_close(); lprintf( L_NOISE, "end of page, %d lines sent", lines_seen ); /*!!! ERROR HANDLING!! */ /*!!! PARANOIA: alarm()!! */ return SUCCESS; } mgetty-1.1.36/io.c0100644000031200000620000001064606355273371012554 0ustar gertgroup#ident "$Id: io.c,v 4.2 1997/06/28 20:41:29 gert Exp $ Copyright (c) Gert Doering" /* io.c * * This module contains a few low-level I/O functions * (will be extended) */ #include #include #include "syslibs.h" #include #include #include "mgetty.h" /* warning: these includes have to appear *after* "mgetty.h"! */ #ifdef USE_POLL # include # ifndef _AIX int poll _PROTO(( struct pollfd fds[], unsigned long nfds, int timeout )); # endif /* AIX */ #endif /* USE_POLL */ /* SCO Unix defines XENIX as well, which will confuse the code below */ #if defined(M_XENIX) && defined(M_UNIX) # undef M_XENIX #endif #ifdef USE_SELECT # include # if defined (linux) || defined (sunos4) || defined (SVR4) || \ defined (__hpux) || defined (MEIBE) || defined(sgi) || \ defined (ISC) || defined (BSD) || defined(sysV68) || \ defined(m88k) || defined(M_XENIX) # include # include # ifdef ISC # include # endif /* ISC */ # ifdef M_XENIX # include # endif # else /* not sys/types.h + sys/time.h */ # include # endif # ifdef NEED_BZERO # define bzero( ptr, length ) memset( ptr, 0, length ) # endif #endif /* USE_SELECT */ void delay _P1( (waittime), int waittime ) /* wait waittime milliseconds */ { #ifdef USE_USLEEP usleep( waittime * 1000 ); #else #ifdef USE_POLL struct pollfd sdummy; poll( &sdummy, 0, waittime ); #else #ifdef USE_NAP nap( (long) waittime ); #else #ifdef USE_SELECT struct timeval s; s.tv_sec = waittime / 1000; s.tv_usec = (waittime % 1000) * 1000; select( 0, (fd_set *) NULL, (fd_set *) NULL, (fd_set *) NULL, &s ); #else /* neither poll nor nap nor select available */ if ( waittime < 2000 ) waittime = 2000; /* round up */ sleep( waittime / 1000); /* a sleep of 1 may not sleep at all */ #endif /* use select */ #endif /* use nap */ #endif /* use poll */ #endif /* use usleep */ } /* check_for_input( open file deskriptor ) * * returns TRUE if there's something to read on filedes, FALSE otherwise */ boolean check_for_input _P1( (filedes), int filedes ) { #ifdef USE_SELECT fd_set readfds; struct timeval timeout; #endif #ifdef USE_POLL struct pollfd fds; #endif int ret; #ifdef USE_SELECT FD_ZERO( &readfds ); FD_SET( filedes, &readfds ); timeout.tv_sec = timeout.tv_usec = 0; ret = select( FD_SETSIZE , &readfds, NULL, NULL, &timeout ); #else # ifdef USE_POLL fds.fd = filedes; fds.events = POLLIN; fds.revents= 0; ret = poll( &fds, 1, 0 ); # else ret = 0; /* CHEAT! */ # endif #endif if ( ret < 0 ) lprintf( L_ERROR, "poll / select failed" ); return ( ret > 0 ); } #if !defined( USE_SELECT) && !defined( USE_POLL ) static RETSIGTYPE wfi_timeout(SIG_HDLR_ARGS) {} #endif /* wait until a character is available * where select() or poll() exists, no characters will be read, * if only read() can be used, at least one character will be dropped * * return TRUE if data is found, FALSE if "msecs" milliseconds have passed */ boolean wait_for_input _P2( (fd, msecs), int fd, int msecs ) { #ifdef USE_SELECT fd_set readfds; struct timeval timeout, *tptr; #endif #ifdef USE_POLL struct pollfd fds; int timeout; #endif int slct; #ifdef USE_SELECT FD_ZERO( &readfds ); FD_SET( fd, &readfds ); if ( msecs >= 0 ) { timeout.tv_sec = msecs / 1000; timeout.tv_usec = (msecs % 1000) * 1000; /* microsecs! */ tptr = &timeout; } else tptr = NULL; slct = select( FD_SETSIZE, &readfds, NULL, NULL, tptr ); lprintf( L_JUNK, "select returned %d", slct ); #else /* use poll */ # ifdef USE_POLL if ( msecs < 0 ) timeout = -1; else timeout = msecs; fds.fd = fd; fds.events = POLLIN; fds.revents= 0; slct = poll( &fds, 1, timeout ); lprintf( L_JUNK, "poll returned %d", slct ); # else { char t; int oerrno; if ( msecs > 0 ) { signal( SIGALRM, wfi_timeout ); alarm( (msecs+999)/1000 ); } slct = read( fd, &t, 1 ); oerrno = errno; alarm(0); signal( SIGALRM, SIG_DFL ); errno = oerrno; if ( slct < 0 ) { if ( errno == EINTR ) lprintf( L_JUNK, "read: timeout" ); else lprintf( L_ERROR, "read: error" ); } else { lprintf(L_JUNK, "read returned: "); lputc(L_JUNK, t ); } } # endif #endif return ( slct>0 ); } mgetty-1.1.36/tio.c0100600000031200001470000006102510506054350012336 0ustar gertfax#ident "@(#)$Id: tio.c,v 4.9 2006/06/14 09:49:24 gert Exp $ Copyright (c) 1993 Gert Doering" /* tio.c * * contains routines dealing with SysV termio / POSIX termios / BSD sgtty * */ #include #include #include #ifdef NeXT #include #endif #include "mgetty.h" #include "tio.h" #ifdef POSIX_TERMIOS # ident "@(#)tio.c compiled with POSIX_TERMIOS" #endif #ifdef SYSV_TERMIO # ident "@(#)tio.c compiled with SYSV_TERMIO" #endif #ifdef BSD_SGTTY # ident "@(#)tio.c compiled with BSD_SGTTY" #endif #ifdef USE_TERMIOX # include #endif #if defined( M_UNIX ) && defined( MAM_BUG ) #include #endif #ifdef sysV68 #include #include #include #include #include #endif /* some systems do not define all flags needed later, e.g. NetBSD */ #if defined(BSD) || defined(__FreeBSD_kernel__) # ifndef IUCLC # define IUCLC 0 # endif # ifndef TAB3 # ifdef NeXT # define TAB3 XTABS # else # define TAB3 OXTABS # endif /* !NeXT */ # endif #endif /* baud rate table */ static struct speedtab { #ifdef POSIX_TERMIOS speed_t cbaud; #else unsigned short cbaud; /* baud rate, e.g. B9600 */ #endif int nspeed; /* speed in numeric format */ char *speed; /* speed in display format */ } speedtab[] = { { B50, 50, "50" }, { B75, 75, "75" }, { B110, 110, "110" }, { B134, 134, "134" }, { B150, 150, "150" }, { B200, 200, "200" }, { B300, 300, "300" }, { B600, 600, "600" }, #ifdef B900 { B900, 900, "900" }, #endif { B1200, 1200, "1200" }, { B1800, 1800, "1800" }, { B2400, 2400, "2400" }, #ifdef B3600 { B3600, 3600, "3600" }, #endif { B4800, 4800, "4800" }, #ifdef B7200 { B7200, 7200, "7200" }, #endif { B9600, 9600, "9600" }, #ifdef B14400 { B14400, 14400, "14400" }, #endif #ifdef B19200 { B19200, 19200, "19200" }, #endif /* B19200 */ #ifdef B28800 { B28800, 28800, "28800" }, #endif #ifdef B38400 { B38400, 38400, "38400" }, #endif /* B38400 */ #ifdef EXTA { EXTA, 19200, "EXTA" }, #endif #ifdef EXTB { EXTB, 38400, "EXTB" }, #endif #ifdef B57600 { B57600, 57600, "57600" }, #endif #ifdef B76800 { B76800, 76800, "76800" }, #endif #ifdef B115200 { B115200,115200,"115200"}, #endif #ifdef B230400 { B230400,230400,"230400"}, #endif #ifdef B460800 { B460800,460800,"460800"}, #endif { 0, 0, "" } }; /* get current tio settings for given filedescriptor */ int tio_get _P2((fd, t), int fd, TIO *t ) { #ifdef SYSV_TERMIO if ( ioctl( fd, TCGETA, t ) < 0 ) { lprintf( L_ERROR, "TCGETA failed" ); return ERROR; } #endif #ifdef POSIX_TERMIOS if ( tcgetattr( fd, t ) < 0 ) { lprintf( L_ERROR, "tcgetattr failed" ); return ERROR; } #endif #ifdef BSD_SGTTY if ( gtty( fd, t ) < 0 ) { lprintf( L_ERROR, "gtty failed" ); return ERROR; } #endif return NOERROR; } int tio_set _P2( (fd, t), int fd, TIO * t) /*!! FIXME: flags, wait */ { #ifdef sunos4 int modem_lines; #endif #ifdef SYSV_TERMIO if ( ioctl( fd, TCSETA, t ) < 0 ) { lprintf( L_ERROR, "ioctl TCSETA failed" ); return ERROR; } #endif #ifdef POSIX_TERMIOS if ( tcsetattr( fd, TCSANOW, t ) < 0 ) { lprintf( L_ERROR, "tcsetattr failed" ); return ERROR; } #ifdef sunos4 /* On SunOS, make sure that RTS and DTR are asserted if you wanna * use hardware flow control */ if (t->c_cflag & CRTSCTS) { /* make sure RTS is asserted!!!!!! */ ioctl(fd, TIOCMGET, &modem_lines); modem_lines |= (TIOCM_RTS | TIOCM_DTR); ioctl(fd, TIOCMSET, &modem_lines); } #endif /* sunos4 */ #endif /* posix_termios */ #ifdef BSD_SGTTY if ( stty( fd, t ) < 0 ) { lprintf( L_ERROR, "stty failed" ); return ERROR; } #endif return NOERROR; } /* check whether a given speed (integer) is valid for the given system */ int tio_check_speed _P1( (speed), int speed ) { int i; for ( i=0; speedtab[i].cbaud != 0; i++ ) { if ( speedtab[i].nspeed == speed ) { return speedtab[i].cbaud; } } lprintf( L_NOISE, "speed %d not found in table", speed ); errno=EINVAL; return -1; } /* set speed, do not touch the other flags * "speed" is given as numeric baud rate, not as Bxxx constant */ int tio_set_speed _P2( (t, speed ), TIO *t, unsigned int speed ) { int i, symspeed=0; for ( i=0; speedtab[i].cbaud != 0; i++ ) { if ( speedtab[i].nspeed == speed ) { symspeed = speedtab[i].cbaud; break; } } if ( symspeed == 0 ) { errno=EINVAL; lprintf( L_ERROR, "tss: unknown/unsupported bit rate: %d", speed ); return ERROR; } lprintf( L_NOISE, "tss: set speed to %d (%03o)", speed, symspeed ); #ifdef SYSV_TERMIO t->c_cflag = ( t->c_cflag & ~CBAUD) | symspeed; #endif #ifdef POSIX_TERMIOS cfsetospeed( t, symspeed ); cfsetispeed( t, symspeed ); #endif #ifdef BSD_SGTTY t->sg_ispeed = t->sg_ospeed = symspeed; #endif return NOERROR; } /* get port speed. Return integer value, not symbolic constant */ int tio_get_speed _P1( (t), TIO *t ) { #ifdef SYSV_TERMIO ushort cbaud = t->c_cflag & CBAUD; #endif #ifdef POSIX_TERMIOS speed_t cbaud = cfgetospeed( t ); #endif #ifdef BSD_SGTTY int cbaud = t->sg_ospeed; #endif struct speedtab * p; for ( p=speedtab; p->nspeed != 0; p++ ) { if ( p->cbaud == cbaud ) break; } return p->nspeed; } /* set "raw" mode: do not process input or output, do not buffer */ /* do not touch cflags or xon/xoff flow control flags */ void tio_mode_raw _P1( (t), TIO * t ) { #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS) t->c_iflag &= ( IXON | IXOFF | IXANY ); /* clear all flags except */ /* xon / xoff handshake */ t->c_oflag = 0; /* no output processing */ t->c_lflag = 0; /* no signals, no echo */ t->c_cc[VMIN] = 1; /* disable line buffering */ t->c_cc[VTIME] = 0; #else t->sg_flags = RAW; #endif } /* "cbreak" mode - do not process input in lines, but process ctrl * characters, echo characters back, ... * warning: must be based on raw / sane mode */ void tio_mode_cbreak _P1( (t), TIO * t ) { #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) t->c_oflag = 0; t->c_iflag &= ~( IGNCR | ICRNL | INLCR | IUCLC ); t->c_lflag &= ~( ICANON | ISIG ); t->c_cc[VMIN] = 1; t->c_cc[VTIME]= 0; #else t->sg_flags |= CBREAK; #endif } /* set "sane" mode, usable for login, ... * unlike the other tio_mode_* functions, this function initializes * all flags, and should be called before calling any other function */ void tio_mode_sane _P2( (t, local), TIO * t, int local ) { #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS ) t->c_iflag = BRKINT | IGNPAR | IXON | IXANY; t->c_oflag = OPOST | TAB3; /* be careful, only touch "known" flags */ t->c_cflag&= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); t->c_cflag|= CS8 | CREAD | HUPCL | ( local? CLOCAL:0 ); t->c_lflag = ECHOK | ECHOE | ECHO | ISIG | ICANON; #if !defined(POSIX_TERMIOS) t->c_line = 0; #endif /* initialize the most important c_cc's here */ t->c_cc[VEOF] = 0x04; #if defined(VEOL) && VEOL < TIONCC t->c_cc[VEOL] = 0; #endif #ifdef VSWTCH t->c_cc[VSWTCH] = 0; #endif #else /* BSD_SGTTY */ t->sg_flags = ECHO | EVENP | ODDP; /* t->sg_flags = ECHO; */ t->sg_erase = 0x7f; /* erase character */ t->sg_kill = 0x25; /* kill character, ^u */ #endif } /* tio_default_cc( TIO ) * * initialize all c_cc fields (for POSIX and SYSV) to proper start * values (normally, the serial driver should do this, but there are * numerous systems where some of the more esoteric (VDSUSP...) flags * are plain wrong (e.g. set to "m" or so) * * do /not/ initialize VERASE and VINTR, since some systems use * ^H / DEL here, others DEL / ^C. */ void tio_default_cc _P1( (t), TIO *t ) { #ifdef BSD_SGTTY t->sg_erase = 0x7f; /* erase character */ t->sg_kill = 0x25; /* kill character, ^u */ #else /* posix or sysv */ t->c_cc[VQUIT] = CQUIT; t->c_cc[VKILL] = CKILL; t->c_cc[VEOF] = CEOF; #if defined(VEOL) && VEOL < TIONCC t->c_cc[VEOL] = CEOL; #endif #if defined(VSTART) && VSTART < TIONCC t->c_cc[VSTART] = CSTART; #endif #if defined(VSTOP) && VSTOP < TIONCC t->c_cc[VSTOP] = CSTOP; #endif #if defined(VSUSP) && VSUSP < TIONCC t->c_cc[VSUSP] = CSUSP; #endif #if defined(VSWTCH) && VSWTCH < TIONCC t->c_cc[VSWTCH] = CSWTCH; #endif /* the following are for SVR4.2 (and higher) */ #if defined(VDSUSP) && VDSUSP < TIONCC t->c_cc[VDSUSP] = CDSUSP; #endif #if defined(VREPRINT) && VREPRINT < TIONCC t->c_cc[VREPRINT] = CRPRNT; #endif #if defined(VDISCARD) && VDISCARD < TIONCC t->c_cc[VDISCARD] = CFLUSH; #endif #if defined(VWERASE) && VWERASE < TIONCC t->c_cc[VWERASE] = CWERASE; #endif #if defined(VLNEXT) && VLNEXT < TIONCC t->c_cc[VLNEXT] = CLNEXT; #endif #endif /* bsd <-> posix + sysv */ } void tio_map_cr _P2( (t, perform_mapping), TIO * t, int perform_mapping ) { #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) if ( perform_mapping ) { t->c_iflag |= ICRNL; t->c_oflag |= ONLCR; } else { t->c_iflag &= ~ICRNL; t->c_oflag &= ~ONLCR; } #else /* BSD_SGTTY (tested only on NeXT yet, but should work) */ if ( perform_mapping ) { t->sg_flags |= CRMOD ; } else { t->sg_flags &= ~CRMOD ; } #endif } /* enable uppercase <-> lowercase mapping */ void tio_map_uclc _P2( (t, perform_mapping), TIO * t, int perform_mapping ) { #if defined(__bsdi__) || !defined(OLCUC) || !defined(XCASE) lprintf( L_WARN, "uclc mapping not available" ); #else # if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) if ( perform_mapping ) { t->c_iflag |= IUCLC; t->c_oflag |= OLCUC; t->c_lflag |= XCASE; } else { t->c_iflag &= ~IUCLC; t->c_oflag &= ~OLCUC; t->c_lflag &= ~XCASE; } # else /* BSD_SGTTY */ # include "not implemented yet" # endif #endif /* BSDI */ } /* tio_carrier() * specify whether the port should be carrier-sensitive or not */ void tio_carrier _P2( (t, carrier_sensitive), TIO *t, int carrier_sensitive ) { #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) if ( carrier_sensitive ) { t->c_cflag &= ~CLOCAL; } else { t->c_cflag |= CLOCAL; } #else /* BSD_SGTTY (tested only on NeXT yet, but should work) */ if ( carrier_sensitive ) { t->sg_flags &= ~LNOHANG ; } else { t->sg_flags |= LNOHANG ; } #endif } /* set handshake */ /* hardware handshake flags - use what is available on local system */ #ifdef CRTSCTS # define HARDWARE_HANDSHAKE CRTSCTS /* linux, SunOS */ #else # ifdef CRTSFL # define HARDWARE_HANDSHAKE CRTSFL /* SCO 3.2v4.2 */ # else # ifdef RTSFLOW # define HARDWARE_HANDSHAKE RTSFLOW | CTSFLOW /* SCO 3.2v2 */ # else # ifdef CTSCD # define HARDWARE_HANDSHAKE CTSCD /* AT&T 3b1? */ # else # define HARDWARE_HANDSHAKE 0 /* nothing there... */ # endif # endif # endif #endif /* Dial-Out parallel to a Dial-in on SCO 3.2v4.0 does only work if * *only* CTSFLOW is set (Uwe S. Fuerst) */ #ifdef BROKEN_SCO_324 # undef HARDWARE_HANDSHAKE # define HARDWARE_HANDSHAKE CTSFLOW #endif /* tio_set_flow_control * * set flow control according to the parameter. It can be any * combination of * FLOW_XON_IN - use Xon/Xoff on incoming data * FLOW_XON_OUT- respect Xon/Xoff on outgoing data * FLOW_HARD - use RTS/respect CTS line for hardware handshake * (not every combination will work on every system) * * WARNING: for most systems, this function will not touch the tty * settings, only modify the TIO structure. On some systems, * you have to use extra ioctl()s [notably SVR4, sysV68, and * AIX] to modify hardware flow control settings. On those * systems, these calls are done immediately. */ int tio_set_flow_control _P3( (fd, t, type), int fd, TIO * t, int type ) { #ifdef USE_TERMIOX struct termiox tix; #endif lprintf( L_NOISE, "tio_set_flow_control(%s%s%s )", type & FLOW_HARD ? " HARD": "", type & FLOW_XON_IN ? " XON_IN": "", type & FLOW_XON_OUT? " XON_OUT": "" ); #if defined( SYSV_TERMIO ) || defined( POSIX_TERMIOS ) t->c_cflag &= ~HARDWARE_HANDSHAKE; t->c_iflag &= ~( IXON | IXOFF | IXANY ); if ( type & FLOW_HARD ) t->c_cflag |= HARDWARE_HANDSHAKE; if ( type & FLOW_XON_IN ) t->c_iflag |= IXOFF; /* for login, we want IXON|IXANY, for voice, we must not set IXANY! */ if ( type & FLOW_XON_OUT ) { t->c_iflag |= IXON; if ( type & FLOW_XON_IXANY ) t->c_iflag |= IXANY; } #else # ifdef NEXTSGTTY lprintf( L_WARN, "tio_set_flow_control: not yet implemented" ); # else # include "not yet implemented" # endif #endif /* SVR4 came up with a new method of setting h/w flow control */ #ifdef USE_TERMIOX lprintf( L_NOISE, "tio_set_flow_control: using termiox" ); if (ioctl(fd, TCGETX, &tix) < 0) { lprintf( L_ERROR, "ioctl TCGETX" ); return ERROR; } if ( type & FLOW_HARD ) tix.x_hflag |= (RTSXOFF | CTSXON); else tix.x_hflag &= ~(RTSXOFF | CTSXON); if ( ioctl(fd, TCSETX, &tix) < 0 ) { lprintf( L_ERROR, "ioctl TCSETX" ); return ERROR; } #endif /* AIX has yet another method to set hardware flow control * interesting enough, in AIX 4, this ioctl still exists but doesn't * work anymore -- instead, they have adopted termiox. *bah* */ #if defined(_AIX) && !defined(USE_TERMIOX) lprintf( L_NOISE, "tio_set_flow_control: using TXADDCD" ); if ( ioctl( fd, ( type & FLOW_HARD ) ? TXADDCD : TXDELCD, "rts" ) < 0 ) { lprintf( L_NOISE, "ioctl TXADDCD/TXDELCD failed, errno=%d", errno); return ERROR; } #ifdef DEBUG { union txname t; int i; lprintf( L_NOISE, "control disciplines:"); for ( i=1; ; i++ ) { t.tx_which = i; if ( ioctl( fd, TXGETCD, &t ) ) { lprintf( L_FATAL, "TXGETCD error" ); break; } if ( t.tx_name == NULL || !t.tx_name[0] ) break; lputc( L_NOISE, ' '); lputs( L_NOISE, t.tx_name ); } } #endif /* DEBUG */ #endif /* _AIX */ /* * sysV68 uses special ioctls, too. The following code should work for * mvme332xt controllers. The mvme337 driver supports the same ioctls * but has not been tested. Others may not support hardware flow * control at all. Refer to the corresponding mvmeXXX(7) manpage for * details. */ #ifdef sysV68 lprintf( L_NOISE, "tio_set_flow_control: using TCSETHW" ); if ( type & FLOW_HARD ) { if ( ioctl(fd, TCSETHW, 1) < 0 ) { lprintf( L_ERROR, "ioctl TCSETHW on failed" ); return ERROR; } } else { if ( ioctl(fd, TCSETHW, 0) < 0 ) { /* We use a lower logging priority if errno is EINVAL, so * mgetty can be used on devices which do not support the * special m332xt ioctls without filling syslog with * unnecessary error messages. */ if (EINVAL == errno) { lprintf( L_NOISE, "ioctl TCSETHW off failed" ); } else { lprintf( L_ERROR, "ioctl TCSETHW off failed" ); return ERROR; } } } #endif /* sysV68 */ return NOERROR; } /* for convenience - do not have to get termio settings before, but * it's slower (two system calls more) */ int tio_set_flow_control2 _P2( (fd, type), int fd, int type ) { TIO t; if ( tio_get( fd, &t ) == ERROR ) return ERROR; tio_set_flow_control( fd, &t, type ); return tio_set( fd, &t ); } int tio_toggle_dtr _P2( (fd, msec_wait), int fd, int msec_wait ) { /* On SVR4.2, lowering DTR by setting the port speed to zero will * bring the port to some strange state where every ioctl() later * on simply fails - so use special "modem control" ioctl()s to * lower and raise DTR * Strange enough, on *some* platforms, you have to pass the mctl * flag word by value, on others by reference. Oh world... */ #if defined(TIOCMBIS) && \ ( defined(sun) || defined(SVR4) || defined(NeXT) || defined(linux) ) int mctl = TIOCM_DTR; #if !defined( TIOCM_VALUE ) if ( ioctl( fd, TIOCMBIC, &mctl ) < 0 ) #else if ( ioctl( fd, TIOCMBIC, (char *) mctl ) < 0 ) #endif { lprintf( L_ERROR, "TIOCMBIC failed" ); return ERROR; } delay( msec_wait ); #if !defined( TIOCM_VALUE) if ( ioctl( fd, TIOCMBIS, &mctl ) < 0 ) #else if ( ioctl( fd, TIOCMBIS, (char *) mctl ) < 0 ) #endif { lprintf( L_ERROR, "TIOCMBIS failed" ); return ERROR; } return NOERROR; #else /* !TIOCMBI* */ /* On HP/UX, lowering DTR by setting the port speed to B0 will * leave it there. So, do it via HP/UX's special ioctl()'s... */ #if defined(_HPUX_SOURCE) || defined(MCGETA) unsigned long mflag = 0L; if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) { lprintf( L_ERROR, "MCSETAF failed" ); return ERROR; } delay( msec_wait ); if ( ioctl( fd, MCGETA, &mflag ) < 0 ) { lprintf( L_ERROR, "MCGETA failed" ); return ERROR; } mflag = MRTS | MDTR; if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) { lprintf( L_ERROR, "MCSETAF failed" ); return ERROR; } return NOERROR; #else /* !MCGETA */ /* The "standard" way of doing things - via speed = B0 */ TIO t, save_t; #ifdef sunos4 int modem_lines; #endif int result; if ( tio_get( fd, &t ) == ERROR ) return ERROR; save_t = t; #ifdef SYSV_TERMIO t.c_cflag = ( t.c_cflag & ~CBAUD ) | B0; /* speed = 0 */ #endif #ifdef POSIX_TERMIOS cfsetospeed( &t, B0 ); cfsetispeed( &t, B0 ); #endif #ifdef BSD_SGTTY t.sg_ispeed = t.sg_ospeed = B0 #endif tio_set( fd, &t ); delay( msec_wait ); #ifdef sunos4 /* on SunOS, if you hangup via B0, the DTR line will *stay* low. * So: enable it manually again. */ ioctl(fd, TIOCMGET, &modem_lines); modem_lines |= (TIOCM_RTS | TIOCM_DTR); ioctl(fd, TIOCMSET, &modem_lines); #endif result = tio_set( fd, &save_t ); #if (defined(M_UNIX) && defined(MAM_BUG)) || defined (sysV68) /* some Unix variants apparently forget to raise DTR again * after lowering it. Reopening the port fixes it. Crude, but works. */ close( open( "/dev/tty", O_RDONLY | O_NDELAY ) ); #endif return result; #endif /* !MCSETA */ #endif /* !SVR4 */ } /* flush input or output data queue * * "queue" is one of the TIO_Q* values from tio.h */ int tio_flush_queue _P2( (fd, queue), int fd, int queue ) { int r = NOERROR; #ifdef POSIX_TERMIOS switch( queue ) { case TIO_Q_IN: r = tcflush( fd, TCIFLUSH ); break; case TIO_Q_OUT: r = tcflush( fd, TCOFLUSH ); break; case TIO_Q_BOTH: r = tcflush( fd, TCIOFLUSH );break; default: lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); return ERROR; } #endif #ifdef SYSV_TERMIO switch ( queue ) { case TIO_Q_IN: r = ioctl( fd, TCFLSH, 0 ); break; case TIO_Q_OUT: r = ioctl( fd, TCFLSH, 1 ); break; case TIO_Q_BOTH: r = ioctl( fd, TCFLSH, 2 ); break; default: lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); return ERROR; } #endif #ifdef BSD_SGTTY int arg; switch ( queue ) { case TIO_Q_IN: arg = FREAD; break; case TIO_Q_OUT: arg = FWRITE; break; case TIO_Q_BOTH: arg = FREAD | FWRITE; break; default: lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); return ERROR; } r = ioctl( fd, TIOCFLUSH, (char *) &arg ); #endif if ( r != 0 ) lprintf( L_ERROR, "tio: cannot flush queue" ); return r; } /* control flow control: if "restart_output" is TRUE, stopped tty output is * resumed, if it is FALSE, the output is stopped * * I'm fairly sure it won't work on all supported systems... */ int tio_flow _P2( (fd, restart_output), int fd, int restart_output ) { int r; #ifdef POSIX_TERMIOS if ( restart_output ) r = tcflow( fd, TCOON ); else r = tcflow( fd, TCOOFF ); #endif #ifdef SYSV_TERMIO if ( restart_output ) r = ioctl( fd, TCXONC, 1 ); else r = ioctl( fd, TCXONC, 0 ); #endif #ifdef BSD_SGTTY if ( restart_output ) r = ioctl( fd, TIOCSTART, NULL ); else r = ioctl( fd, TIOCSTOP, NULL ); #endif if ( r != 0 ) lprintf( L_ERROR, "tio: cannot change flow ctrl state" ); return r; } /* tio_drain(fd): wait for output queue to drain */ int tio_drain_output _P1( (fd), int fd ) { #ifdef POSIX_TERMIOS if ( tcdrain( fd ) == ERROR ) { lprintf( L_ERROR, "tio_drain: tcdrain" ); return ERROR; } #else # ifdef SYSV_TERMIO if ( ioctl( fd, TCSBRK, 1 ) == ERROR ) { lprintf( L_ERROR, "tio_drain: TCSBRK/1" ); return ERROR; } # else /* no way to wait for data to drain with BSD_SGTTY */ lprintf( L_WARN, "tio_drain: expect spurious failures" ); # endif #endif return NOERROR; } /* send a BREAK signal to the tty * * kernel break via tcsendbreak() or ioctl(TCSENDBRK) lasts at least * 0.25 seconds. We can speed up this by switching baud rate to 1/4, * and then sending a 0-byte (activated #ifdef FAST_BREAK). * * on some systems (don't we love it all?) the "real" break functions * don't work, so we must use FAST_BREAK. */ int tio_break _P1((fd), int fd) { /* SunOS4 doesn't seem to like "tcsendbreak" (noop), so send a "long zero" */ #if defined(sunos4) || defined(M_UNIX) || defined(FAST_BREAK) TIO tio, tio_save; int speed; char null = 0; lprintf( L_NOISE, "sending FAST break" ); if ( tio_get( fd, &tio ) == ERROR ) { lprintf( L_ERROR, "tio_break: can't get tio" ); return ERROR; } tio_save = tio; if ( (speed = tio_get_speed( &tio ) ) < 150 || tio_set_speed( &tio, speed/4 ) == ERROR || tio_set( fd, &tio ) == ERROR ) { lprintf( L_ERROR, "tio_break: can't set 1/4 speed" ); return ERROR; } if ( write( fd, &null, 1 ) != 1 ) { lprintf( L_ERROR, "tio_break: can't write 0-byte" ); return ERROR; } /* before we switch baud rates back, make sure zero byte has been sent! */ if ( tio_drain_output( fd ) == ERROR ) return ERROR; if ( tio_set( fd, &tio_save ) == ERROR ) { lprintf( L_ERROR, "tio_break: can't reset old TIO state" ); return ERROR; } #else /* !FAST_BREAK -> use standard functions */ lprintf( L_NOISE, "sending system call break" ); #ifdef POSIX_TERMIOS if ( tcsendbreak( fd, 0 ) < 0 ) { lprintf( L_ERROR, "tcsendbreak() failed" ); return ERROR; } #endif #ifdef SYSV_TERMIO if ( ioctl( fd, TCSBRK, 0 ) < 0 ) { lprintf( L_ERROR, "ioctl( TCSBRK ) failed" ); return ERROR; } #endif #ifdef BSD_SGTTY if ( ioctl( fd, TIOCSBRK, 0 ) < 0 ) { lprintf( L_ERROR, "ioctl( TIOCSBRK ) failed" ); return ERROR; } delay( 250 ); if ( ioctl( fd, TIOCCBRK, 0 ) < 0 ) { lprintf( L_ERROR, "ioctl( TIOCCBRK ) failed" ); return ERROR; } #endif #endif /* FAST_BREAK */ return NOERROR; } /* tio_get_rs232_lines() * * get the status of all RS232 status lines * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_* * flags, we use them, on others we may have to do some other tricks) * * "-1" can mean "error" or "not supported on this system" (e.g. SCO). */ int tio_get_rs232_lines _P1( (fd), int fd) { int flags; #ifdef TIO_F_SYSTEM_DEFS if ( ioctl(fd, TIOCMGET, &flags ) < 0 ) lprintf( L_ERROR, "tio_get_rs232_lines: TIOCMGET failed" ); #else /* !TIO_F_SYSTEM_DEFS */ flags=-1; #endif if ( flags != -1 ) { lprintf( L_NOISE, "tio_get_rs232_lines: status:" ); if ( flags & TIO_F_RTS ) lputs( L_NOISE, " RTS" ); if ( flags & TIO_F_CTS ) lputs( L_NOISE, " CTS" ); if ( flags & TIO_F_DSR ) lputs( L_NOISE, " DSR" ); if ( flags & TIO_F_DTR ) lputs( L_NOISE, " DTR" ); if ( flags & TIO_F_DCD ) lputs( L_NOISE, " DCD" ); if ( flags & TIO_F_RI ) lputs( L_NOISE, " RI" ); } return flags; } /* tio_set_rs232_lines() * * set the status of the DTR and RTS RS232 status lines * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_* * flags, we use them, on others we may have to do some other tricks) * * "-1" can mean "error" or "not supported on this system" (e.g. SCO). */ int tio_set_rs232_lines _P3( (fd, do_dtr, do_rts), int fd, int do_dtr, int do_rts ) { int mctl, rc=0; #ifdef TIO_F_SYSTEM_DEFS mctl = TIOCM_DTR; if ( do_dtr != -1 && ioctl( fd, do_dtr? TIOCMBIS: TIOCMBIC, &mctl ) < 0 ) { lprintf( L_ERROR, "tio_set_rs232_lines: %s DTR failed", do_dtr? "set": "clear" ); rc=-1; } mctl = TIOCM_RTS; if ( do_rts != -1 && ioctl( fd, do_rts? TIOCMBIS: TIOCMBIC, &mctl ) < 0 ) { lprintf( L_ERROR, "tio_set_rs232_lines: %s RTS failed", do_rts? "set": "clear" ); rc=-1; } #else lprintf( L_WARN, "setting of RS232 lines not supported" ); #endif return rc; } mgetty-1.1.36/tio.h0100644000031200001470000001326510342063637012364 0ustar gertfax#ident "$Id: tio.h,v 4.7 2005/11/26 13:48:15 gert Exp $ Copyright (c) 1993 Gert Doering" #ifndef __TIO_H__ #define __TIO_H__ /* tio.h * * contains definitions / prototypes needed for tio.c * */ #ifdef NEXTSGTTY # define BSD_SGTTY # undef POSIX_TERMIOS # undef SYSV_TERMIO #endif #if !defined( POSIX_TERMIOS ) && !defined( BSD_SGTTY ) && !defined( SYSV_TERMIO) # if defined(linux) || defined(sunos4) || defined(_AIX) || defined(BSD) || \ defined(SVR4) || defined(solaris2) || defined(m88k) || defined(M_UNIX) ||\ defined(__sgi) || defined(__GLIBC__) # define POSIX_TERMIOS # else # define SYSV_TERMIO # endif #endif #ifdef SYSV_TERMIO #undef POSIX_TERMIOS #undef BSD_SGTTY #include typedef struct termio TIO; #endif #ifdef POSIX_TERMIOS #undef BSD_SGTTY #include typedef struct termios TIO; #endif #ifdef BSD_SGTTY #include typedef struct sgttyb TIO; #endif /* on SCO and other SVR3 systems, the TIOCMGET calls are only available * with special drivers, like the digiboard drivers, or my hacked "FAS" */ #ifdef USE_FAS_TIOCMGET # include #endif /* make sure gets included: contains TIOCM* definitions * on AIX, and ioctl() prototype on NeXT and Linux */ #if defined(_AIX) || defined(NeXT) || defined(linux) # include #endif /* define some types for gettydefs.c */ #ifdef SYSV_TERMIO /* You may have to look at sys/termio.h to determine the type of the * c_?flag structure members. */ typedef unsigned short tioflag_t; #define TIONCC NCC #endif #ifdef POSIX_TERMIOS typedef tcflag_t tioflag_t; #define TIONCC NCCS #endif #if defined(BSD_SGTTY) && defined(USE_GETTYDEFS) #include "cannot use /etc/gettydefs with sgtty (yet?)" #endif /* SVR4 came up with a new method of setting h/w flow control */ /* unfortunately, it's broken in 4.2 and Solaris2, and not there in IRIX! */ #if defined(SVR4) && \ !defined(SVR42) && !defined(solaris2) && !defined(sgi) # define USE_TERMIOX #endif /* AIX 4.x has it as well, AIX 3.x has not, check with _AIX41 */ #if defined(_AIX) && defined(_AIX41) && !defined(USE_TERMIOX) # define USE_TERMIOX #endif /* if not defined in the default header files, #define some important things */ #ifdef _AIX #include #endif #ifdef _HPUX_SOURCE # include #endif #if !defined(VSWTCH) && defined(VSWTC) #define VSWTCH VSWTC #endif #ifndef _POSIX_VDISABLE #define _POSIX_VDISABLE '\377' #endif /* default control chars */ #ifndef CESC #define CESC '\\' #endif #ifndef CINTR #define CINTR 0177 /* DEL */ #endif #ifndef CQUIT #define CQUIT 034 /* FS, cntl | */ #endif #ifndef CERASE #define CERASE '\b' /* BS, nonstandard */ #endif #ifndef CKILL #define CKILL '\025' /* NAK, nonstandard */ #endif #ifndef CEOF #define CEOF 04 /* cntl d */ #endif #ifndef CSTART #define CSTART 021 /* cntl q */ #endif #ifndef CSTOP #define CSTOP 023 /* cntl s */ #endif #ifndef CEOL #define CEOL 000 /* cntl j */ #endif #ifdef CSWTCH # undef CSWTCH /* usually ^z, unwanted here */ #endif #define CSWTCH 000 /* */ #ifndef CSUSP # ifdef SVR42 # define CSUSP 026 /* cntl z */ # else # define CSUSP _POSIX_VDISABLE /* have only job control aware */ /* shells use it */ # endif #endif /* the following are used only if the corresponding V... defines are */ /* available, and that's only on SVR42 (as far as I know) */ #ifndef CDSUSP #define CDSUSP 025 /* cntl y */ #endif #ifndef CRPRNT #define CRPRNT 000 /* */ #endif #ifndef CFLUSH #define CFLUSH 000 /* */ #endif #ifndef CWERASE #define CWERASE 000 /* */ #endif #ifndef CLNEXT #define CLNEXT 000 /* */ #endif /* queue selection flags (for tio_flush_queue) */ #define TIO_Q_IN 0x01 /* incoming data queue */ #define TIO_Q_OUT 0x02 /* outgoing data queue */ #define TIO_Q_BOTH ( TIO_Q_IN | TIO_Q_OUT ) /* RS232 line status flags */ /* system flags are used if available, otherwise we define our own */ #ifdef TIOCM_DTR # define TIO_F_SYSTEM_DEFS # define TIO_F_DTR TIOCM_DTR # define TIO_F_DSR TIOCM_DSR # define TIO_F_RTS TIOCM_RTS # define TIO_F_CTS TIOCM_CTS # define TIO_F_DCD TIOCM_CAR # define TIO_F_RI TIOCM_RNG #else # define TIO_F_DTR 0x001 # define TIO_F_DSR 0x002 # define TIO_F_RTS 0x004 # define TIO_F_CTS 0x008 # define TIO_F_DCD 0x010 # define TIO_F_RI 0x020 #endif /* function prototypes */ int tio_get _PROTO (( int fd, TIO *t )); int tio_set _PROTO (( int fd, TIO *t )); int tio_check_speed _PROTO (( int speed )); int tio_set_speed _PROTO (( TIO *t, unsigned int speed )); int tio_get_speed _PROTO (( TIO *t )); void tio_mode_raw _PROTO (( TIO *t )); void tio_mode_cbreak _PROTO (( TIO *t )); void tio_mode_sane _PROTO (( TIO *t, int set_clocal_flag )); void tio_default_cc _PROTO (( TIO *t )); void tio_map_cr _PROTO (( TIO *t, int perform_crnl_mapping )); void tio_map_uclc _PROTO (( TIO *t, int perform_case_mapping )); int tio_set_flow_control _PROTO(( int fd, TIO *t, int flowctrl_type )); int tio_set_flow_control2 _PROTO(( int fd, int flowctrl_type )); void tio_carrier _PROTO (( TIO *t, int carrier_sensitive )); int tio_toggle_dtr _PROTO(( int fd, int msec_wait )); int tio_flush_queue _PROTO(( int fd, int queue )); int tio_flow _PROTO(( int fd, int restart_output )); int tio_break _PROTO(( int fd )); int tio_drain_output _PROTO(( int fd )); int tio_get_rs232_lines _PROTO(( int fd )); /* get line status */ int tio_set_rs232_lines _PROTO(( int fd, int do_dtr, int do_rts )); #ifdef USE_GETTYDEFS typedef struct { char *tag; TIO before; TIO after; char *prompt; char *nexttag; } GDE; int loadgettydefs _PROTO((char *s)); void dumpgettydefs _PROTO((char *file)); GDE *getgettydef _PROTO((char *s)); #endif /* USE_GETTYDEFS */ #endif /* __TIO_H__ */ mgetty-1.1.36/gettydefs.c0100644000031200000620000003315106266175363014142 0ustar gertgroup#ident "$Id: gettydefs.c,v 4.1 1997/01/12 14:53:39 gert Exp $ Copyright (c) 1993 Gert Doering/Chris Lewis" /* gettydefs.c * * Read /etc/gettydefs file, and permit retrieval of individual entries. * * Code in this module by Chris Lewis */ #include #include #include #include #include #include "syslibs.h" #include "mgetty.h" #include "policy.h" boolean verbose; char * mydup _P1 ((s), register char *s) { register char *p = (char *) malloc(strlen(s) + 1); if (!p) { lprintf(L_ERROR, "mydup can't malloc"); exit(1); } strcpy(p, s); return(p); } #ifdef USE_GETTYDEFS static char gettydefs_ID[] = "@(#)gettydefs.c compiled with USE_GETTYDEFS"; #include "tio.h" struct modeword { char *name; tioflag_t turnon; tioflag_t turnoff; unsigned short metaon; unsigned short metaoff; }; /* Meta tokens */ #define SANE 0x0001 #define ODDP 0x0002 #define PARITY 0x0004 #define NPARITY 0x0008 #define RAW 0x0010 #define COOKED 0x0020 #define NL 0x0040 #define NNL 0x0080 #define LCASE 0x0100 #define NLCASE 0x0200 #define TABS 0x0400 #define NTABS 0x0800 /* input modes */ static struct modeword iflags[] = { { "IGNBRK", IGNBRK, IGNBRK }, { "BRKINT", BRKINT, BRKINT, SANE }, { "IGNPAR", IGNPAR, IGNPAR, SANE }, { "PARMRK", PARMRK, PARMRK }, { "INPCK", INPCK, INPCK }, { "ISTRIP", ISTRIP, ISTRIP, SANE }, { "INLCR", INLCR, INLCR, 0, NNL }, { "IGNCR", IGNCR, IGNCR, 0, NNL }, { "ICRNL", ICRNL, ICRNL, (SANE|NL), NNL }, { "IUCLC", IUCLC, IUCLC, LCASE, NLCASE }, { "IXON", IXON, IXON, SANE }, { "IXANY", IXANY, IXANY }, { "IXOFF", IXOFF, IXOFF }, { NULL } }; /* output modes */ static struct modeword oflags[] = { { "OPOST", OPOST, OPOST, (SANE|COOKED), RAW }, { "OLCUC", OLCUC, OLCUC, LCASE, NLCASE }, { "ONLCR", ONLCR, ONLCR, NL, NNL }, { "OCRNL", OCRNL, OCRNL, 0, NNL }, { "ONOCR", ONOCR, ONOCR }, { "ONLRET", ONLRET, ONLRET, NNL }, { "OFILL", OFILL, OFILL }, { "OFDEL", OFDEL, OFDEL }, { "NLDLY", NLDLY, NLDLY }, { "NL0", NL0, NLDLY }, { "NL1", NL1, NLDLY }, { "CR0", CR0, CRDLY }, { "CR1", CR1, CRDLY }, { "CR2", CR2, CRDLY }, { "CR3", CR3, CRDLY }, { "TAB0", TAB0, TABDLY, TABS }, { "TAB1", TAB1, TABDLY }, { "TAB2", TAB2, TABDLY }, { "TAB3", TAB3, TABDLY, NTABS }, { "BS0", BS0, BSDLY }, { "BS1", BS1, BSDLY }, { "VT0", VT0, VTDLY }, { "VT1", VT1, VTDLY }, { "FF0", FF0, FFDLY }, { "FF1", FF1, FFDLY }, { NULL } }; /* control modes */ static struct modeword cflags[] = { { "B0", B0, CBAUD }, { "B50", B50, CBAUD }, { "B75", B75, CBAUD }, { "B110", B110, CBAUD }, { "B134", B134, CBAUD }, { "B150", B150, CBAUD }, { "B200", B200, CBAUD }, { "B300", B300, CBAUD }, { "B600", B600, CBAUD }, #ifdef B900 { "B900", B900, CBAUD }, #endif { "B1200", B1200, CBAUD }, { "B1800", B1800, CBAUD }, { "B2400", B2400, CBAUD }, #ifdef B3600 { "B3600", B3600, CBAUD }, #endif { "B4800", B4800, CBAUD }, #ifdef B7200 { "B7200", B7200, CBAUD }, #endif { "B9600", B9600, CBAUD }, #ifdef B19200 { "B19200", B19200, CBAUD }, #endif #ifdef B38400 { "B38400", B38400, CBAUD }, #endif #ifdef B57600 { "B57600", B57600, CBAUD }, #endif #ifdef B76800 { "B76800", B76800, CBAUD }, #endif #ifdef B115200 { "B115200", B115200, CBAUD }, #endif #ifdef B230400 { "B230400", B230400, CBAUD }, #endif #ifdef B230400 { "B230400", B230400, CBAUD }, #endif #ifdef B460800 { "B460800", B460800, CBAUD }, #endif { "EXTA", EXTA, CBAUD }, { "EXTB", EXTB, CBAUD }, { "CS5", CS5, CSIZE }, { "CS6", CS6, CSIZE }, { "CS7", CS7, CSIZE, (ODDP|PARITY) }, { "CS8", CS8, CSIZE, (SANE|NPARITY) }, { "CSTOPB", CSTOPB, CSTOPB }, { "CREAD", CREAD, CREAD, SANE }, { "PARENB", PARENB, PARENB, (ODDP|PARITY), (NPARITY) }, { "PARODD", PARODD, PARODD, ODDP }, { "HUPCL", HUPCL, HUPCL }, { "CLOCAL", CLOCAL, CLOCAL }, /* Various handshaking defines */ #ifdef CTSCD { "CTSCD", CTSCD, CTSCD }, #endif #ifdef CRTSCTS { "CRTSCTS", CRTSCTS, CRTSCTS }, #endif #ifdef CRTSFL { "CRTSFL", CRTSFL, CRTSFL }, #endif #ifdef RTSFLOW { "RTSFLOW", RTSFLOW, RTSFLOW }, { "CTSFLOW", CTSFLOW, CTSFLOW }, #endif #ifdef HDX { "HDX", HDX, HDX }, #endif { NULL } }; /* line discipline */ static struct modeword lflags[] = { { "ISIG", ISIG, ISIG, SANE }, { "ICANON", ICANON, ICANON, (SANE|COOKED), RAW }, { "XCASE", XCASE, XCASE, LCASE, NLCASE }, { "ECHO", ECHO, ECHO, SANE }, { "ECHOE", ECHOE, ECHOE }, { "ECHOK", ECHOK, ECHOK, SANE }, { "ECHONL", ECHONL, ECHONL }, { "NOFLSH", NOFLSH, NOFLSH }, { NULL } }; /* c_cc special characters */ static struct modeword ccchars[] = { {"VINTR", VINTR, CINTR}, {"VQUIT", VQUIT, CQUIT}, {"VERASE", VERASE, CERASE}, {"VKILL", VKILL, CKILL}, {"VEOF", VEOF, CEOF}, #if defined(VEOL) && VEOL < TIONCC {"VEOL", VEOL, CEOL}, #endif #if defined(CEOL2) && defined(VEOL2) && VEOL2 < TIONCC {"VEOL2", VEOL2, CEOL2}, #endif #if defined(VSUSP) && VSUSP < TIONCC {"VSUSP", VSUSP, CSUSP}, #endif #if defined(VSTART) && VSTART < TIONCC {"VSTART", VSTART, CSTART}, #endif #if defined(VSTOP) && VSTOP < TIONCC {"VSTOP", VSTOP, CSTOP}, #endif #if defined(VSWTCH) && VSWTCH < TIONCC {"VSWTCH", VSWTCH, CSWTCH}, #endif /* SVR4.2 */ #if defined(VDSUSP) && VDSUSP < TIONCC {"VDSUSP", VDSUSP, CDSUSP}, #endif #if defined(VREPRINT) && VREPRINT < TIONCC {"VREPRINT", VREPRINT, CRPRNT}, #endif #if defined(VDISCARD) && VDISCARD < TIONCC {"VDISCARD", VDISCARD, CFLUSH}, #endif #if defined(VWERASE) && VWERASE < TIONCC {"VWERASE", VWERASE, CWERASE}, #endif #if defined(VLNEXT) && VLNEXT < TIONCC {"VLNEXT", VLNEXT, CLNEXT}, #endif {"VMIN", VMIN, 0}, {"VTIME", VTIME, 0}, { NULL } }; struct modeword metatokens[] = { { "SANE", SANE }, { "ODDP", ODDP }, { "PARITY", PARITY }, { "EVENP", PARITY }, { "-ODDP", NPARITY }, { "-PARITY", NPARITY }, { "-EVENP", NPARITY }, { "RAW", RAW }, { "-RAW", COOKED }, { "COOKED", COOKED }, { "NL", NL }, { "-NL", NNL }, { "LCASE", LCASE }, { "-LCASE", NLCASE }, { "TABS", TABS }, { "-TABS", NTABS }, { "TAB3", NTABS }, { NULL } }; #define GDCHUNK 5 GDE *gdep = (GDE *) NULL; GDE *cur = (GDE *) NULL; static int cntalloc = 0; static struct modeword * findmode _P2 ((modes, tok), struct modeword *modes, register char *tok) { for( ; modes->name; modes++) if (strcmp(modes->name, tok) == 0) return(modes); return((struct modeword *) NULL); } static void metaset _P3((tc, modes, key), tioflag_t *tc, struct modeword *modes, int key) { for ( ; modes->name; modes++) { if (modes->metaon&key) *tc = (*tc & ~ modes->turnoff) | modes->turnon; if (modes->metaoff&key) *tc = (*tc & ~ modes->turnoff); } } static void parsetermio _P2((ti, str), TIO *ti, char *str) { register char *p; struct modeword *m; tioflag_t *flag; int metakey; /* initialize c_cc[] array (tio_* doesn't init INTR/ERASE!) */ tio_default_cc( ti ); ti->c_cc[VINTR] = CINTR; ti->c_cc[VERASE] = CERASE; #ifndef POSIX_TERMIOS ti->c_line = 0; #endif for (p = str; *p; p++) if (islower(*p)) *p = toupper(*p); while ( (p = strtok(str, " \t")) != NULL ) { int not = FALSE; str = NULL; metakey = 0; if (strcmp(p, "EK") == 0) { ti->c_cc[VERASE] = '#'; ti->c_cc[VKILL] = CKILL; continue; } for (m = metatokens; m->name; m++) if (strcmp(p, m->name) == 0) { metakey = m->turnon; break; } if (metakey) { metaset(&ti->c_lflag, lflags, metakey); metaset(&ti->c_oflag, oflags, metakey); metaset(&ti->c_iflag, iflags, metakey); metaset(&ti->c_cflag, cflags, metakey); continue; } if (*p == '-') { not = TRUE; p++; } if ((m = findmode(lflags, p)) != NULL) flag = &ti->c_lflag; else if ((m = findmode(oflags, p)) != NULL) flag = &ti->c_oflag; else if ((m = findmode(iflags, p)) != NULL) flag = &ti->c_iflag; else if ((m = findmode(cflags, p)) != NULL) flag = &ti->c_cflag; if (m) { if (not) *flag = (*flag & ~ m->turnoff); else *flag = (*flag & ~ m->turnoff) | m->turnon; } else { if ((m = findmode(ccchars, p)) != NULL) { char *p2; p2 = strtok(str, " \t"); if (!p2) { if (verbose) fprintf(stderr, "No value after %s\n", p); return; } if (*p2 == '\\') switch(*(p2+1)) { case 'n': *p2 = '\n'; break; case 'r': *p2 = '\r'; break; case 'b': *p2 = '\010'; break; case 'v': *p2 = '\013'; break; case 'g': *p2 = '\007'; break; case 'f': *p2 = '\f'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { char tbuf[4]; strncpy(tbuf, p2+1, 3); tbuf[3] = '\0'; *p2 = strtol(tbuf, (char **) NULL, 8); break; } default: *p2 = *(p2+1); } else if (*p2 == '^') /* ^x means C-x, ^? is DEL */ *p2 = (*(p2+1) == '?')? 0x7f : *(p2+1) - '@'; ti->c_cc[m->turnon] = *p2; } else if (verbose) fprintf(stderr, "Can't parse %s\n", p); } } } static char * stripblanks _P1 ((s), register char *s) { register char *p; while(*s && isspace(*s)) s++; p = s; while(*p && !isspace(*p)) p++; *p = '\0'; return(s); } #define GETTYBUFSIZE (10*BUFSIZ) int getentry _P3((entry, elen, f), char *entry, int elen, FILE *f) { char buf[BUFSIZ*2]; register char *p; entry[0] = '\0'; do { if (!fgets(buf, sizeof(buf), f)) return(0); for (p = buf; isspace(*p); p++); } while(*p == '#' || *p == '\n'); p = strchr(buf, '\n'); if (p) *p = '\0'; strcat(entry, buf); while (1) { if (!fgets(buf, sizeof(buf), f)) break; p = strchr(buf, '\n'); if (p) *p = '\0'; for (p = buf; isspace(*p); p++); if (!*p) break; strcat(entry, " "); strcat(entry, p); } return(1); } /* * loads all of the entries from the gettydefs file * returns 0 if it fails. */ int loadgettydefs _P1((file), char *file ) { FILE *gd = fopen(file, "r"); char buf[GETTYBUFSIZE]; register char *p; char *tag, *prompt, *nexttag, *before, *after; if (!gd) { lprintf(L_WARN, "Can't open %s\n", file); return(0); } while(getentry(buf, sizeof(buf), gd)) { p = buf; tag = strtok(p, "#"); if (!tag) continue; tag = stripblanks(tag); tag = mydup(tag); before = strtok(NULL, "#"); if (!before) continue; after = strtok(NULL, "#"); if (!after) continue; prompt = strtok(NULL, "#"); if (!prompt) continue; /* do NOT escape prompt here - it may contain \D and \T, and * for that, the real time at login should be used */ prompt = mydup(prompt); nexttag = strtok(NULL, "#"); if (!nexttag) continue; p = strchr(nexttag, '\n'); if (p) *p = '\0'; nexttag = stripblanks(nexttag); nexttag = mydup(nexttag); #ifdef NEVER printf("tag: %s\nbefore: %s\nafter: %s\nprompt: %s\nnexttag: %s\n\n", tag, before, after, prompt, nexttag); #endif if (cur - gdep >= cntalloc-2) { GDE *sav; sav = gdep; if (!gdep) { gdep = (GDE *) malloc(sizeof(GDE) * GDCHUNK); cur = gdep; } else { gdep = (GDE *) realloc(gdep, sizeof(GDE) * (GDCHUNK + cntalloc)); cur = gdep + (cur - sav); } cntalloc += GDCHUNK; } memset(cur, sizeof(*cur), '\0'); cur->tag = tag; cur->prompt = prompt; cur->nexttag = nexttag; parsetermio(&cur->before, before); parsetermio(&cur->after, after); if (verbose) printf("Processed `%s' gettydefs entry\n", tag); cur++; cur->tag = (char *) NULL; } fclose(gd); return(1); } GDE * getgettydef _P1 ((s), register char *s) { for (cur = gdep; cur && cur->tag; cur++) if (strcmp(cur->tag, s) == 0) return(cur); if (gdep && gdep->tag) { lprintf(L_WARN, "getgettydef(%s) entry not found using %s", s, gdep->tag); return(gdep); } lprintf(L_WARN, "getgettydef(%s) no entry found", s); return((GDE *) NULL); } void dumpflag _P3((type, modes, flag), char *type, struct modeword *modes, tioflag_t flag) { printf("%s: %08lo", type, (unsigned long) flag); for(; modes->name; modes++) if ((flag&modes->turnoff) == modes->turnon) printf(" %s", modes->name); putchar('\n'); } void dump _P2((ti, s), TIO *ti, char *s) { register int i; register struct modeword *modes; printf("%s:", s); dumpflag("\tiflags", iflags, ti->c_iflag); dumpflag("\toflags", oflags, ti->c_oflag); dumpflag("\tcflags", cflags, ti->c_cflag); dumpflag("\tlflags", lflags, ti->c_lflag); printf("\tc_cc:\t"); for (i = 0; i < TIONCC; i++) { if (i == 6) printf("\n\t\t"); for (modes = ccchars; modes->name; modes++) if (modes->turnon == i) { printf("%s(", modes->name); break; } if (!modes->name) /* skip unallocated ones */ continue; /* Yeah, I know. But who's ever heard of getty on a EBCDIC system ;-) */ if (ti->c_cc[i] < ' ') printf("^%c", ti->c_cc[i] + '@'); else if (ti->c_cc[i] == (0xff & _POSIX_VDISABLE)) printf("disabled"); else if (ti->c_cc[i] >= 0x7f) printf("\\%03o", 0xff&ti->c_cc[i]); else putchar(ti->c_cc[i]); printf(") "); } printf("\n\n"); } static void spew _P1 ((gd), GDE *gd) { printf("tag: `%s'\nprompt: `%s'\nnexttag: `%s'\n", gd->tag, gd->prompt, gd->nexttag); dump(&gd->before, "before"); dump(&gd->after, "after"); printf("\n"); } void dumpgettydefs _P1((file), char *file) { if (! loadgettydefs(file)) { fprintf(stderr, "Couldn't read %s\n", file); exit(1); } printf("loaded entries:\n"); for (cur = gdep; cur->tag; cur++) spew(cur); } #endif mgetty-1.1.36/login.c0100644000031200001470000002212507764203252012672 0ustar gertfax#ident "$Id: login.c,v 4.19 2003/12/05 22:28:58 gert Exp $ Copyright (C) 1993 Gert Doering" /* login.c * * handle calling of login program(s) for data calls */ #include #include #include #include #include #include #ifndef EINVAL #include #endif #include #include #include /* NeXTStep/86 has some byte order problems (Christian Starkjohann) */ #if defined(NeXT) && defined(__LITTLE_ENDIAN__) && !defined(NEXTSGTTY) # define pw_uid pw_short_pad1 # define pw_gid pw_short_pad2 # define gr_gid gr_short_pad #endif #include "mgetty.h" #include "config.h" #include "policy.h" #include "mg_utmp.h" #ifdef SECUREWARE extern int setluid(); #endif extern char * Device; /* mgetty.c */ /* match( user, key ) * * match "user" against "key" * key may start or end with "*" (wildcard) */ boolean match _P2( (user,key), char * user, char * key ) { int lk = strlen( key ); int lu = strlen( user ); int i; lprintf( L_NOISE, "match: user='%s', key='%s'", user, key ); /* empty lines do not match */ if ( lk == 0 ) return FALSE; #ifdef FIDO /* special handling for fido logins */ if ( user[0] == '\377' && strcmp( key, "/FIDO/" ) == 0 ) { return TRUE; } #endif if ( key[0] == '*' ) /* "*bc?" */ { if ( key[lk-1] == '*' ) /* "*bc*" */ { if ( lk < 2 ) return TRUE; /* "*" or "**" */ for ( i=0; i <= lu - (lk-2); i++ ) { if ( strncmp( &user[i], &key[1], lk-2 ) == 0 ) return TRUE; } return FALSE; } else /* "*bcd" */ { return ( ( lu >= lk-1 ) && ( strcmp( &user[ lu-(lk-1) ], &key[1] ) == 0 ) ); } } else /* "abc?" */ { if ( key[lk-1] == '*' ) /* "abc*" */ { return ( ( lu >= lk-1 ) && ( strncmp( user, key, lk-1 ) == 0 ) ); } else { return ( ( lu == lk ) && ( strcmp( user, key ) == 0 ) ); } } return FALSE; /*NOTREACHED*/ } /* execute login * * which login program is executed depends on LOGIN_FILE * default is "/bin/login user" * * does *NOT* return */ void login_dispatch _P3( (user, is_callback, cfg_file ), char * user, boolean is_callback, char * cfg_file ) { #define MAX_LOGIN_ARGS 9 char * argv[MAX_LOGIN_ARGS+2]; /* name + args + NULL */ int argc = 0; char * cmd = NULL; int i; /* read "mgetty.login" config file (if specified) */ FILE * fp = NULL; int file_version = 1; /* login.config format changed! */ char * line, * key, *p; struct passwd * pw; extern struct passwd * getpwnam(); struct stat st; if ( cfg_file == NULL ) { lprintf( L_JUNK, "login: no login cfg file defined" ); goto fallthrough; } cfg_file = _makepath( cfg_file, CONFDIR ); lprintf( L_JUNK, "login: use login config file %s", cfg_file ); /* first of all, some (somewhat paranoid) checks for file ownership, * file permissions (0i00), ... * If something fails, fall through to default ("/bin/login ") */ if ( stat( cfg_file, &st ) < 0 ) { lprintf( L_ERROR, "login: stat('%s') failed", cfg_file ); goto fallthrough; } /* permission check */ if ( st.st_uid != 0 || ( ( st.st_mode & 0077 ) != 0 ) ) { errno=EINVAL; lprintf( L_FATAL, "login: '%s' ignored, wrong permissions. Must be owned by 'root' and have mode '0600'", cfg_file ); goto fallthrough; } /* go for it! */ if ( (fp = fopen( cfg_file, "r" )) == NULL ) { lprintf( L_FATAL, "login: cannot open %s", cfg_file ); } else while ( ( line = fgetline( fp ) ) != NULL ) { norm_line( &line, &key ); /* as the format of login.config has changed over time, we have * to have "file versions", set by the '!version ' keyword */ if ( strcmp( key, "!version" ) == 0 ) { file_version = atoi(line); if ( file_version < 1 || file_version > 2 ) { errno = EINVAL; lprintf( L_ERROR, "login: invalid file version '%s'", line); file_version = 1; } lprintf( L_NOISE, "login: version %d", file_version); continue; } if ( match( user, key ) ) { char * user_id; char * utmp_entry; lputs( L_NOISE, "*** hit!" ); #ifdef FIDO if ( user[0] == '\377' && strcmp( key, "/FIDO/" ) == 0 ) { user++; } #endif /* in version 2 files, the next field is used to qualify * this line for callback only/never/don't care */ if ( file_version > 1 ) { char cbq = toupper( *(line++) ); if ( ( cbq == 'Y' && ! is_callback ) || ( cbq == 'N' && is_callback ) ) { lprintf( L_NOISE, "-> skipped: %c/%d", cbq, is_callback ); continue; } /* skip to next field */ while( *line && !isspace(*line) ) line++; while( isspace(*line) ) line++; } /* get (login) user id */ user_id = strtok( line, " \t" ); /* get utmp entry */ utmp_entry = strtok( NULL, " \t" ); /* get login program */ argv[0] = cmd = strtok( NULL, " \t" ); /* sanity checks - *before* setting anything */ errno = EINVAL; if ( user_id == NULL ) { lprintf( L_FATAL, "login: uid field blank, skipping line" ); continue; } if ( utmp_entry == NULL ) { lprintf( L_FATAL, "login: utmp field blank, skipping line" ); continue; } if ( cmd == NULL ) { lprintf( L_FATAL, "login: no login command, skipping line" ); continue; } /* OK, all values given. Now write utmp entry */ if ( strcmp( utmp_entry, "-" ) != 0 ) { if ( strcmp( utmp_entry, "@" ) == 0 ) utmp_entry = user; lprintf( L_NOISE, "login: utmp entry: %s", utmp_entry ); make_utmp_wtmp( Device, UT_USER, utmp_entry, Connect ); } /* set UID (+login uid) */ if ( strcmp( user_id, "-" ) != 0 ) { pw = getpwnam( user_id ); if ( pw == NULL ) { lprintf( L_ERROR, "getpwnam('%s') failed", user_id ); } else { lprintf( L_NOISE, "login: user id: %s (uid %d, gid %d)", user_id, pw->pw_uid, pw->pw_gid ); #if SECUREWARE if ( setluid( pw->pw_uid ) == -1 ) { lprintf( L_ERROR, "cannot set LUID %d", pw->pw_uid); } #endif if ( setgid( pw->pw_gid ) == -1 ) { lprintf( L_ERROR, "cannot set gid %d", pw->pw_gid ); } if ( setuid( pw->pw_uid ) == -1 ) { lprintf( L_ERROR, "cannot set uid %d", pw->pw_uid ); } } } /* end if (uid given) */ /* now build 'login' command line */ /* strip path name off to-be-argv[0] */ p = strrchr( argv[0], '/' ); if ( p != NULL ) argv[0] = p+1; /* break up line into whitespace-separated command line arguments, substituting '@' by the user name */ argc = 1; p = strtok( NULL, " \t" ); while ( argc <= MAX_LOGIN_ARGS && p != NULL ) { if ( strcmp( p, "@" ) == 0 ) /* user name */ { if ( user != NULL && user[0] != 0 ) { argv[argc++] = user; } } else if ( strcmp( p, "\\I" ) == 0 ) /* Connect */ { argv[argc++] = Connect[0]? Connect: "??"; } else if ( strcmp( p, "\\Y" ) == 0 ) /* CallerID */ { argv[argc++] = CallerId; } else argv[argc++] = p; p = strtok( NULL, " \t" ); } if ( p != NULL ) /* arguments left? */ lprintf( L_WARN, "login.config: max. %d command line arguments possible, truncated at: '%s'", MAX_LOGIN_ARGS, p); break; } /* end if (matching line found) */ } /* end while( not end of config file ) */ if ( fp != NULL ) fclose( fp ); fallthrough: /* default to "/bin/login " */ if ( argc == 0 ) { lprintf( L_NOISE, "login: fall back to %s", DEFAULT_LOGIN_PROGRAM ); cmd = DEFAULT_LOGIN_PROGRAM; argv[argc++] = "login"; /* append user name to argument list (if not empty) */ if ( user[0] != 0 ) { argv[argc++] = user; } } /* terminate list */ argv[argc] = NULL; /* verbose login message */ lprintf( L_NOISE, "calling login: cmd='%s', argv[]='", cmd ); for ( i=0; i #include "syslibs.h" #include #include #include #include #include #ifndef sunos4 #include #endif #ifndef EINTR #include #endif #include "mgetty.h" #include "policy.h" #include "tio.h" static boolean has_timeout; static RETSIGTYPE timeout(SIG_HDLR_ARGS) { has_timeout = TRUE; } void get_statistics _P3( (fd, expect_send, tgt_file), int fd, char * expect_send[], char * tgt_file ) { char line[MAXLINE]; int r; FILE * fp = NULL; /* target file */ if ( tgt_file != NULL ) /* to file, not to lprintf() */ { fp = fopen( tgt_file, "a" ); if ( fp == NULL ) lprintf( L_ERROR, "do_stat: can't open %s", tgt_file ); else /* open ok, log time */ { time_t now = time(NULL); char *snow = ctime( &now ); if ( snow ) fprintf( fp, "--- %.*s ---\n", (int) strlen(snow)-1, snow); } } while ( *expect_send != NULL ) { /* handle "expect" part */ r=0; if ( **expect_send != 0 ) /* !empty string */ { lprintf( L_MESG, "do_stat: expect '%s'", *expect_send ); /* 10 seconds timeout should be sufficient here */ signal( SIGALRM, timeout ); alarm(10); while( 1 ) { if ( read( fd, &line[r], 1 ) != 1 ) { if ( has_timeout ) lprintf( L_WARN, "do_stat: timeout" ); else lprintf( L_ERROR, "do_stat: error reading data" ); alarm(0); return; } if ( line[r] == '\r' || line[r] == '\n' ) /* line full */ { line[r] = 0; /* terminate */ if ( r != 0 ) /* log... */ { if ( fp == NULL ) /* to logfile */ lprintf( L_MESG, "*** %s", line ); else /* to stat.f. */ fprintf( fp, "%s\n", line ); } if ( strncmp( line, *expect_send, strlen( *expect_send ) ) == 0 ) { lputs( L_MESG, " ** found **" ); break; } r=0; } else if ( rd.p = (s); (cp)->flags = C_OVERRIDE; } #define conf_set_bool( cp, b ) { (cp)->d.i = (b); (cp)->flags = C_OVERRIDE; } #define conf_set_int( cp, n ) { (cp)->d.i = (n); (cp)->flags = C_OVERRIDE; } /* macros for implementation-indepentent access */ #define c_isset( cp ) ( c.cp.flags != C_EMPTY ) #define c_string( cp ) ((char *) c.cp.d.p) #define c_bool( cp ) ((boolean) c.cp.d.i) #define c_int( cp ) ((int) c.cp.d.i) #define c_chat( cp ) ((char **) c.cp.d.p) /* concatenate two paths (if second path doesn't start with "/") */ /* two variants: ANSI w/ macro, K&R w/ C subroutine in config.c */ #ifdef __STDC__ #define makepath( file, base ) ((file)[0] == '/'? (file) : (base"/"file)) #else #define makepath( file, base ) _makepath( file, base ) #endif extern char * _makepath _PROTO(( char * file, char * base )); #endif /* ___CONFIG_H */ mgetty-1.1.36/config.c0100600000031200001470000002316110506054347013015 0ustar gertfax#ident "$Id: config.c,v 4.6 2006/06/14 09:52:34 gert Exp $ Copyright (c) 1993 Gert Doering" /* * config.c * * This module is part of the mgetty kit - see LICENSE for details * * Read and parse config file(s), see conf_*.[ch] for example use */ #include #include "syslibs.h" #include #include #ifndef ENOENT #include #endif #include "mgetty.h" #include "config.h" /* read a line from FILE * fp, terminated by "\n" * the line can be of any length (buffer will dynamically grow) * - trailing "\n" is chopped off * - continuation lines (trailing "\") will automatically be put together * - comment lines (leading "#") will be skipped */ char * fgetline _P1((fp), FILE * fp ) { static int bufsz = 0; static char * bufp = NULL; int bufidx; char * p; if ( bufp == NULL ) { if ( ( bufp = malloc( bufsz = 1024 ) ) == NULL ) { lprintf( L_ERROR, "fgetline: cannot allocate memory" ); return NULL; } } bufidx = 0; while ( TRUE ) { p = fgets( &bufp[ bufidx ], bufsz-bufidx, fp ); if ( p == NULL ) /* nothing more to read */ { if ( bufidx == 0 ) { free( bufp ); bufp = NULL; bufsz = 0; return NULL; } else break; } /* continuation lines? Buffer overflow? */ bufidx += strlen( &bufp[ bufidx ] ); /* discard trailing '\n' */ if ( bufidx > 0 && bufp[ bufidx-1 ] == '\n' ) bufp[ --bufidx ] = 0; /* buffer full */ if ( bufidx == bufsz-1 ) { lprintf( L_NOISE, "realloc line" ); if ( ( p = realloc( bufp, bufsz += 1024 ) ) == NULL ) { free( bufp ); bufp = NULL; bufsz = 0; lprintf( L_ERROR, "fgetline: cannot realloc" ); return NULL; } bufp = p; continue; } /* continuation lines */ if ( bufidx > 0 && bufp[ bufidx-1 ] == '\\' ) { bufidx--; continue; } /* comments */ if ( bufidx > 0 ) { char * sp = bufp; while( isspace( *sp ) ) sp++; /* skip whitespace */ if ( *sp == '#' ) { bufidx = 0; continue; } } break; } return bufp; } /* compress whitespace, drop leading / trailing whitespace, * put pointer to key word into *key */ void norm_line _P2( (line, key), char ** line, char ** key ) { char * r, *wp; int w, kflag; r = wp = *line; w = 0; kflag = 0; while ( *r ) { if ( isspace( *r ) ) { if ( w > 0 && wp[ w-1 ] != ' ' ) { if ( kflag == 0 ) kflag = w; wp[ w++ ] = ' '; } } else wp[ w++ ] = *r; r++; } wp[ w ] = 0; if ( w > 0 && wp[ w-1 ] == ' ' ) w--; wp[ w ] = 0; /* set key / line pointers */ *key = wp; if ( kflag == 0 ) *line = &wp[w]; else { wp[ kflag ] = 0; *line = &wp[ kflag+1 ]; } } /* change a input line into a (char ** ) chat sequence * all the data is in one malloc() block, so one free() suffices */ void * conf_get_chat _P1( (line), char * line ) { int cnt, i; int quote; char ** p; char * s; /* get number of distinct strings in this chat, for allocation */ quote=0; for ( cnt = i = 0; line[i]; i++ ) { if ( line[i] == '"' && ( i==0 || line[i-1]!='\\' ) ) quote = !quote; if ( line[i] == ' ' && !quote ) cnt++; } cnt+=2; /* lprintf( L_JUNK, "gc: %d strings", cnt-1 ); */ /* allocate memory for ptr list and chat script itself */ p = (char **) malloc( cnt * sizeof( char * ) + strlen(line) +1 ); if ( p == 0 ) { lprintf( L_ERROR, "conf_get_chat: cannot malloc" ); return NULL; } s = (char * ) &p[cnt]; /* pointer to data area */ /* build up ptr list, and copy script over */ quote = 0; p[ cnt=0 ] = s; while( *line ) { if ( *line == '"' ) quote = !quote; else if ( *line == ' ' && ! quote ) { *(s++) = 0; cnt++; p[cnt] = s; } else /* handle a few escape sequences */ if ( *line == '\\' && *(line+1) ) { switch( *(++line) ) { case 'r': *(s++) = '\r'; break; case 'n': *(s++) = '\n'; break; case 't': *(s++) = '\t'; break; case '\\': case '\"': *(s++) = *line; break; default: /* rest is handled in do_chat.c, especially "\c" */ *(s++) = '\\'; *(s++) = *line; } } else *(s++) = *line; line++; } /* terminate last string and ptr list */ *s = 0; cnt++; p[cnt] = NULL; /* for ( i=0; p[i]; i++ ) lprintf( L_JUNK, "chat string %d = '%s'", i, p[i] ); */ return p; } /* change "verbal" flow control names into FLOW_* bits * note: numeric constants (0x01/0x06) are used to avoid the need * to pull in tio.h/termio(s).h and friends */ int conf_get_flow _P2( (line, cp), char * line, conf_data * cp ) { if ( strncmp( line, "rts", 3 ) == 0 || strncmp( line, "hard", 4 ) == 0 ) { cp->d.i = FLOW_HARD; return 0; /* hardware flow control only */ } if ( strncmp( line, "xon", 3 ) == 0 || strncmp( line, "soft", 4 ) == 0 ) { cp->d.i = FLOW_SOFT; return 0; /* software flow control only */ } if ( strcmp( line, "both" ) == 0 ) { cp->d.i = FLOW_BOTH; return 0; /* hardware & software */ } if ( strcmp( line, "none" ) == 0 ) { cp->d.i = FLOW_NONE; return 0; /* none of it (DDTAH) */ } lprintf( L_WARN, "conf_get_flow: unknown keyword '%s'", line); return -1; } /* write the config structure into the log file */ void display_cd _P1( (cd), conf_data * cd ) { conf_data * cp; char ** p; cp = cd; while ( cp->key != NULL ) { char buf[100]; lprintf( L_NOISE, "key: '%s', type=%d, flags=%d, data=", cp->key, cp->type, cp->flags ); if ( cp->flags == C_EMPTY ) lputs( L_NOISE, "(empty)" ); else if ( cp->flags == C_IGNORE ) lputs( L_NOISE, "(ignored)" ); else switch ( cp->type ) { case CT_FLOWL: #ifdef PTR_IS_LONG /* 64bit machines: d.i is "long" */ case CT_INT: sprintf( buf, "%ld", cp->d.i ); #else case CT_INT: sprintf( buf, "%d", cp->d.i ); #endif lputs( L_NOISE, buf ); break; case CT_STRING: lputs( L_NOISE, (char *) cp->d.p ); break; case CT_BOOL: lputs( L_NOISE, cp->d.i ? "TRUE" : "FALSE" ); break; case CT_CHAT: p = (char **) cp->d.p; while ( *p != NULL ) { lputs( L_NOISE, *p ); lputc( L_NOISE, ' '); p++; } break; default: lputs( L_NOISE, "**unprintable**" ); break; } cp++; } } int get_config _P4( (conf_file,cd,section_key,key_value), char * conf_file, conf_data * cd, char * section_key, char * key_value ) { FILE * conf_fp; char * line; char * key; conf_data * cp; int errflag = 0; int ignore = 0; /* ignore keywords in non-matching section */ conf_fp = fopen( conf_file, "r" ); if ( conf_fp == NULL ) { if ( errno == ENOENT ) lprintf( L_WARN, "no config file found: %s", conf_file ); else lprintf( L_FATAL, "cannot open %s", conf_file ); return ERROR; } lprintf( L_NOISE, "reading %s...", conf_file ); /* display_cd ( cd ); */ while ( ( line = fgetline( conf_fp ) ) != NULL ) { norm_line( &line, &key ); if ( key[0] == 0 ) continue; /* empty line */ lprintf( L_NOISE, "conf lib: read: '%s %s'", key, line ); /* sort in data */ errflag = 0; cp = cd; if ( strcmp( key, section_key ) == 0 ) /* new section */ { ignore = ( key_value == NULL ) || /* match "wanted" section? */ ( strcmp( line, key_value ) != 0 ); lprintf( L_NOISE, "section: %s %s, %s", key, line, (ignore)?"ignore":"**found**" ); } else if ( ! ignore ) while ( cp->key != NULL ) { if ( strcmp( cp->key, key ) == 0 ) { /* special case: CT_KEYWORD pseudo-type * * additional "section key" keyword, handled similar to the * "standard" section keyword -> ignore everything below */ if ( cp->type == CT_KEYWORD ) { lprintf( L_NOISE, "found CT_KEYWORD %s %s", key, line ); ignore = TRUE; break; } if ( cp->flags == C_CONF && ( cp->type == CT_STRING || cp->type == CT_CHAT ) ) { free( cp->d.p ); cp->d.p = NULL; } if ( cp->flags != C_OVERRIDE && cp->flags != C_IGNORE ) { switch( cp->type ) { case CT_INT: if ( isdigit( line[0] ) || ( line[0] == '-' && isdigit( line[1] ) ) ) cp->d.i = strtol( line, NULL, 0 ); else errflag++; break; case CT_STRING: if ( ( cp->d.p = malloc( strlen( line ) +1 ) ) == NULL ) errflag ++; else strcpy( cp->d.p, line ); break; case CT_CHAT: if ( ( cp->d.p = conf_get_chat( line ) ) == NULL ) errflag ++; break; case CT_BOOL: cp->d.i = ( line[0] == 0 || line[0] == 1 || tolower(line[0]) == 'y' || tolower(line[0]) == 't' || strncmp( line, "on", 2 ) == 0 ); break; case CT_FLOWL: if ( conf_get_flow( line, cp ) < 0 ) errflag++; break; default: lprintf( L_ERROR, "yet unable to handle type %d", cp->type ); errflag ++; break; } cp->flags = C_CONF; } break; } cp++; } if ( cp->key == NULL || errflag ) { lprintf( L_WARN, "something foul in config line: '%s %s'", key, line ); if ( cp->key == NULL ) lprintf( L_WARN, " (keyword '%s' not found)", key ); else lprintf( L_WARN, " (most likely syntax error)" ); } } display_cd ( cd ); fclose( conf_fp ); return NOERROR; } /* makepath * * only needed on non-ANSI-compilers or for non-fixed arguments * * concatenate the first argument (file name) with the second * (path name), but only if the file name doesn't start with "/" */ char * _makepath _P2( (file, path), char * file, char * path ) { char * p; if ( file[0] == '/' ) return file; p = malloc( strlen( path ) + strlen( file ) +2 ); if ( p == NULL ) { lprintf( L_FATAL, "malloc error (in makepath)" ); exit(1); } sprintf( p, "%s/%s", path, file ); return p; } mgetty-1.1.36/conf_sf.h0100644000031200001470000000163206666313143013205 0ustar gertfax#ident "$Id: conf_sf.h,v 4.5 1999/02/24 16:05:36 gert Exp $ Copyright (c) 1994 Gert Doering" /* all (dynamic) sendfax configuration is contained in this structure. * It is initialized and loaded in conf_sf.c and accessed from sendfax.c */ extern struct conf_data_sendfax { struct conf_data ttys, ttys_0, /* for "ignore" */ modem_init, modem_handshake, modem_type, modem_quirks, fax_send_flow, fax_rec_flow, max_tries, max_tries_ctd, speed, switchbd, open_delay, ignore_carrier, dial_prefix, station_id, poll_dir, normal_res, fax_min_speed, fax_max_speed, debug, verbose, fax_poll_wanted, /* cli only (-p) */ fax_page_header, use_stdin, /* cli only (-S) */ rename_files, /* cli only (-r) */ acct_handle, /* cli only (-A) */ end_of_config; } c; int sendfax_parse_args _PROTO(( int argc, char ** argv )); void sendfax_get_config _PROTO(( char * port )); mgetty-1.1.36/conf_sf.c0100600000031200001470000001346210554072554013173 0ustar gertfax#ident "$Id: conf_sf.c,v 4.13 2006/11/22 15:40:40 gert Exp $ Copyright (c) Gert Doering" /* conf_sf.c * * configuration defaults / configuration reading code for sendfax */ #include #include #include #include "mgetty.h" #include "policy.h" #include "syslibs.h" #include "config.h" #include "conf_sf.h" extern char * mgetty_version; /* sendfax.c/version.h */ #ifndef FAX_SEND_MAX_TRIES #define FAX_SEND_MAX_TRIES 0 #endif #ifndef FAX_SEND_SWITCHBD #define FAX_SEND_SWITCHBD 0 #endif struct conf_data_sendfax c = { { "fax-devices", {0}, CT_STRING, C_EMPTY }, { "fax-devices", {0}, CT_STRING, C_IGNORE }, { "modem-init", {0}, CT_STRING, C_EMPTY }, #ifdef FAX_MODEM_HANDSHAKE { "modem-handshake", {(p_int) FAX_MODEM_HANDSHAKE}, CT_STRING, C_PRESET }, #else { "modem-handshake", {0}, CT_STRING, C_EMPTY }, #endif { "modem-type", {(p_int) DEFAULT_MODEMTYPE}, CT_STRING, C_PRESET }, { "modem-quirks", {0}, CT_INT, C_EMPTY }, { "fax-send-flow", {FAXSEND_FLOW}, CT_FLOWL, C_PRESET }, { "fax-rec-flow", {FAXREC_FLOW}, CT_FLOWL, C_PRESET }, { "max-tries", {FAX_SEND_MAX_TRIES}, CT_INT, C_PRESET }, { "max-tries-continue", {TRUE}, CT_BOOL, C_PRESET }, { "speed", {FAX_SEND_BAUD}, CT_INT, C_PRESET }, { "switchbd", {FAX_SEND_SWITCHBD}, CT_INT, C_PRESET }, { "open-delay", {0}, CT_INT, C_EMPTY }, { "ignore-carrier", {TRUE }, CT_BOOL, C_PRESET }, { "dial-prefix", {(p_int) FAX_DIAL_PREFIX}, CT_STRING, C_PRESET }, { "fax-id", {(p_int)FAX_STATION_ID}, CT_STRING, C_PRESET }, { "poll-dir", {(p_int)"."}, CT_STRING, C_PRESET }, { "normal-res", {0}, CT_BOOL, C_PRESET }, { "fax-min-speed", {0}, CT_INT, C_PRESET }, { "fax-max-speed", {14400}, CT_INT, C_PRESET }, { "debug", {LOG_LEVEL}, CT_INT, C_PRESET }, { "verbose", {FALSE}, CT_BOOL, C_PRESET }, { "" /* polling */, {FALSE}, CT_BOOL, C_PRESET }, { "page-header", {0}, CT_STRING, C_EMPTY }, { "" /* stdin */, {FALSE}, CT_BOOL, C_PRESET }, { "" /* rename */, {FALSE}, CT_BOOL, C_PRESET }, { "" /* acct_handle */, {(p_int)""}, CT_STRING, C_PRESET }, { NULL, {0}, CT_STRING, C_EMPTY }}; int sendfax_parse_args _P2( (argc,argv), int argc, char ** argv ) { int opt; char * p; /* sanity check: * make sure that structs-in-struct can be handled exactly as if * packed in array (get_config relies on it!) */ conf_data c_a[2]; if ( ( (char *)&c_a[1] - (char *)&c_a[0] ) != ( (char *)&c.ttys_0 - (char *)&c.ttys ) ) { fprintf( stderr, "ERROR: config table size mixup. contact author\n" ); exit(99); } /* since "ttys" has to be writable, we strdup() the default string */ p = malloc( sizeof( FAX_MODEM_TTYS )+1 ); if ( p == NULL ) c.ttys.flags = C_EMPTY; else { strcpy( p, FAX_MODEM_TTYS ); c.ttys.d.p = p; c.ttys.flags = C_CONF; } /* get command line arguments */ while ((opt = getopt(argc, argv, "d:vx:ph:l:nm:SC:I:rA:D:M:R:V")) != EOF) { switch (opt) { case 'd': /* set target directory for polling */ conf_set_string( &c.poll_dir, optarg ); break; case 'v': /* verbose blurb on stdout */ conf_set_bool( &c.verbose, TRUE ); break; case 'x': /* set debug level */ conf_set_int( &c.debug, atoi(optarg) ); log_set_llevel( c_int(debug) ); break; case 'p': /* activate poll receive */ conf_set_int( &c.fax_poll_wanted, TRUE ); break; case 'h': /* set header page */ conf_set_string( &c.fax_page_header, optarg ); break; case 'l': /* set device(s) to use */ if ( optarg[0] == '/' && strncmp( optarg, "/dev/", 5 ) != 0 ) { fprintf( stderr, "%s: -l: device must be located in /dev!\n", argv[0]); exit(1); } conf_set_string( &c.ttys, optarg ); break; case 'n': /* set normal resolution */ conf_set_bool( &c.normal_res, TRUE ); break; case 'm': /* modem initialization string */ conf_set_string( &c.modem_init, optarg ); break; case 'S': /* modem on stdin */ conf_set_bool( &c.use_stdin, TRUE ); break; case 'C': /* modem class */ conf_set_string( &c.modem_type, optarg ); break; case 'I': /* local fax id */ conf_set_string( &c.station_id, optarg ); break; case 'r': conf_set_bool( &c.rename_files, TRUE ); break; case 'A': conf_set_string( &c.acct_handle, optarg ); break; case 'D': conf_set_string( &c.dial_prefix, optarg ); break; case 'M': /* set max. fax speed */ conf_set_int( &c.fax_max_speed, atoi(optarg) ); break; case 'R': /* retries */ conf_set_int( &c.max_tries, atoi(optarg) ); break; case 'V': printf("\nmgetty+sendfax by Gert Doering\n%s\n\n", mgetty_version); printf("log file written to '%s'\n", FAX_LOG ); #ifdef SENDFAX_CONFIG printf("config file read from '%s'\n\n", makepath( SENDFAX_CONFIG, CONFDIR )); #endif exit(0); case '?': /* unrecognized parameter */ return ERROR; break; } } return NOERROR; } /* get sendfax configuration from file (if configured) * * if "port == NULL", read "fax-devices" (c.tty), if != NULL, skip * c.tty (because it woudln't make sense to set it, and would break * fax_open()) */ void sendfax_get_config _P1( (port), char * port ) { #ifdef SENDFAX_CONFIG if ( port == NULL ) { lprintf( L_NOISE, "reading default configuration" ); get_config( makepath( SENDFAX_CONFIG, CONFDIR ), (conf_data *)&c, "port", NULL ); } else { lprintf( L_NOISE, "reading specific data for port '%s'", port ); get_config( makepath( SENDFAX_CONFIG, CONFDIR ), ((conf_data *)&c)+1, "port", port ); } #else lprintf( L_NOISE, "not reading config file, not configured" ); #endif log_set_llevel( c_int(debug) ); if ( c_isset(modem_quirks) ) { lprintf( L_NOISE, "set modem_quirks: 0x%04x", c_int(modem_quirks)); modem_quirks = c_int(modem_quirks); } } mgetty-1.1.36/conf_mg.h0100644000031200001470000000474110341370426013174 0ustar gertfax#ident "$Id: conf_mg.h,v 4.11 2005/11/24 16:57:58 gert Exp $ Copyright (c) 1994 Gert Doering" /* all (dynamic) mgetty configuration is contained in this structure. * It is initialized and loaded in conf_mg.c and accessed from mgetty.c */ extern struct conf_data_mgetty { struct conf_data speed, /* port speed */ switchbd, /* speed switch for fax rec.*/ direct_line, /* direct lines */ blocking, /* do blocking open */ port_owner, /* "uucp" */ port_group, /* "modem" */ port_mode, /* "660" */ toggle_dtr, /* toggle DTR for modem reset */ toggle_dtr_waittime, /* time to hold DTR low */ need_dsr, /* wait for DSR+CTS */ data_only, /* no fax */ fax_only, /* no data */ modem_type, /* auto/c2.0/cls2/data */ modem_quirks, /* strange behaviourisms */ init_chat, /* modem initialization */ force_init_chat, /* for stubborn modems */ post_init_chat, /* for forgetful modems */ data_flow, /* flow ctl. in data mode */ fax_send_flow, /* '' in fax rec mode */ fax_rec_flow, /* '' in fax send mode */ modem_check_time, /* modem still alive? */ rings_wanted, /* number of RINGs */ msn_list, /* ISDN MSNs (dist.ring) */ getcnd_chat, /* get caller ID (for ELINK)*/ cnd_program, /* accept caller? */ answer_chat, /* ATA...CONNECT...""...\n */ answer_chat_timeout, /* longer as S7! */ autobauding, ringback, /* ringback enabled */ ringback_time, /* ringback time */ ignore_carrier, /* do not clear CLOCAL */ issue_file, /* /etc/issue file */ prompt_waittime, /* ms wait before prompting */ login_prompt, login_time, /* max. time to log in */ do_send_emsi, /* send EMSI_REQ string */ env_ttyprompt, /* suppress login prompt */ login_config, /* login.config file name */ station_id, /* local fax station ID */ fax_min_speed, /* minimum fax speed */ fax_max_speed, /* maximum fax sped */ fax_server_file, /* fax to send upon poll */ diskspace, /* min. free disk space */ notify_mail, /* fax mail goes to... */ fax_owner, /* "fax" */ fax_group, /* "staff" */ fax_mode, /* "660" */ fax_spool_in, /* "/var/fax/inc:/tmp" */ debug, /* log level */ statistics_chat, /* get some call statist. */ statistics_file, /* default: log file */ gettydefs_tag, termtype, /* $TERM=... */ end_of_config; } c; int mgetty_parse_args _PROTO(( int argc, char ** argv )); void mgetty_get_config _PROTO(( char * port )); mgetty-1.1.36/conf_mg.c0100644000031200001470000002314410356006656013174 0ustar gertfax#ident "$Id: conf_mg.c,v 4.18 2005/12/30 21:41:07 gert Exp $ Copyright (c) Gert Doering" /* conf_mg.c * * configuration defaults / configuration reading code for mgetty */ #include #include #include #include "mgetty.h" #include "policy.h" #include "syslibs.h" #include "tio.h" #include "config.h" #include "conf_mg.h" extern char * mgetty_version; /* mgetty.c/version.h */ #ifndef MODEM_CHECK_TIME # define MODEM_CHECK_TIME -1 /* no check */ #endif #ifndef FAX_RECV_SWITCHBD #define FAX_RECV_SWITCHBD 0 /* no switching */ #endif #ifndef FAX_FILE_MODE #define FAX_FILE_MODE -1 /* controlled by umask */ #endif /* initialize the modem - MODEM_INIT_STRING defined in policy.h */ static char * def_init_chat_seq[] = { "", "\\dATQ0V1H0", "OK", MODEM_INIT_STRING, "OK", NULL }; /* "force init" the modem (DLE ETX for voice modems, +++ATH0 for all others) */ static char * def_force_init_chat_seq[] = { "", "\\d\020\03\\d\\d\\d+++\\d\\d\\d\r\\dATQ0V1H0", "OK", NULL }; /* default way to answer the phone... */ static char * def_answer_chat_seq[] = { "", "ATA", "CONNECT", "\\c", "\n", NULL }; /* this is the default configuration... */ struct conf_data_mgetty c = { { "speed", {DEFAULT_PORTSPEED}, CT_INT, C_PRESET }, { "switchbd", {FAX_RECV_SWITCHBD}, CT_INT, C_PRESET }, { "direct", {FALSE}, CT_BOOL, C_PRESET }, { "blocking", {FALSE}, CT_BOOL, C_PRESET }, { "port-owner", {(p_int) DEVICE_OWNER}, CT_STRING, C_PRESET }, #ifdef DEVICE_GROUP { "port-group", {(p_int) DEVICE_GROUP}, CT_STRING, C_PRESET }, #else { "port-group", {0}, CT_STRING, C_EMPTY }, #endif { "port-mode", {FILE_MODE}, CT_INT, C_PRESET }, { "toggle-dtr", {TRUE}, CT_BOOL, C_PRESET }, { "toggle-dtr-waittime", {500}, CT_INT, C_PRESET }, { "need-dsr", {FALSE}, CT_BOOL, C_PRESET }, { "data-only", {FALSE}, CT_BOOL, C_PRESET }, { "fax-only", {FALSE}, CT_BOOL, C_PRESET }, { "modem-type", {(p_int) DEFAULT_MODEMTYPE}, CT_STRING, C_PRESET }, { "modem-quirks", {0}, CT_INT, C_EMPTY }, { "init-chat", {0}, CT_CHAT, C_EMPTY }, { "force-init-chat", {0}, CT_CHAT, C_EMPTY }, { "post-init-chat", {0}, CT_CHAT, C_EMPTY }, { "data-flow", {DATA_FLOW}, CT_FLOWL, C_PRESET }, { "fax-send-flow", {FAXSEND_FLOW}, CT_FLOWL, C_PRESET }, { "fax-rec-flow", {FAXREC_FLOW}, CT_FLOWL, C_PRESET }, { "modem-check-time", {MODEM_CHECK_TIME}, CT_INT, C_PRESET }, { "rings", {1}, CT_INT, C_PRESET }, { "msn-list", {(p_int) NULL}, CT_CHAT, C_EMPTY }, { "get-cnd-chat", {0}, CT_CHAT, C_EMPTY }, { "cnd-program", {(p_int) NULL}, CT_STRING, C_EMPTY }, { "answer-chat", {0}, CT_CHAT, C_EMPTY }, { "answer-chat-timeout", {80}, CT_INT, C_PRESET }, { "autobauding", {FALSE}, CT_BOOL, C_PRESET }, { "ringback", {FALSE}, CT_BOOL, C_PRESET }, { "ringback-time", {30}, CT_INT, C_PRESET }, { "ignore-carrier", {FALSE}, CT_BOOL, C_PRESET }, { "issue-file", {(p_int)"/etc/issue"}, CT_STRING, C_PRESET }, { "prompt-waittime", {500}, CT_INT, C_PRESET }, { "login-prompt", {(p_int) LOGIN_PROMPT}, CT_STRING, C_PRESET }, #ifdef MAX_LOGIN_TIME { "login-time", {MAX_LOGIN_TIME}, CT_INT, C_PRESET }, #else { "login-time", {0}, CT_INT, C_EMPTY }, #endif { "fido-send-emsi", {TRUE}, CT_BOOL, C_PRESET }, { "login-env-ttyprompt-hack", {FALSE}, CT_BOOL, C_PRESET }, #ifdef LOGIN_CFG_FILE { "login-conf-file", {(p_int) LOGIN_CFG_FILE}, CT_STRING, C_PRESET }, #else { "login-conf-file", {0}, CT_STRING, C_EMPTY }, #endif { "fax-id", {(p_int)FAX_STATION_ID}, CT_STRING, C_PRESET }, { "fax-min-speed", {0}, CT_INT, C_PRESET }, { "fax-max-speed", {14400}, CT_INT, C_PRESET }, { "fax-server-file", {0}, CT_STRING, C_EMPTY }, { "diskspace", {MINFREESPACE}, CT_INT, C_PRESET }, #ifdef MAIL_TO { "notify", {(p_int)MAIL_TO}, CT_STRING, C_PRESET }, #else { "notify", {0}, CT_STRING, C_EMPTY }, #endif { "fax-owner", {(p_int)FAX_IN_OWNER}, CT_STRING, C_PRESET }, #ifdef FAX_IN_GROUP { "fax-group", {(p_int)FAX_IN_GROUP}, CT_STRING, C_PRESET }, #else { "fax-group", {0}, CT_STRING, C_EMPTY }, #endif { "fax-mode", {FAX_FILE_MODE}, CT_INT, C_PRESET }, #ifdef __STDC__ { "fax-spool-in", {(p_int) FAX_SPOOL_IN ":/tmp"}, CT_STRING, C_PRESET }, #else { "fax-spool-in", {(p_int) FAX_SPOOL_IN}, CT_STRING, C_PRESET }, #endif { "debug", {LOG_LEVEL}, CT_INT, C_PRESET }, { "statistics-chat", {0}, CT_CHAT, C_EMPTY }, { "statistics-file", {0}, CT_STRING, C_EMPTY }, { "gettydefs", {(p_int)GETTYDEFS_DEFAULT_TAG}, CT_STRING, C_PRESET }, { "term", {0}, CT_STRING, C_EMPTY }, { NULL, {0}, CT_STRING, C_EMPTY }}; /* * exit_usage() - exit with usage display */ void exit_usage _P1((code), int code ) { #ifdef USE_GETTYDEFS lprintf( L_FATAL, "Usage: mgetty [-x debug] [-s speed] [-r] line [gettydefentry]" ); #else lprintf( L_FATAL, "Usage: mgetty [-x debug] [-s speed] [-r] line" ); #endif exit(code); } int mgetty_parse_args _P2( (argc,argv), int argc, char ** argv ) { int opt; #ifdef USE_GETTYDEFS extern boolean verbose; #endif /* sanity check: * make sure that structs-in-struct can be handled exactly as if * packed in array (get_config relies on it!) */ conf_data c_a[2]; if ( ( (char *)&c_a[1] - (char *)&c_a[0] ) != ( (char *)&c.switchbd - (char *)&c.speed ) ) { fprintf( stderr, "ERROR: config table size mixup. contact author\n" ); exit(99); } /* initialize a few things that can't be done statically */ c.init_chat.d.p = (void *) def_init_chat_seq; c.init_chat.flags = C_PRESET; c.force_init_chat.d.p = (void *) def_force_init_chat_seq; c.force_init_chat.flags = C_PRESET; c.answer_chat.d.p = (void *) def_answer_chat_seq; c.answer_chat.flags = C_PRESET; /* get command line arguments */ /* some magic done by the command's name */ if ( strcmp( get_basename( argv[0] ), "getty" ) == 0 ) { conf_set_bool( &c.blocking, TRUE ); conf_set_bool( &c.direct_line, TRUE ); } while ((opt = getopt(argc, argv, "c:x:s:rp:n:R:i:DC:FS:k:m:I:baV")) != EOF) { switch (opt) { case 'c': /* check */ #ifdef USE_GETTYDEFS verbose = TRUE; dumpgettydefs(optarg); exit(0); #else lprintf( L_FATAL, "gettydefs not supported\n"); exit_usage(2); #endif case 'k': /* kbytes free on disk */ conf_set_int( &c.diskspace, atol(optarg) ); break; case 'x': /* log level */ conf_set_int( &c.debug, atoi(optarg) ); log_set_llevel( c_int(debug) ); break; case 's': /* port speed */ conf_set_int( &c.speed, atoi(optarg) ); break; case 'r': /* direct line (nullmodem) */ conf_set_int( &c.direct_line, TRUE ); break; case 'p': /* login prompt */ conf_set_string( &c.login_prompt, optarg ); break; case 'n': /* ring counter */ conf_set_int( &c.rings_wanted, atoi(optarg) ); break; case 'R': /* ringback timer */ conf_set_bool( &c.ringback, TRUE ); conf_set_int( &c.ringback_time, atoi(optarg) ); break; case 'i': /* use different issue file */ conf_set_string( &c.issue_file, optarg ); break; case 'D': /* switch off fax */ conf_set_bool( &c.data_only, TRUE ); break; case 'F': /* switch off data-mode (security!) */ conf_set_bool( &c.fax_only, TRUE ); break; case 'C': /* set modem mode (fax/data) */ conf_set_string( &c.modem_type, optarg ); break; case 'S': /* fax poll file to send */ conf_set_string( &c.fax_server_file, optarg ); break; case 'I': /* local station ID */ conf_set_string( &c.station_id, optarg); break; case 'b': /* open port in blocking mode */ conf_set_bool( &c.blocking, TRUE ); break; case 'a': /* autobauding */ conf_set_bool( &c.autobauding, TRUE ); break; case 'm': /* modem init sequence */ c.init_chat.flags = C_OVERRIDE; c.init_chat.d.p = conf_get_chat( optarg ); break; case 'V': /* show version number */ printf("\nmgetty+sendfax by Gert Doering\n%s\n\n", mgetty_version); printf("log file written to '"); printf(LOG_PATH, ""); #ifdef MGETTY_CONFIG printf("'\nconfig file read from '%s", makepath( MGETTY_CONFIG, CONFDIR )); #endif printf("'\n\n"); exit(0); case '?': exit_usage(2); break; } } return NOERROR; } /* get mgetty configuration from file (if configured) */ void mgetty_get_config _P1( (port), char * port ) { #ifdef MGETTY_CONFIG lprintf( L_NOISE, "reading configuration data for port '%s'", port ); get_config( makepath( MGETTY_CONFIG, CONFDIR ), (conf_data *)&c, "port", port ); #else lprintf( L_NOISE, "not reading config file, not configured" ); #endif /* tell log subsystem about new log level */ log_set_llevel( c_int(debug) ); /* tell getdisk.c about desired disk space (in kbytes) */ minfreespace = c_int(diskspace); /* sanity checks */ if ( tio_check_speed( c_int(speed) ) < 0 ) { lprintf( L_FATAL, "invalid port speed: %d", c_int(speed)); exit_usage(2); } if ( c_isset(switchbd) && c_int(switchbd) != 0 && !c_bool(data_only) && tio_check_speed( c_int(switchbd) ) < 0 ) { lprintf( L_FATAL, "invalid fax reception switch speed: %d", c_int(switchbd) ); exit_usage(2); } if ( c_int(rings_wanted) == 0 ) conf_set_int( &c.rings_wanted, 1 ); if ( c_int(ringback_time) < 30 ) conf_set_int( &c.ringback_time, 30); if ( c_int(modem_check_time) >= 0 && c_int(modem_check_time) < 900 ) { lprintf( L_NOISE, "increasing modem_check_time to 900 sec." ); conf_set_int( &c.modem_check_time, 900 ); } if ( c_isset(modem_quirks) ) { lprintf( L_NOISE, "set modem_quirks: 0x%04x", c_int(modem_quirks)); modem_quirks = c_int(modem_quirks); } } mgetty-1.1.36/cnd.c0100644000031200001470000001751310230447277012332 0ustar gertfax#ident "@(#)cnd.c $Id: cnd.c,v 4.26 2005/04/17 11:55:43 gert Exp $ Copyright (c) 1993 Gert Doering/Chris Lewis" #include #include #include #include #include "syslibs.h" #include "policy.h" #include "mgetty.h" #include "config.h" char *Connect = ""; char *CallerId = "none"; char *CallTime = ""; char *CallName = ""; char *CalledNr = ""; /* dialed number [ISDN MSN] */ /* the next few are for Rockwell */ char *CallDate = ""; char *CallMsg1 = ""; char *CallMsg2 = ""; /* those are for Rockwell "CONNECT" messages */ static char * cnd_carrier = ""; static char * cnd_protocol= ""; struct cndtable { char *string; char **variable; }; struct cndtable cndtable[] = { /* for the ELSA MicroLink/TLV.34: "RING;08912345;08765, ATS153=6 */ {"RING;", &CallerId}, {"RING"}, /* speedups */ {"OK"}, /* speedups */ {"CONNECT ", &Connect}, /* ZyXEL 1496 */ {"CALLER NAME: ", &CallName}, {"CALLER NUMBER: ", &CallerId}, {"TIME: ", &CallTime}, {"REASON FOR NO CALLER NUMBER: ", &CallerId}, {"REASON FOR NO CALLER NAME: ", &CallName}, /* isdn4linux (2.4.10 or patched) - Jan Oberlaender, mindriot@gmx.net */ {"CALLED NUMBER: ", &CalledNr}, /* for the ZyXEL 2864(D)I: "FM:xxx TO:yyy" */ {"FM:", &CallerId}, /* those are for rockwell-based modems insisting on a multi-line message "CARRIER ... / PROTOCOL ... / CONNECT" */ {"CARRIER ", &cnd_carrier}, {"PROTOCOL: ", &cnd_protocol}, /* ELSA does it similarily (if AT+MR=1 is set) */ {"+MCR: ", &cnd_carrier}, {"+MRR: ", &cnd_protocol}, /* those are for Rockwell Caller ID */ {"DATE = ", &CallDate}, {"TIME = ", &CallTime}, {"NMBR = ", &CallerId}, {"NAME = ", &CallName}, {"MESG = ", &CallMsg1}, {"MESG = ", &CallMsg2}, /* some Rockwell chips intro the Caller ID as follows */ /* (contributed by Edmund Bacon, ebacon@onesystem.com) */ {"DDN_NMBR= ", &CallerId}, /* The Digi DataFire RAS reports this different again... */ /* (reported by Akiko Takahashi ) */ /* also for the Zoom 2949L, K C Yuen */ /* also used by ELSA MicroLink Office */ {"DATE=", &CallDate}, {"TIME=", &CallTime}, {"NMBR=", &CallerId}, {"NAME=", &CallName}, /* Digi DataFire RAS / Patton 2977 can also report dialed number */ /* (if AT#CID=10 is set, contributed by Edwin Groothuis) */ {"NDID=", &CalledNr}, /* yet another incompatible modem... */ {"CALLER'S NUMBER: ", &CallerId}, /* Kortex Adaptix 56000 (Quercia Michel, quercia@cal.enst.fr) */ {"NBR=", &CallerId}, /* Russian USR Courier V.everything hackware, Alexey Promokhov */ {"CallerID: ", &CallerId}, /* Swedish Telia/ZyXEL Omni 52k - Torulf Lundgren, torulf@upsys.se */ {"Diverting number:", &CallerId}, /* FALCOM A2D gsm modem - Andreas Barth, debian bug */ {"+CLIP: ", &CallerId}, {NULL} }; void cndfind _P1((str), char *str) { struct cndtable *cp; register int len; register char *p; /* strip off blanks */ while (*str && isspace(*str)) str++; p = str + strlen(str) - 1; while(p >= str && isspace(*p)) *p-- = '\0'; lprintf(L_JUNK, "CND: %s", str); /* The ELINK 301 ISDN modem can send us the caller ID if it is asked for it with AT\O. The CID will simply get sent on a single line consisting only of digits. So, if we get a line starting with a digit, let's assume that it's the CID... */ if ( isdigit(*str) ) { CallerId = p = strdup(str); while( isdigit(*p) ) p++; *p = 0; lprintf( L_NOISE, "CND: ELink caller ID: '%s'", CallerId ); return; } for (cp = cndtable; cp->string; cp++) { len = strlen(cp->string); if (strncmp(cp->string, str, len) == 0) { if (!cp->variable) return; /* special case: Rockwell sends *two* MESG=... lines */ if (cp->variable == &CallMsg1 && CallMsg1[0] != 0) continue; /* special case for CONNECT on Rockwell-Based modems */ if ( ( cnd_carrier[0] != 0 || cnd_protocol[0] != 0 ) && strncmp( str, "CONNECT ", 8 ) == 0 ) { *(cp->variable) = malloc( strlen(str) - len + strlen( cnd_carrier ) + strlen( cnd_protocol ) + 5 ); sprintf( *(cp->variable), "%s/%s %s", str+len, cnd_carrier, cnd_protocol ); } else /* normal case */ { *(cp->variable) = p = malloc(strlen(str) - len + 1); (void) strcpy(*(cp->variable), str+len); /* nuke quotes and non-printable characters (some of this * stuff is passed to shell commands and environment vars) */ while( *p != '\0' ) { if ( *p == '\'' || *p == '\"' || !isprint(*p) ) *p = ' '; p++; } } lprintf(L_JUNK, "CND: found: %s", *(cp->variable)); return; } } } /* process Rockwell-style caller ID. Weird */ void process_rockwell_mesg _P0 (void) { int length = 0; int loop; char *p; /* In Canada, Bell Canada has come up with a fairly odd method of encoding the caller_id into MESG fields. With Supra caller ID (Rockwell), these come out as follows: MESG = 030735353531323132 The first two bytes seem to mean nothing. The second two bytes are a hex number representing the phone number length. The phone number begins with the digit 3, then each digit of the phone number. Each digit of the phone number is preceeded by the character '3'. NB: I'm not sure whether this is Bell's or Rockwell's folly. I'd prefer to blaim Rockwell. gert */ if ( CallMsg1[0] == 0) return; if ( (CallMsg1[0] != '0') || (CallMsg1[1] != '3')) return; /* Get the length of the number */ CallMsg1[4] = '\0'; sscanf( &CallMsg1[2], "%x", &length); lprintf(L_JUNK, "CND: number length: %d",length); /* Allocate space for the new number */ p = CallerId = malloc(length + 1); /* Get the phone number only and put it into CallerId */ for (loop = 5; loop <= (3 + length*2); loop += 2) { *p = CallMsg1[loop]; p++; } *p = 0; lprintf(L_JUNK, "CND: caller ID: %s", CallerId); } /* lookup Caller ID in CNDFILE, decide upon answering or not */ int cndlookup _P0 (void) { int match = 1; #ifdef CNDFILE FILE *cndfile; char buf[BUFSIZ]; cndfile = fopen( makepath( CNDFILE, CONFDIR ), "r"); if ( cndfile == NULL ) return(1); process_rockwell_mesg(); /* parse ugly rockwell msg */ lprintf(L_JUNK, "CND: check no: '%s'", CallerId ); while (fgets(buf, sizeof(buf), cndfile)) { register char *p = buf, *p2; while(isspace(*p)) p++; if (*p == '#' || *p == '\n') continue; while( (p2 = strtok(p, " \t\n,")) != NULL ) { match = (*p2 != '!'); if (!match) p2++; lprintf(L_JUNK, "CND: check vs: %s", p2); if (strcmp(p2, "all") == 0) goto leave; if (strncmp(p2, CallerId, strlen(p2)) == 0) goto leave; p = NULL; } } match = 1; leave: fclose(cndfile); #endif return(match); } /* check Caller ID via external program call */ int cnd_call _P3((name, tty, dist_ring), char * name, char * tty, int dist_ring ) { char * program; int rc; program = malloc( strlen(name) + strlen(tty) + strlen( CallerId ) + strlen( CalledNr ) + strlen( CallName ) + sizeof( CONSOLE ) + 50 ); if ( program == NULL ) { lprintf( L_ERROR, "cnd_call: can't malloc" ); return 0; } sprintf( program, "%s %s '%s' '%s' %d '%s' >%s 2>&1 >8; } mgetty-1.1.36/getdisk.c0100644000031200001470000002410110143751263013203 0ustar gertfax#ident "@(#)getdisk.c $Id: getdisk.c,v 4.4 2004/11/08 20:10:27 gert Exp $ Copyright (c) 1994 Elegant Communications Inc." /* This software is graciously provided by Elegant Communications Inc., on the proviso that it is only used in Gert Doering's mgetty+sendfax program. getdiskstats() - disk partition statistics function. The key to configuration is choosing the right one of the following five types: BSDSTATFS - BSD/hp-ux/SunOS/Dynix/vrios/OSF-1 2-parameter statfs() ULTRIXSTATFS - Ultrix wacko statfs SVR4 - SVR4 statvfs() SVR3 - SVR3/88k/Apollo 4-parameter statfs() USTAT - ustat(), no statfs etc. The first section of code uses symbolic names to indicate which platform needs which type of partition grabbing. In mgetty, this source will automatically choose the right variant with ISC, AIX, HP/UX, 3b1, sun and linux (I hope). If your system doesn't automatically select by itself, try defining the "v*" macro from below that seems closest to your system. For example, if you have a 3b2, insert "vu3b2" into CCFLAGS in the top-level makefile. If you succeed, please let us know: which "v*" macro you used, and whether your C compiler predefines a macro designating your system. Eg: HP/UX predefines "__hpux" - instead of a "vhpux" macro, we key on "__hpux". If all else fails, try USTAT which is fairly generic, but doesn't return as much information as stat[v]fs does. getdiskstats(char * path, mntinf *mi) path: pointer to file on partition to be statfs/ustat'd mi: pointer to mntinf structure that will filled to contain the partition statistics of the partition that has file "path". returns: 0 on success. */ #include #include "policy.h" #include "mgetty.h" /* some systems define this in an include file somewhere below, and mgetty.h defines it as well. So just #undef it, we don't need it here anyway */ #undef MAXPATH /* for the most part, these defines are simply used to show which systems need which type of statfs/ustat(). They can all be removed if the correct one of the 5 selectors is chosen (say) in Makefile. There are, after these defines, a few more #ifs that further figure out inclusions and other things where the 5 selectors themselves are inadequate - in many cases, they'll just turn out to be the defines that they use on their systems already. For example, "vu3b2" is just our jargon for a 3b2. */ #if defined(vmiti) || defined(vtandem) || defined(vmips) || defined(ISC) || \ defined(M_UNIX) || defined(m88k) || \ defined(vm68k) || defined(vu3b2) || \ defined(vxps) || defined(vu6050) || defined(vs5k80) || \ defined(vs5k50) || defined(vdpx2) || defined(vdynptx) || \ defined(venc) # define SVR3 #endif #if defined(vpyr) || defined(vsnxdyn) || defined(__hpux) || defined(vdynix) || \ defined(vaix) || defined(_AIX) || defined(vaixps2) || defined(sunos4) || \ defined(linux) || defined(__osf__) || defined(BSD) # define BSDSTATFS /* as used from the att universe of Pyramid! :-) */ #endif /* If your system is SVR4, the mgetty+sendfax Makefile should already predefine SVR4 */ #if defined(vdrs) || defined(vdrs6k) || defined(vdcosx) || defined(vamiga) || \ defined(vnecews) || defined(vnecup) || defined(vnecnpx) || \ defined(vsnx386) || defined(vsnxmips) || defined(vsolaris) # define SVR4 #endif #ifdef ultrix # define ULTRIXSTATFS #endif #if defined(_3B1_) # define USTAT #endif /* imported from NetBSD pkgsrc */ #if defined(__NetBSD__) && (__NetBSD_Version__ > 200030000) #undef BSDSTATFS #define SVR4 #endif #if defined(SVR4) # define SVR3 #endif #if defined(BSDSTATFS) || defined(ULTRIXSTATFS) || \ defined(SVR3) || defined(SVR4) || defined(USTAT) # define HASDISKSTAT #endif /* END OF STATFS type fiddling */ /* this is the beginning of getdiskstats() proper */ #ifdef ULTRIXSTATFS # include #endif #ifdef HASDISKSTAT # if !defined(vsnxdyn) && !defined(vdomain) && !defined(_AIX) # include # include # include # endif # ifdef BSDSTATFS # ifdef _AIX # include # else # ifdef __osf__ # include # else # if !defined(BSD) || defined(NeXT) # include # endif /* !BSD */ # endif /* !__osf__ */ # endif /* _AIX */ # define MYSTATFS(a,b) statfs(a,b) # define STATFSS statfs # else /* !BSDSTATFS */ # ifdef ULTRIXSTATFS /* oh grotty, oh stupid, oh-nonstandard one */ # define MYSTATFS(a,b) statfs(a,b) # define STATFSS fs_data # define f_bavail fd_req.bfreen # define f_ffree fd_req.gfree # define f_bfree fd_req.bfree # define f_frsize fd_req.bsize # define f_bsize fd_req.bsize # define f_blocks fd_req.btot # define f_files fd_req.gtot # else # ifdef USTAT # include # include # define STATFSS ustat # define MYSTATFS(a,b) (stat(a, &stb) == 0 ? ustat(stb.st_dev, b) : -1) # define f_bfree f_tfree # define f_bavail f_tfree # define f_ffree f_tinode # endif # ifdef SVR4 # include # define STATFSS statvfs # define MYSTATFS(a,b) statvfs(a,b) # else # if defined(SVR3) || defined(vdomain) /* eg: Apollo/88k */ # include # include # define f_bavail f_bfree # define STATFSS statfs # define MYSTATFS(a,b) statfs(a,b,sizeof(struct STATFSS),0) # endif /* SVR3 */ # endif /* SVR4 */ # endif /* ULTRIXSTATFS */ # endif /* BSDSTATFS */ #endif /* HASDISKSTAT */ long minfreespace = MINFREESPACE; /* returns how many "minfreesize" hunks will fit onto the freespace left on the partition that contains "path". Ie: if you have 2.5Mb free, and minfreespace is 1Mb, you get back "2". */ #ifndef TESTDISK int checkspace _P1 ((path), char *path) { #ifdef HASDISKSTAT struct mountinfo mi; unsigned int kbytes; if (getdiskstats(path, &mi)) return(1); /* the "shift" stuff is actually a division by 1024, to get "kbytes" * instead of bytes. But if we do it that way, we risk 32bit overflows * on disks > 4G, or "0" if mi_bsize is 512 or 256. */ kbytes = (mi.mi_bavail>>2) * (mi.mi_bsize>>8); lprintf( L_NOISE, "%d Mb free on %s", kbytes/1024, path ); return( kbytes / minfreespace); #else return(1); #endif } #endif /* All of the configuration crap above is simply so that this function compiles. Returns 0 on success, 1 otherwise. a "mntinf" structure is passed back containing the stat[v]fs/ustat information on the partition containing "path". */ int getdiskstats _P2 ((path, mi), char *path, mntinf *mi) { #ifdef HASDISKSTAT struct STATFSS info; #ifdef USTAT struct stat stb; #endif if (MYSTATFS(path, &info) < 0) { return(1); } /* Systems known to lie & have NBPSCTR */ #if defined(ISC) || defined(M_UNIX) || defined(m88k) /* * Interactive 1.0.6 lies - it says bsize is 1024, but returns a frag * size of zero instead of 512. NBPSCTR (Number of Bytes per Physical * SeCToR) is defined as 512 in . This "bug" is probably * due to 386/ix 1.0.6's default to only support 1024 byte filesystems * (FsTYPE == 2), both in the kernel, and out, in which case BSIZE is * 1024 too! (Smarter systems define FsTYPE to 3 outside of the kernel.) * * SCO Unix 3.2.2 also lies. */ mi->mi_bsize = (info.f_frsize > 0) ? info.f_frsize : NBPSCTR; #else # if defined(vmips) || defined(USTAT) /* * Mips 4.52 also lies - it claims bsize and frsize both as 1024, but * it still uses a block size of 512 when reporting total/free blocks. */ /* * classic SVR2 ustat() implementations have no block size in the * ustat structure, but has NBPSCTR in sys/param.h */ mi->mi_bsize = NBPSCTR; # else /* Systems that don't define f_frsize at all * OR give a meaningless value. */ # if defined(BSDSTATFS) || defined(m88k) mi->mi_bsize = info.f_bsize; # else /* if frag size is given, it is the units for blocks * otherwise, it is either bsize or somebody is running * old code that lies */ mi->mi_bsize = (info.f_frsize > 0) ? info.f_frsize : info.f_bsize; # endif # endif #endif /* * WARNING: on some systems (vrios & SVR4) the value for f_frsize (or * f_bsize) may be correct for the remote system's real filesystem when * used over NFS, but almost every NFS implementation will only return * f_bfree (and f_bavail) in units of 1 Kb blocks and usually return -1 * for f_files and f_ffree. XRSAdf doesn't really have to be concerned * with this inconsistancy, though the eXpert handler must be careful. */ #ifdef USTAT mi->mi_blocks = mi->mi_files = -1; #else mi->mi_blocks = info.f_blocks; mi->mi_files = info.f_files; #endif /* USTAT */ mi->mi_bfree = info.f_bfree; mi->mi_bavail = info.f_bavail; /* may be duplicate of f_bfree */ mi->mi_ffree = info.f_ffree; return(0); #else return(-1); #endif /* STATFS */ } /* Test program */ #ifdef TESTDISK #if ! defined(HASDISKSTAT) #include "ERROR: don't know how to get fs info - see Makefile for defines" #endif int main(argc, argv) int argc; char **argv; { struct mountinfo mi; argv++; printf("%s personality\n", #ifdef USTAT "ustat()" #endif #ifdef ULTRIXSTATFS "ultrix statfs()" #endif #ifdef BSDSTATFS "BSD statfs()" #endif #ifdef SVR3 "SVR3 4parameter statfs()" #endif #ifdef SVR4 "SVR4 statvfs()" #endif ); while(*argv) { if (getdiskstats(*argv, &mi)) { fprintf(stderr, "statfs on %s failed\n", *argv); } else { printf( "STATFS report on %s:\n", *argv ); printf( "\tfundamental file system block size %ld\n", mi.mi_bsize); printf( "\ttotal data blocks in file system %ld\n", mi.mi_blocks); printf( "\tfree block in fs %ld\n", mi.mi_bfree); printf( "\tfree blocks avail to non-superuser %ld\n", mi.mi_bavail); printf( "\ttotal file nodes in file system %ld\n", mi.mi_files); printf( "\tfree file nodes in fs %ld\n", mi.mi_ffree); } argv++; } exit(0); } #endif mgetty-1.1.36/mksed.c0100644000031200001470000000426010210332172012645 0ustar gertfax#ident "$Id: mksed.c,v 4.10 2005/02/27 11:52:26 gert Exp $ Copyright (c) Gert Doering" #include #include "mgetty.h" #include "policy.h" #ifndef MAIL_TO # define MAIL_TO "root" #endif int main _P0( void ) { printf( "sed \\\n" ); printf( " -e 's;@ADMIN@;%s;g'\\\n", ADMIN ); printf( " -e 's;@FAX_SPOOL@;%s;g'\\\n", FAX_SPOOL ); printf( " -e 's;@FAX_SPOOL_IN@;%s;g'\\\n", FAX_SPOOL_IN ); printf( " -e 's;@FAX_SPOOL_OUT@;%s;g'\\\n", FAX_SPOOL_OUT ); printf( " -e 's;@FAX_OUT_USER@;%s;g'\\\n", FAX_OUT_USER ); printf( " -e 's;@VARRUNDIR@;%s;g'\\\n", VARRUNDIR ); printf( " -e 's;@FAX_MODEM_TTYS@;%s;g'\\\n", FAX_MODEM_TTYS ); printf( " -e 's;@FAX_STATION_ID@;%s;g'\\\n", FAX_STATION_ID ); printf( " -e 's;@FAX_LOG@;%s;g'\\\n", FAX_LOG ); printf( " -e 's;@LOG_LEVEL@;%d;g'\\\n", LOG_LEVEL ); printf( " -e 's;@LOG_PATH@;"); printf( LOG_PATH, "ttyxx" ); printf( ";g'\\\n" ); printf( " -e 's;@NOLOGIN@;" ); printf( NOLOGIN_FILE, "ttyxx" ); printf( ";g'\\\n" ); printf( " -e 's;@KVG_PID_FILE@;%s/mgetty.pid.$TTY;g'\\\n", VARRUNDIR); #ifdef SVR4 printf( " -e 's;@LOCK@;%s/LK.iii.jjj.kkk;g'\\\n", LOCK_PATH ); #else printf( " -e 's;@LOCK@;"); printf( LOCK, "ttyxx" ); printf( ";g'\\\n" ); #endif printf( " -e \"s;@MAILER@;%s;g\"\\\n", MAILER ); printf( " -e 's;@FAX_ADMIN@;%s;g'\\\n", MAIL_TO ); printf( " -e 's;@SPEED@;%d;g'\\\n", DEFAULT_PORTSPEED ); printf( " -e 's;@AWK@;%s;g'\\\n", AWK ); printf( " -e 's;@PERL@;%s;g'\\\n", PERL ); printf( " -e 's;@TKPERL@;%s;g'\\\n", TKPERL ); printf( " -e 's;@ECHO@;%s;g'\\\n", ECHO ); printf( " -e 's;@SHELL@;%s;g'\\\n", SHELL ); printf( " -e 's;@TRAP_OFF@;trap%s;g'\\\n", SHELL_TRAP_POSIX? " -": "" ); printf( " -e 's;@BINDIR@;%s;g'\\\n", BINDIR ); printf( " -e 's;@SBINDIR@;%s;g'\\\n", SBINDIR ); printf( " -e 's;@LIBDIR@;%s;g'\\\n", LIBDIR ); printf( " -e 's;@CONFDIR@;%s;g'\\\n", CONFDIR ); printf( " -e 's;@LOGIN@;%s;g'\n", DEFAULT_LOGIN_PROGRAM ); return 0; } mgetty-1.1.36/utmp.c0100644000031200001470000001113607407472415012552 0ustar gertfax#ident "$Id: utmp.c,v 4.4 2001/12/17 22:43:24 gert Exp $ Copyright (c) Gert Doering" /* some parts of the code (writing of the utmp entry) * is based on the "getty kit 2.0" by Paul Sutcliffe, Jr., * paul@devon.lns.pa.us, and are used with permission here. */ #include "mgetty.h" #if defined(sunos4) || defined(BSD) #include #include #include #else /* !BSD */ #include #include #include #include #include #include #ifndef ENOENT #include #endif #if defined(_3B1_) || defined(MEIBE) || defined(ISC) typedef short pid_t; #endif #endif #include "mg_utmp.h" #ifndef UTMP_FILE # ifdef _PATH_UTMP # define UTMP_FILE _PATH_UTMP /* FreeBSD and NetBSD */ # else # define UTMP_FILE "/etc/utmp" /* SunOS and NeXT */ # endif #endif #if defined(sunos4) || defined(BSD) || defined(ultrix) /* on SunOS (and other BSD-derived systems), the getty process does * * not have to care for the utmp entries, login and init do all the work * Anyway, we have to _read_ it to get the number of users logged in. */ void make_utmp_wtmp _P4( (line, ut_type, ut_user, ut_host), char * line, short ut_type, char * ut_user, char * ut_host ) { /* On BSD systems, everything works a bit differently. * UT_INIT and UT_LOGIN entries are ignored (init and login do all * the work), UT_USER is set via the login() function (in libutil.a). * [NB: If we wanted to set UT_INIT, it would have to be an entry with * empty ut_name and ut_host] */ #if defined(__FreeBSD__) || defined(__NetBSD__) struct utmp utmp; extern void login _PROTO(( struct utmp * utmp )); bzero( (void*) &utmp, sizeof(utmp) ); if ( ut_type == UT_USER ) { utmp.ut_time = time(NULL); strncpy( utmp.ut_name, ut_user, sizeof(utmp.ut_name) ); strncpy( utmp.ut_line, line, sizeof(utmp.ut_line) ); if ( ut_host != NULL ) strncpy( utmp.ut_host, ut_host, sizeof(utmp.ut_host) ); login( &utmp ); } lprintf(L_NOISE, "utmp + wtmp entry made"); #endif /* __FreeBSD__ */ } int get_current_users _P0(void) { struct utmp utmp; FILE *fp; int Nusers = 0; fp = fopen( UTMP_FILE, "r"); if ( fp == NULL ) { lprintf(L_ERROR, "get_cu: %s", UTMP_FILE ); return 0; } while ( fread( &utmp, sizeof(utmp), 1, fp ) == 1 ) { if ( utmp.ut_name[0] != 0 && utmp.ut_line[0] != 0 ) Nusers++; } fclose(fp); return Nusers; } #else /* System V style utmp handling */ void make_utmp_wtmp _P4( (line, ut_type, ut_user, ut_host), char * line, short ut_type, char * ut_user, char * ut_host ) { struct utmp *utmp; pid_t pid; struct stat st; FILE * fp; pid = getpid(); lprintf(L_JUNK, "looking for utmp entry... (my PID: %d)", pid); while ((utmp = getutent()) != (struct utmp *) NULL) { if (utmp->ut_pid == pid && (utmp->ut_type == INIT_PROCESS || utmp->ut_type == LOGIN_PROCESS)) { strcpy(utmp->ut_line, line ); utmp->ut_time = time( NULL ); utmp->ut_type = ut_type; /* {INIT,LOGIN,USER}_PROCESS */ /* "LOGIN", "uugetty", "dialout" */ strncpy( utmp->ut_user, ut_user, sizeof( utmp->ut_user ) ); #if defined(SVR4) || defined(linux) if (ut_host != NULL) { strncpy( utmp->ut_host, ut_host, sizeof( utmp->ut_host ) - 1); # ifdef solaris2 /* Solaris 2.x */ utmp->ut_syslen = strlen(utmp->ut_host) + 1; # endif } #endif /* SVR4 */ #if defined(M_UNIX) || defined(__GLIBC__) if ( pututline(utmp) == NULL ) { lprintf( L_ERROR, "cannot create utmp entry" ); } #else /* Oh god, how I hate systems declaring functions as void... */ pututline( utmp ); #endif /* write same record to end of wtmp * if wtmp file exists */ #ifdef SVR4 updwtmpx(WTMPX_FILE, utmp); #else # if defined(__GLIBC__) && __GLIBC__ >= 2 updwtmp(WTMP_FILE, utmp); # else if (stat(WTMP_FILE, &st) && errno == ENOENT) break; if ((fp = fopen(WTMP_FILE, "a")) != (FILE *) NULL) { (void) fseek(fp, 0L, SEEK_END); (void) fwrite((char *)utmp,sizeof(*utmp),1,fp); (void) fclose(fp); } # endif /* GNU Libc 2.x */ #endif /* !SVR4 */ lprintf(L_NOISE, "utmp + wtmp entry made"); break; } } endutent(); } int get_current_users _P0(void) { struct utmp * utmp; int Nusers = 0; setutent(); while ((utmp = getutent()) != (struct utmp *) NULL) { if (utmp->ut_type == USER_PROCESS) { Nusers++; /*lprintf(L_NOISE, "utmp entry (%s)", utmp->ut_name); */ } } endutent(); return Nusers; } #endif /* !sunos4, !BSD, !ultrix */ mgetty-1.1.36/mg_utmp.h0100644000031200000620000000300606266175366013620 0ustar gertgroup#ident "$Id: mg_utmp.h,v 4.1 1997/01/12 14:53:42 gert Exp $ Copyright (c) Gert Doering" /* definitions for utmp reading / writing routines, * highly SysV / BSD dependent */ #if !defined(sunos4) && !defined(BSD) && !defined(ultrix) /* SysV style */ #ifdef SVR4 /* on SVR4, use extended utmpx file */ # include # define utmp utmpx # define getutent getutxent # define getutid getutxid # define getutline getutxline # define pututline pututxline # define setutent setutxent # define endutent endutxent # define ut_time ut_xtime #else /* !SVR4 */ # include #endif #ifdef _AIX struct utmp * getutent(); /* AIX 3.2.5 doesn't declare these */ void setutent(); #endif #define UT_INIT INIT_PROCESS #define UT_LOGIN LOGIN_PROCESS #define UT_USER USER_PROCESS #else /* SunOS or generic BSD */ #include #include /* BSDish /etc/utmp files do not have the "ut_type" field, * but I need it as flag whether to write an utmp entry or not */ #define UT_INIT 0 #define UT_LOGIN 1 #define UT_USER 2 #endif /* SysV vs. BSD */ /* prototypes */ void make_utmp_wtmp _PROTO(( char * line, short ut_type, char * ut_user, char * ut_host )); int get_current_users _PROTO(( void )); /* system prototypes - not all supported systems have these */ #if defined(M_UNIX) struct utmp *getutent _PROTO((void)); #ifndef _SCO_DS /* ODT 5.0 */ struct utmp *pututline _PROTO((struct utmp * utmp)); #endif void setutent _PROTO((void)); void endutent _PROTO((void)); #endif /* M_UNIX */ mgetty-1.1.36/syslibs.h0100644000031200001470000000063607407464547013274 0ustar gertfax#ident "$Id: syslibs.h,v 4.3 2001/12/17 21:53:32 gert Exp $ Copyright (c) Gert Doering" /* Include stdlib.h / malloc.h, depending on the O/S */ #ifndef _NOSTDLIB_H #include #endif #if !defined( __bsdi__ ) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(NeXT) && !defined(__MACH__) #include #endif #ifdef NEXTSGTTY /* NeXT, not POSIX subsystem */ # include #endif mgetty-1.1.36/goodies.c0100644000031200001470000001405207756216365013225 0ustar gertfax#ident "$Id: goodies.c,v 4.5 2003/11/17 19:08:49 gert Exp $ Copyright (c) 1993 Gert Doering" /* * goodies.c * * This module is part of the mgetty kit - see LICENSE for details * * various nice functions that do not fit elsewhere */ #include #include "syslibs.h" #include #include #include #include #include #include #include #include /* NeXTStep/86 has some byte order problems (Christian Starkjohann) */ #if defined(NeXT) && defined(__LITTLE_ENDIAN__) && !defined(NEXTSGTTY) # define pw_uid pw_short_pad1 # define pw_gid pw_short_pad2 # define gr_gid gr_short_pad #endif #include "mgetty.h" #include "config.h" #ifdef SVR4 # include #endif /* get the base file name of a file path */ char * get_basename _P1( (s), char * s ) { char * p; if ( s == NULL ) return NULL; p = strrchr( s, '/' ); return ( p == NULL ) ? s: p+1; } /* auxiliary function: get a uid/gid pair from two strings * specifying user and group */ void get_ugid _P4( (user, group, uid, gid), conf_data * user, conf_data * group, uid_t * uid, gid_t * gid ) { /* default */ *uid = *gid = 0; if ( user->flags != C_EMPTY ) /* user set */ { struct passwd *pwd; if ( isdigit( *(char*)(user->d.p) )) /* numeric */ pwd = getpwuid( atoi( (char*) (user->d.p) )); else /* string */ pwd = getpwnam( (char*)(user->d.p) ); if ( pwd == NULL ) lprintf( L_ERROR, "can't get user id for '%s'", user->d.p ); else { *uid = pwd->pw_uid; *gid = pwd->pw_gid; } endpwent(); } /* if group is set, override group corresponding to user */ if ( group->flags != C_EMPTY ) { struct group * grp; if ( isdigit( *(char*)(group->d.p) )) /* numeric */ grp = getgrgid( atoi( (char*)(group->d.p)) ); else /* string */ grp = getgrnam( (char*) (group->d.p) ); if ( grp == NULL ) lprintf( L_ERROR, "can't get group '%s'", group->d.p ); else *gid = grp->gr_gid; endgrent(); } } /* return process name + arguments for process "PID" * * use /proc filesystem on Linux and SVR4 * * if no information is available, return NULL */ char * get_ps_args _P1 ((pid), int pid ) { #ifdef SVR4 char *pscomm = NULL; # ifdef PIOCPSINFO int procfd; char procfname[12]; static prpsinfo_t psi; sprintf (procfname, "/proc/%05d", pid); procfd = open (procfname, O_RDONLY); if ( procfd < 0 ) { lprintf( L_ERROR, "cannot open %s", procfname ); } else { if (ioctl (procfd, PIOCPSINFO, &psi) != -1) { psi.pr_psargs[PRARGSZ-1] = '\0'; pscomm = psi.pr_psargs; } close(procfd); } # endif /* PIOCPSINFO */ return pscomm; #endif /* SVR4 */ #if defined(linux) || \ ( defined(__FreeBSD__ ) && __FreeBSD_version >= 330000 ) # ifdef DIALOUT_SHOW_USERNAMES char procfn[30]; struct stat buf; struct passwd *pwe; static char u_logname[30]; sprintf (procfn, "/proc/%d", pid); if (stat (procfn, &buf) < 0) { lprintf( L_ERROR, "cannot stat %s", procfn ); return NULL; } if ((pwe = getpwuid (buf.st_uid)) == 0) { lprintf( L_ERROR, "cannot getpwuid %d", buf.st_uid ); return NULL; } strncpy( u_logname, pwe->pw_name, sizeof(u_logname)-1); u_logname[sizeof(u_logname)-1]=0; return u_logname; # else /* standard behaviour: show command line */ char procfn[30]; int procfd; int i,l; static char psinfo[60]; /* 60 is considered long enough */ sprintf( procfn, "/proc/%d/cmdline", pid ); procfd = open( procfn, O_RDONLY ); if ( procfd < 0 ) { lprintf( L_ERROR, "cannot open %s", procfn ); return NULL; } l = read( procfd, psinfo, sizeof( psinfo ) -1 ); if ( l < 0 ) { lprintf( L_ERROR, "reading %s failed", procfn ); close( procfd ); return NULL; } close( procfd ); psinfo[l] = 0; /* arguments separated by \0, replace with space */ for ( i=0; i0 && isspace(psinfo[l-1]) ) psinfo[--l]='\0'; return psinfo; # endif /* show user name, not process cmd line */ #endif /* linux */ #if !defined(SVR4) && !defined(linux) return NULL; #endif } #if defined(NEED_STRDUP) /* provide strdup() for systems not having it... */ char * strdup _P1( (src), char *src) { char * dest; if (!src) return(NULL); dest = (char *)malloc(strlen(src) + 1); if (!dest) return(NULL); strcpy(dest,src); return(dest); } #endif #if defined(NEED_PUTENV) /* provide putenv() for NEXTSTEP: * original code by Terrence W. Holm (tholm@uvicctr.UUCP), * slightly modified by Karl Berry (karl@cs.umb.edu) * contributed to mgetty by Gregor Hoffleit (flight@mathi.uni-heidelberg.DE) */ #define PSIZE sizeof(char *) extern char **environ; int putenv _P1( (entry), char *entry) { unsigned length, size; char * temp; char ** p; char ** new_environ; temp = strchr(entry,'='); if ( temp == 0 ) return( -1 ); length = (unsigned) (temp - entry + 1); for ( p=environ; *p != 0 ; p++ ) if ( strncmp( entry, *p, length ) == 0 ) { *p = entry; return( 0 ); } size = p - environ; new_environ = (char **) malloc( (size+2)*PSIZE ); if ( new_environ == (char **) NULL ) return( -1 ); memcpy ((char *) new_environ, (const char *) environ, size*PSIZE ); new_environ[size] = entry; new_environ[size+1] = NULL; environ = new_environ; return(0); } #endif /* NEED_PUTENV */ #ifdef NeXT /* provide function to repair broken tty settings * mega-ugly, but it seems to work * code provided by Christian Starkjohann */ # include # include void NeXT_repair_line(int fd) { int bitset = LPASS8 | LPASS8OUT; int bitclr = LNOHANG; #ifndef NEXTSGTTY /* needed only for broken POSIX subsystem */ struct sgttyb sg; ioctl(fd, TIOCGETP, &sg); sg.sg_flags |= EVENP | ODDP; ioctl(fd, TIOCSETP, &sg); #endif ioctl(fd, TIOCLBIS, &bitset); ioctl(fd, TIOCLBIC, &bitclr); } #endif mgetty-1.1.36/callback/README0100644000031200000620000000125606426151650014404 0ustar gertgroupThis is a first cut of my callback tool. Highly BETA, many rough edges. You call it from "login.config" like this: # # callback experiments # cback-gert - - /usr/local/sbin/callback -S 11223344 to call you back on "11223344" upon entering of a login name of "cback-gert". If you don't specify a number on the command line, the program will ask. If you don't specify a username but "*", things will break: callback will loop forever, calling you again and again (skipping login.config upon the second connect doesn't work yet), because it will *always* call callback... Use it for your own fun, and on your own risk. NEW: there is a callback man page ("man 8 callback") now. gert mgetty-1.1.36/callback/Makefile0100644000031200001470000000175010377113151014603 0ustar gertfax# Makefile for the "callback" subtree # of mgetty+sendfax # # SCCS: %W% %E% Copyright (c) Gert Doering # CC=gcc CFLAGS=-O2 -I.. -g zigzag: cd .. ; $(MAKE) call-back all: callback ct CBOBJS=callback.o conf_cb.o ../config.o ../logfile.o ../do_chat.o \ ../modem.o ../locks.o ../tio.o ../io.o ../goodies.o CTOBJS=ct.o callback: $(CBOBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o callback $(CBOBJS) $(LIBS) ct: $(CTOBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o ct $(CTOBJS) $(LIBS) conf_cb.o : conf_cb.c conf_cb.h ../mgetty.h ../ugly.h ../policy.h \ ../syslibs.h ../config.h ../Makefile $(CC) $(CFLAGS) -DCONFDIR=\"$(CONFDIR)\" -c conf_cb.c callback.o: callback.c ../syslibs.h ../mgetty.h ../ugly.h ../policy.h \ ../tio.h ../mg_utmp.h ../version.h ../config.h conf_cb.h $(CC) $(CFLAGS) -DVARRUNDIR=\"$(VARRUNDIR)\" -c callback.c clean: rm -f callback ct *.o # # install programs # install: all $(INSTALL) -s -m 700 -o root callback $(SBINDIR) $(INSTALL) -s -m 4711 -o root ct $(BINDIR) # source modules mgetty-1.1.36/callback/callback.c0100600000031200001470000004066110233206374015040 0ustar gertfax#ident "%W% %E% Copyright (c) Gert Doering" /* callback.c * * main module of the mgetty based callback / connect terminal (ct) system * * Operation: * - detach from terminal and controlling process * - find free tty line *which is controlled by mgetty* * (won't work if no mgetty there) * - init modem * - dial out, try different numbers if desired * - upon CONNECT, send mgetty on that line a SIGUSR1 (via MGETTY_PID_FILE) * [if compiled w/o MG_PID_FILE, read utmp and try to find mgetty pid] * + mgetty is in state St_dialout (because a lock file exists) * + in this state, SIGUSR1 means "take the line back from me" * + mgetty reopens the line, sends a SIGUSR1 back (pid of callback * program taken from lock file) * + mgetty overwrites lock file with its own [attention! RACE!] * - wait 5 seconds * - exit * + mgetty sends "Welcome... login:"-prompt * + mgetty calls /bin/login (bypass login.config!!) * * Use: * - call "callback" from login.config for automatic dial-back * - call "ct" (connect terminal) from the shell */ #include #include #include "syslibs.h" #include #include #include #include #include #ifndef sunos4 #include #endif #ifdef NeXT #include #endif #include "mgetty.h" #include "policy.h" #include "tio.h" #include "mg_utmp.h" #include "version.h" #include "config.h" #include "conf_cb.h" #if (defined(M_XENIX) && !defined(M_UNIX)) || defined(NEXTSGTTY) #define O_NOCTTY 0 #endif /* what kind of "surprising" things are recognized */ chat_action_t dial_chat_actions[] = { { "NO CARRIER", A_FAIL }, { "NO DIALTONE",A_FAIL }, { "BUSY", A_FAIL }, { "ERROR", A_FAIL }, { "RING\r", A_FAIL }, { NULL, A_FAIL } }; /* prototypes for system functions (that are missing in some * system header files) */ #if !defined(__NetBSD__) && !defined(__OpenBSD__) time_t time _PROTO(( time_t * tloc )); #endif /* conf_cb.c */ void exit_usage _PROTO((int num)); char * Device; /* device to use */ char * DevID; /* device name withouth '/'s */ extern time_t call_start; /* time when we sent ATA */ /* defined in faxrec.c */ boolean mgetty_ACK = FALSE; /* mgetty has ACKed the "take over" */ static RETSIGTYPE sig_mgetty_ack(SIG_HDLR_ARGS) { signal( SIGUSR1, sig_mgetty_ack ); lprintf( L_NOISE, "got ACK signal from mgetty" ); mgetty_ACK = TRUE; } boolean timeout = FALSE; static RETSIGTYPE sig_timer(SIG_HDLR_ARGS) { signal( SIGALRM, sig_timer ); lprintf( L_NOISE, "got alarm signal -> huh?" ); timeout = TRUE; } static RETSIGTYPE sig_goodbye _P1 ( (signo), int signo ) { lprintf( L_AUDIT, "failed dev=%s, pid=%d, got signal %d, exiting", Device, getpid(), signo ); rmlocks(); exit(10); } /* find the process ID of the mgetty process monitoring a given line */ int find_mgetty _P1( (device), char * device ) { int pid; /* look in mgetty's PID file (this is the easy way out) */ char pid_file_name[ MAXPATH ]; FILE * fp; char *DevID, *p; /* name mangling for SVR4 systems ("/dev/term/a" -> "term-a") */ DevID = p = strdup( Device ); if ( !DevID ) { perror( "callback: can't malloc" ); exit(99); } while( *p ) { if ( *p == '/' ) *p = '-'; p++; } sprintf( pid_file_name, "%s/mgetty.pid.%s", VARRUNDIR, DevID ); lprintf( L_NOISE, "find_mgetty: look in PID file %s", pid_file_name); fp = fopen( pid_file_name, "r" ); if ( fp == NULL ) { lprintf( L_ERROR, "can't read mgetty pid file %s", pid_file_name ); return -1; } if ( fscanf( fp, "%d", &pid ) != 1 ) { lprintf( L_ERROR, "can't read mgetty pid from %s", pid_file_name ); pid = -1; } fclose( fp ); lprintf( L_MESG, "PID for mgetty on line %s: %d", device, pid ); return pid; } void detach_tty _P0( void ) { int r; /* detach from controlling tty (close all FD's, get rid of c.tty, ...) */ lprintf( L_MESG, "detaching from ctty..." ); printf( "\nDialing continues in the background, all further messages will\nbe written to the logfile '" ); printf( LOG_PATH, "callback" ); printf( "'.\nPlease look there for errors / diagnostics.\n\n" ); fflush(stdout); tio_drain_output(1); /* make sure data is sent to modem */ sleep(1); /* and modem has sent it out */ switch( fork() ) { case 0: /* child */ /* close old tty */ close(0); close(1); close(2); #ifndef M_UNIX /* detach from controlling tty (we need to get a new one :)) */ if ( ( r = open( "/dev/tty", O_RDWR ) ) >= 0 ) { ioctl( r, TIOCNOTTY, NULL ); close( r ); } #endif /* get a new process group */ #if defined(BSD) || defined(sunos4) setpgrp( 0, getpid() ); #else setpgrp(); #endif break; case -1: /* error */ perror( "fork failed, can't detach myself" ); fprintf( stderr, "giving up.\n" ); exit(4); default: /* parent */ exit(0); } } /* make file descriptor stdin/stdout/stderr [only] */ int fd_make_stddev _P1( (fd), int fd ) { if ( fd > 0 ) { (void) close(0); if ( dup(fd) != 0 ) { lprintf( L_ERROR, "can't dup(fd=%d) to stdin", fd ); return ERROR; } close(fd); } (void) close(1); (void) close(2); if ( dup(0) != 1 ) { lprintf( L_ERROR, "can't dup(0) to stdout" ); return ERROR; } if ( dup(0) != 2 ) { lprintf( L_ERROR, "can't dup(0) to stderr" ); return ERROR; } return NOERROR; } /* open device, and set up all terminal parameters properly */ int callback_init_device _P1( (dev), char * dev ) { int fd; TIO tio; fd = open( dev, O_RDWR | O_NDELAY | O_NOCTTY ); if ( fd == -1 ) { lprintf( L_ERROR, "can't open %s", dev ); return -1; } /* set back to non-blocking */ fcntl( fd, F_SETFL, O_RDWR ); if ( tio_get( fd, &tio ) == ERROR ) { close(fd); return -1; } tio_mode_sane( &tio, TRUE ); tio_set_speed( &tio, c_int(speed) ); tio_default_cc( &tio ); tio_mode_raw( &tio ); #ifdef sun tio_set_flow_control( fd, &tio, (DATA_FLOW) & (FLOW_SOFT) ); #else tio_set_flow_control( fd, &tio, DATA_FLOW ); #endif if ( tio_set( fd, &tio ) == ERROR ) { close(fd); return -1; } return fd; } /* loop through all devices in "ttys" (separated with ":"), * try to lock and open() them, check if mgetty running, * return file descriptor or -1 * * if all ttys are locked, try every "rtime" seconds until "end_time" * seconds are reached (unix time), then give up. * * the device opened is stored in "device", the process id of the mgetty * process monitoring the line in "*mgetty_pid". */ int callback_find_device _P5( (ttys, device, mgetty_pid, rtime, end_time), char * ttys, char * device, int * mgetty_pid, int rtime, int end_time ) { char * p, *p_help; int fd; char tty[MAXLINE]; boolean found_locked; /* found some tty locked */ lprintf( L_NOISE, "cbfd: search ttys '%s'", ttys ); do { found_locked = FALSE; p = ttys; while( *p != 0 ) { p_help = memccpy( tty, p, ':', strlen(p)+1 ); if ( p_help != NULL ) { p_help--; *p_help = 0; p++; } p+=strlen(tty); if ( strncmp( tty, "/dev/", 5 ) == 0 ) { strcpy( device, tty ); } else { if ( tty[0] == '/' ) { lprintf( L_WARN, "%s: absolute paths must start with /dev, skipping", tty ); continue; } sprintf( device, "/dev/%s", tty ); } Device = device+5; /* device name without "/dev/" */ lprintf( L_NOISE, "cbfd: device: '%s'", device ); /* try locking */ if ( makelock( Device ) != SUCCESS ) { lprintf( L_MESG, "%s: locked", Device ); found_locked = TRUE; continue; } /* mgetty there? */ if ( (*mgetty_pid = find_mgetty( Device )) == -1 ) { lprintf( L_MESG, "no mgetty on %s, can't use this line", Device ); rmlocks(); continue; } /* try open/setup device */ if ( ( fd = callback_init_device( device )) == -1 ) { lprintf( L_MESG, "can't init %s, skipping", Device ); rmlocks(); continue; } /* got 'em */ return fd; } /* end while( process all ttys ) */ /* if some locked ttys were seen, we try again later. If none * were found, retrying would be quite useless, so we don't. */ if ( found_locked ) { lprintf( L_NOISE, "delaying %d seconds before next try", rtime ); sleep(rtime); } } while( found_locked && time(NULL) < end_time ); return -1; } int dialup _P4((fd, phone, count, end_time), int fd, char ** phone, int count, int end_time ) { int n; char dialbuf[MAXLINE]; char * r; /* set up timeout watchdog, in case modem dies and does not send * anything back to us in the maximum time-to-connect */ signal( SIGALRM, sig_timer ); n=0; do { alarm(180); /* 3 minute timeout */ lprintf( L_MESG, "dialing %s...", phone[n] ); sprintf( dialbuf, "%s%s", c_string(dial_prefix), phone[n] ); mdm_send( dialbuf, fd ); while( 1 ) { r = mdm_get_line( fd ); if ( r == NULL ) break; lprintf( L_MESG, "dialup: got '%s'", r ); if ( strncmp( r, "CONNECT", 7 ) == 0 ) { alarm(0); lprintf( L_MESG, "got CONNECT, success!" ); return NOERROR; } if ( strncmp( r, "ERROR", 5 ) == 0 || strncmp( r, "OK", 2 ) == 0 || strncmp( r, "BUSY", 4 ) == 0 || strncmp( r, "NO DIALTONE", 11 ) == 0 || strncmp( r, "NO CARRIER", 10 ) == 0 || strncmp( r, "NO ANSWER", 10 ) == 0 ) { lprintf( L_MESG, "dialup attempt failed, try next number"); break; } } alarm(0); if ( ++n >= count ) n=0; /* next phone number */ sleep( c_int(retry_time) ); } while( time(NULL) < end_time && ! timeout ); lprintf( L_MESG, "time ran out, giving up" ); return ERROR; } /* provide some "dummy" things for do_chat(), otherwise callback won't link */ /*!!! FIXME - we don't really want this */ int virtual_ring = FALSE; void cndfind _P1( (p), char * p ) { /* DUMMY */ } int main _P2((argc, argv), int argc, char ** argv) { char devname[MAXLINE+1]; /* full device name (with /dev/) */ int mgetty_pid = -1; /* pid of mgetty on that device */ char ** t_numbers; /* telephone numbers */ int t_count; /* number of numbers */ char * t_help; char phonebuf[40]; /* telephone number entered */ char buf[MAXLINE+1]; TIO tio; int fd; int i; time_t end_time; action_t action; /* startup */ /* catch all nasty signals, clean up behind, and log... */ (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGINT, sig_goodbye); (void) signal(SIGQUIT, sig_goodbye); (void) signal(SIGTERM, sig_goodbye); /* some systems, notable BSD 4.3, have to be told that system * calls are not to be automatically restarted after those signals. */ #ifdef HAVE_SIGINTERRUPT siginterrupt( SIGINT, TRUE ); siginterrupt( SIGALRM, TRUE ); siginterrupt( SIGHUP, TRUE ); siginterrupt( SIGUSR1, TRUE ); siginterrupt( SIGUSR2, TRUE ); #endif Device = "unknown"; /* we *must* run as root to signal mgetty */ if ( geteuid() != 0 ) { fprintf( stderr, "\nSorry, callback must be run as userid \"root\", otherwise it won't work.\n\n" ); lprintf( L_AUDIT, "fail: non-root user id %d", getuid() ); exit(2); } /* process the command line */ callback_parse_args( argc, argv ); /* remaining command line arguments is/are telephone number(s) */ if (optind < argc) /* phone number given on the command line */ { t_count = argc - optind; t_numbers = &argv[optind]; } else /* read telephone number from stdin */ { lprintf( L_MESG, "reading telephone number from stdin" ); printf( "Telephone number for callback: " ); /*!!! FIXME: accept only proper telephone numbers */ fgets( phonebuf, 30, stdin ); t_count = 1; t_numbers = &t_help; t_numbers[0] = phonebuf; i = strlen(phonebuf); while (i>0 && !isprint(phonebuf[i-1])) phonebuf[--i] = 0; } /* Initialize Logging */ sprintf( buf, LOG_PATH, "callback" ); log_init_paths( argv[0], buf, NULL ); lprintf( L_NOISE, "callback: %s", mgetty_version ); lprintf( L_JUNK, "%d telephone numbers given:", t_count ); for( i=0; i0) ? rand()%c_int(delay_rand) : rand()%5 ); if (i<4) i=4; lprintf( L_NOISE, "delaying %d seconds", i ); sleep(i); /* try each device in turn until we find one that is not locked, * can be open()ed, and has an mgetty process monitoring it */ fd = callback_find_device( c_string(ttys), devname, &mgetty_pid, c_int(retry_time), end_time ); if ( fd == -1 ) { lprintf( L_ERROR, "can't get dialout device, exiting" ); exit(2); } /*!!! do we really need this? */ if ( fd_make_stddev( fd ) == ERROR ) { lprintf( L_ERROR, "can't make stdin/stdout/sterr, exiting" ); exit(2); } fd=0; /* use stdin from now on */ /* switch off stdio buffering */ setbuf( stdin, (char *) NULL ); setbuf( stdout, (char *) NULL ); setbuf( stderr, (char *) NULL ); /* set log "infix" according to device name */ log_init_paths( NULL, NULL, &Device[strlen(Device)-3] ); /* read device specific configuration file */ callback_get_config( Device ); /* make a short (+randomized!) pause, giving mgetty enough time * to initialize modem, and making "spoofing" harder */ /* init modem */ lprintf( L_MESG, "initializing modem..." ); if ( do_chat( fd, c_chat(modem_init), dial_chat_actions, &action, 10, TRUE ) != SUCCESS ) { if ( action == A_TIMOUT ) { lprintf( L_ERROR, "Error: modem does not answer, giving up!" ); return ERROR; } lprintf( L_WARN, "modem init failed: expect problems." ); } /* dial all numbers, in turn, until CONNECT is established * if no connection is made on first turn, sleep 60 seconds, and try again */ if ( dialup( fd, t_numbers, t_count, end_time ) == ERROR ) { lprintf( L_ERROR, "can't dial any of the given numbers, exiting" ); exit(10); } /* connection is made */ #if 0 /* drain input - make sure there are no leftover "NO CARRIER"s * or "ERROR"s lying around from some previous dial-out */ clean_line( STDIN, 1); /* wait .3s for line to clear (some modems send a \n after "OK", this may confuse the "call-chat"-routines) */ clean_line( STDIN, 3); /* sleep... waiting for activity */ /* wait for line to clear (after "CONNECT" a baud rate may be sent by the modem, on a non-MNP-Modem the MNP-request string sent by a calling MNP-Modem is discarded here, too) */ clean_line( STDIN, 3); #endif /* honor carrier now: terminate if modem hangs up prematurely */ tio_get( STDIN, &tio ); tio_carrier( &tio, TRUE ); tio_set( STDIN, &tio ); /* wait a little bit, then print "pre-welcome" message */ delay( c_int(prompt_waittime) ); printf( "Connection established, please wait...\r\n" ); /* wait for data to be sent to modem before charging ahead... */ tio_drain_output( STDIN ); delay( 300 ); /* signal mgetty, wait for answer, die peacefully. */ signal( SIGUSR1, sig_mgetty_ack ); if ( kill( mgetty_pid, SIGUSR1 ) < 0 ) { lprintf( L_ERROR, "can't signal mgetty process %d, giving up", mgetty_pid); printf( "Fatal error: can't pass control, hanging up.\r\n" ); sleep(5); exit(5); } signal( SIGALRM, sig_timer ); alarm(30); pause(); /* just sleep until SIGALRM or SIGUSR1 arrives */ alarm(0); if ( timeout || !mgetty_ACK ) { lprintf( L_FATAL, "wait_ack: something went wrong, didn't get ACK in time" ); printf( "Fatal error: can't pass control, hanging up.\r\n" ); sleep(5); exit(5); } lprintf( L_AUDIT, "callback: success, device=%s, mgetty=%d", devname, mgetty_pid ); return 0; } mgetty-1.1.36/callback/conf_cb.c0100644000031200001470000001116606534514611014710 0ustar gertfax#ident "%W% %E% Copyright (c) Gert Doering" /* conf_cb.c * * configuration defaults / configuration reading code for callback tool */ #include #include #include #include "mgetty.h" #include "policy.h" #include "syslibs.h" #include "tio.h" #include "config.h" #include "conf_cb.h" extern char * mgetty_version; /* mgetty.c/version.h */ /* initialize the modem - MODEM_INIT_STRING defined in policy.h */ static char * def_init_chat_seq[] = { "", "ATQ0V1H0", "OK", "AT+FCLASS=0", "OK", NULL }; /* this is the default configuration... */ struct conf_data_mgetty c = { { "dialout-devices", {(p_int)FAX_MODEM_TTYS}, CT_STRING, C_PRESET }, { "dialout-devices", {0}, CT_STRING, C_IGNORE }, { "delay", {20}, CT_INT, C_PRESET }, { "delay-randomize", {10}, CT_INT, C_PRESET }, { "retry-time", {30}, CT_INT, C_PRESET }, { "max-time", {600}, CT_INT, C_PRESET }, { "modem-init", {0}, CT_CHAT, C_PRESET }, { "speed", {DEFAULT_PORTSPEED}, CT_INT, C_PRESET }, { "dial-prefix", {(p_int) FAX_DIAL_PREFIX}, CT_STRING, C_PRESET }, { "autobauding", {FALSE}, CT_BOOL, C_PRESET }, { "prompt-waittime", {300}, CT_INT, C_PRESET }, { "", {FALSE}, CT_BOOL, C_PRESET }, /* nodetach */ { "debug", {LOG_LEVEL}, CT_INT, C_PRESET }, { NULL, {0}, CT_STRING, C_EMPTY }}; /* * exit_usage() - exit with usage display */ void exit_usage _P1((code), int code ) { fprintf( stderr, "Usage: callback [-x ] [-V] [-l ] [-m ]\n [-s ] [-d] [-S] [phone number(s)...]\n"); exit(code); } int callback_parse_args _P2( (argc,argv), int argc, char ** argv ) { int opt; /* sanity check: * make sure that structs-in-struct can be handled exactly as if * packed in array (get_config relies on it!) */ conf_data c_a[2]; if ( ( (char *)&c_a[1] - (char *)&c_a[0] ) != ( (char *)&c.ttys_0 - (char *)&c.ttys ) ) { fprintf( stderr, "ERROR: config table size mixup. contact author\n" ); exit(99); } /* initialize a few things that can't be done statically */ c.modem_init.d.p = (void *) def_init_chat_seq; c.modem_init.flags = C_PRESET; #if 0 c.answer_chat.d.p = (void *) def_answer_chat_seq; c.answer_chat.flags = C_PRESET; #endif /* get command line arguments */ while ((opt = getopt(argc, argv, "x:s:am:l:SdV")) != EOF) { switch (opt) { case 'x': /* log level */ conf_set_int( &c.debug, atoi(optarg) ); log_set_llevel( c_int(debug) ); break; case 's': /* port speed */ conf_set_int( &c.speed, atoi(optarg) ); break; case 'a': /* autobauding */ /*!!! FIXME: not implemented */ conf_set_bool( &c.autobauding, TRUE ); break; case 'm': /* modem init sequence */ c.modem_init.flags = C_OVERRIDE; c.modem_init.d.p = conf_get_chat( optarg ); break; case 'l': /* set device(s) to use */ if ( optarg[0] == '/' && strncmp( optarg, "/dev/", 5 ) != 0 ) { fprintf( stderr, "%s: -l: device must be located in /dev!\n", argv[0]); exit(1); } conf_set_string( &c.ttys, optarg ); break; case 'S': /* unconditionally use *this* line for call back */ conf_set_string( &c.ttys, ttyname(0) ); lprintf( L_MESG, "using stdin for dial out, tty=%s", c_string(ttys)); break; case 'd': /* debug mode: don't detach from tty */ conf_set_bool( &c.nodetach, TRUE ); lprintf( L_MESG, "debug mode active" ); break; case 'V': /* show version number */ printf("\nmgetty+sendfax by Gert Doering\n%s\n\n", mgetty_version); printf("log file written to '"); printf(LOG_PATH, "callback" ); printf("'\n\n"); exit(0); case '?': exit_usage(2); break; } } return NOERROR; } /* get callback configuration from file (defaults are used if it doesn't exist) */ void callback_get_config _P1( (port), char * port ) { #ifdef CALLBACK_CONFIG if ( port == NULL ) { lprintf( L_NOISE, "reading default configuration" ); get_config( makepath( CALLBACK_CONFIG, CONFDIR ), (conf_data *)&c, "port", NULL ); } else { lprintf( L_NOISE, "reading specific data for port '%s'", port ); get_config( makepath( CALLBACK_CONFIG, CONFDIR ), ((conf_data *)&c)+1, "port", port ); } #else lprintf( L_NOISE, "not reading config file, not configured" ); #endif /* tell log subsystem about new log level */ log_set_llevel( c_int(debug) ); /* sanity checks */ if ( tio_check_speed( c_int(speed) ) < 0 ) { lprintf( L_FATAL, "invalid port speed: %d", c_int(speed)); exit_usage(2); } /*!!! further checks required? */ } mgetty-1.1.36/callback/conf_cb.h0100644000031200000620000000173206426151721015264 0ustar gertgroup#ident "%W% %E% Copyright (c) 1994 Gert Doering" /* all (dynamic) callback configuration is contained in this structure. * It is initialized and loaded in conf_cb.c and accessed from callback.c */ extern struct conf_data_mgetty { struct conf_data ttys, /* ttys */ ttys_0, /* for second pass, "ignore" */ delay, /* min. delay before first call */ delay_rand, /* add random time 0...dr to delay */ retry_time, /* time between two dialup attempts */ max_retry_time, /* how long to try altogether */ modem_init, /* modem initialization */ speed, /* port speed */ dial_prefix, /* ATDT0WP... */ autobauding, /* change baud rate to CONNECT "xxx" */ prompt_waittime, /* pause [in ms] after CONNECT */ nodetach, /* don't fork() */ debug, /* debugging */ end_of_config; } c; int callback_parse_args _PROTO(( int argc, char ** argv )); void callback_get_config _PROTO(( char * port )); mgetty-1.1.36/callback/ct.c0100644000031200000620000000024406426151650014272 0ustar gertgroup#include #include "mgetty.h" int main _P2((argc, argv), int argc, char ** argv ) { fprintf( stderr, "ct: not yet implemented\n" ); return 1; } mgetty-1.1.36/callback/callback.config0100644000031200000620000000034306426151762016447 0ustar gertgroup# # this is a very much undocumented sample file for "callback.config". # # it's only good to show what options exist. See the source for docs! # dialout-devices tty5a:tty5d retry-time 30 max-time 90 debug 9 dial-prefix ATX3D mgetty-1.1.36/callback/login.cfg.doc0100644000031200001470000000310506671556050015507 0ustar gertfaxDate: Mon, 22 Feb 1999 08:35:40 +0100 From: Gert Doering To: Pang Wai Man Raymond , mgetty@muc.de Subject: Re: Restrict login through callback, not dial-in by mgetty? X-mgetty-docs: http://alpha.greenie.net/mgetty/ Hi, On Mon, Feb 22, 1999 at 10:53:24AM +0800, Pang Wai Man Raymond wrote: > Requirement > =========== > Without using the dialback modem, > 1. a dummy account with password, can initiate the callback > 2. users can only login through callback, but not dial-in. > > I can implement step 1 but not 2. Does anybody have alternative? Set up login.config like this: ------- login.config sample, file version 2 ---------- # login.config # # use version-2 format !version 2 # # # this is the dummy user name, it's allowed to login only if this # is not already an ongoing callback callback N - - /bin/login @ # # these are the real users: only allowed if it's a callback ("Y") * Y - - /bin/login @ # # if some other user name was entered, and it's not a callback, # throw them out * - - - /bin/false ------- login.config sample, file version 2 ---------- I admit that the "version 2" stuff isn't documented anywhere yet (except the source) and it hasn't been fully tested either. So please get mgetty 1.1.20, test it, and report back to us :) gert -- USENET is *not* the non-clickable part of WWW! //www.muc.de/~gert/ Gert Doering - Munich, Germany gert@greenie.muc.de fax: +49-89-35655025 gert.doering@physik.tu-muenchen.de mgetty-1.1.36/compat/mg.echo.c0100644000031200000620000001323006426151403014726 0ustar gertgroup/* echo.c * * taken from GNU shell utilities 1.9.2 * heavily modified by Gert Doering (configuration stuff dropped) */ /* echo.c, taken from Bash. Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software; you can redistribute 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. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include /* echo [-neE] [arg ...] Output the ARGs. If -n is specified, the trailing newline is suppressed. If the -e option is given, interpretation of the following backslash-escaped characters is turned on: \a alert (bell) \b backspace \c suppress trailing newline \f form feed \n new line \r carriage return \t horizontal tab \v vertical tab \\ backslash \num the character whose ASCII code is NUM (octal). You can explicitly turn off the interpretation of the above characters on System V systems with the -E option. */ /* If defined, interpret backslash escapes if -e is given. */ #define V9_ECHO /* If defined, interpret backslash escapes unless -E is given. V9_ECHO must also be defined. */ #define V9_DEFAULT #if defined (V9_ECHO) # if defined (V9_DEFAULT) # define VALID_ECHO_OPTIONS "neE" # else # define VALID_ECHO_OPTIONS "ne" # endif /* !V9_DEFAULT */ #else /* !V9_ECHO */ # define VALID_ECHO_OPTIONS "n" #endif /* !V9_ECHO */ /* The name this program was run with. */ char *program_name; static void usage (status) int status; { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else { printf ("Usage: %s [OPTION]... [STRING]...\n", program_name); printf ("\ \n\ -n do not output the trailing newline\n\ -e (unused)\n\ -E disable interpolation of some sequences in STRINGs\n\ --help display this help and exit (should be alone)\n\ --version output version information and exit (should be alone)\n\ \n\ Without -E, the following sequences are recognized and interpolated:\n\ \n\ \\NNN the character whose ASCII code is NNN (octal)\n\ \\\\ backslash\n\ \\a alert (BEL)\n\ \\b backspace\n\ \\c suppress trailing newline\n\ \\f form feed\n\ \\n new line\n\ \\r carriage return\n\ \\t horizontal tab\n\ \\v vertical tab\n\ "); } exit (status); } /* Print the words in LIST to standard output. If the first word is `-n', then don't print a trailing newline. We also support the echo syntax from Version 9 unix systems. */ void main (argc, argv) int argc; char **argv; { int display_return = 1, do_v9 = 0; program_name = argv[0]; #if 0 parse_long_options (argc, argv, usage); #else if ( argc > 1 && strcmp( argv[1], "--help" ) == 0 ) usage(0); if ( argc > 1 && strcmp( argv[1], "--version" ) == 0 ) { printf( "GNU Echo 1.9.2 - hacked for mgetty\n" ); exit(0); } #endif /* System V machines already have a /bin/sh with a v9 behaviour. We use the identical behaviour for these machines so that the existing system shell scripts won't barf. */ #if defined (V9_ECHO) && defined (V9_DEFAULT) do_v9 = 1; #endif --argc; ++argv; while (argc > 0 && *argv[0] == '-') { register char *temp; register int i; /* If it appears that we are handling options, then make sure that all of the options specified are actually valid. Otherwise, the string should just be echoed. */ temp = argv[0] + 1; for (i = 0; temp[i]; i++) { if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0) goto just_echo; } if (!*temp) goto just_echo; /* All of the options in TEMP are valid options to ECHO. Handle them. */ while (*temp) { if (*temp == 'n') display_return = 0; #if defined (V9_ECHO) else if (*temp == 'e') do_v9 = 1; #if defined (V9_DEFAULT) else if (*temp == 'E') do_v9 = 0; #endif /* V9_DEFAULT */ #endif /* V9_ECHO */ else goto just_echo; temp++; } argc--; argv++; } just_echo: if (argc > 0) { #if defined (V9_ECHO) if (do_v9) { while (argc > 0) { register char *s = argv[0]; register int c; while ((c = *s++)) { if (c == '\\' && *s) { switch (c = *s++) { case 'a': c = '\007'; break; case 'b': c = '\b'; break; case 'c': display_return = 0; continue; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = (int) 0x0B; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c -= '0'; if (*s >= '0' && *s <= '7') c = c * 8 + (*s++ - '0'); if (*s >= '0' && *s <= '7') c = c * 8 + (*s++ - '0'); break; case '\\': break; default: putchar ('\\'); break; } } putchar(c); } argc--; argv++; if (argc > 0) putchar(' '); } } else #endif /* V9_ECHO */ { while (argc > 0) { fputs (argv[0], stdout); argc--; argv++; if (argc > 0) putchar (' '); } } } if (display_return) putchar ('\n'); exit (0); } mgetty-1.1.36/compat/newslock.c0100600000031200001470000000076210233255777014671 0ustar gertfax/* * newslock - simple, unbroken version of ln(1) for shell-program locking * * (System V has broken ln(1) itself.) * * TAKEN UNMODIFIED FROM C-NEWS BY Geoffrey Collyer AND Henry Spencer */ #include #include #include #include int main(argc, argv) int argc; char *argv[]; { if (argc != 3) { fprintf(stderr, "Usage: %s tempname lockname\n", argv[0]); exit(2); } if (link(argv[1], argv[2]) < 0) exit(1); else exit(0); /* NOTREACHED */ } mgetty-1.1.36/compat/README0100644000031200000620000000063306426151403014125 0ustar gertgroupIn this directory (mgetty/compat) you'll find various programs that are needed to make mgetty+sendfax work on not-so-compatible platforms. mg.echo.c: a replacement for the SystemV echo program, which can do escape characters, taken from GNU shellutils 1.92 (modified). newslock.c: an "atomic test-and-set" link operation for files, to be called from shell scripts. Taken from C-News (unmodified). mgetty-1.1.36/contrib/next-login/Makefile0100644000031200000620000000255606152102552017151 0ustar gertgroup# # Copyright (c) 1988 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 redistribution 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. # # from @(#)Makefile 5.3 (Berkeley) 5/9/89 # CFLAGS= -O -bsd -DORIGINAL -DFIX8BIT LIBC= /lib/libsys_s.a SRCS= login.c setenv.c OBJS= login.o setenv.o MAN= login.0 DESTDIR= /usr/local all: login login: ${LIBC} ${OBJS} ${CC} -object -o $@ -s ${OBJS} setenv.o: setenv.c ${CC} ${CFLAGS} -DLIBC_SCCS -c $< clean: rm -f ${OBJS} core login cleandir: clean rm -f ${MAN} tags .depend depend: ${SRCS} mkdep -p ${CFLAGS} ${SRCS} install: install -s -o root -g bin -m 4755 login ${DESTDIR}/bin/modem-login lint: ${SRCS} lint ${CFLAGS} ${SRCS} tags: ${SRCS} ctags ${SRCS} mgetty-1.1.36/contrib/next-login/README0100644000031200000620000001046406152152121016363 0ustar gertgroupThis is a replacement for NEXTSTEP's /bin/login. It has been patched by Ingo Paschke to provide 8-bit clean login's with mgetty's sgtty NEXTSTEP port. To use, just "make install". This will install modem-login in /usr/local/bin. Then, in mgetty's login.config, replace `/bin/login' with `/usr/local/bin/modem-login' or change DEFAULT_LOGIN_PROGRAM in policy.h to `/usr/local/bin/modem-login'. For more information on NEXTSTEP and mgetty, consult the `Operating Systems' section on NEXTSTEP in the mgetty manual. Gregor Hoffleit This is the README of the original jsh-login as found on peanuts.leo.org as Patches/jsh-login.s.tar.gz: --- This is a replacement for /bin/login in NeXT Software Release 2.0 and 2.1 that enables job control for /bin/sh users. /bin/sh and /bin/jsh are hard links to the same file; job control is enabled if argv[0][0]=='j' or the -J flag is set. Shells started from login have a '-' prepended to their basename to indicate that .profile should be sourced, so if you specify /bin/jsh as your login shell, its sees its name as -jsh, and doesn't activate job control. This has been reported to BUG_NEXT. This version of login passes the "-J" flag if the login shell is /bin/sh. Everything else still thinks you're running "regular" sh, so you don't have to muck with /etc/shells or anything. Inferior shells will *not* have job control enabled; use jsh instead if that's what you want (most of the time it isn't). --- This is Ingo's patch: --- Sun, 14 Apr 1996 23:23:25 de.comp.sys.next Thread 12 of 15 Lines 92 mgetty fuer NSfIP? - Teilerfolg... No responses ipaschke@xlan.hil.de Ingo Paschke at private Hallo! ipaschke@xlan.hil.de (Ingo Paschke) writes: >Das Problem ist nur, dass /bin/login offenbar die Verbindung wieder auf >7-Bit, gerade Paritaet zuruecksetzt: Issue und login-Prompt werden von >mgetty korrekt in 8-Bit ausgegeben, das Passwort-Prompt ist dann nicht mehr >lesbar, weil es in 7-Bit ausgegeben wird. Man nehme jsh-login.s.tar.gz von peanuts (/Patches), wende folgendes diff an (NeXT_repair_line ist von mgetty-0.99 geklaut): ------------------------------------------------------------------- diff -burN jsh-login.orig/Makefile jsh-login/Makefile --- jsh-login.orig/Makefile Fri Apr 26 11:51:56 1991 +++ jsh-login/Makefile Sun Apr 14 22:43:42 1996 @@ -17,11 +17,12 @@ # from @(#)Makefile 5.3 (Berkeley) 5/9/89 # -CFLAGS= -O -bsd +CFLAGS= -O -bsd -DORIGINAL -DFIX8BIT LIBC= /lib/libsys_s.a SRCS= login.c setenv.c OBJS= login.o setenv.o MAN= login.0 +DESTDIR= /usr/local all: login @@ -40,9 +41,8 @@ depend: ${SRCS} mkdep -p ${CFLAGS} ${SRCS} -install: ${MAN} - install -s -o root -g bin -m 4755 login ${DESTDIR}/bin/login - install -c -o bin -g bin -m 444 login.0 ${DESTDIR}/usr/man/cat1 +install: + install -s -o root -g bin -m 4755 login ${DESTDIR}/bin/modem-login lint: ${SRCS} lint ${CFLAGS} ${SRCS} diff -burN jsh-login.orig/login.c jsh-login/login.c --- jsh-login.orig/login.c Fri Apr 26 12:00:26 1991 +++ jsh-login/login.c Sun Apr 14 22:37:10 1996 @@ -180,6 +180,10 @@ (void)ioctl(0, TIOCSETC, &tc); (void)ioctl(0, TIOCSETP, &sgttyb); +#if defined(NeXT) && defined(FIX8BIT) + NeXT_repair_line(0); +#endif + for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); @@ -705,5 +709,16 @@ (void)write(fd, (char *)ut, sizeof(struct utmp)); (void)close(fd); } +} +#endif + +#if defined(NeXT) && defined(FIX8BIT) +NeXT_repair_line(int fd) +{ + int bitset = LPASS8 | LPASS8OUT; + int bitclr = LNOHANG; + + ioctl(fd, TIOCLBIS, &bitset); + ioctl(fd, TIOCLBIC, &bitclr); } #endif -------------------------------------------------------------- ... und kann sich ganz auf das naechste Problem konzentrieren. Dummerweise funktioniert naemlich das "LNOHANG"-Bit-Loeschen nicht (d.h. ich denke schon, dass das Loeschen funktioniert, das scheint NEXTSTEP jedoch wenig zu stoeren). Legt der Anrufer also einfach auf, haengt die Kiste ewiglich :(. Ideen? Aaargh! Jemand erwecke mich bitte aus diesem NEXTSTEP-tty-Alptraum! ;). Ciao, Ingo. -- Ingo Paschke Braunschweig, Germany [MIME, Nextmail welcome.] mgetty-1.1.36/contrib/next-login/login.c0100644000031200000620000004143406152102552016763 0ustar gertgroup/* * Copyright (c) 1980, 1987, 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. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #endif /* not lint */ /* * login [ name ] * login -h hostname (for telnetd, etc.) * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ #include #ifdef NeXT #include #else #include #endif #include #include #include #include #include #include #ifdef NeXT #include #ifndef UT_NAMESIZE #define UT_NAMESIZE 8 #endif #endif #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #ifdef KERBEROS #include #include char realm[REALM_SZ]; int kerror = KSUCCESS, notickets = 1; #endif #define TTYGRPNAME "tty" /* name of group to own ttys */ /* * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */ int timeout = 300; struct passwd *pwd; int failures; char term[64], *hostname, *username, *tty; struct sgttyb sgttyb; struct tchars tc = { CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK }; struct ltchars ltc = { CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT }; #ifndef NeXT /* NeXT doesn't ifdef this out for some reason */ char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; #endif main(argc, argv) int argc; char **argv; { extern int errno, optind; extern char *optarg, **environ; struct timeval tp; struct tm *ttp; struct group *gr; register int ch; register char *p; int ask, fflag, hflag, pflag, cnt; int quietlog, passwd_req, ioctlval, timedout(); char *domain, *salt, *envinit[1], *ttyn, *pp; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); time_t time(); off_t lseek(); (void)signal(SIGALRM, timedout); (void)alarm((u_int)timeout); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)setpriority(PRIO_PROCESS, 0, 0); #ifndef NeXT (void)quota(Q_SETUID, 0, 0, 0); #endif /* * -p is used by getty to tell login not to destroy the environment * -f is used to skip a second login authentication * -h is used by other servers to pass the name of the remote * host to login so that it may be placed in utmp and wtmp */ (void)gethostname(tbuf, sizeof(tbuf)); domain = index(tbuf, '.'); fflag = hflag = pflag = 0; passwd_req = 1; while ((ch = getopt(argc, argv, "fh:p")) != EOF) switch (ch) { case 'f': fflag = 1; break; case 'h': if (getuid()) { (void)fprintf(stderr, "login: -h for super-user only.\n"); exit(1); } hflag = 1; if (domain && (p = index(optarg, '.')) && strcasecmp(p, domain) == 0) *p = 0; hostname = optarg; break; case 'p': pflag = 1; break; case '?': default: (void)fprintf(stderr, "usage: login [-fp] [username]\n"); exit(1); } argc -= optind; argv += optind; if (*argv) { username = *argv; ask = 0; } else ask = 1; ioctlval = 0; (void)ioctl(0, TIOCLSET, &ioctlval); (void)ioctl(0, TIOCNXCL, 0); (void)fcntl(0, F_SETFL, ioctlval); (void)ioctl(0, TIOCGETP, &sgttyb); sgttyb.sg_erase = CERASE; sgttyb.sg_kill = CKILL; (void)ioctl(0, TIOCSLTC, <c); (void)ioctl(0, TIOCSETC, &tc); (void)ioctl(0, TIOCSETP, &sgttyb); #if defined(NeXT) && defined(FIX8BIT) NeXT_repair_line(0); #endif for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); ttyn = ttyname(0); if (ttyn == NULL || *ttyn == '\0') { (void)sprintf(tname, "%s??", _PATH_TTY); ttyn = tname; } if (tty = rindex(ttyn, '/')) ++tty; else tty = ttyn; openlog("login", LOG_ODELAY, LOG_AUTH); for (cnt = 0;; ask = 1) { ioctlval = 0; (void)ioctl(0, TIOCSETD, &ioctlval); if (ask) { fflag = 0; getloginname(); } /* * Note if trying multiple user names; * log failures for previous user name, * but don't bother logging one failure * for nonexistent name (mistyped username). */ if (failures && strcmp(tbuf, username)) { if (failures > (pwd ? 0 : 1)) badlogin(tbuf); failures = 0; } (void)strcpy(tbuf, username); if (pwd = getpwnam(username)) salt = pwd->pw_passwd; else salt = "xx"; /* if user not super-user, check for disabled logins */ if (pwd == NULL || pwd->pw_uid) checknologin(); /* * Disallow automatic login to root; if not invoked by * root, disallow if the uid's differ. */ if (fflag && pwd) { int uid = getuid(); passwd_req = pwd->pw_uid == 0 || (uid && uid != pwd->pw_uid); } #ifdef NeXT if (pwd->pw_uid == 0 && !rootterm(tty)) { fprintf(stderr, "%s login refused on this terminal.\n", pwd->pw_name); if (hostname) syslog(LOG_NOTICE, "LOGIN %s REFUSED FROM %s ON TTY %s", pwd->pw_name, hostname, tty); else syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", pwd->pw_name, tty); continue; } #endif /* * If no pre-authentication and a password exists * for this user, prompt for one and verify it. */ if (!passwd_req || (pwd && !*pwd->pw_passwd)) break; setpriority(PRIO_PROCESS, 0, -4); pp = getpass("Password:"); p = crypt(pp, salt); setpriority(PRIO_PROCESS, 0, 0); #ifdef KERBEROS /* * If not present in pw file, act as we normally would. * If we aren't Kerberos-authenticated, try the normal * pw file for a password. If that's ok, log the user * in without issueing any tickets. */ if (pwd && !krb_get_lrealm(realm,1)) { /* * get TGT for local realm; be careful about uid's * here for ticket file ownership */ (void)setreuid(geteuid(),pwd->pw_uid); kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, "krbtgt", realm, DEFAULT_TKT_LIFE, pp); (void)setuid(0); if (kerror == INTK_OK) { bzero(pp, strlen(pp)); notickets = 0; /* user got ticket */ break; } } #endif (void) bzero(pp, strlen(pp)); if (pwd && !strcmp(p, pwd->pw_passwd)) break; (void)printf("Login incorrect\n"); failures++; /* we allow 10 tries, but after 3 we start backing off */ if (++cnt > 3) { if (cnt >= 10) { badlogin(username); (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); sleepexit(1); } sleep((u_int)((cnt - 3) * 5)); } } /* committed to login -- turn off timeout */ (void)alarm((u_int)0); /* paranoia... */ endpwent(); #ifndef NeXT /* * If valid so far and root is logging in, see if root logins on * this terminal are permitted. */ if (pwd->pw_uid == 0 && !rootterm(tty)) { if (hostname) syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", hostname); else syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); (void)printf("Login incorrect\n"); sleepexit(1); } if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { switch(errno) { case EUSERS: (void)fprintf(stderr, "Too many users logged on already.\nTry again later.\n"); break; case EPROCLIM: (void)fprintf(stderr, "You have too many processes running.\n"); break; default: perror("quota (Q_SETUID)"); } sleepexit(0); } #endif if (chdir(pwd->pw_dir) < 0) { (void)printf("No directory %s!\n", pwd->pw_dir); if (chdir("/")) exit(0); pwd->pw_dir = "/"; (void)printf("Logging in with home = \"/\".\n"); } quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; #ifdef KERBEROS if (notickets && !quietlog) (void)printf("Warning: no Kerberos tickets issued\n"); #endif #ifndef NeXT #define TWOWEEKS (14*24*60*60) if (pwd->pw_change || pwd->pw_expire) (void)gettimeofday(&tp, (struct timezone *)NULL); if (pwd->pw_change) if (tp.tv_sec >= pwd->pw_change) { (void)printf("Sorry -- your password has expired.\n"); sleepexit(1); } else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { ttp = localtime(&pwd->pw_change); (void)printf("Warning: your password expires on %s %d, %d\n", months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); } if (pwd->pw_expire) if (tp.tv_sec >= pwd->pw_expire) { (void)printf("Sorry -- your account has expired.\n"); sleepexit(1); } else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { ttp = localtime(&pwd->pw_expire); (void)printf("Warning: your account expires on %s %d, %d\n", months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); } #endif /* nothing else left to fail -- really log in */ { #ifdef NeXT void login(); #endif struct utmp utmp; bzero((char *)&utmp, sizeof(utmp)); (void)time(&utmp.ut_time); strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); if (hostname) strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); login(&utmp); } dolastlog(quietlog); if (!hflag) { /* XXX */ static struct winsize win = { 0, 0, 0, 0 }; (void)ioctl(0, TIOCSWINSZ, &win); } (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); (void)chmod(ttyn, 0620); (void)setgid(pwd->pw_gid); initgroups(username, pwd->pw_gid); #ifndef NeXT quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); #endif if (*pwd->pw_shell == '\0') pwd->pw_shell = _PATH_BSHELL; /* turn on new line discipline for the csh */ else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { ioctlval = NTTYDISC; (void)ioctl(0, TIOCSETD, &ioctlval); } /* real NeXT source diverges here */ /* destroy environment unless user has requested preservation */ #ifdef NeXT if (!pflag){ envinit[0]=(char *)NULL; environ = envinit; } #else if (!pflag) environ = envinit; #endif (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", pwd->pw_shell, 1); if (term[0] == '\0') strncpy(term, stypeof(tty), sizeof(term)); (void)setenv("TERM", term, 0); (void)setenv("USER", pwd->pw_name, 1); (void)setenv("PATH", _PATH_DEFPATH, 0); /* real NeXT source merges here */ if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); if (pwd->pw_uid == 0) if (hostname) syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", tty, hostname); else syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); if (!quietlog) { struct stat st; motd(); (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) (void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); } (void)signal(SIGALRM, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); tbuf[0] = '-'; strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); #ifndef NeXT if (setlogname(pwd->pw_name, strlen(pwd->pw_name)) < 0) syslog(LOG_ERR, "setlogname() failure: %m"); #endif /* discard permissions last so can't get killed and drop core */ (void)setuid(pwd->pw_uid); #if defined(NeXT) && !defined(ORIGINAL) execlp(pwd->pw_shell, tbuf, /* enable job control! */ strcmp(pwd->pw_shell, _PATH_BSHELL) ? 0 : "-J", 0); #else execlp(pwd->pw_shell, tbuf, 0); #endif (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); exit(0); } getloginname() { register int ch; register char *p; static char nbuf[UT_NAMESIZE + 1]; for (;;) { (void)printf("login: "); for (p = nbuf; (ch = getchar()) != '\n'; ) { if (ch == EOF) { badlogin(username); exit(0); } if (p < nbuf + UT_NAMESIZE) *p++ = ch; } if (p > nbuf) if (nbuf[0] == '-') (void)fprintf(stderr, "login names may not start with '-'.\n"); else { *p = '\0'; username = nbuf; break; } } } timedout() { (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); exit(0); } rootterm(ttyn) char *ttyn; { struct ttyent *t; return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); } jmp_buf motdinterrupt; motd() { register int fd, nchars; int (*oldint)(), sigint(); char tbuf[8192]; if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) return; oldint = signal(SIGINT, sigint); if (setjmp(motdinterrupt) == 0) while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); (void)signal(SIGINT, oldint); (void)close(fd); } sigint() { longjmp(motdinterrupt, 1); } checknologin() { register int fd, nchars; char tbuf[8192]; if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); sleepexit(0); } } dolastlog(quiet) int quiet; { struct lastlog ll; int fd; char *ctime(); if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { (void)printf("Last login: %.*s ", 24-5, (char *)ctime(&ll.ll_time)); if (*ll.ll_host != '\0') (void)printf("from %.*s\n", sizeof(ll.ll_host), ll.ll_host); else (void)printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line); } (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); } bzero((char *)&ll, sizeof(ll)); (void)time(&ll.ll_time); strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); if (hostname) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); (void)write(fd, (char *)&ll, sizeof(ll)); (void)close(fd); } } badlogin(name) char *name; { if (failures == 0) return; if (hostname) syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", failures, failures > 1 ? "S" : "", hostname, name); else syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", failures, failures > 1 ? "S" : "", tty, name); } #undef UNKNOWN #define UNKNOWN "su" char * stypeof(ttyid) char *ttyid; { struct ttyent *t; return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); } /* NeXT has their version of setenv here */ getstr(buf, cnt, err) char *buf, *err; int cnt; { char ch; do { if (read(0, &ch, sizeof(ch)) != sizeof(ch)) exit(1); if (--cnt < 0) { (void)fprintf(stderr, "%s too long\r\n", err); sleepexit(1); } *buf++ = ch; } while (ch); } sleepexit(eval) int eval; { sleep((u_int)5); exit(eval); } #ifdef NeXT /* * 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[] = "@(#)login.c 5.1 (Berkeley) 9/27/88"; #endif /* LIBC_SCCS and not lint */ #ifdef NOTDEF /* included above */ #include #include #include #include #endif #define UTMPFILE "/etc/utmp" #define WTMPFILE "/usr/adm/wtmp" void login(ut) struct utmp *ut; { register int fd; int tty; off_t lseek(); tty = ttyslot(); if (tty > 0 && (fd = open(UTMPFILE, O_WRONLY, 0)) >= 0) { (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET); (void)write(fd, (char *)ut, sizeof(struct utmp)); (void)close(fd); } if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) >= 0) { (void)write(fd, (char *)ut, sizeof(struct utmp)); (void)close(fd); } } #endif #if defined(NeXT) && defined(FIX8BIT) NeXT_repair_line(int fd) { int bitset = LPASS8 | LPASS8OUT; int bitclr = LNOHANG; ioctl(fd, TIOCLBIS, &bitset); ioctl(fd, TIOCLBIC, &bitclr); } #endif mgetty-1.1.36/contrib/next-login/pathnames.h0100644000031200000620000000255406152102553017641 0ustar gertgroup/* * Copyright (c) 1989 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 */ #ifdef NeXT #define _PATH_BSHELL "/bin/sh" #define _PATH_CSHELL "/bin/csh" #define _PATH_LASTLOG "/usr/adm/lastlog" #define _PATH_TTY "/dev/tty" #define _PATH_DEFPATH ":/usr/ucb:/bin:/usr/bin:/usr/local/bin" #define _PATH_HUSHLOGIN ".hushlogin" #define _PATH_MAILDIR "/usr/spool/mail" #else #include #define _PATH_DEFPATH "/bin:/usr/bin:/usr/games:" #define _PATH_HUSHLOGIN ".hushlogin" #define _PATH_MAILDIR "/var/spool/mail" #endif #define _PATH_MOTDFILE "/etc/motd" #define _PATH_NOLOGIN "/etc/nologin" mgetty-1.1.36/contrib/next-login/setenv.c0100644000031200000620000000720106152102553017152 0ustar gertgroup/* * Copyright (c) 1987 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 sccsid1[] = "@(#)setenv.c 5.3 (Berkeley) 5/16/90"; #ifndef NeXT static char sccsid2[] = "@(#)getenv.c 5.6 (Berkeley) 5/16/90"; #endif #endif /* LIBC_SCCS and not lint */ /* * setenv -- * Set the value of the environmental variable "name" to be * "value". If rewrite is set, replace any current value. */ setenv(name, value, rewrite) register char *name, *value; int rewrite; { extern char **environ, *malloc(); static int alloced; /* if allocated space before */ register char *C; int l_value, offset; static char *_findenv(); if (*value == '=') /* no `=' in value */ ++value; l_value = strlen(value); if ((C = _findenv(name, &offset))) { /* find if already exists */ if (!rewrite) return(0); if (strlen(C) >= l_value) { /* old larger; copy over */ while (*C++ = *value++); return(0); } } else { /* create new slot */ register int cnt; register char **P; for (P = environ, cnt = 0; *P; ++P, ++cnt); if (alloced) { /* just increase size */ environ = (char **)realloc((char *)environ, (sizeof(char *) * (cnt + 2))); if (!environ) return(-1); } else { /* get new space */ alloced = 1; /* copy old entries into it */ P = (char **)malloc((sizeof(char *) * (cnt + 2))); if (!P) return(-1); bcopy(environ, P, cnt * sizeof(char *)); environ = P; } environ[cnt + 1] = 0; offset = cnt; } for (C = name; *C && *C != '='; ++C); /* no `=' in name */ if (!(environ[offset] = /* name + `=' + value */ malloc(((int)(C - name) + l_value + 2)))) return(-1); for (C = environ[offset]; (*C = *name++) && *C != '='; ++C); for (*C++ = '='; *C++ = *value++;); return(0); } /* * unsetenv(name) -- * Delete environmental variable "name". */ void unsetenv(name) char *name; { extern char **environ; register char **P; int offset; static char *_findenv(); while (_findenv(name, &offset)) /* if set multiple times */ for (P = &environ[offset];; ++P) if (!(*P = *(P + 1))) break; } #ifndef NeXT /* * getenv -- * Returns ptr to value associated with name, if any, else NULL. */ char * getenv(name) char *name; { int offset; static char *_findenv(); return(_findenv(name, &offset)); } #endif /* * _findenv -- * Returns pointer to value associated with name, if any, else NULL. * Sets offset to be the offset of the name/value combination in the * environmental array, for use by setenv(3) and unsetenv(3). * Explicitly removes '=' in argument name. */ static char * _findenv(name, offset) register char *name; int *offset; { extern char **environ; register int len; register char **P, *C; for (C = name, len = 0; *C && *C != '='; ++C, ++len); for (P = environ; *P; ++P) if (!strncmp(*P, name, len)) if (*(C = *P + len) == '=') { *offset = P - environ; return(++C); } return(0); } mgetty-1.1.36/contrib/ptylogin/Makefile0100644000031200001470000000123406650144621016356 0ustar gertfax# /* Makefile -- ptylogin makefile # * Marc SCHAEFER # * Creation: 10/01/98 # * Update: 10/01/98 # * V1.0 PV001 # * DESCRIPTION # * This makes ptylogin. # * NOTES # * BUGS # * TODO # * COPYING-POLICY # * (C) Marc SCHAEFER, under the GPL # * BASED-ON # * Original code. # * MODIFICATION-HISTORY # * 10/01/99 schaefer Created this file. # * $Id: Makefile,v 1.1 1999/01/16 17:17:05 gert Exp $ # */ CFLAGS=-Wall LDFLAGS= LIBS=-lbsd CC=gcc SOURCE=ptylogin.c EXECUTABLE=ptylogin all: $(EXECUTABLE) clean: rm -f $(EXECUTABLE) $(EXECUTABLE): $(SOURCE) $(CC) $(SOURCE) $(CFLAGS) $(LDFLAGS) $(LIBS) -o $(EXECUTABLE)mgetty-1.1.36/contrib/ptylogin/TESTS0100644000031200001470000000105106661266155015551 0ustar gertfax- tested that it hangups when user's program exits: DONE - tested that it closes the pty when user hangups: DONE - tested binary SEND and CPU usage: file ok, CPU usage is quite high. DONE - tested binary RECEIVE and CPU usage: file ok, CPU usage is far lower than before. DONE (so maybe a problem in the selection loop when a lot of data goes TO the modem through ptylogin, ie write). - tested lastlog/utmp: - in exit case: *BUG*: not updated - in hangup case: not tested - tested correct mode/owner on tty: yes. DONE mgetty-1.1.36/contrib/ptylogin/ptylogin.10100444000031200001470000000604206646142104016644 0ustar gertfax.TH ptylogin 1 "10 january 1999" .IX ptylogin .SH NAME ptylogin \-\ replacement for mgetty's login.config rlogin hack fixing security and denial of service problems with ownership of tty. .SH SYNOPSIS .B ptylogin login-name .SH DESCRIPTION This manual page documents .BR ptylogin . .B ptylogin is launched from mgetty's login.config configuration file with root priviledges. It opens a pty slave/master pair, and forks /bin/login. It ensures data stream is 8 bit. This means that the user which logs in will not be connected to the tty of the modem, but to a pty. The pty slave will be owned (because of /bin/login) by the logged-on user. The modem tty will be owned by root, and permissions will be rw access for root only. That tty doesn't need, by the way, to be logged-in. When the modem disconnects, the master pty is closed and a SIGHUP is transmitted to the other side. The worse that the user can then do is leave their process on if they disabled the SIGHUP. However they can't access the modem device nor reopen it. For enhanced security we assume the escape sequence of the modem is disabled, and that a modem hangup from the user calling our local modem causes a SIGHUP to the ptylogin process. Please look at the .B Paranoid Secure Port Implementation RCS revision SPEC,v 1.6 1999/01/05 08:41:46 or later for all details of the problem ptylogin fixes (it's quite tricky). .SS OPTIONS .I "\login-name" This must be a 8 char maximum login name to launch login into, must exist, and may not contain \- or spaces. As .B /bin/login is not launched through system() but instead with exec(), common attacks like semicolons or other separators cannot happen. .SH EXAMPLES The login.config could be configured like this: .I "* root dialin /usr/bin/ptylogin @" Note that if you specify users which bypass this default, for example for PPP, FTN or UUCP, you would enter something like .I "uu* \- \- /bin/login.one @" .B WARNING: You must use a login program which doesn't allow more than one retry. Else interactive users can bypass the default ptylogin restricted login. .SH AUTHOR Marc SCHAEFER .SH VERSION Manual version 1.0 PV001 documents ptylogin version 1.0 .SH NOTES .SH BUGS Please look at the source. .SH TODO .SH BASED\-ON \- An idea to simplify rlogin and still fix the problems from Theodore Y. Ts'o \- rlogind and rlogin code from Linux NetKit-0.09 \- virtual_connection from Marc SCHAEFER .SH HISTORY .SH COPYRIGHT This work is (C) Marc SCHAEFER 1999 and has been done in my free time. However, it is placed under the GPL and thus any use is authorized as long as you do not prevent others from using it and accessing the original source code or your extensions. .SH DISCLAIMER The author hereby disclaims any warranty, either expressed or implied, regarding this software and documentation. The fact that this software attempts to fix a security vulnerability doesn't mean that it doesn't have any vulnerability, some which could be more serious than the one it tries to fix. mgetty-1.1.36/contrib/ptylogin/ptylogin.c0100644000031200001470000002216606650144624016741 0ustar gertfax/* ptylogin.c -- links the current tty to a /bin/login process through * a pty pair * Marc SCHAEFER * Creation: 10/01/98 * Update: 10/01/98 * V1.0 PV001 * DESCRIPTION * This emulates a rlogin -8E -l USER localhost from mgetty's login.conf * without the need for two sockets, two processes, and networking * running. * This allows to prevent direct control of the modem tty by a * malicious user, work-arounding many Denial of Service or even * security problems. Please look at the ``Paranoid Secure Port * Implementation'', RCS revision SPEC,v 1.6 1999/01/05 08:41:46 or * later for all details. * USAGE * See manpage. * RESULT * 0 everything fine * 1 couldn't exec() /bin/login or allocate pty. * 2 missing argument, illegal login name or not running as root. * NOTES * - This should NOT be suid as it is not necessary and it has not * been designed to be run outside of mgetty's login.config. * BUGS * TODO * - Test * - Do we need to ensure running as root for pty security ? * - Do we need to change tty permission and owner or is it done by * mgetty ? * - Alternative pty allocation code not needing root ? (there is * code floating around for Linux). * - Ask people to review the code and the specification. * ASSUMPTIONS * - This is called with root priviledges since this is more secure * in term of tty ownership and pty allocation. * COPYING-POLICY * (C) Marc SCHAEFER, under the GPL * parts Copyright (c) 1983, 1988, 1989 * The Regents of the University of California * BASED-ON * - A problem described by Marc SCHAEFER in the above Paranoid * specification. * - An idea to simplify rlogin and still fix the problems from * "Theodore Y. Ts'o" * - rlogind and rlogin code from Linux NetKit-0.09, BSD license. * - virtual_connection from Marc SCHAEFER , GPL. * MODIFICATION-HISTORY * 10/01/99 schaefer Created this file. * $Id: ptylogin.c,v 1.1 1999/01/16 17:17:08 gert Exp $ */ #include #include #include #include #include #include #include #include #include #include /* Macro and definitions */ #define MAXIMUM_LOGIN_NAME_LENGTH 8 #define PTS_NAME_SIZE 20 #define _PATH_LOGIN "/bin/login" #define BUFFER_LENGTH 4096 #undef MGETTY_HAS_SET_OWNER_AND_MODE /* ptylogin does it */ /* Public function definitions and hacks */ /* BUGS * - Should be in libbsd.h or similar include file. */ pid_t forkpty(int *, char *, struct termios *, struct winsize *); /* Private type definitions */ #ifndef fd_t typedef int fd_t; #endif /* !fd_t */ /* Private function definitions */ /* NAME * connect_login * DESCRIPTION * Connects this process to the /bin/login process through a pty * pair. Do any local tty initialization (including chmod()/chown()). * RESULT * exit code * 0 session terminated normally (hangup or exit) * 1 couldn't spawn child or open ptys. * NOTES * BUGS * TODO */ static int connect_login(char *login_name); /* NAME * reject_login_name * DESCRIPTION * Verify the constraints on the login name, which are that it doesn't * dashes (-) or spaces (only normal spaces), and it 8 characters * long or less. * RESULT * 0 if the constraint DO apply and the login name should be * accepted, else different of zero and the login should be rejected. * NOTES * - We tested this function with 7, 8 and 9 characters. We also tested * one hash at the end and beginning and one space at the end. In all * case the function answered as expected. * BUGS * TODO * - Theoretically those constraints are already mostly handled by * mgetty. Check this. Until then we do it here. */ static int reject_login_name(char *login_name); /* NAME * set_raw * DESCRIPTION * Sets the stdin tty to raw (if mode == 1), else cooked. * RESULT * NONE * NOTES * - Each call to set_raw(0) must have been after a corresponding * and unnested call to set_raw(1) because of internal state. * BUGS * TODO */ static void set_raw(int mode); /* Public constants */ char rcsid[] = "$Id: ptylogin.c,v 1.1 1999/01/16 17:17:08 gert Exp $"; /* Private constants */ /* Private variables */ static struct winsize win = { 0, 0, 0, 0 }; static struct termio saved; /* Internal state for set_raw() */ /* Function implementation */ int main(int argc, char **argv) { if (argc == 2) { if ((getuid() == 0) && (geteuid() == 0)) { if (!reject_login_name(argv[1])) { exit(connect_login(argv[1])); } else { fprintf(stderr, "%s: illegal length or character(s) in login name.\n", argv[0]); exit(2); } /* NOT REACHED */ } else { fprintf(stderr, "%s: not running as root.\n", argv[0]); exit(2); } /* NOT REACHED */ } else { fprintf(stderr, "%s login-name\n%s: bad args.\n", argv[0], argv[0]); exit(2); } /* NOT REACHED */ } static int reject_login_name(char *login_name) { return (strlen(login_name) > MAXIMUM_LOGIN_NAME_LENGTH) || (strchr(login_name, ' ')) || (strchr(login_name, '-')); } static int connect_login(char *login_name) { pid_t pid; fd_t master_fd; char line[PTS_NAME_SIZE]; #ifndef MGETTY_HAS_SET_OWNER_AND_MODE if (fchown(0, 0, 0)) { perror("fchown()"); return 1; } else if (fchmod(0, 0600)) { perror("fchmod()"); return 1; } #endif /* !MGETTY_HAS_SET_OWNER_AND_MODE */ switch (pid = forkpty(&master_fd, line, NULL, &win)) { case 0: /* Child. Setup slave and exec /bin/login */ /* ASSUMPTIONS * - No other open file except slave pty, which is on 0/1/2. * - Controlling tty set. */ /* NOTES * - Keeping whole environment. */ execl(_PATH_LOGIN, "login", login_name, NULL); return 1; /* if arriving here, something wrong */ break; default: /* Parent */ if (pid < 0) { if (errno == ENOENT) { perror("Out of ptys"); } else { perror("forkpty()"); } return 1; } else { int ok = 1; int nfound; fd_set readfds; fd_set writefds; char from[BUFFER_LENGTH]; char to[BUFFER_LENGTH]; int infrom = 0; int into = 0; int temp; /* Transfer bytes transparently until SIGHUP or EOF */ set_raw(1); while (ok) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(0, &readfds); FD_SET(master_fd, &readfds); if (infrom) { FD_SET(1, &writefds); } if (into) { FD_SET(master_fd, &writefds); } /* from: buffer used to store data from remote site to be output * to stdout (1). (read from master_fds) * to: buffer used to store data from `modem' to be output to * socket. (read from 0). */ nfound = select(master_fd + 1, &readfds, &writefds, NULL, NULL); if (nfound) { if (FD_ISSET(0, &readfds)) { if (into < BUFFER_LENGTH) { temp = read(0, to + into, BUFFER_LENGTH - into); if (temp == -1 || temp == 0 ) { ok = 0; } else { into += temp; } } /* else we will do it later. */ } if (FD_ISSET(master_fd, &readfds)) { if (infrom < BUFFER_LENGTH) { temp = read(master_fd, from + infrom, BUFFER_LENGTH - infrom); if (temp == -1 || temp == 0) { ok = 0; } else { infrom += temp; } } /* else we will do it later. */ } if (FD_ISSET(1, &writefds)) { if (infrom > 0) { temp = write(1, from, infrom); if (temp == -1 ) { ok = 0; } else { infrom -= temp; } } } if (FD_ISSET(master_fd, &writefds)) { if (into > 0) { temp = write(master_fd, to, into); if (temp == -1 ) { ok = 0; } else { into -= temp; } } } } } set_raw(0); return 0; } break; } printf("connect"); return 0; } void set_raw(int mode) { struct termio tty; /* ASSUMPTION * - Doing it for 0 also does it for 1 (device-wide). */ if (!mode) { ioctl(0, TCSETAW, &saved); } else { ioctl(0, TCGETA, &tty); ioctl(0, TCGETA, &saved); tty.c_iflag = (IGNBRK); /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */ tty.c_lflag &= ~(ECHO | ICANON | ISIG); tty.c_oflag = 0; /* Transparent output */ tty.c_cflag &= ~PARENB; /* Same baud rate, disable parity */ tty.c_cflag |= CS8; /* Set character size = 8 */ /* NOTES * - We assume mgetty set crtscts. */ tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */ tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ ioctl(0, TCSETAW, &tty); } } mgetty-1.1.36/contrib/Makefile0100644000031200000050000000106510377121514014677 0ustar gertuucp# # Makefile for miscellaneous stuff in contrib # # # settings for CC, CFLAGS imported from above # (call with "make contrib-all" from top level mgetty directory) all: faxin FIOBJS=faxin.o \ ../modem.o ../faxlib.o ../faxrec.o ../faxsend.o ../faxhng.o \ ../logfile.o ../io.o ../tio.o ../getdisk.o faxin: $(FIOBJS) $(CC) $(CFLAGS) $(LDFLAGS) -o faxin $(FIOBJS) $(LIBS) faxin.o: faxin.c ../mgetty.h ../policy.h $(CC) $(CFLAGS) $(LDFLAGS) -I.. -c -o faxin.o faxin.c $(LIBS) g3hack: g3hack.c $(CC) $(CFLAGS) -o g3hack g3hack.c clean: rm -f faxin g3hack *.o mgetty-1.1.36/contrib/README0100644000031200000620000001464406152152212014304 0ustar gertgroupMuch of this stuff is contributed by someone else, so please don't ask *me*. gert ----------------------------------------------------------- next-login/ Replacement for /bin/login on NeXT machines (standard one has problems with 8-Bit characters) ----------------------------------------------------------- autoprint.sh make the "print" command of ELM/MUSH print the incoming fax instead if you feed it a "a fax has arrived" mail. ----------------------------------------------------------- logparse.c A Logfile parser for sendfax-Logfiles ----------------------------------------------------------- faxman.pl / faxman.doc Fax Manager: view incoming / outgoing fax queues, manipulate faxes, print, ... - Klaus Lichtenwalder (klaus@gaston.m.isar.de) (now in ../frontends/tkperl) ----------------------------------------------------------- faxview.tcl Fax viewer using Tcl/Tk, from Ralf Schleicher (rs@purple.in-ulm.de) (now in ../frontends/tcl) ----------------------------------------------------------- faxdvi-1.1.tar Tool suite for even better interaction of faxspool/sendfax with TeXdvi, written by Ralf Schleicher . NOT INCLUDED (too big), but you can get it from ftp.informatik.tu-muenchen.de, in the /pub/comp/networking/communication/modems/mgetty/ directory. ----------------------------------------------------------- faxdvi2.perl Part of that suite, make faxing of .dvi files more comfortable. ----------------------------------------------------------- ttyenable script to enable / disable /etc/inittab entries for a given tty line (H.P.Heidinger) ----------------------------------------------------------- readme.supra some notes about some SUPRA Faxmodem releases that tend to forget about the RTS/CTS handshake settings ----------------------------------------------------------- log_diags Some patches by Uwe S. Fuerst, to include diagnostic informations about the last connection made into the mgetty log files (configurable for different modem types). Look at it, instructions / examples included. ----------------------------------------------------------- dvi-fax A brief instruction how to make "dvips" generate high-quality 204x196 dpi fonts for fax files (far better output quality than with re-scaled 300 dpi fonts). klaus@snarc.greenie.muc.de ----------------------------------------------------------- ../samples/new_fax.lj A sample script to print incoming faxes on a HP laserjet. Use as "FAX_NOTIFY_PROGRAM" (policy.h). klaus@snarc.greenie.muc.de ----------------------------------------------------------- ../samples/new_fax.mail A sample script to mail away incoming faxes. gert@greenie.muc.de ----------------------------------------------------------- ../samples/new_fax.mime A sample script to send incoming faxes as MIME mail to ``faxmaster'' Marc@Synergytics.Com ----------------------------------------------------------- lp-fax A printer driver for SCO Unix (and ODT), to send faxes with "lp -dfax -oto=" from within any application Used as "/usr/spool/lp/admins/lp/interfaces/fax" script. gert@greenie.muc.de ----------------------------------------------------------- faxiobe.sh A fax driver backend for IBM AIX (provided by Michael Staats). Readme included in the shell archive. michael@hal6000.thp.uni-duisburg.de ----------------------------------------------------------- gslp-iso.p A patch to ghostscript's "gslp.ps" to be able to use all iso-8859- characters (including national special characters). arne@mars.rmt.sub.org ----------------------------------------------------------- gs-security.fix A patch to ghostscript's "gs_init.ps" to prevent ugly things from happening if you view "bad-guy-postscript". juphoff@nrao.edu ----------------------------------------------------------- 3b1 Some additional hints about AT&T's 3B1 and mgetty+sendfax. ----------------------------------------------------------- faxin.c compile, link with logfile.o, faxlib.o, faxrec.o and you have a standalone fax receiver that could be called upon receipt of "+FCON" from any getty or login program. Options: "-x ", "-d " Make: just go to the mgetty directory, call "make contrib-all" gert@greenie.muc.de ----------------------------------------------------------- scrts.c A small tool for linux (only), to set the CRTSCTS hardware handshake flag. Compile it with "cc -o scrts scrts.c", use it with "scrts " It will (if possible) open the port in non-blocking mode (you need this if "stty crtscts A small program to convert G3 input to X11 screen dumps (xwd) - a lot faster than g3tobpm |pbmtoxwd ----------------------------------------------------------- g3tolj.c From: Chel van Gennip A small program to convert G3 input to HP laserjet output ----------------------------------------------------------- two-modems Instruction + patches to use mgetty with two modems on a line, one for fax-only and one for data-only. ----------------------------------------------------------- ../dialog/listen A small utility to browse through incoming voice messages, play them or delete them. nelson@crynwr.com (Russell Nelson), klaus@snarc.greenie.muc.de (Klaus Weidner) ----------------------------------------------------------- pbmscale.c From: Chel van Gennip To: gert@greenie.muc.de Subject: Re: FAX software to run under SCO ???? [...] To improve the speed of handling faxes I made a simple pbmscale program to scale portable bitmaps without converting them to graymaps. I'll include the source in this mail. To use it with pbmplus you only need some trivial changes in pbmmerge.c an Makefile. Typical usage: cat faxn... |g3topbm|pbmscale -scale 0.35 -aspect 2.0| pnmtoxdm |xdum or cat faxn... |g3topbm|pbmscale -scale 1.35 -aspect 2.0| pbmtolj | lp -d hpdeskjet [...] From: Chel van Gennip To: gert@greenie.muc.de >Do you have some explantation of all the switches? pbmscale [-scale N] [-aspect N] [-stretch] [pbmfile]"; -scale N Scale x and y by factor N, eg. -scale 1.35 -aspect N, N is multiplier for the y scale factor eg. -aspect 1.9 -stretch equivalent with -aspect 2.0 So the resulting bitmap is *x by **y dots. Regards, Chel ----------------------------------------------------------- mgetty-1.1.36/contrib/3b10100644000031200000620000001201505447603270013735 0ustar gertgroupHi, here are a few mails explaining how to get mgetty+sendfax to work on the 3B1 machines (with the mail addresses of people who got it to work). A few words on my own: - the 3B1 cannot do more than 1920 bps - so #define FAX_SEND_BAUD and DEFAULT_PORTSPEED to B19200 - maybe it's necessary to remove the lines in sendfax.c where CLOCAL gets cleared (around line 446): ------- /* by now, the modem should have raised DCD, so remove CLOCAL flag */ fax_termio.c_cflag &= ~CLOCAL; ioctl(...) ------- gert ------------------------------------------------ To: Subject: Re: mgetty-sendfax Message-Id: <9307190917.AA02797@gladys.UUCP> Date: Mon, 19 Jul 1993 18:17:14 +0200 From: gladys!dalton@PacBell.COM (David Dalton) Greetings, Gert... Thanks for answering my message about mgetty-sendfax. You asked where I found the socket code for my AT&T 3B1. This machine is well-supported by hackers (it's almost a cult), and there is an archive at cheops.cis.ohio-state.edu The socket code lives in: pub/att7300/kernel/uipc.tar.Z The socket emulation seems reliable, but it did not include all the header files needed to compile mgetty-sendfax. Several calls brought trouble: timeval, fd_set, and bzero. I did have the necessary objects, but I had to scrounge to find some header files. I pieced together what I needed from the uipc source code and from include files at crl.com, where I have an account. [...] Regards, David Dalton dalton@gladys.uucp pacbell!gladys!dalton -------------------------------------------------------------------------------- From: "Glenn E. Thobe" To: gert@greenie.muc.de Subject: mgetty+sendfax 3b1 patches, Part 1 of 2 ========================= begin 3b1 instructions ================= Installing and using mgetty+sendfax on the AT&T pc7300/unixpc/3b1 mgetty+sendfax won't compile on a 3b1 with only the stock development system, you need a few extras: The socket library with select is kernel/uipc.tar.Z at either osu-cis (archive.cis.ohio-state.edu: pub/att7300) or uunet (ftp.uu.net: systems/att7300). This is essentially the same as what comes with the 3b1 distribution of MGR, which is what I used. Those who have ethernet or starlan, may prefer to use the libraries that come with them (this hasn't been tried). The PBMPLUS sources and patches are in the 1991 comp.sources.misc. You can get supposedly get the fully patched sources in compressed tar form from one of: export.lcs.mit.edu:contrib/pbmplus.tar.Z ftp.ee.lbl.edu:pbmplus.tar.Z where is probably "05dec91". The 3b1 archives (osu-cis and uunet) have binaries for a much older version of PBMPLUS. I compiled with GCC 2.4.5 (binaries from ftp.cs.caltech.edu: pub/3b1). My header files in /usr/include and /usr/include/sys are no longer stock as I consider it more productive to bring the headers up to date than to modify application software to compile with outdated headers. Comp.sources.3b1 has ported BSD headers (bsd-incl) and more-or-less ansified headers (ansihdr) which may prove helpful, at least as a guide, to those who wish to follow this road. You must add -D_3B1_ to your CFLAGS definition in the Makefile. mgetty+sendfax depend on other utilities to compose the g3 format fax image for transmission or to convert the received g3 format image to something that can be viewed on the screen or printed. For composing, you can use pbmtext and the modified pbmtog3. For more flexibility use LaTeX and either dvips or dvialw (or any other combination of utilites you like) to produce PostScript, and use ghostscript (get 3b1 binaries from ftp.cs.caltech.edu) to produce g3. For viewing, you may use g3topbm and either pbmto3b1 for stock TAM windows (get it from uunet or osu-cis) or mview for MGR (get mgrabscr from comp.sources.3b1). Mview has a minor bug which means you must read the PBM image from a file. WARNING, reading beyond this point may endanger your sanity! The 3b1's limited VM means that g3topbm will bomb on full size pages, so I ported Sam Leffler's TIFF library and built fax2tiff and do the following: fax2tiff -M incoming_fax.g3; tifftopnm fax.tiff | pbmtowhatever Unfortunately you can't build the g3 part of the TIFF library on the 3b1 without some machinations because there is not enough VM to compile g3states.h. My answer to this was to modify mkg3state.c to output the state tables in the form of a gas (GNU assembler) source file, which assembles easily, and an abbreviated g3states.h which references the state tables as "extern". The assembled state tables go into libtiff.a. If you don't want to fool with TIFF, you can probably rewrite g3topbm so it doesn't overflow VM. I also modified pbmtoepson (for Epson FX and related 9-pin printers) to produce the highest possible resolution of 240 dpi x 216 dpi and to economize on VM. I am working on a way to make my results (TIFF and pbmtoepson) and available. -Glenn Thobe Thu Sep 16 15:07:57 PDT 1993 ========================= end 3b1 instructions =================== mgetty-1.1.36/contrib/dvi-fax0100644000031200000620000001577105550336244014721 0ustar gertgroupFrom owner-mgetty Tue Jan 25 23:58:10 1994 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.3) id ; Tue, 25 Jan 94 23:58 MET Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.3) id ; Tue, 25 Jan 94 23:58 MET Received: from greenie by colin.muc.de with UUCP id <22327>; Tue, 25 Jan 1994 23:41:49 +0100 Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.3) id ; Tue, 25 Jan 94 20:55 MET Received: by snarc.greenie.muc.de (Linux Smail3.1.28.1 #14) id m0pOt9a-0002hNC; Tue, 25 Jan 94 20:10 MET Message-Id: From: klaus@snarc.greenie.muc.de (Klaus Weidner) Subject: Generating 204x196 fonts for TeX To: mgetty@muc.de (mgetty mailing list) Date: Tue, 25 Jan 1994 20:10:20 +0100 X-Mailer: ELM [version 2.4 PL21] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Length: 5276 Status: RO Hello, due to popular request (hello Gert...), here is a description of what you have to do to get high-quality fonts for your fax files. If you use the usual setup, you will probably end up scaling down the 300dpi bitmap fonts available on your system to 204x196dpi needed for faxing. This works, but the quality of the resulting fonts is awful, and Donald Knuth will probably send the International Font Police after you for such cruel abuse of a wonderful typesetting program. There are three steps you have to take care of to get better results: - your dvi-to-whatever converter has to use the right font size - metafont has to be set up to generate fonts of the right resolution when needed. - both programs have to agree where the fonts are stored. I use dvips to convert the dvi input to PostScript and then GhostScript to generate g3 fax files. The paths used below are those used on my system, you will have to edit them to match your setup. A shell script takes care of everything from the user's point of view: % dvi2fax test.dvi creates the file(s) test-001.fax (one per page) in the current directory, which can then be passed on to sendfax. The script looks like this: ----- dvi2fax ------------------------------------------------------------ #! /bin/sh for i do NAME=`basename $i .dvi` dvips -P dfaxhigh $NAME.dvi -o $NAME.ps gs -sDEVICE=dfaxhigh -sOutputFile=$NAME-%03d.fax -sNOPAUSE -- $NAME.ps done -------------------------------------------------------------------------- This calls dvips with a printer name of `dfaxhigh'. The `-P' flag tells dvips to use the following configuration file: --- /usr/TeX/lib/tex/ps/config.dfaxhigh ---------------------------------- M GThreeFaxHigh X 204 Y 196 -------------------------------------------------------------------------- (M defines the configuration Metafont will use to generate the font, X and Y define the resolution in dots/inch.) You will have to define a Metafont mode for creating the fax fonts, by default it only knows about low-resolution faxes. Put the following definition into /usr/TeX/lib/mf/macros/modes.mf: --- /usr/TeX/lib/mf/macros/modes.mf -------------------------------------- [...] mode_def GThreeFaxHigh = % 204 x 196dpi G3fax mode_param (pixels_per_inch, 204); mode_param (aspect_ratio, 196 / pixels_per_inch); mode_param (blacker, 0); mode_param (fillin, .2); mode_param (o_correction, .2); mode_common_setup_; enddef; -------------------------------------------------------------------------- Then create a new metafont base file: inimf "plain; input modes; dump" mv plain.base /usr/TeX/lib/mf/bases/mf.base Now Metafont knows how to generate fonts at the right resolution. Dvips will check if the needed fonts exist, and if they don't, it will call MakeTeXPK to create them. On my system, the G3 fonts have filenames like `/usr/TeX/lib/tex/fonts/GThreeFaxHigh/cmr10.204pk'. The environment variable TEXPKS is used to tell dvips, xdvi and other programs where the fonts are stored: TEXPKS=/usr/TeX/lib/tex/fonts/%m/%f.%dpk (%m is replaced with the Metafont `mode', %f with the font name and %d with the X pixel size.) If the font doesn't exist, dvips will call a shell script like this: MakeTeXPK The MakeTeXPK script was included in my TeX distribution, I have edited it to match my setup: --- MakeTeXPK ------------------------------------------------------------ #!/bin/sh # # This script file makes a new TeX PK font, because one wasn't # found. Parameters are: # # name dpi bdpi magnification [mode [subdir]] # # `name' is the name of the font, such as `cmr10'. `dpi' is # the resolution the font is needed at. `bdpi' is the base # resolution, useful for figuring out the mode to make the font # in. `magnification' is a string to pass to MF as the # magnification. `mode', if supplied, is the mode to use. # # Note that this file must execute Metafont, and then gftopk, # and place the result in the correct location for the PostScript # driver to find it subsequently. If this doesn't work, it will # be evident because MF will be invoked over and over again. # # Of course, it needs to be set up for your site. # TEXDIR=/usr/TeX/lib/tex LOCALDIR=/usr/TeX/lib/tex # # TEMPDIR needs to be unique for each process because of the possibility # of simultaneous processes running this script. # if test "$TMPDIR" = "" then TEMPDIR=/tmp/mtpk.$$ else TEMPDIR=$TMPDIR/mtpk.$$ fi NAME=$1 DPI=$2 BDPI=$3 MAG=$4 MODE=$5 if [ -z "$MODE" ] then case $BDPI in 204) MODE=GThreeFaxHigh ;; 240) MODE=EpsonMXFX ;; *) MODE=localfont ;; esac fi DESTDIR=$LOCALDIR/fonts/$MODE GFNAME=$NAME.$DPI'gf' PKNAME=$NAME.$DPI'pk' # Clean up on normal or abnormal exit trap "cd /; /bin/rm -rf $TEMPDIR $DESTDIR/pktmp.$$" 0 1 2 15 if test ! -d $DESTDIR then mkdir $DESTDIR fi if test "$6" != "" then DESTDIR=$DESTDIR"$6" if test ! -d $DESTDIR then mkdir $DESTDIR fi fi mkdir $TEMPDIR cd $TEMPDIR if test -r $DESTDIR/$PKNAME then echo "$DESTDIR/$PKNAME already exists!" exit 0 fi # check also in the standard place if test "$6" = "" then if test -r $TEXDIR/fonts/$PKNAME then echo $TEXDIR/fonts/$PKNAME already exists! exit 0 fi else if test -r $TEXDIR/fonts/$6"$PKNAME" then echo $TEXDIR/fonts/$6"$PKNAME" already exists! exit 0 fi fi echo "mf \"\\mode:=$MODE; mag:=$MAG; scrollmode; input $NAME\" < /dev/null" mf "\mode:=$MODE; mag:=$MAG; scrollmode; input $NAME" < /dev/null if test ! -r $GFNAME then echo "Metafont failed for some reason on $GFNAME" exit 1 fi gftopk -v ./$GFNAME ./$PKNAME # Install the PK file carefully, since others may be doing the same # as us simultaneously. mv $PKNAME $DESTDIR/pktmp.$$ cd $DESTDIR mv pktmp.$$ $PKNAME exit 0 ----------------------------------------------------------------------------- ciao, Klaus -- \ klaus@snarc.greenie.muc.de--kweidner@physik.tu-muenchen.de--2:246/55.4 \ .signature error -- quote dumped mgetty-1.1.36/contrib/faxdvi.config0100644000031200000620000000231305647170651016101 0ustar gertgroup# faxdvi.config # # This is an example configuration file for FAXDVI. Feel free to do # anything you want to do with it. # # Ralph Schleicher # 241:10000/1513@PNoF # rs@purple.PNoF.sub.org # Phone number aliases can be specified with the `alias' command. The # syntax is # # alias [] # # The optional comment has to be put into parenthesis. # can be either the final phone number or another alias. Dialing lists # may be built by joining multiple phone numbers separated with commas. # # will be treated as a command if it starts with a vertical # bar (this feature does not work within the definition of a dialing list). # The token `@' will be replaced with only if is given. # alias ts (Thomas Schmitt) 07522-28363 alias cdg (Cees de Groot) |pnof -f -r name -r phone | fgrep '@' | cut -f2 -d, alias pnof ts,cdg # The topmost matching translation rule will be applied to the resulting # phone number after alias substitution. `dialtrans' is a single matching # search and replace command as you know if from perl(1). # dialtrans /^0/0/ dialtrans /^([1-9][0-9]*)$/$1/ dialtrans /^49-7352-// dialtrans /^49-/0/ dialtrans /^/00/ mgetty-1.1.36/contrib/faxdvi2.perl0100755000031200000620000001166505647170575015702 0ustar gertgroup#!/usr/local/bin/perl # # faxdvi2 -- pass a DVI file to the FAX subsystem. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # Ralph Schleicher # 241:10000/1513@PNoF # rs@purple.PNoF.sub.org $config_file = '/usr/local/lib/mgetty+sendfax/faxdvi.config'; $user_file = "$ENV{'HOME'}/.faxdvirc"; $dvips = 'dvips -t letter -P fax'; $gs = 'gs -sPAPERSIZE=letter -sDEVICE=dfaxhigh'; $version_string = 'FAXDVI2 Version 1.0 (Perl)'; sub usage { print <] [-V] [-?] [- ] -C, --config-file Use as the configuration file instead of the default `$config_file'. -V, --version Displays the version number. -?, --help Prints this small help. -, -- Pass verbatim to DVIPS. A real phone number or a FAX alias. You name it. STOP } {} # Get the command line options. # while (($_ = $ARGV[0]) =~ /^-/) { shift; if ($_ eq '-C' || $_ eq '--config-file') { $config_file = shift @ARGV; die "$0: Missing option argument for `$_'\n" if $config_file =~ /^-/; } elsif ($_ eq '-V' || $_ eq '--version') { $version = 1; $exit = 0; } elsif ($_ eq '-?' || $_ eq '--help') { $help = 1; $exit = 0; } elsif (/^--?$/) { push (@DVIPS, shift @ARGV) while @ARGV > 2; last; } else { die "$0: Unknown option `$_', try `--help'\n"; } } if (@ARGV == 2) { $phone_number = $ARGV[0]; $dvi_file = $ARGV[1]; } elsif ($exit eq '') { $help = 1; $exit = 1; } print "\nThis is $version_string\n\n" if $version; &usage if $help; exit $exit if $exit ne ''; # Read the configuration files. # sub configure { local ($config) = @_; local (*CONF); open (CONF, $config) || die "$0:$config: $!\n"; foreach () { next if /^\s*#/; next if /^\s*$/; chop; $comment{$1} = $3, $alias{$1} = $4, next if /^alias\s+(\S+)\s+(\((.*)\)\s+)?(.+)/; push (@dialtrans, $1), next if /^dialtrans\s+(.+)/; die "$0:$config:$.: Bad line\n"; } close (CONF); } &configure ($config_file) if $config_file ne ''; &configure ($user_file) if -f $user_file; # Do alias substitution and phone number translation. # foreach (grep ($alias{$_} =~ /^\|/, keys %alias)) { ($command = $alias{$_}) =~ s/^\|//; $command =~ s/@/$comment{$_}/ if $comment{$_} ne ''; $alias{$_} = `$command`; chop $alias{$_}; die "$0: Command alias for `$_' evaluates to null\n" if $alias{$_} =~ /^\s*$/; } for (@work = ($phone_number); @work > 0; ++$done{shift @work}) { unshift (@work, split (',', $alias{shift @work})) while $alias{$work[0]} ne ''; } foreach $num (keys %done) { foreach $rule (@dialtrans) { if ($num =~ (split (substr ($rule, 0, 1), $rule))[1]) { eval "\$num =~ s$rule"; die "$0: $@\n" if $@ ne ''; last; } } push (@number, $num); } # Convert the DVI file into G3 format. # $temp_dir = "/tmp/faxdvi2.$$"; mkdir ($temp_dir, 0755) || die "$0:$temp_dir: $!\n"; sub cleanup { local ($sig) = @_; local (*DIR); opendir (DIR, $temp_dir); unlink grep ($_ = "$temp_dir/$_", grep (! /^\.\.?$/, readdir (DIR))); closedir (DIR); rmdir ($temp_dir); exit ($sig eq '') ? 0 : 1; } $SIG{'HUP'} = 'cleanup'; $SIG{'INT'} = 'cleanup'; $SIG{'QUIT'} = 'cleanup'; $SIG{'PIPE'} = 'cleanup'; $SIG{'TERM'} = 'cleanup'; open (NULL, ">/dev/null") || die "$0:/dev/null: $!\n"; open (SAVOUT, ">&STDOUT") || die "$0:(stdout): $!\n"; open (STDOUT, ">&NULL") || die "$0:(stdout): $!\n"; open (SAVERR, ">&STDERR") || die "$0:(stderr): $!\n"; open (STDERR, ">&NULL") || die "$0:(stderr): $!\n"; sub bye { open (STDOUT, ">&SAVOUT"); open (STDERR, ">&SAVERR"); warn @_; &cleanup; } $output = join ('/', ($temp_dir, 'f')); system ("$dvips @DVIPS -o $output $dvi_file") && &bye ("$0: DVIPS failed on `$dvi_file'\n"); system ("$gs -dNOPAUSE -sOUTPUTFILE=$output%07d.g3 $output quit.ps") && &bye ("$0: Ghostscript failed for some reason\n"); opendir (DIR, $temp_dir) || &bye ("$0:$temp_dir: $!\n"); @pages = grep ($_ = "$temp_dir/$_", grep (/\.g3$/, readdir (DIR))); closedir (DIR); foreach (@number) { system ("faxspool $_ @pages\n") && &bye ("$0: Sending `$dvi_file' to `$_' failed\n"); } &cleanup; mgetty-1.1.36/contrib/faxin.c0100644000031200000620000000274606010344572014702 0ustar gertgroup#include #include #include #include #include #ifdef ISC #include #endif #include "mgetty.h" #include "policy.h" void exit_usage _P1( (retcode), int retcode ) { fprintf( stderr, "usage: faxin [-d ] [-x ]\n"); exit( retcode ); } char * Device; /* faxrec() needs it [for the filenames] */ time_t call_start; /* ditto */ char * CallerId = "unknown"; /* only available in mgetty / cnd.c */ char * CallName = "unknown"; /* ditto */ int main _P2( (argc, argv), int argc, char ** argv ) { char * fax_spool_in = FAX_SPOOL_IN; int c; char log_path[MAXPATH]; while ((c = getopt(argc, argv, "x:d:")) != EOF) { switch (c) { case 'x': log_set_llevel( atoi(optarg) ); break; case 'd': fax_spool_in = optarg; break; case '?': exit_usage(2); break; } } /* get the name of the tty stdin is connected to (jcp) */ Device = ttyname(STDIN_FILENO); if ( Device == NULL || *Device == '\0' ) Device = "unknown"; /* if present, remove the leading "/dev/" prefix */ if ( strncmp( Device, "/dev/", 5 ) == 0 ) Device += 5; /* remember the start time */ call_start = time( NULL ); /* construct the log path string */ sprintf( log_path, LOG_PATH, Device ); /* initialize logging subsystem */ log_init_paths( argv[0], log_path, &Device[strlen(Device)-2] ); /* receive the fax */ faxrec( fax_spool_in, 0, -1, -1, 644, NULL ); return 0; } mgetty-1.1.36/contrib/faxiobe.sh0100644000031200000620000002616205472172326015407 0ustar gertgroup#!/bin/sh # This is a shell archive (shar 3.32) # made 11/16/1993 15:42 UTC by gert@greenie # Source directory /u/gert/mgetty/contrib # # existing files WILL be overwritten # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 1194 -rw-r--r-- faxiobe/Makefile # 1449 -rw-r--r-- faxiobe/README # 6146 -rw-r--r-- faxiobe/faxiobe.c # 98 -rwxr-xr-x faxiobe/nofax # if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= faxiobe/Makefile ============== if test ! -d 'faxiobe'; then echo "x - creating directory faxiobe" mkdir 'faxiobe' fi echo "x - extracting faxiobe/Makefile (Text)" sed 's/^X//' << 'SHAR_EOF' > faxiobe/Makefile && X X# binary will be installed in DESTDIR with make install X XDESTDIR=/usr/local/sbin X X# set DIALPREF to a prefix to be added to the faxnumber X XDIALPREF=\"8,\" X X# define GHOSTSCRIPT and SENDFAX correct for you site X XGHOSTSCRIPT=\"/usr/local/bin/gs\" XSENDFAX=\"/usr/local/sbin/sendfax -v\" X X# define NOFAX for a dummy program instead of sendfax X# this is for debugging. A sample "nofax" is in the distribution. X XNOFAX=\"/usr/local/bin/nofax\" X X# BUGGYMODEM is defined for our Zyxel 1496EG+. X# ARRGH! XDEFINES=-DDIALPREF="$(DIALPREF)" -DGHOSTSCRIPT="$(GHOSTSCRIPT)"\ X -DSENDFAX="$(SENDFAX)" -DNOFAX="$(NOFAX)" -DBUGGYMODEM X X# Use this for working modems.... X#DEFINES=-DDIALPREF="$(DIALPREF)" -DGHOSTSCRIPT="$(GHOSTSCRIPT)"\ X# -DSENDFAX="$(SENDFAX)" -DNOFAX="$(NOFAX)" -DBUGGYMODEM X Xfaxiobe: faxiobe.o X $(CC) -o faxiobe faxiobe.o $(LDFLAGS) -lqb X Xfaxiobe.o: faxiobe.c X $(CC) -c $(CFLAGS) $(DEFINES) faxiobe.c X Xclean: X /bin/rm -f *.o *~ core faxiobe X Xinstall: faxiobe X [ -d $(DESTDIR) ] || mkdir $(DESTDIR) X /usr/ucb/install -m 2755 -o bin -g printq faxiobe $(DESTDIR) X X### ignore the following.... X Xtarfile: clean X tar czvf /nfs/sahara/ftp/pub/source/faxiobe-1.04.tar.gz -C .. faxiobe X SHAR_EOF $TOUCH -am 1115104093 faxiobe/Makefile && chmod 0644 faxiobe/Makefile || echo "restore of faxiobe/Makefile failed" set `wc -c faxiobe/Makefile`;Wc_c=$1 if test "$Wc_c" != "1194"; then echo original size 1194, current size $Wc_c fi # ============= faxiobe/README ============== echo "x - extracting faxiobe/README (Text)" sed 's/^X//' << 'SHAR_EOF' > faxiobe/README && X -*-text-*- X X Xfaxiobe: a fax backend for AIX. (C) Michael Staats 1993 X free software according the Gnu Public License, see X File copying. X XIf you want to understand what this program does, ask info about X"piobe" and "Understanding Backend Routines in libqb". X XLook at the Makefile and define GHOSTSCRIPT and SENDFAX correctly for Xyour site. Sendfax is the the sendfax program from the mgetty+sendfax Xpackacge by Gert Doering. X XDefine DIALPREF to a string wich will be put in front of the fax Xnumber. Leave it empty if you don't need any prefixes or want Xthe user to provide them with the faxnumber. X XDefine NOFAX to a program to be called instead of sendfax for Xdebugging purpose. There is a small shell script in the distribution. XIt exits with an exitvalue of the faxnumber, so you can debug the Xerrorhandling. X XInstall it as a printer, just with a different backend. XA sample local queue definition could be (in /etc/qconfig): X X========================= entry in /etc/qconfig =============== X X* Local queue fax X Xfax: X device = modem X discipline = fcfs X acctfile = /var/adm/acct/fax Xmodem: X backend = /usr/local/sbin/faxiobe X X=============================================================== X XThen you can send a fax with X Xlp -d fax -o -n [ -o -fg3 ] files ... X Xor X Xlp -d fax [ -o -fg3 ] -o to= files ... X XI'm sorry that I don't have the time to provide more documentation. X XMichael (michael@hal6000.thp.Uni-Duisburg.DE) SHAR_EOF $TOUCH -am 1115103993 faxiobe/README && chmod 0644 faxiobe/README || echo "restore of faxiobe/README failed" set `wc -c faxiobe/README`;Wc_c=$1 if test "$Wc_c" != "1449"; then echo original size 1449, current size $Wc_c fi # ============= faxiobe/faxiobe.c ============== echo "x - extracting faxiobe/faxiobe.c (Text)" sed 's/^X//' << 'SHAR_EOF' > faxiobe/faxiobe.c && X/* faxiobe: A fax backend for AIX. X (C) Michael Staats (michael@hal6000.thp.Uni-Duisburg.DE) X*/ Xstatic const char *What = X"@(#) faxiobe - A fax backend for AIX.\n" X"@(#) (C) Michael Staats (michael@hal6000.thp.Uni-Duisburg.DE)\n" X"@(#) free software according GNU Public License"; X X#include X#include X#include X#include X#include X X#define MAXRETRY "3" X#define SLEEPTIME 300 /* make multiple of 10 please */ X X#ifndef GHOSTSCRIPT X#define GHOSTSCRIPT "/usr/local/bin/gs" X#endif X X#ifndef SENDFAX X#define SENDFAX "/usr/local/sbin/sendfax" X#endif X X#ifndef NOFAX X#define NOFAX "/usr/local/bin/nofax" X#endif X X#ifndef DIALPREF X#define DIALPREF "8," X#endif X X#ifndef SPOOLDIR X#define SPOOLDIR "/var/spool/fax/outgoing" X#endif X X/* #define DEBUG */ X X#ifdef DEBUG X#define USE_NOFAX X#endif X X#define LATER ", I'll try again later...\n" X#define FAILED "Your fax failed, " X X/* define this empty if you modem is not buggy, ours is :-( */ X X#ifdef BUGGYMODEM X#define BUGGYMODEMT "\nOur modem has a little BUG, so please switch it OFF and\ X after 5 seconds ON\n again. If you do not do this, NO incoming calls (faxes)\ Xwill be recognized!!!!\n\n" X#else X#define BUGGYMODEMT X#endif X X#define MSGMOD (get_mail_only()?DOMAIL:DOWRITE) X X#define RETRY 99 X Xchar *msg[] = { X FAILED "unknown commandline option.\n", X FAILED "specify Faxnumber with -o -n\n", X FAILED "ghostscript Error. Maybe input is not PostScript?\n", X FAILED "unknown input format specified.\n", X FAILED "fatal sendfax error.\n" BUGGYMODEMT, X FAILED "fork() failed, no automatic retry.\n", X "Fax failed completely, always errors after " MAXRETRY " trials...\n" X}; X X Xchar *sfmsg[] = { X "", "", /* 0 1 */ X "Cannot open fax device" LATER, X "Error initializing modem" LATER BUGGYMODEMT, X "Line busy" LATER BUGGYMODEMT, /* 4 */ X "","","","","", /* 5 6 7 8 9 */ X "Error ocurred while dialing" LATER BUGGYMODEMT, X "", X "Error transmitting page(s)" LATER X}; X X#define PS 1 X#define G3 2 X Xtypedef struct { char *fstring; int fint; } fstruct; X Xstatic const fstruct formats[] = {{"ps", PS}, {"g3", G3}, {NULL, 0}}; X X#define TRUE 1 X#define FALSE 0 X X#ifdef DEBUG X#define D(a) { a; } X#else X#define D(a) {} X#endif X X Xchar *tmpf = NULL; X Xint rmfiles(); Xint do_rmfiles(); X Xmain(int argc, char *argv[]) X{ X#ifdef DEBUG X FILE *deb = fopen("/dev/console", "w"); X#endif X FILE *fptr; X char *cmd; X int l, i, ffarg, ev; X int rm = FALSE; X char *format = "ps"; X int iformat; X char *faxno = NULL; X int retry; X char *g3files; X fstruct *fs; X X log_init(); X X D(int ii; X fprintf(deb,"%s called, argc = %d args = ",argv[0],argc); X for (ii=1; iifstring != NULL; fs++) X if (strcmp(format, fs->fstring) == 0) iformat = fs->fint; X X switch (iformat) { X case PS: X signal(SIGTERM, rmfiles); X rm = TRUE; X X tmpf = malloc(50+strlen(faxno)); X X sprintf(tmpf,"%s/faxf-%s.%d",SPOOLDIR, faxno, getpid()); X X l=strlen(tmpf); X for (i = ffarg; i < argc; i++) l+=strlen(argv[i])+3; X X cmd = malloc(l+200); X log_status(INIT); X X sprintf(cmd,"%s -q -sDEVICE=dfaxhigh -dNOPAUSE -sOutputFile=%s.%%02d ", X GHOSTSCRIPT, tmpf); X for (i = ffarg; i < argc; i++) { X strcat(cmd, "\""); X strcat(cmd, argv[i]); X strcat(cmd, "\" "); X } X strcat(cmd, "< /dev/null"); X D(fprintf(deb,"faxiobe: cmdline=%s\n",cmd);); X system(cmd); X X sprintf(cmd,"%s.01", tmpf); X if ((fptr = fopen(cmd, "r")) == NULL) { X sysnot(get_to(), "", msg[2], MSGMOD); X exit(EXITOTHER+1); X } else fclose(fptr); X X g3files = malloc(strlen(tmpf)+3); X sprintf(g3files,"%s.??", tmpf); X free(cmd); X break; X case G3: X for (l = 0, i = ffarg; i < argc; i++) l+=strlen(argv[i])+3; X g3files = malloc(l+1); X for (i = ffarg; i < argc; i++) { X strcat(g3files, "\""); X strcat(g3files, argv[i]); X strcat(g3files, "\" "); X } X break; X default: X sysnot(get_to(), "", msg[3], MSGMOD); X exit(EXITOTHER+1); X break; X } X X cmd = malloc(strlen(g3files) + 80); X X#ifdef USE_NOFAX X sprintf(cmd,"%s \"%s\" %s", NOFAX, faxno, g3files); /**/ X#else X sprintf(cmd,"%s \"%s%s\" %s", SENDFAX, DIALPREF, faxno, g3files); /**/ X#endif X X retry = 0; X do { X log_percent(0); X log_status(SENDING); X D(fprintf(deb,"sendfax command=%s\n",cmd);); X ev = system(cmd) >> 8; X X D(fprintf(stderr,"exitval sendfax %d\n",ev);); X switch(ev) { X case 0: X ev = EXITOK; X break; X case 2: X case 3: X case 4: X case 10: X case 12: X if (retry==0) X sysnot(get_to(), "", sfmsg[ev], MSGMOD); X log_status(WAITING); X for (i=0; i < 10; i++) { X log_percent(10*i); /* hm, this doesn't work.... */ X D(fprintf(deb,"%d %% ",i);); X sleep(SLEEPTIME/10); X } X log_percent(0); X log_status(RUNNING); X retry++; X ev = RETRY; X break; X default: X sysnot(get_to(), "", msg[4], MSGMOD); X ev = EXITFATAL; X break; X } X } while (ev == RETRY && retry < atoi(MAXRETRY)); X X if (ev == RETRY) { X sysnot(get_to(), "", msg[6], MSGMOD); X ev = EXITOTHER+1; X } X X free(cmd); X if (rm) do_rmfiles(); X log_status(READY); X if (ev == EXITOK) log_charge(1); X exit(ev); X} X Xint rmfiles() { X do_rmfiles(); X exit(EXITSIGNAL); X} X Xint do_rmfiles() X{ X char *cmd; X if (tmpf == NULL) return(0); X cmd = malloc(strlen(tmpf) + 20); X sprintf(cmd, "/bin/rm -f %s.??", tmpf); X return(system(cmd)); X} X X SHAR_EOF $TOUCH -am 1115102793 faxiobe/faxiobe.c && chmod 0644 faxiobe/faxiobe.c || echo "restore of faxiobe/faxiobe.c failed" set `wc -c faxiobe/faxiobe.c`;Wc_c=$1 if test "$Wc_c" != "6146"; then echo original size 6146, current size $Wc_c fi # ============= faxiobe/nofax ============== echo "x - extracting faxiobe/nofax (Text)" sed 's/^X//' << 'SHAR_EOF' > faxiobe/nofax && X#!/bin/ksh X{ Xdate Xecho "Nofax called with $@" Xll $2 Xecho "exiting with $1" X}>/dev/console Xexit $1 SHAR_EOF $TOUCH -am 1113131693 faxiobe/nofax && chmod 0755 faxiobe/nofax || echo "restore of faxiobe/nofax failed" set `wc -c faxiobe/nofax`;Wc_c=$1 if test "$Wc_c" != "98"; then echo original size 98, current size $Wc_c fi exit 0 mgetty-1.1.36/contrib/sun.readme0100644000031200000620000000340005473410230015376 0ustar gertgroupGert, i am successfully using mgetty-0.15beta on my SUN 3/60 with SUNOS 4.1.0 Please note that i have the sun SYSV libraries installed on my system so the only change required was with respect to the way the SUN zs(4) serial driver handles hardware flow control. I have not tested fax reception yet with this version, but code looks unchanged from version 0.14 There is a problem with this version on my SUN which results in the phone line not being answered. This problem originates after the modem times out awaiting a non existant RING where the mgetty program hangs after the init chat script but before checking for new RINGS. I will look into this later, but i have enclosed a portion of the log file 11/20 12:50:53 got: 16800/ARQ/V42b[0d][0a] ** found ** 11/20 12:50:55 mgetty-0.15 device=cua1, pid=118, calling 'login uulatour'... -- 11/20 12:52:09 check for lockfiles 11/20 12:52:09 locking the line 11/20 12:52:11 lowering DTR to reset Modem 11/20 12:52:12 send: \d\d\d+++\d\d\d[0d]\dATQ0H0\r\n 11/20 12:52:15 waiting for ``OK'' ** found ** [ chat stuff deleted] 11/20 12:52:16 send: AT+FDCC=1,5,0,2,0,0,0\r\n 11/20 12:52:16 waiting for ``OK'' ** found ** 11/20 12:52:18 waiting... 11/20 12:57:05 waiting for ``RING'' 11/20 12:58:25 timeout in chat skript, waiting for `RING': Interrupted system call 11/20 12:58:26 chat failed (timeout or A_FAIL), exiting... 11/20 12:58:26 removing lock file -- 11/20 12:58:26 check for lockfiles 11/20 12:58:26 locking the line 11/20 12:58:26 lowering DTR to reset Modem 11/20 12:58:27 send: \d\d\d+++\d\d\d[0d]\dATQ0H0\r\n 11/20 12:58:30 waiting for ``OK'' ** found ** [ chat stuff deleted] 11/20 12:58:31 send: AT+FDCC=1,5,0,2,0,0,0\r\n 11/20 12:58:31 waiting for ``OK'' ** found ** [this is end of log file] mgetty-1.1.36/contrib/faxmail-smail0100644000031200000620000000621705424452133016076 0ustar gertgroupNewsgroups: de.comp.os.unix Path: greenie!colin.muc.de!lrz-muenchen.de!fauern!news.dfn.de!news.dkrz.de!ifmsun8.ifm.uni-hamburg.de!lutzifer!mwhh!solec!hb From: hb@solec.hanse.de (Heiko Bobzin) Subject: Re: Mail an user fax soll weggefaxt werden - elm-filter oder wie? References: <1993Jul22.183534.2705@panda.hanse.de> Organization: Software & Electronix, Altona, Hamburg Date: Fri, 23 Jul 1993 16:11:56 GMT Message-ID: <1993Jul23.161156.31520@solec.hanse.de> Lines: 85 michaelw@panda.hanse.de (Michael Will) writes: >Wie kann ich es einrichten, das jede mail die an den user fax geht >automatisch an das faxspool-script verfüttert wird? >Wer hat das Problem schon gelöst? Hier ! >All Information welcome :-) Ich hab das Ganze ins smail transports/routers eingebaut (leider hast Du vergessen, Deinen Mail-Transport-Agent anzugeben) in "/usr/local/lib/smail/routers" steht bei mir u.A.: FAXSPOOLER: transport=fax, driver=queryprogram; cmd="/usr/bin/test X${lc:host} = Xfax" und in "/usr/local/lib/smail/transports" noch dazu: fax: max_addrs=5, max_chars=200, +from, return_path, unix_from_hack, driver=pipe; cmd="/bin/sh -c /usr/bin/faxq $((${strip:addr})$)", parent_env Dann muss allerdings auch "uux" mit eingetragem sein, wenn noch nicht vorhanden (s. Manual-Page, je nach Deinen Einstellungen) Das Gute an "smail" ist, daß es so viele Environment- Variablen setzt (SENDER, BASENAME, ADDR ...) ! "faxq" konvertiert die Mails, die an @fax gehen, per "psf" und "ghostscript" nach G3. Das File wird dann in SPOOLDIR abgelegt. Ein Fax-Daemon holt die Dateien dort ab und verschickt sie per "mgetty/sendfax". Jetzt fehlt eigentlich nur noch "/usr/bin/faxq": # if [ "$SENDER" = "" ] ; then SENDER="$LOGNAME" ; fi if [ "$BASENAME" = "" ] ; then BASENAME="f.$SENDER.$$"; fi if [ "$ADDR" = "" ] ; then ADDR="$1"; File="$2" ; fi function do_error_check { if [ "X$?" != "X0" ] ; then ( echo -e "From: root (FAX SUBSYSTEM)\nTo: $SENDER\nSubject: Kann nicht senden $*\n\n" echo "$0: Dein Fax an $addr" echo "$0: Fehler-Ausgabe:" cat $tmp.err rm $tmp.* 2>/dev/null ) | /usr/lib/sendmail $SENDER exit 0 fi } # addr=`echo $ADDR | sed -e 's/@fax//'` tmp=/usr/spool/fax/tmp/$BASENAME.fax SPOOLDIR=/usr/spool/fax/outgoing case $SENDER in root) ;; # root darf faxen machen (he,he,) *) ( echo -e "From: MAILER_DAEMON (FAX SUBSYSTEM)\nTo: $SENDER\nSubject: Faxen an $addr\n\n" echo "$0: Dein Fax an $addr konnte nicht versandt werden." echo "$0: Bitte lass dich bei FaxMaster@sonstwo eintragen!" cat ) | /usr/lib/smail $SENDER exit 0 ;; esac # jobid=`date +'%H%M%S'` if [ "$File" = "" ] ; then ( awk ' { if (flag || match($0,"^From:") || match($0,"^Date:") || match($0,"^To:")) print ; if ($0 == "") flag++; } ' | tee $tmp.log | psf -g Fax | \ gs -sDEVICE=dfaxhigh -sOutputFile=$SPOOLDIR/$jobid.%02d -dQUIET ) 2>$tmp.err else echo | gs -sDEVICE=dfaxhigh -sOutputFile=$SPOOLDIR/$jobid.%02d -dQUIET $File 2>$tmp.err fi # echo "SENDER $SENDER ADDR $addr BASENAME $BASENAME" > $SPOOLDIR/$jobid.job do_error_check postscript-file -- "Die gefährlichsten Hacker sitzen bei der IBM und nicht im Knast." - IBM-Anzeige mgetty-1.1.36/contrib/frame40ps.fix0100600000031200000620000001413206015361715015725 0ustar gertgroupFrom owner-mgetty Fri Aug 18 19:28:01 1995 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Fri, 18 Aug 95 19:28 MEST Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Fri, 18 Aug 95 19:27 MEST Received: from lilly.ping.de ([193.100.14.2]) by colin.muc.de with SMTP id <41359-1>; Fri, 18 Aug 1995 19:27:11 +0200 Received: from cliwe.ping.de by lilly.ping.de with smtp (Smail3.1.28.1 #4) id m0sjUwL-000oo6C; Fri, 18 Aug 95 19:10 MET DST From: fdc@cliwe.ping.de (Frank D. Cringle) Date: Fri, 18 Aug 1995 19:19:25 +0200 Message-Id: <9508181719.AA11601@cliwe.ping.de> Received: by cliwe.ping.de (5.0/GEN-1.0.17-fdc) id AA11601; Fri, 18 Aug 95 19:19:25 +0200 To: mgetty@muc.de In-Reply-To: gert@greenie.muc.de's message of Wed, 16 Aug 1995 19:48:45 +0200 Subject: Re: output from gs3.33 References: <199508152346.QAA21503@hyla.chez.sgi.com> content-length: 0 Status: RO gert@greenie.muc.de (Gert Doering) writes: [ ... ] >This part seems to be responsible for it... looks weird. > > {{1 dict dup /PageSize [paperwidth paperheight]put setpagedevice }stopped > { (Can't select requested paper size for Frame print job!) FMFAILURE } if > {1 dict dup /ManualFeed manualfeed put setpagedevice } stopped pop } > >Does anyone have an idea how to "fix" those documents? OK, I admit it. I have a brain like a sieve! Attached below is a posting by Konstantin Laufer that I saved a few months ago and promptly forgot all about. After applying his patch to a private copy of the frame ps_prolog my scanlines are 1728 pixels long like they should be. Before I rediscovered this treasure I mucked about with gs3 and found that the width is initially set to 1728 (or 2048) in gdev_fax_open() but is subsequently recalculated by gx_device_set_page_size() based on the resolution. It is possible to reset the pdev->width to 1728 in gdev_fax_init_state() and get the desired output, but whether this is a satisfactory fix is beyond me. Did we ever find out what the cause of R"udiger Jacob's original problem was? ---------------------------------------------------------------- |From laufer@math.luc.edu Fri Apr 14 13:45:04 1995 |Path: cliwe.ping.de!ping.de!Germany.EU.net!howland.reston.ans.net!vixen.cso.uiuc.edu!uchinews!apollo!math.luc.edu!laufer |From: laufer@math.luc.edu (Konstantin Laufer) |Newsgroups: comp.text.frame |Subject: Re: US letter vs A4 Letter (solution) |Date: 25 Mar 1995 01:39:02 GMT |Organization: Loyola University Chicago |Lines: 90 |Distribution: world |Message-ID: <3kvs7m$n5f@apollo.it.luc.edu> |References: <3k20ll$mev@klaatu.btv.ibm.com> <3kusjt$bjc@louhi.to.icl.fi> |NNTP-Posting-Host: schauinsland.math.luc.edu In article <3kusjt$bjc@louhi.to.icl.fi>, ippa@to.icl.fi (Ritva Koivisto) writes: > In article <3k20ll$mev@klaatu.btv.ibm.com>, warfield@btv.ibm.com (David R. Warfield) says: > > >FrameMaker seems to explicitly put a lot of printer specific > >information right into the postscript file such as paper tray > >(that's burned me a few times), manual feed, and horizontal and > >vertcial size. I suspect that is why this user had to manually > >eject the page. Can anyone confirm this? Is there a way to > >generate one postscript file from FM that can be used for both > >US letter and A4 letter size? > > Was the error message something like "load letter"? If so, > sounds familiar... My guess is that the error message was the following, taken directly >from $FMHOME/fminit/ps_prolog, where it occurs in two places: Can't select requested paper size for Frame print job! Checking the page size is a new "feature" in FM 4. It is the reason why PostScript files generated by Frame for US Letter cannot be printed on an A4 printer any more and vice versa. Why is this a problem? Because many papers are exchanged *as PS files* between parties in different parts of the world. Here is a fix: 1) Use the following patch (context diff) to remove the repressive size checking from $FMHOME/fminit/ps_prolog. The patched file can go into your personal fminit directory as ~/fminit/ps_prolog. The files generated with the new prolog can be used for either page size. *** /usr/local/software/Xframe4.0/fminit/ps_prolog Tue Feb 1 17:00:56 1994 --- /home/laufer/fminit/ps_prolog Fri Mar 24 13:42:25 1995 *************** *** 653,668 **** /FMoptop count def setpapername manualfeed {true} {papersize} ifelse ! {manualpapersize} {false} ifelse ! {desperatepapersize} {false} ifelse ! { (Can't select requested paper size for Frame print job!) FMFAILURE } if count -1 FMoptop {pop pop} for countdictstack -1 FMdicttop {pop end} for } ! {{1 dict dup /PageSize [paperwidth paperheight]put setpagedevice}stopped ! { (Can't select requested paper size for Frame print job!) FMFAILURE } if ! {1 dict dup /ManualFeed manualfeed put setpagedevice } stopped pop } ! ifelse FMPColor { currentcolorscreen --- 653,663 ---- /FMoptop count def setpapername manualfeed {true} {papersize} ifelse ! {manualpapersize} if count -1 FMoptop {pop pop} for countdictstack -1 FMdicttop {pop end} for } ! if FMPColor { currentcolorscreen 2) A tiny sed script to change the page sizes in existing PS files >from A4 to US Letter. Alternatively, you may directly apply the patch above to the PS files. #! /bin/sh tmpfile=${TMPDIR-/tmp}/fmfixa4.$$ for file in $*; do sed -e "s/595 842/612 792/" < $file > $tmpfile mv $file $file.backup mv $tmpfile $file done To convert from US Letter to A4, change the sed line to this: sed -e "s/612 792/595 842/" < $file > $tmpfile Disclaimer: This stuff is provided as is without any kind of warranty. I use it with Frame 4 on SunOS 4.1.3. I hope it is helpful. Please post improvements to this group. -- Konstantin Laufer@math.luc.edu KL -- Frank Cringle | fdc@cliwe.ping.de voice + fax | +49 2304 467101 mgetty-1.1.36/contrib/g3tolj.c0100644000031200001470000005060407737257442014441 0ustar gertfax/* g3topbm.c - read a Group 3 FAX file and produce a portable bitmap * * * Copyright (C) 1989 by Paul Haeberli . * * * gcc -g -o g3tolj -O2 g3tolj.c * * Permission to use, copy, modify, and distribute this software and its * * documentation for any purpose and without fee is hereby granted, provided * * that the above copyright notice appear in all copies and that both that * * copyright notice and this permission notice appear in supporting * * documentation. This software is provided "as is" without express or * * implied warranty. * * * * pbmtolj.c - read a portable bitmap and produce a LaserJet bitmap file * * * based on pbmtops.c * * * Michael Haberler HP Vienna mah@hpuviea.uucp * mcvax!tuvie!mah * * misfeatures: o positioning * * * Bug fix Dec 12, 1988 : * * lines in putbit() reshuffled now runs OK on HP-UX 6.0 with X10R4 and HP * Laserjet II * * Bo Thide', Swedish Institute of Space Physics, Uppsala * * * * Copyright (C) 1988 by Jef Poskanzer and Michael Haberler. * * Copyright (C) 1993 by Chel van Gennip. * * Update aug 31,1993, Chel van Gennip, combined g3topbm and pbmtolj, removed * 8MB array, added simple scaling to improve speed, * * From: "John Watson -- Self Empl. Sys.Integrator" * * Date: Tue, 11 Jan 94 11:11:03 EST * * Thankyou for sending me this conversion program. * * I found that it generated huge files that took a long time to send to the * laser printer (serial port), so I added a -compress [012] option to * compress the data. Not very "cute" but it works. Some printers are not * capable like the Panasonic KX-P4450i, where I must still use -co 0, most * others can do -co 2, which is much better. * * Update 22 may 1994 Chel van Gennip Better handling of EOF of input files * Support for long faxes * * $Log: g3tolj.c,v $ * Revision 1.2 2003/10/03 11:36:02 gert * fix some return types and prototypes (Debian/ABA) * * Revision 1.1 2003/10/03 11:34:41 gert * G3 -> HP PCL bitmap, initial checkin * * */ /* #include "pbm.h" */ #include #include #include #include typedef unsigned char bit; #define PBM_WHITE 0 #define PBM_BLACK 1 #define pm_error(a,b,c,d,e,f) {fprintf(stderr,a,b,c,d,e,f);fprintf(stderr,"\n");} #define pm_message(a,b,c,d,e,f) {fprintf(stderr,a,b,c,d,e,f);fprintf(stderr,"\n");} #define pm_usage(a) { fprintf(stderr,"usage: %s\n",a) ; exit(7) ;} #define pbm_allocrow(a) (bit*)malloc(a) /* g3.h - header file for group 3 FAX compression filters from pm package */ #ifndef _G3_H_ #define _G3_H_ typedef struct tableentry { int tabid; int code; int length; int count; } tableentry; #define TWTABLE 23 #define MWTABLE 24 #define TBTABLE 25 #define MBTABLE 26 #define EXTABLE 27 #define VRTABLE 28 static struct tableentry twtable[]= { {TWTABLE, 0x35, 8, 0}, {TWTABLE, 0x7, 6, 1}, {TWTABLE, 0x7, 4, 2}, {TWTABLE, 0x8, 4, 3}, {TWTABLE, 0xb, 4, 4}, {TWTABLE, 0xc, 4, 5}, {TWTABLE, 0xe, 4, 6}, {TWTABLE, 0xf, 4, 7}, {TWTABLE, 0x13, 5, 8}, {TWTABLE, 0x14, 5, 9}, {TWTABLE, 0x7, 5, 10}, {TWTABLE, 0x8, 5, 11}, {TWTABLE, 0x8, 6, 12}, {TWTABLE, 0x3, 6, 13}, {TWTABLE, 0x34, 6, 14}, {TWTABLE, 0x35, 6, 15}, {TWTABLE, 0x2a, 6, 16}, {TWTABLE, 0x2b, 6, 17}, {TWTABLE, 0x27, 7, 18}, {TWTABLE, 0xc, 7, 19}, {TWTABLE, 0x8, 7, 20}, {TWTABLE, 0x17, 7, 21}, {TWTABLE, 0x3, 7, 22}, {TWTABLE, 0x4, 7, 23}, {TWTABLE, 0x28, 7, 24}, {TWTABLE, 0x2b, 7, 25}, {TWTABLE, 0x13, 7, 26}, {TWTABLE, 0x24, 7, 27}, {TWTABLE, 0x18, 7, 28}, {TWTABLE, 0x2, 8, 29}, {TWTABLE, 0x3, 8, 30}, {TWTABLE, 0x1a, 8, 31}, {TWTABLE, 0x1b, 8, 32}, {TWTABLE, 0x12, 8, 33}, {TWTABLE, 0x13, 8, 34}, {TWTABLE, 0x14, 8, 35}, {TWTABLE, 0x15, 8, 36}, {TWTABLE, 0x16, 8, 37}, {TWTABLE, 0x17, 8, 38}, {TWTABLE, 0x28, 8, 39}, {TWTABLE, 0x29, 8, 40}, {TWTABLE, 0x2a, 8, 41}, {TWTABLE, 0x2b, 8, 42}, {TWTABLE, 0x2c, 8, 43}, {TWTABLE, 0x2d, 8, 44}, {TWTABLE, 0x4, 8, 45}, {TWTABLE, 0x5, 8, 46}, {TWTABLE, 0xa, 8, 47}, {TWTABLE, 0xb, 8, 48}, {TWTABLE, 0x52, 8, 49}, {TWTABLE, 0x53, 8, 50}, {TWTABLE, 0x54, 8, 51}, {TWTABLE, 0x55, 8, 52}, {TWTABLE, 0x24, 8, 53}, {TWTABLE, 0x25, 8, 54}, {TWTABLE, 0x58, 8, 55}, {TWTABLE, 0x59, 8, 56}, {TWTABLE, 0x5a, 8, 57}, {TWTABLE, 0x5b, 8, 58}, {TWTABLE, 0x4a, 8, 59}, {TWTABLE, 0x4b, 8, 60}, {TWTABLE, 0x32, 8, 61}, {TWTABLE, 0x33, 8, 62}, {TWTABLE, 0x34, 8, 63}, }; static struct tableentry mwtable[]= { {MWTABLE, 0x1b, 5, 64}, {MWTABLE, 0x12, 5, 128}, {MWTABLE, 0x17, 6, 192}, {MWTABLE, 0x37, 7, 256}, {MWTABLE, 0x36, 8, 320}, {MWTABLE, 0x37, 8, 384}, {MWTABLE, 0x64, 8, 448}, {MWTABLE, 0x65, 8, 512}, {MWTABLE, 0x68, 8, 576}, {MWTABLE, 0x67, 8, 640}, {MWTABLE, 0xcc, 9, 704}, {MWTABLE, 0xcd, 9, 768}, {MWTABLE, 0xd2, 9, 832}, {MWTABLE, 0xd3, 9, 896}, {MWTABLE, 0xd4, 9, 960}, {MWTABLE, 0xd5, 9, 1024}, {MWTABLE, 0xd6, 9, 1088}, {MWTABLE, 0xd7, 9, 1152}, {MWTABLE, 0xd8, 9, 1216}, {MWTABLE, 0xd9, 9, 1280}, {MWTABLE, 0xda, 9, 1344}, {MWTABLE, 0xdb, 9, 1408}, {MWTABLE, 0x98, 9, 1472}, {MWTABLE, 0x99, 9, 1536}, {MWTABLE, 0x9a, 9, 1600}, {MWTABLE, 0x18, 6, 1664}, {MWTABLE, 0x9b, 9, 1728}, }; static struct tableentry tbtable[]= { {TBTABLE, 0x37, 10, 0}, {TBTABLE, 0x2, 3, 1}, {TBTABLE, 0x3, 2, 2}, {TBTABLE, 0x2, 2, 3}, {TBTABLE, 0x3, 3, 4}, {TBTABLE, 0x3, 4, 5}, {TBTABLE, 0x2, 4, 6}, {TBTABLE, 0x3, 5, 7}, {TBTABLE, 0x5, 6, 8}, {TBTABLE, 0x4, 6, 9}, {TBTABLE, 0x4, 7, 10}, {TBTABLE, 0x5, 7, 11}, {TBTABLE, 0x7, 7, 12}, {TBTABLE, 0x4, 8, 13}, {TBTABLE, 0x7, 8, 14}, {TBTABLE, 0x18, 9, 15}, {TBTABLE, 0x17, 10, 16}, {TBTABLE, 0x18, 10, 17}, {TBTABLE, 0x8, 10, 18}, {TBTABLE, 0x67, 11, 19}, {TBTABLE, 0x68, 11, 20}, {TBTABLE, 0x6c, 11, 21}, {TBTABLE, 0x37, 11, 22}, {TBTABLE, 0x28, 11, 23}, {TBTABLE, 0x17, 11, 24}, {TBTABLE, 0x18, 11, 25}, {TBTABLE, 0xca, 12, 26}, {TBTABLE, 0xcb, 12, 27}, {TBTABLE, 0xcc, 12, 28}, {TBTABLE, 0xcd, 12, 29}, {TBTABLE, 0x68, 12, 30}, {TBTABLE, 0x69, 12, 31}, {TBTABLE, 0x6a, 12, 32}, {TBTABLE, 0x6b, 12, 33}, {TBTABLE, 0xd2, 12, 34}, {TBTABLE, 0xd3, 12, 35}, {TBTABLE, 0xd4, 12, 36}, {TBTABLE, 0xd5, 12, 37}, {TBTABLE, 0xd6, 12, 38}, {TBTABLE, 0xd7, 12, 39}, {TBTABLE, 0x6c, 12, 40}, {TBTABLE, 0x6d, 12, 41}, {TBTABLE, 0xda, 12, 42}, {TBTABLE, 0xdb, 12, 43}, {TBTABLE, 0x54, 12, 44}, {TBTABLE, 0x55, 12, 45}, {TBTABLE, 0x56, 12, 46}, {TBTABLE, 0x57, 12, 47}, {TBTABLE, 0x64, 12, 48}, {TBTABLE, 0x65, 12, 49}, {TBTABLE, 0x52, 12, 50}, {TBTABLE, 0x53, 12, 51}, {TBTABLE, 0x24, 12, 52}, {TBTABLE, 0x37, 12, 53}, {TBTABLE, 0x38, 12, 54}, {TBTABLE, 0x27, 12, 55}, {TBTABLE, 0x28, 12, 56}, {TBTABLE, 0x58, 12, 57}, {TBTABLE, 0x59, 12, 58}, {TBTABLE, 0x2b, 12, 59}, {TBTABLE, 0x2c, 12, 60}, {TBTABLE, 0x5a, 12, 61}, {TBTABLE, 0x66, 12, 62}, {TBTABLE, 0x67, 12, 63}, }; static struct tableentry mbtable[]= { {MBTABLE, 0xf, 10, 64}, {MBTABLE, 0xc8, 12, 128}, {MBTABLE, 0xc9, 12, 192}, {MBTABLE, 0x5b, 12, 256}, {MBTABLE, 0x33, 12, 320}, {MBTABLE, 0x34, 12, 384}, {MBTABLE, 0x35, 12, 448}, {MBTABLE, 0x6c, 13, 512}, {MBTABLE, 0x6d, 13, 576}, {MBTABLE, 0x4a, 13, 640}, {MBTABLE, 0x4b, 13, 704}, {MBTABLE, 0x4c, 13, 768}, {MBTABLE, 0x4d, 13, 832}, {MBTABLE, 0x72, 13, 896}, {MBTABLE, 0x73, 13, 960}, {MBTABLE, 0x74, 13, 1024}, {MBTABLE, 0x75, 13, 1088}, {MBTABLE, 0x76, 13, 1152}, {MBTABLE, 0x77, 13, 1216}, {MBTABLE, 0x52, 13, 1280}, {MBTABLE, 0x53, 13, 1344}, {MBTABLE, 0x54, 13, 1408}, {MBTABLE, 0x55, 13, 1472}, {MBTABLE, 0x5a, 13, 1536}, {MBTABLE, 0x5b, 13, 1600}, {MBTABLE, 0x64, 13, 1664}, {MBTABLE, 0x65, 13, 1728}, }; static struct tableentry extable[]= { {EXTABLE, 0x8, 11, 1792}, {EXTABLE, 0xc, 11, 1856}, {EXTABLE, 0xd, 11, 1920}, {EXTABLE, 0x12, 12, 1984}, {EXTABLE, 0x13, 12, 2048}, {EXTABLE, 0x14, 12, 2112}, {EXTABLE, 0x15, 12, 2176}, {EXTABLE, 0x16, 12, 2240}, {EXTABLE, 0x17, 12, 2304}, {EXTABLE, 0x1c, 12, 2368}, {EXTABLE, 0x1d, 12, 2432}, {EXTABLE, 0x1e, 12, 2496}, {EXTABLE, 0x1f, 12, 2560}, }; #endif /* _G3_H_ */ void skiptoeol (void); FILE * pm_openr (name) char *name; { FILE *f; if (strcmp (name, "-") == 0) f = stdin; else { f = fopen (name, "r"); if (f == NULL) { perror (name); exit (1); } } return f; } int pm_keymatch (str, keyword, minchars) char *str; char *keyword; int minchars; { register int len; len = strlen (str); if (len < minchars) return 0; while (--len >= 0) { register char c1, c2; c1 = *str++; c2 = *keyword++; if (c2 == '\0') return 0; if (isupper (c1)) c1 = tolower (c1); if (isupper (c2)) c1 = tolower (c2); if (c1 != c2) return 0; } return 1; } static int dpi = 300; static int doubleheight = 1; static hscale = 100; static vscale = 100; static int cmode = 0; /* compression mode, 1=rll, 2=tiff */ static void putinit (), putbit (), putrest (), putitem (); static int item, bitsperitem; static char *line; static int bytecnt; #define TABSIZE(tab) (sizeof(tab)/sizeof(struct tableentry)) #define MAXCOLS 1728 #define MAXROWS 43000 /* up to 20 pages long */ #define MAXHIST 500 int eof = 0; int eols; int rawzeros; int shdata; int kludge; int reversebits; int stretch; #define WHASHA 3510 #define WHASHB 1178 #define BHASHA 293 #define BHASHB 2695 #define HASHSIZE 1021 tableentry *whash[HASHSIZE]; tableentry *bhash[HASHSIZE]; static FILE *ifp; static int shbit = 0; static int eof_err = 0; static inline int rawgetbit () { int b; if (eof_err) { rawzeros = 20; return (1); } if ((shbit & 0xff) == 0) { shdata = getc (ifp); if (shdata == EOF) { eof_err++; pm_error ("EOF / read error at line %d", eols, 0, 0, 0, 0); } shbit = reversebits ? 0x01 : 0x80; } if (shdata & shbit) { rawzeros = 0; b = 1; } else { rawzeros++; b = 0; } if (reversebits) shbit <<= 1; else shbit >>= 1; return b; } addtohash (hash, te, n, a, b) tableentry *hash[]; tableentry *te; int n, a, b; { unsigned int pos; while (n--) { pos = ((te->length + a) * (te->code + b)) % HASHSIZE; if (hash[pos] != 0) pm_error ( "internal error: addtohash fatal hash collision", 0, 0, 0, 0, 0); hash[pos] = te; te++; } } static inline tableentry * hashfind (hash, length, code, a, b) tableentry *hash[]; int length, code; int a, b; { unsigned int pos; tableentry *te; pos = ((length + a) * (code + b)) % HASHSIZE; if (pos < 0 || pos >= HASHSIZE) pm_error ( "internal error: bad hash position, length %d code %d pos %d", length, code, pos, 0, 0); te = hash[pos]; return ((te && te->length == length && te->code == code) ? te : 0); } getfaxrow (row, bitrow) int row; bit *bitrow; { int col; bit *bP; int curlen, curcode, nextbit; int count, color; tableentry *te; for (col = 0, bP = bitrow; col < MAXCOLS; ++col, ++bP) *bP = PBM_WHITE; col = 0; rawzeros = 0; curlen = 0; curcode = 0; color = 1; count = 0; while (!eof) { if (col >= MAXCOLS) { skiptoeol (); return (col); } do { if (rawzeros >= 11) { nextbit = rawgetbit (); if (nextbit) { if (col == 0) /* XXX should be 6 */ eof = (++eols == 3); else eols = 0; #ifdef notdef if (col && col < 1728) pm_message ( "warning, row %d short (len %d)", row, col, 0, 0, 0); #endif /* notdef */ return (col); } } else nextbit = rawgetbit (); curcode = (curcode << 1) + nextbit; curlen++; } while (curcode <= 0); if (curlen > 13) { pm_message ( "bad code word at row %d, col %d (len %d code 0x%x), skipping to EOL", row, col, curlen, curcode, 0); skiptoeol (); return (col); } if (color) { if (curlen < 4) continue; te = hashfind (whash, curlen, curcode, WHASHA, WHASHB); } else { if (curlen < 2) continue; te = hashfind (bhash, curlen, curcode, BHASHA, BHASHB); } if (!te) continue; switch (te->tabid) { case TWTABLE: case TBTABLE: count += te->count; if (col + count > MAXCOLS) count = MAXCOLS - col; if (count > 0) { if (color) { col += count; count = 0; } else { for (; count > 0; --count, ++col) bitrow[col] = PBM_BLACK; } } curcode = 0; curlen = 0; color = !color; break; case MWTABLE: case MBTABLE: count += te->count; curcode = 0; curlen = 0; break; case EXTABLE: count += te->count; curcode = 0; curlen = 0; break; default: pm_error ("internal bad poop", 0, 0, 0, 0, 0); } } return (0); } void skiptoeol () { while (rawzeros < 11) (void) rawgetbit (); for (;;) { if (rawgetbit ()) break; } } static void putinit () { /* Printer reset. */ printf ("\033E"); printf ("\033*rB"); printf ("\033*t%dR", dpi); /* Set raster graphics resolution */ /* move to top left of page & set current position */ printf ("\033&l26A"); /* A4 size */ printf ("\033&l0L"); /* Don't skip perforation */ printf ("\033&l0E"); /* Top margin 0 */ printf ("\033*p0x0Y"); printf ("\033*r1A"); /* Start raster graphics, relative adressing */ /* printf("\033*b2M"); */ printf ("\033*b%dM", cmode);/* set compression mode, 1=rll */ } int o_item = -1; int oo_item = -1; char *cb; /* command byte */ static void putitem () { if (cmode == 1) { if (item == o_item && ((unsigned char) (line[bytecnt - 2]) < 255)) { ++line[bytecnt - 2]; bitsperitem = item = 0; return; } line[bytecnt++] = 0; /* repeat count of one */ line[bytecnt++] = o_item = item; bitsperitem = 0; item = 0; return; } if (cmode == 2) { /* if running repeat, continue if same char again */ if (item == o_item && cb != NULL && *cb < 1 && *cb > -127) { --*cb; bitsperitem = item = 0; return; } /* if running literal see last two same as next and switch to repeat */ if (cb != NULL && *cb > 0 && o_item == oo_item && o_item == item) { *cb -= 2; cb = &line[bytecnt - 2]; *cb = -2; bitsperitem = item = 0; return; } /* if running literal add next byte to string */ if (cb != NULL && *cb >= 0 && *cb < 127) { ++*cb; oo_item = o_item; line[bytecnt++] = o_item = item; bitsperitem = item = 0; return; } /* start new literal */ cb = &line[bytecnt]; line[bytecnt++] = 0; /* repeat count of one */ line[bytecnt++] = o_item = item; oo_item = -1; bitsperitem = 0; item = 0; return; } line[bytecnt++] = item; bitsperitem = 0; item = 0; } static void putbit (b) bit b; { if (b == PBM_BLACK) item += 1 << (7 - bitsperitem); bitsperitem++; if (bitsperitem == 8) { putitem (); } } static void putrest () { /* end raster graphics */ printf ("\033*rB"); /* Printer reset. */ printf ("\033E"); } static struct { int bytecnt; char *line; } hist[MAXHIST]; static int maxhist = MAXHIST; static int histidx = 0; static int lncnt = 0; static int maxline = 11 * 300; newpage (FILE * fd) { int i; putrest (); putinit (); lncnt = 0; for (i = 0; i < maxhist; i++) { fprintf (fd, "\033*b%dW", hist[histidx].bytecnt); fwrite (hist[histidx].line, sizeof (char), hist[histidx].bytecnt, fd); histidx++; if (histidx >= maxhist) histidx = 0; lncnt++; } } static void lj_writerow (FILE * fd, bit * writerow, int wcols) { int i; oo_item = o_item = -1; cb = NULL; item = 0; bytecnt = 0; bitsperitem = 0; for (i = 0; i < wcols; i++) putbit (writerow[i]); if (bitsperitem > 0) putitem (); fprintf (fd, "\033*b%dW", bytecnt); fwrite (line, sizeof (char), bytecnt, fd); hist[histidx].bytecnt = bytecnt; histidx++; if (histidx >= maxhist) histidx = 0; line = hist[histidx].line; lncnt++; if (lncnt > maxline) newpage (fd); }; int main (argc, argv) int argc; char *argv[]; { int argn, rows, wrows, cols, wcols, row, wrow, col, wcol, i; int vval, hval; bit *readrow, *writerow, *bP, *wbP, bitval; float aspect, scale, pagelength, duplength; int format; register int nzcol; char *usage = " g3tolj [-kludge] [-reversebits] [-scale N] [-aspect N]" "\n\t[-resolution 75|100|150|300] [-compress 0|1|2] [-pagelength N]" "\n\t[-duplength N] [g3file]" "\n\tDefaults -sc 1.4 -as 1.0 -re 300 -co 0 -pa 10.95 -du 0.7"; argn = 1; kludge = 0; reversebits = 0; aspect = 1.0; scale = 1.4; pagelength = 10.95; duplength = 0.7; /* Check for flags. */ while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') { if (pm_keymatch (argv[argn], "-kludge", 2)) kludge = 1; else if (pm_keymatch (argv[argn], "-reversebits", 2)) reversebits = 1; else if (pm_keymatch (argv[argn], "-resolution", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%d", &dpi) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-aspect", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &aspect) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-scale", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &scale) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-compress", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%d", &cmode) != 1) pm_usage (usage); if ((cmode < 0) || (cmode > 2)) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-duplength", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &duplength) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-pagelength", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &pagelength) != 1) pm_usage (usage); } else pm_usage (usage); argn++; } if (argn < argc) { ifp = pm_openr (argv[argn]); argn++; } else ifp = stdin; if (argn != argc) pm_usage (usage); vscale = aspect * scale * 100; hscale = scale * 100; eols = 0; maxhist = duplength * dpi; if (maxhist > MAXHIST) maxhist = MAXHIST; for (i = 0; i < maxhist; i++) { hist[i].line = (char *) malloc (2 * (dpi * 10 * hscale) / 100); } histidx = 0; lncnt = 0; maxline = pagelength * dpi; line = hist[histidx].line; putinit (); if (kludge) { /* Skip extra lines to get in sync. */ skiptoeol (); skiptoeol (); skiptoeol (); } skiptoeol (); for (i = 0; i < HASHSIZE; ++i) whash[i] = bhash[i] = (tableentry *) 0; addtohash (whash, twtable, TABSIZE (twtable), WHASHA, WHASHB); addtohash (whash, mwtable, TABSIZE (mwtable), WHASHA, WHASHB); addtohash (whash, extable, TABSIZE (extable), WHASHA, WHASHB); addtohash (bhash, tbtable, TABSIZE (tbtable), BHASHA, BHASHB); addtohash (bhash, mbtable, TABSIZE (mbtable), BHASHA, BHASHB); addtohash (bhash, extable, TABSIZE (extable), BHASHA, BHASHB); wcols = (MAXCOLS * hscale) / 100; wrows = 99999; writerow = pbm_allocrow (wcols); readrow = pbm_allocrow (MAXCOLS); vval = wrow = row = 0; while (row < MAXROWS) { for (col = 0, bP = writerow; col < (MAXCOLS * hscale) / 100; ++col, ++bP) *bP = PBM_WHITE; cols = 1; while (vval < 100) { if (row < MAXROWS) { hval = wcol = 0; bP = readrow; wbP = writerow; col = getfaxrow (row, readrow); col--; while ((col > 0) && (readrow[col] == PBM_WHITE)) col--; col++; if (col > cols) cols = col; wcols = (cols * hscale) / 100; col = 0; while (col < cols) { bitval = *wbP; while (hval < 100) { if (col++ < cols) if (*bP++ == PBM_BLACK) bitval = PBM_BLACK; hval += hscale; } while (hval >= 100) { if (wcol++ < wcols) *wbP++ = bitval; hval -= 100; } } /* while(col */ } /* if(row */ vval += vscale; row++; } /* while vval */ while (vval >= 100) { if (wrow < wrows) { lj_writerow (stdout, writerow, wcols); wrow++; } vval -= 100; } if (eof) break; } putrest (); return 0; } mgetty-1.1.36/contrib/g3tolj.10100644000031200000620000000437105567651013014720 0ustar gertgroup.TH g3tolj 1 "22 may 94" "Chel" "mgetty+sendfax manual" .IX g3tolj .SH NAME g3tolj \- converts a Group 3 fax file into a printable HP-PCL file .SH SYNOPSIS .B g3tolj .RB [ -kludge ] .RB [ -reversebits ] .RB [ -scale\ N ] .RB [ -aspect\ N ] .RB [ -resolution\ 75|100|150|300 ] .RB [ -compress\ 0|1|2 ] .RB [ -pagelength\ N ] .RB [ -duplength\ N ] .RI [ g3file ] .SH DESCRIPTION Reads a Group 3 fax file (raw or digifax) as input. If no filename is given, stdin is used. .IX "Group 3 fax" .IX fax Produces a printable HP-PCL file as output. .SH OPTIONS .TP .B -kludge Tells .I g3tolj to skip the first lines for synchronisation. .TP .B -reversebits Tells .I g3tolj to interpret bits least-significant first, instead of the default most-significant first. Apparently some fax modems do it one way and others do it the other way. If you get a whole bunch of "invalid code" messages, try using this flag. .TP .B -scale N Scale the output to match the printer resolution and paper size, the default of 1.40 will do in most cases. .TP .B -aspect N Scale the output to match the printer resolution and paper size, the default of 1.0 will do for high resolution faxes, 2.0 will do for low resolution faxes. .TP .B -resolution 75|100|150|300 Selects print resolution. The default is 300. .TP .B -compress 0|1|2 Selects compression method for the print output. 0 = none, 1 = rll, 2 = tiff. The default is 0. .TP .B -pagelength N Defines the pagelength in inches, the default is 10.95. After this length a pagebreak is generated and the last part of the previous page is duplicated on the next page .TP .B -duplength N Defines the length in inches that will be duplicated after a pagebreak, The default is 0.7. .SH REFERENCES The standard for Group 3 fax is defined in CCITT Recommendation T.4. .SH BUGS Please report bugs to chel@vangennip.nl .SH "SEE ALSO" pbmtog3(1), pbm(5), g3cat(1), sendfax(8), mgetty(1) .SH AUTHOR .I g3tolj is Copyright (C) 1994 by Chel van Gennip, . Sources of .I g3topbm and .I pbmtolj programs in Jef Poskanzers .I pbmplus package have been used, but al lot of code has been changed or added to simplify its use for printing faxes. Value added: low use of memory, fast scaling, printing of long faxes with page breaks, print file compression (by John Watson) mgetty-1.1.36/contrib/g3toxwd.c0100644000031200001470000005273607737257443014647 0ustar gertfax/* g3topbm.c - read a Group 3 FAX file and produce a portable bitmap * * * Copyright (C) 1989 by Paul Haeberli . * * * pnmtoxwd.c - read a portable anymap and produce a color X11 window dump * * Copyright (C) 1989, 1991 by Jef Poskanzer. * * gcc -g -o g3toxwd -O2 g3toxwd.c * * Permission to use, copy, modify, and distribute this software and its * * documentation for any purpose and without fee is hereby granted, provided * * that the above copyright notice appear in all copies and that both that * * copyright notice and this permission notice appear in supporting * * documentation. This software is provided "as is" without express or * * implied warranty. * * * Update aug 31,1993, Chel van Gennip, combined two programs, delated large * array and added simple scaling to improve speed. * * Update 22 may 1994, better EOF handling by transmission errors chel. Added * -skiprows for long faxes. * * $Log: g3toxwd.c,v $ * Revision 1.2 2003/10/03 11:36:03 gert * fix some return types and prototypes (Debian/ABA) * * Revision 1.1 2003/10/03 11:34:56 gert * G3 -> X11 xwd, initial checkin * * */ #include #include #include #include #include typedef unsigned char bit; #define PBM_WHITE 0 #define PBM_BLACK 1 #define pm_error(a,b,c,d,e,f) {fprintf(stderr,a,b,c,d,e,f);fprintf(stderr,"\n");} #define pm_message(a,b,c,d,e,f) {fprintf(stderr,a,b,c,d,e,f);fprintf(stderr,"\n");} #define pm_usage(a) { fprintf(stderr,"usage: %s\n",a); exit(7); } #define pbm_allocrow(a) (bit*)malloc(a) /* x11wd.h - the following defs are taken from various X.V11R2 header files */ #ifndef _X11WD_H_ #define _X11WD_H_ #define LSBFirst 0 #define MSBFirst 1 #define XYBitmap 0 #define XYPixmap 1 #define ZPixmap 2 #define StaticGray 0 #define GrayScale 1 #define StaticColor 2 #define PseudoColor 3 #define TrueColor 4 #define DirectColor 5 typedef unsigned long xwdval; #define X11WD_FILE_VERSION 7 typedef struct { xwdval header_size; /* Size of the entire file header (bytes). */ xwdval file_version; /* X11WD_FILE_VERSION */ xwdval pixmap_format; /* Pixmap format */ xwdval pixmap_depth; /* Pixmap depth */ xwdval pixmap_width; /* Pixmap width */ xwdval pixmap_height; /* Pixmap height */ xwdval xoffset; /* Bitmap x offset */ xwdval byte_order; /* MSBFirst, LSBFirst */ xwdval bitmap_unit; /* Bitmap unit */ xwdval bitmap_bit_order; /* MSBFirst, LSBFirst */ xwdval bitmap_pad; /* Bitmap scanline pad */ xwdval bits_per_pixel; /* Bits per pixel */ xwdval bytes_per_line; /* Bytes per scanline */ xwdval visual_class; /* Class of colormap */ xwdval red_mask; /* Z red mask */ xwdval green_mask; /* Z green mask */ xwdval blue_mask; /* Z blue mask */ xwdval bits_per_rgb; /* Log base 2 of distinct color values */ xwdval colormap_entries; /* Number of entries in colormap */ xwdval ncolors; /* Number of Color structures */ xwdval window_width; /* Window width */ xwdval window_height; /* Window height */ long window_x; /* Window upper left X coordinate */ long window_y; /* Window upper left Y coordinate */ xwdval window_bdrwidth; /* Window border width */ } X11WDFileHeader; typedef struct { unsigned long pixel; unsigned short red, green, blue; char flags; /* do_red, do_green, do_blue */ char pad; } X11XColor; #endif /* _X11WD_H_ */ /* g3.h - header file for group 3 FAX compression filters from pm package */ #ifndef _G3_H_ #define _G3_H_ typedef struct tableentry { int tabid; int code; int length; int count; } tableentry; #define TWTABLE 23 #define MWTABLE 24 #define TBTABLE 25 #define MBTABLE 26 #define EXTABLE 27 #define VRTABLE 28 static struct tableentry twtable[]= { {TWTABLE, 0x35, 8, 0}, {TWTABLE, 0x7, 6, 1}, {TWTABLE, 0x7, 4, 2}, {TWTABLE, 0x8, 4, 3}, {TWTABLE, 0xb, 4, 4}, {TWTABLE, 0xc, 4, 5}, {TWTABLE, 0xe, 4, 6}, {TWTABLE, 0xf, 4, 7}, {TWTABLE, 0x13, 5, 8}, {TWTABLE, 0x14, 5, 9}, {TWTABLE, 0x7, 5, 10}, {TWTABLE, 0x8, 5, 11}, {TWTABLE, 0x8, 6, 12}, {TWTABLE, 0x3, 6, 13}, {TWTABLE, 0x34, 6, 14}, {TWTABLE, 0x35, 6, 15}, {TWTABLE, 0x2a, 6, 16}, {TWTABLE, 0x2b, 6, 17}, {TWTABLE, 0x27, 7, 18}, {TWTABLE, 0xc, 7, 19}, {TWTABLE, 0x8, 7, 20}, {TWTABLE, 0x17, 7, 21}, {TWTABLE, 0x3, 7, 22}, {TWTABLE, 0x4, 7, 23}, {TWTABLE, 0x28, 7, 24}, {TWTABLE, 0x2b, 7, 25}, {TWTABLE, 0x13, 7, 26}, {TWTABLE, 0x24, 7, 27}, {TWTABLE, 0x18, 7, 28}, {TWTABLE, 0x2, 8, 29}, {TWTABLE, 0x3, 8, 30}, {TWTABLE, 0x1a, 8, 31}, {TWTABLE, 0x1b, 8, 32}, {TWTABLE, 0x12, 8, 33}, {TWTABLE, 0x13, 8, 34}, {TWTABLE, 0x14, 8, 35}, {TWTABLE, 0x15, 8, 36}, {TWTABLE, 0x16, 8, 37}, {TWTABLE, 0x17, 8, 38}, {TWTABLE, 0x28, 8, 39}, {TWTABLE, 0x29, 8, 40}, {TWTABLE, 0x2a, 8, 41}, {TWTABLE, 0x2b, 8, 42}, {TWTABLE, 0x2c, 8, 43}, {TWTABLE, 0x2d, 8, 44}, {TWTABLE, 0x4, 8, 45}, {TWTABLE, 0x5, 8, 46}, {TWTABLE, 0xa, 8, 47}, {TWTABLE, 0xb, 8, 48}, {TWTABLE, 0x52, 8, 49}, {TWTABLE, 0x53, 8, 50}, {TWTABLE, 0x54, 8, 51}, {TWTABLE, 0x55, 8, 52}, {TWTABLE, 0x24, 8, 53}, {TWTABLE, 0x25, 8, 54}, {TWTABLE, 0x58, 8, 55}, {TWTABLE, 0x59, 8, 56}, {TWTABLE, 0x5a, 8, 57}, {TWTABLE, 0x5b, 8, 58}, {TWTABLE, 0x4a, 8, 59}, {TWTABLE, 0x4b, 8, 60}, {TWTABLE, 0x32, 8, 61}, {TWTABLE, 0x33, 8, 62}, {TWTABLE, 0x34, 8, 63}, }; static struct tableentry mwtable[]= { {MWTABLE, 0x1b, 5, 64}, {MWTABLE, 0x12, 5, 128}, {MWTABLE, 0x17, 6, 192}, {MWTABLE, 0x37, 7, 256}, {MWTABLE, 0x36, 8, 320}, {MWTABLE, 0x37, 8, 384}, {MWTABLE, 0x64, 8, 448}, {MWTABLE, 0x65, 8, 512}, {MWTABLE, 0x68, 8, 576}, {MWTABLE, 0x67, 8, 640}, {MWTABLE, 0xcc, 9, 704}, {MWTABLE, 0xcd, 9, 768}, {MWTABLE, 0xd2, 9, 832}, {MWTABLE, 0xd3, 9, 896}, {MWTABLE, 0xd4, 9, 960}, {MWTABLE, 0xd5, 9, 1024}, {MWTABLE, 0xd6, 9, 1088}, {MWTABLE, 0xd7, 9, 1152}, {MWTABLE, 0xd8, 9, 1216}, {MWTABLE, 0xd9, 9, 1280}, {MWTABLE, 0xda, 9, 1344}, {MWTABLE, 0xdb, 9, 1408}, {MWTABLE, 0x98, 9, 1472}, {MWTABLE, 0x99, 9, 1536}, {MWTABLE, 0x9a, 9, 1600}, {MWTABLE, 0x18, 6, 1664}, {MWTABLE, 0x9b, 9, 1728}, }; static struct tableentry tbtable[]= { {TBTABLE, 0x37, 10, 0}, {TBTABLE, 0x2, 3, 1}, {TBTABLE, 0x3, 2, 2}, {TBTABLE, 0x2, 2, 3}, {TBTABLE, 0x3, 3, 4}, {TBTABLE, 0x3, 4, 5}, {TBTABLE, 0x2, 4, 6}, {TBTABLE, 0x3, 5, 7}, {TBTABLE, 0x5, 6, 8}, {TBTABLE, 0x4, 6, 9}, {TBTABLE, 0x4, 7, 10}, {TBTABLE, 0x5, 7, 11}, {TBTABLE, 0x7, 7, 12}, {TBTABLE, 0x4, 8, 13}, {TBTABLE, 0x7, 8, 14}, {TBTABLE, 0x18, 9, 15}, {TBTABLE, 0x17, 10, 16}, {TBTABLE, 0x18, 10, 17}, {TBTABLE, 0x8, 10, 18}, {TBTABLE, 0x67, 11, 19}, {TBTABLE, 0x68, 11, 20}, {TBTABLE, 0x6c, 11, 21}, {TBTABLE, 0x37, 11, 22}, {TBTABLE, 0x28, 11, 23}, {TBTABLE, 0x17, 11, 24}, {TBTABLE, 0x18, 11, 25}, {TBTABLE, 0xca, 12, 26}, {TBTABLE, 0xcb, 12, 27}, {TBTABLE, 0xcc, 12, 28}, {TBTABLE, 0xcd, 12, 29}, {TBTABLE, 0x68, 12, 30}, {TBTABLE, 0x69, 12, 31}, {TBTABLE, 0x6a, 12, 32}, {TBTABLE, 0x6b, 12, 33}, {TBTABLE, 0xd2, 12, 34}, {TBTABLE, 0xd3, 12, 35}, {TBTABLE, 0xd4, 12, 36}, {TBTABLE, 0xd5, 12, 37}, {TBTABLE, 0xd6, 12, 38}, {TBTABLE, 0xd7, 12, 39}, {TBTABLE, 0x6c, 12, 40}, {TBTABLE, 0x6d, 12, 41}, {TBTABLE, 0xda, 12, 42}, {TBTABLE, 0xdb, 12, 43}, {TBTABLE, 0x54, 12, 44}, {TBTABLE, 0x55, 12, 45}, {TBTABLE, 0x56, 12, 46}, {TBTABLE, 0x57, 12, 47}, {TBTABLE, 0x64, 12, 48}, {TBTABLE, 0x65, 12, 49}, {TBTABLE, 0x52, 12, 50}, {TBTABLE, 0x53, 12, 51}, {TBTABLE, 0x24, 12, 52}, {TBTABLE, 0x37, 12, 53}, {TBTABLE, 0x38, 12, 54}, {TBTABLE, 0x27, 12, 55}, {TBTABLE, 0x28, 12, 56}, {TBTABLE, 0x58, 12, 57}, {TBTABLE, 0x59, 12, 58}, {TBTABLE, 0x2b, 12, 59}, {TBTABLE, 0x2c, 12, 60}, {TBTABLE, 0x5a, 12, 61}, {TBTABLE, 0x66, 12, 62}, {TBTABLE, 0x67, 12, 63}, }; static struct tableentry mbtable[]= { {MBTABLE, 0xf, 10, 64}, {MBTABLE, 0xc8, 12, 128}, {MBTABLE, 0xc9, 12, 192}, {MBTABLE, 0x5b, 12, 256}, {MBTABLE, 0x33, 12, 320}, {MBTABLE, 0x34, 12, 384}, {MBTABLE, 0x35, 12, 448}, {MBTABLE, 0x6c, 13, 512}, {MBTABLE, 0x6d, 13, 576}, {MBTABLE, 0x4a, 13, 640}, {MBTABLE, 0x4b, 13, 704}, {MBTABLE, 0x4c, 13, 768}, {MBTABLE, 0x4d, 13, 832}, {MBTABLE, 0x72, 13, 896}, {MBTABLE, 0x73, 13, 960}, {MBTABLE, 0x74, 13, 1024}, {MBTABLE, 0x75, 13, 1088}, {MBTABLE, 0x76, 13, 1152}, {MBTABLE, 0x77, 13, 1216}, {MBTABLE, 0x52, 13, 1280}, {MBTABLE, 0x53, 13, 1344}, {MBTABLE, 0x54, 13, 1408}, {MBTABLE, 0x55, 13, 1472}, {MBTABLE, 0x5a, 13, 1536}, {MBTABLE, 0x5b, 13, 1600}, {MBTABLE, 0x64, 13, 1664}, {MBTABLE, 0x65, 13, 1728}, }; static struct tableentry extable[]= { {EXTABLE, 0x8, 11, 1792}, {EXTABLE, 0xc, 11, 1856}, {EXTABLE, 0xd, 11, 1920}, {EXTABLE, 0x12, 12, 1984}, {EXTABLE, 0x13, 12, 2048}, {EXTABLE, 0x14, 12, 2112}, {EXTABLE, 0x15, 12, 2176}, {EXTABLE, 0x16, 12, 2240}, {EXTABLE, 0x17, 12, 2304}, {EXTABLE, 0x1c, 12, 2368}, {EXTABLE, 0x1d, 12, 2432}, {EXTABLE, 0x1e, 12, 2496}, {EXTABLE, 0x1f, 12, 2560}, }; #endif /* _G3_H_ */ void skiptoeol (void); FILE * pm_openr (name) char *name; { FILE *f; if (strcmp (name, "-") == 0) f = stdin; else { f = fopen (name, "r"); if (f == NULL) { perror (name); exit (1); } } return f; } int pm_keymatch (str, keyword, minchars) char *str; char *keyword; int minchars; { register int len; len = strlen (str); if (len < minchars) return 0; while (--len >= 0) { register char c1, c2; c1 = *str++; c2 = *keyword++; if (c2 == '\0') return 0; if (isupper (c1)) c1 = tolower (c1); if (isupper (c2)) c1 = tolower (c2); if (c1 != c2) return 0; } return 1; } int pm_writebigshort (out, s) FILE *out; short s; { if (putc ((s >> 8) & 0xff, out) == EOF) return -1; if (putc (s & 0xff, out) == EOF) return -1; return 0; } int pm_writebiglong (out, l) FILE *out; long l; { if (putc ((l >> 24) & 0xff, out) == EOF) return -1; if (putc ((l >> 16) & 0xff, out) == EOF) return -1; if (putc ((l >> 8) & 0xff, out) == EOF) return -1; if (putc (l & 0xff, out) == EOF) return -1; return 0; } static int doubleheight = 1; static hscale = 100; static vscale = 100; static void putinit (), putbit (), putrest (), putitem (); static int item, bitsperitem; static char *line; static int bytecnt; #define TABSIZE(tab) (sizeof(tab)/sizeof(struct tableentry)) #define MAXCOLS 1728 #define MAXROWS 4300 /* up to two pages long */ #define XWDCOLS 1000 #define XWDROWS XWDCOLS*290/215 int eof = 0; int eols; int rawzeros; int shdata; int kludge; int reversebits; int stretch; #define WHASHA 3510 #define WHASHB 1178 #define BHASHA 293 #define BHASHB 2695 #define HASHSIZE 1021 tableentry *whash[HASHSIZE]; tableentry *bhash[HASHSIZE]; static FILE *ifp; static int shbit = 0; static int eof_err = 0; static inline int rawgetbit () { int b; if (eof_err) { rawzeros = 20; return (1); } if ((shbit & 0xff) == 0) { shdata = getc (ifp); if (shdata == EOF) { eof_err++; pm_error ("EOF / read error at line %d", eols, 0, 0, 0, 0); } shbit = reversebits ? 0x01 : 0x80; } if (shdata & shbit) { rawzeros = 0; b = 1; } else { rawzeros++; b = 0; } if (reversebits) shbit <<= 1; else shbit >>= 1; return b; } addtohash (hash, te, n, a, b) tableentry *hash[]; tableentry *te; int n, a, b; { unsigned int pos; while (n--) { pos = ((te->length + a) * (te->code + b)) % HASHSIZE; if (hash[pos] != 0) pm_error ( "internal error: addtohash fatal hash collision", 0, 0, 0, 0, 0); hash[pos] = te; te++; } } static inline tableentry * hashfind (hash, length, code, a, b) tableentry *hash[]; int length, code; int a, b; { unsigned int pos; tableentry *te; pos = ((length + a) * (code + b)) % HASHSIZE; if (pos < 0 || pos >= HASHSIZE) pm_error ( "internal error: bad hash position, length %d code %d pos %d", length, code, pos, 0, 0); te = hash[pos]; return ((te && te->length == length && te->code == code) ? te : 0); } getfaxrow (row, bitrow) int row; bit *bitrow; { int col; bit *bP; int curlen, curcode, nextbit; int count, color; tableentry *te; for (col = 0, bP = bitrow; col < MAXCOLS; ++col, ++bP) *bP = PBM_WHITE; col = 0; rawzeros = 0; curlen = 0; curcode = 0; color = 1; count = 0; while (!eof) { if (col >= MAXCOLS) { skiptoeol (); return (col); } do { if (rawzeros >= 11) { nextbit = rawgetbit (); if (nextbit) { if (col == 0) /* XXX should be 6 */ eof = (++eols == 3); else eols = 0; #ifdef notdef if (col && col < 1728) pm_message ( "warning, row %d short (len %d)", row, col, 0, 0, 0); #endif /* notdef */ return (col); } } else nextbit = rawgetbit (); curcode = (curcode << 1) + nextbit; curlen++; } while (curcode <= 0); if (curlen > 13) { pm_message ( "bad code word at row %d, col %d (len %d code 0x%x), skipping to EOL", row, col, curlen, curcode, 0); skiptoeol (); return (col); } if (color) { if (curlen < 4) continue; te = hashfind (whash, curlen, curcode, WHASHA, WHASHB); } else { if (curlen < 2) continue; te = hashfind (bhash, curlen, curcode, BHASHA, BHASHB); } if (!te) continue; switch (te->tabid) { case TWTABLE: case TBTABLE: count += te->count; if (col + count > MAXCOLS) count = MAXCOLS - col; if (count > 0) { if (color) { col += count; count = 0; } else { for (; count > 0; --count, ++col) bitrow[col] = PBM_BLACK; } } curcode = 0; curlen = 0; color = !color; break; case MWTABLE: case MBTABLE: count += te->count; curcode = 0; curlen = 0; break; case EXTABLE: count += te->count; curcode = 0; curlen = 0; break; default: pm_error ("internal bad poop", 0, 0, 0, 0, 0); } } return (0); } void skiptoeol () { while (rawzeros < 11) (void) rawgetbit (); for (;;) { if (rawgetbit ()) break; } } static X11WDFileHeader h11; static char *dumpname; static void putinit () { int i; X11XColor color; /* Init outfil. */ /* Set up the header. */ h11.header_size = sizeof (h11) + strlen (dumpname) + 1; h11.file_version = X11WD_FILE_VERSION; h11.pixmap_format = ZPixmap; h11.pixmap_width = XWDCOLS; h11.pixmap_height = XWDROWS; h11.xoffset = 0; h11.byte_order = MSBFirst; h11.bitmap_bit_order = MSBFirst; h11.window_width = XWDCOLS; h11.window_height = XWDROWS; h11.window_x = 0; h11.window_y = 0; h11.window_bdrwidth = 0; h11.pixmap_depth = 1; h11.bits_per_pixel = 1; h11.colormap_entries = 2; h11.ncolors = 2; h11.bytes_per_line = (XWDCOLS + 7) / 8; h11.bitmap_unit = 8; h11.bitmap_pad = 8; h11.visual_class = StaticGray; h11.red_mask = 0; h11.green_mask = 0; h11.blue_mask = 0; h11.bits_per_rgb = h11.pixmap_depth; /* Write out the header in big-endian order. */ pm_writebiglong (stdout, h11.header_size); pm_writebiglong (stdout, h11.file_version); pm_writebiglong (stdout, h11.pixmap_format); pm_writebiglong (stdout, h11.pixmap_depth); pm_writebiglong (stdout, h11.pixmap_width); pm_writebiglong (stdout, h11.pixmap_height); pm_writebiglong (stdout, h11.xoffset); pm_writebiglong (stdout, h11.byte_order); pm_writebiglong (stdout, h11.bitmap_unit); pm_writebiglong (stdout, h11.bitmap_bit_order); pm_writebiglong (stdout, h11.bitmap_pad); pm_writebiglong (stdout, h11.bits_per_pixel); pm_writebiglong (stdout, h11.bytes_per_line); pm_writebiglong (stdout, h11.visual_class); pm_writebiglong (stdout, h11.red_mask); pm_writebiglong (stdout, h11.green_mask); pm_writebiglong (stdout, h11.blue_mask); pm_writebiglong (stdout, h11.bits_per_rgb); pm_writebiglong (stdout, h11.colormap_entries); pm_writebiglong (stdout, h11.ncolors); pm_writebiglong (stdout, h11.window_width); pm_writebiglong (stdout, h11.window_height); pm_writebiglong (stdout, h11.window_x); pm_writebiglong (stdout, h11.window_y); pm_writebiglong (stdout, h11.window_bdrwidth); /* Write out the dump name. */ fwrite (dumpname, 1, strlen (dumpname) + 1, stdout); /* Write out the colormap, big-endian order. */ color.flags = 7; color.pad = 0; for (i = 0; i < 2; ++i) { color.pixel = i; /* Stupid hack because xloadimage and xwud disagree on * how to * interpret bitmaps. */ if (1) color.red = (long) (2 - 1 - i) * 65535 / (2 - 1); else color.red = (long) i *65535 / (2 - 1); color.green = color.red; color.blue = color.red; pm_writebiglong (stdout, color.pixel); pm_writebigshort (stdout, color.red); pm_writebigshort (stdout, color.green); pm_writebigshort (stdout, color.blue); putc (color.flags, stdout); putc (color.pad, stdout); } } static void putrest () { } static void xwd_writerow (FILE * fd, bit * writerow, int wcols) { register int bitshift; unsigned char byte; register int s, col; bitshift = 7; byte = 0; for (col = 0; col < XWDCOLS; col++) { s = writerow[col] & 1; byte |= s << bitshift; bitshift -= h11.bits_per_pixel; if (bitshift < 0) { putchar (byte); bitshift = 7; byte = 0; } } if (bitshift < 7) putchar (byte); }; int main (argc, argv) int argc; char *argv[]; { int argn, rows, wrows, cols, wcols, row, wrow, col, wcol, i; int vval, hval, skiprows; bit *readrow, *writerow, *bP, *wbP, bitval; float aspect, scale; int format; register int nzcol; char *usage = "g3toxwd [-kludge] [-reversebits] [-scale N] [-aspect N] [-skiprows N] [g3file]"; argn = 1; kludge = 0; reversebits = 0; aspect = 1.0; scale = (1.0 * XWDCOLS) / (1.0 * MAXCOLS); skiprows = 0; dumpname = ""; /* Check for flags. */ while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') { if (pm_keymatch (argv[argn], "-kludge", 2)) kludge = 1; else if (pm_keymatch (argv[argn], "-reversebits", 2)) reversebits = 1; else if (pm_keymatch (argv[argn], "-aspect", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &aspect) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-scale", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%f", &scale) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-skiprows", 2)) { ++argn; if (argn == argc || sscanf (argv[argn], "%d", &skiprows) != 1) pm_usage (usage); } else if (pm_keymatch (argv[argn], "-name", 2)) { ++argn; dumpname = argv[argn]; if (argn == argc) pm_usage (usage); } else pm_usage (usage); argn++; } if (argn < argc) { if (dumpname[0] == '\0') dumpname = argv[argn]; ifp = pm_openr (argv[argn]); argn++; } else { if (dumpname[0] == '\0') dumpname = "stdin"; ifp = stdin; } if (argn != argc) pm_usage (usage); vscale = aspect * scale * 100; hscale = scale * 100; eols = 0; putinit (); if (kludge) { /* Skip extra lines to get in sync. */ skiptoeol (); skiptoeol (); skiptoeol (); } skiptoeol (); for (i = 0; i < HASHSIZE; ++i) whash[i] = bhash[i] = (tableentry *) 0; addtohash (whash, twtable, TABSIZE (twtable), WHASHA, WHASHB); addtohash (whash, mwtable, TABSIZE (mwtable), WHASHA, WHASHB); addtohash (whash, extable, TABSIZE (extable), WHASHA, WHASHB); addtohash (bhash, tbtable, TABSIZE (tbtable), BHASHA, BHASHB); addtohash (bhash, mbtable, TABSIZE (mbtable), BHASHA, BHASHB); addtohash (bhash, extable, TABSIZE (extable), BHASHA, BHASHB); wcols = (MAXCOLS * hscale) / 100; writerow = pbm_allocrow (wcols); readrow = pbm_allocrow (MAXCOLS); vval = wrow = row = 0; while (skiprows > 0) { hval = wcol = 0; bP = readrow; wbP = writerow; col = getfaxrow (row, readrow); skiprows--; } while (row < MAXROWS) { for (col = 0, bP = writerow; col < (MAXCOLS * hscale) / 100; ++col, ++bP) *bP = PBM_WHITE; cols = 1; while (vval < 100) { if (row < MAXROWS) { hval = wcol = 0; bP = readrow; wbP = writerow; col = getfaxrow (row, readrow); col--; while ((col > 0) && (readrow[col] == PBM_WHITE)) col--; col++; if (col > cols) cols = col; wcols = (cols * hscale) / 100; col = 0; while (col < cols) { bitval = *wbP; while (hval < 100) { if (col++ < cols) if (*bP++ == PBM_BLACK) bitval = PBM_BLACK; hval += hscale; } while (hval >= 100) { if (wcol++ < wcols) *wbP++ = bitval; hval -= 100; } } /* while(col */ } /* if(row */ vval += vscale; row++; } /* while vval */ while (vval >= 100) { if (wrow < XWDROWS) { xwd_writerow (stdout, writerow, wcols); wrow++; } vval -= 100; } if (eof) break; } for (col = 0, bP = writerow; col < (MAXCOLS * hscale) / 100; ++col, ++bP) *bP = PBM_WHITE; while (wrow < XWDROWS) { xwd_writerow (stdout, writerow, wcols); wrow++; } return 0; } mgetty-1.1.36/contrib/g3toxwd.10100644000031200000620000000356205567653265015131 0ustar gertgroup.TH g3toxwd 1 "22 may 94" "Chel" "mgetty+sendfax manual" .IX g3toxwd .SH NAME g3toxwd \- converts a Group 3 fax file into a displayable xwd file .SH SYNOPSIS .B g3toxwd .RB [ -kludge ] .RB [ -reversebits ] .RB [ -scale\ N ] .RB [ -aspect\ N ] .RB [ -skiprows\ N ] .RB [ -name\ xwdname ] .RI [ g3file ] .SH DESCRIPTION Reads a Group 3 fax file (raw or digifax) as input. If no filename is given, stdin is used. .IX "Group 3 fax" .IX fax Produces a displayable xwd file as output. .SH OPTIONS .TP .B -kludge Tells .I g3toxwd to skip the first lines for synchronisation. .TP .B -reversebits Tells .I g3toxwd to interpret bits least-significant first, instead of the default most-significant first. Apparently some fax modems do it one way and others do it the other way. If you get a whole bunch of "invalid code" messages, try using this flag. .TP .B -scale N Scale the output to match the printer resolution and paper size, the default of 0.58 will do in most cases. .TP .B -aspect N Scale the output to match the printer resolution and paper size, the default of 1.0 will do for high resolution faxes, 2.0 will do for low resolution faxes. .TP .B -skiprows N N faxrows of the input file will be skipped. .TP .B -name The name will be put in the output file for xwd. .TP .SH REFERENCES The standard for Group 3 fax is defined in CCITT Recommendation T.4. .SH BUGS Long fax files are not handled properly. Output size fixed 1000x1350 pixels defined at compile time. Please report bugs to chel@vangennip.nl .SH "SEE ALSO" pbmtog3(1), pbm(5), g3cat(1), sendfax(8), mgetty(1) .SH AUTHOR .I g3toxwd is Copyright (C) 1994 by Chel van Gennip, . Sources of .I g3topbm and .I pbmtoxwd programs in Jef Poskanzers .I pbmplus package have been used, but al lot of code has been changed or added to simplify its use for displaying faxes. Value added: low use of memory, fast scaling. mgetty-1.1.36/contrib/g3tops.c0100600000031200000620000003576105660432237015015 0ustar gertgroupFrom labinfo.iet.unipi.it!luigi Thu Nov 10 15:19:22 1994 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Thu, 10 Nov 94 15:19 MET Received: from labinfo.iet.unipi.it ([131.114.9.5]) by colin.muc.de with SMTP id <25590(1)>; Thu, 10 Nov 1994 15:19:01 +0100 Received: from localhost (luigi@localhost) by labinfo.iet.unipi.it (8.6.5/8.6.5) id PAA01788 for gert@greenie.muc.de; Thu, 10 Nov 1994 15:15:36 +0100 From: Luigi Rizzo Message-Id: <199411101415.PAA01788@labinfo.iet.unipi.it> Subject: Re: mgetty+sendfax To: gert@greenie.muc.de (Gert Doering) Date: Thu, 10 Nov 1994 15:15:36 +0100 In-Reply-To: from "Gert Doering" at Nov 8, 94 11:13:18 pm X-Mailer: ELM [version 2.4 PL23] Content-Type: text Content-Length: 14459 Status: RO Gert, here is what I have so far. It is a simple converter based on your g3topbm.c (which resembles very closely). Just use it as g3tops < g3file > /tmp/psfile ; gs /tmp/psfile I find it faster than converting to pbm and using xv. Feel free to modify it/incorporate it into the existing g3toxx programs. Luigi -------------------------------------------------------- #define G3PS #ident "@(#)g3topbm.c 1.18 94/10/31 (c) Gert Doering" #include #include #include "syslibs.h" #include #include #include "ugly.h" #include "g3.h" char psheader[]= "%!\n0 72 25.4 div 297 mul translate\n" "72 204 div 72 98 div scale\n" "1 -1 scale\n" "/L { 0 rmoveto 0 rlineto} def\n" "/P { 1 exch L} def\n" "/N { currentpoint stroke 1 add exch pop 0 exch moveto} def\n" "/M { currentpoint exch pop add stroke 0 exch moveto} def\n" "0 0 moveto\n"; int lastx=0, lastblack= -1; int whitelines=0; int pixblock _PROTO((char *start, char *end)); int nullscan _PROTO((char *start, char *end)); void emitlj _PROTO((int resolution, int numx, int numy, char *image)); void emitpbm _PROTO((int hcol, int row, char *bitmap, int bperrow )); #ifdef DEBUG void putbin _P1( (d), unsigned long d ) { unsigned long i = 0x80000000; while ( i!=0 ) { putc( ( d & i ) ? '1' : '0', stderr ); i >>= 1; } putc( '\n', stderr ); } #endif static int byte_tab[ 256 ]; static int o_stretch; /* -stretch: double each line */ static int o_lj; /* -l: LJ output */ static int o_turn; /* -t: turn 90 degrees right */ struct g3_tree * black, * white; #define CHUNK 2048; static char rbuf[2048]; /* read buffer */ static int rp; /* read pointer */ static int rs; /* read buffer size */ #define MAX_ROWS 4300 #define MAX_COLS 1728 /* !! FIXME - command line parameter */ #define BASERES 200 /* resolution of G3 */ #define MVTYPE int /* scale the bitmap */ char *scalebm _P5( (res, cols, rows, map, bperrow), int res, int *cols, int *rows, char *map, int *bperrow) { int nc, nr, i, newbperrow; register char *orp, *nrp; char *newmap; MVTYPE *mulvec; if ( res == BASERES ) /* don't do anything of not scaled */ { return map; } /* do scaling, from "BASERES" to "res" dpi */ nr = (*rows * res) / BASERES; nc = (((*cols * res) / BASERES) + 7) & ~7; newbperrow = (nc + 7) >> 3; newmap = malloc(nr * newbperrow ); if (!newmap) { fprintf (stderr, "g3topbm: cannot allocate %d bytes for scale raster\n", nr * newbperrow ); exit(1); } memset( newmap, 0, nr * newbperrow ); { int max = *cols > *rows ? *cols: *rows; MVTYPE *mv; mulvec = (MVTYPE *) malloc(max * sizeof(MVTYPE)); if (!mulvec) { fprintf (stderr, "g3topbm: cannot allocate multiplier vector\n"); exit(1); } for (mv = mulvec, i = 0; i < max; i++) { *mv++ = (i * res) / BASERES; } } orp = map; for (i = 0; i < *rows; i++) { register MVTYPE *mv; register int j; nrp = newmap + (mulvec[i] * newbperrow); for (j = 0, mv = mulvec; j < *cols; j++, mv++) { if (!(j & 0x7) && !orp[j >> 3]) { j += 8; mv += 8; continue; } if (orp[j >> 3] & (0x80 >> (j & 0x7))) nrp[(*mv) >> 3] |= (0x80 >> ((*mv) & 0x7)); } orp += *bperrow; } free (map); *rows = nr; *cols = nc; *bperrow = newbperrow; return (newmap); } /* turn the bitmap */ char * turnbm _P4 (( cols, rows, map, bperrow ), int * cols, int * rows, char * map, int * bperrow ) { char * newmap; int newbperrow, nr, nc, nx, ny; register int obit; register char * newbp, * obyte; char * oldbp; int byte, bit; o_turn &= 3; if ( o_turn == 0 ) return map; /* turn right */ nc = *rows; /* new columns */ nr = *cols; /* new rows */ newbperrow = ( nc+7 ) / 8; newmap = malloc( nr * newbperrow ); if ( newmap == NULL ) { fprintf( stderr, "g3topbm: cannot allocate %d bytes for turn bitmap", nr * newbperrow ); exit(1); } memset( newmap, 0, nr * newbperrow ); for( nx = 0; nx> (nx&7); byte = nx >> 3; oldbp = &map[ (*rows - nx - 1) * *bperrow ]; for ( ny = nr, newbp= &newmap[byte], /* new y */ obyte = oldbp, obit=0x80; ny>0; ny--, newbp += newbperrow ) { if ( (*obyte) & obit ) { *newbp |= bit; } obit >>= 1; if ( obit == 0 ) { obit=0x80; obyte++; } } } free( map ); *rows = nr; *cols = nc; *bperrow = newbperrow; return newmap; } int main _P2( (argc, argv), int argc, char ** argv ) { int data; int hibit; struct g3_tree * p; int nr_pels; int fd; int color; int i; int cons_eol; int bperrow = MAX_COLS/8; /* bytes per bit row */ char * bitmap; /* MAX_ROWS by (bperrow) bytes */ char * bp; /* bitmap pointer */ int row; int max_rows; /* max. rows allocated */ int col, hcol; /* column, highest column ever used */ extern int optind; extern char *optarg; int resolution = BASERES; /* initialize lookup trees */ build_tree( &white, t_white ); build_tree( &white, m_white ); build_tree( &black, t_black ); build_tree( &black, m_black ); init_byte_tab( 0, byte_tab ); while((i = getopt(argc, argv, "rsld:t")) != EOF) { switch (i) { case 'r': init_byte_tab( 1, byte_tab ); break; case 's': o_stretch=1; break; case 'l': o_lj=1; break; case 'd': resolution = atoi(optarg); if ( resolution != 75 && resolution != 150 && resolution != 300 ) { fprintf( stderr, "g3topbm: only supports 75, 150, or 300 dpi\n"); exit(1); } break; case 't': o_turn++; break; case '?': fprintf( stderr, "usage: g3topbm [-l|-r|-s|-d |-t] [g3 file]\n"); exit(1); } } if (o_lj && resolution == BASERES) resolution = 150; if ( optind < argc ) /* read from file */ { fd = open( argv[optind], O_RDONLY ); if ( fd == -1 ) { perror( argv[optind] ); exit( 1 ); } } else fd = 0; hibit = 0; data = 0; cons_eol = 0; /* consecutive EOLs read - zero yet */ color = 0; /* start with white */ rs = read( fd, rbuf, sizeof(rbuf) ); if ( rs < 0 ) { perror( "read" ); close( rs ); exit(8); } /* skip GhostScript header */ rp = ( rs >= 64 && strcmp( rbuf+1, "PC Research, Inc" ) == 0 ) ? 64 : 0; /* initialize bitmap */ row = col = hcol = 0; bitmap = (char *) malloc( ( max_rows = MAX_ROWS ) * MAX_COLS / 8 ); if ( bitmap == NULL ) { fprintf( stderr, "cannot allocate %d bytes for bitmap", max_rows * MAX_COLS/8 ); close( fd ); exit(9); } memset( bitmap, 0, max_rows * MAX_COLS/8 ); bp = &bitmap[ row * MAX_COLS/8 ]; #ifdef G3PS fprintf(stdout,"%s",psheader); #endif /* G3PS */ while ( rs > 0 && cons_eol < 4 ) /* i.e., while (!EOF) */ { #ifdef DEBUG fprintf( stderr, "hibit=%2d, data=", hibit ); putbin( data ); #endif while ( hibit < 20 ) { data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit ); hibit += 8; if ( rp >= rs ) { rs = read( fd, rbuf, sizeof( rbuf ) ); if ( rs < 0 ) { perror( "read2"); break; } rp = 0; if ( rs == 0 ) { goto do_write; } } #ifdef DEBUG fprintf( stderr, "hibit=%2d, data=", hibit ); putbin( data ); #endif } if ( color == 0 ) /* white */ p = white->nextb[ data & BITM ]; else /* black */ p = black->nextb[ data & BITM ]; while ( p != NULL && ! ( p->nr_bits ) ) { data >>= BITS; hibit -= BITS; p = p->nextb[ data & BITM ]; } if ( p == NULL ) /* invalid code */ { fprintf( stderr, "invalid code, row=%d, col=%d, file offset=%lx, skip to eol\n", row, col, (unsigned long) lseek( fd, 0, 1 ) - rs + rp ); while ( ( data & 0x03f ) != 0 ) { data >>= 1; hibit--; if ( hibit < 20 ) { data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit ); hibit += 8; if ( rp >= rs ) /* buffer underrun */ { rs = read( fd, rbuf, sizeof( rbuf ) ); if ( rs < 0 ) { perror( "read4"); break; } rp = 0; if ( rs == 0 ) goto do_write; } } } nr_pels = -1; /* handle as if eol */ } else /* p != NULL <-> valid code */ { data >>= p->nr_bits; hibit -= p->nr_bits; nr_pels = ( (struct g3_leaf *) p ) ->nr_pels; #ifdef DEBUG fprintf( stderr, "PELs: %d (%c)\n", nr_pels, '0'+color ); #endif } /* handle EOL (including fill bits) */ if ( nr_pels == -1 ) { #ifdef G3PS whitelines++; /*fprintf(stdout,"N\n"); */ lastx=0; lastblack= -1; #endif #ifdef DEBUG fprintf( stderr, "hibit=%2d, data=", hibit ); putbin( data ); #endif /* skip filler 0bits -> seek for "1"-bit */ while ( ( data & 0x01 ) != 1 ) { if ( ( data & 0xf ) == 0 ) /* nibble optimization */ { hibit-= 4; data >>= 4; } else { hibit--; data >>= 1; } /* fill higher bits */ if ( hibit < 20 ) { data |= ( byte_tab[ (int) (unsigned char) rbuf[ rp++] ] << hibit ); hibit += 8; if ( rp >= rs ) /* buffer underrun */ { rs = read( fd, rbuf, sizeof( rbuf ) ); if ( rs < 0 ) { perror( "read3"); break; } rp = 0; if ( rs == 0 ) goto do_write; } } #ifdef DEBUG fprintf( stderr, "hibit=%2d, data=", hibit ); putbin( data ); #endif } /* end skip 0bits */ hibit--; data >>=1; color=0; if ( col == 0 ) cons_eol++; /* consecutive EOLs */ else { if ( col > hcol && col <= MAX_COLS ) hcol = col; row++; /* bitmap memory full? make it larger! */ if ( row >= max_rows ) { char * p = realloc( bitmap, ( max_rows += 500 ) * MAX_COLS/8 ); if ( p == NULL ) { perror( "realloc() failed, page truncated" ); rs = 0; } else { bitmap = p; memset( &bitmap[ row * MAX_COLS/8 ], 0, ( max_rows - row ) * MAX_COLS/8 ); } } col=0; bp = &bitmap[ row * MAX_COLS/8 ]; cons_eol = 0; } } else /* not eol */ { if ( col+nr_pels > MAX_COLS ) nr_pels = MAX_COLS - col; if ( color == 0 ) /* white */ col += nr_pels; else /* black */ { register int bit = ( 0x80 >> ( col & 07 ) ); register char *w = & bp[ col>>3 ]; for ( i=nr_pels; i > 0; i-- ) { *w |= bit; bit >>=1; if ( bit == 0 ) { bit = 0x80; w++; } col++; } } if ( nr_pels < 64 ) { color = !color; /* terminating code */ #ifdef G3PS if (color) { /* black begins */ lastblack= col; } else { /* black ends */ int black=col- lastblack; int move=lastblack - lastx; if (lastblack > -1) { if (whitelines>1) fprintf(stdout,"%d M\n",whitelines); else if (whitelines==1) fprintf(stdout,"N\n"); whitelines=0; fprintf(stdout,"%d %d L\n",black, move); } lastx=col; lastblack= -1; } #endif } } } /* end main loop */ do_write: /* write pbm (or whatever) file */ #ifdef G3PS fprintf(stdout,"showpage\n"); exit(0); #endif if( fd != 0 ) close(fd); /* close input file */ #ifdef DEBUG fprintf( stderr, "consecutive EOLs: %d, max columns: %d\n", cons_eol, hcol ); #endif bitmap = scalebm(resolution, &hcol, &row, bitmap, &bperrow ); bitmap = turnbm( &hcol, &row, bitmap, &bperrow ); if (o_lj) emitlj(resolution, hcol, row, bitmap); else emitpbm(hcol, row, bitmap, bperrow ); return 0; } /* hcol is the number of columns, row the number of rows * bperrow is the number of bytes actually used by hcol, which may * be greater than (hcol+7)/8 [in case of an unscaled g3 image less * than 1728 pixels wide] */ void emitpbm _P4(( hcol, row, bitmap, bperrow), int hcol, int row, char *bitmap, int bperrow ) { register int i; sprintf( rbuf, "P4\n%d %d\n", hcol, ( o_stretch? row*2 : row ) ); write( 1, rbuf, strlen( rbuf )); if ( hcol == (bperrow*8) && !o_stretch ) write( 1, bitmap, row * bperrow ); else { if ( !o_stretch ) for ( i=0; i ESCLEN) return(cur - start); else cur += numnulls; } return(end - start); } void emitlj _P4((resolution, numx, numy, image), int resolution, int numx, int numy, char *image) { int bperline; int resmult = 300/resolution; register char *ip, *lineanch, *nip; register currow, bcount; bperline = ((numx + 7) / 8); /* some spoolers use a "cut" to do printer-type selection (eg: "%!" processing). The newline is to prevent cut (or other line-length-limited UNIX utilities) dying. */ printf("\033*t%dR\n", resolution); for(currow = 0; currow < numy; currow++) { lineanch = ip = &image[bperline * currow]; nip = ip + bperline; while (ip < nip && !*ip) ip++; if (ip >= nip) continue; /* line has no pixels */ while (!*(nip - 1)) nip--; /* truncate trailing nulls */ while (ip < nip) { /* inv: !*ip && !*nip */ bcount = pixblock(ip, nip); printf("\033*p%dx%dY\033*r1A\033*b%dW", (ip - lineanch) * 8 * resmult, (currow * resmult) << o_stretch, bcount); fwrite(ip, 1, bcount, stdout); if (o_stretch) { printf("\033*b%dW", bcount); fwrite(ip, 1, bcount, stdout); } fputs("\033*rB", stdout); for(ip += bcount; ip < nip && !*ip; ip++); } } putchar('\f'); } /****** end of file **********/ mgetty-1.1.36/contrib/gs-security.fix0100600000031200000620000000522406017167152016405 0ustar gertgroupFrom owner-mgetty Thu Aug 24 11:13:35 1995 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Thu, 24 Aug 95 11:13 MEST Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Thu, 24 Aug 95 11:13 MEST Received: from tarsier.cv.nrao.edu ([192.33.115.50]) by vogon.muc.de with SMTP id <93325-1>; Thu, 24 Aug 1995 11:13:04 +0200 Received: (from juphoff@localhost) by tarsier.cv.nrao.edu (8.6.12/8.6.9) id FAA07826; Thu, 24 Aug 1995 05:12:23 -0400 Date: Thu, 24 Aug 1995 11:12:23 +0200 Message-Id: <199508240912.FAA07826@tarsier.cv.nrao.edu> From: Jeff Uphoff To: mgetty@muc.de Subject: Ghostscript problem. X-Spook: Mossad NORML Mossad X-Mailer: VM 5.94 (beta); GNU Emacs 19.29.1 X-Attribution: Up Status: RO Here's the description of the hole that I mentioned in my previous e-mail, which was a CC of a message that I was posting to the Linux security list. I CC'd the 'mgetty' list because we were discussing, and trying to compile a list of, software that calls Ghostscript (both "safely" and "unsafely") and I had mentioned that 'faxspool' calls it (safely) to do file-conversions. Since there may be people out there FAXing files that they have received from the outside--thus opening themselves up to this vulnerability--this is of interest here as well. (Any users of the WWW that view remote Postscript files are of course *very* vulnerable!) The easiest way to demonstrate the problem is to view the following Postscript file with either Ghostview or Ghostscript. Even the "-dSAFER" option (which Ghostview v1.5 passes to Ghostscript by default) does not prevent the file-write: %!PS- (%pipe%echo hacker@rogue.site >> /tmp/foo) (r) file quit Replace /tmp/foo with /.rhosts (or use Postscript's getenv capabilites to write to ~/.rhosts) and you quickly see the dangers... One fix (thanks go out to Olaf Kirch for this) is to patch the gs_init.ps file in your Ghostscript library area in the following manner: --- gs_init.ps.orig Sun Aug 20 23:22:01 1995 +++ gs_init.ps Sun Aug 20 23:22:46 1995 @@ -302,7 +302,8 @@ % If we want a "safer" system, disable some obvious ways to cause havoc. SAFER not { (%END SAFER) .skipeof } if /file - { dup (r) eq + { exch dup /..fname exch def exch + dup (r) eq ..fname (%pipe%*) .stringmatch not and { file } { /invalidfileaccess signalerror } ifelse --Up. -- Jeff Uphoff - systems/network admin. | juphoff@nrao.edu National Radio Astronomy Observatory | jeff.uphoff@linux.org Charlottesville, VA, USA | http://linux.nrao.edu/~juphoff/ mgetty-1.1.36/contrib/logparse.c0100600000031200000620000000553405740217025015400 0ustar gertgroup/* Analyse der Fax-Logdatei: Liste aller ausgehenden erfolgreichen */ /* Verbindungen mit Dauer und Kosten. */ /* Das optionale erste Argument gibt die Dauer einer Telefoneinheit an */ /* 24.11.94 Roland Meier */ #include #include #include #include #define STRSIZ 100 int main(int argc, char *argv[]) { FILE *fin; char *ptr; char str[STRSIZ],id[STRSIZ]; double einheit=0, gpreis=0; int amon,atag,astd,amin,asek; int bmon,btag,bstd,bmin,bsek; int anz, stat, geschw=0, ende=0, endeerk=1; if (argc>1) { einheit = atoi(argv[1]); if ((!einheit) || (argc>2)) { fprintf(stderr,"usage: %s [Dauer einer Einheit]\n\n", argv[0]); exit(1); } } if (!einheit) einheit = 360; if ( !(fin=fopen("/var/spool/fax/Faxlog","r"))) { fprintf(stderr,"Logdatei nicht gefunden!\n\n"); exit(2); } printf("Dauer einer Telefoneinheit: %1.0f Sekunden\n", einheit); printf("empfangene ID\t\tDatum\t\tSeiten Dauer Kosten Geschw. OK=0\n"); while (fgets(str,STRSIZ,fin)) { if (strstr(str,"+FCON")) { sscanf(str,"%d/%d %d:%d:%d", &amon, &atag, &astd, &amin, &asek); if (!endeerk) fprintf(stderr, "Fehler: FCON ohne vorheriges hangup!\n"); endeerk=0; /* Flag Ende erkannt */ } else if ((ptr=strstr(str,"fax_id: '+FCSI: "))) { strcpy(id,ptr+17); id[strlen(id)-3]=0; } else if ((ptr=strstr(str,"checking f"))) { sscanf(ptr+10,"%d", &anz); } else if ((ptr=strstr(str,"transmission par"))) { sscanf(ptr+29, "%d", &geschw); } else if (!endeerk && (ptr=strstr(str,"hangup: '+FHNG:"))) { sscanf(str,"%d/%d %d:%d:%d", &bmon, &btag, &bstd, &bmin, &bsek); sscanf(ptr+16, "%d", &stat); ende=endeerk=1; } else if (!endeerk && strstr(str,"##### failed transmitting")) { sscanf(str,"%d/%d %d:%d:%d", &bmon, &btag, &bstd, &bmin, &bsek); ptr=strstr(str,"+FHS:"); sscanf(ptr+5, "%d", &stat); ende=endeerk=1; } if (ende) { double preis; int atime, btime; if (amon != bmon) { /* ich gehe mal vom naechsten Monat aus... */ switch (amon) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: btag += 31; break; default: btag += 30; } } atime = atag*24*3600+astd*3600+amin*60+asek; btime = btag*24*3600+bstd*3600+bmin*60+bsek; preis = ceil((btime-atime)/einheit)*0.23; gpreis += preis; printf("%s\t%2d.%2d %2d:%2d:%2d\t%2d S,%3d Sek,%5.2f DM, G.%d,St %d\n", id, atag,amon,astd,amin,asek, #if 0 btag,bmon,bstd,bmin,bsek, \t%2d.%2d %2d:%2d:%2d #endif anz, btime-atime, preis, geschw, stat); ende=anz=geschw=0; /* falls Fehler beim naechsten Mal */ strcpy(id,"(FEHLER!) "); } } printf("Gesamtkosten: %1.2f DM\n", gpreis); fclose(fin); return(0); } mgetty-1.1.36/contrib/lp-fax0100775000010700000220000000311005535343624013471 0ustar lplp: # @(#) FaxPrinter 1.0 # # modelled to resemble the SCO printer drivers as closely # as possible # # install this as /usr/spool/lp/model/fax, then add a printer # (via sysadmsh) with printer interface "fax" (name it what you # want, e.g. "fax"). Then send faxes from your applications with # # lp -d -o to= " # e.g.: # lp -dfax -oto=0893243328 /tmp/fax1.ps # # works only if "faxspool" can be found in the command path PATH=/usr/local/bin:$PATH export PATH # return everything to the right of the first "=" parse () { echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`" } # general error handling LP_ERR_LABEL="UX:lp" errmsg () { case $1 in ERROR ) sev=" ERROR"; ;; WARNING ) sev="WARNING"; ;; esac echo "${LP_ERR_LABEL}: ${sev}: $2 TO FIX: $3" >&2 } printer=`basename $0` request=$1 name=$2 title=$3 copies=$4 options=$5 shift; shift; shift; shift; shift # resolution normal_res=no # fax number fax_no="" for i in $options do case $i in n|normal|low) normal_res=yes ;; to=*) fax_no=`parse ${i}` ;; esac done # user = fifth field of /etc/passwd user=`sed -n "s/^$name:.*:.*:.*:\(.*\):.*:.*$/\1/p" /etc/passwd` if [ -z "$fax_no" ] then errmsg ERROR "no fax telephone number given" \ "set option \"-o to=\"" exit 1 fi # for the sake of faxq umask 022 # send the file(s) to the standard out $copies times while [ "$copies" -gt 0 ] do /usr/local/bin/faxspool -u $name -f "$name ($user)" $fax_no $* # for file # do # 0<${file} eval ${FILTER} 2>&1 # echo "\033E\c" # done copies=`expr $copies - 1` done exit 0 mgetty-1.1.36/contrib/mgetty-to-flexfax.sh0100644000031200000620000000432205621537126017347 0ustar gertgroupFrom quack.kfu.com!nsayer Tue Aug 9 00:05:12 1994 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Tue, 9 Aug 94 00:05 MEST Received: from quack.kfu.com ([192.216.60.254]) by colin.muc.de with SMTP id <135962(2)>; Tue, 9 Aug 1994 00:04:35 +0200 Received: by quack.kfu.com id AA17510 (5.65c8/IDA-1.4.4 for gert@greenie.muc.de); Mon, 8 Aug 1994 15:04:20 -0700 From: Nick Sayer Message-Id: <199408082204.AA17510@quack.kfu.com> Subject: g3 to tiff To: gert@greenie.muc.de (Gert Doering) Date: Tue, 9 Aug 1994 00:04:20 +0200 In-Reply-To: from "Gert Doering" at Aug 8, 94 09:40:18 pm X-Mailer: ELM [version 2.4 PL22] Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Length: 1371 Status: RO I've done it. It's just fax2tiff from the tiff distribution. The trick is to add -M to the parameters because the faxes come in little endian. I also modified it to allow me to add an IMAGEDESCRIPTION tag which contains the TSI of the sender. This matches what flexfax does, and let's faxinfo work right. After that, it's just like this: --- new_fax --- #! /bin/sh PATH=/usr/local/bin:/usr/ucb:/bin:/usr/local/lib/mgetty+sendfax:$PATH export PATH FILE=/var/spool/fax/recvq/mgetty.$$ hangup=$1 ; shift id="$1" ; shift nump=$1 ; shift if [ $hangup -eq 0 ]; then hangup="" fi fax2tiff -d "$id" -M -o $FILE $* >/dev/null 2>&1 rm -f $* chown uucp.uucp $FILE chmod 600 $FILE /var/spool/fax/bin/faxrcvd $FILE '?' '?' '?' "$hangup" ttym9 exit 0 --- Normally 'mgetty.$$' would be a bad choice for a filename, but my faxrcvd script (for flexfax) moves that to a different name anyway. BTW: You might pass this on to Klaus (his e-mail seems to be /dev/null, so far as I can tell :-) ): If answer_mode == ANSWER_VOICE (_not_ ANSWER_VOICE | ANSWER_{DATA,FAX} ), it seems silly to even bother doing "AT+FCLASS=0 A". Might as well just hang up. -- Nick Sayer | "Don't worry, they'll ride up with N6QQQ @ N0ARY.#NOCAL.CA.USA.NOAM | wear." +1 408 249 9630, log in as 'guest' | URL: http://www.kfu.com/~nsayer/ | -- Are You Being Served? mgetty-1.1.36/contrib/pbm2styl800.tar.gz0100644000031200000620000000751706023537417016573 0ustar gertgroup‹wLN0íksÚH2_£_1&›l ÆØ±Mî°_ÖÂÎån½®­ 0FJ¿¶’ß~Ý=’ØÞì%{uEïƒ4ÓÓïéî™q×®ùÁ½µU©”{/¾T+•F£Î^0Æ6ô·ZW¿ñëFe³ÆX£R[¯×á¾Wkðþ«|'z2ú÷{HËæÎcã„çÿ‚~,¬­hl…±qÚ à =,î—ØÛµêÛ·삤Ã>†b<+*iýþX²8ƒ²Ûв)Jñܶt¼+¶™˜ÒÑY+ô“ßnÀ˜5McÚÚ ëìŸGNßõñ(#=Ö‚Nà…Ƀ˫fá§ÀT¤d­òv­²É*ÕíÚæöÆû©°“Ÿä‰šÔ7Ò—®ËÈò#á'<GX‚ûÂ$¤Ò0Ž…e†Î©{eоtÛ?=ûwçèý‡ Vøù+éô¬Ðlä–‡ïˆC‹Ôü:ìÆu”ø˜Ž%|x:&¹öØA عðizaoïH¦7®4ã'EéÌâ€^~×ÐÙð‰Ô¯õ‘níЈ™_6ê[•«\¯WØ/BZ€ÒæÛ¬Ö¶Ø™¼âO怣yÕÆV}KM< u=“¨ãŠ8vìú4¦5 BaY‚¹¾ @=LÚ±u-Ïã÷é™\¦™<žIÄeF]6 ¶wŸõCP@}‹„$µÔP›û#z _„¸'ãTÆ‘œìp'´¬ßznè4é~ÂnGhð‹¡•Ö÷„€i–¯=øM_ Á¡'¤ -i µ8æVJ`ô%â·YÙQ¿éãvë£W»‘rÕ«ß“é°PòœÑg· ²¶á‰‚“s@Õ¡‰ ÄÄÈlL˜AÆAWíeÄ a Ð廈D°árÄAEçð)…‡Þƒž,¥M˜í»^ñ¸¼Þ]‡ÕÕÒ„ø K$Ù~žñÌëìàHm¤HLìNîÄRT$Ôx‚›Å7E²íë•ZµqUÒ«:üÕÉK;™)_Xæ§°|ñ ¢|æƒÔXW€9>È.¶j‡™ tÉbuܺ¤ºY´‚ä$HNîy;D75dzýˆ%TsdÔ}r®™ë <䪒¬95è‹6ÿW¤¶ÕÕÉ´/3WI mËÿÁC lKQG¼©QˆI6ñÝôÓŒÙe…Gá U¡‚.èÅ+†^ohñ°Ÿ]5+]eÈ›;×ïŠFµ´sm)”¨gÄèGØ ²GK:#ÜøØFƒa«YÝݽž–;®:>F»QÄÅ$ô 'ðÇ^9‰Œ3´;ÛD¬¦\­T+[ »y6¡€m(Ön¥g"´ {}‘\Ô@ïÁ<£â—£«fQùšuõ¹,½{w]Z©¾­ÍµÕxÂ*šbjR}ësêëµôœçL1=¥ñŒ)[zjÊ| ªØ¯¶¡h÷d¡Góý‚`1Ù{#«_]½j¢(KÍfe: ÌÖ1ÂÄKÒÞ™†Ùž:éþÈR³â-™Ž.(-0u6š%˜YAöƒëÉ× ²Q¹\ž…À¿•AoX¼~níAžÈªÛóßÕ¶g½šKo2¯þÎÆ#ï6g¿›¯ Ì4çìòqRRÕYMgu¦›¸»›.$¸–£?ŠÀ,³!üJ(§Ф`ïCO8åG0̶~„|À›;p>óßä}1|›>0„§½2†Ç÷ѹ^ú-¤ÌóÚ„”øËÜQ³‰ý2ÇÝ•SæU‘D‚ë̾™<–S‰4¼ü,H¦¸»“©Ò-Τè*«í g)=´<á~— ‰b³’ˤÜà¿„½¡°± Htæv1åncÙ`&ÉE‹(HyhOá¸q½!w(u÷!ß>°«{j·udo°¨ö€öÜì¬Ü’š¤9ái­AU ¸|L`nþ¤’iÖ¶*[F‚P˜HX‚"ª6â:•-'¹)¦:Ÿö?¶;ÆÑÉÑÅ6dË=xh3§ÊœÚ´”íææºráõF…™c©ÃÈU§¶RÛh4#‚øÐz\8Ä]¿¨ºzáuoåuÿ+èµM}s}:Ö± .'Ry ë•ô©Çkø8ŸÌàY%¹ Fešª†æ]¿7”h¨°o=ÎÀ­'‘Ä$¨X&$¬Pé¯J3Óï´œˆ[ óìty–ͯN!ÂC.G)Žÿ¢Z&Ô¿øÀÃq0öÜi`ª1as©ºÜôtê#¬Àכ˫’ö{LJèøràSõºaÿ²V‰:g”²û$él2qw±¨º*UÏ¡k ߇݇ê+3V›}ÕƒRŒÿSbõCe»à´°-\ ‡Š[³°<•]Ï£”Ü û^Øßf…'ùb—ÆÍ ¾tzå*þûÄlHMü¨¾<Û;6ùI8hËTô/Sió˜ ¿‚ùuÉ“uº“'\µºžÂ¥((¶Ç>qÜ[PjmU*%æpØ—•3.—'ΘÑXmccJgê3¶wj1ÝqŸeZ!äVEp:œ.éxÄÖÙ4¾.œÕqñ%°èí§Cn$ÀÕhØ–mÌ *ÄnzI(¬@–²ÚLq”ŸÞÜë¢×cÇÎ#-Fêx±³ºqH¨sâʉŠÒ—$ üLგÞ= (¬+|פDå÷¸C4HLP²×² ¿‰¢Ï›¨Cµó<©ZÂÁ× Îêÿ8'ö<*±{›µ­|°Ì/É{©Ép´ê=ëì,ÚNx· ž4\Ê.Þ #Ï"jÒ¯6:à‰<§S( hÔ#$ñtÕ±ƒ=:À}Õ å¸gÊD¦p­FÈ “Ì"Sû?%vqÚ”ä¢q??±©Ù `^ÛÂŒDá?ÆNÂ^­ÅšÈOå ñ ‡ØÌ$”$ûÁí¯>¹ZÀŽùHôÁŒ¿çŸÿ²ju£ž;ÿ­Ö«•Åùï€W,¶•V/§N‚—µWÚ«o;ƉÚâëÜù,>š:ˆÕàé¾k>o[ÛßÙd½^ú¡qhñ¯n½?‡×ÆiŸ¹eá¨VèS«©Ë=Ø<ãd[K1¹9ûvµ—?÷cø$Œ%f¸é¹Ñ°Æi÷’UÊ×2ˆËîvîX}u/7‚ä–BHéÇ10˘8Û0¦â±i/=›ý,IYŒ_õ~evëà¸ý53 úU­yÑê-jÍfÐI¼×ØÖ^¢ƒ<ôn² ÁÃòà!»ÚÄ–ÔZÙ¥;Æÿ (E}ß5žˆÿõJ½š‹ÿ•F­±ˆÿ?”þUz dÚcµ¯óAÓ26'©DŽC¬În…E P1Äõƒï²‘ëÐø§3“û¾æKÁxاÜfùš—ùX8Ñù´™¾€7G®pÙ=ÏòãT¨Å%@ôP¸` ÛÄ(ÎkaÂvª(›œŸhŽÜÂl9ˆE¬Úmà©>õ…Oa©ª(ÏRÙÇöÑ ì1hõ‘*Ÿ-£¾°Ç`Œ‰²âvÞòÓðBI’αá!±W¥3(?Ò¥"R¡ÎУ‚ …ú™‡©ºÎaZ1–»pJ lH-¼ïúÐ~o±ýmR´í=ˆp@çHªž^PC–À Øò`=pÙe#¶G:ª6Á¸–m(ŃûUdØçw0¶¬€H{|²ìÖ€˜AÀS< ß‹²ƒˆé¬»Ò!–X ?â›ûqÓP«–«[JK1]eÖ¦¼¤±(œµ˜R3C¡ö!‘ÁëLÎï&IahJÚ6"X¶§Î°?œS°jkaû2ºŒgæn•eúU>ZtËÑÐU1XÆî1mbÈäé˜îp-7ËèÂPÓ ´8ð D,À¿ wÄ«ï„t 4’ˆAaQ—Pð`ÜLûˆÆ¤hh“F¢¦}B‡Ê÷!êë&2ô‰]y1)NÂÏúVÿ[[_7ÎöABØ…üY:áÞ¤¸ÅV¼…מ(@8cN]ešÌ'à/}9“»d(ãŽè ‘ßµ,ê+“cƒ?u-a[®Ï4ÛÊvPRÊÒÞÈØ3Ì‘ëNìmÙ¦¥¡aÑ|QDW2Lî8d<• GŒ²rˆò>àŽiÚ¾;¾÷ä`hsåfr¯Qõ\‚µ’-¼?ù®œB˜< »@ˆ®'Ÿî„aÔ DƒŸª!Gð2›NJ‰ƒåµ¬ñçn?¸EâÉ5c“8Õ»=òUE$)† †df¨X;hëó¡Wf§H¬2`‡}v½ 2íXÀº VLÇ‚Ò6[>VÁ”=¨Jèº ðâA ã¿wA_CŽÒ–þ÷4C³92yƒ„ë ¯/Hô%znºÃ!€[´.é ë^½Šl£¼¬ýåØ_ ,à»B¦BûNk<‘ÿ×6+ùü¿VYßXäÿ?Ê2í*+@œ8ã@ؘ\`ð(hå£e*ƒòùvÒ:n§ûÌÈžžQ7:NÅçg÷Úë©{°u ÞÖ§ÃΧC­¼—]±³Ç.™qîhÐ^û|ÿC§}´÷éä=P—úØq^2ŸÕ*ùã:mþiݼÓ8Nã *Q*”aãÌÑò]ë"*„Ô9q®bßVi3+!ö*!íÉRˆ=U iÏ-…ØÌR(¯9µÐ =MC…'‹¡ÂkûÚŸ¯…´¨ú3µ–9§‹J¡BTr¦K¡B¶*D¥–¯…ØcµP^OVCI1”P–TÚój ùê‚ÃY«±é¢ÝÑÊgHŒªX)–³ ‘È¢ù…Ïí#˜ÝfG'‡§ãÖÅÑéIû¤€Á®¸QÒ¢(uqÚѾ)5ÓÊ¿fçfë•íê&ä\4 ŸÑÃE~¶€,` XÀ°€,` XÀ°€,` XÀž„ÿØ> iPmgetty-1.1.36/contrib/pbmscale.c0100644000031200000620000000747105422505227015365 0ustar gertgroup/* pbmscale.c - scale a portable bitmap ** ** Copyright (C) 1989 by Paul Haeberli . ** Copyright (C) 1993 by Chel van Gennip ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. ** ** Update jun 11,1993, Chel van Gennip, ** added simple scaling to improve speed ** */ #include "pbm.h" void main( argc, argv ) int argc; char *argv[]; { FILE *ifp; int argn, rows, wrows, cols, wcols, row, wrow, col, wcol, i,format; int vval,vscale,hval,hscale; bit *readrow, *writerow, *bP, *wbP,bitval; float aspect,scale; char *usage = "[-scale N] [-aspect N] [-stretch] [pbmfile]"; pbm_init( &argc, argv ); argn = 1; aspect=1.0; scale=1.0; /* Check for flags. */ while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-stretch", 2 ) ) aspect=2.0; else if ( pm_keymatch( argv[argn], "-aspect", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%f", &aspect ) != 1 ) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-scale", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%f", &scale ) != 1 ) pm_usage( usage ); } else pm_usage( usage ); argn++; } if ( argn < argc ) { ifp = pm_openr( argv[argn] ); argn++; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); vscale=aspect*scale*100; hscale=scale*100; pbm_readpbminit( ifp, &cols, &rows, &format ); readrow= pbm_allocrow( cols ); wcols=(cols*hscale)/100; wrows=(rows*vscale)/100; writerow= pbm_allocrow( wcols ); pbm_writepbminit( stdout, wcols, wrows, 0 ); vval=wrow=row=0; while(row=100){ if(wcol++=100){ if(wrow Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Wed, 4 Jan 95 14:05 MET Received: from ben.britain.eu.net ([192.91.199.254]) by colin.muc.de with SMTP id <25577-1>; Wed, 4 Jan 1995 14:05:27 +0100 Received: from durham.ac.uk by ben.britain.eu.net via JANET with NIFTP (PP) id ; Wed, 4 Jan 1995 13:04:32 +0000 Received: from gauss.dur.ac.uk by durham.ac.uk; Wed, 4 Jan 95 13:03:52 GMT From: Tony Scholl Date: Wed, 4 Jan 1995 14:03:50 +0100 Message-Id: Received: from germain.durham.ac.uk (germain.dur) by uk.ac.durham.gauss; Wed, 4 Jan 95 13:03:50 GMT Received: by germain.durham.ac.uk (4.1/SMI-4.1) id AA14688; Wed, 4 Jan 95 13:03:35 GMT To: gert@greenie.muc.de Subject: pbmsplit Status: RO Hi, A promised, here's a late Christmas present (and a pretty crummy one, too --- _my_ Christmas present was a ZyXEL...) but I've found it useful at times. Tony ---------------------------------cut here------------------------------------ /* pbmsplit.c: split a pbm file into pieces of specified size, with overlapping/breaking on blank rows. Usage: pbmsplit [-w rows|-o rows] [-n rows] {-|infile} [outfile] Optional argument -n is number of rows for each output file (default 2400). Optional argument -w is number of rows by which it is permissible to shorten an output file to search for a whitespace-only row to break (default 0). Optional argument -o is number of rows to overlap (default 0). You cannot specify both -o and -w. Argument - means read from stdin (in which case outfile MUST be given) Output is written to outfile.001, etc; outfile defaults to infile. This was put together by Tony Scholl (a.j.scholl@durham.ac.uk). I've tested it a little, and it seems to work. But the code is far from brilliant, so if you can write a better/working one please do..... */ #define MAXROWS 2400 #include #include #include #include #include int row_len; void usage () { fprintf (stderr, "Usage: pbmsplit [-w rows|-o rows] [-n rows] {-|infile} [outfile]\n"); exit (-1); } void fatal (char *s) { fprintf (stderr, s); fprintf (stderr, "\n"); exit (-1); } void copy_rows (FILE *inf, FILE *outf, int r) { int c, n; n = r * row_len; while ((n-- > 0) && ((c = getc(inf)) != EOF)) putc(c, outf); if (n > 0) { fclose (inf); fclose (outf); fatal ("Unexpected EOF"); } } void copy_saved_rows (FILE *outf, char *buf, int r) { int n; n = r * row_len; while (n-- > 0) putc (*(buf++), outf); } void copy_and_save_rows (FILE *inf, FILE *outf, char *buf, int r) { int c, n; n = r * row_len; while ((n-- > 0) && ((c = getc (inf)) != EOF)) { putc (c, outf); *(buf++) = c; } if (n > 0) { fclose (inf); fclose (outf); fatal ("Unexpected EOF"); } } /* function to copy characters and return the OR of them */ int copy_row2 (FILE *inf, FILE *outf) { int c, n; int d = 0; n = row_len; while ((n-- > 0) && ((c = getc (inf)) != EOF)) { putc (c, outf); d |= c; } if (n > 0) { fclose (inf); fclose (outf); fatal ("Unexpected EOF"); } return (d); } int put_white (FILE *outf, int r) { int n; n = r * row_len; while (n-- > 0) putc ('\0', outf); } main (int argc, char *argv[]) { int count = 0; int over_rows = 0; int max_rows = MAXROWS; int min_rows = 0; int frows, fcols; int rows_remaining; char header[64]; FILE *in_f; FILE *out_f; char *in_fname; char *out_fbasename; char out_fname[256]; char *over_buf; /* parse arguments */ if (argc == 1) usage (); while ((**++argv == '-') && (*++*argv != '\0') && (argc-- > 3)) { switch (**(argv++)) { case 'o': over_rows = atoi (*argv); break; case 'w': min_rows = - atoi (*argv); break; case 'n': max_rows = atoi (*argv); break; default: fprintf (stderr, "Invalid option \"-%s\"\n", *(--argv)); usage (); } argc--; } min_rows += max_rows; in_fname = *argv; switch (argc) { case 3: argv++; case 2: out_fbasename = *argv; break; default: usage (); } if ( out_fbasename[0] == '\0' ) usage (); if ((over_rows > 0) && (min_rows != max_rows)) fprintf (stderr, "Warning: you cannot use both -o and -w! I'm ignoring -w.\n"); if (over_rows > max_rows/2) fatal ("You have specified an excessive overlap!"); if (*in_fname != '\0') in_f = fopen (in_fname, "r"); else in_f = stdin; if (in_f == NULL) { fprintf (stderr, "Cannot open %s for reading\n", in_fname); exit (-1); } fgets (header, 62, in_f); if (strcmp (header, "P4\n") != 0) fatal ("Wrong magic number"); fgets (header, 63, in_f); fcols = atoi (strtok (header, " ")); frows = rows_remaining = atoi (strtok (NULL, " ")); row_len = (fcols + 7) / 8; if (over_rows == 0) /* no overlapping */ { while (rows_remaining > 0) { sprintf (out_fname, "%s.%03d", out_fbasename, ++count); if ((out_f = fopen (out_fname, "w")) == (FILE *)NULL) { close (in_f); fatal ("Cannot open output file"); } if (rows_remaining < max_rows) /* put the lot */ { fprintf (out_f, "P4\n%d %d\n", fcols, rows_remaining); copy_rows (in_f, out_f, rows_remaining); rows_remaining = 0; } else /* first put min_rows */ { int j = min_rows; fprintf (out_f, "P4\n%d %d\n", fcols, max_rows); copy_rows (in_f, out_f, min_rows); /* now look for white rows */ while ((j < max_rows) && (j++) && copy_row2 (in_f, out_f)) ; rows_remaining -= j; put_white (out_f, max_rows-j); } /* now close outfile */ fclose (out_f); } } else /* do overlapping */ { if ((over_buf = (char *)malloc (over_rows * row_len + 1)) == NULL) fatal ("Cannot allocate memory"); while (rows_remaining > 0) { sprintf (out_fname, "%s.%03d", out_fbasename, ++count); if ((out_f = fopen (out_fname, "w")) == (FILE *)NULL) { close (in_f); fatal ("Cannot open output file"); } if (count == 1) { if (rows_remaining <= max_rows) /* put the lot */ { fprintf (out_f, "P4\n%d %d\n", fcols, rows_remaining); copy_rows (in_f, out_f, rows_remaining); rows_remaining = 0; } else /* put a page, saving overlap */ { fprintf (out_f, "P4\n%d %d\n", fcols, max_rows); copy_rows (in_f, out_f, max_rows - over_rows); copy_and_save_rows (in_f, out_f, over_buf, over_rows); rows_remaining -= max_rows; } } else /* count > 1 */ { if (rows_remaining <= max_rows - over_rows) /* put the lot */ { fprintf (out_f, "P4\n%d %d\n", fcols, rows_remaining + over_rows); copy_saved_rows (out_f, over_buf, over_rows); copy_rows (in_f, out_f, rows_remaining); rows_remaining = 0; } else { fprintf (out_f, "P4\n%d %d\n", fcols, max_rows); copy_saved_rows (out_f, over_buf, over_rows); copy_rows (in_f, out_f, max_rows - 2 * over_rows); copy_and_save_rows (in_f, out_f, over_buf, over_rows); rows_remaining -= max_rows - over_rows; } } /* now close outfile */ fclose (out_f); } } fclose (in_f); } /******************************* end ****************************************/ mgetty-1.1.36/contrib/pgx.c0100644000031200000620000000577205653444415014406 0ustar gertgroup#if 0 From ursa-major.spdcc.com!uucp Tue Oct 18 22:28:02 1994 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Tue, 18 Oct 94 22:28 MET Received: from ursa-major.spdcc.com ([140.186.80.3]) by colin.muc.de with SMTP id <25577(1)>; Tue, 18 Oct 1994 22:27:47 +0100 Received: by ursa-major.spdcc.com with sendmail-5.65/4.7 id ; Tue, 18 Oct 94 17:12:35 -0400 Received: by crucible Tue, 18 Oct 94 17:09:47 EDT; id AA26935 Date: Tue, 18 Oct 1994 22:09:00 +0100 From: Winston Edmond Subject: Mgetty contribution, part 11 of 11 To: gert@greenie.muc.de Message-Id: <9410181712.AA26017@spdcc.com> Status: RO part 11: contrib/pgx.c Count pages / extract page Compiles with: gcc -O2 -o pgx pgx.c Installation: I put it in /usr/local/bin/. --------------------------------------------------------------------------- #endif /* Count pages or extract a page from a file */ /* Usage: pgx [-] [] Without the page number, counts pages and prints result on stdout. With the page number, copy that one page from stdin to stdout. 94Oct15 WBE initial version */ #include #define false 0 #define true 1 int main (int argc, char *argv[]) { int lines_per_page = 60; int curpage, curline; /* current page and line numbers */ int c, i; int onpage = false; /* (bool) true when requested page reached */ int wanted_page = 0; /* page to extract (0 if just counting) */ int empty; /* true if no chars on page yet */ /* process command line arguments */ if (argc > 3) { usage: fprintf (stderr, "Usage: %s [-] []\n", argv[0]); exit (1); } i = 1; if (argc > 1 && argv[1][0] == '-') { c = argv[1][1]; if (! isdigit (c)) goto usage; lines_per_page = atoi (argv[i]+1); i += 1; } if (i < argc) { c = argv[i][0]; if (! isdigit (c)) goto usage; wanted_page = atoi (argv[i]); if (wanted_page <= 0) { /* non-numeric or bad argument */ fprintf (stderr, "Page numbers must be > 0.\n"); goto usage; } } /* continues */ /* main continued */ curpage = 0, empty = true; while ( (c = getchar()) != EOF ) { if (empty) { /* there's at least 1 more char in file */ empty = false; not_empty: onpage = (++curpage == wanted_page); curline = 1; } if (c == '\f') { if (onpage) exit (0); c = getchar (); if (c == '\n') c = getchar (); /* ignore LF after FF */ if (c == EOF) break; /* ignore page breaks that end document */ goto not_empty; } if (onpage) putchar (c); if (c == '\n' && ++curline > lines_per_page) { if (onpage) exit (0); empty = true; } } if (onpage) exit (0); if (wanted_page > 0) { fprintf (stderr, "No page %d in input\n", wanted_page); exit (2); } printf ("%d", curpage); /* page count */ exit (0); /* normal exit */ } mgetty-1.1.36/contrib/readme.supra0100644000031200000620000000776405612551542015753 0ustar gertgroupFrom sashimi.wwa.com!pshrink!veck Sat Jul 9 21:16:51 1994 Return-Path: Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.2) id ; Sat, 9 Jul 94 21:16 MEST Received: from newton.Space.NET ([194.45.12.1]) by colin.muc.de with SMTP id <135943(2)>; Sat, 9 Jul 1994 21:19:20 +0200 Received: from sashimi.wwa.com ([198.49.174.1]) by newton.Space.NET with SMTP id <375029-3>; Sat, 9 Jul 1994 21:14:39 +0200 Received: from pshrink by sashimi.wwa.com with uucp (Smail3.1.28.1 #8) id m0qMhtQ-000bmFC; Sat, 9 Jul 94 14:16 CDT Date: Sat, 9 Jul 1994 11:55:12 +0200 From: "Steven King [Really!]" Subject: Re: MGETTY: Can't do RTS/CTS? To: Gert Doering In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Status: RO On Fri, 1 Jul 1994, Gert Doering wrote: > Should do. I'm using it with a ZyXEL and H/W flow control, and it works. I found my problem with mgetty not playing nicely with my Supra. Turned out to be a Supra problem. (Oooh, big surprise there!) Here's the synopsis I posted to comp.os.linux.help. Since there *is* a work-around possible in mgetty, I figured you might want to consider it for future releases. Thanks for your help! (And your excellent program!) Newsgroups: comp.os.linux.help From: veck@pshrink.chi.il.us (Steven King [Really!]) Subject: Re: MGETTY: Can't do RTS/CTS? Message-ID: <1994Jul9.154954.547@pshrink.chi.il.us> Date: Sat, 9 Jul 1994 15:49:54 GMT veck@pshrink.chi.il.us publicly declared: >Well, one problem. I just discovered that mgetty doesn't enable RTS/CTS >handshaking properly. This is most noticable when a low-speed modem dials >in to my Supra 14k4 modem. I do an "ls -l" and the whole thing is sent to >the Supra at 38400 bps. Unfortunately, the Supra is only spooling out to >the remote modem at 2400 bps, and the text gets very garbled. I found the problem. You're gonna love it. First, after mgetty initted the modem, I connected with kermit and checked the settings. AT&V showed me that RTS/CTS was turned off, despite the fact that it's turned on in the non-volatile RAM and I set mgetty's init string to just "ATZ" to load the stored settings. So I cranked up mgetty's debugging level to the point where I could see everything it sent to the modem. No obvious problems. It sent the "ATZ" then a bunch of fax commands. Howinthehell did flow control get nuked? I connected with kermit again and started issuing the commands one by one, just as mgetty did. In between I checked the settings to see where I lost flow control. ATQ0V1H0 Hard-coded into mgetty to make sure it can talk to the modem, no problems here ATZ Okay, &K3 is set, we have flow control AT+FCLASS=0 Bingo! A side effect is that this turns off flow control, as shown by AT&V reporting &K0. So, apparently Supra modems (both my 14k4 and my 28k8 models have this behavior) turn flow control *OFF* as a side-effect of "AT+FCLASS=0". Supra probably thinks this is a feature of some sort. Who know what evil lurks in the hearts of firmware programmers? The fix was too easy. Now that I knew where flow control was being disabled, it was simply a matter of hacking a line into mgetty to re-enable it. Thanks to Gert's fine programming this simply meant adding a single line to mgetty.c. After line 65, add 65 "AT+FDCC=1,5,0,2,0,0,0", "OK", >>>> 66 "AT&K3", "OK", as the last fax init string. A simple fix, but hard-coded for Supra modems. If your modem isn't a Supra this may not be the proper command. (But if your modem isn't a Supra you probably don't have this problem, eh?) -- ------------------------------------------ "What if there were no beer?" Yep, that's about the only time I'd order a Zima, all right. mgetty-1.1.36/contrib/scrts.c0100644000031200000620000000200505441202656014722 0ustar gertgroup/* scrts.c - auxiliary program to set the CRTSCTS flag on serial ttys * called like: "scrts ttyS1 ttyS5" * intended to be used on Linux, where sendfax cannot send the * flag itself. */ #include #include #include #include int main( int argc, char ** argv ) { int i, fd; struct termios tio; char device[1000]; for ( i=1; iûÛü‰¶ÕëXâ™Âqº|Â6Wþ³„èôl»ÛµÚÝ.ÆlÇj=g‡¿mšy‰Ï–«ß†‹³¥Jžý¿ûËêö§Æ*ÔÙ2ŽïÎUôWâa[V·Ýþ²ý{Žmìß±,÷vÛéXÏ„õûÿÍÿþøGqlõFã$н@<—Û4‘Qì{‘T™/W •eûÈ[ g)<çù)R•}:$ÖÐöýþ$òV³À'§'š‡kuv§öôÊÛˆçÿô¯ÏÅ÷u²_ÿÝøÙ&Q÷¡zø Ú¿|Ž®³ÓÓƒ9÷áÑ:óãÕÊ[4•“p.NÔ'ñ®ƒøá,ݧ™Z‰ïw§âùðâl¡â•Ê’½øÁ¶ðy.ž£ÛÒÄ¿‹ÿ¾—‰³ô9ø²aöñ<Ú$â,x^‡*%Å7ÝÄqt`›Y¸–ÅÀóÓ¿dý‹el¼…:ߤ5ûíõß²Ûjý;NÖ¿Õéücýÿ=þþðûëéÙ ˆgê¬un5øƒ›(/‹“â»y*®§îÍëë·4ö6Ì"õB\†~§ñ<ïâ$gb2x?»ÿy>ºr lo×A¸^ ãÝ a_§óöąݧÑQìoWjý¨T ‚•ÆÛÄWé qâeðÄÓ:Ìt»ÙDá— ®á¨‡=Cµ×ð ±Ib«ˆ¦ÒêŒB?-a7²j;}KtƒxQ›9 r,®€Æ‹®óžÓl¬¶Ñã,*ÈÕÎ_j@FAαÓ4³oFPD\¤øx÷ú> ‹D¥P6w\ÊU|¯²˜îßÈÑKß'« ßr(‰Ð,GA#ñÑáo“ ÍðIâ;&º–kõ°ñ²%¬$´±ò²$ÜQÛ_Ià%гîk6¨s#ý(NU4¸q¥—økº{“w;V*»çéþBI˜_â!"™>á]«ˆ¹†™‚ظ°$QôF8?\¬Is/JU³AºNý¼èÎ7ñF˜ïcn ˜Cí„c®ˆÊÅm»ìj6PK<§Ó!±ø.oÿ˜·ò¢ N!’8еóH²˜ùq'á\Aœâ2#…OÜ|v#f/Ål(RŸô0ws‰† $zé÷¿4ðÊÍ—7bùR, Ð¥›ƒÄ’— ¼,€¯Ý|s#6/Ŧހî†A7 º)@ÓKx ¶#ééZ­ßa잸¾]í&¢´Ú›·ã"è8€ŸÇÚšîHÝca!YC¶^AyÛ¨tž€}}'+l7+Dèµa^ˆôS’iê××5êÓiŽÒÌô'Á+„VP¾H+ÅË ³h0žÔÆÇÎyq5é2~ MLË‹†¿sómª’ ZÞßùñ&Ä”T ?f2žmçð$¬„/탓ñ"Úo–'/…8ÕíÜæyå4/»+4’Ÿ¤ÂÀêik¨fc³Í°Á«äÞ‹Ðgœ“ hÿ~-ôÍ‘ÓË\†7,—ô÷׸@-þîz¡;.ù²£ ›+û0 “"P|g‰µÊÚÔ§œ1XÝÜé¦Èf"‰3 Ng6dcüGa~d°ö‡¶P9(_7D>ÝÎ4³}šÃÈ Ù02Ø$…–ápÕñ&U<ÍŒˆb­×¨Ú‡lËþ/p`-’Îaò]ZøWyõ¹ÓaáÚ߸U s0ÔlŒ……r7`Cÿ9/üMc"UµðØ 9ÄÎ|Gf‡Œ2ØM†Ï’­^3Õzü8}ý“òn6ìîw¶ZV¸µ¥ço3¾u¤bëXÍ#È€vKfaðP[®<ìòkºïÈ2kÅ„º2€b}› õd*¬²0¥Ö…¤uCw}é« Œ"¹Ü®^²]EÞ6c2C/⵺£aWúžá4"ê‘JÓÅëÉOÛ8õõ"b©ºfL£çÊr7âëÔg^ʰ-9G™ðE[C³j¼ƒu¥¢(ÜÒcnÞb¡4ÉžiƒÛ}¹QI¶Œ·)¥éÔ3Sœ…¹ÊÅ6ŒX‚HÍY9®¼³6lͽèy“p±Ô-ÈRXBU2W€°ÅºÑ•\^ºäF¦³*›}J=µòVr€Ý´Ps¿&lEÚ•±Vl"?ÔÍ:°dºñ|ÖÚ mrÏÍ.|¹ÆÚXbÐÃÆîg¡ÑÊàâÀ?p‹x³/Y ä\­Â5RîÑ’EjE~0×Î2pQê,B¬Èu¬ñFr‰È©x2ƒ±LÏQŒ%Š 3˜Ô|whÉ@aÐ3ÚrmSðÛ²@CGfqº…iØ'0ÄXü ¯]-™!yÍjË·]¹ñ¹a•{’qZ…0ËúJö%¼¾ ­Eb¬¼ÔßFF ÚJ] ]Bý´õ’L{èpDK/šk:c-¸ÐÓ›Àƒ°ÂHåY®%e(pm9(gæ"«•ƒÃ€à¶ä  n[êÖt;rP¬w·+ìê.¹¡[›²{!ÇþW r|Än(Çž”ëÊ×òH¾®ÇòõòD¾®‹7²ä8[2™‘-,§1räUIsÔ’W%ÍQ[^Òuä#j2]yuÀ¡Oˆ²pñZ]È+w½þF}y[qÈ[æ¢É åíWÞÉ•Tcùv':>N$BÌ"­¡±%½’ϱ½Ä;ðÚ6ã–ôJ5ŒáÔºwçsŽ»ÒÓP=é׌9¾ªâÖ—ªâ6 ðsÄoˆú¨6­±+à {$à {,à W‹3‘aybI•±j'¶\—Ó˜8ØI š“–ŒKš“6$Š%štd\¡ve|À6³ûÐ ^ȘÉÂLúr[qÈmÅe(·G<\¹= ;’ûÊøZ¦Æš“‰Ü—9Æ^ûœ£ÚNY˜Êש»ô’œv®y¼Î¨ŸVú¦œ©¦b“»5:mÿ—ÞÆÕ9ªÆˆ”b˜ý‰B³ò‹èÉñÚ©`g2E5Ä9©&4âšCäYN UJÙuÇcΛ‘Q1{ƒ>ªWß* vÕóH”èzŒOiÌBæ•jtún„_{+Å5—Qµ› _B… v£8Ù‹:4ëˆõ!ë*ubޤ‹º 0èâ~åí"µ^À+Ë#„úx^T?ròzDÊ&kTºFÆW–G†Œ— 2´EòZ#׉ü“cõ\™jdÓFÚ颰4)åGÖP]!À‡¿õ@Îîôó'½‚8©‡)Vš “b =ˆsÑc&„¢K*ׯ4ÕuéO‚]ãP’bjúø–oõd hʵé0Çb»}fdq:ö ô˜.†?¥Ædg.ÕÄ"C.´äð‘þlÊÈ¥_¡®³öuì¬‚Ž®õ!EYXɽÍPô+pÕ·hïl>ª•ºš4Û•³gB;£e !†Ñ”PUÝÚ䛥`¼0äˆú!¢±¶ öãÒ>=—`W4&„™]’>ò¢r°ÄÐ…T¨À¤I{<_ª¢s3ŽUPà1³Rç·oò‚~°»}RøIV™`Ë0OæÈ5™ÒtøP+¬À’(CyÄ4?Hª2ÎeÓLp™/æÓ+ði6 £éáç Fâø4_d´><úà @²5ƒ”ËR2ùƒœ¿m‘’õ=D*ï1€O÷ü»£~Û:çz9yêQ‹Ž]©G¥>Á‘Q0pƒäΰ´x;Ø›–¹P×í c€…!nêÙ›âš'äÌ™ “тܡ²h1”-P¬ØŸ§;.§{öÊ#B…f>.+{:‰òãµï‡+ïN/n(Ÿ¯G-Q2ÇTt6u@çÏ3˜:hP¨ÅÍëõ<¦ %oQ7óYéuœ†º(©b?í…n¼M°—Ц°ðÛ¨¹eŽ],½nY¾Ru’W¾Þk‰óÖ(-Ó=»Œd—6À@#GŠ“oœßÛeèß¡°Hÿ÷,IÍAH’þ¾˜ ­P¹£7ª…ÞçHlŠÔ4èíÌ`³}6ê^çrNŽ”çóL|ø¨Áèb¾š}+ÍâÍ@Åü#„ÒUq“BcXî{Q¬Éo<­+»v®_ôqÞ@¸h¼Ýo6P>ÑCóR{ÕÏ6{á_>–£ÃaŒ1±»ø|Ô9A¹?N3$ä^”4:Dp’Sœ@×% •ùž¿Tº¹¸¦;F›Ï•ðý˜cáÊ[  Oï0QÚ冒&ŒˆVqfI¬óbÓ'=ÞûÞl’ݵeŽhßÇp³¡Çµz¿eˆ@Ƨ øœ³é‚85Bäæ s3GY‘Ëk/›ð>¯­Äº-ö~¤¿<à`Å{KtÛâ½ ã¼®ø`åǪ—‚r$Þ¡À¨Îð^%Yô¦} ­d°ë”ǯHÎÍ1ðÐl|ÐPï­‚ð{}¦{?BoQReŠCÛìô‚Ør4<1|ü" îJXQéYIºÙÐó=¢Í±òÛÉSªµ8â1¸ÍµÙýûÙŸ0½#)q/)Ù3׫òÄålÃâƒ[ùs ܼ×7(\-sCB0ÒRÛùOXE«w®Ÿº˜£R2©un¶ï¯M¾…ø@&¡¢³8t!‹‡:Ø\ÒPW‹ºf¦‹ÚQ vJ4Q@ò N\>ÌWÂéðÄuÒ‡ÜaâŠ"dÑ”(dñÕ$B&MYA­.?|Ò˜Pe¯Û½fËiW¤åÛÕ¦|ê!xYê*Ÿs̱OÀ6„°üŒ#Û%çG@ÐáµKÆ¥(\–óò]®·¹ª¼ m¬NÀ£XˆŽõô¸¾ ÑfãxxŠ˜Î}ØÆøôÇWÒ•¾ëÒö³ºÙ`<ÊVýyôN¼|w8®‘=a¼ÙhUøâ‹`Ú  *`ÇšŸ&å+á¯8nSÀO((›±::[¢ÕµPµùÂ߈•HWúáàe.SNúRNúðKJmåÆÛŸëçe‡‡ FzÑÒ·¶! JZ4ô`|pã>’¹,hîS";â%¹Kчjæ¸oö ñ³(5]»ªkoÕ¡t>²³>K˜1x aÓ9J(ÚgŽÌa*«{8_1ÈÓÍÆEœ¯šäi"äd˜ãGðòú:ϱ‹@ê¹R|æ`Úƒ·’oʽ®‚yîľzöfª#S›ìxÕeGB=q¦IqœÆPph^ð9Ì/‘ºëÄÊQC{+"èžo‚©e¸æÜèØàó¡ DWð)Ý8I^!¬G*ÉU’Äúñ4?0/ϖئæ~‘ñWƒåœ–²zt-U´9>;õ~}p–fž·¥¼Å'ñF%´³p·(û)ׂ¼Ô¦t,8É–aªËRºÆÅ "ýZxÌå‘—ìù)ùO—,âÉ>ÞŠ%ílÛ˜å¥ÙõhÂÅ¿OÅJ­bvÒr¤Äþ ÛŸxðRè`CO•ß§ù\QM XÄsaf`H„±f®‘oÊx›QÚÉ]"öQN(¤ü9§s¤p.Ž´Iïg°M¸?ÿ7ËCt ¥{eqWˆò½zA¨çèe¤$ž­èŸwù°„¾WfÒðõ¼ ~¨·œ“+L›_«®yWðOâ”XÊâÝA:…㌕#uA@·|öxB›BáÔ¿§—+XæGµS>¤Û³”+R¤¨8yž†"95ÉJ^ä±'â LþD¼0‚‹ôÊPǦ9ðæRSôæ;SÁ”ó0›õ“H|ªiαÈ較0ÛOi`ÊkãO< óJÉ?W˜­ßB(°Ä¦_¶®Ýª—XŒxÆgMéG/»×å{qüâÌ(öË,ÒŒ_#|Å‹ò͸©Ê¨ 8zÏ­Ù¨¢ø"*nÓšÊ9ú%žeáJÅ´”ˆûgPµ `ÖðÉo½(xÊå V|$Ž Ï÷Qðé¹G4ë¼8 ÍF~ PCE”Íßá„D/·| È›8„<RÂdØt#¾.¡×n6þï¥ü¹‘ëÇýçÏûøŠó Gœwq‹r漫ƒ¯-Î-4-Í1‹QOäÃgõ„Ï,&Tö€Í¼©0ÔàEÒZ¼îB½†J­*wjº"«áGæuYôR6@Ø1•—˜‘GA/cÒãFŠüèÁœéc5•ˆjè#$Ý‘cúýD”Vq´å½‡%vØ„tÛ²,þBzÍ‚2+H¿{ú‚˜§^QN鄨B!)Z¶èõºÂ¶»}æ0½DÕâè:ÂÒ_ý¯ßÕöp6„\Í¢ðÓV >…¶Û¢x"&ô¡Ñæn³á8`eµÄEÛ'oémowö£ç/“Ð_f§Ü?–|;üÑÿÚ½WÃÉ9æ„ëÂé‹.ÉÛB=êØ}႞Ýj·¹Aÿ{çdn¢ó³×ëŹxå!–â2Œ~=åAâN/¾þ6¥r8 S¬R= …rœSîù&ôV ÚÆÄNFg-ÛéuĵL2uÊßD^HÇÒ!ž¿8¥Û¯¢uÐChm0?ù¡Ý¸o9+‹ÎîŸòÀ71ïX}úPâdâíˆ;Ý{B|‚}_8‡ìù[-úhóÃ;ÿBówTº}ˆ=ÅzERZ`È'#•Òßy%Z÷N³ÿ r™Z¸þSÆü&ít±|z`Eÿ9âW”ôÓP‰Þу†0Ã7¡”ô'•P˜Ø’޼õúý)ci¡íÐÇ,ëÛ´à´@Çf-ûÚ»¶î¶$½¯ê_Q¡­#2& ‚"%S3™X–d[‰äèØš¬wÌä H6EŒH€]¬ÑoÝ—ý ó´[_5)9‰v7A'¶t£»ºªºn]Ýft­Î&?ð4œ æ½—<âyÁ6ýŒÏ þYʤ_×éåáßX40¯ñ,F¾çÚÜbZ>gšIO¸ÈUÎþ`­¯§ñ)Ñõ PC$ñ†ó|‹€+zÅÖ¼là>ÜçN±~Ñ[é®mº+T´ù-W6?¿‚ûÙ0#lÝj¿‘P¨Y‚ÞN“¹µ b±p¨î[G®7Þ¦ÑäE¤‘hn{—ö€—8j—al†¤fǹIÍN{’n½!iiDÖB$-­¸ÕÕÒŠ ­Í–³­·jz²»Àj[g¿!qÇC€§ø1æ8‚˜eûßÑ»÷™z; ãОw´8,ù²Aƒg·ÞÍk19F’õelÖ4ÌÉŽ…±kÓcÎA–î¸÷ˆÉ/…U´þŒBõo¿ÏrçügöðåŽ>pþËi:leç›-œÿm9­­òü×#žÿœ£ºâWx$— »¤^‚x ±>稭²ï6gÙQõŽv:6ZJȈÿŸŽÝ>Â?ˆ-IôçõÛ¿Òq«¬O‡^_û,xšì‹TÙ±¸JÍV G8¿NVÞ8t’ýtèžèE0ë” ¹™²ÃªùÁÉaLÔkÆ´h8ß@¶Ò”/œ€$Rê?‚„“(&Œ€1ÓQ†^È/YYKl _Û8:d¹Æ ï ’,àbÏ•…{ì²ÁÃB¨F}×gñKæ£å‹GÒij†ÜRjuçøxÿíu+èÒéVh ¿4×ȶy0­ ‡Á'¸éÁ¸g—öuÂ+®¾M') \B˜HÂfUãQ©žFæ|Õ€zWµ•ˆ%ñ¦z cÝ¥¾È*j'› ‹ žx^¡vno¬ñA†w€¡¯6-‘CüC—êîI\Þ´’ã¼w‡Îúª*À.¡7¾âûnÂl4›> ‚›sA$0ò"éqñIél–‚ÑÀ3ìÅÃÊÛ¤ñSC‰$Ü_¸¦å½§°»•?g¿[ØÿK·R#Fžéÿö¹z›åɉ™9ùɤÇb„Y¾¼„¢®,ZÊ—·ˆ†nåüøÐÞîV˜ê4F¤ 5ïò™gá!òxòà u:•êŠÑw=fq§Ã›kuÚ´éN¦cÝí*§¹ÑÊéÝÀæWéSö?ªÛ]îSeа¯¶œv Uøã¨¥¾×WlgíZ}þs©* ÇæÁM²Pt ψQZú’ÅwÄ2R. ¨ d>OÙ †–²5©a-‚y6)æž*EøY¦ßwC¦ð)äNœ„~$/óO…7•¾§ý¾6=Wy)òL«¡fÒºadqë 7P¥ˆ§ê§¯+ä{cŠk”ÞiÀ’'8õÕJLÁ ÿ5~L»°°TÉjâÕ]‚6s´¢¤—« (ÃåÖ¨qÿ¹” VDÃó<4‰Ÿ3:e°@§»°ß4éW+zg uÁj+­ƒ„…¨0:”–׹ќi›à¢èU“(µææy]ú­ÌÆÇÃL’ªQ¦p!Èꈗ²K‡; âÀPÌÌÄšx~ÚÕPL7T¡Êƒ|ôsª9>ÒŒƒîe ìJžÁ«ƒGûÛt¡±-åeV<+×÷â+’]2Bìr[ôjº±6ßEŽÿyk#SÏß.¤x:¹_AñÌÖK|=Ö§F|Û,ßx±zcepÅM¸§^§,ÍÖ)„_\Ž9úSq@•¯YAˆ¯3ijT‰tAZ°¬‰`Ü-àâÚ‚†é'¶B}ª/§TùøsÃêüÄd®,e…åëcÆGùïîe†­"à"qµÈee䱦‹À­UÌ˘ÑÇ Œ MùF ´ÁPö&Su¼ˆÖYkE…’­°[¯—èÀÛ­*díÑZåŽÀ«¬qÕ½]΋µB‡·{ËeÁÃ}v®AºÞ{Q”è‹°’‘jÂJÚEìp1K‡È[Û¦Õh X† ùw„ísØ\¥Ô¤åõ% zŸ;œFbŽØ<‹w‘W”™ÃâV?6É5lÏaFf·[í¿EÝhªû;.¹±±Íᓾd]‡Æê°à#=ØV·.¤Yh®ßö2w[~jÎ_ÿc͉«%æÄoQ¿vá-\Pé»À~1"ÕxÞYßh¶6šÍçFe¶Á5Ï€ÕÉ7÷ßhY¼þFÁpÈBók«Iç³ß7ªûJû¸nDu÷“k³¥_§îH'±æú—H¯Ot º[ 7ãj<3©3|Q@‘§QÈ–p“HòzB¾N´O] Ç[˜Ý“Ǧƒ(V#çw’œh2ù¯ÿô0eåñ}0eû"èñ÷¸¥¿(ÖK£8ªÉ lÁ¼J*8æ7úWÈ­>%‰ÂÚ,æÖǹÝeíéþYoìÆqž¦¿¢U„|¢!BŽÜœÜqD°ÃÔy"Ñ‚Ÿ&n?ÀÈCаºùanÌLß±ê)læè3£sFA$sgý3ì ¤ð¥^™“Ú “þ™öët¡½±ñdªÆÄ7÷šy‹±šÛþ5u¦=_€µ2›ñ¬øcÛª³ .¾•v=7¨ guÁüàëõQ0Ñë£Éº=aF·ùýÍÍlŸ¦"áóuÖ¾ë^4ðù¯©+5[v|³›Ÿ·×óQ½Æc#9euó0[ ÿû¿2¿Œüßjßsÿo»‘ßÿé8Í×µv)ÿ¥<ùJüh¤ÔzQ}R[¼Ñ–Ö}çúÔiß¿ùËmÏ=÷ܹMµ|//Têxçä‘Ä<òvÑ11,ÑfçÝ&ÕÉþ‡—o¿©Ì·©àíñ‡Ã¹·c¯N–ô­õGÇÇï¹>žL×ÿŽû9$7ù©Cˆü%}E)ãuZ=5͹ZåÁ’ì¥R‚«pBÖ0÷{Íÿ02óKÙ÷®ÿ–ÓÈïÿuœ äl67Ëõÿbý#òËW?{·‡¼ÒÂhœ —^p,+R\^VecÓzš½ÌÇ–éJçÕÏ‹ý+sÙv¿¢þ°.kaý¿ÛßÙ;Úÿâc<àÿ5[­|ýo5œ-I ÛÜ(×ÿc”,;Ñ4C~Ù7š\3yO"&â|‡—†¬/‚pÑŸ¬’f}˜M]ÖöÖÎáñ› õXã¾ÍªøÖT2¾j6Íòª$#Çd5íFG¿‡Iߤã;ÛÁeÏL¥ñÙ(4üµXîðR# ²˜…&mK¢j‘‰%#-ĉó"8šf$¤á Yhf˜8TÙ-éìuÐÔ€ËüÙ% ’ø[“ „Ö 8ŠÆ$›šÏc¦ ‹~|¥¤f~£6¢ ÖY,9Ô&OÊ+Æ+«5`H½÷&¸Wi3TÁ}9*Èq ƒ€}27Í„›õ)WgñQ/TiP’½7sš§ÇŽ‹ÜÃl¬3œqAW&¤¼²W„féV´ç÷Ç {ò¿àŸŠÈ3aðoEd)2¶öX7^ãQcL<‹B™8kdòQðŒ=“ ${îì*âh¨­erûq" F‘–‹^$L"Hðã±'LP¯—DWù!TicŽŠCàŒyy–’•¥)e5y–4Ʊk’ ælÜ‘vá\çÉLñ\êØìs•n±G€›±-´³éß„!/<ÈÐ;À2ÄVÇEˆÃ >ŽJ¥»*¹šæ÷eŒ$ü!J»./:Ú=ܵx Ã7q§ÏÔèôå4ü7WøYb¨#9l{Ž ÚúÈŽÃåXèX2*ƒa|ÁœÆ+¨•ä#^*WH¸¨¨7ÀêÌ$cNÉSÉôν ‰†ñ¢4QqœÆqL‰é´Ëþ8sÉÁP*°%Ý“©X§ƒµrBP%Ö¸0ÛE½ä”;Åœ)‡À¡K^½ÉTîâ™Xì ¤Î0ñ¿"y¸ÇžùCéÿ#ÜÊÅÔzäøoËieúÓimHü·Õ,õÿc”÷ß½?øáíÊÊ7¸„N€9É2E$tªs¾Uoߟì¢af­¯§•°áwßj¦fj÷¸ð²?U»oŽ~Ø+¾Däãb‰CwKÎñL[©Ãƒ—{ïòo–)Xþ¦)eMç͹:Zý¯Øo¸Û%| •Îh[­<­¦3®‘5¡­v{qÊÅÓªé¬ö_`—ui{¬[è§U3¡…mo©ç‡ϧ¢[ï×$¢QÍQX[x~Ñ?´#¶` 5_ʇ fMFXÖDXƒ»Ÿ6èÏ”wjØcå6)©RÉÛÓŽÕ„(ƒ€ÄO¼š·*+óŸñ©ÙÇ«ödÛ"¬çþù¬âÑÒé'oJV‡þBqT?­¦Ü_³ãÓOµ?¤XÿEú<žÿ×Èý¿ÍFKþý·ÆVÿy”bYÖý² V^…;c¦#9›ÛíÆû´Ô³gÏè' +'£D"IÌ Î¶³±ÝnšóB/^Å PߢgæÇ‹ŠVÍÞáNLÊö²I— Ù{SDÝiWu§iovj׫HAÀÖM/¸üÿt-Û‘rŸíÍõÜë Ïçg¤¦‰å…‡ƒ›Ueq?rÛu05oøÝ3’XÙ> ·Ä¥4òЕŸÝ¡—·ÚŸL‡®öOçÀ·é¥–$¦„}Gö&:<3xîÔ7ü£ˆêFQ‚#úT6ÒŒc۱뢱…õšíÛÁ'Íæ›ïö˜©/XŸ=Ùî‹iyŸô¤{.‡O®íF«=oºA˜½±»ÝNߙ켦iwL ÏêYŠŽn‡lºË.7í™-ÏÛ¯³ðyS /+›ÃüF&ÞiÖÙ|ÖîlÔ¶L]ñHzhðy=‡tÿäPx¦}&‘ßr:uk˱ÍÚu¹¯U§Þ¨]oÜgMœ­ÍÅmÒžßkݬ‰œ$&Œáà—½æøÆV§UËûk¶¸?gÃnºk “¬> V¡Í2¸²ã’wvì¾Ò;9ærRNÛ Received: by greenie.muc.de (/\==/\ Smail3.1.24.1 #24.3) id ; Sat, 21 May 94 23:02 MEST Received: from mail.Germany.EU.net ([192.76.144.65]) by colin.muc.de with SMTP id <135940(1)>; Sat, 21 May 1994 17:57:30 +0200 Received: by mail.Germany.EU.net with SMTP (8.6.5:29/EUnetD-2.4.3.c) via EUnet id RAA20948; Sat, 21 May 1994 17:57:28 +0200 Received: by ruhr.de (/\88/\ Smail3.1.22.1 #22.6) id ; Sat, 21 May 94 17:55 GMT Received: by hphbbs.E.open.DE (Smail3.1.28.1 #6) id m0q4szj-0004s4C; Sat, 21 May 94 17:29 MET DST Message-Id: From: hph@hphbbs.E.open.DE (H.P.Heidinger) Subject: ttyenable/-disable V1.5 To: oklein@smallo.BO.open.de (Olaf Klein), gert@greenie.muc.de (Gert Doering) Date: Sat, 21 May 1994 17:29:46 +0200 Reply-To: hph@hphbbs.E.open.DE Organization: HPHBBS - UseNet City-Router, Essen (Germany) Phone: +49-201-287433 (data+voice) Voice = 3 times 1 ring, wait on 4th call X-Mailer: ELM [version 2.4 PL23] Content-Type: text Content-Length: 10697 Status: RO Hi, Anbei kommt ttyenable/-disable V1.5. Gegenueber V1.2 sind folgende Maengel behoben: - ein Bug, nachdem zB ttyS2 und ttyS20..29 gleich handelt wurden (in Funktion 'isTTY'): alt: gotcha=`find /dev -type c -follow|grep /dev/$token` &&\ neu: gotcha=`find /dev -type c -follow|grep -w /dev/$token` &&\ Hinweis: das "ange'pipe'te" grep ist absolut notwendig, weil "find" leider IMMER einen Exit-Code von 0 (true) ausspuckt, wenn er nicht SELBST aus irgendwelchen Gruenden kaputt geht. Wenn "ls" nicht so eloquent waere, wenn das gesuchte Device NICHT existiert ("No such blafasel ..."), wuerde sich das zeitaufwendige "find|grep" auch ersetzen lassen. Vorschlaege?? - ein Crosscheck gegen die temporaere 'inittab', um mehrfache gettys auf dem selben Device aber unter verschiedenen Labels auszuschliessen (siehe Programmtext, Funktion: 'crosscheck' --------------------------- 8< schnipp ... schnapp 8< -------------------------- #!/bin/sh #set -x ############################################################################### # /etc/ttyenable (link to /etc/ttydisable as well) -- for LINUX # (C)May-1994, H.P. Heidinger, Essen, Germany -- All rights released! # ----------------------------------------------------------------------------- # Rights: -rwx------ 1 root root 0 May 13 14:29 /etc/ttyenable # ----------------------------------------------------------------------------- # Enable/Disable tty channels in the inittab-file; i.e. change the # entry for a given device from :off: to :respawn: and vice-versa. # # Usage: a){ttyenable|ttydisable} [-D] [ -v] [ -h] # b){ttyenable|ttydisable} [-D] [ -v] [ -h] { -d | -l