home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / pcmail2 / part06 < prev    next >
Text File  |  1990-01-24  |  65KB  |  2,275 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i038: PC-MAIL release 2, 6/11
  3. from: wswietse@lso.win.tue.nl (Wietse Venema)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 38
  7. Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
  8. Archive-name: pcmail2/part06
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 6 (of 11)."
  17. # Contents:  main/connect.c main/email.c main/gmail.c main/gphys.c
  18. #   main/gpres.c main/mbox.c main/nmail.c main/startup.c main/str.c
  19. # Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:18 1990
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f main/connect.c -a "${1}" != "-c" ; then 
  22.   echo shar: Will not over-write existing file \"main/connect.c\"
  23. else
  24. echo shar: Extracting \"main/connect.c\" \(6857 characters\)
  25. sed "s/^X//" >main/connect.c <<'END_OF_main/connect.c'
  26. X/*++
  27. X/* NAME
  28. X/*      connect 3
  29. X/* SUMMARY
  30. X/*      pre- and post protocol host access
  31. X/* PROJECT
  32. X/*      pc-mail
  33. X/* PACKAGE
  34. X/*      cico
  35. X/* SYNOPSIS
  36. X/*      int connect()
  37. X/*
  38. X/*      int disconnect()
  39. X/* DESCRIPTION
  40. X/*      connect() tries to make a connection to the remote host
  41. X/*      and to log on, using the dial-up script and login-name
  42. X/*    entries in the communications parameter file, and the password
  43. X/*    provided as command-line parameter to the cico program.
  44. X/*    A UUCP-like send/expect script facility is used. Thus a login
  45. X/*    sequence might look like:
  46. X/*
  47. X/*    send expect send expect ...
  48. X/*
  49. X/*    The program will send the first "send" string, then expect the
  50. X/*    first "expect" string, and so on.
  51. X/*
  52. X/*    Alternative expect/send sequences can be specified in the usual manner:
  53. X/*
  54. X/*    expect-send-expect-send-expect...
  55. X/*
  56. X/*    If the first expect string fails, the alternative send string is 
  57. X/*    transmitted and the alternative expect is tried, and so on, until
  58. X/*    an expect string succeeds, or until the list of alternatives is
  59. X/*    exhausted.
  60. X/*
  61. X/*    After the dial-up script has completed the program
  62. X/*    proceeds with the following build-in send/expect sequence:
  63. X/*
  64. X/*    ogin: your_login_name\\r ssword: your_password\\r
  65. X/*
  66. X/*      disconnect() tries to break a connection, using the disconnect
  67. X/*      entry in the communications parameter file. Unlike connect()
  68. X/*    this function is not driven by a send-expect script.
  69. X/*
  70. X/*    The following escape sequences are recognized in send or expect
  71. X/*    strings:
  72. X/*
  73. X/* .nf
  74. X/*    \\b    backspace
  75. X/*    \\r    carriage return
  76. X/*    \\n    newline
  77. X/*    \\t    tab
  78. X/*    \\s    space
  79. X/*    \\f    form feed
  80. X/*    \\nnn    octal character value
  81. X/*    \\\\    a real backslash
  82. X/* .fi
  83. X/*
  84. X/*    In addition, the following "send" strings are given special
  85. X/*    treatment:
  86. X/*
  87. X/* .nf
  88. X/*    BREAK    send a null character
  89. X/*    EOT    send Control-D
  90. X/* FUNCTIONS AND MACROS
  91. X/*      xwrite(), xgetc(), trap(), debug(4)(), log(), split()
  92. X/* FILES
  93. X/*      $MAILDIR/s00000        communications parameter file
  94. X/*    $MAILDIR/LOGFILE    system logfile
  95. X/* SEE ALSO
  96. X/*      params(5)       communications parameter file entries
  97. X/* DIAGNOSTICS
  98. X/*      connect() returns a status E_BADSETUP if the systems parameter
  99. X/*    file contains bad data, and E_NOLINE if the login script fails.
  100. X/* AUTHOR(S)
  101. X/*      W.Z. Venema
  102. X/*      Eindhoven University of Technology
  103. X/*      Department of Mathematics and Computer Science
  104. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  105. X/* CREATION DATE
  106. X/*      Fri Mar 27 17:11:12 GMT+1:00 1987
  107. X/* LAST MODIFICATION
  108. X/*    90/01/22 13:01:26
  109. X/* VERSION/RELEASE
  110. X/*    2.1
  111. X/*--*/
  112. X
  113. X#include <stdio.h>
  114. X#include <setjmp.h>
  115. X#include <ctype.h>
  116. X
  117. X#include "defs.h"
  118. X#include "params.h"
  119. X#include "status.h"
  120. X#include "comm.h"
  121. X#include "logs.h"
  122. X#include "sysdep.h"
  123. X
  124. Xhidden char *blnk = " \t";        /* send/expect separators */
  125. X
  126. X/* forward declarations */
  127. X
  128. Xhidden void conn_send();
  129. Xhidden void conn_xpct();
  130. Xhidden char *escape();
  131. X
  132. X/* connect - connect to remote system; simple script processing with retries */
  133. X
  134. Xpublic int connect()
  135. X{
  136. X    int    *savetrap = systrap;        /* save exception handler */
  137. X    jmp_buf mytrap;            /* our exception handler */
  138. X    int     retval;            /* completion code */
  139. X    char   *seq = DIAL_SEQUENCE;
  140. X    register char *cp;
  141. X
  142. X    /* set up exception handler */
  143. X
  144. X    if (retval = setjmp(systrap = mytrap)) {    /* get here if expect fails */
  145. X    systrap = savetrap;            /* it just happened */
  146. X    return (retval);
  147. X    }
  148. X    /* optional dial-up sequence */
  149. X
  150. X    for (cp = split(&seq, blnk); cp; cp = split(&seq, blnk)) {
  151. X    conn_send(escape(cp));
  152. X    if (cp = split(&seq, blnk))
  153. X        conn_xpct(escape(cp));
  154. X    }
  155. X
  156. X    /* mandatory login sequence; hack this for non-UNIX hosts */
  157. X
  158. X    conn_xpct("ogin:");
  159. X    conn_send(strcons("%s\r", LOGIN_NAME));
  160. X    conn_xpct("ssword:");
  161. X    conn_send(strcons("%s\r", password));
  162. X
  163. X    /* restore exception handler */
  164. X
  165. X    systrap = savetrap;                /* get here if expect wins */
  166. X    return (0);                    /* say no problems... */
  167. X}
  168. X
  169. X/* disconnect - disconnect line */
  170. X
  171. Xpublic int disconnect()
  172. X{
  173. X    conn_send(escape(DISC_SEQUENCE));        /* send disconnect sequence */
  174. X    return (0);                    /* always succeeds... */
  175. X}
  176. X
  177. X/* conn_send - send BREAK, EOT or string literal */
  178. X
  179. Xhidden void conn_send(s)
  180. Xregister char *s;
  181. X{
  182. X    static char null = '\0';
  183. X    static char eot = '\04';
  184. X
  185. X    sleep(1);
  186. X
  187. X    if (*s) {
  188. X    debug(4) ("Sending: %S\n", s);
  189. X    if (strcmp(s, "BREAK") == 0) {
  190. X        xwrite(ttfd, &null, 1);
  191. X    } else if (strcmp(s, "EOT") == 0) {
  192. X        xwrite(ttfd, &eot, 1);
  193. X    } else {
  194. X        while (*s) {
  195. X        delay();
  196. X        xwrite(ttfd, s++, 1);
  197. X        }
  198. X    }
  199. X    }
  200. X}
  201. X
  202. X/* conn_xpct - pattern matching without meta characters */
  203. X
  204. Xhidden void conn_xpct(s)
  205. Xchar   *s;
  206. X{
  207. X    int     c;
  208. X    int     i;
  209. X    int     n;
  210. X    char   *xp;
  211. X    char   *sp;
  212. X
  213. X    /*
  214. X     * Keep listening until we time out or until we receive the expected
  215. X     * string (thus, if the other end keeps sending garbage we will never
  216. X     * terminate). Make sure that we do not overrun our buffer. Parity bits
  217. X     * are ignored. If we do not succeed, try alternative sequences if they
  218. X     * are specified.
  219. X     */
  220. X
  221. X    for (xp = split(&s, "-"); xp; xp = split(&s, "-")) {
  222. X
  223. X    debug(4) ("Expecting: %S\nReceiving: ", xp);
  224. X
  225. X    if (((n = strlen(xp)) > MSGBUF))
  226. X        n = MSGBUF;
  227. X    for (i = 0; (c = xgetc()) != EOF; /* void */ ) {
  228. X        msgin[i++] = (c &= 0177);
  229. X        debug(4) ("%C", c);
  230. X        if (i >= n && strncmp(xp, &msgin[i - n], n) == 0) {
  231. X        debug(4) (" ok!\n");
  232. X        return;
  233. X        } else if (i >= MSGBUF) {
  234. X        strncpy(msgin, &msgin[i - (n - 1)], n - 1);
  235. X        i = n - 1;
  236. X        }
  237. X    }
  238. X    debug(4) (" failed!\n");
  239. X
  240. X    /* try alternative sequence, if specified, else fail */
  241. X
  242. X    if (sp = split(&s, "-")) {
  243. X        conn_send(sp);
  244. X    } else {
  245. X        trap(E_NOLINE, "LOGIN FAILED (at \"%S\")", xp);
  246. X    }
  247. X    }
  248. X}
  249. X
  250. X/* escape - interpret backslash sequences */
  251. X
  252. Xhidden char *escape(s)
  253. Xregister char *s;
  254. X{
  255. X    static char buf[BUFSIZ];
  256. X    register char *cp = buf;
  257. X    register char ch;
  258. X    int     c;
  259. X    int     i;
  260. X
  261. X    while (*s && cp < buf + sizeof(buf) - 1) {    /* don't overflow the buffer */
  262. X
  263. X    if (*s != '\\') {            /* ordinary character */
  264. X        *cp++ = *s++;
  265. X    } else if (isdigit(*++s) && *s < '8') {    /* \nnn octal code */
  266. X        sscanf(s, "%3o", &c);
  267. X        *cp++ = c;
  268. X        i = 1;
  269. X        s++;
  270. X        while (i++ < 3 && isdigit(*s) && *s < '8')
  271. X        s++;
  272. X    } else if ((ch = *s++) == 0) {        /* at string terminator */
  273. X        break;
  274. X    } else if (ch == 'b') {            /* \b becomes backspace */
  275. X        *cp++ = '\b';
  276. X    } else if (ch == 'f') {            /* \f becomes formfeed */
  277. X        *cp++ = '\f';
  278. X    } else if (ch == 'n') {            /* \n becomes newline */
  279. X        *cp++ = '\n';
  280. X    } else if (ch == 'r') {            /* \r becomes carriage ret */
  281. X        *cp++ = '\r';
  282. X    } else if (ch == 's') {            /* \s becomes blank */
  283. X        *cp++ = ' ';
  284. X    } else if (ch == 't') {            /* \t becomes tab */
  285. X        *cp++ = '\t';
  286. X    } else {                /* \any becomes any */
  287. X        *cp++ = ch;
  288. X    }
  289. X    }
  290. X    *cp = '\0';                    /* terminate the result */
  291. X    return (buf);
  292. X}
  293. END_OF_main/connect.c
  294. if test 6857 -ne `wc -c <main/connect.c`; then
  295.     echo shar: \"main/connect.c\" unpacked with wrong size!
  296. fi
  297. # end of overwriting check
  298. fi
  299. if test -f main/email.c -a "${1}" != "-c" ; then 
  300.   echo shar: Will not over-write existing file \"main/email.c\"
  301. else
  302. echo shar: Extracting \"main/email.c\" \(6160 characters\)
  303. sed "s/^X//" >main/email.c <<'END_OF_main/email.c'
  304. X/*++
  305. X/* NAME
  306. X/*    email 3
  307. X/* SUMMARY
  308. X/*    manipulate one message in preparation
  309. X/* PROJECT
  310. X/*    pc-mail
  311. X/* PACKAGE
  312. X/*    mail
  313. X/* SYNOPSIS
  314. X/*    #include "mail.h"
  315. X/*
  316. X/*    int work()
  317. X/*
  318. X/*    int work_disp(def_addr)
  319. X/*    char *def_addr;
  320. X/* DESCRIPTION
  321. X/*      The functions in this module are responsible for manipulations 
  322. X/*    on mail messages in preparation.
  323. X/*
  324. X/*    work() should be invoked when the user has selected an existing
  325. X/*    message in preparation. It does some initializations and invokes
  326. X/*    the work_disp() function.
  327. X/*
  328. X/*      work_disp() allows the user to specify the disposition of a
  329. X/*    mail message in preparation. It should be used after the user has
  330. X/*    created a message, or after the user has selected a message in 
  331. X/*    preparation.
  332. X/*
  333. X/*    The message file is displayed on the screen and user the 
  334. X/*    can choose to print, mail, edit or delete etc. the message.
  335. X/*
  336. X/*    The def_addr argument contains a default mail destination: for example,
  337. X/*    an address extracted from a message being replied to. It should be an
  338. X/*    e-mail address or an empty string.
  339. X/*
  340. X/*    The code in this module is a little tricky, to avoid "orphan" work
  341. X/*    files (message file without a metafile).
  342. X/* COMMANDS
  343. X/*    The program specified in the EDITOR environment variable,
  344. X/*    or a system-dependent default.
  345. X/* FILES
  346. X/*    mail.msg, file being edited in the current directory
  347. X/*      $MAILDIR/ennnnn, message file (body)
  348. X/*    $MAILDIR/cnnnnn, meta file (summary)
  349. X/*    $MAILDIR/header, template mail header file
  350. X/*    $MAILDIR/trailer, template signature file
  351. X/* SEE ALSO
  352. X/*      pager(3), pager(5), kbdinp(3), edit(3)
  353. X/* AUTHOR(S)
  354. X/*      W.Z. Venema
  355. X/*      Eindhoven University of Technology
  356. X/*      Department of Mathematics and Computer Science
  357. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  358. X/* CREATION DATE
  359. X/*    Tue May 12 15:35:20 GMT+1:00 1987
  360. X/* LAST MODIFICATION
  361. X/*    90/01/22 13:01:35
  362. X/* VERSION/RELEASE
  363. X/*    2.1
  364. X/*--*/
  365. X
  366. X#include <stdio.h>
  367. X#include <sys/types.h>
  368. X#include <sys/stat.h>
  369. X
  370. X#include <errno.h>
  371. X#include "defs.h"
  372. X#include "path.h"
  373. X#include "pager.h"
  374. X#include "screen.h"
  375. X#include "mail.h"
  376. X#include "status.h"
  377. X
  378. X/* forward declarations */
  379. X
  380. Xhidden void junk_work();
  381. Xhidden int edit_work();
  382. Xhidden int show_work();
  383. Xhidden int hold_work();
  384. Xhidden int send_work();
  385. Xhidden int queue_work();
  386. X
  387. Xpublic char address[MAXLINE];        /* default destination */
  388. Xhidden File *workfile = 0;        /* pager file */
  389. X
  390. X/* work - user selected message in preparation */
  391. X
  392. Xpublic int work()
  393. X{
  394. X    return (work_disp(""));
  395. X}
  396. X
  397. X/* work_disp - ask disposition of a message in preparation */
  398. X
  399. Xpublic int work_disp(def_addr)
  400. Xchar *def_addr;
  401. X{
  402. X    static Screen screen[] = {
  403. X    'C',    "Close",hold_work,"Send message later, return to message-selection menu",
  404. X#ifdef    ATTACH
  405. X    'A',    "Attach",attach", "Attach file to message",
  406. X#endif
  407. X    'D',    "Delete",delete,  delcurr,
  408. X    'E',    "Edit",    edit_work,"Edit this message",
  409. X    'M',    "Mail",    send_work,"Send this message to destination",
  410. X    'P',    "Print",print,      printcurr,
  411. X    PGUP,    PgUp,    pu_pager, pageup,
  412. X    PGDN,    PgDn,    pd_pager, pagedn,
  413. X    UP,    "Up",    up_pager, csrup,
  414. X    DOWN,    "Down",    dn_pager, csrdn,
  415. X    0,    0,    show_work,
  416. X    "(Reading a message in preparation)",
  417. X    };
  418. X    struct stat s;
  419. X
  420. X    strcpy(address, def_addr);            /* set up default address */
  421. X    kbdinp(screen);                /* ask disposition */
  422. X    junk_work();                /* destroy mail pager file */
  423. X    return (S_REDRAW);                /* say screen was changed */
  424. X}
  425. X
  426. X/* show_work - show message in preparation or error message in middle window */
  427. X
  428. Xhidden int show_work()
  429. X{
  430. X    if (workfile) {                /* check pager file exists */
  431. X    set_pager(workfile);            /* select existing display */
  432. X    } else if (rd_pager(workfile = open_pager(), message)) {
  433. X    mesg_pager(workfile, m_msgread);    /* cannot display message */
  434. X    }
  435. X    ds_pager();                    /* (re)draw display */
  436. X    return (0);                    /* screen is up-to-date */
  437. X}
  438. X
  439. X/* junk_work - destroy message in preparation display */
  440. X
  441. Xhidden void junk_work()
  442. X{
  443. X    if (workfile) {                /* no-op if no display */
  444. X    close_pager(workfile);            /* release memory */
  445. X    workfile = 0;                /* say it is gone */
  446. X    }
  447. X}
  448. X
  449. X/* edit_work - edit a message in preparation */
  450. X
  451. Xhidden int edit_work()
  452. X{
  453. X    register int stat;
  454. X
  455. X    if (stat = edit(message, MAILFILE))        /* try to edit the message */
  456. X    errdisp(stat);                /* edit() had a problem */
  457. X    junk_work();                /* force new message display */
  458. X    return (S_REDRAW);                /* say screen has changed */
  459. X}
  460. X
  461. Xhidden int label_work();
  462. X
  463. X/* hold_work - stop editing but do not yet mail a message in preparation */
  464. X
  465. Xhidden int hold_work()
  466. X{
  467. X    static Screen screen[] = {
  468. X    STRING,    0, label_work, int_error,
  469. X    0,    0, 0,
  470. X    getsummary,
  471. X    };
  472. X    struct stat s;
  473. X
  474. X    /*
  475. X     * The user does not yet want to send the message off. The purpose of the
  476. X     * following code is to ask for a one-line summary, but only if such a
  477. X     * comment does not yet exist. The summary is used to identify the
  478. X     * message in preparation in the message- selection display.
  479. X     */
  480. X
  481. X    if (stat(message, &s) || !stat(comment, &s)) {
  482. X    return (S_BREAK);            /* we are done here */
  483. X    } else {
  484. X    return (kbdinp(screen) | S_REDRAW);    /* ask for a summary */
  485. X    }
  486. X}
  487. X
  488. X/* label_work - save summary line to meta file */
  489. X
  490. Xhidden  label_work(string)
  491. Xchar   *string;
  492. X{
  493. X    register int stat;
  494. X
  495. X    if (stat = metafile(comment, string, (char *) 0)) {
  496. X    errdisp(stat);                /* oops, notify the user */
  497. X    return (S_REDRAW);            /* say screen has changed */
  498. X    } else {
  499. X    chmod(comment, 0444);            /* make comments read-only */
  500. X    junk_desk();                /* say mail box has changed */
  501. X    return (S_BREAK);            /* say no more work */
  502. X    }
  503. X}
  504. X
  505. X/* send_work - user wants to send message in preparation, ask for destination */
  506. X
  507. Xhidden int send_work()
  508. X{
  509. X    static Screen screen[] = {
  510. X    EDIT,    0,    queue_work,    address,
  511. X    0,    0,    when,
  512. X    "Press ESC to cancel. Send message to:",
  513. X    };
  514. X
  515. X    return (kbdinp(screen) | S_REDRAW);
  516. X}
  517. X
  518. X/* queue_work - spool mail, delete message in preparation and meta file */
  519. X
  520. Xhidden int queue_work(to)
  521. Xchar   *to;
  522. X{
  523. X    register int stat;
  524. X
  525. X    if (stat = submit(message, to)) {
  526. X    errdisp(stat);                /* cannot queue message */
  527. X    return (S_REDRAW);            /* say screen has changed */
  528. X    } else {
  529. X    return (unspool() | S_BREAK);        /* remove work and meta file */
  530. X    }
  531. X}
  532. END_OF_main/email.c
  533. if test 6160 -ne `wc -c <main/email.c`; then
  534.     echo shar: \"main/email.c\" unpacked with wrong size!
  535. fi
  536. # end of overwriting check
  537. fi
  538. if test -f main/gmail.c -a "${1}" != "-c" ; then 
  539.   echo shar: Will not over-write existing file \"main/gmail.c\"
  540. else
  541. echo shar: Extracting \"main/gmail.c\" \(6153 characters\)
  542. sed "s/^X//" >main/gmail.c <<'END_OF_main/gmail.c'
  543. X/*++
  544. X/* NAME
  545. X/*      gmail 1
  546. X/* SUMMARY
  547. X/*      deliver unsent mail via gnuucp
  548. X/* PROJECT
  549. X/*      pc-mail
  550. X/* PACKAGE
  551. X/*      gnu
  552. X/* SYNOPSIS
  553. X/*      gmail [-d debuglevel]
  554. X/* DESCRIPTION
  555. X/*    This program replaces the sending function of the pc-mail "cico"
  556. X/*    program, on systems that use GNUUCP for message transport.
  557. X/*
  558. X/*      gmail searches the pc-mail message data base for unsent mail
  559. X/*    (with the "Out" status) and queues it for transmission via GNUUCP.
  560. X/*    When a message has been queued it is renamed to reflect
  561. X/*    the "Sent" status.
  562. X/*
  563. X/*    This program is intended to be called via the MAILCMD environment
  564. X/*    variable, so that it is invoked upon exit from the mail user
  565. X/*    interface program.
  566. X/*
  567. X/*      In order to avoid corruption of the message data base, control-c
  568. X/*    interrupts are disabled while this program executes.
  569. X/* ENVIRONMENT
  570. X/*    MAILDIR, path to pc-mail message data base
  571. X/* COMMANDS
  572. X/*    rmail, the gnuucp mailer
  573. X/* FILES
  574. X/*      In the spool directory:
  575. X/*    d<seqno>    unsent mail, message body
  576. X/*    x<seqno>    unsent mail, destination and subject
  577. X/*    q<seqno>    sent mail, message body
  578. X/*    r<seqno>    sent mail, destination and subject
  579. X/* SEE ALSO
  580. X/*      path(5)         spool directory, file name formats
  581. X/* DIAGNOSTICS
  582. X/*      Problems are reported on the standard error output, and cause the
  583. X/*    program to terminate with a nonzero exit status.
  584. X/* BUGS
  585. X/*    It is left up to GNUUCP to determine what to do with undeliverable mail.
  586. X/* AUTHOR(S)
  587. X/*      W.Z. Venema
  588. X/*      Eindhoven University of Technology
  589. X/*      Department of Mathematics and Computer Science
  590. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  591. X/* CREATION DATE
  592. X/*    Wed Jan  3 22:16:28 MET 1990
  593. X/* LAST MODIFICATION
  594. X/*    90/01/22 13:01:40
  595. X/* VERSION/RELEASE
  596. X/*    2.1
  597. X/*--*/
  598. X
  599. X#include <stdio.h>
  600. X#include <signal.h>
  601. X#include <time.h>
  602. X#include <varargs.h>
  603. X
  604. X#include "defs.h"
  605. X#include "ndir.h"
  606. X#include "path.h"
  607. X
  608. X#ifndef    RMAIL
  609. X#define    RMAIL    "rmail"
  610. X#endif
  611. X
  612. X/* Forward declarations */
  613. X
  614. Xhidden char *get_dest();
  615. Xhidden int uuqueue();
  616. Xhidden void error();
  617. Xhidden void frename();
  618. Xhidden void parse_args();
  619. Xhidden void scanmail();
  620. Xhidden void usage();
  621. X
  622. X#define debug    if (dflag) (void) printf
  623. X
  624. Xhidden int dflag = 0;            /* debugging option */
  625. X
  626. Xpublic char *progname = "gmail";    /* for diagnostics */
  627. X
  628. X/* .. */
  629. X
  630. Xmain(argc, argv)
  631. Xint     argc;
  632. Xchar  **argv;
  633. X{
  634. X    (void) signal(SIGINT, SIG_IGN);        /* disable ctrl-c */
  635. X    if (pathinit())                /* get path info */
  636. X    error("no mail directory or MAILDIR environment variable not set");
  637. X    parse_args(argc, argv);            /* parse command args */
  638. X    scanmail();                    /* search for unsent mail */
  639. X    exit(0);
  640. X    /* NOTREACHED */
  641. X}
  642. X
  643. X/* parse_args - process command-line arguments */
  644. X
  645. Xhidden void parse_args(argc, argv)
  646. Xint     argc;
  647. Xchar  **argv;
  648. X{
  649. X    while (--argc && *++argv && **argv == '-') {/* process options */
  650. X    switch (*++*argv) {
  651. X    case 'd':                /* turn debugging on */
  652. X        dflag++;
  653. X        break;
  654. X    default:                /* unknown option */
  655. X        usage("invalid option: -%c", **argv);
  656. X        break;
  657. X    }
  658. X    }
  659. X
  660. X    /* check for extraneous arguments */
  661. X
  662. X    if (argc > 0)
  663. X    usage("unexpected argument: %s", *argv);
  664. X}
  665. X
  666. X/* scan for unsent mail */
  667. X
  668. Xhidden void scanmail()
  669. X{
  670. X    unsigned msgno;            /* message sequence number */
  671. X    register DIR *dp;
  672. X    struct direct *de;
  673. X    char   *dest;
  674. X
  675. X    debug("directory: \"%s\"\n", maildir);
  676. X
  677. X    /*
  678. X     * Scan the spool directory for unsent mail. After the message has been
  679. X     * piped through rmail, rename it to reflect the "Sent" status. Do not give
  680. X     * up if a file cannot be opened; just proceed with the next message.
  681. X     */
  682. X
  683. X    if ((dp = opendir(maildir)) == 0)
  684. X    error("cannot read the mail directory: %s", maildir);
  685. X
  686. X    while (de = readdir(dp)) {
  687. X    debug("file: \"%s\"\n", de->d_name);
  688. X    if (de->d_name[0] == OUT_META && (msgno = seqno(de->d_name))
  689. X    && (dest = get_dest(msgno)) && uuqueue(msgno, dest)) {
  690. X        frename(out_mesg(msgno), sent_mesg(msgno));
  691. X        frename(out_meta(msgno), sent_meta(msgno));
  692. X    }
  693. X    }
  694. X    closedir(dp);
  695. X}
  696. X
  697. X/* uuqueue - queue one message */
  698. X
  699. Xhidden int uuqueue(msgno, dest)
  700. Xunsigned msgno;
  701. Xchar   *dest;
  702. X{
  703. X    char    cmd[BUFSIZ];
  704. X    char   *path;
  705. X    char   *rcpt;
  706. X    static char sep[] = " \t\r\n";
  707. X
  708. X    if (access(path = out_mesg(msgno), 04)) {
  709. X    debug("%s: cannot read message file: %s\n", path, sys_errlist[errno]);
  710. X    return (0);
  711. X    } else {
  712. X
  713. X    /*
  714. X     * The GNUUCP rmail program has to invoked for each recipient. rmail
  715. X     * will have to deal with undeliverable mail anyway, so we ignore
  716. X     * that class of errors.
  717. X     */
  718. X
  719. X    for (rcpt = strtok(dest, sep); rcpt; rcpt = strtok((char *) 0, sep)) {
  720. X        (void) sprintf(cmd, "%s %s <%s", RMAIL, rcpt, path);
  721. X        debug("command: %s\n", cmd);
  722. X        if (system(cmd) == 127)
  723. X        error("could not invoke the shell");
  724. X    }
  725. X    return (1);
  726. X    }
  727. X}
  728. X
  729. X/* get_dest - extract recipients */
  730. X
  731. Xhidden char *get_dest(msgno)
  732. Xunsigned msgno;
  733. X{
  734. X    static char buf[MAXLINE];
  735. X    FILE   *fp;
  736. X    char   *ret;
  737. X    char   *path;
  738. X
  739. X    if ((fp = fopen(path = out_meta(msgno), "r")) == 0) {
  740. X    debug("%s: cannot open: %s\n", path, sys_errlist[errno]);
  741. X    return (0);
  742. X    } else {
  743. X    if ((ret = fgets(buf, sizeof(buf), fp)) == 0)
  744. X        debug("%s: no recipients found\n", path);
  745. X    (void) fclose(fp);
  746. X    return (ret);
  747. X    }
  748. X}
  749. X
  750. X/* frename - forcibly change the name of a file */
  751. X
  752. Xhidden void frename(from, to)
  753. Xchar   *from;
  754. Xchar   *to;
  755. X{
  756. X    debug("rename: %s -> %s\n", from, to);
  757. X
  758. X    if (chmod(to, 0600) == 0)
  759. X    (void) unlink(to);
  760. X    if (rename(from, to))
  761. X    error("cannot rename %s to %s: %s", from, to, sys_errlist[errno]);
  762. X}
  763. X
  764. X/* error - complain */
  765. X
  766. X/* VARARGS */
  767. X
  768. Xhidden void error(va_alist) 
  769. Xva_dcl
  770. X{
  771. X    va_list ap;
  772. X    char   *fmt;
  773. X
  774. X    (void) fprintf(stderr, "%s: ", progname);
  775. X    va_start(ap);
  776. X    fmt = va_arg(ap, char *);
  777. X    (void) vfprintf(stderr, fmt, ap);
  778. X    va_end(ap);
  779. X    (void) putc('\n', stderr);
  780. X    exit(2);
  781. X}
  782. X
  783. X/* usage - explain what is wrong */
  784. X
  785. X/* VARARGS */
  786. X
  787. Xhidden void usage(va_alist) 
  788. Xva_dcl
  789. X{
  790. X    va_list ap;
  791. X    char   *fmt;
  792. X
  793. X    (void) fprintf(stderr, "%s: ", progname);
  794. X    va_start(ap);
  795. X    fmt = va_arg(ap, char *);
  796. X    (void) vfprintf(stderr, fmt, ap);
  797. X    va_end(ap);
  798. X    (void) fprintf(stderr, "\nusage: gmail [-d]\n");
  799. X    exit(2);
  800. X}
  801. END_OF_main/gmail.c
  802. if test 6153 -ne `wc -c <main/gmail.c`; then
  803.     echo shar: \"main/gmail.c\" unpacked with wrong size!
  804. fi
  805. # end of overwriting check
  806. fi
  807. if test -f main/gphys.c -a "${1}" != "-c" ; then 
  808.   echo shar: Will not over-write existing file \"main/gphys.c\"
  809. else
  810. echo shar: Extracting \"main/gphys.c\" \(6844 characters\)
  811. sed "s/^X//" >main/gphys.c <<'END_OF_main/gphys.c'
  812. X/*++
  813. X/* NAME
  814. X/*    gphys 3
  815. X/* SUMMARY
  816. X/*    g protocol packet input/output
  817. X/* PROJECT
  818. X/*    pc-mail
  819. X/* PACKAGE
  820. X/*    cico
  821. X/* SYNOPSIS
  822. X/*    #include "gp.h"
  823. X/*
  824. X/*    void gsctrl(fd,c)
  825. X/*    int fd,c;
  826. X/*
  827. X/*    void gsdata(fd,pk,c)
  828. X/*    int fd,c;
  829. X/*    Packet *pk;
  830. X/*
  831. X/*    int grpack(fd,pk)
  832. X/*    int fd;
  833. X/*    Packet *pk;
  834. X/* DESCRIPTION
  835. X/*    The functions in this module send and receive packets. Interfacing
  836. X/*    is based on Packet structures. Messages are interpreted elsewhere.
  837. X/*
  838. X/*    gsctrl() sends a control packet to the remote receiver (no data
  839. X/*    segment).
  840. X/*
  841. X/*    gsdata() sends a data packet to the remote receiver. 
  842. X/*    The Packet structure is completed with a 16-bit checksum.
  843. X/*    This function expects read/write sequence information in 
  844. X/*    the c parameter.
  845. X/*
  846. X/*    grpack() receives a packet from the remote transmitter and checks
  847. X/*    its integrity. It fills in the k, c, len and check fields of the 
  848. X/*    Packet structure and returns the type of message (DATA, SHORT, 
  849. X/*    CLOSE, RJ, RR, etcetera).
  850. X/* DIAGNOSTICS
  851. X/*    grpack() returns FAIL if a corrupted packet was received, and
  852. X/*    TIME if no packet was received within the time-out interval.
  853. X/* BUGS
  854. X/*    No data re-reading in case of transmission errors.
  855. X/*    Some parts of the code rely on 8-bit bytes, 16-bit short integers.
  856. X/* AUTHOR(S)
  857. X/*    W.Z. Venema
  858. X/*    Eindhoven University of Technology
  859. X/*    Department of Mathematics and Computer Science
  860. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  861. X/* CREATION DATE
  862. X/*    Sun Apr 19 11:39:27 GMT+1:00 1987
  863. X/* LAST MODIFICATION
  864. X/*    90/01/22 13:01:42
  865. X/* VERSION/RELEASE
  866. X/*    2.1
  867. X/*--*/
  868. X
  869. X#include <signal.h>
  870. X#include <setjmp.h>
  871. X#include "gp.h"
  872. X
  873. X/* local and forward declarations */
  874. X
  875. Xstatic jmp_buf timebuf;
  876. Xstatic int chksum(),readhead(),readdata(),clkint();
  877. X
  878. X#define    READ(fd,cp,n)    { if (read(fd,cp,n) != n) clkint(); }
  879. X
  880. X/*
  881. X* "A six byte framing envelope is constructed using the control"
  882. X* "byte C of a packet and five other bytes as depicted below."
  883. X*        <DLE><k><c0><c1><C><x>
  884. X* "The <DLE> symbol denotes the ASCII ctrl/P character. If the"
  885. X* "envelope is to be followed by a data segment, <k> has the"
  886. X* "value log2(size)-4; i.e. 1 <= k < 8. If k is 9, then the"
  887. X* "envelope represents a control packet. The <c0> and <c1>"
  888. X* "bytes are the low-order and high-order bytes respectively of"
  889. X* "0xAAA minus a 16-bit checksum. For control packets, this"
  890. X* "16-bit checksum is the same as the control byte C. For data"
  891. X* "packets, the checksum is calculated by the program below."
  892. X* "The <x> byte is the exclusive-or of <k><c0><c1><C>. Error"
  893. X* "control is accomplished by checking a received framing"
  894. X* "envelope for compliance with the definition, and comparing a"
  895. X* "checksum function of the data segment with <c0><c1>."
  896. X*/
  897. X
  898. X/* gsctrl - send control packet (no data segment) */
  899. X
  900. Xvoid gsctrl(fd,c)
  901. Xint fd,c;
  902. X{
  903. X    char header[6];
  904. X    register char chkhdr;
  905. X    register char *cp = header;
  906. X    int cksm = MAGIC-c;                /* do checksum */
  907. X
  908. X    *cp++ = CTRL('P');                /* start of header */
  909. X    chkhdr  = *cp++ = KCTRL;            /* k byte (control) */
  910. X    chkhdr ^= *cp++ = cksm;            /* c0 byte (checksum lsb) */
  911. X    chkhdr ^= *cp++ = cksm>>8;            /* c1 byte (checksum msb) */
  912. X    chkhdr ^= *cp++ = c;            /* message|sequence info */
  913. X    *cp = chkhdr;                /* header checksum */
  914. X
  915. X    write(fd,header,sizeof(header));        /* send header */
  916. X    DEBUG(9,"xmt: %o\n",c&0377);        /* show header */
  917. X}
  918. X
  919. X/* gsdata - send data packet */
  920. X
  921. Xvoid gsdata(fd,pk,c)
  922. Xint fd,c;
  923. Xregister Packet *pk;
  924. X{
  925. X    char header[6];
  926. X    register char chkhdr;
  927. X    register char *cp = header;
  928. X    int cval = pk->c|(c&077);            /* fold in sequence info */
  929. X
  930. X    pk->chk = MAGIC-(chksum(pk->data,pk->len)^(0377&cval));
  931. X
  932. X    *cp++ = CTRL('P');                /* start of header */
  933. X    chkhdr  = *cp++ = pk->k;            /* k byte (message length) */
  934. X    chkhdr ^= *cp++ = pk->chk;            /* c0 byte (checksum lsb) */
  935. X    chkhdr ^= *cp++ = pk->chk>>8;        /* c1 byte (checksum msb) */
  936. X    chkhdr ^= *cp++ = cval;            /* data|sequence info */
  937. X    *cp = chkhdr;                /* header checksum */
  938. X
  939. X    write(fd,header,sizeof(header));        /* send header */
  940. X    DEBUG(9,"xmt: %o\n",cval&0377);        /* show header */
  941. X
  942. X    write(fd,pk->data,pk->len);            /* send data segment */
  943. X    DEBUG(9,"xmt: data %d bytes\n",pk->segl);    /* show data */
  944. X}
  945. X
  946. X/* grpack - receive one data or control packet; return packet type info */
  947. X
  948. Xint grpack(fd,pk)
  949. Xint fd;
  950. Xregister Packet *pk;
  951. X{
  952. X    if (setjmp(timebuf))            /* in case we time out */
  953. X    return(TIME);                /* it just happened */
  954. X    signal(SIGALRM,clkint);            /* alarm clock response */
  955. X    alarm(ALARM);                /* set alarm clock */
  956. X
  957. X    if (readhead(fd,pk)) {            /* read packet header */
  958. X    DEBUG(7,"rcv: bad header\n","");
  959. X    alarm(0);                /* turn timer off */
  960. X    return(FAIL);                /* header checksum error */
  961. X    } else if (pk->k == KCTRL) {
  962. X    alarm(0);                /* turn timer off */
  963. X    return(MESG(pk->c));            /* CLOSE | RJ | RR etcetera */
  964. X    } else if (readdata(fd,pk)) {
  965. X    DEBUG(7,"rcv: bad data\n","");
  966. X    alarm(0);                /* turn timer off */
  967. X    return(FAIL);                /* data checksum error */
  968. X    } else {
  969. X    alarm(0);                /* turn timer off */
  970. X    return(TYPE(pk->c));            /* DATA | SHORT */
  971. X    }
  972. X}
  973. X
  974. X/* readhead - read header and check header checksum */
  975. X
  976. Xstatic int readhead(fd,pk)
  977. Xint fd;
  978. Xregister Packet *pk;
  979. X{
  980. X    char header[5];
  981. X    int ok;
  982. X    register char chkhdr;
  983. X    register char *cp = header;
  984. X
  985. X    do {                    /* start reading */
  986. X    READ(fd,cp,1);                /* skip all garbage */
  987. X    } while (*cp != CTRL('P'));            /* up to packet header */
  988. X
  989. X    READ(fd,header,sizeof(header));        /* read packet header */
  990. X
  991. X    chkhdr  = pk->k = *cp++;            /* data length or control */
  992. X    chkhdr ^= pk->chk = *cp++&0377;        /* data checksum lsb */
  993. X    chkhdr ^= *cp;
  994. X    pk->chk |= (*cp++&0377)<<8;    /* data checksum msb */
  995. X    chkhdr ^= pk->c = *cp++;            /* control packet or data */
  996. X    if (ok = (chkhdr == *cp))
  997. X    DEBUG(9,"rcv: %o\n",pk->c&0377);
  998. X    return(!ok);                /* check the checksum */
  999. X}
  1000. X
  1001. X/* readdata - read data segment and check data checksum */
  1002. X
  1003. Xstatic int readdata(fd,pk)
  1004. Xint fd;
  1005. Xregister Packet *pk;
  1006. X{
  1007. X    if (seglen[pk->k] > pk->len) {
  1008. X    DEBUG(7,"rcv: data %d bytes too big\n",seglen[pk->k]);
  1009. X    return(1);
  1010. X    } else {
  1011. X    register int i;
  1012. X    DEBUG(9,"rcv: data %d bytes\n",pk->len = seglen[pk->k]);
  1013. X    for (i = 0; i < pk->len; i++) {
  1014. X        READ(fd,&pk->data[i],1);
  1015. X    }
  1016. X    return(pk->chk+(chksum(pk->data,pk->len)^(pk->c&0377)) != MAGIC);
  1017. X    }
  1018. X}
  1019. X
  1020. X/* clkint - tiny time-out routine */
  1021. X
  1022. Xstatic int clkint()
  1023. X{
  1024. X    DEBUG(9,"rcv: timed out\n","");
  1025. X    longjmp(timebuf,1);
  1026. X    /* NOTREACHED */
  1027. X}
  1028. X
  1029. X/* chksum - unix packet driver checksum algorithm */
  1030. X
  1031. Xstatic int chksum(s,n)
  1032. Xregister char *s;
  1033. Xregister n;
  1034. X{
  1035. X    register short sum;
  1036. X    register unsigned short t;
  1037. X    register short x;
  1038. X
  1039. X    sum = -1;
  1040. X    x = 0;
  1041. X    do {
  1042. X    if (sum < 0) {
  1043. X        sum <<= 1;
  1044. X        sum++;
  1045. X    } else
  1046. X        sum <<= 1;
  1047. X    t = sum;
  1048. X    sum += (unsigned)*s++ & 0377;
  1049. X    x += sum ^ n;
  1050. X    if ((unsigned short)sum <= t) {
  1051. X        sum ^= x;
  1052. X    }
  1053. X    } while (--n > 0);
  1054. X
  1055. X    return(sum);
  1056. X}
  1057. END_OF_main/gphys.c
  1058. if test 6844 -ne `wc -c <main/gphys.c`; then
  1059.     echo shar: \"main/gphys.c\" unpacked with wrong size!
  1060. fi
  1061. # end of overwriting check
  1062. fi
  1063. if test -f main/gpres.c -a "${1}" != "-c" ; then 
  1064.   echo shar: Will not over-write existing file \"main/gpres.c\"
  1065. else
  1066. echo shar: Extracting \"main/gpres.c\" \(6380 characters\)
  1067. sed "s/^X//" >main/gpres.c <<'END_OF_main/gpres.c'
  1068. X/*++
  1069. X/* NAME
  1070. X/*    gpres.c 3
  1071. X/* SUMMARY
  1072. X/*    g-protocol general interface
  1073. X/* PROJECT
  1074. X/*    pc-mail
  1075. X/* PACKAGE
  1076. X/*    cico
  1077. X/* SYNOPSIS
  1078. X/*    int gopen(fd);
  1079. X/*    int fd;
  1080. X/*
  1081. X/*    int gwrite(fd,buf,len)
  1082. X/*    int fd,len;
  1083. X/*    char *buf;
  1084. X/*
  1085. X/*    int gread(fd,buf,len)
  1086. X/*    int fd,len;
  1087. X/*    char *buf;
  1088. X/*
  1089. X/*    int gclose(fd)
  1090. X/*    int fd;
  1091. X/* DESCRIPTION
  1092. X/*    The functions in this module present an interface that closely
  1093. X/*    resembles the unix kernel i/o interface.
  1094. X/*
  1095. X/*    gopen() handles the initial message exchange. fd should be
  1096. X/*    connected to a tty line. gopen() normally returns a zero value.
  1097. X/*
  1098. X/*    gwrite() returns the number of bytes `written' to the remote system.
  1099. X/*    It should be considered an error if this is not equal to the number
  1100. X/*    of bytes requested.
  1101. X/*    A zero-length write should be used to indicate EOF during file transfer.
  1102. X/*
  1103. X/*    gread() returns the requested number of bytes or the number of
  1104. X/*    bytes sent by the remote system, whichever is smaller.
  1105. X/*    A zero-length read indicates EOF during file transfer.
  1106. X/*
  1107. X/*    gclose() shuts the protocol down, but does not otherwise change
  1108. X/*    communications line parameters. It normally returns a zero value.
  1109. X/* FUNCTIONS AND MACROS
  1110. X/*    galloc(), gfree(), gsproto(), grproto()
  1111. X/* DIAGNOSTICS
  1112. X/*    All functions return -1 in case of unrecoverable problems.
  1113. X/* BUGS
  1114. X/*    All g protocol routines assume that the XON/XOFF flow control
  1115. X/*    has been turned off.
  1116. X/*    Some parts of the code rely on 8-bit bytes, 16-bit short integers.
  1117. X/* AUTHOR(S)
  1118. X/*    W.Z. Venema
  1119. X/*    Eindhoven University of Technology
  1120. X/*    Department of Mathematics and Computer Science
  1121. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1122. X/* CREATION DATE
  1123. X/*    Sun Apr 19 12:41:37 GMT+1:00 1987
  1124. X/* LAST MODIFICATION
  1125. X/*    90/01/22 13:01:43
  1126. X/* VERSION/RELEASE
  1127. X/*    2.1
  1128. X/*--*/
  1129. X
  1130. X#include <setjmp.h>
  1131. X#include "gp.h"
  1132. X
  1133. X/* local and forward declarations */
  1134. X
  1135. Xstatic jmp_buf failbuf;
  1136. Xstatic void gpeek(),gpoke(),memcpy();
  1137. X
  1138. X/* gfail - exception handling */
  1139. X
  1140. Xvoid gfail()
  1141. X{
  1142. X    longjmp(failbuf,1);
  1143. X}
  1144. X
  1145. X/* gopen - not quite an analogon of unix open(2) */
  1146. X
  1147. Xint gopen(fd)
  1148. Xint fd;
  1149. X{
  1150. X    return(ginit(fd));        /* do packet stuff elsewhere */
  1151. X}
  1152. X
  1153. X/* gwrite - g-protocol analogon of unix write(2) */
  1154. X
  1155. Xgwrite(fd,data,len)
  1156. Xint fd,len;
  1157. Xchar *data;
  1158. X{
  1159. X    /* set up exception handling */
  1160. X
  1161. X    if (setjmp(failbuf))            /* in case gsproto fails */
  1162. X    return(FAIL);                /* it just did */
  1163. X
  1164. X    /* handle special case of zero-length writes separately */
  1165. X
  1166. X    if (len <= 0) {                /* end-of-file message */
  1167. X    register Packet *pk = galloc();        /* allocate output packet */
  1168. X    gpoke(pk,data,len);            /* make null-data packet */
  1169. X    gsproto(fd,pk);                /* send to other side */
  1170. X    } else {                    /* true data message */
  1171. X    register int shot;            /* quantum size */
  1172. X    register int rest;            /* amount left to do */
  1173. X    for (rest = len; rest > 0; rest -= shot,data += shot) {
  1174. X        register Packet *pk = galloc();    /* allocate output packet */
  1175. X        gpoke(pk,data,shot = MIN(pk->len,rest));/* fill the packet */
  1176. X        gsproto(fd,pk);
  1177. X    }
  1178. X    }
  1179. X    return(len);                /* no problems detected */
  1180. X}
  1181. X
  1182. X/* gread - g-protocol analogon of unix read(2) */
  1183. X
  1184. Xgread(fd,data,len)
  1185. Xint fd,len;
  1186. Xchar *data;
  1187. X{
  1188. X    static Packet *pk;                /* our byte stock */
  1189. X    register int igot;                /* our return value */
  1190. X
  1191. X    /* set up exception handling */
  1192. X
  1193. X    if (setjmp(failbuf))            /* in case grproto fails */
  1194. X    return(FAIL);                /* it just did */
  1195. X
  1196. X    /* if no bytes in stock, get some fresh ones and see how much we got */
  1197. X
  1198. X    if (pk == 0 || pk->segl <= 0)        /* we are out of data */
  1199. X    gpeek(pk = grproto(fd));        /* get fresh packet */
  1200. X
  1201. X    /* return as many bytes as asked, or as in stock, whichever is less */
  1202. X
  1203. X    if ((igot = MIN(len,pk->segl)) > 0) {
  1204. X    memcpy(data,pk->segp,igot);        /* copy to caller's buffer */
  1205. X    pk->segp += igot;            /* update stock pointer */
  1206. X    pk->segl -= igot;            /* update stock count */
  1207. X    }
  1208. X    if (pk->segl <= 0)                /* if we exhausted the stock */
  1209. X    gfree(pk);                /* release packet */
  1210. X    return(igot);                /* no problems detected */
  1211. X}
  1212. X
  1213. X/* gclose - turn g protocol off */
  1214. X
  1215. Xgclose(fd)
  1216. Xint fd;
  1217. X{
  1218. X    return(gfinit(fd));                /* not here! */
  1219. X}
  1220. X
  1221. X/* 
  1222. X* "Each transmitter is constrained to observe the maximum data segment"
  1223. X* "size established during initial synchronization by the receiver that"
  1224. X* "it sends to. (...) `short' packets have zero or more data bytes but less"
  1225. X* "than the maximum. The first one or two bytes of the data segment of"
  1226. X* "a short packet are `count' bytes that indicate the difference between"
  1227. X* "the maximum size and the number of bytes in the short segment. If the"
  1228. X* "difference is less than 127, one count byte is used. If the difference"
  1229. X* "exceeds 127, then the low-order seven bits of the difference are put"
  1230. X* "in the first data byte and the remaining high-order bit is set as an"
  1231. X* "indication that the remaining bits of the difference are in the second"
  1232. X* "byte.
  1233. X*/
  1234. X
  1235. X/* gpoke - prepare packet for transmission */
  1236. X
  1237. Xstatic void gpoke(pk,data,len)
  1238. Xregister Packet *pk;
  1239. Xint len;
  1240. Xchar *data;
  1241. X{
  1242. X    register int diff = pk->len-len;        /* packet/data size mismatch */
  1243. X
  1244. X    pk->segp = pk->data;            /* set up write pointer */
  1245. X    pk->segl = len;                /* actual segment length */
  1246. X    if (diff < 0 || len < 0) {
  1247. X    DEBUG(7,"gpoke: trouble\n","");        /* something very wrong */
  1248. X    gfail();
  1249. X    /* NOTREACHED */
  1250. X    } else if (diff == 0) {
  1251. X    pk->c = DATA;                /* long data segment */
  1252. X    } else if (diff <= 127) {
  1253. X    pk->c = SHORT;                /* short data segment */
  1254. X    *pk->segp++ = diff;            /* one difference byte */
  1255. X    } else if (diff > 127) {
  1256. X    pk->c = SHORT;                /* tiny data segment */
  1257. X    *pk->segp++ = diff|0200;        /* two difference bytes */
  1258. X    *pk->segp++ = diff>>7;
  1259. X    }
  1260. X    memcpy(pk->segp,data,pk->segl);        /* copy data into packet */
  1261. X}
  1262. X
  1263. X/* gpeek - prepare newly packet for reading */
  1264. X
  1265. Xstatic void gpeek(pk)
  1266. Xregister Packet *pk;
  1267. X{
  1268. X    register int diff;
  1269. X
  1270. X    pk->segp = pk->data;            /* set up read pointer */
  1271. X    if (TYPE(pk->c) == DATA) {
  1272. X    diff = 0;                /* long data segment */
  1273. X    } else if (TYPE(pk->c) != SHORT) {
  1274. X    DEBUG(7,"gread: trouble\n","");        /* something funny */
  1275. X    gfail();
  1276. X    /* NOTREACHED */
  1277. X    } else if ((diff = *pk->segp++&0377)&0200) {/* short data segment */
  1278. X    diff = (diff&0177)|((*pk->segp++&0377)<<7);
  1279. X    }
  1280. X    pk->segl = pk->len-diff;            /* actual segment size */
  1281. X    DEBUG(9,"rcv: data %d bytes\n",pk->segl);
  1282. X}
  1283. X
  1284. X/* memcpy - not-so-efficient implementation */
  1285. X
  1286. Xstatic void memcpy(dst,src,len)
  1287. Xregister char *dst,*src;
  1288. Xregister int len;
  1289. X{
  1290. X    while (len-- > 0)
  1291. X    *dst++ = *src++;
  1292. X}
  1293. END_OF_main/gpres.c
  1294. if test 6380 -ne `wc -c <main/gpres.c`; then
  1295.     echo shar: \"main/gpres.c\" unpacked with wrong size!
  1296. fi
  1297. # end of overwriting check
  1298. fi
  1299. if test -f main/mbox.c -a "${1}" != "-c" ; then 
  1300.   echo shar: Will not over-write existing file \"main/mbox.c\"
  1301. else
  1302. echo shar: Extracting \"main/mbox.c\" \(6112 characters\)
  1303. sed "s/^X//" >main/mbox.c <<'END_OF_main/mbox.c'
  1304. X/*++
  1305. X/* NAME
  1306. X/*      mbox 3
  1307. X/* SUMMARY
  1308. X/*      display and manipulate one non-work message
  1309. X/* PROJECT
  1310. X/*      pc-mail
  1311. X/* PACKAGE
  1312. X/*      mail
  1313. X/* SYNOPSIS
  1314. X/*      int mbox(meta,msgid)
  1315. X/*    int meta;
  1316. X/*    unsigned msgid;
  1317. X/* DESCRIPTION
  1318. X/*      mbox() is invoked when the user has selected a non-work mail message.
  1319. X/*    It instructs the pager to display the selected mail message. 
  1320. X/*      The user has the usual options for manipulating the message
  1321. X/*    being displayed.
  1322. X/*
  1323. X/*    The meta parameter indicates the message type,
  1324. X/*    and msgid is the numerical message id. If the message file is being
  1325. X/*    read for the first time (meta == NEW_META), it will be marked as read
  1326. X/*    by renaming the meta file.
  1327. X/*
  1328. X/*    Message header lines can be suppressed selectively (see setup).
  1329. X/* FILES
  1330. X/*      $MAILDIR/?nnnnn, message and meta files
  1331. X/* SEE ALSO
  1332. X/*      pager(3), pager(5), kbdinp(3)
  1333. X/* DIAGNOSTICS
  1334. X/*      If a selected mail message could not be found an error message
  1335. X/*      is displayed instead.
  1336. X/* AUTHOR(S)
  1337. X/*      W.Z. Venema
  1338. X/*      Eindhoven University of Technology
  1339. X/*      Department of Mathematics and Computer Science
  1340. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1341. X/* CREATION DATE
  1342. X/*      Sun Apr  5 13:01:12 GMT+1:00 1987
  1343. X/* LAST MODIFICATION
  1344. X/*    90/01/22 13:02:11
  1345. X/* VERSION/RELEASE
  1346. X/*    2.1
  1347. X/*--*/
  1348. X
  1349. X#include <stdio.h>
  1350. X#include <ctype.h>
  1351. X
  1352. X#include "defs.h"
  1353. X#include "path.h"
  1354. X#include "pager.h"
  1355. X#include "screen.h"
  1356. X#include "mail.h"
  1357. X#include "ascf.h"
  1358. X#include "params.h"
  1359. X#include "ms_parse.h"
  1360. X
  1361. X /*
  1362. X  * Storage for header lines to be ignored. Both the strings with header
  1363. X  * names, and the pointers to these strings, are kept together.
  1364. X  */
  1365. X
  1366. Xstruct ignore {
  1367. X    char    strs[BUFSIZ];        /* null-terminated strings */
  1368. X    char   *ptrs[BUFSIZ / 2];        /* null-terminated list of pointers */
  1369. X};
  1370. X
  1371. Xhidden void ign_init();            /* forward declarations */
  1372. Xhidden int ign_header();
  1373. Xhidden int mbox_filter();
  1374. X
  1375. Xhidden File *letter = 0;        /* pager file */
  1376. X
  1377. X/* show_letter - display selected mail message */
  1378. X
  1379. Xhidden int show_letter()
  1380. X{
  1381. X    set_pager(letter);                /* select message display */
  1382. X    ds_pager();                    /* put it on the screen */
  1383. X    return (0);                    /* say screen is ok */
  1384. X}
  1385. X
  1386. X/* mbox - user has selected a message file */
  1387. X
  1388. Xpublic int mbox(meta, id)
  1389. Xint     meta;
  1390. Xunsigned id;
  1391. X{
  1392. X    static Screen screen[] = {
  1393. X    'C',    "Close",0,        initscreen,
  1394. X    'D',    "Delete",delete,    delcurr,
  1395. X    'M',    "Mail",    mailfile,    "Mail a copy of this message",
  1396. X    'P',    "Print",print,        printcurr,
  1397. X    'R',    "Reply",reply,        "Create reply to sender",
  1398. X    'S',    "Save",    save,        "Save this message to ordinary file",
  1399. X    'W',    "Work",    makework,    "Save this message to work file",
  1400. X    '|',    "|",    filter,        "Filter this message through command",
  1401. X    PGUP,    PgUp,    pu_pager,    pageup,
  1402. X    PGDN,    PgDn,    pd_pager,    pagedn,
  1403. X    UP,    "Up",    up_pager,    csrup,
  1404. X    DOWN,    "Down",    dn_pager,    csrdn,
  1405. X    0,    0,    show_letter,    "(Reading a mail message)",
  1406. X    };
  1407. X    char   *seen;
  1408. X
  1409. X    /* 
  1410. X     * Mail being read for the first time is renamed to reflect the
  1411. X     * status change.
  1412. X     */
  1413. X
  1414. X    if (mbox_filter(letter = open_pager(), message)) {
  1415. X    mesg_pager(letter, m_msgread);        /* no file or read error */
  1416. X    } else if (meta != NEW_META) {        /* unread message? */
  1417. X     /* void */ ;                /* no */
  1418. X    } else if (rename(comment, seen = old_meta(id)) == 0) {
  1419. X    strcpy(comment, seen);            /* mark message as read */
  1420. X    junk_desk();                /* say desk-top outdated */
  1421. X    }
  1422. X    kbdinp(screen);                /* look at the screen */
  1423. X    close_pager(letter), letter = 0;        /* destroy the display */
  1424. X    return (S_REDRAW);                /* force screen redrawing */
  1425. X}
  1426. X
  1427. X/* mbox_filter - suppress some message-header lines */
  1428. X
  1429. Xhidden int mbox_filter(pp, path)
  1430. XFile   *pp;
  1431. Xchar   *path;
  1432. X{
  1433. X#if (defined(lint) && defined(iAPX286))
  1434. X    static
  1435. X#endif
  1436. X    struct ignore ignore;
  1437. X    FILE   *fp;
  1438. X
  1439. X    if ((fp = ascopen(path, "r")) == 0) {
  1440. X    return (1);
  1441. X    } else {
  1442. X    char    buf[BUFSIZ];
  1443. X    int     ig_flag = 0;
  1444. X    int     ret;
  1445. X    int     context = MS_UUCP;
  1446. X
  1447. X    ign_init(&ignore);            /* initialize filter */
  1448. X
  1449. X    /*
  1450. X     * The header-line suppression algorithm is effective for RFC822-like
  1451. X     * headers lines only. Its main use is to get rid of the "Received:"
  1452. X     * lines that frequently show up in non-local mail.
  1453. X     */
  1454. X
  1455. X    while (ascgets(buf, sizeof(buf), fp)) {
  1456. X        switch (context = ms_parse(context, buf)) {
  1457. X        case MS_UUCP:
  1458. X        app_pager(pp, buf);
  1459. X        break;
  1460. X        case MS_HEADER:
  1461. X        if ((ig_flag = (ign_header(buf, &ignore))) == 0)
  1462. X            app_pager(pp, buf);
  1463. X        break;
  1464. X        case MS_CONT:
  1465. X        if (ig_flag == 0)
  1466. X            app_pager(pp, buf);
  1467. X        break;
  1468. X        case MS_BODY:
  1469. X        app_pager(pp, buf);
  1470. X        break;
  1471. X        }
  1472. X    }
  1473. X    ret = ferror(fp);
  1474. X    ascclose(fp);
  1475. X    return (ret);
  1476. X    }
  1477. X}
  1478. X
  1479. X/* ign_init - setup header lines to be ignored */
  1480. X
  1481. Xhidden void ign_init(ig)
  1482. Xstruct ignore *ig;
  1483. X{
  1484. X    Info   *ip = getparams() + P_IGNORE;/* what to ignore */
  1485. X    char   *sp = ":, ";            /* string separators */
  1486. X    char  **lp = ig->ptrs;        /* separated strings */
  1487. X
  1488. X    /*
  1489. X     * This function takes, from the pc-mail setup file, a (blank or
  1490. X     * comma)-separated list with names of mail headers to be ignored when a
  1491. X     * message is displayed. The list of names is broken up into separate
  1492. X     * strings. The result, a null-terminated list of string pointers, is
  1493. X     * stored in the ig argument. We use strtok() for string splitting. Since
  1494. X     * that function destroys its input, and since the user may change the
  1495. X     * setup at any time, we keep in the ig argument a copy of the relevant
  1496. X     * setup information.
  1497. X     */
  1498. X
  1499. X    if (ip->strval == 0) {            /* nothing to ignore */
  1500. X    *lp = 0;
  1501. X    } else {                    /* copy, then split */
  1502. X    (void) strncpy(ig->strs, ip->strval, sizeof(ig->strs));
  1503. X    for (*lp = strtok(ig->strs, sp); *lp; *lp = strtok((char *) 0, sp))
  1504. X        lp++;
  1505. X    }
  1506. X}
  1507. X
  1508. X/* ign_header - do we ignore this header line */
  1509. X
  1510. Xhidden int ign_header(buf, ig)
  1511. Xregister char *buf;
  1512. Xstruct ignore *ig;
  1513. X{
  1514. X    register int l;            /* header name length */
  1515. X    register char **list;        /* ptr to ignored header names */
  1516. X
  1517. X    /* Make sure that the header name is followed by a colon */
  1518. X
  1519. X    for (list = ig->ptrs; *list; list++) {
  1520. X    if (buf[l = strlen(*list)] == ':' && istrncmp(buf, *list, l) == 0)
  1521. X        return (1);
  1522. X    }
  1523. X    return (0);
  1524. X}
  1525. END_OF_main/mbox.c
  1526. if test 6112 -ne `wc -c <main/mbox.c`; then
  1527.     echo shar: \"main/mbox.c\" unpacked with wrong size!
  1528. fi
  1529. # end of overwriting check
  1530. fi
  1531. if test -f main/nmail.c -a "${1}" != "-c" ; then 
  1532.   echo shar: Will not over-write existing file \"main/nmail.c\"
  1533. else
  1534. echo shar: Extracting \"main/nmail.c\" \(6579 characters\)
  1535. sed "s/^X//" >main/nmail.c <<'END_OF_main/nmail.c'
  1536. X/*++
  1537. X/* NAME
  1538. X/*      nmail
  1539. X/* SUMMARY
  1540. X/*      extract originator and subject from new mail received by cico
  1541. X/* PROJECT
  1542. X/*      pc-mail
  1543. X/* PACKAGE
  1544. X/*      nmail
  1545. X/* SYNOPSIS
  1546. X/*      nmail [-d debuglevel]
  1547. X/* DESCRIPTION
  1548. X/*      nmail searches for new mail files received by cico and extracts
  1549. X/*    the originator's name, and message subject for later use by the 
  1550. X/*    mail visual shell.
  1551. X/*
  1552. X/*     Return address formats we understand (in order of preference):
  1553. X/* .nf
  1554. X/*
  1555. X/*    From: address (full_name)    (take full_name)
  1556. X/*    From: full_name <address>    (take full_name)
  1557. X/*    From: address            (take address)
  1558. X/*    >From address            (take address)
  1559. X/*    From address            (take address)
  1560. X/*
  1561. X/* .fi
  1562. X/*      To avoid tampering, new files will have read-only permission.
  1563. X/*
  1564. X/*      In order to avoid corruption, control-c interrupts are disabled
  1565. X/*    while this program executes.
  1566. X/* FILES
  1567. X/*      In the spool directory:
  1568. X/*    n<seqno>    received mail message
  1569. X/*    h<seqno>    extracted originator name, subject
  1570. X/* SEE ALSO
  1571. X/*      path(5)         spool directory, file names
  1572. X/*      cico(1)         network process
  1573. X/*      mail(1)       visual mail shell
  1574. X/* DIAGNOSTICS
  1575. X/*      Exit status zero when no errors were detected, nonzero in case of file
  1576. X/*      access errors. See status(5) for error codes.
  1577. X/* AUTHOR(S)
  1578. X/*      W.Z. Venema
  1579. X/*      Eindhoven University of Technology
  1580. X/*      Department of Mathematics and Computer Science
  1581. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1582. X/* CREATION DATE
  1583. X/*      Tue Mar 31 20:14:11 GMT+1:00 1987
  1584. X/* LAST MODIFICATION
  1585. X/*    90/01/22 13:02:20
  1586. X/* VERSION/RELEASE
  1587. X/*    2.1
  1588. X/*--*/
  1589. X
  1590. X#include <stdio.h>
  1591. X#include <signal.h>
  1592. X#include <time.h>
  1593. X#include <ctype.h>
  1594. X#include <varargs.h>
  1595. X
  1596. X#include "defs.h"
  1597. X#include "ndir.h"
  1598. X#include "path.h"
  1599. X#include "status.h"
  1600. X#include "ms_parse.h"
  1601. X
  1602. Xextern struct tm *localtime();        /* system functions */
  1603. X
  1604. Xhidden void parse_args();        /* forward declarations */
  1605. Xhidden void newmail();
  1606. Xhidden void extract();
  1607. Xhidden void usage();
  1608. X
  1609. Xhidden int dflag = 0;            /* debugging option */
  1610. X
  1611. X#define debug    if (dflag) printf
  1612. X
  1613. Xpublic char *progname = "nmail";
  1614. X
  1615. Xmain(argc, argv)
  1616. Xint     argc;
  1617. Xchar  **argv;
  1618. X{
  1619. X    signal(SIGINT, SIG_IGN);            /* disable ctrl-c */
  1620. X    parse_args(argc, argv);            /* parse command args */
  1621. X    if (pathinit())                /* get path info */
  1622. X    exit(E_NOSPOOL);            /* bad MAILDIR variable */
  1623. X    umask(0222);                /* make files read-only */
  1624. X    newmail();                    /* get headers from new mail */
  1625. X    exit(0);
  1626. X    /* NOTREACHED */
  1627. X}
  1628. X
  1629. X/* parse_args - process command-line arguments */
  1630. X
  1631. Xhidden void parse_args(argc, argv)
  1632. Xint     argc;
  1633. Xchar  **argv;
  1634. X{
  1635. X    while (--argc && *++argv && **argv == '-') {/* process options */
  1636. X    switch (*++*argv) {
  1637. X    case 'd':                /* turn debugging on */
  1638. X        if (--argc == 0)
  1639. X        usage("missing debugging level argument");
  1640. X        if ((dflag = atoi(*++argv)) < 0 || dflag > 9)
  1641. X        dflag = 0;
  1642. X        break;
  1643. X    default:                /* unknown option */
  1644. X        usage("invalid option: -%c", **argv);
  1645. X        break;
  1646. X    }
  1647. X    }
  1648. X
  1649. X    /* check for extraneous arguments */
  1650. X
  1651. X    if (argc > 0)
  1652. X    usage("unexpected argument: %s", *argv);
  1653. X}
  1654. X
  1655. X/* scan for new mail that hasn't gotten yet a metafile */
  1656. X
  1657. Xhidden void newmail()
  1658. X{
  1659. X    register DIR *dp;
  1660. X    struct direct *de;
  1661. X    unsigned msgno;
  1662. X
  1663. X    debug("directory: \"%s\"\n", maildir);
  1664. X
  1665. X    /*
  1666. X     * Scan the spool directory for newly-arrived mail.
  1667. X     * 
  1668. X     * Incoming mail message files have a name of "n<seqno>". The originator
  1669. X     * name is normally present in files with names "h<seqno>" or "o<seqno>".
  1670. X     * The presence of an "o" file implies that the file "n<seqno>" has been
  1671. X     * read by the user. An "h" file means that the user has not yet read the
  1672. X     * message file.
  1673. X     * 
  1674. X     * If a message file has no corresponding "h" or "o" file we assume it is a
  1675. X     * new mail message and create an "h" file with the name of the
  1676. X     * originator and the subject of the message.
  1677. X     */
  1678. X
  1679. X    if ((dp = opendir(maildir)) == 0)
  1680. X    exit(E_NOSPOOL);
  1681. X
  1682. X    while (de = readdir(dp)) {
  1683. X    debug("nmail: file \"%s\"\n", de->d_name);
  1684. X    if (de->d_name[0] == NEW_MESG
  1685. X        && (msgno = seqno(de->d_name))) {
  1686. X        if (access(old_meta(msgno), 4) == 0) {
  1687. X         /* already marked as read */ ;
  1688. X        } else if (access(new_meta(msgno), 4) == 0) {
  1689. X         /* already marked as unread */ ;
  1690. X        } else {                /* create meta file */
  1691. X        extract(new_mesg(msgno), new_meta(msgno));
  1692. X        }
  1693. X    }
  1694. X    }
  1695. X    closedir(dp);
  1696. X}
  1697. X
  1698. X/* extract - extract originator and subject info from mail file to meta file */
  1699. X
  1700. Xhidden void extract(mail, meta)
  1701. Xchar   *mail;
  1702. Xchar   *meta;
  1703. X{
  1704. X    FILE   *mesgfp,
  1705. X           *metafp;
  1706. X    char    line[MAXLINE];
  1707. X    char    from[MAXLINE];            /* name of sender */
  1708. X    char    subj[MAXLINE];            /* message subject */
  1709. X    int     context = MS_UUCP;
  1710. X
  1711. X    debug("-- \"%s\" -> \"%s\"\n", mail, meta);
  1712. X
  1713. X    if ((mesgfp = fopen(mail, "r")) == NULL)    /* cannot open existing file */
  1714. X    exit(E_SYSFAIL);
  1715. X
  1716. X    strcpy(from, "Somewhere");            /* default originator */
  1717. X    subj[0] = '\0';                /* initialize subject */
  1718. X
  1719. X    /*
  1720. X     * Some mailers generate real headers, separated from the message body by
  1721. X     * an empty line. So we stop when we find an empty line. Other mailers
  1722. X     * have no headers, so we stop when we see no header line. The following
  1723. X     * algorithm tries to extract the real user name if possible, otherwise
  1724. X     * it takes whatever it can get.
  1725. X     */
  1726. X
  1727. X    while ((context != MS_BODY) && fgets(line, sizeof(line), mesgfp)) {
  1728. X    switch (context = ms_parse(context, line)) {
  1729. X    case MS_UUCP:
  1730. X        if (sscanf(line, "%*[>] From %s", from) != 1)
  1731. X        (void) sscanf(line, "From %s", from);
  1732. X        break;
  1733. X    case MS_HEADER:
  1734. X        if (hscanf(line, "Subject:", " %[^\n]", subj) == 0
  1735. X        && hscanf(line, "From:", " %*s ( %[^)] )", from) == 0)
  1736. X        (void) hscanf(line, "From:", " %[^<] <", from);
  1737. X        break;
  1738. X    }
  1739. X    }
  1740. X
  1741. X    /* carefully check all went well */
  1742. X
  1743. X    if (ferror(mesgfp))                /* sorry, read problem */
  1744. X    exit(E_READERR);
  1745. X    if ((metafp = fopen(meta, "w")) == NULL)    /* cannot create metafile */
  1746. X    exit(E_WRITERR);
  1747. X    fprintf(metafp, "%s\n%s\n", from, subj);    /* write originator, subject */
  1748. X    if (ferror(metafp)) {
  1749. X    (void) fclose(metafp);            /* ms-dog needs this! */
  1750. X    (void) chmod(meta, 0666);        /* sorry, write problem */
  1751. X    (void) unlink(meta);            /* delete metafile */
  1752. X    exit(E_WRITERR);
  1753. X    }
  1754. X    (void) fclose(mesgfp);
  1755. X    (void) fclose(metafp);
  1756. X}
  1757. X
  1758. X/* usage - explain what is wrong */
  1759. X
  1760. X/* VARARGS */
  1761. X
  1762. Xhidden void usage(va_alist) 
  1763. Xva_dcl
  1764. X{
  1765. X    va_list ap;
  1766. X    char   *fmt;
  1767. X
  1768. X    va_start(ap);
  1769. X    fmt = va_arg(ap, char *);
  1770. X    vfprintf(stderr, fmt, ap);
  1771. X    va_end(ap);
  1772. X    fprintf(stderr, "\nusage: nmail [-d debugging_level]\n");
  1773. X    exit(2);
  1774. X}
  1775. END_OF_main/nmail.c
  1776. if test 6579 -ne `wc -c <main/nmail.c`; then
  1777.     echo shar: \"main/nmail.c\" unpacked with wrong size!
  1778. fi
  1779. # end of overwriting check
  1780. fi
  1781. if test -f main/startup.c -a "${1}" != "-c" ; then 
  1782.   echo shar: Will not over-write existing file \"main/startup.c\"
  1783. else
  1784. echo shar: Extracting \"main/startup.c\" \(6115 characters\)
  1785. sed "s/^X//" >main/startup.c <<'END_OF_main/startup.c'
  1786. X/*++
  1787. X/* NAME
  1788. X/*      startup 3
  1789. X/* SUMMARY
  1790. X/*      startup/terminate network protocol
  1791. X/* PROJECT
  1792. X/*      pc-mail
  1793. X/* PACKAGE
  1794. X/*      cico
  1795. X/* SYNOPSIS
  1796. X/*      startproto()
  1797. X/*
  1798. X/*      endproto()
  1799. X/* DESCRIPTION
  1800. X/*      startproto() should be called after a successfull login on a remote
  1801. X/*      host. It performs the primary handshake with the other system
  1802. X/*      (call accepted/locked) and negotiates a communications protocol.
  1803. X/*      It then sets the function pointers Close/Read/Write to the
  1804. X/*      appropriate values. Until endproto() is called, all i/o to the
  1805. X/*      remote host should proceed through the functions pointed to by
  1806. X/*      Read/Write.
  1807. X/*
  1808. X/*      endproto() turns the protocol off, and sends the silly "OO" message
  1809. X/*      to the remote system. It does not disconnect, nor does it change
  1810. X/*      the state of the communications port.
  1811. X/* FUNCTIONS AND MACROS
  1812. X/*      xgetc(), xwrite(), trap()
  1813. X/* DIAGNOSTICS
  1814. X/*      The process of negotiation is shown when debugging is enabled.
  1815. X/*      startproto() and endproto() return 0 in case of success, E_LOST
  1816. X/*      if no response arrived and E_REJECT if the response differed
  1817. X/*      from the expected response.
  1818. X/* BUGS
  1819. X/*      startproto() assumes that the local system is the calling system.
  1820. X/* AUTHOR(S)
  1821. X/*      W.Z. Venema
  1822. X/*      Eindhoven University of Technology
  1823. X/*      Department of Mathematics and Computer Science
  1824. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1825. X/* CREATION DATE
  1826. X/*      Fri Mar 27 13:43:00 GMT+1:00 1987
  1827. X/* LAST MODIFICATION
  1828. X/*    90/01/22 13:02:41
  1829. X/* VERSION/RELEASE
  1830. X/*    2.1
  1831. X/*--*/
  1832. X
  1833. X#include <stdio.h>
  1834. X#include <setjmp.h>
  1835. X
  1836. X#include "defs.h"
  1837. X#include "params.h"
  1838. X#include "comm.h"
  1839. X#include "logs.h"
  1840. X#include "status.h"
  1841. X#include "sysdep.h"
  1842. X
  1843. X/* forward declarations */
  1844. X
  1845. Xhidden char *xpct();            /* expect a string */
  1846. Xhidden char *send();            /* send a string */
  1847. X
  1848. X/* the functions that inplement the various protocols */
  1849. X
  1850. Xextern  kopen(), kclose(), kread(), kwrite();    /* k protocol */
  1851. Xextern  gopen(), gclose(), gread(), gwrite();    /* g protocol */
  1852. X
  1853. Xtypedef struct proto {
  1854. X    char    name;            /* name of the protocol */
  1855. X    int     (*open) ();            /* the open function */
  1856. X    int     (*close) ();        /* the close function */
  1857. X    int     (*read) ();            /* the read function */
  1858. X    int     (*write) ();        /* the write function */
  1859. X};
  1860. X
  1861. X/* the order of protocols is significant! */
  1862. X
  1863. Xhidden struct proto ptbl[] = {
  1864. X    'k', kopen, kclose, kread, kwrite,    /* try this first */
  1865. X    'g', gopen, gclose, gread, gwrite,    /* then this one */
  1866. X    /* add your protocols at the appropriate place */
  1867. X    0,                    /* terminator! */
  1868. X};
  1869. X
  1870. X/* startproto - do primary handshake, establish protocol and turn it on */
  1871. X
  1872. Xpublic  startproto()
  1873. X{
  1874. X    int    *savetrap = systrap;
  1875. X    jmp_buf mytrap;
  1876. X    register struct proto *pp;
  1877. X    register char *cp;
  1878. X    int     status;
  1879. X
  1880. X    if (status = setjmp(systrap = mytrap)) {    /* get here if expect fails */
  1881. X    systrap = savetrap;
  1882. X    return (status);
  1883. X    }
  1884. X    /* the primary handshake: who are we and is it ok we call right now */
  1885. X
  1886. X    sscanf(xpct("Shere"), "Shere=%s", rmthost);    /* try to get host name */
  1887. X    log("SUCCEEDED (call to %s)", rmthost);
  1888. X
  1889. X    /* some uucico implementations seem to have problems with debug level 0 */
  1890. X
  1891. X    send(strcons("S%s -x%d", LOGIN_NAME, MAX(dflag, 1)));
  1892. X    xpct("ROK");                /* we're accepted or rejected */
  1893. X
  1894. X    /* choose a protocol from the list offered by the other side */
  1895. X
  1896. X    for (cp = xpct("P") + 1, pp = ptbl; pp->name && !index(cp, pp->name); pp++)
  1897. X     /* void */ ;
  1898. X    if (pp->name == 0) {            /* no common protocol */
  1899. X    send("UN");
  1900. X    trap(E_REJECT, "FAILED (no common protocol in \"%s\")", cp);
  1901. X    /* NOTREACHED */
  1902. X    }
  1903. X    send(strcons("U%c", pp->name));        /* my choice of protocol */
  1904. X
  1905. X    /* install protocol */
  1906. X
  1907. X    Close = pp->close;                /* for endproto() */
  1908. X    Read = pp->read;
  1909. X    Write = pp->write;
  1910. X    if (pp->open && CALL(pp->open) (ttfd))    /* start up a protocol */
  1911. X    trap(E_LOST, "FAILED (startup)");
  1912. X
  1913. X    /* finish up */
  1914. X
  1915. X    log("OK (startup)");
  1916. X    systrap = savetrap;                /* get here if expect wins */
  1917. X    return (0);
  1918. X}
  1919. X
  1920. X/* endproto - terminate protocol */
  1921. X
  1922. Xpublic  endproto()
  1923. X{
  1924. X    int    *savetrap = systrap;            /* save exception handler */
  1925. X    jmp_buf mytrap;
  1926. X    int     status;
  1927. X
  1928. X    if (Close)                    /* check there is one */
  1929. X    CALL(Close) (ttfd);            /* turn protocol off */
  1930. X    send("OOOOOO");                /* byebye */
  1931. X
  1932. X    /* Don\'t wait for the other side\'s OOOOOO, just sleep and quit. */
  1933. X
  1934. X    (void) sleep(1);
  1935. X    log("OK (conversation complete)");
  1936. X    return (0);
  1937. X}
  1938. X
  1939. X/* send - write message to remote host and return pointer to message */
  1940. X
  1941. Xhidden char *send(str)
  1942. Xchar   *str;
  1943. X{
  1944. X    xwrite(ttfd, "\020", 1);            /* message header */
  1945. X    xwrite(ttfd, str, strlen(str) + 1);        /* include trailing null */
  1946. X    debug(4) ("send: %S\n", str);
  1947. X    return (str);                /* return the message */
  1948. X}
  1949. X
  1950. X/* xpct - read message from host in "^Pmessage[\0\n]" format; trap on errors */
  1951. X
  1952. Xhidden char *xpct(pat)
  1953. Xchar   *pat;
  1954. X{
  1955. X    register int c;
  1956. X    register char *p = msgin;
  1957. X    register int inmsg = 0;
  1958. X
  1959. X    /*
  1960. X     * Keep reading until we time out, or until a complete message has been
  1961. X     * received. Consider the link as lost in case of time out. Assume we are
  1962. X     * rejected if the received message differs from what was expected.
  1963. X     */
  1964. X
  1965. X    debug(4) ("xpct: %S\n", pat);
  1966. X
  1967. X    for (;;) {
  1968. X    if ((c = xgetc()) == EOF) {
  1969. X        trap(E_LOST, "FAILED (protocol handshake)");
  1970. X        /* NOTREACHED */
  1971. X    } else if ((c &= 0177) == '\020') {
  1972. X        debug(4) (" got sync\n");        /* got start of message */
  1973. X        p = msgin;                /* reset */
  1974. X        inmsg = 1;
  1975. X    } else if (inmsg == 0) {    
  1976. X        debug(4) ("%C", c);            /* don\'t store, just debug */
  1977. X    } else if (*p++ = ((c == '\n') ? '\0' : c)) {
  1978. X        debug(4) ("%C", c);            /* store and debug */
  1979. X        if (p >= msgin + MSGBUF) {        /* spurious Ctrl-P seen? */
  1980. X        p = msgin;            /* reset */
  1981. X        inmsg = 0;            /* reset */
  1982. X        }
  1983. X    } else if ((debug(4) ("\n")), strncmp(pat, msgin, strlen(pat)) == 0) {
  1984. X        return (msgin);            /* expect succeeded */
  1985. X    } else {
  1986. X        msgin[30] = '\0';            /* truncate to 30 */
  1987. X        trap(E_REJECT, "FAILED (%S)", msgin);
  1988. X        /* NOTREACHED */
  1989. X    }
  1990. X    }
  1991. X}
  1992. END_OF_main/startup.c
  1993. if test 6115 -ne `wc -c <main/startup.c`; then
  1994.     echo shar: \"main/startup.c\" unpacked with wrong size!
  1995. fi
  1996. # end of overwriting check
  1997. fi
  1998. if test -f main/str.c -a "${1}" != "-c" ; then 
  1999.   echo shar: Will not over-write existing file \"main/str.c\"
  2000. else
  2001. echo shar: Extracting \"main/str.c\" \(6415 characters\)
  2002. sed "s/^X//" >main/str.c <<'END_OF_main/str.c'
  2003. X/*++
  2004. X/* NAME
  2005. X/*    strcons,istrcmp,strvec,vecstr,split 3
  2006. X/* SUMMARY
  2007. X/*    string utility routines
  2008. X/* PROJECT
  2009. X/*    pc-mail
  2010. X/* PACKAGE
  2011. X/*    general stuff
  2012. X/* SYNOPSIS
  2013. X/*    #include "defs.h"
  2014. X/*
  2015. X/*    char *strcons(format,args)
  2016. X/*    char *format;
  2017. X/*
  2018. X/*    char *split(cpp, sep)
  2019. X/*    char **cpp;
  2020. X/*    char *sep;
  2021. X/*
  2022. X/*    int istrncmp(s1,s2,n)
  2023. X/*    char *s1,s2;
  2024. X/*    int n;
  2025. X/*
  2026. X/*    int istrcmp(s1,s2)
  2027. X/*    char *s1,s2;
  2028. X/*
  2029. X/*    char **strvec(string,separ)
  2030. X/*    char *string;
  2031. X/*    char *separ;
  2032. X/*
  2033. X/*    freevec(vec)
  2034. X/*    char **vec;
  2035. X/*
  2036. X/*    char *vecstr(vector,separ)
  2037. X/*    char **vector;
  2038. X/*    char *separ;
  2039. X/* DESCRIPTION
  2040. X/*    strcons() produces a formatted string, using printf()-like
  2041. X/*    arguments. Basically it is an sprintf() that returns a
  2042. X/*    pointer to the result. memory for the result is taken from
  2043. X/*    a small memory pool that is recycled upon successive calls.
  2044. X/*
  2045. X/*    split() searches the string pointed to by cpp for the occurrance
  2046. X/*    of the text token (a string not containing any of the characters
  2047. X/*    given in the "sep" argument). *cpp is updated if a token is
  2048. X/*    found; a null pointer is returned otherwise. This function
  2049. X/*    is an attempt to improve upon the strtok() function, which
  2050. X/*    can parse only one string at a time. It still modifies its
  2051. X/*    arguments, however.
  2052. X/*
  2053. X/*    istrcmp() is a case-insensitive version of the strcmp() function.
  2054. X/*
  2055. X/*    istrncmp() is a case-insensitive version of the strncmp() function.
  2056. X/*
  2057. X/*    strvec() breaks a null-terminated string using the separators given
  2058. X/*    in separ, and returns a null-terminated vector of pointers to the
  2059. X/*    resulting substrings. Memory for the vector and substrings are
  2060. X/*    allocated in dynamic memory. The original string is not modified.
  2061. X/*
  2062. X/*    freevec() frees storage allocated by strvec().
  2063. X/*
  2064. X/*    vecstr() takes a null-terminated vector of string pointers
  2065. X/*    and builds a string from the strings pointed to by the vector
  2066. X/*    argument, separated by the string in the separ argument.
  2067. X/*    Memory for the result is allocated in dynamic memory.
  2068. X/* FUNCTIONS AND MACROS
  2069. X/*    strtok(), malloc(), memcpy(), sprintf()
  2070. X/* DIAGNOSTICS
  2071. X/*    strvec(), vecstr() return a null pointer if there was not enough memory
  2072. X/*    avaliable to hold the result.
  2073. X/* BUGS
  2074. X/*    strcons() does not do smart garbage collection; it just uses
  2075. X/*    a circular buffer. The present implementation is not portable
  2076. X/*    to machines that pass arguments via registers.
  2077. X/*
  2078. X/*    strvec() cannot handle strings with more than BUFSIZ words.
  2079. X/*    strvec() uses strtok(), which may have side effects.
  2080. X/* AUTHOR(S)
  2081. X/*    W.Z. Venema
  2082. X/*    Eindhoven University of Technology
  2083. X/*    Department of Mathematics and Computer Science
  2084. X/*    Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  2085. X/* CREATION DATE
  2086. X/*    Tue Apr  5 20:59:29 MET 1988
  2087. X/* LAST MODIFICATION
  2088. X/*    90/01/22 13:02:43
  2089. X/* VERSION/RELEASE
  2090. X/*    2.1
  2091. X/*--*/
  2092. X
  2093. X#include <stdio.h>
  2094. X#include <ctype.h>
  2095. X#include <varargs.h>
  2096. X
  2097. X#include "defs.h"
  2098. X
  2099. X#define    NBUF    4
  2100. X
  2101. X/* strcons - quick-and-dirty string constructor */
  2102. X
  2103. X/* VARARGS */
  2104. X
  2105. Xchar   *strcons(va_alist) 
  2106. Xva_dcl
  2107. X{
  2108. X    va_list ap;
  2109. X    static char strbuf[NBUF][BUFSIZ];
  2110. X    static int where = 0;
  2111. X    register char *cp;
  2112. X    char   *fmt;
  2113. X
  2114. X    va_start(ap);
  2115. X    fmt = va_arg(ap, char *);
  2116. X    (void) vsprintf(cp = strbuf[where = (where + 1) % NBUF], fmt, ap);
  2117. X    va_end(ap);
  2118. X    return (cp);
  2119. X}
  2120. X
  2121. X/* istrcmp - case-insensitive string comparison */
  2122. X
  2123. X#define    LOW(c)    (isascii(c)&&isupper(c)?tolower(c):(c))
  2124. X
  2125. Xint     istrcmp(s1, s2)
  2126. Xregister char *s1;
  2127. Xregister char *s2;
  2128. X{
  2129. X    while (*s1 && (LOW(*s1) == LOW(*s2)))
  2130. X    s1++, s2++;
  2131. X    return (LOW(*s1) - LOW(*s2));
  2132. X}
  2133. X
  2134. X/* istrncmp - case-insensitive string comparison */
  2135. X
  2136. X#define    LOW(c)    (isascii(c)&&isupper(c)?tolower(c):(c))
  2137. X
  2138. Xint     istrncmp(s1, s2, n)
  2139. Xregister char *s1;
  2140. Xregister char *s2;
  2141. Xregister int n;
  2142. X{
  2143. X    while (n > 0 && *s1 && (LOW(*s1) == LOW(*s2)))
  2144. X    n--, s1++, s2++;
  2145. X    return (n > 0 ? LOW(*s1) - LOW(*s2) : 0);
  2146. X}
  2147. X
  2148. X/* strvec - make vector of substring pointers */
  2149. X
  2150. Xchar  **strvec(str, sep)
  2151. Xchar   *str;
  2152. Xchar   *sep;
  2153. X{
  2154. X#ifdef lint
  2155. X    static
  2156. X#endif
  2157. X    char   *tmp[BUFSIZ];        /* scratch substring pointer storage */
  2158. X    register char **cpp = tmp;
  2159. X    char   *sp;                /* ptr to private copy of original */
  2160. X    register int bytec;
  2161. X
  2162. X    /* make a copy of the original string */
  2163. X
  2164. X    if ((sp = malloc(strlen(str) + 1)) == 0)
  2165. X    return (0);
  2166. X    (void) strcpy(sp, str);
  2167. X
  2168. X    /* chop our copy at sequences of one or more separators */
  2169. X
  2170. X    for (*cpp = strtok(sp, sep); *cpp; *++cpp = strtok((char *) 0, sep))
  2171. X     /* void */ ;
  2172. X
  2173. X    /* now construct the vector of pointers to the substrings */
  2174. X
  2175. X    if ((cpp = (char **) malloc(bytec = (cpp - tmp + 1) * sizeof(*cpp))) == 0)
  2176. X    return (0);
  2177. X    return ((char **) memcpy((char *) cpp, (char *) tmp, bytec));
  2178. X}
  2179. X
  2180. X/* freevec - release storage allocated by strvec() */
  2181. X
  2182. Xfreevec(vec)
  2183. Xchar  **vec;
  2184. X{
  2185. X    free(vec[0]);
  2186. X    free((char *) vec);
  2187. X}
  2188. X
  2189. X/* vecstr - from null-terminated vector of string pointers to one flat string */
  2190. X
  2191. Xpublic char *vecstr(vec, sep)
  2192. Xchar  **vec;
  2193. Xchar   *sep;
  2194. X{
  2195. X    register char **cpp;
  2196. X    register int len = 0;        /* length of final string */
  2197. X    register char *cp;
  2198. X    register int flen = strlen(sep);    /* filler between substrings */
  2199. X
  2200. X    /* find out how big the resulting string will be */
  2201. X
  2202. X    for (cpp = vec; *cpp; cpp++)
  2203. X    len += strlen(*cpp) + flen;
  2204. X
  2205. X    /* allocate and initialize the result string */
  2206. X
  2207. X    if ((cp = malloc(len + 1)) == 0)
  2208. X    return (0);
  2209. X    *cp = '\0';
  2210. X
  2211. X    /* fill the resulting string */
  2212. X
  2213. X    for (cpp = vec; *cpp; cpp++) {
  2214. X    (void) strcat(cp, *cpp);
  2215. X    (void) strcat(cp, sep);
  2216. X    }
  2217. X    return (cp);
  2218. X}
  2219. X
  2220. X/* split - return next token in *cpp, update cpp */
  2221. X
  2222. Xpublic char *split(cpp, sep)
  2223. Xregister char **cpp;
  2224. Xregister char *sep;
  2225. X{
  2226. X    register char *start;
  2227. X    char   *end;
  2228. X    char   *strpbrk();
  2229. X
  2230. X    /*
  2231. X     * Find the beginning of the first token. If none is found, just return a
  2232. X     * null value. Otherwise, if there is a separator that follows the token,
  2233. X     * nullify it and advance *cpp to the first character after the nullified
  2234. X     * separator. If the token is not followed by a separator advance *cpp to
  2235. X     * the null byte that follows the token.
  2236. X     */
  2237. X
  2238. X    start = *cpp + strspn(*cpp, sep);
  2239. X
  2240. X    if (start[0] == 0) {
  2241. X    return (0);                /* no token */
  2242. X    } else if (end = strpbrk(start, sep)) {    /* look for separator */
  2243. X    *end = '\0';                /* nullify */
  2244. X    *cpp = end + 1;                /* advance beyond end */
  2245. X    return (start);                /* return token */
  2246. X    } else {
  2247. X    *cpp = start + strlen(start);        /* advance to terminator */
  2248. X    return (start);                /* return token */
  2249. X    }
  2250. X}
  2251. END_OF_main/str.c
  2252. if test 6415 -ne `wc -c <main/str.c`; then
  2253.     echo shar: \"main/str.c\" unpacked with wrong size!
  2254. fi
  2255. # end of overwriting check
  2256. fi
  2257. echo shar: End of archive 6 \(of 11\).
  2258. cp /dev/null ark6isdone
  2259. MISSING=""
  2260. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2261.     if test ! -f ark${I}isdone ; then
  2262.     MISSING="${MISSING} ${I}"
  2263.     fi
  2264. done
  2265. if test "${MISSING}" = "" ; then
  2266.     echo You have unpacked all 11 archives.
  2267.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2268. else
  2269.     echo You still need to unpack the following archives:
  2270.     echo "        " ${MISSING}
  2271. fi
  2272. ##  End of shell archive.
  2273. exit 0
  2274.  
  2275.