home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / tpage2 < prev    next >
Encoding:
Text File  |  1992-06-12  |  53.8 KB  |  1,843 lines

  1. Newsgroups: comp.sources.unix
  2. From: Tom_Limoncelli@Warren.MENTORG.COM
  3. Subject: v26i059: tpage2 - tom's utilities for alphanumeric pagers (V2.0)
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: Tom_Limoncelli@Warren.MENTORG.COM
  8. Posting-Number: Volume 26, Issue 59
  9. Archive-Name: tpage2
  10.  
  11. [ I don't have an alphanumeric pager so I couldn't test this.  --vix ]
  12.  
  13. Own an alpha-numeric pager?  This will let your computer speak the protocol
  14. so you can send messages to it.  With the help of a mail filter like
  15. "procmail" (available via ftp from your local comp.sources.unix archive or
  16. from berg@messua.informatik.rwth-aachen.de) you can have messages containing
  17. certain keywords automatically sent to your pager.
  18.  
  19.     Tom_Limoncelli@Warren.MENTORG.COM
  20.  
  21. #! /bin/sh
  22. # This is a shell archive.  Remove anything before this line, then unpack
  23. # it by saving it into a file and typing "sh file".  To overwrite existing
  24. # files, type "sh file -c".  You can also feed this as standard input via
  25. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  26. # will see the following message at the end:
  27. #        "End of shell archive."
  28. # Contents:  README HISTORY INSTALL depend ixocico.c schedule
  29. #   startdaemon table tpage.l tpage.pl tpaged.pl
  30. # Wrapped by vixie@cognition.pa.dec.com on Sat Jun 13 16:43:45 1992
  31. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  32. if test -f 'README' -a "${1}" != "-c" ; then 
  33.   echo shar: Will not clobber existing file \"'README'\"
  34. else
  35. echo shar: Extracting \"'README'\" \(2173 characters\)
  36. sed "s/^X//" >'README' <<'END_OF_FILE'
  37. READDME -- General information about "tpage"
  38. X  by Tom Limoncelli, tal@warren.mentorg.com 
  39. X  Copyright (c) 1992, Tom Limoncelli
  40. X  The sources can be freely copied for non-commercial use only
  41. X  and only if the source is unmodified.
  42. X
  43. X"tpage" or "Tom's Pager System" is a set of programs that let
  44. you send messages to alpha-numeric pagers using the "IXO" protocol.
  45. It supports a dialing directory, a "who's on duty now" schedule,
  46. and can do special tricks with RFC822-format email.
  47. X
  48. The system has the following features:
  49. X
  50. X...sends pages to any pager system that supports the IXO protocol.
  51. X
  52. X...additional protocols can be added. (I'll write the touch-tone
  53. X      protocol soon).
  54. X
  55. X...can parse email messages and extract the interesting info from
  56. X   them resulting in shorter messages.
  57. X
  58. X...can copy it's input to stdout and therefore can be used as a "tee".
  59. X
  60. X...maintains a directory of people's phone numbers/PINs.
  61. X
  62. X...can page "the person on duty" (searches a schedule).
  63. X
  64. X...schedule can have slots that are empty, but find someone anyway if
  65. X   the message is marked "urgent".
  66. X
  67. X...with programs like procmail, permits you to send certain email
  68. X   messages to your pager.
  69. X
  70. X...a list of modems can be given to the daemon.
  71. X
  72. How it works (and how all the programs fit together):
  73. X
  74. o  beep2.pl takes command-line and stdin, reads the schedule, looks
  75. X   up people's paging info in the directory, and queues the message.
  76. o  tpaged.pl should always be running.  Every 30 seconds it wakes up
  77. X   to check the queue for messages.
  78. o  tpaged.pl then sorts and batches the messages.
  79. o  tpaged.pl then calls the appropriate program to do the protocol
  80. X   (currently that's ixocico but others can be written) and watches
  81. X   the output for messages:
  82. X   "#MESOK x" which means that message "x" was successful and can be
  83. X       deleted from the queue.
  84. X   "#MESREJECT x" which means that message "x" was rejected and should
  85. X       be deleted from the queue.  Email will be sent to the person
  86. X       that sent the page.
  87. X
  88. XFor installation instructions, read INSTALL.
  89. XFor program history, read HISTORY.
  90. X
  91. If you aren't using "procmail", you're working too hard.  Check
  92. X"archie" for a location near you!
  93. END_OF_FILE
  94. if test 2173 -ne `wc -c <'README'`; then
  95.     echo shar: \"'README'\" unpacked with wrong size!
  96. fi
  97. # end of 'README'
  98. fi
  99. if test -f 'HISTORY' -a "${1}" != "-c" ; then 
  100.   echo shar: Will not clobber existing file \"'HISTORY'\"
  101. else
  102. echo shar: Extracting \"'HISTORY'\" \(994 characters\)
  103. sed "s/^X//" >'HISTORY' <<'END_OF_FILE'
  104. HISTORY
  105. X  by Tom Limoncelli, tal@warren.mentorg.com 
  106. X  Copyright (c) 1992, Tom Limoncelli 
  107. X  The sources can be freely copied for non-commercial use only
  108. X  and only if the source is unmodified.
  109. X
  110. XFor installation instructions, read INSTALL.
  111. XFor program history, read HISTORY.
  112. XFor general program information, read README. 
  113. X
  114. X
  115. X(( This program is the successor to "fbeep".
  116. X((
  117. X(( fbeep history:
  118. X((
  119. X((    1.0  Oct 29, 1991 -- First working version.
  120. X((
  121. X((    1.1  Oct 30, 1991 -- Debugging levels implemented (-s -v -vv).
  122. X((
  123. X((    1.2  Oct 30, 1991 -- Cleaned the output, error message on failure.
  124. X((
  125. X((    1.3  Nov 20, 1991 -- Added -m, -M and "null person" options.
  126. X((
  127. X((                         Made -a (abort) replace -w (wait).
  128. X((
  129. X((    1.4  Jan  2, 1992 -- Destination can now be a list of people.
  130. X((
  131. X((     (project ended, replaced by tpage, tpaged, and ixocico)
  132. X
  133. X
  134. beep2.pl:
  135. X    1.0 Jan 31, 1992 -- First release.
  136. X
  137. tpaged.pl history:
  138. X    1.0 Jan 31, 1992 -- First release.
  139. X
  140. ixocico.c
  141. X    1.0 Jan 31, 1992 -- First release.
  142. X
  143. END_OF_FILE
  144. if test 994 -ne `wc -c <'HISTORY'`; then
  145.     echo shar: \"'HISTORY'\" unpacked with wrong size!
  146. fi
  147. # end of 'HISTORY'
  148. fi
  149. if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  150.   echo shar: Will not clobber existing file \"'INSTALL'\"
  151. else
  152. echo shar: Extracting \"'INSTALL'\" \(4323 characters\)
  153. sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
  154. INSTALL -- How to install the Tom Page set of programs.
  155. X  by Tom Limoncelli, tal@warren.mentorg.com 
  156. X  Copyright (c) 1992, Tom Limoncelli 
  157. X  The sources can be freely copied for non-commercial use only
  158. X  and only if the source is unmodified.
  159. X
  160. XFor program history, read HISTORY.
  161. XFor general program information, read README. 
  162. X
  163. X
  164. THEORY OF OPERATION: (this assumes you've read README already)
  165. X--------------------
  166. X
  167. tpage.pl (which is often renamed to "beep" or "page") takes a number of
  168. options, figures out who and how to send to a person, figures
  169. out the message, and stuffs the info into a file for the daemon
  170. to read.
  171. X
  172. tpage.pl refers to /home/adm/lib/tpage/table to find out the phone
  173. number and other information that must be given to the daemon.  You
  174. can also specify a different file name with the "-T" option.
  175. X
  176. tpaged.pl wakes up every couple minutes to see if there
  177. is anything new in the queue.  If there is, it takes the information,
  178. dials out to your paging company, and transmits the message.
  179. X
  180. Rather than page a particular person, tpage.pl can be given a schedule
  181. and be told, "page whoever is on duty right now".  This is done
  182. by giving it "-" as the "who" parameter.  The schedule is stored
  183. in /home/adm/lib/tpage/schedule, or by specifying a file name with
  184. the "-S" option.
  185. X
  186. tpage can take the message from the command line, or from stdin.  If
  187. it is coming from stdin, it can parse it as email and do various
  188. things with it (see the man page).
  189. X
  190. X
  191. INSTALLATION:
  192. X-------------
  193. X
  194. X1.  Install the Perl programming language.  The front-end to tpaged
  195. is written in Perl.  Any version should do, but it was developed with
  196. version 4.019.  Hopefully, this program already exists on your system.
  197. If not, I highly recommend that you get it from ftp.uu.net:/pub/gnu
  198. and install it.
  199. X
  200. XFor the rest of this document, $TPAGE will refer to the directory
  201. that you wish to keep the files associated with the tpage system.
  202. X
  203. ALL FILES SHOULD BE COPIED to $TPAGE except tpage (belongs in
  204. X/usr/local/bin/tpage).  The queue directory should be $TPAGE/pqueue but
  205. nothing will break if you put it someplace else.
  206. X
  207. X2.  Edit tpage.pl and copy it to "/usr/local/bin/tpage".  The first
  208. section explains what variables need to be edited and why.  You might
  209. want to call it "page" or "beep" instead.
  210. X
  211. XEdit tpaged.pl and copy it to "$TPAGE/tpage".  The first
  212. section of each file explains what variables need to be edited and why.
  213. X
  214. XEdit tpage.l and copy it to "/usr/local/man/manl" or wherever local
  215. manpages are kept.  The first section of each file explains what
  216. variables need to be edited and why.
  217. X
  218. If you run SunOS you won't have to edit ixocico.c.  If you don't run SunOS
  219. you're going to have the fun of porting this program.  I put in a couple
  220. of #defines to get you started.  Anyway, compile it with a simple
  221. X"make ixocico" and you're done with it.  ixocico doesn't require many
  222. edits because tpaged gives it everything it needs to know.  ixocico
  223. also belongs in $TPAGE/ixocico
  224. X
  225. Copy the sample "table" file and copy it to $DEFAULT_T (which should
  226. be $TPAGE/table if you're smart).  Read it.  Then edit it to your
  227. requirements.
  228. X
  229. Copy the sample "schedule" file and copy it to $DEFAULT_S (which should
  230. be $TPAGE/schedule if you're smart).  Read it.  Then edit it to your
  231. requirements.  You can edit this later or even skip this step if you
  232. don't care about the schedule feature.
  233. X
  234. X3.  Read the man page ("nroff -man tpage.l | more").
  235. X
  236. X4.  Create the $QUEUE_DIR directory (as defined in $TPAGE/tpage.pl and
  237. X$TPAGE/tpaged.pl) and do a chmod 0777 on it.  Make sure that users on any
  238. machine that should be able to run "tpage" can create files there and
  239. delete at least their own files.  If you use NFS you'll have to export
  240. that directory.  If you don't use NFS, you're smart.
  241. X
  242. X5.  Set up a cron job that runs "startdaemon" every 20 minutes on the
  243. machine with the modems.  You might want to run it as root, you might
  244. want to run it as any user that can access those modems.
  245. X
  246. X6.  Read the man page ("nroff -man tpage.l | more").
  247. X
  248. Test it and you're done.  Try:
  249. X
  250. tpage -d 1xxxyyyzzzz -p 123456 "this is a test"
  251. X(substitute your phone number and pin)
  252. X
  253. tpage alias "this is a second test"
  254. X(replace "alias" with a name from the "table" file)
  255. X
  256. tpage - -
  257. this is a test using the schedule and stdin.
  258. X^D
  259. X
  260. X(this should page the "person on duty")
  261. X
  262. X
  263. END_OF_FILE
  264. if test 4323 -ne `wc -c <'INSTALL'`; then
  265.     echo shar: \"'INSTALL'\" unpacked with wrong size!
  266. fi
  267. # end of 'INSTALL'
  268. fi
  269. if test -f 'depend' -a "${1}" != "-c" ; then 
  270.   echo shar: Will not clobber existing file \"'depend'\"
  271. else
  272. echo shar: Extracting \"'depend'\" \(390 characters\)
  273. sed "s/^X//" >'depend' <<'END_OF_FILE'
  274. What routines use on what routines
  275. X----------------------------------
  276. X
  277. safeprint: 
  278. X
  279. checksum: safeprint
  280. X
  281. grabmodem:
  282. X
  283. send: safeprint
  284. X
  285. match: safeprint
  286. X
  287. hangup_modem: send
  288. X
  289. unlockmodem:
  290. X
  291. bail_out: hangup_modem unlockmodem
  292. X
  293. lockmodem: bail_out
  294. X
  295. getline: bailout safe_print
  296. X
  297. getpacket: bail_out safeprint
  298. X
  299. main: lockmodem grabmodem bail_out send match hangup_modem getpacket getline checksum
  300. X
  301. END_OF_FILE
  302. if test 390 -ne `wc -c <'depend'`; then
  303.     echo shar: \"'depend'\" unpacked with wrong size!
  304. fi
  305. # end of 'depend'
  306. fi
  307. if test -f 'ixocico.c' -a "${1}" != "-c" ; then 
  308.   echo shar: Will not clobber existing file \"'ixocico.c'\"
  309. else
  310. echo shar: Extracting \"'ixocico.c'\" \(12182 characters\)
  311. sed "s/^X//" >'ixocico.c' <<'END_OF_FILE'
  312. X/* ixocico -- IXO protocol call-in call-out.
  313. X**   by Tom Limoncelli, tal@warren.mentorg.com
  314. X**   Copyright (c) 1992, Tom Limoncelli
  315. X**   The sources can be freely copied for non-commercial use only
  316. X**   and only if they are unmodified.
  317. X**
  318. X** Version 1.0 -- See file HISTORY for details.
  319. X*/
  320. X
  321. X/****************************************************************/
  322. X/* USER CONFIGURABLE OPTIONS: */
  323. X
  324. X/* this should be "#define" if you use SunOS, or "#undef" if you
  325. X** use HPUX.  This controls the name of LOCKDIR and if getpriority()
  326. X** is used.  I'm sure more needs to be done, but that's a start.
  327. X*/
  328. X#define REAL_OS
  329. X
  330. X#ifdef REAL_OS
  331. X#define LOCKDIR    "/var/spool/uucp"
  332. X#else
  333. X#define LOCKDIR "/usr/spool/locks"
  334. X/* That may not be correct */
  335. X#endif
  336. X
  337. X/* not talking to the modem correctly?  Try mucking with
  338. the grabmodem() routine.  */
  339. X
  340. X/* END OF USER CONFIGURABLE OPTIONS */
  341. X/****************************************************************/
  342. X
  343. X#include <stdio.h>
  344. X#include <fcntl.h>
  345. X#include <string.h>
  346. X/* #include <strings.h> */
  347. X#include <ctype.h>
  348. X#include <errno.h>
  349. X#include <sys/termios.h>
  350. X
  351. X#ifdef REAL_OS
  352. X#include <sys/time.h>        /* required for <sys/resource.h> */
  353. X#include <sys/resource.h>    /* required for getpriority() */
  354. X#endif
  355. X
  356. X/* ASCII constants */
  357. X#define STX (2)
  358. X#define EOT (4)
  359. X#define ACK (6)
  360. X#define LF (10)
  361. X#define CR (13)
  362. X#define NAK (21)
  363. X#define ESC (27)
  364. X#define RS (30)
  365. X
  366. X#define MAX_PACKET    (10000)    /* we'll never get a packet this big */
  367. X#define MAXLINE    (1000)
  368. X
  369. X/* only two little global variables, how's that? */
  370. X
  371. int modem = 0;
  372. char *lockname = NULL;
  373. X
  374. X/* print a string without worrying about unprintable charactors */
  375. void 
  376. safeprint(str)
  377. char           *str;
  378. X{
  379. X    while (*str) {
  380. X        if (isgraph(*str))
  381. X            (void) fprintf(stdout, "%c", *str);
  382. X        else {
  383. X            switch (*str) {
  384. X            case LF:
  385. X                (void) fprintf(stdout, "\\n");
  386. X                break;
  387. X            case CR:
  388. X                (void) fprintf(stdout, "\\r");
  389. X                break;
  390. X            case 32:
  391. X                (void) fprintf(stdout, "\\s");
  392. X                break;
  393. X            default:
  394. X                (void) fprintf(stdout, "\\%d", *str);
  395. X                break;
  396. X            }
  397. X        }
  398. X        str++;
  399. X    }
  400. X    fflush(stdout);
  401. X}
  402. X
  403. X/* calculate checksum of a packet */
  404. char *checksum(pk)
  405. char *pk;
  406. X{
  407. X    static char check[10];
  408. X    int sum = 0;
  409. X
  410. X    for (;*pk; pk++) sum += *pk;
  411. X    check[2] = '0' + (sum & 15); sum = sum >> 4;
  412. X    check[1] = '0' + (sum & 15); sum = sum >> 4;
  413. X    check[0] = '0' + (sum & 15);
  414. X    check[3] = 0;
  415. X
  416. printf("CHECKSUM=:"); safeprint(check); printf(":\n");
  417. X    return check;
  418. X}
  419. X
  420. X/* open the modem.  You should have done a lockmodem() first */
  421. int grabmodem(dev)
  422. char           *dev;
  423. X{
  424. X    struct termios  ti;
  425. X    int             modem;
  426. X
  427. X    errno = 0;
  428. X    modem = open(dev, O_RDWR, 0);
  429. X    if (errno) {
  430. X        printf("#MODOPEN modem can't be opened\n");
  431. X        return 0;
  432. X    }
  433. X
  434. X    /* set tty params to 300bps, even parity, 7-1-e */
  435. X    errno = 0;
  436. X    ioctl(modem, TCGETS, &ti);
  437. X    if (errno) {
  438. X        close(modem);
  439. X        return 0;
  440. X    }
  441. X    ti.c_iflag |= IGNBRK;   /* ignore breaks */
  442. X    /* ti.c_iflag |= IGNPAR; *//* ignore parity */
  443. X    ti.c_iflag &= ~INPCK;   /* ignore parity errors */
  444. X    ti.c_iflag |= ISTRIP;   /* strip 8th bit */
  445. X    ti.c_iflag &= ~INLCR;   /* don't cr->nl */
  446. X    ti.c_iflag &= ~ICRNL;   /* don't cr->nl */
  447. X    ti.c_iflag &= ~IGNCR;   /* don't ignore cr */
  448. X    /* ti.c_iflag &= ~IXON; *//* don't do xon */
  449. X    /* ti.c_iflag &= ~IXOFF; *//* don't do xoff */
  450. X
  451. X    ti.c_oflag &= ~OPOST;   /* don't post-process */
  452. X
  453. X    ti.c_cflag &= ~CBAUD;   /* baud=300 */
  454. X    ti.c_cflag |= B300;
  455. X    ti.c_cflag &= ~CSIZE;   /* 8-bit bytes */
  456. X    ti.c_cflag |= CS8;
  457. X    ti.c_cflag &= ~CSTOPB;  /* one stop bit */
  458. X    ti.c_cflag &= ~PARENB;  /* parity */
  459. X    ti.c_cflag &= ~PARODD;  /* even parity */
  460. X    ti.c_cflag |= HUPCL;    /* hang up on last close */
  461. X    /* ti.c_cflag |= CRTSCTS; *//* hardware handshaking */
  462. X    ti.c_cc[VMIN] = 0;  /* read() can get as few as 0 bytes */
  463. X    ti.c_cc[VTIME] = 50;    /* time out at 5 seconds no matter what */
  464. X
  465. X    ti.c_lflag &= ~ISIG;    /* disable signals */
  466. X    ti.c_lflag &= ~ICANON;  /* disable signals */
  467. X    ti.c_lflag &= ~ECHO;    /* don't echo */
  468. X
  469. X    errno = 0;
  470. X    ioctl(modem, TCSETS, &ti);
  471. X    if (errno) {
  472. X        close(modem);
  473. X        return 0;
  474. X    }
  475. X    return modem;
  476. X}
  477. X
  478. X/* send data to the modem */
  479. void send(fd, str)
  480. int             fd;
  481. char           *str;
  482. X{
  483. X    printf("Sending: :"); safeprint(str); printf(":\n", str);
  484. X    write(fd, str, strlen(str));
  485. X}
  486. X
  487. X/* wait for a particular string from the modem (err = # of times to re-try) */
  488. int match(mod, str, err) 
  489. X    int mod;
  490. X    char *str;
  491. X    int err;
  492. X{
  493. X    int len;
  494. X    char c;
  495. X
  496. printf("MATCHING on :"); safeprint(str); printf(":\n", str);
  497. X
  498. X    while (1) {
  499. X        c = 0;
  500. X/* printf("waiting for :%c:\n", *str); */
  501. X        len = read(mod, &c, 1);
  502. X        if (len) {
  503. X/* printf("got=%d:%c\n", c,c); */
  504. X            if (c == *str) str++;
  505. X            if (!(*str)) break; /* matched all?  Exit loop */
  506. X        }
  507. X        if (!err--) {
  508. X            printf("NOT MATCHED\n");
  509. X            return 1;
  510. X        }
  511. X    }
  512. printf("MATCHED\n");
  513. X    return 0;
  514. X}
  515. X
  516. X/* hang up the modem */
  517. void 
  518. hangup_modem(fd)
  519. int             fd;
  520. X{
  521. X    sleep(3);
  522. X    send(fd, "+++");
  523. X    sleep(3);
  524. X    send(fd, "ATH\r");
  525. X    sleep(1);
  526. X}
  527. X
  528. X/* unlock the modem */
  529. void unlockmodem(name)
  530. char           *name;
  531. X{
  532. X    printf("Unlocking modem.\n");
  533. X    (void)unlink(name);
  534. X    return;
  535. X}
  536. X
  537. X/* clean up and leave this program */
  538. void bail_out()
  539. X{
  540. X    if (modem) {
  541. X        hangup_modem(modem);
  542. X        close(modem);
  543. X    }
  544. X    if (lockname) unlockmodem(lockname);
  545. X    exit(0);
  546. X}
  547. X
  548. X/* lock the modem OR DIE*/
  549. char *lockmodem(dev)
  550. char           *dev;
  551. X{
  552. X    int lock, pid;
  553. X    int failcnt = 3;
  554. X    char waitcnt = 0;
  555. X    char *lkn, lname[200];
  556. X
  557. X    strcpy(lname, LOCKDIR);
  558. X    strcat(lname, "/LCK..");
  559. X    strcat(lname, 1 + rindex(dev, '/'));
  560. X
  561. printf("Lockfile = %s\n", lname);
  562. X    lkn = strdup(lname);
  563. X    while (failcnt--) {
  564. X        errno = 0;
  565. X        lock = open(lname, O_CREAT | O_WRONLY | O_EXCL, 0777);
  566. X        if (lock == -1) {
  567. X#ifdef REAL_OS
  568. X            printf("Modem is locked, attempting to steal.\n");
  569. X            /* locked, let's read the cookie in the lock */
  570. X            pid = 0;
  571. X            if ((lock = open(lname, O_RDONLY)) != -1) {
  572. X                (void)read(lock, &pid, sizeof(int) );
  573. X                printf("Device is locked by process %d\n", pid);
  574. X                close(lock);
  575. X            }
  576. X            printf("Lock = %d\n", lock);
  577. X            if (pid < 3) {
  578. X                printf("#MODOPEN device is locked by pid < 3\n");
  579. X                bail_out();
  580. X            }
  581. X            /* see if the process still is alive */
  582. X            errno = 0;
  583. X            (void) getpriority(PRIO_PROCESS, pid);
  584. X            if (errno == ESRCH) {   /* lock process dead, let's go! */
  585. X                if (unlink(lname)) {
  586. X                    printf("#MODOPEN Can't steal lock.\n");
  587. X                    bail_out();
  588. X                } else {
  589. X                    printf("Lock is stale, stealing!\n");
  590. X                }
  591. X            } else {
  592. X                printf("#MODOPEN Valid lock in the way.\n");
  593. X                bail_out();
  594. X            }
  595. X#else
  596. X            printf("#MODOPEN it's locked, I'm out of here!\n");
  597. X            bail_out();
  598. X#endif
  599. X        } else {
  600. X            /* lock opened, stuff and go */
  601. X            pid = getpid();
  602. X            write(lock, &pid, sizeof(int));
  603. X            close(lock);
  604. X            break;
  605. X        }
  606. X    }
  607. X    if (failcnt==-1) {
  608. X        printf("#MODOPEN Couldn't lock modem after many tries.\n");
  609. X        bail_out();
  610. X    }
  611. X    return lkn;
  612. X}
  613. X
  614. X/* get a line from stdin OR DIE */
  615. char *getline(line)
  616. char *line;
  617. X{
  618. X    int len;
  619. X    char *r;
  620. X
  621. X    /* get a line, if EOF return 0 */
  622. X    if (!(r = fgets(line, MAXLINE, stdin))) return 0;
  623. X
  624. X    printf("Data in queue=:"); safeprint(line); printf(":\n", line);
  625. X
  626. X    if (!(len = strlen(line))) {
  627. X        printf("#BADQUEUE Blank line in queued data\n");
  628. X        bail_out();
  629. X    }
  630. X
  631. X    if (line[len-1] == '\n') {
  632. X        line[len-1] = 0;
  633. X    } else {
  634. X        /* if fgets didn't return a string ending in \n */
  635. X        printf("#BADQUEUE Data in queue has line too long\n");
  636. X        bail_out();
  637. X    }
  638. X    return r;
  639. X}
  640. X
  641. X/* Loop until you get a valid packet.  If you get a "message sequence" then
  642. display it.  If you get an invalid pack DIE */
  643. X
  644. void getpacket(fd, str)
  645. int fd;
  646. char *str;
  647. X{
  648. X    int max;
  649. X    char c;
  650. X    int len;
  651. X    char *buf = str;
  652. X    int err;
  653. X
  654. X    *str = 0;
  655. X    err=50;    /* permit up to 500 message sequences or bad packets */
  656. X    while (err--) {
  657. X        printf("Getting packet\n");
  658. X        max = MAX_PACKET;
  659. X        while (read(fd, &c, 1) == 1) {
  660. X            if (c == LF) continue;    /* skip LF's */
  661. X            if (c == CR) {
  662. X                /* don't actually put CR in the string */
  663. X                break;
  664. X            }
  665. X            *buf++ = c;
  666. X            max--;
  667. X            if (!max) {
  668. X                /* packet was too long */
  669. X                printf("#PACKLEN packet was too long\n");
  670. X                bail_out();
  671. X            }
  672. X        }
  673. X        *buf = 0;
  674. X        len =  buf - str;
  675. X        if (len) {
  676. X            printf("Got packet--length=%d\n", len);
  677. X            if (isgraph(*str)) {
  678. X                printf("#GOTMESSEQ message sequece=:");
  679. X                safeprint(str);
  680. X                printf(":\n");
  681. X            } else {
  682. X                /* print packet contents */
  683. X                printf("packet is data=:"); safeprint(str); printf(":013:\n");
  684. X                return;
  685. X            }
  686. X        }
  687. X    }
  688. X    printf("#LONELY It's too quiet in here.  Disconnecting.\n");
  689. X    bail_out();
  690. X}
  691. X
  692. int main(argc, argv)
  693. int argc;
  694. char *argv[];
  695. X{
  696. X    char dialstring[MAX_PACKET];
  697. X    char *pack = dialstring;    /* use same workspace */
  698. X    char line[MAXLINE+1];
  699. X    char pin[MAXLINE+1];
  700. X    char mesg[MAXLINE+1];
  701. X    int mesnum, failcnt, len;
  702. X    char c;
  703. X
  704. X    /* check arguments */
  705. X    if (argc != 3) {
  706. X        printf("#WRONGARGS wrong number of arguments\n");
  707. X        bail_out();
  708. X    }
  709. X
  710. X    /* lock modem or die */
  711. X    lockname = lockmodem( argv[1] );
  712. X    /* open modem or die */
  713. X    printf("opening modem\n");
  714. X    modem = grabmodem( argv[1] );
  715. X    if (!modem) bail_out();
  716. X
  717. X    /* see if modem is awake or hangup; after 3 tries die */
  718. X    failcnt = 3;
  719. X    while (failcnt--) {
  720. X        send(modem, "AT\r");
  721. X        if (match(modem, "OK", 9)) {
  722. X            printf("No response.  Hang up and try again.\n");
  723. X            hangup_modem(modem);
  724. X            while (read(modem, &c, 1)) { /*DONOTHING*/ };
  725. X        } else break;
  726. X    }
  727. X    if (failcnt==-1) bail_out();
  728. X
  729. printf("dialing\n");
  730. X
  731. X    /* send the "A" of "ATDT" */
  732. X    do {
  733. X        send(modem, "A");
  734. X    } while (match(modem, "A", 2));
  735. X    /* send the rest of the dial string */
  736. X    sprintf( dialstring, "TDT%s\r", argv[2] );
  737. X    send(modem, dialstring);
  738. X    (void) match(modem, argv[2], 10);
  739. X
  740. X    /* wait for the modem to connect */
  741. X    printf("waiting for CONNECT\n");
  742. X    if (match(modem, "CONNECT", 400)) {
  743. X        printf("#NOCONN no connect\n");
  744. X        bail_out();
  745. X    }
  746. X
  747. printf("Waiting for ID=\n");
  748. X
  749. X    /* send a CR ever second until "ID=" comes back */
  750. X    while (1) {
  751. X        if (match(modem, "ID=", 100)) send(modem, "\r");
  752. X        else break;
  753. X    }
  754. X
  755. printf("Logging in\n");
  756. X
  757. X    failcnt = 3;
  758. X    while (failcnt--) {
  759. X        /* switch to "automatic protocol" */
  760. X        printf("Sending ESC\n");
  761. X        write(modem, "\033", 1);
  762. X        send(modem, "PG1000000\r");
  763. X
  764. X    printf("Waiting for acceptance (aren't we all)\n");
  765. X        getpacket(modem, pack);
  766. X        len = strlen(pack);
  767. X        if ((len==1) && (*pack == ACK)) {
  768. X            printf("login successful\n");
  769. X            break;
  770. X        }
  771. X        if ((len==1) && (*pack == NAK)) {
  772. X            printf("retrying to log in.\n");
  773. X            continue;
  774. X        }
  775. X        if ((len==2) && (*pack == ESC) && (pack[1] == EOT)) {
  776. X            printf("forced disconnect\n");
  777. X            bail_out();
  778. X        }
  779. X        printf("#UNKNOWNPROTO not the response we're looking for.  Disconnecting.\n");
  780. X        bail_out();
  781. X    }
  782. X    if (failcnt==-1) bail_out();
  783. X
  784. printf("waiting for message go ahead\n");
  785. X    failcnt=40;
  786. X    while (failcnt--) {
  787. X        getpacket(modem, pack);
  788. X        if (!strcmp(pack, "\033[p")) break;
  789. X    }
  790. X    if (failcnt==-1) bail_out();
  791. X    printf("got message go-ahead\n");
  792. X
  793. X    for (mesnum=0; getline(pin); ) {
  794. X        getline(mesg);
  795. X        failcnt=100;
  796. X        while (failcnt--) {
  797. X            /* build the packet to be sent */
  798. X            pack[0] = STX;
  799. X            pack[1] = 0;
  800. X            strcat(pack, pin);
  801. X            strcat(pack, "\r");
  802. X            strcat(pack, mesg);
  803. X            strcat(pack, "\r\3");    /* CR then ETX */
  804. X            strcat(pack, checksum(pack));
  805. X            strcat(pack, "\r");
  806. X            send(modem, pack);
  807. X    
  808. X            /* wait for response and deal */
  809. X            printf("waiting for validation\n");
  810. X            getpacket(modem, pack);
  811. X            len = strlen(pack);
  812. X            if ((len==1)&&(*pack==ACK)) {
  813. X                printf("#MESOK %d message xmitted fine\n", mesnum++);
  814. X                break;
  815. X            } else if ((len==1)&&(*pack==NAK)) {
  816. X                printf("re-retrying message %d\n", mesnum);
  817. X            } else if ((len==1)&&(*pack==RS)) {
  818. X                printf("#MESREJECT %d message rejected\n", mesnum++);
  819. X                break;
  820. X            } else if ((len==2)&&(*pack==ESC)&&(*pack==EOT)) {
  821. X                printf("#FORDIS forced disconnect\n");
  822. X                bail_out();
  823. X            }
  824. X        }
  825. X        if (failcnt==-1) {
  826. X            printf("#PROTERR couldn't send packets\n");
  827. X            bail_out();
  828. X        }
  829. X    }
  830. X    printf("#DONE we're done.  Logging out.\n");
  831. X    send(modem, "\4\r");    /* EOT then CR */
  832. X
  833. X    failcnt=3;
  834. X    while (failcnt--) {
  835. X        printf("waiting for system logout\n");
  836. X        getpacket(modem, pack);
  837. X        len=strlen(pack);
  838. X        if ((len==2) && (pack[0] == ESC) && (pack[1] == EOT)) {
  839. X            printf("#BYE asked to hangup\n");
  840. X            bail_out();
  841. X        }
  842. X        if ((len==1)&&(*pack==RS)) {
  843. X            printf("#WRONGANY something went wrong. (useless msg)\n");
  844. X            bail_out();
  845. X        }
  846. X/*        if (!stricmp(line, "NO CARRIER")) break; */
  847. X    }
  848. X    printf("#BYE we're leaving.\n");
  849. X    bail_out();
  850. X}
  851. X
  852. X
  853. END_OF_FILE
  854. if test 12182 -ne `wc -c <'ixocico.c'`; then
  855.     echo shar: \"'ixocico.c'\" unpacked with wrong size!
  856. fi
  857. # end of 'ixocico.c'
  858. fi
  859. if test -f 'schedule' -a "${1}" != "-c" ; then 
  860.   echo shar: Will not clobber existing file \"'schedule'\"
  861. else
  862. echo shar: Extracting \"'schedule'\" \(2140 characters\)
  863. sed "s/^X//" >'schedule' <<'END_OF_FILE'
  864. X# beepersched -- the schedule of who's on-call at what times.
  865. X# [For use with tpage.pl -- By Tom Limoncelli (tal@warren.mentorg.com)]
  866. X#
  867. X# This file is only used if "who" is "-"
  868. X#
  869. X# The lines that begin with 0-6 refer to the days Sun-Sat.  The 48
  870. X# bytes after refer to who's on duty each half-hour.
  871. X#
  872. X# This schedule shows tal, ingo, and greg as
  873. X# having different hours.  On Monday night, all three are paged.
  874. X# 
  875. X# A "-" in this list (not to be confused with "-" on the command
  876. X# line) means "no body is on duty".  If the "-U" (urgent) is used,
  877. X# beep2.pl keeps looking for another schedule to see if maybe it
  878. X# can find someone else scheduled for that time.  The way I manage
  879. X# things is to have lower-case letters mean individual people and
  880. X# capitol letters meaning the fall-back "urgent" people (usually a list
  881. X# of the person and their fallback).  For example, "g" is for greg,
  882. X# and "G" is for greg and the person that backs him up.
  883. X# Of course, you can use any system you wish.
  884. X#
  885. X#                        N
  886. X#                        O
  887. X#                    1 1 O                   1 1
  888. X#0 1 2 3 4 5 6 7 8 9 0 1 N 1 2 3 4 5 6 7 8 9 0 1
  889. X0--------------------ttttttttttttttttAAAAAAAAAAAA
  890. X1------------ttttgggttttttggggiiiiiiitt----------
  891. X2------------ttttgggttttttggggiiiiiiitttttttttttt
  892. X3------------ttttgggttttttggggiiiiiiitt----------
  893. X4------------ttttgggttttttggggiiiiiiitttttttttttt
  894. X5------------ttttgggttttttggggiiiiiiitt----------
  895. X6-------------------tttttttttttttttttttttttttt---
  896. X#
  897. X# these will only be accessed if -U is used.
  898. X# A "-" in this list means "don't call anyone"
  899. X#
  900. X#                    1 1 O                   1 1
  901. X#0 1 2 3 4 5 6 7 8 9 0 1 N 1 2 3 4 5 6 7 8 9 0 1
  902. X0TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
  903. X1TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
  904. X2TTTTTTTTTTTTTTTTTTT--------------TTTTT----------
  905. X3TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
  906. X4TTTTTTTTTTTTTTTTTTT--------------TTTTT----------
  907. X5TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
  908. X6TTTTTTTTTTTTTTTTTTT--------------TTTTTTTTTTTTTTT
  909. X#
  910. X#
  911. g=greg
  912. i=ingo
  913. t=tal
  914. X#
  915. X# a person and their backup
  916. G=greg,tal
  917. I=ingo,greg
  918. T=tal,greg
  919. X#
  920. A=greg,tal,ingo
  921. END_OF_FILE
  922. if test 2140 -ne `wc -c <'schedule'`; then
  923.     echo shar: \"'schedule'\" unpacked with wrong size!
  924. fi
  925. # end of 'schedule'
  926. fi
  927. if test -f 'startdaemon' -a "${1}" != "-c" ; then 
  928.   echo shar: Will not clobber existing file \"'startdaemon'\"
  929. else
  930. echo shar: Extracting \"'startdaemon'\" \(595 characters\)
  931. sed "s/^X//" >'startdaemon' <<'END_OF_FILE'
  932. X#! /usr/local/bin/perl4.019
  933. X
  934. X# "start daemon" -- Start the tpaged daemon if it isn't running.
  935. X#   by Tom Limoncelli, tal@warren.mentorg.com
  936. X#   Copyright (c) 1992, Tom Limoncelli
  937. X
  938. X
  939. X$BSD = -f '/vmunix';
  940. X$pscmd = $BSD ? "ps -auxww" : "ps -ef";
  941. X
  942. open(PS, "$pscmd|") || die "Can't run ps: !$";
  943. X$title = <PS>;
  944. X$found = 0;
  945. while (<PS>) {
  946. X    chop;
  947. X    $found = 1 if /tpaged/;
  948. X}
  949. X
  950. if (!$found) {
  951. X    unless (fork) {    #    this is the child
  952. X        unless (fork) {    #    this is the child's child
  953. X            sleep 1 until getppid == 1;
  954. X            system "/home/adm/lib/tpage/tpaged &";
  955. X            exit 0;
  956. X        }
  957. X        exit 0;
  958. X    }
  959. X    print "Started tpaged\n";
  960. X}
  961. END_OF_FILE
  962. if test 595 -ne `wc -c <'startdaemon'`; then
  963.     echo shar: \"'startdaemon'\" unpacked with wrong size!
  964. fi
  965. chmod +x 'startdaemon'
  966. # end of 'startdaemon'
  967. fi
  968. if test -f 'table' -a "${1}" != "-c" ; then 
  969.   echo shar: Will not clobber existing file \"'table'\"
  970. else
  971. echo shar: Extracting \"'table'\" \(623 characters\)
  972. sed "s/^X//" >'table' <<'END_OF_FILE'
  973. X# beepertab -- table of information about people's beepers.
  974. X# [ For use with tpage.pl by Tom Limoncelli (tal@warren.mentorg.com)]
  975. X#
  976. X# Comment lines begin with "#".
  977. X#
  978. X# The columns are name, numeric pager phone # (currently unused), IXO
  979. X# protocol number to dial, and the person's pagerid.
  980. X#
  981. X# Aliases are implemented by repeating data.  (ooo, fancy!)
  982. X#
  983. greg     5551212    18006789012     1234567
  984. gregt    5551212    18006789012     1234567
  985. X#
  986. ingo     5551213    18006789012     7654321
  987. idean    5551213    18006789012     7654321
  988. X#
  989. tom      5551214    18006789012     1122334 
  990. tal      5551214    18006789012     1122334 
  991. END_OF_FILE
  992. if test 623 -ne `wc -c <'table'`; then
  993.     echo shar: \"'table'\" unpacked with wrong size!
  994. fi
  995. # end of 'table'
  996. fi
  997. if test -f 'tpage.l' -a "${1}" != "-c" ; then 
  998.   echo shar: Will not clobber existing file \"'tpage.l'\"
  999. else
  1000. echo shar: Extracting \"'tpage.l'\" \(6781 characters\)
  1001. sed "s/^X//" >'tpage.l' <<'END_OF_FILE'
  1002. X.ds l local
  1003. X.TH TPAGE N "30 Jan 1992"
  1004. X.BY "Tom Limoncelli, tal@warren.mentorg.com"
  1005. X.SH NAME
  1006. tpage \- front-end to Tom's Pager System
  1007. X.br
  1008. tpaged \- daemon that manages paging queue
  1009. X.br
  1010. ixocico \- program that executes the IXO protocol
  1011. X.SH SYNOPSIS
  1012. X.B /usr/local/bin/tpage
  1013. X[
  1014. X.B \-T
  1015. table file
  1016. X] [
  1017. X.B \-S
  1018. schedule file
  1019. X] [
  1020. X.B \-U
  1021. X] [
  1022. X.B \-d
  1023. phone num
  1024. X] [
  1025. X.B \-p
  1026. pin
  1027. X] [
  1028. X.B \-t
  1029. X] [
  1030. X.B \-v
  1031. X] [
  1032. X.B \-m
  1033. X] [
  1034. X.B \-M
  1035. X] [
  1036. X.B \-e
  1037. X]
  1038. X.B who
  1039. X[
  1040. X.B message
  1041. or
  1042. X.B \-
  1043. X]
  1044. X.br
  1045. X.B /home/adm/lib/tpage/tpaged
  1046. X.br
  1047. X.B /home/adm/lib/tpage/ixocico
  1048. dev phonenum
  1049. X.br
  1050. X.SH DESCRIPTION
  1051. X.I tpage
  1052. is the front-end to the system.  A user can run this program to
  1053. submit a message to someone's pager.
  1054. X.PP
  1055. The program wants 4
  1056. things:  (1) the phone number to dial, (2) the person's PIN
  1057. pin (Personal Identification Number), (3) who to email if the
  1058. page isn't accepted, and (4) the message.
  1059. X.PP
  1060. Once it has all that information, it dumps it into a file
  1061. which is read by 
  1062. X.B tpaged
  1063. which delivers the message to the paging service using
  1064. the appropriate protocol.  tpaged selects the correct
  1065. program for you.  Each protocol is implemented as
  1066. a separate program.  Currently \fBixocico\fR
  1067. is the only program to choose from, and it implements 
  1068. the IXO protocol.
  1069. X.PP
  1070. The phone 
  1071. number (1) and PIN (2) can be specified with the 
  1072. X.B \-d
  1073. and
  1074. X.B \-p
  1075. options, OR by specifying a name (which instructs tpage
  1076. to look up the information in the pager table file), OR by 
  1077. specifying the name ``\-'' which
  1078. means ``whoever is on duty'' (which instructs tpage to find
  1079. out who is on duty from the schedule file, and then look up
  1080. their phone number and PIN in the pager table file).
  1081. X.PP
  1082. Specifying a phone number without a PIN (or vice-versa) results
  1083. in the missing data being looked up in the pager table file.
  1084. X.PP
  1085. A comma-separated list of names may be given.  It is much more
  1086. efficient to use a list of names than to do single pages.
  1087. X.PP
  1088. NOTE: A name must always be specified, so if you use the
  1089. X.B \-d
  1090. and
  1091. X.B \-p
  1092. options you must also specify a name (such as ``foo'') which will
  1093. be ignored.  Combining a list of names with the
  1094. X.B \-d
  1095. and/or
  1096. X.B \-p
  1097. options works in a logical but undefined manner.
  1098. X.PP
  1099. To specify who to email if there is a problem (3) use the
  1100. X.B \-e
  1101. option.  The default for this is to not send email to anyone.
  1102. X.PP
  1103. The message (4) can be specified on the command line or if ``-'' is
  1104. given, stdin is read for the message.  No matter how many
  1105. bytes you give it, the high-bit is stripped, RETURNs and TABs are
  1106. turned into spaces, and groups of spaces are turned into single
  1107. spaces.  The first 160 bytes (configurable in the program) is
  1108. all that's sent, since that's all that the pager will display.
  1109. X.PP
  1110. Command-line options are:
  1111. X.TP 10
  1112. X.BR \-T " table file"
  1113. X\fItable file\fR is the file that has the
  1114. table of people and the info needed to communicate
  1115. with their pager.  The default is /home/adm/lib/tpage/table.
  1116. X.TP
  1117. X.BR \-S " schedule file"
  1118. X\fIschedule file\fR is the file that has the
  1119. is the file that is used
  1120. to find out who's on duty at this moment.  This file is only
  1121. consulted if ``who'' is ``\-''.  The default is
  1122. X/home/adm/lib/tpage/schedule.
  1123. X.TP
  1124. X.B \-U
  1125. This option marks the message as \fIurgent\fR.  If the schedule
  1126. lists that no one is on duty at that time but the message is
  1127. marked \fIurgent\fR, a secondary schedule is consulted.
  1128. X.TP
  1129. X.BR \-d " phone num"
  1130. Ignore what the table file says, use this phone number when
  1131. dialing.  If a list of people is specified, this phone number
  1132. is used for the first person, the others will be looked
  1133. up in the \-T file.
  1134. X.TP
  1135. X.BR \-p " pin"
  1136. Ignore what the table file says, use this PIN when transmitting
  1137. the message.
  1138. If a list of people is specified, this phone number
  1139. is used for the first person, the others will be looked
  1140. up in the \-T file.
  1141. X.TP
  1142. X.B \-t
  1143. Act as a ``tee''.  Copy stdin to stdout.  If you give this
  1144. option and the message is not coming from 
  1145. X.TP
  1146. X.B \-v
  1147. Verbose mode.  Currently useless since there isn't anything
  1148. extra worth printing.
  1149. X.TP
  1150. X.B \-m
  1151. Parse the input as mail.  Skip all the headers but extract the ``From'',
  1152. X``Subject'', and ``Priority'' lines.  If they exist, append to the
  1153. beginning of the message ``F: frominfo'', ``S: subject line'',
  1154. X``P: priority''.  ``F:'' and ``P:'' are clipped to be one screenful
  1155. in length.  They are all padded out to the end of the screen.
  1156. X.TP
  1157. X.B \-M
  1158. Skip ``mail quoted'' lines.  Netnews and Mail often have other messages
  1159. quoted by prefixing each line with greater than symbol.  This option
  1160. skips any input line that begins with zero or more whitespace charactors,
  1161. followed by zero or more letters or numbers, followed by zero or more
  1162. of \<, \>, {, or }.  This should catch the normal quoting methods
  1163. as well as anything the perverse superquote.el package 
  1164. for GNU Emacs
  1165. might come up with.
  1166. X.TP
  1167. X.B \-e
  1168. On error, send email to this person.  If any errors happen when
  1169. the tpage command is beign run, the user is notified.  This
  1170. is for sending email when the page is being processed.  In
  1171. other words, if the PIN is incorrect.  If the phone number is
  1172. incorrect the tpaged daemon will keep redialing and redialing it
  1173. trying to figure out why it can't get through.
  1174. X.PP
  1175. X.IR tpaged
  1176. tpage is a program that you don't need to know about.  Your
  1177. sysadmin should have installed it for you.  It wakes up about
  1178. every 20 seconds, sees if there are any new messages to send
  1179. out and tries to send them.  It can understand multiple paging
  1180. protocols (tpage picks the best one for you) though it
  1181. currently only knows about the IXO protocol.  tpage can run
  1182. as ``root'' but is often just run as ``daemon''.
  1183. X.PP
  1184. X.IR ixocico
  1185. is the message transport program for the tpage system.  It is called
  1186. by
  1187. X.B tpaged
  1188. and told what device to use and what phone number to dial on
  1189. the command line.  It
  1190. gets the PINs and messages to send from stdin.
  1191. X.PP
  1192. It co-exists with the uucp programs fine as it uses the
  1193. same methods to lock the modems.  It notices stale locks
  1194. and blows them away.  Not all locking features have been
  1195. proven to work on HPUX, only SunOS.
  1196. It will not wait for a modem to be unlocked.
  1197. X.PP
  1198. X.B tpaged
  1199. watches the output of
  1200. X.B ixocico
  1201. for lines beginning with # to know success
  1202. or failure of particular messages and of the entire batch.
  1203. X.PP
  1204. X.SH FILES
  1205. X.ta 6c
  1206. X.nf
  1207. X/home/adm/lib/tpage/schedule    schedule of who's on duty
  1208. X/home/adm/lib/tpage/table    table of people and their pager info
  1209. X.SH SEE ALSO
  1210. uucico(1), xkill(l)
  1211. X.SH HISTORY
  1212. Written by Tom Limoncelli (tal@Warren.MENTORG.COM)
  1213. at Mentor Graphics Corporation, Silicon Design Division,
  1214. Warren, New Jersey.  May be re-distributed only in it's unmodified
  1215. form.
  1216. X.SH BUGS
  1217. If
  1218. X.B \-d
  1219. and
  1220. X.B \-p
  1221. are specified, a name still must be specified.
  1222. X.PP
  1223. It currently only compiles under SunOS even though some
  1224. defines are inserted so that it doesn't fail all over the
  1225. place on silly operating systems like HPUX.
  1226. END_OF_FILE
  1227. if test 6781 -ne `wc -c <'tpage.l'`; then
  1228.     echo shar: \"'tpage.l'\" unpacked with wrong size!
  1229. fi
  1230. chmod +x 'tpage.l'
  1231. # end of 'tpage.l'
  1232. fi
  1233. if test -f 'tpage.pl' -a "${1}" != "-c" ; then 
  1234.   echo shar: Will not clobber existing file \"'tpage.pl'\"
  1235. else
  1236. echo shar: Extracting \"'tpage.pl'\" \(9757 characters\)
  1237. sed "s/^X//" >'tpage.pl' <<'END_OF_FILE'
  1238. X#! /usr/local/bin/perl4.019
  1239. X
  1240. X# tpage.pl -- front-end to tpage system.
  1241. X#   by Tom Limoncelli, tal@warren.mentorg.com
  1242. X#   Copyright (c) 1992, Tom Limoncelli
  1243. X#   The sources can be freely copied for non-commercial use only
  1244. X#   and only if they are unmodified.
  1245. X
  1246. X# Version 1.0 -- See file HISTORY for details.
  1247. X
  1248. X####################################################################
  1249. X#
  1250. X# Parameters that the user can set:
  1251. X#
  1252. X####################################################################
  1253. X
  1254. X$debug = 0;
  1255. X# leave that off
  1256. X
  1257. X$MAX_WINDOW = 16;
  1258. X#This is the number of charactors at a time do you see on your
  1259. X# pager.  This is used when word-wrapping.
  1260. X
  1261. X$MAX_MESSAGE = 160;
  1262. X# How many bytes can one message be.  This must be less than 250
  1263. X# minus the length of your PIN.  This is because each packet in the ixo
  1264. X# protocol must be less than 250 chars.  If you have a pager that can
  1265. X# receive longer messages, you'll have to modify the ixocico.c program
  1266. X# to handle the "packet continuation" feature.  No biggie, just 
  1267. X# something that I didn't feel like implementing since I can't even 
  1268. X# test it with my pager.
  1269. X
  1270. X$DEFAULT_S = '/home/adm/lib/tpage/schedule';
  1271. X# (default: '/home/adm/lib/tpage/schedule')
  1272. X# If you plan on using the schedule feature, this is the file
  1273. X# name where beep2.pl will look for the schedule.  It must be accessable
  1274. X# on the machine that runs tpage.pl, not the machine that runs the
  1275. X# daemon (tpaged.pl).
  1276. X
  1277. X$DEFAULT_T = '/home/adm/lib/tpage/table';
  1278. X# (default: '/home/adm/lib/tpage/table')
  1279. X# If you plan on using the table feature (that is, store a list
  1280. X# of people and their paging info), this is the file name where tpage.pl
  1281. X# will look for the data.  It must be accessable on the machine that
  1282. X# runs tpage.pl, not the machine that runs the daemon (tpaged.pl).
  1283. X
  1284. X$QUEUE_DIR = '/home/adm/lib/tpage/pqueue/';
  1285. X# (default: '/home/adm/lib/tpage/pqueue/'
  1286. X# This is the directory where messages will be queued.  The trailing "/"
  1287. X# is required.
  1288. X
  1289. X####################################################################
  1290. X# some helping functions
  1291. X
  1292. require("getopts.pl");
  1293. X
  1294. sub strip_string {
  1295. X    local($s) = @_;
  1296. print "DEBUG: REMOVE_CONTROLS :", $s, ":\n" if $debug;
  1297. X    $s =~ tr/\200-\377/\000\177/;    # remove high-bit
  1298. X    $s =~ tr/\000-\037\177//d;    # delete unprintables
  1299. X    $s =~ s/\s+/ /g;            # change groups of white space into " "
  1300. X    $s =~ s/^ //;                # remove spaces from the front
  1301. X    $s =~ s/ $//;                # remove spaces from the end
  1302. X    
  1303. print "DEBUG: REMOVE_DONE :", $s, ":\n" if $debug;
  1304. X    return $s;
  1305. X}
  1306. X
  1307. X####################################################################
  1308. X# Here's the actual program
  1309. X
  1310. X####################################################################
  1311. X# Get the command line options.
  1312. X
  1313. X# set the defaults
  1314. X
  1315. print "\n";
  1316. X
  1317. X# -S  schedule file
  1318. X$opt_S = $DEFAULT_S;
  1319. X# -T  pager table
  1320. X$opt_T = $DEFAULT_T;
  1321. X# -U  use urgent schedule if no one is scheduled for that time.
  1322. X$opt_U = 0;
  1323. X# -d  number to dial. (first name in list only)
  1324. X$opt_d = "";
  1325. X# -p  pager id to use. (first name in list only)
  1326. X$opt_p = "";
  1327. X# -t  tee all stdin into stdout.
  1328. X$opt_t = 0;
  1329. X# -v  verbose mode.
  1330. X$opt_v = 0;
  1331. X# -m  input will be in RFC822, skip boring stuff.
  1332. X$opt_m = 0;
  1333. X# -M  like -m but also skip >-quoted text.
  1334. X$opt_M = 0;
  1335. X# -e  if it errors, send email to this person.
  1336. X$opt_e = "";
  1337. X
  1338. X$line_from = "";
  1339. X$line_subj = "";
  1340. X$line_prio = "";
  1341. X
  1342. do Getopts('S:T:Ud:p:tvmMe:');
  1343. X
  1344. X# get the wholist
  1345. X$opt_wholist = shift (@ARGV);
  1346. X$opt_wholist = "special" if $opt_d && $opt_p;
  1347. X
  1348. X####################################################################
  1349. X# Get the message (either on the command line or stdin; handle -t -m -M
  1350. X
  1351. X# bunch up all the rest
  1352. X$opt_message = join(' ', @ARGV);
  1353. print "opt_message = :$opt_message:\n" if $debug;
  1354. X$opt_message = &strip_string( $opt_message ) if $opt_message;
  1355. print "opt_message = :$opt_message:\n" if $debug;
  1356. die "$0: No message.  Cat got your tongue?" if ( $opt_message eq "" );
  1357. X
  1358. die "$0: Can't use -m/-M and have message on the command line"
  1359. X        if ($opt_m || $opt_M) && $opt_message ne '-';
  1360. X
  1361. X# maybe get message from stdin, echoing to stdout if $opt_t;
  1362. if ($opt_message eq '-') {
  1363. X    $opt_message = '';
  1364. X    # handle -m headers first
  1365. X    if ($opt_m) {
  1366. X        print "DEBUG: Doing -m work\n" if $debug;
  1367. X        local($line) = "";
  1368. X        while (<>) {
  1369. X            if ( /^\S/ || /^$/ ) {    # start of new header, do previous one
  1370. X                $line_from = substr($line, 6) if $line =~ /^From/;
  1371. X                $line_subj = substr($line, 9) if $line =~ /^Subject: /;
  1372. X                $line_prio = substr($line, 10) if $line =~ /^Priority: /;
  1373. X                $line = $_;
  1374. X            } else {
  1375. X                $line .= $_;
  1376. X            }
  1377. X            last if /^$/;            # end of headers, start processing
  1378. X        }
  1379. X    }
  1380. X    $line_from = &strip_string( $line_from ) if $line_from;
  1381. X    $line_subj = &strip_string( $line_subj ) if $line_subj;
  1382. X    $line_prio = &strip_string( $line_prio ) if $line_prio;
  1383. X
  1384. X    while (<>) {
  1385. X# -M means skip if the line is news quoted email.
  1386. X# a line is news quoted if it begins with one of the following:
  1387. X#      [white] [word] quote
  1388. X# where "white" is any amount of whitespace (zero or one times)
  1389. X# where word is any letters/numbers (userid) (zero or one times)
  1390. X# where quote is any of >, <, }, or {.
  1391. X        next if $opt_M && /^\s*\S*[\>\}\<\{]/;
  1392. X        print if $opt_t;
  1393. X        $_ = &strip_string( $_ );
  1394. X        $opt_message .= $_;
  1395. X        $opt_message .= " ";
  1396. X        # once we've got quite a bunch, screw the rest.
  1397. X        if ( length($opt_message) > ($MAX_MESSAGE * 8)) {
  1398. X             while (<>) { print if $opt_t; }
  1399. X        }
  1400. X    }
  1401. X}
  1402. X
  1403. X####################################################################
  1404. X# massage the message
  1405. X
  1406. if ($debug) {
  1407. X    print "DEBUG: pre-processed messages\n";
  1408. X    print "FROM=:$line_from:\n";
  1409. X    print "PRIO=:$line_prio:\n";
  1410. X    print "SUBJ=:$line_subj:\n";
  1411. X    print "MESS=:$opt_message:\n";
  1412. X}
  1413. X
  1414. X$line_from = substr( "F: " . $line_from . ' ' x $MAX_WINDOW,
  1415. X        0, $MAX_WINDOW) if $line_from;        # pad to display size
  1416. X
  1417. X$line_prio = substr( "P: " . $line_prio . ' ' x $MAX_WINDOW,
  1418. X        0, $MAX_WINDOW) if $line_prio;        # pad to display size
  1419. X
  1420. X$l = $MAX_WINDOW * int ((length($line_subj)+$MAX_WINDOW+2) / $MAX_WINDOW);
  1421. X$line_subj = substr( "S: " . $line_subj . ' ' x $MAX_WINDOW,
  1422. X        0, $l) if $line_subj;        # pad to display size
  1423. X
  1424. X$opt_message = &strip_string( $opt_message );
  1425. X# put it all together
  1426. X$the_message = substr( $line_prio . $line_from . $line_subj . $opt_message, 0, $MAX_MESSAGE);
  1427. X
  1428. if ($debug) {
  1429. X    print "DEBUG: post-processed messages\n";
  1430. X    print "FROM=:$line_from:\n";
  1431. X    print "PRIO=:$line_prio:\n";
  1432. X    print "SUBJ=:$line_subj:\n";
  1433. X    print "MESS=:$opt_message:\n";
  1434. X    print "COMPLETE=:$the_message:\n";
  1435. X}
  1436. X
  1437. X####################################################################
  1438. X# At this point we can do some more of the sanity checking.
  1439. X
  1440. X#die "$0: Conflicting verbosity levels" if ($opt_s && ($opt_v || $opt_V));
  1441. die "$0: Schedule file $opt_S can't be read/found"
  1442. X        unless ( ($opt_wholist eq '-') || (-r $opt_S && -r $opt_T) );
  1443. die "$0: Pager table $opt_T can't be read"
  1444. X        unless ($opt_d && $opt_p) || ( -r $opt_T );
  1445. X
  1446. X####################################################################
  1447. X# use the schedule to fill in "who" if we need.
  1448. X
  1449. if ($opt_wholist eq '-') {
  1450. X    local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  1451. X    local($l) = $wday;
  1452. X    local($h) = $hour * 2 + int ($hour / 30) + 1;
  1453. X    local($w,$found1) = 0;
  1454. X
  1455. print "L = $l\n" if $debug;
  1456. print "H = $h\n" if $debug;
  1457. print "U = $opt_U\n" if $debug;
  1458. X
  1459. X    # Read from schedule until you hit a line beginning with $l.
  1460. X    # At that point, get the char $h bytes in.  If that byte is "-",
  1461. X    # and $opt_U, keep going.
  1462. X    print "\nChecking schedule:\n\n";
  1463. X    open(SCHED, "<$opt_S") || die "Can't open $opt_S: $!";
  1464. X    while (1) {
  1465. X        $w = '';
  1466. X        while (<SCHED>) {
  1467. X            last if /^${l}/;
  1468. X        }
  1469. X        $w = substr($_, $h, 1);
  1470. X        $found1 = 1 if $w;                # we found one!
  1471. X        next if $opt_U && $w eq '-';
  1472. X        last;
  1473. X    }
  1474. X
  1475. X    die "$0: Schedule doesn't have a line for this day of the week.\n" unless $found1;
  1476. X    die "$0: No one is assigned to be on duty at this time.\n" if $w eq '-';
  1477. X
  1478. X    # Now search until a line begins with $w= and assign line to wholist
  1479. X    $opt_wholist = '';
  1480. X    while (<SCHED>) {
  1481. X        next unless /^${w}\=/;
  1482. X        chop( $opt_wholist = substr($_, 2) );
  1483. X    }
  1484. X    die "$0: Schedule error: No people assigned to '" . $w . "'\n" unless $opt_wholist;
  1485. X    close SCHED;
  1486. X}
  1487. X
  1488. X####################################################################
  1489. X# we we still don't know who to call, bail out.
  1490. X
  1491. die "$0: The schedule didn't specify anyone to call!"
  1492. X        unless ($opt_wholist) || ($opt_d && $opt_p);
  1493. die "$0: There isn't anyone scheduled for this time of day."
  1494. X        if $opt_wholist eq '-';
  1495. X
  1496. X####################################################################
  1497. X# rotate through "$opt_wholist" and queue each person
  1498. X
  1499. X$cnt = 0;
  1500. foreach $who ( split(',', $opt_wholist) ) {
  1501. X    $cnt++;
  1502. X
  1503. X    # look up "who"'s information
  1504. X    open(TABL, "<$opt_T") || die "Can't open $opt_T: $!";
  1505. X    while (<TABL>) {
  1506. X        next if /^#/;
  1507. X        chop;
  1508. X        local($name,$phonen,$phonea,$pin) = split;
  1509. X        if ($name eq $who) {
  1510. X            $opt_d = $phonea unless $opt_d;    # might have it from ARGV
  1511. X            $opt_p = $pin unless $opt_p;    # might have it from ARGV
  1512. X            print "Got $who is :$opt_d:$opt_p:\n" if $debug;
  1513. X            last;
  1514. X        }
  1515. X    }
  1516. X    close TABL;
  1517. X
  1518. X    die "$0: We were not able to find a phone number for $who.\n" unless $opt_d;
  1519. X    die "$0: We were not able to find a PIN for $who.\n" unless $opt_p;
  1520. X
  1521. X    # write into the queue the proper information.
  1522. X    chop( $thishost = `hostname` );
  1523. X    $qname = $QUEUE_DIR . "P" . $thishost . time . $cnt;
  1524. X    print "QUEUE=$qname\n" if $debug;
  1525. X    open(QU, ">$qname" ) || die "Can't open $qname for writing: $!";
  1526. X    print QU "A\n";
  1527. X    print QU $opt_d, "\n";
  1528. X    print QU $opt_p, "\n";
  1529. X    if ($opt_e eq '-') {     # '-' means send errors to $who,
  1530. X        print QU $who, "\n";
  1531. X    } else {
  1532. X        print QU $opt_e, "\n";
  1533. X    }
  1534. X    print QU $the_message, "\n";
  1535. X    print QU "X\n";
  1536. X    close QU;
  1537. X    print "Message queued for $who: $the_message\n";
  1538. X    
  1539. X    # zap the phone# and PIN so that ARGV's info only effects us once.
  1540. X    $opt_d = "";
  1541. X    $opt_p = "";
  1542. X}
  1543. X
  1544. print "\n";
  1545. END_OF_FILE
  1546. if test 9757 -ne `wc -c <'tpage.pl'`; then
  1547.     echo shar: \"'tpage.pl'\" unpacked with wrong size!
  1548. fi
  1549. chmod +x 'tpage.pl'
  1550. # end of 'tpage.pl'
  1551. fi
  1552. if test -f 'tpaged.pl' -a "${1}" != "-c" ; then 
  1553.   echo shar: Will not clobber existing file \"'tpaged.pl'\"
  1554. else
  1555. echo shar: Extracting \"'tpaged.pl'\" \(8441 characters\)
  1556. sed "s/^X//" >'tpaged.pl' <<'END_OF_FILE'
  1557. X#! /usr/local/bin/perl4.019
  1558. X
  1559. X# tpaged -- back-end to tpage system.
  1560. X#   by Tom Limoncelli, tal@warren.mentorg.com
  1561. X#   Copyright (c) 1992, Tom Limoncelli
  1562. X#   The sources can be freely copied for non-commercial use only
  1563. X#   and only if they are unmodified.
  1564. X
  1565. X# Version 1.0 -- See file HISTORY for details. 
  1566. X
  1567. X####################################################################
  1568. X#
  1569. X# Parameters that the user can set:
  1570. X#
  1571. X####################################################################
  1572. X
  1573. X$debug = 0;
  1574. X$QUEUE_DIR = '/home/adm/lib/tpage/pqueue/';        # same as in tpage.pl
  1575. X$IXOCICO = '/home/tal/work/beep2/ixocico';        # where is ixocico?
  1576. X$MAIL = '/usr/ucb/mail';                        # which mail to use?
  1577. X
  1578. X# list of devices to rotate through.
  1579. X@DEVICES = ( "/dev/ttyz4" );    # currently they are all spoken
  1580. X# to at the same speed and same parameters.  Some day I'll set up
  1581. X# a modemtab system, but I don't think more than one modem is
  1582. X# really needed for this system.
  1583. X
  1584. X# amount of time to sleep between scans
  1585. X$SLEEP_TIME =  30;
  1586. X
  1587. X####################################################################
  1588. X# QUEUE FILES FORMAT:
  1589. X#
  1590. X# Files in the queue have the name of the format in the
  1591. X# first line.  Currently there is only one format and it
  1592. X# is named "A".  The first line marks it as the "A" format.
  1593. X# a subroutine called read_format_A reads this format.  Other
  1594. X# formats can be written (see comments by read_format_A)
  1595. X#
  1596. X# The "A" format:
  1597. X# line  contents
  1598. X#    1: A\n
  1599. X#    2: number to dial\n
  1600. X#    3: pin\n
  1601. X#    4: entire message\n
  1602. X#    5: X\n
  1603. X
  1604. X# read_format_*  -- modules that read various data formats.
  1605. X#                   Currently implemented: The "A" format.
  1606. X# do_proto_*     -- modules that do various beeper protocols.
  1607. X#                   Currently implmented: the ixo protocol.
  1608. X#                   Future protocols:     numeric-only pagers.
  1609. X
  1610. X####################################################################
  1611. X# Here's the actual program
  1612. X
  1613. X# define some globals
  1614. X
  1615. local(%ixo_dial);
  1616. local(%protocols);
  1617. X
  1618. while (1) {
  1619. X    local ($first,$allfiles);
  1620. X
  1621. X    # We could scoop up all the files and process them, but chances
  1622. X    # are if one file is found, more are on the way.  So, instead
  1623. X    # we scoop, if any are found we sleep 5 seconds and re-scoop.
  1624. X    while (1) {
  1625. X        opendir(QDIR, $QUEUE_DIR) || die "$0: Can't open $QUEUE_DIR: $!";
  1626. X        @allfiles = grep( !/^\./, readdir(QDIR) );
  1627. X        closedir(QDIR);
  1628. X
  1629. X        if ($#allfiles!=-1) {    # files?  take 5 and then process.
  1630. X            sleep 5;
  1631. X            last;
  1632. X        } else {            # no files?  hibernate.
  1633. X            sleep $SLEEP_TIME;
  1634. X            next;
  1635. X        }
  1636. X    }
  1637. X
  1638. X    print "DEBUG: allfiles= ", join(' ', @allfiles), "\n" if $debug;
  1639. X    opendir(QDIR, $QUEUE_DIR) || die "$0: Can't open $QUEUE_DIR: $!";
  1640. X    @allfiles = grep( !/^\./, readdir(QDIR) );
  1641. X    closedir(QDIR);
  1642. X    print "DEBUG: allfiles= ", join(' ', @allfiles), "\n" if $debug;
  1643. X
  1644. X    foreach $file (@allfiles) {
  1645. X        print "DEBUG: Doing $file\n" if $debug;
  1646. X        open(DATA, "<" . $QUEUE_DIR . $file) || print "Can't open $file: $!";
  1647. X        chop( $first = <DATA> );
  1648. print "DEBUG: first=$first\n" if $debug;
  1649. X        eval "do read_format_$first();";
  1650. X    }
  1651. X    
  1652. X    foreach $proto (sort keys %protocol) {
  1653. X        next unless $protocol{ $proto };
  1654. X        eval "do do_protocol_$proto();";
  1655. X        $protocol{ $proto } = 0;
  1656. X        sleep $SLEEP_TIME;
  1657. X    }
  1658. X}
  1659. X
  1660. X# Each read_format_ must:
  1661. X#  read from <DATA> and then close(DATA).
  1662. X#  %protocol{ protocol name } = 1 (for the protocol to use)
  1663. X#  and stuff the right data into the right variables for that protocol
  1664. X#  to use.
  1665. X
  1666. sub read_format_A
  1667. X{
  1668. X    local($dial,$pin,$error,$mess,$X);
  1669. X    print "DEBUG: reading format A\n" if $debug;
  1670. X    chop( $dial = <DATA> );
  1671. X    chop( $pin = <DATA> ); 
  1672. X    chop( $error = <DATA> );
  1673. X    chop( $mess = <DATA> );
  1674. X    chop( $X = <DATA> );
  1675. X
  1676. X    return if $X ne "X";  # file isn't in correct format or isn't done.
  1677. X    return if $dial eq "";
  1678. X    return if $pin eq "";
  1679. X    return if $mess eq "";
  1680. X
  1681. X    $protocol{ 'ixo' } = 1;
  1682. X    $ixo_dial{ $dial } = 1;
  1683. X    eval "unshift(@ixo_${dial}_pin, \$pin)";
  1684. X    eval "unshift(@ixo_${dial}_error, \$error)";
  1685. X    eval "unshift(@ixo_${dial}_mess, \$mess)";
  1686. X    eval "unshift(@ixo_${dial}_file, \$file)";
  1687. X}
  1688. X
  1689. X# Each do_protocol_ must:
  1690. X#  delete files out of the queue that are successful.
  1691. X#  delete files out of the queue that are aged.
  1692. X#  clean up so that the routine can be called again.
  1693. X
  1694. sub do_protocol_ixo {
  1695. X    print "DEBUG: doing protocol IXO\n" if $debug;
  1696. X#    local($pin, $error, $mess, $file, $cmd, $empty);
  1697. X    local($pin, $error, $mess, $file, $cmd);
  1698. X#    $empty = 1;
  1699. X    # build the temp file and the command line
  1700. X    local($tmpfile) = "/tmp/tpaged.$$";
  1701. X    foreach $dial (keys %ixo_dial) {
  1702. X        next unless $ixo_dial{ $dial };
  1703. X        print "DEBUG: Number to dial is $dial\n" if $debug;
  1704. X        open(IX, ">$tmpfile" ) || die "$0: Can't create $tmpfile: $!";
  1705. X        foreach (eval "@ixo_${dial}_pin") {
  1706. X            print IX eval "pop(@ixo_${dial}_pin )", "\n";
  1707. X            print IX eval "pop(@ixo_${dial}_mess)", "\n";
  1708. X            unshift(@ixo_list, eval "pop(@ixo_${dial}_error)" );
  1709. X            unshift(@ixo_list, eval "pop(@ixo_${dial}_file )" );
  1710. X#            $empty = 0;
  1711. X        }
  1712. X        close IX;
  1713. X        print "DEBUG: ", ($#ixo_list) / 2, " messages to send.\n" if $debug;
  1714. X#        if ($empty) {
  1715. X#            print "DEBUG: nothing to do!\n" if $debug;
  1716. X#            unlink $tmpfile;
  1717. X#            return;
  1718. X#        }
  1719. X        $cmd = $IXOCICO . " <" . $tmpfile . " "
  1720. X            . push(@DEVICES, shift @DEVICES) . " " . $dial;
  1721. X        print "DEBUG: About to execute: $cmd\n" if $debug;
  1722. X        open(IX, $cmd . "|") || die "$0: Can't execute ixocico: $!";
  1723. X        $mesgnum = 0;    # count the messages as they're processed
  1724. X        $success = 0;
  1725. X        # get to the next message (same as #MESOK)
  1726. X        $error = pop(@ixo_list);
  1727. X        $file  = pop(@ixo_list);
  1728. X        print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
  1729. X        while (<IX>) {
  1730. X            print if $debug;
  1731. X            next unless /^#/;
  1732. X
  1733. X            print unless $debug;
  1734. X
  1735. X            /^#WRONGARGS / &&
  1736. X                die("$0: Major program bug: $!");
  1737. X            /^#NOCONN / && do {
  1738. X                printf("$0: Nobody answered the phone!\n") if $debug;
  1739. X                last;
  1740. X            };
  1741. X            /^#UNKNOWNPROTO / && do {
  1742. X                print "$0: Uhhh, are you sure that's a pager service?\n" if $debug;
  1743. X                last;
  1744. X            };
  1745. X            /^\#MESOK (\d) / && do {
  1746. X                print "DEBUG: message $1 done.\n" if $debug;
  1747. X                if ($1 == $mesgnum++) {
  1748. X                    print "DEBUG: unlinking " . $QUEUE_DIR . $file . "\n" if $debug;
  1749. X                    unlink $QUEUE_DIR . $file;
  1750. X                    # get to the next message (same as #MESREJECT)
  1751. X                    $error = pop(@ixo_list);
  1752. X                    $file  = pop(@ixo_list);
  1753. X                    print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
  1754. X                } else {
  1755. X                    print "Things have gotten out of sync.  Restarting.\n" if $debug;
  1756. X                    last;
  1757. X                }
  1758. X            };
  1759. X            /^#MESREJECT (\d) / && do {
  1760. X                if ($1 == $mesgnum++) {
  1761. X                    if ($error) {
  1762. X                        $cmd = "$MAIL <" . $QUEUE_DIR . $file . " -s 'the following pin and message was rejected' " . $error;
  1763. X            print "DEBUG: About to execute $cmd\n" if $debug;
  1764. X                    }
  1765. X                    print "DEBUG: unlinking " . $QUEUE_DIR . $file . "\n" if $debug;
  1766. X                    unlink $QUEUE_DIR . $file;
  1767. X                    # get to the next message (same as #MESOK)
  1768. X                    $error = pop(@ixo_list);
  1769. X                    $file  = pop(@ixo_list);
  1770. X                    print "DEBUG: ERROR=$error; FILE=$file\n" if $debug;
  1771. X                } else {
  1772. X                    print "Things have gotten out of sync.  Restarting.\n" if $debug;
  1773. X                    last;
  1774. X                }
  1775. X            };
  1776. X            /^#FORDIS / && do {
  1777. X                print "Forced disconnect from server.\n" if $debug;
  1778. X                last;
  1779. X            };
  1780. X            /^#PROTERR / && do {
  1781. X                print "Server not following protocol.\n" if $debug;
  1782. X                last;
  1783. X            };
  1784. X            ( /^#DONE / || /#BYE / ) && do {
  1785. X                if ($#ixo_list) {
  1786. X                    print "Done with sending batch.  Waiting BYE.\n" if $debug;
  1787. X                    $success = 1;
  1788. X                    next;
  1789. X                } else {
  1790. X                    print "ixocico is done but more data waiting to be sent!  Program bug.\n" if $debug;
  1791. X                    last;
  1792. X                }
  1793. X            };
  1794. X            /^#WRONGANY / && do {
  1795. X                print "We've been notified that one of the batch may have been not xmited.\n(great protocol, eh?)\n" if $debug;
  1796. X                next;
  1797. X            };
  1798. X            /^#BADQUEUE / && do {
  1799. X                die "$0: Programmer error.  Data in queue is bad: $_\n";
  1800. X            };
  1801. X            /^#MODOPEN / && do {
  1802. X                print "Modem can't be opened\n" if $debug;
  1803. X                last;
  1804. X            };
  1805. X            /^#PACKLEN / && do {
  1806. X                die "$0: Protocol error.  Should never happen: $_\n";
  1807. X            };
  1808. X            /^#GOTMESSEQ / && do {
  1809. X                print "MESSAGE: $_\n" if $debug;
  1810. X            };
  1811. X            /^#LONELY / && do {
  1812. X                print "Hello?  Hello?  Either I'm getting the silent treatment or the server is dead." if $debug;
  1813. X                last;
  1814. X            };
  1815. X        }
  1816. X        close IX;
  1817. X        unlink $tmpfile;
  1818. X        $ixo_dial{ $dial } = 0;
  1819. X    }
  1820. X
  1821. X    print "DEBUG: ixo_dial = " if $debug;
  1822. X    foreach $i (keys %ixo_dial) {
  1823. X        next unless $ixo_dial{ $dial };
  1824. X        print $i if $debug;
  1825. X    };
  1826. X    print "\n" if $debug;
  1827. X
  1828. X    eval "@ixo_${dial}_pin   = ()";
  1829. X    eval "@ixo_${dial}_mess  = ()";
  1830. X    eval "@ixo_${dial}_error = ()";
  1831. X    eval "@ixo_${dial}_file  = ()";
  1832. X    $ixo_list = ();
  1833. X}
  1834. END_OF_FILE
  1835. if test 8441 -ne `wc -c <'tpaged.pl'`; then
  1836.     echo shar: \"'tpaged.pl'\" unpacked with wrong size!
  1837. fi
  1838. chmod +x 'tpaged.pl'
  1839. # end of 'tpaged.pl'
  1840. fi
  1841. echo shar: End of shell archive.
  1842. exit 0
  1843.