home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / smail2 / part04 < prev    next >
Encoding:
Internet Message Format  |  1987-02-16  |  57.4 KB

  1. Subject:  v08i070:  Smail release 2.3, Part04/05
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by:  Larry Auton <lda@clyde.att.com>
  6. Mod.sources: Volume 8, Issue 70
  7. Archive-name: smail2/Part04
  8.  
  9. [ OOPS!  Please excuse the "Part03/03" header on the last part.  --r$ ]
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line,
  13. # then unpack it by saving it in a file and typing "sh file".
  14. # If all goes well, you will see the message "End of shell archive."
  15. # Contents:  src/deliver.c src/headers.c src/main.c src/make.cf.sh
  16. #   src/map.c src/misc.c src/resolve.c src/smail.prompt
  17. #   src/svbinmail.c src/sysexits.h
  18. # Wrapped by rs@mirror on Mon Feb  9 17:10:08 1987
  19. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  20. echo shar: extracting "'src/deliver.c'" '(11313 characters)'
  21. if test -f 'src/deliver.c' ; then 
  22.   echo shar: will not over-write existing file "'src/deliver.c'"
  23. else
  24. sed 's/^X//' >src/deliver.c <<'@//E*O*F src/deliver.c//'
  25. X/*
  26. X**  Deliver.c
  27. X**
  28. X**  Routines to effect delivery of mail for rmail/smail. 
  29. X**
  30. X*/
  31. X
  32. X#ifndef lint
  33. Xstatic char     *sccsid="@(#)deliver.c    2.3 (smail) 1/26/87";
  34. X#endif
  35. X
  36. X# include    <stdio.h>
  37. X# include    <sys/types.h>
  38. X# include    <ctype.h>
  39. X# include    "defs.h"
  40. X#ifdef BSD
  41. X#include <strings.h>
  42. X#else
  43. X#include <string.h>
  44. X#endif
  45. X
  46. Xextern int  exitstat;        /* set if a forked mailer fails */
  47. Xextern enum edebug debug;    /* how verbose we are         */ 
  48. Xextern char hostname[];        /* our uucp hostname         */
  49. Xextern char hostdomain[];    /* our host's domain         */
  50. Xextern enum ehandle handle;    /* what we handle        */
  51. Xextern enum erouting routing;    /* how we're routing addresses  */
  52. Xextern char *uuxargs;        /* arguments given to uux       */
  53. Xextern int  queuecost;        /* threshold for queueing mail  */
  54. Xextern int  maxnoqueue;        /* max number of uucico's       */
  55. Xextern char *spoolfile;        /* file name of spooled message */
  56. Xextern FILE *spoolfp;        /* file ptr  to spooled message */
  57. Xextern int spoolmaster;        /* set if creator of spoolfile  */
  58. Xextern char nows[];        /* local time in ctime(3) format*/
  59. Xextern char arpanows[];        /* local time in arpadate format*/
  60. Xchar stderrfile[20];        /* error file for stderr traping*/
  61. X
  62. X/*
  63. X**
  64. X**  deliver():  hand the letter to the proper mail programs.
  65. X**
  66. X**  Issues one command for each different host of <hostv>,
  67. X**  constructing the proper command for LOCAL or UUCP mail.
  68. X**  Note that LOCAL mail has blank host names.
  69. X**
  70. X**  The <userv> names for each host are arguments to the command.
  71. X** 
  72. X**  Prepends a "From" line to the letter just before going 
  73. X**  out, with a "remote from <hostname>" if it is a UUCP letter.
  74. X**
  75. X*/
  76. X
  77. Xdeliver(argc, hostv, userv, formv, costv)
  78. Xint argc;                /* number of addresses        */
  79. Xchar *hostv[];                /* host names            */
  80. Xchar *userv[];                /* user names            */
  81. Xenum eform formv[];            /* form for each address    */
  82. Xint costv[];                /* cost vector             */
  83. X{
  84. X    FILE *out;            /* pipe to mailer        */
  85. X    FILE *popen();            /* to fork a mailer         */
  86. X#ifdef RECORD
  87. X    void record();            /* record all transactions    */
  88. X#endif
  89. X#ifdef LOG
  90. X    void log();
  91. X#endif
  92. X    char *mktemp();
  93. X    char from[SMLBUF];        /* accumulated from argument     */
  94. X    char lcommand[SMLBUF];        /* local command issued     */
  95. X    char rcommand[SMLBUF];        /* remote command issued    */
  96. X    char scommand[SMLBUF];        /* retry  command issued    */
  97. X    char *command;            /* actual command        */
  98. X    char buf[SMLBUF];        /* copying rest of the letter   */
  99. X    enum eform form;        /* holds form[i] for speed     */
  100. X    long size;            /* number of bytes of message     */
  101. X    char *flags;            /* flags for uux        */
  102. X    char *sflag;            /* flag  for smail        */
  103. X    int i, j, stat, retrying;
  104. X    char *c, *postmaster();
  105. X    int failcount = 0;
  106. X    int noqcnt = 0;            /* number of uucico's started   */
  107. X    char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately    */
  108. X    char *uux_queue   = UUX_QUEUE;    /* uucico job gets queued       */
  109. X    off_t message;
  110. X
  111. X/*
  112. X** rewind the spool file and read the collapsed From_ line
  113. X*/
  114. X    (void) fseek(spoolfp, 0L, 0);
  115. X    (void) fgets(from, sizeof(from), spoolfp);
  116. X    if((c = index(from, '\n')) != 0) *c = '\0';
  117. X    message = ftell(spoolfp);
  118. X
  119. X/*
  120. X**  We pass through the list of addresses.
  121. X*/
  122. X    stderrfile[0] = '\0';
  123. X    for(i = 0; i < argc; i++) {
  124. X        char *lend = lcommand;
  125. X        char *rend = rcommand;
  126. X        char *send = scommand;
  127. X
  128. X/*
  129. X**  If we don't have sendmail, arrange to trap standard error
  130. X**  for inclusion in the message that is returned with failed mail.
  131. X*/
  132. X        (void) unlink(stderrfile);
  133. X        (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
  134. X        (void) mktemp(stderrfile);
  135. X        (void) freopen(stderrfile, "w", stderr);
  136. X
  137. X        *lend = *rend = *send = '\0';
  138. X
  139. X/*
  140. X**  If form == ERROR, the address was bad 
  141. X**  If form == SENT, it has been sent on a  previous pass.
  142. X*/
  143. X        form = formv[i];
  144. X        if (form == SENT) {
  145. X            continue;
  146. X        }
  147. X/*
  148. X**  Build the command based on whether this is local mail or uucp mail.
  149. X**  By default, don't allow more than 'maxnoqueue' uucico commands to
  150. X**  be started by a single invocation of 'smail'.
  151. X*/
  152. X        if(uuxargs == NULL) {    /* flags not set on command line */
  153. X            if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
  154. X                flags = uux_noqueue;
  155. X            } else {
  156. X                flags = uux_queue;
  157. X            }
  158. X        } else {
  159. X            flags = uuxargs;
  160. X        }
  161. X
  162. X        retrying = 0;
  163. X        if(routing == JUSTDOMAIN) {
  164. X            sflag = "-r";
  165. X        } else if(routing == ALWAYS) {
  166. X            sflag = "-R";
  167. X        } else {
  168. X            sflag = "";
  169. X        }
  170. X
  171. X        (void) sprintf(lcommand, LMAIL(from, hostv[i]));
  172. X        (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
  173. X
  174. X/*
  175. X**  For each address with the same host name and form, append the user
  176. X**  name to the command line, and set form = ERROR so we skip this address
  177. X**  on later passes. 
  178. X*/
  179. X        /* we initialized lend (rend) to point at the
  180. X         * beginning of its buffer, so that at
  181. X         * least one address will be used regardless
  182. X         * of the length of lcommand (rcommand).
  183. X         */
  184. X        for (j = i; j < argc; j++) {
  185. X            if ((formv[j] != form)
  186. X             || (strcmpic(hostv[i], hostv[j]) != 0)
  187. X             || ((lend - lcommand) > MAXCLEN)
  188. X             || ((rend - rcommand) > MAXCLEN)) {
  189. X                continue;
  190. X            }
  191. X
  192. X            /*
  193. X            ** seek to the end of scommand
  194. X            ** and add on a 'smail' command
  195. X            ** multiple commands are separated by ';'
  196. X            */
  197. X
  198. X            send += strlen(send);
  199. X            if(send != scommand) {
  200. X                *send++ = ';' ;
  201. X            }
  202. X
  203. X            (void) sprintf(send, RETRY(sflag));
  204. X            send += strlen(send);
  205. X
  206. X            lend += strlen(lend);
  207. X            rend += strlen(rend);
  208. X
  209. X            if (form == LOCAL) {
  210. X                (void) sprintf(lend, LARG(userv[j]));
  211. X                (void) sprintf(send, LARG(userv[j]));
  212. X            } else {
  213. X                (void) sprintf(lend, RLARG(hostv[i], userv[j]));
  214. X                (void) sprintf(send, RLARG(hostv[i], userv[j]));
  215. X            }
  216. X
  217. X            (void) sprintf(rend, RARG(userv[j]));
  218. X            formv[j] = SENT;
  219. X        }
  220. Xretry:
  221. X/*
  222. X** rewind the spool file and read the collapsed From_ line
  223. X*/
  224. X        (void) fseek(spoolfp, message, 0);
  225. X
  226. X        /* if the address was in a bogus form (usually DOMAIN),
  227. X        ** then don't bother trying the uux.
  228. X        **
  229. X        ** Rather, go straight to the next smail routing level.
  230. X        */
  231. X        if(form == ERROR) {
  232. X            static char errbuf[SMLBUF];
  233. X            (void) sprintf(errbuf,
  234. X                "address resolution ('%s' @ '%s') failed",
  235. X                    userv[i], hostv[i]);
  236. X            command = errbuf;
  237. X            size    = 0;
  238. X            goto form_error;
  239. X        }
  240. X
  241. X        if (retrying) {
  242. X            command = scommand;
  243. X        } else if (form == LOCAL) {
  244. X            command = lcommand;
  245. X        } else {
  246. X            command = rcommand;
  247. X            if(flags == uux_noqueue) {
  248. X                noqcnt++;
  249. X            }
  250. X        }
  251. X        ADVISE("COMMAND: %s\n", command);
  252. X
  253. X/*
  254. X** Fork the mailer and set it up for writing so we can send the mail to it,
  255. X** or for debugging divert the output to stdout.
  256. X*/
  257. X        if (debug == YES) {
  258. X            out = stdout;
  259. X        } else {
  260. X            failcount = 0;
  261. X            do {
  262. X                out = popen(command, "w");
  263. X                if (out) break;
  264. X                /*
  265. X                 * Fork failed.  System probably overloaded.
  266. X                 * Wait awhile and try again 10 times.
  267. X                 * If it keeps failing, probably some
  268. X                 * other problem, like no uux or smail.
  269. X                 */
  270. X                (void) sleep(60);
  271. X            } while (++failcount < 10);
  272. X        }
  273. X        if(out == NULL) {
  274. X            exitstat = EX_UNAVAILABLE;
  275. X            (void) printf("couldn't execute %s.\n", command);
  276. X            continue;
  277. X        }
  278. X
  279. X        size = 0;
  280. X/*
  281. X**  Output our From_ line.
  282. X*/
  283. X        if (form == LOCAL) {
  284. X#ifdef SENDMAIL
  285. X            size += fprintf(out, LFROM(from, nows, hostname));
  286. X#else
  287. X            char *p;
  288. X            if((p=index(from, '!')) == NULL) {
  289. X                size += fprintf(out,
  290. X                    LFROM(from, nows, hostname));
  291. X            } else {
  292. X                *p = NULL;
  293. X                size += fprintf(out, RFROM(p+1, nows, from));
  294. X                *p = '!';
  295. X            }
  296. X#endif
  297. X        } else {
  298. X            size += fprintf(out, RFROM(from, nows, hostname));
  299. X        }
  300. X
  301. X#ifdef SENDMAIL
  302. X/*
  303. X**  If using sendmail, insert a Received: line only for mail
  304. X**  that is being passed to uux.  If not using sendmail, always
  305. X**  insert the received line, since sendmail isn't there to do it.
  306. X*/
  307. X        if(command == rcommand && handle != ALL)
  308. X#endif
  309. X        {
  310. X            size += fprintf(out,
  311. X                "Received: by %s (%s)\n\tid AA%05d; %s\n",
  312. X                    hostdomain, VERSION,
  313. X                    getpid(), arpanows);
  314. X        }
  315. X
  316. X/*
  317. X**  Copy input.
  318. X*/
  319. X        while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
  320. X            size += fputs(buf, out);
  321. X        }
  322. X/*
  323. X**  Get exit status and if non-zero, set global exitstat so when we exit
  324. X**  we can indicate an error.
  325. X*/
  326. Xform_error:
  327. X        if (debug != YES) {
  328. X            if(form == ERROR) {
  329. X                exitstat = EX_NOHOST;
  330. X            } else if (stat = pclose(out)) {
  331. X                exitstat = stat >> 8;
  332. X            }
  333. X            /*
  334. X             * The 'retrying' check prevents a smail loop.
  335. X             */
  336. X            if(exitstat != 0) {
  337. X                /*
  338. X                ** the mail failed, probably because the host
  339. X                ** being uux'ed isn't in L.sys or local user
  340. X                ** is unknown.
  341. X                */
  342. X
  343. X                if((retrying == 0)    /* first pass */
  344. X                && (routing != REROUTE)    /* have higher level */
  345. X                && (form != LOCAL)) {    /* can't route local */
  346. X                    /*
  347. X                    ** Try again using a higher
  348. X                    ** level of routing.
  349. X                    */
  350. X                    ADVISE("%s failed (%d)\ntrying %s\n",
  351. X                        command, exitstat, scommand);
  352. X                    exitstat = 0;
  353. X                    retrying = 1;
  354. X                    form = SENT;
  355. X                    goto retry;
  356. X                }
  357. X
  358. X                /*
  359. X                ** if we have no other routing possibilities
  360. X                ** see that the mail is returned to sender.
  361. X                */
  362. X
  363. X                if((routing == REROUTE)
  364. X                    || (form == LOCAL)) {
  365. X
  366. X                    /*
  367. X                    ** if this was our last chance,
  368. X                    ** return the mail to the sender.
  369. X                    */
  370. X
  371. X                    ADVISE("%s failed (%d)\n",
  372. X                        command, exitstat);
  373. X                    
  374. X                    (void) fseek(spoolfp, message, 0);
  375. X#ifdef SENDMAIL
  376. X                    /* if we have sendmail, then it
  377. X                    ** was handed the mail, which failed.
  378. X                    ** sendmail returns the failed mail
  379. X                    ** for us, so we need not do it again.
  380. X                    */
  381. X                    if(form != LOCAL)
  382. X#endif
  383. X                    {
  384. X                        return_mail(from, command);
  385. X                    }
  386. X                    exitstat = 0;
  387. X                }
  388. X            }
  389. X# ifdef LOG
  390. X            else {
  391. X                if(retrying == 0) log(command, from, size); /* */
  392. X            }
  393. X# endif
  394. X        }
  395. X    }
  396. X/*
  397. X**  Update logs and records.
  398. X*/
  399. X# ifdef RECORD
  400. X    (void) fseek(spoolfp, message, 0);
  401. X    record(command, from, size);
  402. X# endif
  403. X
  404. X/*
  405. X**  close spool file pointer.
  406. X**  if we created it, then unlink file.
  407. X*/
  408. X    (void) fclose(spoolfp);
  409. X    if(spoolmaster) {
  410. X        (void) unlink(spoolfile);
  411. X    }
  412. X    (void) unlink(stderrfile);
  413. X}
  414. X
  415. X/*
  416. X** return mail to sender, as determined by From_ line.
  417. X*/
  418. Xreturn_mail(from, fcommand)
  419. Xchar *from, *fcommand;
  420. X{
  421. X    char buf[SMLBUF];
  422. X    char domain[SMLBUF], user[SMLBUF];
  423. X    char *r;
  424. X    FILE *fp, *out, *popen();
  425. X    int i = 0;
  426. X
  427. X    r = buf;
  428. X
  429. X    (void) sprintf(r, "%s %s", SMAIL, VFLAG);
  430. X    r += strlen(r);
  431. X
  432. X    if(islocal(from, domain, user)) {
  433. X        (void) sprintf(r, LARG(user));
  434. X    } else {
  435. X        (void) sprintf(r, RLARG(domain, user));
  436. X    }
  437. X
  438. X    i = 0;
  439. X    do {
  440. X        out = popen(buf, "w");
  441. X        if (out) break;
  442. X        /*
  443. X         * Fork failed.  System probably overloaded.
  444. X         * Wait awhile and try again 10 times.
  445. X         * If it keeps failing, probably some
  446. X         * other problem, like no uux or smail.
  447. X         */
  448. X        (void) sleep(60);
  449. X    } while (++i < 10);
  450. X
  451. X    if(out == NULL) {
  452. X        (void) printf("couldn't execute %s.\n", buf);
  453. X        return;
  454. X    }
  455. X
  456. X    (void) fprintf(out, "Date: %s\n", arpanows);
  457. X    (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
  458. X    (void) fprintf(out, "Subject: failed mail\n");
  459. X    (void) fprintf(out, "To: %s\n", from);
  460. X    (void) fprintf(out, "\n");
  461. X    (void) fprintf(out, "=======     command failed      =======\n\n");
  462. X    (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
  463. X
  464. X    (void) fprintf(out, "======= standard error follows  =======\n");
  465. X    (void) fflush(stderr);
  466. X    if((fp = fopen(stderrfile, "r")) != NULL) {
  467. X        while(fgets(buf, sizeof(buf), fp) != NULL) {
  468. X            (void) fputs(buf, out);
  469. X        }
  470. X    }
  471. X    (void) fclose(fp);
  472. X    (void) fprintf(out, "======= text of message follows =======\n");
  473. X/*
  474. X**  Copy input.
  475. X*/
  476. X    (void) fprintf(out, "From %s\n", from);
  477. X    while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
  478. X        (void) fputs(buf, out);
  479. X    }
  480. X    (void) pclose(out);
  481. X}
  482. @//E*O*F src/deliver.c//
  483. if test 11313 -ne "`wc -c <'src/deliver.c'`"; then
  484.     echo shar: error transmitting "'src/deliver.c'" '(should have been 11313 characters)'
  485. fi
  486. fi # end of overwriting check
  487. echo shar: extracting "'src/headers.c'" '(13909 characters)'
  488. if test -f 'src/headers.c' ; then 
  489.   echo shar: will not over-write existing file "'src/headers.c'"
  490. else
  491. sed 's/^X//' >src/headers.c <<'@//E*O*F src/headers.c//'
  492. X/*
  493. X**  message spooing, header and address parsing and completion
  494. X**  functions for smail/rmail
  495. X*/
  496. X
  497. X#ifndef lint
  498. Xstatic char     *sccsid="@(#)headers.c    2.3 (smail) 1/26/87";
  499. X#endif
  500. X
  501. X# include    <stdio.h>
  502. X# include    <sys/types.h>
  503. X# include    <time.h>
  504. X# include    <ctype.h>
  505. X# include    <pwd.h>
  506. X# include    "defs.h"
  507. X#ifdef BSD
  508. X#include <strings.h>
  509. X#else
  510. X#include <string.h>
  511. X#endif
  512. X
  513. Xextern enum edebug debug;    /* how verbose we are         */ 
  514. Xextern char hostname[];        /* */
  515. Xextern char hostdomain[];    /* */
  516. Xextern char *spoolfile;        /* file name of spooled message */
  517. Xextern FILE *spoolfp;        /* file ptr  to spooled message */
  518. Xextern int spoolmaster;        /* set if creator of spoolfile  */
  519. Xextern time_t now;        /* time                */
  520. Xextern char nows[], arpanows[];    /* time strings            */
  521. Xextern struct tm *gmt, *loc;    /* time structs            */
  522. X
  523. Xstatic char toline[SMLBUF];
  524. Xstatic char fromline[SMLBUF];
  525. Xstatic char dateline[SMLBUF];
  526. Xstatic char midline[SMLBUF];
  527. Xstatic char *ieof = "NOTNULL";
  528. X
  529. Xstruct reqheaders {
  530. X    char *name;
  531. X    char *field;
  532. X    char have;
  533. X};
  534. X
  535. Xstatic struct reqheaders reqtab[] = {
  536. X    "Date:"        ,    dateline    ,    'N'    ,
  537. X    "From:"        ,    fromline    ,    'N'    ,
  538. X    "Message-Id:"    ,    midline        ,    'N'    ,
  539. X    "To:"        ,    toline        ,    'N'    ,
  540. X    NULL         ,    NULL        ,    'N'
  541. X};
  542. X
  543. X
  544. X/*
  545. X**
  546. X** parse(): parse <address> into <domain, user, form>.
  547. X**
  548. X**     input        form
  549. X**    -----        ----
  550. X**    user        LOCAL
  551. X**    domain!user    DOMAIN
  552. X**    user@domain    DOMAIN
  553. X**    @domain,address    LOCAL    (just for sendmail)
  554. X**    host!address    UUCP
  555. X**
  556. X*/
  557. X
  558. Xenum eform
  559. Xparse(address, domain, user)
  560. Xchar *address;        /* input address     */
  561. Xchar *domain;        /* output domain     */
  562. Xchar *user;        /* output user         */
  563. X{
  564. X    int parts;
  565. X    char *partv[MAXPATH];                /* to crack address */
  566. X
  567. X/*
  568. X**  If this is route address form @hosta,@hostb:user@hostd, break for
  569. X**  LOCAL since only sendmail would want to eat it.
  570. X*/
  571. X    if (*address == '@')
  572. X        goto local;
  573. X/*
  574. X**  Try splitting at @.  If it work, this is user@domain, form DOMAIN.
  575. X**  Prefer the righthand @ in a@b@c.
  576. X*/
  577. X    if ((parts = ssplit(address, '@', partv)) >= 2) {
  578. X        (void) strcpy(domain, partv[parts-1]);
  579. X        (void) strncpy(user, partv[0], partv[parts-1]-partv[0]-1);
  580. X        user[partv[parts-1]-partv[0]-1] = '\0';
  581. X        return (DOMAIN);
  582. X    } 
  583. X/*
  584. X**  Try splitting at !. If it works, see if the piece before the ! has
  585. X**  a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
  586. X*/
  587. X    if (ssplit(address, '!', partv) > 1) {
  588. X        (void) strcpy(user, partv[1]);
  589. X        (void) strncpy(domain, partv[0], partv[1]-partv[0]-1);
  590. X        domain[partv[1]-partv[0]-1] = '\0';
  591. X
  592. X        if((parts = ssplit(domain, '.', partv)) < 2) {
  593. X            return(UUCP);
  594. X        }
  595. X
  596. X        if(partv[parts-1][0] == '\0') {
  597. X            partv[parts-1][-1] = '\0'; /* strip trailing . */
  598. X        }
  599. X        return (DOMAIN);
  600. X    }
  601. X/* 
  602. X**  Done trying.  This must be just a user name, form LOCAL.
  603. X*/
  604. Xlocal:
  605. X    (void) strcpy(user, address);
  606. X    (void) strcpy(domain, "");
  607. X    return(LOCAL);                /* user */
  608. X}
  609. X
  610. Xbuild(domain, user, form, result)
  611. Xchar *domain;
  612. Xchar *user;
  613. Xenum eform form;
  614. Xchar *result;
  615. X{
  616. X    switch((int) form) {
  617. X    case LOCAL:
  618. X        (void) sprintf(result, "%s", user); 
  619. X        break;
  620. X    case UUCP:
  621. X        (void) sprintf(result, "%s!%s", domain, user);
  622. X        break;
  623. X    case DOMAIN:
  624. X        (void) sprintf(result, "%s@%s", user, domain);
  625. X        break;
  626. X    }
  627. X}
  628. X
  629. X/*
  630. X**  ssplit(): split a line into array pointers.
  631. X**
  632. X**  Each pointer wordv[i] points to the first character after the i'th 
  633. X**  occurence of c in buf.  Note that each wordv[i] includes wordv[i+1].
  634. X**
  635. X*/
  636. X
  637. Xssplit(buf, c, ptr)
  638. Xregister char *buf;        /* line to split up         */
  639. Xchar c;                /* character to split on    */
  640. Xchar **ptr;            /* the resultant vector        */
  641. X{
  642. X        int count = 0;
  643. X        int wasword = 0;
  644. X
  645. X        for(; *buf; buf++) {
  646. X        if (!wasword) {
  647. X            count++;
  648. X            *ptr++ = buf;
  649. X        }
  650. X        wasword = (c != *buf);
  651. X        }
  652. X    if (!wasword) {
  653. X        count++;
  654. X        *ptr++ = buf;
  655. X    }
  656. X        *ptr = NULL;
  657. X        return(count);
  658. X}
  659. X
  660. X/*
  661. X** Determine whether an address is a local address
  662. X*/
  663. X
  664. Xislocal(addr, domain, user)
  665. Xchar *addr, *domain, *user;
  666. X{
  667. X        enum eform form, parse();
  668. X
  669. X        /*
  670. X        ** parse the address
  671. X        */
  672. X
  673. X        form = parse(addr, domain, user);
  674. X
  675. X        if((form == LOCAL)            /* user */
  676. X        ||(strcmpic(domain, hostdomain) == 0)    /* user@hostdomain */
  677. X        ||(strcmpic(domain, hostname)   == 0)) {/* user@hostname */
  678. X            return(1);
  679. X        }
  680. X        return(0);
  681. X}
  682. X
  683. X/*
  684. X** spool - message spooling module
  685. X**
  686. X** (1) get dates for headers, etc.
  687. X** (2) if the message is on the standard input (no '-f')
  688. X**     (a) create a temp file for spooling the message.
  689. X**     (b) collapse the From_ headers into a path.
  690. X**     (c) if the mail originated locally, then
  691. X**         (i) establish default headers
  692. X**        (ii) scan the message headers for required header fields
  693. X**       (iii) add any required message headers that are absent
  694. X**     (d) copy rest of the message to the spool file
  695. X**     (e) close the spool file
  696. X** (3) open the spool file for reading
  697. X*/
  698. X
  699. Xvoid
  700. Xspool(argc, argv)
  701. Xint argc;
  702. Xchar **argv;
  703. X{
  704. X    static char *tmpf = "/tmp/rmXXXXXX";    /* temp file name */
  705. X    char *mktemp();
  706. X    char buf[SMLBUF];
  707. X    static char splbuf[SMLBUF];
  708. X    char from[SMLBUF], domain[SMLBUF], user[SMLBUF];
  709. X    void rline(), scanheaders(), compheaders();
  710. X
  711. X    /*
  712. X    ** if the mail has already been spooled by
  713. X    ** a previous invocation of smail don't respool.
  714. X    ** check the file name to prevent things like
  715. X    ** rmail -f /etc/passwd badguy@dreadfuldomain
  716. X    */
  717. X
  718. X    if((spoolfile != NULL)
  719. X    && (strncmp(spoolfile, tmpf, strlen(tmpf) - 6) != 0)) {
  720. X        error(EX_TEMPFAIL, "spool: bad file name '%s'\n", spoolfile);
  721. X    }
  722. X
  723. X    /*
  724. X    ** set dates in local, arpa, and gmt forms
  725. X    */
  726. X    setdates();
  727. X
  728. X    /*
  729. X    ** If necessary, copy stdin to a temp file.
  730. X    */
  731. X
  732. X    if(spoolfile == NULL) {
  733. X        spoolfile = strcpy(splbuf, tmpf);
  734. X        (void) mktemp(spoolfile);
  735. X
  736. X        if((spoolfp = fopen(spoolfile, "w")) == NULL) {
  737. X            error(EX_CANTCREAT, "can't create %s.\n", spoolfile);
  738. X        }
  739. X
  740. X        spoolmaster = 1;
  741. X
  742. X        /*
  743. X        ** rline reads the standard input,
  744. X        ** collapsing the From_ and >From_
  745. X        ** lines into a single uucp path.
  746. X        ** first non-from_ line is in buf[];
  747. X        */
  748. X
  749. X        rline(from, buf);
  750. X
  751. X        /*
  752. X        ** if the mail originated here, we parse the header
  753. X        ** and add any required headers that are missing.
  754. X        */
  755. X
  756. X        if(islocal(from, domain, user)) {
  757. X            /*
  758. X            ** initialize default headers
  759. X            */
  760. X            def_headers(argc, argv, from);
  761. X
  762. X            /*
  763. X            ** buf has first, non-from_  line
  764. X            */
  765. X            scanheaders(buf);
  766. X            /*
  767. X            ** buf has first, non-header line,
  768. X            */
  769. X
  770. X            compheaders();
  771. X
  772. X            if(buf[0] != '\n') {
  773. X                (void) fputs("\n", spoolfp);
  774. X            }
  775. X        }
  776. X
  777. X        /*
  778. X        ** now, copy the rest of the letter into the spool file
  779. X        ** terminate on either EOF or '^.$'
  780. X        */
  781. X
  782. X        while(ieof != NULL) {
  783. X            (void) fputs(buf, spoolfp);
  784. X            if((fgets(buf, SMLBUF, stdin) == NULL)
  785. X            || (buf[0] == '.' && buf[1] == '\n')) {
  786. X                ieof = NULL;
  787. X            }
  788. X        }
  789. X
  790. X        /*
  791. X        ** close the spool file, and the standard input.
  792. X        */
  793. X
  794. X        (void) fclose(spoolfp);
  795. X        (void) fclose(stdin);    /* you don't see this too often! */
  796. X    }
  797. X
  798. X    if((spoolfp = fopen(spoolfile, "r")) == NULL) {
  799. X        error(EX_TEMPFAIL, "can't open %s.\n", spoolfile);
  800. X    }
  801. X}
  802. X
  803. X/*
  804. X**
  805. X**  rline(): collapse From_ and >From_ lines.
  806. X**
  807. X**  Same idea as the old rmail, but also turns user@domain to domain!user. 
  808. X**
  809. X*/
  810. X
  811. Xvoid
  812. Xrline(from, retbuf)
  813. Xchar *from;
  814. Xchar *retbuf;
  815. X{
  816. X    int parts;            /* for cracking From_ lines ... */
  817. X    char *partv[16];        /* ... apart using ssplit()     */
  818. X    char user[SMLBUF];        /* for rewriting user@host    */
  819. X    char domain[SMLBUF];        /* "   "         "              */
  820. X    char addr[SMLBUF];        /* "   "         "              */
  821. X    enum eform form, parse();    /* "   "         "              */
  822. X    extern build();            /* "   "         "              */
  823. X    struct passwd *pwent, *getpwuid();/* to get default user    */
  824. X    char *c;
  825. X    int nhops, i;
  826. X    char buf[SMLBUF], tmp[SMLBUF], *hop[128], *e, *b, *p;
  827. X
  828. X    if(spoolmaster == 0) return;
  829. X
  830. X    buf[0] = from[0] = addr[0] = '\0';
  831. X/*
  832. X**  Read each line until we hit EOF or a line not beginning with "From "
  833. X**  or ">From " (called From_ lines), accumulating the new path in from
  834. X**  and stuffing the actual sending user (the user name on the last From_ 
  835. X**  line) in addr.
  836. X*/
  837. X    for(;;) {
  838. X        (void) strcpy(retbuf, buf);
  839. X        if(ieof == NULL) {
  840. X            break;
  841. X        }
  842. X        if((fgets(buf, sizeof(buf), stdin) == NULL)
  843. X        || (buf[0] == '.' && buf[1] == '\n')) {
  844. X            ieof = NULL;
  845. X            break;
  846. X        }
  847. X        if (strncmp("From ", buf, 5) 
  848. X            && strncmp(">From ", buf, 6)) {
  849. X            break;
  850. X        }
  851. X/*
  852. X**  Crack the line apart using ssplit.
  853. X*/
  854. X        if(c = index(buf, '\n')) {
  855. X            *c = '\0';
  856. X        }
  857. X        parts = ssplit(buf, ' ', partv);
  858. X/*
  859. X**  Tack host! onto the from argument if "remote from host" is present.
  860. X*/
  861. X
  862. X        if (parts > 3 
  863. X            && !strncmp("remote from ", partv[parts-3], 12))
  864. X        {
  865. X            (void) strcat(from, partv[parts-1]);
  866. X            (void) strcat(from, "!");
  867. X        } 
  868. X/*
  869. X**  Stuff user name into addr, overwriting the user name from previous 
  870. X**  From_ lines, since only the last one counts.  Then rewrite user@host 
  871. X**  into host!user, since @'s don't belong in the From_ argument.
  872. X*/
  873. X        (void) strncpy(addr, partv[1], partv[2]-partv[1]-1); 
  874. X        addr[partv[2]-partv[1]-1] = '\0';    /* ugh */
  875. X
  876. X        (void) parse(addr, domain, user);
  877. X        if(*domain == '\0') {
  878. X            form = LOCAL;
  879. X        } else {
  880. X            form = UUCP;
  881. X        }
  882. X
  883. X        build(domain, user, form, addr);
  884. X    }
  885. X/*
  886. X**  Now tack the user name onto the from argument.
  887. X*/
  888. X    (void) strcat(from, addr);
  889. X/*
  890. X**  If we still have no from argument, we have junk headers, but we try
  891. X**  to get the user's name using /etc/passwd.
  892. X*/
  893. X    if (from[0] == '\0') {
  894. X        if ((pwent = getpwuid(getuid())) == NULL) {
  895. X            (void) strcpy(from, "nowhere");    /* bad news */
  896. X        } else {
  897. X            (void) strcpy(from, pwent->pw_name);
  898. X        }
  899. X    }
  900. X
  901. X    /* split the from line on '!'s */
  902. X    nhops = ssplit(from, '!', hop);
  903. X
  904. X    for(i = 0; i < (nhops - 1); i++) {
  905. X        b = hop[i];
  906. X        if(*b == '\0') {
  907. X            continue;
  908. X        }
  909. X        e = hop[i+1];
  910. X        e-- ;
  911. X        *e = '\0';    /* null terminate each path segment */
  912. X        e++;
  913. X
  914. X#ifdef HIDDENHOSTS
  915. X/*
  916. X**  Strip hidden hosts:  anything.hostname.MYDOM -> hostname.MYDOM
  917. X*/
  918. X        for(p = b;(p = index(p, '.')) != NULL; p++) {
  919. X            if(strcmpic(hostdomain, p+1) == 0) {
  920. X                (void) strcpy(b, hostdomain);
  921. X                break;
  922. X            }
  923. X        }
  924. X#endif
  925. X
  926. X/*
  927. X**  Strip useless MYDOM: hostname.MYDOM -> hostname
  928. X*/
  929. X        if(strcmpic(hop[i], hostdomain) == 0) {
  930. X            (void) strcpy(hop[i], hostname);
  931. X        }
  932. X    }
  933. X
  934. X/*
  935. X**  Now strip out any redundant information in the From_ line
  936. X**  a!b!c!c!d    => a!b!c!d
  937. X*/
  938. X
  939. X    for(i = 0; i < (nhops - 2); i++) {
  940. X        b = hop[i];
  941. X        e = hop[i+1];
  942. X        if(strcmpic(b, e) == 0) {
  943. X            *b = '\0';
  944. X        }
  945. X    }
  946. X/*
  947. X**  Reconstruct the From_ line
  948. X*/
  949. X    tmp[0] = '\0';            /* empty the tmp buffer */
  950. X
  951. X    for(i = 0; i < (nhops - 1); i++) {
  952. X        if((hop[i][0] == '\0')    /* deleted this hop */
  953. X         ||((tmp[0] == '\0')    /* first hop == hostname */
  954. X          &&(strcmpic(hop[i], hostname) == 0))) {
  955. X            continue;
  956. X        }
  957. X        (void) strcat(tmp, hop[i]);
  958. X        (void) strcat(tmp, "!");
  959. X    }
  960. X    (void) strcat(tmp, hop[i]);
  961. X    (void) strcpy(from, tmp);
  962. X    (void) strcpy(retbuf, buf);
  963. X    (void) fprintf(spoolfp, "%s\n", from);
  964. X}
  965. X
  966. Xvoid
  967. Xscanheaders(buf)
  968. Xchar *buf;
  969. X{
  970. X    int inheader = 0;
  971. X
  972. X    while(ieof != NULL) {
  973. X        if(buf[0] == '\n') {
  974. X            break; /* end of headers */
  975. X        }
  976. X
  977. X        /*
  978. X        ** header lines which begin with whitespace
  979. X        ** are continuation lines
  980. X        */
  981. X        if((inheader == 0)
  982. X        || ((buf[0] != ' ' && buf[0] != '\t'))) {
  983. X            /* not a continuation line
  984. X            ** check for header
  985. X            */
  986. X            if(isheader(buf) == 0) {
  987. X                /*
  988. X                ** not a header
  989. X                */
  990. X                break;
  991. X            }
  992. X            inheader = 1;
  993. X            haveheaders(buf);
  994. X        }
  995. X        (void) fputs(buf, spoolfp);
  996. X        if((fgets(buf, SMLBUF, stdin) == NULL)
  997. X        || (buf[0] == '.' && buf[1] == '\n')) {
  998. X            ieof = NULL;
  999. X        }
  1000. X    }
  1001. X
  1002. X    if(isheader(buf)) {
  1003. X        buf[0] = '\0';
  1004. X    }
  1005. X}
  1006. X
  1007. X/*
  1008. X** complete headers - add any required headers that are not in the message
  1009. X*/
  1010. Xvoid
  1011. Xcompheaders()
  1012. X{
  1013. X    struct reqheaders *i;
  1014. X
  1015. X    /*
  1016. X    ** look at the table of required headers and
  1017. X    ** add those that are missing to the spooled message.
  1018. X    */
  1019. X    for(i = reqtab; i->name != NULL; i++) {
  1020. X        if(i->have != 'Y') {
  1021. X            (void) fprintf(spoolfp, "%s\n", i->field);
  1022. X        }
  1023. X    }
  1024. X}
  1025. X
  1026. X/*
  1027. X** look at a string and determine
  1028. X** whether or not it is a valid header.
  1029. X*/
  1030. Xisheader(s)
  1031. Xchar *s;
  1032. X{
  1033. X    char *p;
  1034. X
  1035. X    /*
  1036. X    ** header field names must terminate with a colon
  1037. X    ** and may not be null.
  1038. X    */
  1039. X    if(((p = index(s, ':')) == NULL) || (s == p)) {
  1040. X        return(0);
  1041. X
  1042. X    }
  1043. X    /*
  1044. X    ** header field names must consist entirely of
  1045. X    ** printable ascii characters.
  1046. X    */
  1047. X    while(s != p) {
  1048. X        if((*s < '!') || (*s > '~')) {
  1049. X            return(0);
  1050. X        }
  1051. X        s++;
  1052. X    }
  1053. X    /*
  1054. X    ** we hit the ':', so the field may be a header
  1055. X    */
  1056. X    return(1);
  1057. X}
  1058. X
  1059. X/*
  1060. X** compare the header field to those in the required header table.
  1061. X** if it matches, then mark the required header as being present
  1062. X** in the message.
  1063. X*/
  1064. Xhaveheaders(s)
  1065. Xchar *s;
  1066. X{
  1067. X    struct reqheaders *i;
  1068. X
  1069. X    for(i = reqtab; i->name != NULL; i++) {
  1070. X        if(strncmpic(i->name, s, strlen(i->name)) == 0) {
  1071. X            i->have = 'Y';
  1072. X            break;
  1073. X        }
  1074. X    }
  1075. X}
  1076. X
  1077. X/*
  1078. X** create default headers for the message.
  1079. X*/
  1080. Xdef_headers(argc, argv, from)
  1081. Xint argc;
  1082. Xchar **argv;
  1083. Xchar *from;
  1084. X{
  1085. X    def_to(argc, argv);    /* default To:        */
  1086. X    def_date();        /* default Date:    */
  1087. X    def_from(from);        /* default From:     */
  1088. X    def_mid();        /* default Message-Id:    */
  1089. X}
  1090. X
  1091. X/*
  1092. X** default Date: in arpa format
  1093. X*/
  1094. Xdef_date()
  1095. X{
  1096. X    (void) strcpy(dateline, "Date: ");
  1097. X    (void) strcat(dateline, arpanows);
  1098. X}
  1099. X
  1100. X/*
  1101. X** default Message-Id
  1102. X**  Message-Id: <yymmddhhmm.AAppppp@hostdomain>
  1103. X**
  1104. X**    yy     year
  1105. X**    mm     month
  1106. X**    dd     day
  1107. X**    hh     hour
  1108. X**    mm     minute
  1109. X**    ppppp    process-id
  1110. X**
  1111. X** date and time are set by GMT
  1112. X*/
  1113. Xdef_mid()
  1114. X{
  1115. X    (void) sprintf(midline, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s>",
  1116. X        gmt->tm_year,
  1117. X        gmt->tm_mon+1,
  1118. X        gmt->tm_mday,
  1119. X        gmt->tm_hour,
  1120. X        gmt->tm_min,
  1121. X        getpid(),
  1122. X        hostdomain);
  1123. X}
  1124. X
  1125. X/*
  1126. X** default From:
  1127. X**  From: user@hostdomain
  1128. X*/
  1129. Xdef_from(from)
  1130. Xchar *from;
  1131. X{
  1132. X    (void) sprintf(fromline, "From: %s@%s", from, hostdomain);
  1133. X}
  1134. X
  1135. X/*
  1136. X** default To:
  1137. X**  To: recip1, recip2, ...
  1138. X**
  1139. X** lines longer than 50 chars are continued on another line.
  1140. X*/
  1141. Xdef_to(argc, argv)
  1142. Xint argc;
  1143. Xchar **argv;
  1144. X{
  1145. X    int i, n;
  1146. X    char *bol;
  1147. X
  1148. X    bol = toline;
  1149. X    (void) strcpy(bol, "To:");
  1150. X    for(n = i = 0; i < argc; i++) {
  1151. X        n = strlen(bol);
  1152. X        if(n > 50) {
  1153. X            (void) strcat(bol, "\n\t");
  1154. X            bol = bol + strlen(bol);
  1155. X            *bol = '\0';
  1156. X            n = 8;
  1157. X        }
  1158. X        if(i == 0) {
  1159. X            (void) strcat(bol, " ");
  1160. X        } else {
  1161. X            (void) strcat(bol, ", ");
  1162. X        }
  1163. X        (void) strcat(bol, argv[i]);
  1164. X    }
  1165. X}
  1166. @//E*O*F src/headers.c//
  1167. if test 13909 -ne "`wc -c <'src/headers.c'`"; then
  1168.     echo shar: error transmitting "'src/headers.c'" '(should have been 13909 characters)'
  1169. fi
  1170. fi # end of overwriting check
  1171. echo shar: extracting "'src/main.c'" '(4213 characters)'
  1172. if test -f 'src/main.c' ; then 
  1173.   echo shar: will not over-write existing file "'src/main.c'"
  1174. else
  1175. sed 's/^X//' >src/main.c <<'@//E*O*F src/main.c//'
  1176. X/*
  1177. X**
  1178. X**  rmail/smail - UUCP mailer with automatic routing.
  1179. X**
  1180. X**  Christopher Seiwald        /+\
  1181. X**  chris@cbosgd.att.com    +\
  1182. X**  January, 1985        \+/
  1183. X**
  1184. X*/
  1185. X
  1186. X#ifndef lint
  1187. Xstatic char     *sccsid="@(#)main.c    2.2 (smail) 1/26/87";
  1188. X#endif
  1189. X
  1190. X/*
  1191. X**
  1192. X**  usage:      rmail [options] address...
  1193. X**        smail [options] address...
  1194. X**  options:
  1195. X**        -d         debug - verbose and don't invoke mailers.
  1196. X**        -v        verbose - just verbose.
  1197. X**        -h hostname    set hostname 
  1198. X**        -H hostdomain    set hostdomain (default hostname.MYDOM)
  1199. X**        -p pathfile    path database filename
  1200. X**        -r        force routing of host!address
  1201. X**        -R        reroute even explicit path!user
  1202. X**        -l        user@domain goes to local mailer
  1203. X**        -L        all mail goes local
  1204. X**        -q number    mail queueing cost threshold
  1205. X**        -m number    limit on number of uux_noqueue jobs
  1206. X**        -u string    string of flags for uux
  1207. X**        -a aliasfile    aliases filename (not used with SENDMAIL)
  1208. X*/
  1209. X
  1210. X#include    <stdio.h>
  1211. X#include    <ctype.h>
  1212. X#include    "defs.h"
  1213. X#ifdef BSD
  1214. X#include <strings.h>
  1215. X#else
  1216. X#include <string.h>
  1217. X#endif
  1218. X
  1219. Xint exitstat = 0;        /* exit status, set by resolve, deliver    */
  1220. X
  1221. Xenum edebug debug     = NO;    /* set by -d or -v option        */
  1222. Xenum ehandle handle   = HANDLE;    /* which mail we can handle, see defs.h    */
  1223. Xenum erouting routing = ROUTING;/* to route or not to route, see defs.h */
  1224. X
  1225. Xchar hostname[SMLBUF]   = "";    /* set by -h, defaults in defs.h     */
  1226. Xchar hostdomain[SMLBUF] = "";    /* set by -H, defaults in defs.h     */
  1227. X
  1228. Xchar *pathfile  = PATHS;    /* or set by -p             */
  1229. Xchar *uuxargs   = NULL;        /* or set by -u                */
  1230. Xchar *aliasfile = ALIAS;    /* or set by -a                */
  1231. Xint  queuecost  = QUEUECOST;    /* or set by -q                */
  1232. Xint  maxnoqueue = MAXNOQUEUE;    /* or set by -m                         */
  1233. X
  1234. Xchar *spoolfile = NULL;        /* name of the file containing letter   */
  1235. XFILE *spoolfp;            /* file pointer to spoolfile        */
  1236. Xint  spoolmaster = 0;        /* indicates 'control' of spoolfile     */
  1237. Xvoid spool();
  1238. X
  1239. X
  1240. X/*
  1241. X**
  1242. X**  rmail/smail: mail stdin letter to argv addresses.
  1243. X**
  1244. X**  After processing command line options and finding our host and domain 
  1245. X**  names, we map addresses into <host,user,form,cost> sets.  Then we deliver.
  1246. X**
  1247. X*/
  1248. X
  1249. Xmain( argc, argv )
  1250. Xint argc;
  1251. Xchar *argv[];
  1252. X{
  1253. X    char *hostv[MAXARGS];        /* UUCP neighbor         */
  1254. X    char *userv[MAXARGS];        /* address given to host     */
  1255. X    int  costv[MAXARGS];        /* cost of resolved route    */
  1256. X    enum eform formv[MAXARGS];    /* invalid, local, or uucp     */
  1257. X    char *p;
  1258. X    int c;
  1259. X    int nargc;
  1260. X    char **nargv, **alias();
  1261. X
  1262. X    char *optstr = "dvrRlLH:h:p:u:q:a:m:f:";
  1263. X    extern char *optarg;
  1264. X    extern int optind;
  1265. X
  1266. X/*
  1267. X**  see if we aren't invoked as rmail
  1268. X*/
  1269. X    if((p = rindex(argv[0], '/')) == NULL) {
  1270. X        p = argv[0];
  1271. X    } else {
  1272. X        p++;
  1273. X    }
  1274. X
  1275. X    if(*p != 'r' ) {
  1276. X        handle = ALL;
  1277. X    }
  1278. X
  1279. X/*
  1280. X**  Process command line arguments
  1281. X*/
  1282. X    while ((c = getopt(argc, argv, optstr)) != EOF) {
  1283. X        switch ( c ) {
  1284. X        case 'd': debug      = YES;         break;
  1285. X        case 'v': debug      = VERBOSE;     break; 
  1286. X        case 'r': routing    = ALWAYS;        break;
  1287. X        case 'R': routing    = REROUTE;        break;
  1288. X        case 'l': handle     = JUSTUUCP;    break;
  1289. X        case 'L': handle     = NONE;        break;
  1290. X        case 'f': spoolfile  = optarg;        break;
  1291. X        case 'p': pathfile   = optarg;         break;
  1292. X        case 'u': uuxargs    = optarg;         break;
  1293. X        case 'a': aliasfile  = optarg;         break;
  1294. X        case 'H': (void) strcpy(hostdomain, optarg);    break;
  1295. X        case 'h': (void) strcpy(hostname, optarg);     break;
  1296. X        case 'm': if(isdigit(*optarg)) {
  1297. X                  maxnoqueue = atoi(optarg);
  1298. X              }
  1299. X              break;
  1300. X        case 'q': if(isdigit(*optarg)) {
  1301. X                  queuecost = atoi(optarg);
  1302. X              }
  1303. X              break;
  1304. X        default:
  1305. X            error( EX_USAGE, "valid flags are %s\n", optstr);
  1306. X        }
  1307. X    }
  1308. X    if ( argc <= optind ) {
  1309. X        error( EX_USAGE, "usage: %s [flags] address...\n", argv[0] );
  1310. X    }
  1311. X
  1312. X/*
  1313. X**  Get our default hostname and hostdomain.
  1314. X*/
  1315. X    getmynames();
  1316. X
  1317. X/*
  1318. X**  Spool the letter in a temporary file.
  1319. X*/
  1320. X    nargc = argc - optind;
  1321. X    spool(nargc, &argv[optind]);
  1322. X
  1323. X/*
  1324. X** If we have sendmail, aliasing was done there, so alias() is a NOP.
  1325. X** If we don't have sendmail, do our own aliasing.
  1326. X*/
  1327. X    nargv = alias(&nargc, &argv[optind]);
  1328. X
  1329. X/*
  1330. X**  Map argv addresses to <host, user, form, cost>.
  1331. X*/
  1332. X    map(nargc, nargv, hostv, userv, formv, costv);
  1333. X/*
  1334. X**  Deliver.
  1335. X*/
  1336. X    deliver(nargc, hostv, userv, formv, costv);
  1337. X/*
  1338. X**  Exitstat was set if any resolve or deliver failed, otherwise 0.
  1339. X*/
  1340. X    return( exitstat );
  1341. X}
  1342. @//E*O*F src/main.c//
  1343. if test 4213 -ne "`wc -c <'src/main.c'`"; then
  1344.     echo shar: error transmitting "'src/main.c'" '(should have been 4213 characters)'
  1345. fi
  1346. fi # end of overwriting check
  1347. echo shar: extracting "'src/make.cf.sh'" '(3038 characters)'
  1348. if test -f 'src/make.cf.sh' ; then 
  1349.   echo shar: will not over-write existing file "'src/make.cf.sh'"
  1350. else
  1351. sed 's/^X//' >src/make.cf.sh <<'@//E*O*F src/make.cf.sh//'
  1352. X#! /bin/sh
  1353. X#
  1354. X# @(#)make.cf.sh    2.1 (smail) 12/14/86
  1355. X#
  1356. Xcat <<!EOM!
  1357. XThis script will prompt you for the automatically configurable parameters
  1358. Xin the stock version of the sendmail configuration file.  Naturally, any
  1359. Xlocal extensions will have to be added manually.
  1360. X
  1361. XClyde is a VAX running AT&T System V Release 2.0, with a port of sendmail.
  1362. XClyde is a gateway for the domain .att.com.
  1363. X
  1364. XBelow is a trace of the session that
  1365. Xconfigured the sendmail.cf on clyde.ATT.COM:
  1366. X===
  1367. X
  1368. X!EOM!
  1369. X
  1370. Xecho "press return to continue"; read foo
  1371. X
  1372. Xcat <<!EOM!
  1373. XEnter Date (MM-DD-YY):
  1374. X06-24-86
  1375. XEnter This Host's Name:
  1376. Xclyde
  1377. XEnter This Host's Official Domain:
  1378. XATT.COM
  1379. XEnter Any Equivalent Domain Classes:
  1380. XATT
  1381. XEnter Any Domains For Which This Host Is An Authority:
  1382. XATT.UUCP
  1383. XDoes This Host Have SMTP Connections (y/n)?
  1384. Xno
  1385. XEnter Full Path to Executable That Will Provide Local Mail Delivery:
  1386. X/bin/lmail
  1387. XIs /bin/lmail A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?
  1388. Xno
  1389. XWill This Host Act As A Gateway Between Domains (y/n)?
  1390. Xyes
  1391. XAre subdomains beneath this hosts' domain to be hidden (y/n)?
  1392. Xyes
  1393. X===
  1394. X!EOM!
  1395. X# get date of configuration
  1396. XCF_DATE=`/bin/sh ./smail.prompt string "Enter Date (MM-DD-YY):"`
  1397. X
  1398. X# get host name
  1399. XCF_HOST=`/bin/sh ./smail.prompt string "Enter This Host's Name:"`
  1400. X
  1401. X# get host domain
  1402. XCF_DOMAIN=`/bin/sh ./smail.prompt string "Enter This Host's Official Domain:"`
  1403. X
  1404. X# get domain classes
  1405. XCF_DCLASS=`/bin/sh ./smail.prompt string "Enter Any Equivalent Domain Classes:"`
  1406. X
  1407. X# get domain authority
  1408. XCF_AUTHORITY=`/bin/sh ./smail.prompt string "Enter Any Domains For Which This Host Is An Authority:"`
  1409. X
  1410. XCF_SMTP=`/bin/sh ./smail.prompt yesno "Does This Host Have SMTP Connections (y/n)?"`
  1411. Xif test "$CF_SMTP" = "yes"
  1412. Xthen
  1413. X
  1414. X#get list of local SMTP connections
  1415. X    CF_SMTP=`/bin/sh ./smail.prompt file "Enter Full Path to File that Contains List of SMTP Connections:"`
  1416. X
  1417. X    CF_SMTP="FE$CF_SMTP %s"
  1418. Xelse
  1419. X    CF_SMTP=""
  1420. Xfi
  1421. X
  1422. X# get path to local delivery agent
  1423. XCF_LOCALMAIL=`/bin/sh ./smail.prompt file "Enter Full Path to Executable That Will Provide Local Mail Delivery:"`
  1424. X
  1425. XCF_SYSTEM=`/bin/sh ./smail.prompt yesno "Is $CF_LOCALMAIL A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?"`
  1426. Xif test "$CF_SYSTEM" = "yes"
  1427. Xthen
  1428. X    CF_SVMAIL="#"
  1429. X    CF_BSMAIL=""
  1430. Xelse
  1431. X    CF_SVMAIL=""
  1432. X    CF_BSMAIL="#"
  1433. Xfi
  1434. X
  1435. XCF_GATEWAY=`/bin/sh ./smail.prompt yesno "Will This Host Act As A Gateway Between Domains(y/n)?"`
  1436. Xif test "$CF_GATEWAY" = "yes"
  1437. Xthen
  1438. X    CF_GATEWAY=""
  1439. Xelse
  1440. X    CF_GATEWAY="#"
  1441. Xfi
  1442. X
  1443. XCF_HIDDENHOSTS=`/bin/sh ./smail.prompt yesno "Are subdomains beneath this hosts' domain to be hidden (y/n)?"`
  1444. Xif test "$CF_HIDDENHOSTS" = "yes"
  1445. Xthen
  1446. X    CF_HIDDENHOSTS=""
  1447. Xelse
  1448. X    CF_HIDDENHOSTS="#"
  1449. Xfi
  1450. X
  1451. Xsed     \
  1452. X    -e "s/CF_HOST/Dw$CF_HOST/" \
  1453. X    -e "s/CF_DOMAIN/DD$CF_DOMAIN/" \
  1454. X    -e "s/CF_AUTHORITY/DA$CF_AUTHORITY/" \
  1455. X    -e "s/CF_DCLASS/CDUUCP $CF_DCLASS/" \
  1456. X    -e "s;CF_SMTP;$CF_SMTP;" \
  1457. X    -e "s;CF_DATE;$CF_DATE;" \
  1458. X    -e "s;CF_LOCALMAIL;$CF_LOCALMAIL;" \
  1459. X    -e "s;CF_BSMAIL;$CF_BSMAIL;" \
  1460. X    -e "s;CF_SVMAIL;$CF_SVMAIL;" \
  1461. X    -e "s;CF_GATEWAY;$CF_GATEWAY;" \
  1462. X    -e "s;CF_HIDDENHOSTS;$CF_HIDDENHOSTS;" \
  1463. X    template.cf > sendmail.cf
  1464. @//E*O*F src/make.cf.sh//
  1465. if test 3038 -ne "`wc -c <'src/make.cf.sh'`"; then
  1466.     echo shar: error transmitting "'src/make.cf.sh'" '(should have been 3038 characters)'
  1467. fi
  1468. fi # end of overwriting check
  1469. echo shar: extracting "'src/map.c'" '(1425 characters)'
  1470. if test -f 'src/map.c' ; then 
  1471.   echo shar: will not over-write existing file "'src/map.c'"
  1472. else
  1473. sed 's/^X//' >src/map.c <<'@//E*O*F src/map.c//'
  1474. X#ifndef lint
  1475. Xstatic char     *sccsid="@(#)map.c    2.2 (smail) 1/26/87";
  1476. X#endif
  1477. X
  1478. X# include    <stdio.h>
  1479. X# include    <sys/types.h>
  1480. X# include    "defs.h"
  1481. X#ifdef BSD
  1482. X#include <strings.h>
  1483. X#else
  1484. X#include <string.h>
  1485. X#endif
  1486. X
  1487. Xextern int queuecost;
  1488. X
  1489. X/*
  1490. X**
  1491. X**  map(): map addresses into <host, user, form, cost> sets.
  1492. X**
  1493. X**  Calls resolve() for each address of argv.  The result is hostv and 
  1494. X**  userv arrays (pointing into buffers userz and hostz), and formv array.
  1495. X**
  1496. X*/
  1497. X
  1498. Xmap(argc, argv, hostv, userv, formv, costv)
  1499. Xint argc;                /* address count         */
  1500. Xchar **argv;                /* address vector         */
  1501. Xchar *hostv[];                /* remote host vector         */
  1502. Xchar *userv[];                /* user name vector         */
  1503. Xenum eform formv[];            /* address format vector     */
  1504. Xint costv[];                /* cost vector             */
  1505. X{
  1506. X    int i, cost;
  1507. X    enum eform resolve();
  1508. X    char *c;
  1509. X    static char userbuf[BIGBUF], *userz;
  1510. X    static char hostbuf[BIGBUF], *hostz;
  1511. X
  1512. X    userz = userbuf;
  1513. X    hostz = hostbuf;
  1514. X
  1515. X    for( i=0; i<argc; i++ ) {
  1516. X#ifdef DEFQUEUE
  1517. X        cost = queuecost+1;        /* default is queueing */
  1518. X#else
  1519. X        cost = queuecost-1;        /* default is no queueing */
  1520. X#endif
  1521. X        userv[i] = userz;        /* put results here */
  1522. X        hostv[i] = hostz;
  1523. X        if ( **argv == '(' ) {        /* strip () */
  1524. X            ++*argv;
  1525. X            c = index( *argv, ')' );
  1526. X            if (c)
  1527. X                *c = '\0';
  1528. X        }
  1529. X                        /* here it comes! */
  1530. X        formv[i] = resolve(*argv++, hostz, userz, &cost);
  1531. X        costv[i] = cost;
  1532. X        userz += strlen( userz ) + 1;    /* skip past \0 */
  1533. X        hostz += strlen( hostz ) + 1;
  1534. X    }
  1535. X}
  1536. @//E*O*F src/map.c//
  1537. if test 1425 -ne "`wc -c <'src/map.c'`"; then
  1538.     echo shar: error transmitting "'src/map.c'" '(should have been 1425 characters)'
  1539. fi
  1540. fi # end of overwriting check
  1541. echo shar: extracting "'src/misc.c'" '(7381 characters)'
  1542. if test -f 'src/misc.c' ; then 
  1543.   echo shar: will not over-write existing file "'src/misc.c'"
  1544. else
  1545. sed 's/^X//' >src/misc.c <<'@//E*O*F src/misc.c//'
  1546. X
  1547. X/*
  1548. X**  Miscellaneous support functions for smail/rmail
  1549. X*/
  1550. X
  1551. X#ifndef lint
  1552. Xstatic char     *sccsid="@(#)misc.c    2.3 (smail) 1/26/87";
  1553. X#endif
  1554. X
  1555. X# include    <stdio.h>
  1556. X# include    <sys/types.h>
  1557. X# include    <ctype.h>
  1558. X# include    "defs.h"
  1559. X#ifdef BSD
  1560. X# include    <sys/time.h>
  1561. X# include    <sys/timeb.h>
  1562. X# include    <strings.h>
  1563. X#else
  1564. X# include    <time.h>
  1565. X# include    <sys/utsname.h>
  1566. X# include    <string.h>
  1567. X#endif
  1568. X
  1569. Xextern int  exitstat;        /* set if a forked mailer fails */
  1570. Xextern enum edebug debug;    /* how verbose we are         */ 
  1571. Xextern enum ehandle handle;    /* what we handle        */
  1572. Xextern char *uuxargs;        /* arguments given to uux       */
  1573. Xextern int  queuecost;        /* threshold for queueing mail  */
  1574. Xextern int  maxnoqueue;        /* max number of uucico's       */
  1575. Xextern enum erouting routing;    /* when to route addresses    */
  1576. Xextern char hostdomain[];    /* */
  1577. Xextern char hostname[];        /* */
  1578. Xextern char *pathfile;        /* location of path database    */
  1579. Xextern char *spoolfile;        /* file name of spooled message */
  1580. Xextern FILE *spoolfp;        /* file ptr  to spooled message */
  1581. Xextern int spoolmaster;        /* set if creator of spoolfile  */
  1582. X
  1583. Xstruct tm *gmt, *loc;        /* GMT and local time structure    */
  1584. Xtime_t now;            /* current system time        */
  1585. Xchar nows[50];            /* time in ctime format        */
  1586. Xchar arpanows[50];        /* time in arpa format        */
  1587. X
  1588. X# ifdef LOG
  1589. Xvoid
  1590. Xlog(command, from, size)
  1591. Xchar *command, *from;
  1592. Xlong size;
  1593. X{
  1594. X    FILE *fd;
  1595. X    char *logtime, tbuf[50];
  1596. X    int cmask;
  1597. X
  1598. X    logtime = strcpy(tbuf, nows);
  1599. X    logtime[16] = '\0';
  1600. X    logtime += 4;
  1601. X
  1602. X    cmask = umask(0);
  1603. X    fd = fopen(LOG, "a");
  1604. X    (void) umask(cmask);
  1605. X
  1606. X    if (fd != NULL) {
  1607. X        (void) fprintf(fd, "%s\t%ld\t%s\t%s\n",
  1608. X            logtime, size, from, command);
  1609. X        (void) fclose(fd);
  1610. X    }
  1611. X}
  1612. X# endif
  1613. X
  1614. X# ifdef RECORD
  1615. XFILE *
  1616. Xrecord(command, from, size)
  1617. Xchar *command, *from;
  1618. Xlong size;
  1619. X{
  1620. X    FILE *fd;
  1621. X    char *logtime, buf[SMLBUF];
  1622. X    int cmask;
  1623. X
  1624. X    logtime = strcpy(buf, nows);
  1625. X    logtime[16] = 0;
  1626. X    logtime += 4;
  1627. X
  1628. X    cmask = umask(0);
  1629. X    fd = fopen(RECORD, "a");
  1630. X    (void) umask(cmask);
  1631. X
  1632. X    if (fd != NULL) {
  1633. X        (void) fprintf(fd, "%s: %s, from %s, %ld bytes\n", 
  1634. X            logtime, command, from, size);
  1635. X    }
  1636. X    while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
  1637. X        (void) fputs(buf, fd);
  1638. X    }
  1639. X    (void) fclose(fd);
  1640. X}
  1641. X# endif
  1642. X
  1643. X
  1644. Xsetdates()
  1645. X{
  1646. X    time_t time();
  1647. X    struct tm *gmtime();
  1648. X    char *ctime(), *arpadate();
  1649. X
  1650. X    (void) time(&now);
  1651. X    (void) strcpy(nows, ctime(&now));
  1652. X    gmt = gmtime(&now);
  1653. X    loc = localtime(&now);
  1654. X    (void) strcpy(arpanows, arpadate(nows));
  1655. X}
  1656. X
  1657. X/*
  1658. X**  Note: This routine was taken from sendmail
  1659. X**
  1660. X**  ARPADATE -- Create date in ARPANET format
  1661. X**
  1662. X**    Parameters:
  1663. X**        ud -- unix style date string.  if NULL, one is created.
  1664. X**
  1665. X**    Returns:
  1666. X**        pointer to an ARPANET date field
  1667. X**
  1668. X**    Side Effects:
  1669. X**        none
  1670. X**
  1671. X**    WARNING:
  1672. X**        date is stored in a local buffer -- subsequent
  1673. X**        calls will overwrite.
  1674. X**
  1675. X**    Bugs:
  1676. X**        Timezone is computed from local time, rather than
  1677. X**        from whereever (and whenever) the message was sent.
  1678. X**        To do better is very hard.
  1679. X**
  1680. X**        Some sites are now inserting the timezone into the
  1681. X**        local date.  This routine should figure out what
  1682. X**        the format is and work appropriately.
  1683. X*/
  1684. X
  1685. Xchar *
  1686. Xarpadate(ud)
  1687. X    register char *ud;
  1688. X{
  1689. X    register char *p;
  1690. X    register char *q;
  1691. X    static char b[40];
  1692. X    extern char *ctime();
  1693. X    register int i;
  1694. X    extern struct tm *localtime();
  1695. X#ifndef BSD
  1696. X    extern char *tzname[];
  1697. X    time_t t, time();
  1698. X#else
  1699. X    /* V7 and 4BSD */
  1700. X    struct timeb t;
  1701. X    extern struct timeb *ftime();
  1702. X    extern char *timezone();
  1703. X#endif
  1704. X
  1705. X    /*
  1706. X    **  Get current time.
  1707. X    **    This will be used if a null argument is passed and
  1708. X    **    to resolve the timezone.
  1709. X    */
  1710. X
  1711. X#ifndef BSD
  1712. X    (void) time(&t);
  1713. X    if (ud == NULL)
  1714. X        ud = ctime(&t);
  1715. X#else
  1716. X    /* V7 or 4BSD */
  1717. X    ftime(&t);
  1718. X    if (ud == NULL)
  1719. X        ud = ctime(&t.time);
  1720. X#endif
  1721. X
  1722. X    /*
  1723. X    **  Crack the UNIX date line in a singularly unoriginal way.
  1724. X    */
  1725. X
  1726. X    q = b;
  1727. X
  1728. X    p = &ud[8];        /* 16 */
  1729. X    if (*p == ' ')
  1730. X        p++;
  1731. X    else
  1732. X        *q++ = *p++;
  1733. X    *q++ = *p++;
  1734. X    *q++ = ' ';
  1735. X
  1736. X    p = &ud[4];        /* Sep */
  1737. X    *q++ = *p++;
  1738. X    *q++ = *p++;
  1739. X    *q++ = *p++;
  1740. X    *q++ = ' ';
  1741. X
  1742. X    p = &ud[22];        /* 1979 */
  1743. X    *q++ = *p++;
  1744. X    *q++ = *p++;
  1745. X    *q++ = ' ';
  1746. X
  1747. X    p = &ud[11];        /* 01:03:52 */
  1748. X    for (i = 8; i > 0; i--)
  1749. X        *q++ = *p++;
  1750. X
  1751. X                /* -PST or -PDT */
  1752. X#ifndef BSD
  1753. X    p = tzname[localtime(&t)->tm_isdst];
  1754. X#else
  1755. X    p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
  1756. X#endif
  1757. X    if (p[3] != '\0')
  1758. X    {
  1759. X        /* hours from GMT */
  1760. X        p += 3;
  1761. X        *q++ = *p++;
  1762. X        if (p[1] == ':')
  1763. X            *q++ = '0';
  1764. X        else
  1765. X            *q++ = *p++;
  1766. X        *q++ = *p++;
  1767. X        p++;        /* skip ``:'' */
  1768. X        *q++ = *p++;
  1769. X        *q++ = *p++;
  1770. X    }
  1771. X    else
  1772. X    {
  1773. X        *q++ = ' ';
  1774. X        *q++ = *p++;
  1775. X        *q++ = *p++;
  1776. X        *q++ = *p++;
  1777. X    }
  1778. X
  1779. X    p = &ud[0];        /* Mon */
  1780. X    *q++ = ' ';
  1781. X    *q++ = '(';
  1782. X    *q++ = *p++;
  1783. X    *q++ = *p++;
  1784. X    *q++ = *p++;
  1785. X    *q++ = ')';
  1786. X
  1787. X    *q = '\0';
  1788. X    return (b);
  1789. X}
  1790. X
  1791. X/*
  1792. X *    The user name "postmaster" must be accepted regardless of what
  1793. X *    combination of upper and lower case is used.  This function is
  1794. X *    used to convert all case variants of "postmaster" to all lower
  1795. X *    case.  If the user name passed in is not "postmaster", it is
  1796. X *    returned unchanged.
  1797. X */
  1798. Xchar *
  1799. Xpostmaster(user)
  1800. Xchar *user;
  1801. X{
  1802. X    static char *pm = "postmaster";
  1803. X
  1804. X    if(strcmpic(user, pm) == 0) {
  1805. X        return(pm);
  1806. X    } else {
  1807. X        return(user);
  1808. X    }
  1809. X}
  1810. X
  1811. X/*
  1812. X**    strncmpic: string compare, ignore case, stop after 'n' chars
  1813. X*/
  1814. X
  1815. Xstrncmpic(s1, s2, n)
  1816. Xchar *s1, *s2;
  1817. Xint n;
  1818. X{
  1819. X    register char *u = s1;
  1820. X    register char *p = s2;
  1821. X
  1822. X    while((n > 0) && (*p != '\0')) {
  1823. X        /* chars match or only case different */
  1824. X        if(lower(*u) == lower(*p)) {
  1825. X            p++;    /* examine next char */
  1826. X            u++;
  1827. X        } else {
  1828. X            break;    /* no match - stop comparison */
  1829. X        }
  1830. X        n--;
  1831. X    }
  1832. X    if(n > 0) {
  1833. X        return(lower(*u) - lower(*p)); /* return "difference" */
  1834. X    } else {
  1835. X        return(0);
  1836. X    }
  1837. X}
  1838. X
  1839. X/*
  1840. X**    strcmpic: string compare, ignore case
  1841. X*/
  1842. X
  1843. Xstrcmpic(s1, s2)
  1844. Xchar *s1, *s2;
  1845. X{
  1846. X    register char *u = s1;
  1847. X    register char *p = s2;
  1848. X
  1849. X    while(*p != '\0') {
  1850. X        /* chars match or only case different */
  1851. X        if(lower(*u) == lower(*p)) {
  1852. X            p++;    /* examine next char */
  1853. X            u++;
  1854. X        } else {
  1855. X            break;    /* no match - stop comparison */
  1856. X        }
  1857. X    }
  1858. X
  1859. X    return(lower(*u) - lower(*p)); /* return "difference" */
  1860. X}
  1861. X
  1862. X/*
  1863. X * Return 1 iff the string is "UUCP" (ignore case).
  1864. X */
  1865. Xisuucp(str)
  1866. Xchar *str;
  1867. X{
  1868. X    if(strcmpic(str, "UUCP") == 0) {
  1869. X        return(1);
  1870. X    } else {
  1871. X        return(0);
  1872. X    }
  1873. X}
  1874. X
  1875. X/*
  1876. X** sform(form) returns a pointer to a string that tells what 'form' means
  1877. X*/
  1878. X
  1879. Xchar *
  1880. Xsform(form)
  1881. Xenum eform form;
  1882. X{
  1883. X    if(form == ERROR)  return("ERROR");
  1884. X    if(form == LOCAL)  return("LOCAL");
  1885. X    if(form == DOMAIN) return("DOMAIN");
  1886. X    if(form == UUCP)   return("UUCP");
  1887. X    if(form == ROUTE)  return("ROUTE");
  1888. X    return("UNKNOWN");
  1889. X}
  1890. X
  1891. X/*
  1892. X**
  1893. X**  getmynames(): what is my host name and host domain?
  1894. X**
  1895. X**  Hostname set by -h, failing that by #define HOSTNAME, failing
  1896. X**  that by gethostname() or uname().
  1897. X**  
  1898. X**  Hostdomain set by -h, failing that by #define HOSTDOMAIN,
  1899. X**  failing that as hostname.MYDOM, or as just hostname.
  1900. X**
  1901. X**  See defs.h for the inside story.
  1902. X**
  1903. X*/
  1904. X
  1905. Xgetmynames()
  1906. X{
  1907. X#ifdef HOSTNAME
  1908. X    if (!*hostname)
  1909. X        (void) strcpy(hostname, HOSTNAME);
  1910. X#endif
  1911. X#ifdef GETHOSTNAME
  1912. X    if (!*hostname)
  1913. X        gethostname(hostname, SMLBUF - 1);
  1914. X#endif
  1915. X#ifdef UNAME
  1916. X    if (!*hostname) {
  1917. X        struct utsname site;
  1918. X
  1919. X        if (uname(&site) < 0)
  1920. X            error(EX_SOFTWARE, "uname() call failed", 0);
  1921. X        (void) strcpy(hostname, site.nodename);
  1922. X    }
  1923. X#endif
  1924. X    if (!*hostname)
  1925. X        error(EX_SOFTWARE, "can't determine hostname.\n", 0);
  1926. X#ifdef HOSTDOMAIN
  1927. X    if (!*hostdomain)
  1928. X        (void) strcpy(hostdomain, HOSTDOMAIN);
  1929. X#endif
  1930. X#ifdef MYDOM
  1931. X    if (!*hostdomain)
  1932. X        (void) strcat(strcpy(hostdomain, hostname), MYDOM);
  1933. X#endif
  1934. X    if (!*hostdomain)
  1935. X        (void) strcpy(hostdomain, hostname);
  1936. X
  1937. X}
  1938. @//E*O*F src/misc.c//
  1939. if test 7381 -ne "`wc -c <'src/misc.c'`"; then
  1940.     echo shar: error transmitting "'src/misc.c'" '(should have been 7381 characters)'
  1941. fi
  1942. fi # end of overwriting check
  1943. echo shar: extracting "'src/resolve.c'" '(7236 characters)'
  1944. if test -f 'src/resolve.c' ; then 
  1945.   echo shar: will not over-write existing file "'src/resolve.c'"
  1946. else
  1947. sed 's/^X//' >src/resolve.c <<'@//E*O*F src/resolve.c//'
  1948. X/*
  1949. X**
  1950. X**  Resolve.c
  1951. X**
  1952. X**  Routes then resolves addresses into UUCP or LOCAL.
  1953. X**
  1954. X*/
  1955. X#ifndef lint
  1956. Xstatic char     *sccsid="@(#)resolve.c    2.2 (smail) 1/26/87";
  1957. X#endif
  1958. X
  1959. X#include    <ctype.h>
  1960. X#include    <stdio.h>
  1961. X#include    "defs.h"
  1962. X#ifdef BSD
  1963. X#include <strings.h>
  1964. X#else
  1965. X#include <string.h>
  1966. X#endif
  1967. X
  1968. Xextern int exitstat;        /* set if address doesn't resolve     */
  1969. Xextern enum ehandle handle;    /* what mail we can handle        */
  1970. Xextern enum edebug debug;    /* verbose and debug modes        */
  1971. Xextern enum erouting routing;    /* when to route addresses        */
  1972. Xextern char hostdomain[];    /* */
  1973. Xextern char hostname[];        /* */
  1974. Xextern char *pathfile;        /* location of path database        */
  1975. X
  1976. Xchar *sform();
  1977. X
  1978. X/*
  1979. X**
  1980. X**  rsvp(): how to resolve addresses.
  1981. X**
  1982. X**  After parsing an address into <form>, the resolved form will be
  1983. X**  rsvp( form ).  If == ROUTE, we route the parsed address and parse again.
  1984. X**
  1985. X*/
  1986. X
  1987. X# define rsvp(a) table[(int)a][(int)handle]
  1988. X
  1989. Xenum eform table[5][3] = {
  1990. X/*    all        justuucp    none */
  1991. X{    ERROR,         ERROR,         ERROR },     /* error */
  1992. X{    LOCAL,         LOCAL,         LOCAL },     /* local */
  1993. X{    ROUTE,         LOCAL,         LOCAL },     /* domain */
  1994. X{    UUCP,         UUCP,         LOCAL },     /* uucp */
  1995. X{    ERROR,         ERROR,         ERROR }};    /* route */
  1996. X
  1997. X/*
  1998. X**
  1999. X**  resolve(): resolve addresses to <host, user, form>.
  2000. X**
  2001. X**  This is a gnarly piece of code, but it does it all.  Each section 
  2002. X**  is documented.
  2003. X**
  2004. X*/
  2005. X
  2006. Xenum eform
  2007. Xresolve( address, domain, user , cost)
  2008. Xchar *address;                /* the input address     */
  2009. Xchar *domain;                /* the returned domain     */
  2010. Xchar *user;                /* the returned user     */
  2011. Xint *cost;                /* the returned cost     */
  2012. X{
  2013. X    enum eform form;        /* the returned form    */ 
  2014. X    enum eform parse();        /* to crack addresses    */
  2015. X    int parts;            /* to ssplit addresses    */
  2016. X    char *partv[MAXPATH];        /* "  "      "        */
  2017. X    char temp[SMLBUF];        /* "  "      "        */
  2018. X    int i;
  2019. X        
  2020. X
  2021. X/*
  2022. X**  If we set REROUTE and are prepared to deliver UUCP mail, we split the 
  2023. X**  address apart at !'s and try to resolve successively larger righthand 
  2024. X**  substrings until we succeed.  Otherwise, we just resolve the whole thing 
  2025. X**  once.
  2026. X*/
  2027. X    if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
  2028. X        parts = ssplit( address, '!', partv );
  2029. X    } else {
  2030. X        parts = 1;
  2031. X        partv[0] = address;
  2032. X    }
  2033. X/*
  2034. X**  This for(i) loop selects successively larger
  2035. X**  righthand substrings of the address.
  2036. X*/
  2037. X    for( i = parts - 1; i >= 0; i-- ) {
  2038. X/*
  2039. X**  Parse the address.
  2040. X*/
  2041. X        (void) strcpy( temp, partv[i] );
  2042. X        form = parse( temp, domain, user );
  2043. X
  2044. XDEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
  2045. X    temp,user,domain,sform(form));
  2046. X
  2047. X/*
  2048. X**  If we are looking at a substring (that's not the entire string)
  2049. X**  which parses to a LOCAL address, we skip to the next larger substring.
  2050. X*/
  2051. X        if((i != 0) && (form == LOCAL))
  2052. X            continue;
  2053. X/*
  2054. X**  Routing, when required, is the next step.
  2055. X**  We route the address if we have a ROUTE form
  2056. X**  or if we have a UUCP form and we are told to
  2057. X**  route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
  2058. X*/
  2059. X        if((rsvp( form ) == ROUTE)
  2060. X         ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {
  2061. X
  2062. X            int look_smart = 0;
  2063. X
  2064. X            if((routing == REROUTE) && (i == 0)) {
  2065. X                look_smart = 1; /* last chance */
  2066. X            }
  2067. X
  2068. X            /* route() puts the new route in 'temp' */
  2069. X            if(route(domain,user,look_smart,temp,cost) != EX_OK) {
  2070. X                continue;    /* If routing fails, try
  2071. X                        /* next larger substring.
  2072. X                        /* */
  2073. X            }
  2074. X/*
  2075. X**  After routing, reparse the new route into domain and user. 
  2076. X*/
  2077. X            form = parse( temp, domain, user );
  2078. X
  2079. XDEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
  2080. X    temp,user,domain,sform(form));
  2081. X
  2082. X        }
  2083. X        break;    /* route is resolved */
  2084. X    }
  2085. X/*
  2086. X**  For LOCAL mail in non-local format, we rewrite the full address into 
  2087. X**  <user> and leave <domain> blank.
  2088. X*/
  2089. X    if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
  2090. X        build( domain, user, form, temp );
  2091. X        (void) strcpy( user, temp );
  2092. X        (void) strcpy( domain, "" );
  2093. X        form = LOCAL;
  2094. X    }
  2095. X/*
  2096. X**  If we were supposed to route an address but failed (form == ERROR), 
  2097. X**  or after routing we are left with an address that still needs to
  2098. X**  be routed (rsvp( form ) == ROUTE), complain.
  2099. X*/
  2100. X    if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
  2101. X        exitstat = EX_NOHOST;
  2102. X        ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
  2103. X            address, user, domain, sform(form));
  2104. X        form = ERROR;
  2105. X    } else {
  2106. X        ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
  2107. X            address, user, domain, sform(form));
  2108. X    }
  2109. X    return ( form );
  2110. X}
  2111. X
  2112. X/*
  2113. X**
  2114. X**  route(): route domain, plug in user.
  2115. X**
  2116. X**  Less complicated than it looks.  Each section is documented.
  2117. X**
  2118. X*/
  2119. X
  2120. Xroute(domain, user, look_smart, result, cost)
  2121. Xchar *domain;            /* domain or host name     */
  2122. Xchar *user;            /* user name         */
  2123. Xint look_smart;            /* do we try to route through a smarter host? */
  2124. Xchar *result;            /* output route     */
  2125. Xint *cost;            /* cost of output route */
  2126. X{
  2127. X    int    uucpdom = 0;
  2128. X    int    domains, step;            /* to split domain    */
  2129. X    char    *domainv[MAXDOMS];        /* "  "     "        */
  2130. X    char    temp[SMLBUF], path[SMLBUF];
  2131. X
  2132. X/*
  2133. X**  Fully qualify the domain, and then strip the last (top level domain) 
  2134. X**  component off, so that we look it up separately.
  2135. X*/
  2136. X    temp[0] = '.';
  2137. X    (void) strcpy(temp+1, domain );
  2138. X
  2139. X    domains = ssplit( temp+1, '.', domainv );
  2140. X
  2141. X/*
  2142. X** check target domain for the local host name and host domain.
  2143. X** if it matches, then the path skip the lookup in the database.
  2144. X** this prevents mail loops for cases where SMARTHOST is defined
  2145. X** in the routing table, but the local host is not.  It also is
  2146. X** a little faster when the local host is the target domain.
  2147. X*/
  2148. X    if((strcmpic(domain, hostname) == 0)
  2149. X    || (strcmpic(domain, hostdomain) == 0)) {
  2150. X        step = 0;
  2151. X        *cost = 0;
  2152. X        (void) strcpy(path, "%s");
  2153. XDEBUG("route: '%s' is local\n", domain);
  2154. X        goto route_complete;
  2155. X    }
  2156. X
  2157. X    /* If the domain ends in .UUCP, trim that off. */
  2158. X    if((domains > 0) && isuucp(domainv[domains-1])) {
  2159. X        domains--;
  2160. X        domainv[domains][-1] = '\0';
  2161. X        uucpdom = 1;
  2162. X    }
  2163. X/*
  2164. X**  Try to get the path for successive components of the domain.  
  2165. X**  Example for osgd.cb.att.uucp:
  2166. X**    osgd.cb.att
  2167. X**    cb.att
  2168. X**    att
  2169. X**    uucp ( remember stripping top level? )
  2170. X**    SMARTHOST
  2171. X**  Returns with error if we find no path.
  2172. X*/
  2173. X    for(step = 0; (step < domains); step++) {
  2174. X        if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
  2175. X        || (getpath(domainv[step]  , path, cost) == EX_OK))/* no dot */
  2176. X            break;
  2177. X    }
  2178. X
  2179. X    if(step == domains) {
  2180. X    /*
  2181. X    ** we've looked at each component of the domain without success
  2182. X    */
  2183. X        /*
  2184. X        ** If domain is a UUCP address, look for a UUCP gateway.
  2185. X        */
  2186. X        if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
  2187. X            /*
  2188. X            ** The domain not is a UUCP address, or we can't
  2189. X            ** find a UUCP gateway.  If this is our last chance,
  2190. X            ** look for a smarter host to deliver the mail.
  2191. X            */
  2192. X            if((look_smart == 0)
  2193. X            || (getpath(SMARTHOST, path, cost) != EX_OK)) {
  2194. X                /*
  2195. X                ** All our efforts have been in vain.
  2196. X                ** Tell them the bad news.
  2197. X                */
  2198. X                DEBUG("route '%s' failed\n", domain);
  2199. X                return( EX_NOHOST );
  2200. X            }
  2201. X        }
  2202. X    }
  2203. X
  2204. Xroute_complete:
  2205. X
  2206. XDEBUG("route:  '%s' (%s) = '%s' (%d)\n", domain, domainv[step], path, *cost);
  2207. X
  2208. X/*
  2209. X**  If we matched on the entire domain name, this address is fully resolved, 
  2210. X**  and we plug <user> into it.  If we matched on only part of the domain 
  2211. X**  name, we plug <domain>!<user> in.  
  2212. X*/
  2213. X    build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
  2214. X    (void) sprintf(result, path, temp);
  2215. X    return( EX_OK );
  2216. X}
  2217. @//E*O*F src/resolve.c//
  2218. if test 7236 -ne "`wc -c <'src/resolve.c'`"; then
  2219.     echo shar: error transmitting "'src/resolve.c'" '(should have been 7236 characters)'
  2220. fi
  2221. fi # end of overwriting check
  2222. echo shar: extracting "'src/smail.prompt'" '(762 characters)'
  2223. if test -f 'src/smail.prompt' ; then 
  2224.   echo shar: will not over-write existing file "'src/smail.prompt'"
  2225. else
  2226. sed 's/^X//' >src/smail.prompt <<'@//E*O*F src/smail.prompt//'
  2227. X#
  2228. X# @(#)smail.prompt    2.1 (smail) 12/14/86
  2229. X#
  2230. X
  2231. Xloop=true
  2232. Xwhile test $loop = true
  2233. Xdo 
  2234. X    case "$1" in
  2235. X    string)
  2236. X        echo "$2" 1>&2
  2237. X        read ans
  2238. X        if test ! -z "$ans"
  2239. X        then
  2240. X            echo $ans
  2241. X            loop=false;
  2242. X        fi
  2243. X    ;;
  2244. X    file)
  2245. X        echo "$2" 1>&2
  2246. X        read ans
  2247. X        case "$ans" in
  2248. X        /*)
  2249. X            if test -f "$ans"
  2250. X            then
  2251. X                echo $ans
  2252. X                loop=false;
  2253. X            else
  2254. X                echo "file '$ans' not found" 1>&2
  2255. X            fi
  2256. X        ;;
  2257. X        *)
  2258. X            echo "must give FULL PATH to file" 1>&2
  2259. X        ;;
  2260. X        esac
  2261. X    ;;
  2262. X    yesno)
  2263. X        echo "$2" 1>&2
  2264. X        read ans
  2265. X        case "$ans" in
  2266. X        y|Y|yes|Yes|YES)
  2267. X            echo "yes"
  2268. X            loop=false
  2269. X        ;;
  2270. X        n|N|no|No|NO)
  2271. X            echo "no"
  2272. X            loop=false
  2273. X        ;;
  2274. X        *)
  2275. X            echo "Please enter yes or no" 1>&2
  2276. X        ;;
  2277. X        esac
  2278. X    ;;
  2279. X    *)
  2280. X
  2281. X        echo "usage: $0 string|yesno prompt_message" 1>&2
  2282. X        echo BOGUS_PROMPT_STRING
  2283. X        loop=false
  2284. X    ;;
  2285. X    esac
  2286. Xdone
  2287. @//E*O*F src/smail.prompt//
  2288. if test 762 -ne "`wc -c <'src/smail.prompt'`"; then
  2289.     echo shar: error transmitting "'src/smail.prompt'" '(should have been 762 characters)'
  2290. fi
  2291. fi # end of overwriting check
  2292. echo shar: extracting "'src/svbinmail.c'" '(1749 characters)'
  2293. if test -f 'src/svbinmail.c' ; then 
  2294.   echo shar: will not over-write existing file "'src/svbinmail.c'"
  2295. else
  2296. sed 's/^X//' >src/svbinmail.c <<'@//E*O*F src/svbinmail.c//'
  2297. X#ifndef lint
  2298. Xstatic char    *sccsid = "@(#)svbinmail.c    2.2 (smail) 1/26/87";
  2299. X#endif
  2300. X/* */
  2301. X/* This program will be used in place of /bin/mail on SVR2 sites.
  2302. X/* It looks at the arguments and decides whether to call
  2303. X/* SENDER for sending mail, or READER for reading mail.
  2304. X/*
  2305. X/* before installing as /bin/mail, move the stock /bin/mail to /bin/lmail
  2306. X/*
  2307. X/*  */
  2308. X
  2309. X#include <stdio.h>
  2310. X#include "defs.h"
  2311. X#ifdef BSD
  2312. X#include <strings.h>
  2313. X#else
  2314. X#include <string.h>
  2315. X#endif
  2316. X
  2317. X#ifdef SENDMAIL
  2318. X#define SENDER    SENDMAIL
  2319. X#else
  2320. X#define    SENDER    "/bin/rmail"
  2321. X#endif
  2322. X
  2323. X#define    READER    "/bin/lmail"
  2324. X
  2325. X#define TRUE 1
  2326. X#define FALSE 0
  2327. X
  2328. Xchar prog[128];
  2329. X
  2330. Xvoid    perror(), exit(), usage();
  2331. X
  2332. Xmain(argc, argv)
  2333. Xint argc;
  2334. Xchar *argv[];
  2335. X{
  2336. X    extern int optind;
  2337. X    extern char *optarg;
  2338. X
  2339. X    int i, j, c;
  2340. X    int reading, sending;
  2341. X
  2342. X    reading = sending = FALSE;
  2343. X
  2344. X    (void) strcpy(prog, argv[0]);
  2345. X
  2346. X    if(argc == 1) {
  2347. X        reading = TRUE;
  2348. X    } else {
  2349. X        while((c = getopt(argc, argv, "epqrtf:")) != EOF) {
  2350. X            switch(c) {
  2351. X            case 'e':
  2352. X            case 'p':
  2353. X            case 'q':
  2354. X            case 'r':
  2355. X            case 'f':
  2356. X                reading = TRUE;
  2357. X                break;
  2358. X            case 't':
  2359. X                sending = TRUE;
  2360. X                break;
  2361. X            default:
  2362. X                usage();
  2363. X                return(1);
  2364. X            }
  2365. X        }
  2366. X    }
  2367. X
  2368. X    /* any arguments left over -> sending */
  2369. X    if(argc > optind) {
  2370. X        sending = TRUE;
  2371. X    }
  2372. X
  2373. X    if((reading == TRUE) && (sending == TRUE)) {
  2374. X        usage();
  2375. X        return(1);
  2376. X    }
  2377. X
  2378. X    if(sending == TRUE) {
  2379. X        argv[0] = SENDER;
  2380. X        for(i = 1, j = optind; j < argc; i++, j++) {
  2381. X            argv[i] = argv[j];
  2382. X        }
  2383. X        argv[i] = NULL;
  2384. X    } else {
  2385. X        argv[0] = READER;
  2386. X    }
  2387. X
  2388. X    (void) execvp(argv[0], argv);
  2389. X    (void) fprintf(stderr, "%s: execvp(\"%s\", argv) failed: ",
  2390. X        prog, argv[0]);
  2391. X    perror("");
  2392. X    return(1);
  2393. X}
  2394. X
  2395. Xvoid
  2396. Xusage()
  2397. X{
  2398. X    (void) fprintf(stderr, "usage:\t%s [ -epqr ] [ -f file ]\n", prog);
  2399. X    (void) fprintf(stderr, "\t%s [ -t ] persons\n", prog);
  2400. X}
  2401. @//E*O*F src/svbinmail.c//
  2402. if test 1749 -ne "`wc -c <'src/svbinmail.c'`"; then
  2403.     echo shar: error transmitting "'src/svbinmail.c'" '(should have been 1749 characters)'
  2404. fi
  2405. fi # end of overwriting check
  2406. echo shar: extracting "'src/sysexits.h'" '(483 characters)'
  2407. if test -f 'src/sysexits.h' ; then 
  2408.   echo shar: will not over-write existing file "'src/sysexits.h'"
  2409. else
  2410. sed 's/^X//' >src/sysexits.h <<'@//E*O*F src/sysexits.h//'
  2411. X/*
  2412. X**    @(#)sysexits.h    2.1 (smail) 12/14/86
  2413. X*/
  2414. X
  2415. X# define EX_OK        0    /* successful termination */
  2416. X# define EX_USAGE    64    /* command line usage error */
  2417. X# define EX_NOHOST    68    /* host name unknown */
  2418. X# define EX_UNAVAILABLE    69    /* service unavailable */
  2419. X# define EX_SOFTWARE    70    /* internal software error */
  2420. X# define EX_OSFILE    72    /* critical OS file missing */
  2421. X# define EX_CANTCREAT    73    /* can't create (user) output file */
  2422. X# define EX_TEMPFAIL    75    /* temp failure; user is invited to retry */
  2423. @//E*O*F src/sysexits.h//
  2424. if test 483 -ne "`wc -c <'src/sysexits.h'`"; then
  2425.     echo shar: error transmitting "'src/sysexits.h'" '(should have been 483 characters)'
  2426. fi
  2427. fi # end of overwriting check
  2428. echo shar: "End of shell archive."
  2429. exit 0
  2430.